Prevent "oops" moments by running preflight checks before every Git push
A lightweight, configurable Git pre-push hook that automatically runs your quality checks (tests, linting, type-checking, etc.) before allowing a push to go through.
Install no-push-oops as a dev dependency in your project:
# npm
npm install --save-dev no-push-oops
# yarn
yarn add -D no-push-oops
# pnpm
pnpm add -D no-push-oopsIf the hook isn't installed automatically, run:
npx no-push-oops install# Choose your package manager
npm install --save-dev no-push-oops
# or
yarn add -D no-push-oops
# or
pnpm add -D no-push-oopspackage.json:{
"no-push-oops": {
"command": "npm run pr-preflight"
},
"scripts": {
"pr-preflight": "npm run lint && npm run test && npm run build"
}
}You can configure no-push-oops in three ways:
1. In package.json:
{
"no-push-oops": {
"command": "npm run pr-preflight",
"message": "Running quality checks...",
"skipCI": true,
"skipOnBranches": ["main", "develop"],
"verbose": false,
"timeout": 300000
}
}2. In .nopushoopsrc.json:
{
"command": "npm run pr-preflight",
"message": "Running quality checks...",
"skipCI": true
}3. In .nopushoopsrc:
{
"command": "npm run pr-preflight"
}| Option | Type | Default | Description |
|---|---|---|---|
command | string | "npm run pr-preflight" | Single command to run |
commands | string[] | - | Multiple commands to run in sequence |
message | string | "Running pr-preflight checks before push" | Custom message to display |
skipCI | boolean | true | Skip checks in CI environments |
skipOnBranches | string[] | [] | Branches to skip checks on |
verbose | boolean | false | Show detailed output |
timeout | number | 300000 | Command timeout in milliseconds |
Once installed, no-push-oops will automatically run on every git push. If the checks fail, the push will be aborted.
You can manually run the checks:
npx no-push-oops runIf you need to bypass the hook (not recommended):
git push --no-verifyTo remove the hook:
npx no-push-oops uninstall{
"no-push-oops": {
"command": "npm run lint && npm run test"
}
}{
"no-push-oops": {
"commands": [
"npm run lint",
"npm run test:unit",
"npm run test:integration",
"npm run type-check",
"npm run build"
],
"message": "Running full CI pipeline...",
"timeout": 600000
}
}{
"no-push-oops": {
"command": "npm run validate",
"skipOnBranches": ["main", "master", "production"]
}
}{
"no-push-oops": {
"command": "npm run test",
"verbose": true
}
}| Feature | no-push-oops | husky | pre-commit |
|---|---|---|---|
| Zero config | Yes | No | No |
| TypeScript | Yes | No | No |
| Pre-push focus | Yes | No | No |
| Auto-install | Yes | Yes | Yes |
| Branch filtering | Yes | No | Yes |
| Timeout support | Yes | No | Yes |
Why choose no-push-oops?
You can use no-push-oops programmatically in your Node.js scripts:
import {
loadConfig,
runPreflightChecks,
installHook,
uninstallHook
} from 'no-push-oops';
// Load configuration
const config = loadConfig();
// Run preflight checks
const success = await runPreflightChecks(config);
// Install/uninstall hooks programmatically
installHook();
uninstallHook();export interface NoPushOopsConfig {
command?: string;
commands?: string[];
message?: string;
skipCI?: boolean;
skipOnBranches?: string[];
verbose?: boolean;
timeout?: number;
}
export interface CommandResult {
success: boolean;
exitCode: number;
command: string;
output?: string;
error?: string;
}import {
loadConfig,
runPreflightChecks,
isCI,
getCurrentBranch
} from 'no-push-oops';
async function customPrePush() {
const config = loadConfig();
// Skip in CI
if (config.skipCI && isCI()) {
console.log('Skipping in CI environment');
return true;
}
// Skip on specific branches
const branch = getCurrentBranch();
if (branch && config.skipOnBranches?.includes(branch)) {
console.log(`Skipping on branch: ${branch}`);
return true;
}
// Run checks
return await runPreflightChecks(config);
}
customPrePush().then(success => {
process.exit(success ? 0 : 1);
});