feat(dev-infra): update commit-message functions to properly type commits from git log (#41458)

For commits from git log entries additional fields are available such as the reference
hash and author name, update the utility functions in commit-message to include the
parsed fields.  Additionally define, per commit message type, whether to include the
commit in a release notes entry.

PR Close #41458
This commit is contained in:
Joey Perrott 2021-04-01 16:03:38 -07:00 committed by atscott
parent ba3344ddbe
commit c63d00e5b0
4 changed files with 60 additions and 8 deletions

View File

@ -38,11 +38,17 @@ export enum ScopeRequirement {
Forbidden,
}
export enum ReleaseNotesLevel {
Hidden,
Visible,
}
/** A commit type */
export interface CommitType {
description: string;
name: string;
scope: ScopeRequirement;
releaseNotesLevel: ReleaseNotesLevel;
}
/** The valid commit types for Angular commit messages. */
@ -51,45 +57,54 @@ export const COMMIT_TYPES: {[key: string]: CommitType} = {
name: 'build',
description: 'Changes to local repository build system and tooling',
scope: ScopeRequirement.Optional,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
ci: {
name: 'ci',
description: 'Changes to CI configuration and CI specific tooling',
scope: ScopeRequirement.Forbidden,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
docs: {
name: 'docs',
description: 'Changes which exclusively affects documentation.',
scope: ScopeRequirement.Optional,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
feat: {
name: 'feat',
description: 'Creates a new feature',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Visible,
},
fix: {
name: 'fix',
description: 'Fixes a previously discovered failure/bug',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Visible,
},
perf: {
name: 'perf',
description: 'Improves performance without any change in functionality or API',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Visible,
},
refactor: {
name: 'refactor',
description: 'Refactor without any change in functionality or API (includes style changes)',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
release: {
name: 'release',
description: 'A release point in the repository',
scope: ScopeRequirement.Forbidden,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
test: {
name: 'test',
description: 'Improvements or corrections made to the project\'s test suite',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
};

View File

@ -41,6 +41,13 @@ export interface Commit {
isRevert: boolean;
}
/** A parsed commit which originated from a Git Log entry */
export interface CommitFromGitLog extends Commit {
author: string;
hash: string;
shortHash: string;
}
/**
* A list of tuples expressing the fields to extract from each commit log entry. The tuple contains
* two values, the first is the key for the property and the second is the template shortcut for the
@ -107,9 +114,16 @@ const parseOptions: Options&{notesPattern: (keywords: string) => RegExp} = {
notesPattern: (keywords: string) => new RegExp(`(${keywords})(?:: ?)(.*)`),
};
/** Parse a commit message into its composite parts. */
export const parseCommitMessage: (fullText: string) => Commit = parseInternal;
/** Parse a commit message from a git log entry into its composite parts. */
export const parseCommitFromGitLog: (fullText: Buffer) => CommitFromGitLog = parseInternal;
/** Parse a full commit message into its composite parts. */
export function parseCommitMessage(fullText: string|Buffer): Commit {
function parseInternal(fullText: string): Commit;
function parseInternal(fullText: Buffer): CommitFromGitLog;
function parseInternal(fullText: string|Buffer): CommitFromGitLog|Commit {
// Ensure the fullText symbol is a `string`, even if a Buffer was provided.
fullText = fullText.toString();
/** The commit message text with the fixup and squash markers stripped out. */
@ -148,5 +162,8 @@ export function parseCommitMessage(fullText: string|Buffer): Commit {
isFixup: FIXUP_PREFIX_RE.test(fullText),
isSquash: SQUASH_PREFIX_RE.test(fullText),
isRevert: REVERT_PREFIX_RE.test(fullText),
author: commit.author || undefined,
hash: commit.hash || undefined,
shortHash: commit.shortHash || undefined,
};
}

View File

@ -7,7 +7,7 @@
*/
import * as gitCommits_ from 'git-raw-commits';
import {Commit, gitLogFormatForParsing, parseCommitMessage} from './parse';
import {CommitFromGitLog, gitLogFormatForParsing, parseCommitFromGitLog} from './parse';
// Set `gitCommits` as this imported value to address "Cannot call a namespace" error.
const gitCommits = gitCommits_;
@ -16,16 +16,16 @@ const gitCommits = gitCommits_;
/**
* Find all commits within the given range and return an object describing those.
*/
export function getCommitsInRange(from: string, to: string = 'HEAD'): Promise<Commit[]> {
export function getCommitsInRange(from: string, to: string = 'HEAD'): Promise<CommitFromGitLog[]> {
return new Promise((resolve, reject) => {
/** List of parsed commit objects. */
const commits: Commit[] = [];
const commits: CommitFromGitLog[] = [];
/** Stream of raw git commit strings in the range provided. */
const commitStream = gitCommits({from, to, format: gitLogFormatForParsing});
// Accumulate the parsed commits for each commit from the Readable stream into an array, then
// resolve the promise with the array when the Readable stream ends.
commitStream.on('data', (commit: Buffer) => commits.push(parseCommitMessage(commit)));
commitStream.on('data', (commit: Buffer) => commits.push(parseCommitFromGitLog(commit)));
commitStream.on('error', (err: Error) => reject(err));
commitStream.on('end', () => resolve(commits));
});

View File

@ -1670,52 +1670,66 @@ var ScopeRequirement;
ScopeRequirement[ScopeRequirement["Optional"] = 1] = "Optional";
ScopeRequirement[ScopeRequirement["Forbidden"] = 2] = "Forbidden";
})(ScopeRequirement || (ScopeRequirement = {}));
var ReleaseNotesLevel;
(function (ReleaseNotesLevel) {
ReleaseNotesLevel[ReleaseNotesLevel["Hidden"] = 0] = "Hidden";
ReleaseNotesLevel[ReleaseNotesLevel["Visible"] = 1] = "Visible";
})(ReleaseNotesLevel || (ReleaseNotesLevel = {}));
/** The valid commit types for Angular commit messages. */
const COMMIT_TYPES = {
build: {
name: 'build',
description: 'Changes to local repository build system and tooling',
scope: ScopeRequirement.Optional,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
ci: {
name: 'ci',
description: 'Changes to CI configuration and CI specific tooling',
scope: ScopeRequirement.Forbidden,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
docs: {
name: 'docs',
description: 'Changes which exclusively affects documentation.',
scope: ScopeRequirement.Optional,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
feat: {
name: 'feat',
description: 'Creates a new feature',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Visible,
},
fix: {
name: 'fix',
description: 'Fixes a previously discovered failure/bug',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Visible,
},
perf: {
name: 'perf',
description: 'Improves performance without any change in functionality or API',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Visible,
},
refactor: {
name: 'refactor',
description: 'Refactor without any change in functionality or API (includes style changes)',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
release: {
name: 'release',
description: 'A release point in the repository',
scope: ScopeRequirement.Forbidden,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
test: {
name: 'test',
description: 'Improvements or corrections made to the project\'s test suite',
scope: ScopeRequirement.Required,
releaseNotesLevel: ReleaseNotesLevel.Hidden,
},
};
@ -1790,8 +1804,11 @@ const parseOptions = {
noteKeywords: [NoteSections.BREAKING_CHANGE, NoteSections.DEPRECATED],
notesPattern: (keywords) => new RegExp(`(${keywords})(?:: ?)(.*)`),
};
/** Parse a full commit message into its composite parts. */
function parseCommitMessage(fullText) {
/** Parse a commit message into its composite parts. */
const parseCommitMessage = parseInternal;
/** Parse a commit message from a git log entry into its composite parts. */
const parseCommitFromGitLog = parseInternal;
function parseInternal(fullText) {
// Ensure the fullText symbol is a `string`, even if a Buffer was provided.
fullText = fullText.toString();
/** The commit message text with the fixup and squash markers stripped out. */
@ -1828,6 +1845,9 @@ function parseCommitMessage(fullText) {
isFixup: FIXUP_PREFIX_RE.test(fullText),
isSquash: SQUASH_PREFIX_RE.test(fullText),
isRevert: REVERT_PREFIX_RE.test(fullText),
author: commit.author || undefined,
hash: commit.hash || undefined,
shortHash: commit.shortHash || undefined,
};
}
@ -2083,7 +2103,7 @@ function getCommitsInRange(from, to = 'HEAD') {
const commitStream = gitCommits({ from, to, format: gitLogFormatForParsing });
// Accumulate the parsed commits for each commit from the Readable stream into an array, then
// resolve the promise with the array when the Readable stream ends.
commitStream.on('data', (commit) => commits.push(parseCommitMessage(commit)));
commitStream.on('data', (commit) => commits.push(parseCommitFromGitLog(commit)));
commitStream.on('error', (err) => reject(err));
commitStream.on('end', () => resolve(commits));
});