Skip to content

Commit c793718

Browse files
committed
fixup! build: group changelog entries by packages
Address feedback
1 parent f5d0aaf commit c793718

File tree

4 files changed

+100
-36
lines changed

4 files changed

+100
-36
lines changed

CONTRIBUTING.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,21 +166,37 @@ we use the git commit messages to **generate the Angular Material change log**.
166166

167167
### Commit Message Format
168168
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
169-
format that includes a **type**, a **scope** and a **subject**:
169+
format that includes a **type**, a **package**, a **scope** and a **subject**:
170170

171171
```
172-
<type>(<scope>): <subject>
172+
<type>(<package>/<scope>): <subject>
173173
<BLANK LINE>
174174
<body>
175175
<BLANK LINE>
176176
<footer>
177177
```
178178

179-
The **header** is mandatory and the **scope** of the header is optional.
179+
The **header** is mandatory. For changes which are shown in the changelog (`fix`, `feat`,
180+
`perf` and `revert`), the **package** and **scope** fields are mandatory.
181+
182+
The `package` and `scope` fields can be omitted if the change does not affect a specific
183+
package and is not displayed in the changelog (e.g. build changes or refactorings).
180184

181185
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
182186
to read on GitHub as well as in various git tools.
183187

188+
Example:
189+
190+
```
191+
fix(material/button): unable to disable button through binding
192+
193+
Fixes a bug in the Angular Material `button` component where buttons
194+
cannot be disabled through an binding. This is because the `disabled`
195+
input did not set the `.mat-button-disabled` class on the host element.
196+
197+
Fixes #1234
198+
```
199+
184200
### Revert
185201
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of
186202
the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is
@@ -201,6 +217,10 @@ Must be one of the following:
201217
(example scopes: gulp, broccoli, npm)
202218
* **chore**: Other changes that don't modify `src` or `test` files
203219
220+
### Package
221+
The commit message should specify which package is affected by the change. For example:
222+
`material`, `cdk-experimental`, etc.
223+
204224
### Scope
205225
The scope could be anything specifying place of the commit change. For example
206226
`datepicker`, `dialog`, etc.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"stage-release": "ts-node --project tools/release/ tools/release/stage-release.ts",
3030
"publish-release": "ts-node --project tools/release/ tools/release/publish-release.ts",
3131
"check-release-output": "ts-node --project tools/release tools/release/check-release-output.ts",
32+
"changelog": "ts-node --project tools/release tools/release/changelog.ts",
3233
"preinstall": "node ./tools/npm/check-npm.js",
3334
"format:ts": "git-clang-format HEAD $(git diff HEAD --name-only | grep -v \"\\.d\\.ts\")",
3435
"format:bazel": "yarn -s bazel:buildifier --lint=fix --mode=fix",

tools/release/changelog-root-template.hbs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33
{{#each packageGroups}}
44
### {{title}}
55

6+
{{#if breakingChanges.length}}
7+
_Breaking changes:_
8+
9+
{{#each breakingChanges}}
10+
* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}}
11+
{{/each}}
12+
13+
{{/if}}
614
| | |
715
| ---------- | --------------------- |
816
{{#each commits}}
9-
| <img src="{{typeImageUrl}}" alt="{{typeDescription}}"> | {{> commit root=@root}} |
17+
| {{type}} | {{> commit root=@root}} |
1018
{{/each}}
1119

1220
{{/each}}
1321

14-
{{> footer}}
15-

tools/release/changelog.ts

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ const conventionalChangelog = require('conventional-changelog');
1010
const changelogCompare = require('conventional-changelog-writer/lib/util');
1111
const merge2 = require('merge2');
1212

13+
/** Interface that describes a package in the changelog. */
14+
interface ChangelogPackage {
15+
commits: any[];
16+
breakingChanges: any[];
17+
}
18+
19+
/** Hardcoded order of packages shown in the changelog. */
20+
const changelogPackageOrder = [
21+
'cdk',
22+
'material',
23+
'google-maps',
24+
'youtube-player',
25+
'material-moment-adapter',
26+
'cdk-experimental',
27+
'material-experimental',
28+
];
29+
1330
/** Prompts for a changelog release name and prepends the new changelog. */
1431
export async function promptAndGenerateChangelog(changelogPath: string) {
1532
const releaseName = await promptChangelogReleaseName();
@@ -80,14 +97,15 @@ function createChangelogWriterOptions(changelogPath: string) {
8097

8198
return {
8299
// Overwrite the changelog templates so that we can render the commits grouped
83-
// by package names.
100+
// by package names. Templates are based on the original templates of the
101+
// angular preset: "conventional-changelog-angular/templates".
84102
mainTemplate: readFileSync(join(__dirname, 'changelog-root-template.hbs'), 'utf8'),
85103
commitPartial: readFileSync(join(__dirname, 'changelog-commit-template.hbs'), 'utf8'),
86104

87105
// Specify a writer option that can be used to modify the content of a new changelog section.
88106
// See: conventional-changelog/tree/master/packages/conventional-changelog-writer
89107
finalizeContext: (context: any) => {
90-
const packageGroups: {[packageName: string]: any[]} = {};
108+
const packageGroups: {[packageName: string]: ChangelogPackage} = {};
91109

92110
context.commitGroups.forEach((group: any) => {
93111
group.commits.forEach((commit: any) => {
@@ -115,48 +133,67 @@ function createChangelogWriterOptions(changelogPath: string) {
115133
// require specifying the "material" package explicitly, we can remove
116134
// the fallback to the "material" package.
117135
const packageName = commit.package || 'material';
118-
const {color, title} = getTitleAndColorOfTypeLabel(commit.type);
136+
const type = getTypeOfCommitGroupDescription(group.title);
119137

120138
if (!packageGroups[packageName]) {
121-
packageGroups[packageName] = [];
139+
packageGroups[packageName] = {commits: [], breakingChanges: []};
122140
}
141+
const packageGroup = packageGroups[packageName];
123142

124-
packageGroups[packageName].push({
125-
typeDescription: title,
126-
typeImageUrl: `https://img.shields.io/badge/-${title}-${color}`,
127-
...commit
128-
});
143+
packageGroup.breakingChanges.push(...commit.notes);
144+
packageGroup.commits.push({...commit, type});
129145
});
130146
});
131147

132-
context.packageGroups = Object.keys(packageGroups).sort().map(pkgName => {
133-
return {
134-
title: pkgName,
135-
commits: packageGroups[pkgName].sort(commitSortFunction),
136-
};
137-
});
148+
context.packageGroups =
149+
Object.keys(packageGroups).sort(preferredOrderComparator).map(pkgName => {
150+
const packageGroup = packageGroups[pkgName];
151+
return {
152+
title: pkgName,
153+
commits: packageGroup.commits.sort(commitSortFunction),
154+
breakingChanges: packageGroup.breakingChanges,
155+
};
156+
});
138157

139158
return context;
140159
}
141160
};
142161
}
143162

144-
/** Gets the title and color from a commit type label. */
145-
function getTitleAndColorOfTypeLabel(typeLabel: string): {title: string, color: string} {
146-
if (typeLabel === `Features`) {
147-
return {title: 'feature', color: 'green'};
148-
} else if (typeLabel === `Bug Fixes`) {
149-
return {title: 'bug fix', color: 'orange'};
150-
} else if (typeLabel === `Performance Improvements`) {
151-
return {title: 'performance', color: 'blue'};
152-
} else if (typeLabel === `Reverts`) {
153-
return {title: 'revert', color: 'grey'};
154-
} else if (typeLabel === `Documentation`) {
155-
return {title: 'docs', color: 'darkgreen'};
156-
} else if (typeLabel === `refactor`) {
157-
return {title: 'refactor', color: 'lightgrey'};
163+
/**
164+
* Comparator function that sorts a given array of strings based on the
165+
* hardcoded changelog package order. Entries which are not hardcoded are
166+
* sorted in alphabetical order after the hardcoded entries.
167+
*/
168+
function preferredOrderComparator(a: string, b: string): number {
169+
const aIndex = changelogPackageOrder.indexOf(a);
170+
const bIndex = changelogPackageOrder.indexOf(b);
171+
// If a package name could not be found in the hardcoded order, it should be
172+
// sorted after the hardcoded entries in alphabetical order.
173+
if (aIndex === -1) {
174+
return bIndex === -1 ? a.localeCompare(b) : 1;
175+
} else if (bIndex === -1) {
176+
return -1;
177+
}
178+
return aIndex - bIndex;
179+
}
180+
181+
/** Gets the type of a commit group description. */
182+
function getTypeOfCommitGroupDescription(description: string): string {
183+
if (description === 'Features') {
184+
return 'feature';
185+
} else if (description === 'Bug Fixes') {
186+
return 'bug fix';
187+
} else if (description === 'Performance Improvements') {
188+
return 'performance';
189+
} else if (description === 'Reverts') {
190+
return 'revert';
191+
} else if (description === 'Documentation') {
192+
return 'docs';
193+
} else if (description === 'Code Refactoring') {
194+
return 'refactor';
158195
}
159-
return {title: typeLabel, color: 'yellow'};
196+
return description.toLowerCase();
160197
}
161198

162199
/** Entry-point for generating the changelog when called through the CLI. */

0 commit comments

Comments
 (0)