From 26b2c89e4f3c75fe08d003f1a509e89e04b8f55f Mon Sep 17 00:00:00 2001 From: Andrew Lisowski Date: Fri, 26 Mar 2021 13:53:32 -0700 Subject: [PATCH] check all commits in PR for highest semver bump --- .../__tests__/conventional-commits.test.ts | 41 +++++++++++++- plugins/conventional-commits/package.json | 1 + plugins/conventional-commits/src/index.ts | 53 +++++++++++++++---- 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/plugins/conventional-commits/__tests__/conventional-commits.test.ts b/plugins/conventional-commits/__tests__/conventional-commits.test.ts index dbc9a1881..88f1d753a 100644 --- a/plugins/conventional-commits/__tests__/conventional-commits.test.ts +++ b/plugins/conventional-commits/__tests__/conventional-commits.test.ts @@ -49,6 +49,7 @@ describe("parseCommit", () => { labels: defaultLabels, semVerLabels: versionLabels, logger: dummyLog(), + git: { getCommitsForPR: () => Promise.resolve([]) } as any, } as Auto); const logParseHooks = makeLogParseHooks(); @@ -73,6 +74,7 @@ describe("parseCommit", () => { labels: defaultLabels, semVerLabels: versionLabels, logger: dummyLog(), + git: { getCommitsForPR: () => Promise.resolve([]) } as any, } as Auto); const logParseHooks = makeLogParseHooks(); @@ -97,6 +99,7 @@ describe("parseCommit", () => { labels: defaultLabels, semVerLabels: versionLabels, logger: dummyLog(), + git: { getCommitsForPR: () => Promise.resolve([]) } as any, } as Auto); const logParseHooks = makeLogParseHooks(); @@ -121,6 +124,7 @@ describe("parseCommit", () => { labels: defaultLabels, semVerLabels: versionLabels, logger: dummyLog(), + git: { getCommitsForPR: () => Promise.resolve([]) } as any, } as Auto); const logParseHooks = makeLogParseHooks(); @@ -137,6 +141,38 @@ describe("parseCommit", () => { }); }); + test("should apply a PRs greatest semver label", async () => { + const conventionalCommitsPlugin = new ConventionalCommitsPlugin(); + const autoHooks = makeHooks(); + conventionalCommitsPlugin.apply({ + hooks: autoHooks, + labels: defaultLabels, + semVerLabels: versionLabels, + logger: dummyLog(), + git: { + getCommitsForPR: () => + Promise.resolve([ + { sha: "8", commit: { message: "docs: child commit" } }, + { sha: "1", commit: { message: "chore: child commit" } }, + { sha: "2", commit: { message: "feat!: another commit" } }, + ]), + } as any, + } as Auto); + + const logParseHooks = makeLogParseHooks(); + autoHooks.onCreateLogParse.call({ + hooks: logParseHooks, + } as LogParse); + + const commit = makeCommitFromMsg("fix lint", {pullRequest: {number: 123}}); + expect( + await logParseHooks.parseCommit.promise({ ...commit }) + ).toStrictEqual({ + ...commit, + labels: ["major"], + }); + }); + test("should skip when not a fix/feat/breaking change commit", async () => { const conventionalCommitsPlugin = new ConventionalCommitsPlugin(); const autoHooks = makeHooks(); @@ -145,6 +181,7 @@ describe("parseCommit", () => { labels: defaultLabels, semVerLabels: versionLabels, logger: dummyLog(), + git: { getCommitsForPR: () => Promise.resolve([]) } as any, } as Auto); const logParseHooks = makeLogParseHooks(); @@ -171,6 +208,7 @@ describe("parseCommit", () => { labels: defaultLabels, semVerLabels: versionLabels, logger: dummyLog(), + git: { getCommitsForPR: () => Promise.resolve([]) } as any, } as Auto); const logParseHooks = makeLogParseHooks(); @@ -204,7 +242,8 @@ describe("normalizeCommit", () => { getPr: jest.fn(), getCommitsForPR: () => Promise.resolve([ - { sha: "1", commit: { message: "fix: child commit" } }, + { sha: "1", commit: { message: "chore: child commit" } }, + { sha: "2", commit: { message: "chore: another commit" } }, ]), } as unknown) as Git; conventionalCommitsPlugin.apply({ diff --git a/plugins/conventional-commits/package.json b/plugins/conventional-commits/package.json index 013a1e24d..a2ba44d1d 100644 --- a/plugins/conventional-commits/package.json +++ b/plugins/conventional-commits/package.json @@ -42,6 +42,7 @@ "conventional-changelog-core": "^4.2.0", "conventional-changelog-preset-loader": "^2.3.4", "conventional-commits-parser": "^3.1.0", + "endent": "^2.0.1", "fp-ts": "^2.5.3", "io-ts": "^2.1.2", "tslib": "2.1.0" diff --git a/plugins/conventional-commits/src/index.ts b/plugins/conventional-commits/src/index.ts index 0973eb126..b0b8751c9 100644 --- a/plugins/conventional-commits/src/index.ts +++ b/plugins/conventional-commits/src/index.ts @@ -12,6 +12,7 @@ import { getReleaseType, getHigherSemverTag, } from "@auto-it/core"; +import endent from "endent"; /** Resolve a conventional commit preset */ function presetResolver(presetPackage: CoreOptions.Config) { @@ -201,19 +202,12 @@ export default class ConventionalCommitsPlugin implements IPlugin { auto.hooks.onCreateLogParse.tap(this.name, (logParse) => { logParse.hooks.parseCommit.tapPromise(this.name, async (commit) => { - if (!auto.semVerLabels) { + if (!auto.semVerLabels || !auto.git) { return commit; } try { const message = `${commit.subject}\n\n${commit.rawBody}`; - const label = await getBump(message); - - if (!label) { - return commit; - } - - const incrementLabel = auto.semVerLabels.get(label); const allSemVerLabels = [ auto.semVerLabels.get(SEMVER.major), auto.semVerLabels.get(SEMVER.minor), @@ -222,13 +216,50 @@ export default class ConventionalCommitsPlugin implements IPlugin { (acc, labels) => (labels ? [...acc, ...labels] : acc), [] ); + const prHasSemverLabel = commit.labels.some((l) => + allSemVerLabels.includes(l) + ); + let bump = await getBump(message); + // Take into account all conventional commit message in each commit for a PR if ( - incrementLabel && - !commit.labels.some((l) => allSemVerLabels.includes(l)) + commit.pullRequest && + // If the PR already has a semver label it takes precedence over conventional + // commit messages + !prHasSemverLabel ) { + const prCommits = await auto.git.getCommitsForPR( + commit.pullRequest.number + ); + const prBumps = ( + await Promise.all(prCommits.map((c) => getBump(c.commit.message))) + ).filter((bump): bump is + | SEMVER.major + | SEMVER.minor + | SEMVER.patch => Boolean(bump && bump !== "skip")); + + if (prBumps.includes(SEMVER.major)) { + bump = SEMVER.major; + } else if (prBumps.includes(SEMVER.minor)) { + bump = SEMVER.minor; + } else if (prBumps.includes(SEMVER.patch)) { + bump = SEMVER.patch; + } + } + + if (!bump) { + return commit; + } + + const incrementLabel = auto.semVerLabels.get(bump); + + if (incrementLabel && !prHasSemverLabel) { auto.logger.verbose.log( - `Found "${label}" from conventional commit message: ${message}` + endent` + Found "${bump}" from conventional commit message: ${message} + + Applying "${incrementLabel}" + ` ); commit.labels = [...commit.labels, incrementLabel[0]];