Skip to content

Commit 3391d3b

Browse files
author
Benjamin E. Coe
authored
refactor!: parse conventional commits in manifest (googleapis#1772)
* refactor: parse conventional commits in manifest Parse conventional commits in manifest, applying plugins earlier before passing to strategy. * chore: add note about plugin
1 parent 0c85dbe commit 3391d3b

32 files changed

+233
-196
lines changed

__snapshots__/base.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ exports['Strategy buildReleasePullRequest allows overriding initial version 1']
88
99
### Miscellaneous Chores
1010
11-
* initial commit ([abc123](https://github.com/googleapis/base-test-repo/commit/abc123))
11+
* initial commit ([16d3754](https://github.com/googleapis/base-test-repo/commit/16d3754a2134a6d19ee19d2e5ba4dfbc))
1212
1313
---
1414
This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
@@ -24,7 +24,7 @@ exports['Strategy buildReleasePullRequest allows overriding initial version in b
2424
2525
### Features
2626
27-
* initial commit ([abc123](https://github.com/googleapis/base-test-repo/commit/abc123))
27+
* initial commit ([a90fc00](https://github.com/googleapis/base-test-repo/commit/a90fc00ca62382346da72dd8f51078a7))
2828
2929
---
3030
This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
@@ -40,7 +40,7 @@ exports['Strategy buildReleasePullRequest should pass changelogHost to default b
4040
4141
### Bug Fixes
4242
43-
* a bugfix ([abc5566](https://example.com/googleapis/base-test-repo/commit/abc5566))
43+
* a bugfix ([6c1715c](https://example.com/googleapis/base-test-repo/commit/6c1715c07438036db68bb939cf36fe6f))
4444
4545
---
4646
This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).

src/manifest.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import {ChangelogSection} from './changelog-notes';
1616
import {GitHub, GitHubRelease, GitHubTag} from './github';
1717
import {Version, VersionsMap} from './version';
18-
import {Commit} from './commit';
18+
import {Commit, parseConventionalCommits} from './commit';
1919
import {PullRequest} from './pull-request';
2020
import {logger as defaultLogger, Logger} from './util/logger';
2121
import {CommitSplit} from './util/commit-split';
@@ -677,7 +677,10 @@ export class Manifest {
677677
);
678678
this.logger.debug(`type: ${config.releaseType}`);
679679
this.logger.debug(`targetBranch: ${this.targetBranch}`);
680-
let pathCommits = commitsPerPath[path];
680+
let pathCommits = parseConventionalCommits(
681+
commitsPerPath[path],
682+
this.logger
683+
);
681684
// The processCommits hook can be implemented by plugins to
682685
// post-process commits. This can be used to perform cleanup, e.g,, sentence
683686
// casing all commit messages:

src/plugin.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import {GitHub} from './github';
1616
import {CandidateReleasePullRequest, RepositoryConfig} from './manifest';
1717
import {Strategy} from './strategy';
18-
import {Commit} from './commit';
18+
import {Commit, ConventionalCommit} from './commit';
1919
import {Release} from './release';
2020
import {logger as defaultLogger, Logger} from './util/logger';
2121

@@ -47,9 +47,7 @@ export abstract class ManifestPlugin {
4747
* @param {Commit[]} commits The set of commits that will feed into release pull request.
4848
* @returns {Commit[]} The modified commit objects.
4949
*/
50-
// TODO: for next major version, let's run the default conventional commit parser earlier
51-
// (outside of the strategy classes) and pass in the ConventionalCommit[] objects in.
52-
processCommits(commits: Commit[]): Commit[] {
50+
processCommits(commits: ConventionalCommit[]): ConventionalCommit[] {
5351
return commits;
5452
}
5553

src/plugins/linked-versions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {RepositoryConfig, CandidateReleasePullRequest} from '../manifest';
1717
import {GitHub} from '../github';
1818
import {Logger} from '../util/logger';
1919
import {Strategy} from '../strategy';
20-
import {Commit} from '../commit';
20+
import {Commit, parseConventionalCommits} from '../commit';
2121
import {Release} from '../release';
2222
import {Version} from '../version';
2323
import {buildStrategy} from '../factory';
@@ -87,7 +87,7 @@ export class LinkedVersions extends ManifestPlugin {
8787
const strategy = groupStrategies[path];
8888
const latestRelease = releasesByPath[path];
8989
const releasePullRequest = await strategy.buildReleasePullRequest(
90-
commitsByPath[path],
90+
parseConventionalCommits(commitsByPath[path], this.logger),
9191
latestRelease
9292
);
9393
if (releasePullRequest?.version) {

src/plugins/sentence-case.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import {ManifestPlugin} from '../plugin';
1616
import {GitHub} from '../github';
1717
import {RepositoryConfig} from '../manifest';
18-
import {Commit} from '../commit';
18+
import {ConventionalCommit} from '../commit';
1919

2020
// A list of words that should not be converted to uppercase:
2121
const SPECIAL_WORDS = ['gRPC', 'npm'];
@@ -43,9 +43,13 @@ export class SentenceCase extends ManifestPlugin {
4343
* @param {Commit[]} commits The set of commits that will feed into release pull request.
4444
* @returns {Commit[]} The modified commit objects.
4545
*/
46-
processCommits(commits: Commit[]): Commit[] {
46+
processCommits(commits: ConventionalCommit[]): ConventionalCommit[] {
4747
this.logger.info(`SentenceCase processing ${commits.length} commits`);
4848
for (const commit of commits) {
49+
// The parsed conventional commit message, without the type:
50+
console.info(commit.bareMessage);
51+
commit.bareMessage = this.toUpperCase(commit.bareMessage);
52+
4953
// Check whether commit is in conventional commit format, if it is
5054
// we'll split the string by type and description:
5155
if (commit.message.includes(':')) {

src/strategies/base.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
import {DefaultVersioningStrategy} from '../versioning-strategies/default';
2626
import {DefaultChangelogNotes} from '../changelog-notes/default';
2727
import {Update} from '../update';
28-
import {ConventionalCommit, Commit, parseConventionalCommits} from '../commit';
28+
import {ConventionalCommit, Commit} from '../commit';
2929
import {Version, VersionsMap} from '../version';
3030
import {TagName} from '../util/tag-name';
3131
import {Release} from '../release';
@@ -249,14 +249,12 @@ export abstract class BaseStrategy implements Strategy {
249249
* open a pull request.
250250
*/
251251
async buildReleasePullRequest(
252-
commits: Commit[],
252+
commits: ConventionalCommit[],
253253
latestRelease?: Release,
254254
draft?: boolean,
255255
labels: string[] = []
256256
): Promise<ReleasePullRequest | undefined> {
257-
const conventionalCommits = await this.postProcessCommits(
258-
parseConventionalCommits(commits, this.logger)
259-
);
257+
const conventionalCommits = await this.postProcessCommits(commits);
260258
this.logger.info(`Considering: ${conventionalCommits.length} commits`);
261259
if (conventionalCommits.length === 0) {
262260
this.logger.info(`No commits for path: ${this.path}, skipping`);

src/strategies/java.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {Version} from '../version';
1717
import {BaseStrategy, BaseStrategyOptions, BuildUpdatesOptions} from './base';
1818
import {Changelog} from '../updaters/changelog';
1919
import {JavaSnapshot} from '../versioning-strategies/java-snapshot';
20-
import {Commit} from '../commit';
20+
import {ConventionalCommit} from '../commit';
2121
import {Release} from '../release';
2222
import {ReleasePullRequest} from '../release-pull-request';
2323
import {PullRequestTitle} from '../util/pull-request-title';
@@ -74,7 +74,7 @@ export class Java extends BaseStrategy {
7474
}
7575

7676
async buildReleasePullRequest(
77-
commits: Commit[],
77+
commits: ConventionalCommit[],
7878
latestRelease?: Release,
7979
draft?: boolean,
8080
labels: string[] = []
@@ -156,7 +156,7 @@ export class Java extends BaseStrategy {
156156
}
157157

158158
protected async needsSnapshot(
159-
commits: Commit[],
159+
commits: ConventionalCommit[],
160160
latestRelease?: Release
161161
): Promise<boolean> {
162162
if (this.skipSnapshot) {

test/helpers.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ import * as snapshot from 'snap-shot-it';
2020
import * as suggester from 'code-suggester';
2121
import {CreatePullRequestUserOptions} from 'code-suggester/build/src/types';
2222
import {Octokit} from '@octokit/rest';
23-
import {Commit} from '../src/commit';
23+
import {
24+
Commit,
25+
ConventionalCommit,
26+
parseConventionalCommits,
27+
} from '../src/commit';
2428
import {GitHub, GitHubTag, GitHubRelease} from '../src/github';
2529
import {Update} from '../src/update';
2630
import {expect} from 'chai';
@@ -110,6 +114,23 @@ export function readPOJO(name: string): object {
110114
return JSON.parse(content);
111115
}
112116

117+
export function buildMockConventionalCommit(
118+
message: string,
119+
files: string[] = []
120+
): ConventionalCommit[] {
121+
return parseConventionalCommits([
122+
{
123+
// Ensure SHA is same on Windows with replace:
124+
sha: crypto
125+
.createHash('md5')
126+
.update(message.replace(/\r\n/g, '\n'))
127+
.digest('hex'),
128+
message,
129+
files: files,
130+
},
131+
]);
132+
}
133+
113134
export function buildMockCommit(message: string, files: string[] = []): Commit {
114135
return {
115136
// Ensure SHA is same on Windows with replace:
@@ -121,6 +142,7 @@ export function buildMockCommit(message: string, files: string[] = []): Commit {
121142
files: files,
122143
};
123144
}
145+
124146
export function buildGitHubFileContent(
125147
fixturesPath: string,
126148
fixture: string

test/manifest.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2724,7 +2724,7 @@ describe('Manifest', () => {
27242724
mockCommits(sandbox, github, [
27252725
{
27262726
sha: 'aaaaaa',
2727-
message: 'fix: some bugfix',
2727+
message: 'fix: some bugfix\nfix:another fix',
27282728
files: ['path/a/foo'],
27292729
},
27302730
{
@@ -2854,14 +2854,13 @@ describe('Manifest', () => {
28542854
});
28552855

28562856
it('should apply plugin hook "processCommits"', async () => {
2857-
const mockPlugin = sandbox.createStubInstance(SentenceCase);
2858-
mockPlugin.run.returnsArg(0);
2859-
mockPlugin.preconfigure.returnsArg(0);
2860-
mockPlugin.processCommits.returnsArg(0);
2857+
const spyPlugin = sinon.spy(new SentenceCase(github, 'main', {}));
28612858
sandbox
28622859
.stub(pluginFactory, 'buildPlugin')
28632860
.withArgs(sinon.match.has('type', 'sentence-case'))
2864-
.returns(mockPlugin);
2861+
// TS compiler is having issues with sinon.spy.
2862+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2863+
.returns(spyPlugin as any as InstanceType<typeof SentenceCase>);
28652864
const manifest = new Manifest(
28662865
github,
28672866
'main',
@@ -2881,7 +2880,34 @@ describe('Manifest', () => {
28812880
);
28822881
const pullRequests = await manifest.buildPullRequests();
28832882
expect(pullRequests).not.empty;
2884-
sinon.assert.calledOnce(mockPlugin.processCommits);
2883+
// This assertion verifies that conventional commit parsing
2884+
// was applied before calling the processCommits plugin hook:
2885+
sinon.assert.calledWith(spyPlugin.processCommits, [
2886+
{
2887+
sha: 'aaaaaa',
2888+
message: 'fix: Another fix',
2889+
files: ['path/a/foo'],
2890+
pullRequest: undefined,
2891+
type: 'fix',
2892+
scope: null,
2893+
bareMessage: 'Another fix',
2894+
notes: [],
2895+
references: [],
2896+
breaking: false,
2897+
},
2898+
{
2899+
sha: 'aaaaaa',
2900+
message: 'fix: Some bugfix',
2901+
files: ['path/a/foo'],
2902+
pullRequest: undefined,
2903+
type: 'fix',
2904+
scope: null,
2905+
bareMessage: 'Some bugfix',
2906+
notes: [],
2907+
references: [],
2908+
breaking: false,
2909+
},
2910+
]);
28852911
});
28862912
});
28872913

test/plugins/sentence-case.ts

Lines changed: 14 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {SentenceCase} from '../../src/plugins/sentence-case';
1616
import {expect} from 'chai';
1717

1818
import {GitHub} from '../../src/github';
19+
import {buildMockConventionalCommit} from '../helpers';
1920

2021
describe('SentenceCase Plugin', () => {
2122
let github: GitHub;
@@ -30,44 +31,26 @@ describe('SentenceCase Plugin', () => {
3031
it('converts description to sentence case', async () => {
3132
const plugin = new SentenceCase(github, 'main', {});
3233
const commits = await plugin.processCommits([
33-
{
34-
sha: 'abc123',
35-
message: 'fix: hello world',
36-
},
37-
{
38-
sha: 'abc123',
39-
message: 'fix: Goodnight moon',
40-
},
34+
...buildMockConventionalCommit('fix: hello world'),
35+
...buildMockConventionalCommit('fix: Goodnight moon'),
4136
]);
4237
expect(commits[0].message).to.equal('fix: Hello world');
4338
expect(commits[1].message).to.equal('fix: Goodnight moon');
4439
});
4540
it('leaves reserved words lowercase', async () => {
4641
const plugin = new SentenceCase(github, 'main', {});
4742
const commits = await plugin.processCommits([
48-
{
49-
sha: 'abc123',
50-
message: 'feat: gRPC can now handle proxies',
51-
},
52-
{
53-
sha: 'abc123',
54-
message: 'fix: npm now rocks',
55-
},
43+
...buildMockConventionalCommit('feat: gRPC can now handle proxies'),
44+
...buildMockConventionalCommit('fix: npm now rocks'),
5645
]);
5746
expect(commits[0].message).to.equal('feat: gRPC can now handle proxies');
5847
expect(commits[1].message).to.equal('fix: npm now rocks');
5948
});
6049
it('handles sentences with now breaks', async () => {
6150
const plugin = new SentenceCase(github, 'main', {});
6251
const commits = await plugin.processCommits([
63-
{
64-
sha: 'abc123',
65-
message: 'feat: beep-boop-hello',
66-
},
67-
{
68-
sha: 'abc123',
69-
message: 'fix:log4j.foo.bar',
70-
},
52+
...buildMockConventionalCommit('feat: beep-boop-hello'),
53+
...buildMockConventionalCommit('fix:log4j.foo.bar'),
7154
]);
7255
expect(commits[0].message).to.equal('feat: Beep-boop-hello');
7356
expect(commits[1].message).to.equal('fix: Log4j.foo.bar');
@@ -76,39 +59,29 @@ describe('SentenceCase Plugin', () => {
7659
it('allows a custom list of specialWords to be provided', async () => {
7760
const plugin = new SentenceCase(github, 'main', {}, ['hello']);
7861
const commits = await plugin.processCommits([
79-
{
80-
sha: 'abc123',
81-
message: 'fix: hello world',
82-
},
83-
{
84-
sha: 'abc123',
85-
message: 'fix: Goodnight moon',
86-
},
62+
...buildMockConventionalCommit('fix: hello world'),
63+
...buildMockConventionalCommit('fix: Goodnight moon'),
8764
]);
8865
expect(commits[0].message).to.equal('fix: hello world');
8966
expect(commits[1].message).to.equal('fix: Goodnight moon');
9067
});
9168
it('handles subject with multiple : characters', async () => {
9269
const plugin = new SentenceCase(github, 'main', {}, []);
9370
const commits = await plugin.processCommits([
94-
{
95-
sha: 'abc123',
96-
message: 'fix: hello world:goodnight moon',
97-
},
71+
...buildMockConventionalCommit('abc123'),
72+
...buildMockConventionalCommit('fix: hello world:goodnight moon'),
9873
]);
9974
expect(commits[0].message).to.equal('fix: Hello world:goodnight moon');
10075
});
10176
it('handles commit with no :', async () => {
10277
const plugin = new SentenceCase(github, 'main', {}, []);
10378
const commits = await plugin.processCommits([
104-
{
105-
sha: 'abc123',
106-
message: 'hello world goodnight moon',
107-
},
79+
...buildMockConventionalCommit('hello world goodnight moon'),
10880
]);
10981
// Ensure there's no exception, a commit without a <type> is not
11082
// a conventional commit, and will not show up in CHANGELOG. We
11183
// Do not bother sentence-casing:
112-
expect(commits[0].message).to.equal('hello world goodnight moon');
84+
console.info(commits);
85+
expect(commits.length).to.equal(0);
11386
});
11487
});

0 commit comments

Comments
 (0)