refactor(dev-infra): refactor commit-message files (#38845)
Refactor the commit-message files to be consistent with how other ng-dev tooling is structured. PR Close #38845
This commit is contained in:
parent
3817e5f1df
commit
d192c87f6a
|
@ -3,18 +3,10 @@ load("@npm_bazel_typescript//:index.bzl", "ts_library")
|
|||
|
||||
ts_library(
|
||||
name = "commit-message",
|
||||
srcs = [
|
||||
"builder.ts",
|
||||
"cli.ts",
|
||||
"commit-message-draft.ts",
|
||||
"config.ts",
|
||||
"parse.ts",
|
||||
"restore-commit-message.ts",
|
||||
"validate.ts",
|
||||
"validate-file.ts",
|
||||
"validate-range.ts",
|
||||
"wizard.ts",
|
||||
],
|
||||
srcs = glob(
|
||||
["**/*.ts"],
|
||||
exclude = ["**/*.spec.ts"],
|
||||
),
|
||||
module_name = "@angular/dev-infra-private/commit-message",
|
||||
visibility = ["//dev-infra:__subpackages__"],
|
||||
deps = [
|
||||
|
@ -32,11 +24,7 @@ ts_library(
|
|||
ts_library(
|
||||
name = "test_lib",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"builder.spec.ts",
|
||||
"parse.spec.ts",
|
||||
"validate.spec.ts",
|
||||
],
|
||||
srcs = glob(["**/*.spec.ts"]),
|
||||
deps = [
|
||||
":commit-message",
|
||||
"//dev-infra/utils",
|
||||
|
|
|
@ -6,112 +6,20 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import * as yargs from 'yargs';
|
||||
import {getUserConfig} from '../utils/config';
|
||||
|
||||
import {info} from '../utils/console';
|
||||
|
||||
import {restoreCommitMessage} from './restore-commit-message';
|
||||
import {validateFile} from './validate-file';
|
||||
import {validateCommitRange} from './validate-range';
|
||||
import {runWizard} from './wizard';
|
||||
import {RestoreCommitMessageModule} from './restore-commit-message/cli';
|
||||
import {ValidateFileModule} from './validate-file/cli';
|
||||
import {ValidateRangeModule} from './validate-range/cli';
|
||||
import {WizardModule} from './wizard/cli';
|
||||
|
||||
/** Build the parser for the commit-message commands. */
|
||||
export function buildCommitMessageParser(localYargs: yargs.Argv) {
|
||||
return localYargs.help()
|
||||
.strict()
|
||||
.command(
|
||||
'restore-commit-message-draft', false,
|
||||
args => {
|
||||
return args.option('file-env-variable', {
|
||||
type: 'string',
|
||||
array: true,
|
||||
conflicts: ['file'],
|
||||
required: true,
|
||||
description:
|
||||
'The key for the environment variable which holds the arguments for the\n' +
|
||||
'prepare-commit-msg hook as described here:\n' +
|
||||
'https://git-scm.com/docs/githooks#_prepare_commit_msg',
|
||||
coerce: arg => {
|
||||
const [file, source] = (process.env[arg] || '').split(' ');
|
||||
if (!file) {
|
||||
throw new Error(`Provided environment variable "${arg}" was not found.`);
|
||||
}
|
||||
return [file, source];
|
||||
},
|
||||
});
|
||||
},
|
||||
args => {
|
||||
restoreCommitMessage(args['file-env-variable'][0], args['file-env-variable'][1] as any);
|
||||
})
|
||||
.command(
|
||||
'wizard <filePath> [source] [commitSha]', '', ((args: any) => {
|
||||
return args
|
||||
.positional(
|
||||
'filePath',
|
||||
{description: 'The file path to write the generated commit message into'})
|
||||
.positional('source', {
|
||||
choices: ['message', 'template', 'merge', 'squash', 'commit'],
|
||||
description: 'The source of the commit message as described here: ' +
|
||||
'https://git-scm.com/docs/githooks#_prepare_commit_msg'
|
||||
})
|
||||
.positional(
|
||||
'commitSha', {description: 'The commit sha if source is set to `commit`'});
|
||||
}),
|
||||
async (args: any) => {
|
||||
await runWizard(args);
|
||||
})
|
||||
.command(
|
||||
'pre-commit-validate', 'Validate the most recent commit message', {
|
||||
'file': {
|
||||
type: 'string',
|
||||
conflicts: ['file-env-variable'],
|
||||
description: 'The path of the commit message file.',
|
||||
},
|
||||
'file-env-variable': {
|
||||
type: 'string',
|
||||
conflicts: ['file'],
|
||||
description:
|
||||
'The key of the environment variable for the path of the commit message file.',
|
||||
coerce: arg => {
|
||||
const file = process.env[arg];
|
||||
if (!file) {
|
||||
throw new Error(`Provided environment variable "${arg}" was not found.`);
|
||||
}
|
||||
return file;
|
||||
},
|
||||
},
|
||||
'error': {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Whether invalid commit messages should be treated as failures rather than a warning',
|
||||
default: !!getUserConfig().commitMessage?.errorOnInvalidMessage || !!process.env['CI']
|
||||
}
|
||||
},
|
||||
args => {
|
||||
const file = args.file || args['file-env-variable'] || '.git/COMMIT_EDITMSG';
|
||||
validateFile(file, args.error);
|
||||
})
|
||||
.command(
|
||||
'validate-range', 'Validate a range of commit messages', {
|
||||
'range': {
|
||||
description: 'The range of commits to check, e.g. --range abc123..xyz456',
|
||||
demandOption: ' A range must be provided, e.g. --range abc123..xyz456',
|
||||
type: 'string',
|
||||
requiresArg: true,
|
||||
},
|
||||
},
|
||||
argv => {
|
||||
// If on CI, and not pull request number is provided, assume the branch
|
||||
// being run on is an upstream branch.
|
||||
if (process.env['CI'] && process.env['CI_PULL_REQUEST'] === 'false') {
|
||||
info(`Since valid commit messages are enforced by PR linting on CI, we do not`);
|
||||
info(`need to validate commit messages on CI runs on upstream branches.`);
|
||||
info();
|
||||
info(`Skipping check of provided commit range`);
|
||||
return;
|
||||
}
|
||||
validateCommitRange(argv.range);
|
||||
});
|
||||
.command(RestoreCommitMessageModule)
|
||||
.command(WizardModule)
|
||||
.command(ValidateFileModule)
|
||||
.command(ValidateRangeModule);
|
||||
}
|
||||
|
||||
if (require.main == module) {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* The source triggering the git commit message creation.
|
||||
* As described in: https://git-scm.com/docs/githooks#_prepare_commit_msg
|
||||
*/
|
||||
export type CommitMsgSource = 'message'|'template'|'merge'|'squash'|'commit';
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import {assertNoErrors, getConfig, NgDevConfig} from '../utils/config';
|
||||
|
||||
/** Configuration for commit-message comands. */
|
||||
export interface CommitMessageConfig {
|
||||
maxLineLength: number;
|
||||
minBodyLength: number;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Arguments, Argv, CommandModule} from 'yargs';
|
||||
|
||||
import {CommitMsgSource} from '../commit-message-source';
|
||||
|
||||
import {restoreCommitMessage} from './restore-commit-message';
|
||||
|
||||
export interface RestoreCommitMessageOptions {
|
||||
fileEnvVariable: string[];
|
||||
}
|
||||
|
||||
/** Builds the command. */
|
||||
function builder(yargs: Argv) {
|
||||
return yargs.option('file-env-variable' as 'fileEnvVariable', {
|
||||
type: 'string',
|
||||
array: true,
|
||||
demandOption: true,
|
||||
description: 'The key for the environment variable which holds the arguments for the\n' +
|
||||
'prepare-commit-msg hook as described here:\n' +
|
||||
'https://git-scm.com/docs/githooks#_prepare_commit_msg',
|
||||
coerce: arg => {
|
||||
const [file, source] = (process.env[arg] || '').split(' ');
|
||||
if (!file) {
|
||||
throw new Error(`Provided environment variable "${arg}" was not found.`);
|
||||
}
|
||||
return [file, source];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** Handles the command. */
|
||||
async function handler({fileEnvVariable}: Arguments<RestoreCommitMessageOptions>) {
|
||||
restoreCommitMessage(fileEnvVariable[0], fileEnvVariable[1] as CommitMsgSource);
|
||||
}
|
||||
|
||||
/** yargs command module describing the command. */
|
||||
export const RestoreCommitMessageModule: CommandModule<{}, RestoreCommitMessageOptions> = {
|
||||
handler,
|
||||
builder,
|
||||
command: 'restore-commit-message-draft',
|
||||
// Description: Restore a commit message draft if one has been saved from a failed commit attempt.
|
||||
// No describe is defiend to hide the command from the --help.
|
||||
describe: false,
|
||||
};
|
|
@ -8,9 +8,10 @@
|
|||
|
||||
import {writeFileSync} from 'fs';
|
||||
|
||||
import {debug, log} from '../utils/console';
|
||||
import {debug, log} from '../../utils/console';
|
||||
|
||||
import {loadCommitMessageDraft} from './commit-message-draft';
|
||||
import {loadCommitMessageDraft} from '../commit-message-draft';
|
||||
import {CommitMsgSource} from '../commit-message-source';
|
||||
|
||||
/**
|
||||
* Restore the commit message draft to the git to be used as the default commit message.
|
||||
|
@ -18,8 +19,7 @@ import {loadCommitMessageDraft} from './commit-message-draft';
|
|||
* The source provided may be one of the sources described in
|
||||
* https://git-scm.com/docs/githooks#_prepare_commit_msg
|
||||
*/
|
||||
export function restoreCommitMessage(
|
||||
filePath: string, source?: 'message'|'template'|'squash'|'commit') {
|
||||
export function restoreCommitMessage(filePath: string, source?: CommitMsgSource) {
|
||||
if (!!source) {
|
||||
log('Skipping commit message restoration attempt');
|
||||
if (source === 'message') {
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Arguments, Argv, CommandModule} from 'yargs';
|
||||
|
||||
import {getUserConfig} from '../../utils/config';
|
||||
|
||||
import {validateFile} from './validate-file';
|
||||
|
||||
|
||||
export interface ValidateFileOptions {
|
||||
file?: string;
|
||||
fileEnvVariable?: string;
|
||||
error: boolean;
|
||||
}
|
||||
|
||||
/** Builds the command. */
|
||||
function builder(yargs: Argv) {
|
||||
return yargs
|
||||
.option('file', {
|
||||
type: 'string',
|
||||
conflicts: ['file-env-variable'],
|
||||
description: 'The path of the commit message file.',
|
||||
})
|
||||
.option('file-env-variable' as 'fileEnvVariable', {
|
||||
type: 'string',
|
||||
conflicts: ['file'],
|
||||
description: 'The key of the environment variable for the path of the commit message file.',
|
||||
coerce: (arg: string) => {
|
||||
const file = process.env[arg];
|
||||
if (!file) {
|
||||
throw new Error(`Provided environment variable "${arg}" was not found.`);
|
||||
}
|
||||
return file;
|
||||
},
|
||||
})
|
||||
.option('error', {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Whether invalid commit messages should be treated as failures rather than a warning',
|
||||
default: !!getUserConfig().commitMessage?.errorOnInvalidMessage || !!process.env['CI']
|
||||
});
|
||||
}
|
||||
|
||||
/** Handles the command. */
|
||||
async function handler({error, file, fileEnvVariable}: Arguments<ValidateFileOptions>) {
|
||||
const filePath = file || fileEnvVariable || '.git/COMMIT_EDITMSG';
|
||||
validateFile(filePath, error);
|
||||
}
|
||||
|
||||
/** yargs command module describing the command. */
|
||||
export const ValidateFileModule: CommandModule<{}, ValidateFileOptions> = {
|
||||
handler,
|
||||
builder,
|
||||
command: 'pre-commit-validate',
|
||||
describe: 'Validate the most recent commit message',
|
||||
};
|
|
@ -8,11 +8,11 @@
|
|||
import {readFileSync} from 'fs';
|
||||
import {resolve} from 'path';
|
||||
|
||||
import {getRepoBaseDir, getUserConfig} from '../utils/config';
|
||||
import {error, green, info, log, red, yellow} from '../utils/console';
|
||||
import {getRepoBaseDir} from '../../utils/config';
|
||||
import {error, green, info, log, red, yellow} from '../../utils/console';
|
||||
|
||||
import {deleteCommitMessageDraft, saveCommitMessageDraft} from './commit-message-draft';
|
||||
import {printValidationErrors, validateCommitMessage} from './validate';
|
||||
import {deleteCommitMessageDraft, saveCommitMessageDraft} from '../commit-message-draft';
|
||||
import {printValidationErrors, validateCommitMessage} from '../validate';
|
||||
|
||||
/** Validate commit message at the provided file path. */
|
||||
export function validateFile(filePath: string, isErrorMode: boolean) {
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Arguments, Argv, CommandModule} from 'yargs';
|
||||
|
||||
import {info} from '../../utils/console';
|
||||
|
||||
import {validateCommitRange} from './validate-range';
|
||||
|
||||
|
||||
export interface ValidateRangeOptions {
|
||||
range: string;
|
||||
}
|
||||
|
||||
/** Builds the command. */
|
||||
function builder(yargs: Argv) {
|
||||
return yargs.option('range', {
|
||||
description: 'The range of commits to check, e.g. --range abc123..xyz456',
|
||||
demandOption: ' A range must be provided, e.g. --range abc123..xyz456',
|
||||
type: 'string',
|
||||
requiresArg: true,
|
||||
});
|
||||
}
|
||||
|
||||
/** Handles the command. */
|
||||
async function handler({range}: Arguments<ValidateRangeOptions>) {
|
||||
// If on CI, and no pull request number is provided, assume the branch
|
||||
// being run on is an upstream branch.
|
||||
if (process.env['CI'] && process.env['CI_PULL_REQUEST'] === 'false') {
|
||||
info(`Since valid commit messages are enforced by PR linting on CI, we do not`);
|
||||
info(`need to validate commit messages on CI runs on upstream branches.`);
|
||||
info();
|
||||
info(`Skipping check of provided commit range`);
|
||||
return;
|
||||
}
|
||||
validateCommitRange(range);
|
||||
}
|
||||
|
||||
/** yargs command module describing the command. */
|
||||
export const ValidateRangeModule: CommandModule<{}, ValidateRangeOptions> = {
|
||||
handler,
|
||||
builder,
|
||||
command: 'validate-range',
|
||||
describe: 'Validate a range of commit messages',
|
||||
};
|
|
@ -5,11 +5,11 @@
|
|||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {error, info} from '../utils/console';
|
||||
import {exec} from '../utils/shelljs';
|
||||
import {error, info} from '../../utils/console';
|
||||
import {exec} from '../../utils/shelljs';
|
||||
|
||||
import {parseCommitMessage} from './parse';
|
||||
import {printValidationErrors, validateCommitMessage, ValidateCommitMessageOptions} from './validate';
|
||||
import {parseCommitMessage} from '../parse';
|
||||
import {printValidationErrors, validateCommitMessage, ValidateCommitMessageOptions} from '../validate';
|
||||
|
||||
// Whether the provided commit is a fixup commit.
|
||||
const isNonFixup = (m: string) => !parseCommitMessage(m).isFixup;
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Arguments, Argv, CommandModule} from 'yargs';
|
||||
|
||||
import {CommitMsgSource} from '../commit-message-source';
|
||||
|
||||
import {runWizard} from './wizard';
|
||||
|
||||
|
||||
export interface WizardOptions {
|
||||
filePath: string;
|
||||
commitSha: string|undefined;
|
||||
source: CommitMsgSource|undefined;
|
||||
}
|
||||
|
||||
/** Builds the command. */
|
||||
function builder(yargs: Argv) {
|
||||
return yargs
|
||||
.positional('filePath', {
|
||||
description: 'The file path to write the generated commit message into',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
})
|
||||
.positional('source', {
|
||||
choices: ['message', 'template', 'merge', 'squash', 'commit'] as const,
|
||||
description: 'The source of the commit message as described here: ' +
|
||||
'https://git-scm.com/docs/githooks#_prepare_commit_msg'
|
||||
})
|
||||
.positional('commitSha', {
|
||||
description: 'The commit sha if source is set to `commit`',
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
/** Handles the command. */
|
||||
async function handler(args: Arguments<WizardOptions>) {
|
||||
await runWizard(args);
|
||||
}
|
||||
|
||||
/** yargs command module describing the command. */
|
||||
export const WizardModule: CommandModule<{}, WizardOptions> = {
|
||||
handler,
|
||||
builder,
|
||||
command: 'wizard <filePath> [source] [commitSha]',
|
||||
// Description: Run the wizard to build a base commit message before opening to complete.
|
||||
// No describe is defiend to hide the command from the --help.
|
||||
describe: false,
|
||||
};
|
|
@ -7,16 +7,12 @@
|
|||
*/
|
||||
import {writeFileSync} from 'fs';
|
||||
|
||||
import {getUserConfig} from '../utils/config';
|
||||
import {debug, info} from '../utils/console';
|
||||
import {getUserConfig} from '../../utils/config';
|
||||
import {debug, info} from '../../utils/console';
|
||||
|
||||
import {buildCommitMessage} from './builder';
|
||||
import {buildCommitMessage} from '../builder';
|
||||
import {CommitMsgSource} from '../commit-message-source';
|
||||
|
||||
/**
|
||||
* The source triggering the git commit message creation.
|
||||
* As described in: https://git-scm.com/docs/githooks#_prepare_commit_msg
|
||||
*/
|
||||
export type PrepareCommitMsgHookSource = 'message'|'template'|'merge'|'squash'|'commit';
|
||||
|
||||
/** The default commit message used if the wizard does not procude a commit message. */
|
||||
const defaultCommitMessage = `<type>(<scope>): <summary>
|
||||
|
@ -25,7 +21,7 @@ const defaultCommitMessage = `<type>(<scope>): <summary>
|
|||
# lines at 100 characters.>\n\n`;
|
||||
|
||||
export async function runWizard(
|
||||
args: {filePath: string, source?: PrepareCommitMsgHookSource, commitSha?: string}) {
|
||||
args: {filePath: string, source?: CommitMsgSource, commitSha?: string}) {
|
||||
if (getUserConfig().commitMessage?.disableWizard) {
|
||||
debug('Skipping commit message wizard due to enabled `commitMessage.disableWizard` option in');
|
||||
debug('user config.');
|
Loading…
Reference in New Issue