diff --git a/@commitlint/cli/src/cli.test.ts b/@commitlint/cli/src/cli.test.ts index 846869d5e8..b7b83ea401 100644 --- a/@commitlint/cli/src/cli.test.ts +++ b/@commitlint/cli/src/cli.test.ts @@ -52,6 +52,16 @@ test('should produce success output with --verbose flag', async () => { expect(actual.stderr).toEqual(''); }); +test('should produce last commit and success output with --verbose flag', async () => { + const cwd = await gitBootstrap('fixtures/simple'); + await execa('git', ['add', 'commitlint.config.js'], {cwd}); + await execa('git', ['commit', '-m', '"test: this should work"'], {cwd}); + const actual = await cli(['--last', '--verbose'], {cwd})(); + expect(actual.stdout).toContain('0 problems, 0 warnings'); + expect(actual.stdout).toContain('test: this should work'); + expect(actual.stderr).toEqual(''); +}); + test('should produce no output with --quiet flag', async () => { const cwd = await gitBootstrap('fixtures/default'); const actual = await cli(['--quiet'], {cwd})('foo: bar'); @@ -529,6 +539,7 @@ test('should print help', async () => { -H, --help-url help url in error message [string] -f, --from lower end of the commit range to lint; applies if edit=false [string] --git-log-args additional git log arguments as space separated string, example '--first-parent --cherry-pick' [string] + -l, --last just analyze the last commit; applies if edit=false [boolean] -o, --format output format of the results [string] -p, --parser-preset configuration preset to use for conventional-commits-parser [string] -q, --quiet toggle console output [boolean] [default: false] diff --git a/@commitlint/cli/src/cli.ts b/@commitlint/cli/src/cli.ts index b871d2fa56..b58c047be1 100644 --- a/@commitlint/cli/src/cli.ts +++ b/@commitlint/cli/src/cli.ts @@ -95,6 +95,11 @@ const cli = yargs(process.argv.slice(2)) "additional git log arguments as space separated string, example '--first-parent --cherry-pick'", type: 'string', }, + last: { + alias: 'l', + description: 'just analyze the last commit; applies if edit=false', + type: 'boolean', + }, format: { alias: 'o', description: 'output format of the results', @@ -214,11 +219,25 @@ async function main(args: MainArgs): Promise { const fromStdin = checkFromStdin(raw, flags); + if ( + Object.hasOwn(flags, 'last') && + (Object.hasOwn(flags, 'from') || Object.hasOwn(flags, 'to') || flags.edit) + ) { + const err = new CliError( + 'Please use the --last flag alone. The --last flag should not be used with --to or --from or --edit.', + pkg.name + ); + cli.showHelp('log'); + console.log(err.message); + throw err; + } + const input = await (fromStdin ? stdin() : read({ to: flags.to, from: flags.from, + last: flags.last, edit: flags.edit, cwd: flags.cwd, gitLogArgs: flags['git-log-args'], @@ -231,7 +250,7 @@ async function main(args: MainArgs): Promise { if (messages.length === 0 && !checkFromRepository(flags)) { const err = new CliError( - '[input] is required: supply via stdin, or --env or --edit or --from and --to', + '[input] is required: supply via stdin, or --env or --edit or --last or --from and --to', pkg.name ); cli.showHelp('log'); @@ -374,7 +393,11 @@ function checkFromEdit(flags: CliFlags): boolean { } function checkFromHistory(flags: CliFlags): boolean { - return typeof flags.from === 'string' || typeof flags.to === 'string'; + return ( + typeof flags.from === 'string' || + typeof flags.to === 'string' || + typeof flags.last === 'boolean' + ); } function normalizeFlags(flags: CliFlags): CliFlags { diff --git a/@commitlint/cli/src/types.ts b/@commitlint/cli/src/types.ts index a622cb05fe..42056cc556 100644 --- a/@commitlint/cli/src/types.ts +++ b/@commitlint/cli/src/types.ts @@ -9,6 +9,7 @@ export interface CliFlags { 'help-url'?: string; from?: string; 'git-log-args'?: string; + last?: boolean; format?: string; 'parser-preset'?: string; quiet: boolean; diff --git a/@commitlint/read/package.json b/@commitlint/read/package.json index 1ea5ebe666..59e8fbed5d 100644 --- a/@commitlint/read/package.json +++ b/@commitlint/read/package.json @@ -39,14 +39,14 @@ "@commitlint/test": "^19.0.0", "@commitlint/utils": "^19.0.0", "@types/git-raw-commits": "^2.0.3", - "@types/minimist": "^1.2.4", - "execa": "^8.0.1" + "@types/minimist": "^1.2.4" }, "dependencies": { "@commitlint/top-level": "^19.0.0", "@commitlint/types": "^19.0.3", "git-raw-commits": "^4.0.0", - "minimist": "^1.2.8" + "minimist": "^1.2.8", + "execa": "^8.0.1" }, "gitHead": "70f7f4688b51774e7ac5e40e896cdaa3f132b2bc" } diff --git a/@commitlint/read/src/read.ts b/@commitlint/read/src/read.ts index a272cca394..d0ffdb9387 100644 --- a/@commitlint/read/src/read.ts +++ b/@commitlint/read/src/read.ts @@ -4,10 +4,13 @@ import type {GitOptions} from 'git-raw-commits'; import {getHistoryCommits} from './get-history-commits.js'; import {getEditCommit} from './get-edit-commit.js'; +import {execa} from 'execa'; + interface GetCommitMessageOptions { cwd?: string; from?: string; to?: string; + last?: boolean; edit?: boolean | string; gitLogArgs?: string; } @@ -16,12 +19,21 @@ interface GetCommitMessageOptions { export default async function getCommitMessages( settings: GetCommitMessageOptions ): Promise { - const {cwd, from, to, edit, gitLogArgs} = settings; + const {cwd, from, to, last, edit, gitLogArgs} = settings; if (edit) { return getEditCommit(cwd, edit); } + if (last) { + const executeGitCommand = await execa('git', [ + 'log', + '-1', + '--pretty=format:"%B"', + ]); + return [executeGitCommand.stdout]; + } + let gitOptions: GitOptions = {from, to}; if (gitLogArgs) { gitOptions = { diff --git a/docs/guides/ci-setup.md b/docs/guides/ci-setup.md index d4c217d373..1d3e37797b 100644 --- a/docs/guides/ci-setup.md +++ b/docs/guides/ci-setup.md @@ -42,7 +42,7 @@ jobs: - name: Validate current commit (last commit) with commitlint if: github.event_name == 'push' - run: npx commitlint --from HEAD~1 --to HEAD --verbose + run: npx commitlint --last --verbose - name: Validate PR commits with commitlint if: github.event_name == 'pull_request' diff --git a/tsconfig.shared.json b/tsconfig.shared.json index 9abe5b68fa..150d512559 100644 --- a/tsconfig.shared.json +++ b/tsconfig.shared.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "target": "ES2017", - "lib": ["es2017"], + "target": "ES2022", + "lib": ["es2022"], "declaration": true, "declarationMap": true, "sourceMap": true,