From 872e044fae965c4299e257013760e7a0c018b9bb Mon Sep 17 00:00:00 2001 From: Preyam Rao Date: Wed, 31 Dec 2025 16:54:38 +0530 Subject: [PATCH] feat: add --yes and --no-verify flags to lazycommit CLI --- src/cli.ts | 14 +++++++++++++ src/commands/lazycommit.ts | 15 ++++++++++++-- tests/specs/cli/commits.ts | 24 ++++++++++++++++++++++ tests/specs/cli/index.ts | 1 + tests/specs/cli/no-verify.ts | 39 ++++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 tests/specs/cli/no-verify.ts diff --git a/src/cli.ts b/src/cli.ts index 34630ec..f2186f2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -55,6 +55,18 @@ cli( alias: 's', default: false, }, + yes: { + type: Boolean, + description: 'Skip approval and commit immediately', + alias: 'y', + default: false, + }, + noVerify: { + type: Boolean, + description: 'Bypass pre-commit and commit-msg hooks', + alias: 'n', + default: false, + }, }, commands: [configCommand, hookCommand], @@ -75,6 +87,8 @@ cli( argv.flags.all, argv.flags.type, argv.flags.split, + argv.flags.yes, + argv.flags.noVerify, rawArgv ); } diff --git a/src/commands/lazycommit.ts b/src/commands/lazycommit.ts index 8f8614f..f3a9a7f 100644 --- a/src/commands/lazycommit.ts +++ b/src/commands/lazycommit.ts @@ -131,6 +131,8 @@ export default async ( stageAll: boolean, commitType: string | undefined, splitCommits: boolean, + skipApproval: boolean, + noVerify: boolean, rawArgv: string[] ) => (async () => { @@ -239,7 +241,11 @@ export default async ( let message: string; let editedAlready = false; let useAsIs = false; - if (messages.length === 1) { + + if (skipApproval) { + message = messages[0]; + useAsIs = true; + } else if (messages.length === 1) { [message] = messages; const choice = await select({ message: `Review generated commit message:\n\n ${message}\n`, @@ -313,7 +319,12 @@ export default async ( } } - await execa('git', ['commit', '-m', message, ...rawArgv]); + const commitArgs = ['commit', '-m', message]; + if (noVerify) { + commitArgs.push('--no-verify'); + } + commitArgs.push(...rawArgv); + await execa('git', commitArgs); outro(`${green('✔')} Successfully committed!`); })().catch((error) => { diff --git a/tests/specs/cli/commits.ts b/tests/specs/cli/commits.ts index f9e696e..617a854 100644 --- a/tests/specs/cli/commits.ts +++ b/tests/specs/cli/commits.ts @@ -74,6 +74,30 @@ export default testSuite(({ describe }) => { await fixture.rm(); }); + test('Skips approval with --yes flag', async () => { + const { fixture, lazycommit } = await createFixture(files); + const git = await createGit(fixture.path); + + await git('add', ['data.json']); + + // With --yes, should commit immediately without prompts + await lazycommit(['--yes']); + + const statusAfter = await git('status', [ + '--porcelain', + '--untracked-files=no', + ]); + expect(statusAfter.stdout).toBe(''); + + const { stdout: commitMessage } = await git('log', [ + '--pretty=format:%s', + ]); + expect(commitMessage).toBeTruthy(); + expect(commitMessage?.length).toBeLessThanOrEqual(50); + + await fixture.rm(); + }); + test('Generated commit message must be under 20 characters', async () => { const { fixture, lazycommit } = await createFixture({ ...files, diff --git a/tests/specs/cli/index.ts b/tests/specs/cli/index.ts index 85d3079..000e939 100644 --- a/tests/specs/cli/index.ts +++ b/tests/specs/cli/index.ts @@ -4,5 +4,6 @@ export default testSuite(({ describe }) => { describe('CLI', ({ runTestSuite }) => { runTestSuite(import('./error-cases.js')); runTestSuite(import('./commits.js')); + runTestSuite(import('./no-verify.js')); }); }); diff --git a/tests/specs/cli/no-verify.ts b/tests/specs/cli/no-verify.ts new file mode 100644 index 0000000..67fcd18 --- /dev/null +++ b/tests/specs/cli/no-verify.ts @@ -0,0 +1,39 @@ +import { testSuite, expect } from 'manten'; +import fs from 'fs/promises'; +import path from 'path'; +import { + assertGroqToken, + createFixture, + createGit, + files, +} from '../../utils.js'; + +export default testSuite(({ describe }) => { + describe('no-verify', async ({ test }) => { + if (!assertGroqToken()) { + return; + } + + test('Bypasses pre-commit hook', async () => { + const { fixture, lazycommit } = await createFixture(files); + const git = await createGit(fixture.path); + + // Create a pre-commit hook that fails + const hookPath = path.join(fixture.path, '.git/hooks/pre-commit'); + await fs.writeFile(hookPath, '#!/bin/sh\nexit 1'); + await fs.chmod(hookPath, '755'); + + await git('add', ['data.json']); + + // Should fail without --no-verify + const { exitCode: failExitCode } = await lazycommit(['--yes'], { reject: false }); + expect(failExitCode).toBe(1); + + // Should pass with --no-verify + const { exitCode: successExitCode } = await lazycommit(['--no-verify', '--yes'], { reject: false }); + expect(successExitCode).toBe(0); + + await fixture.rm(); + }); + }); +});