Skip to content

Commit 9a6b05d

Browse files
clydindgp1130
authored andcommitted
build: exclude redundant cherry-picked commits when generating changelog
If generating a changelog between tags that are on different branches (e.g., 9.0.3 on 9.0.x and 9.1.0-next.0 on master), commits that were cherry-picked and present in the previous version would also show in the newer version's changelog. This update analyzes the commits and excludes any that fit this scenario. Any commits that had conflicts will not be able to be matched authoritatively. Manual review of the generated changelog may still be needed for attempted cherry-pick commits that had conflicts.
1 parent 14dc4fb commit 9a6b05d

File tree

1 file changed

+43
-3
lines changed

1 file changed

+43
-3
lines changed

scripts/changelog.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// tslint:disable:no-console
99
// tslint:disable:no-implicit-dependencies
1010
import { JsonObject, logging } from '@angular-devkit/core';
11+
import { execSync } from 'child_process';
1112
import * as fs from 'fs';
1213
import * as path from 'path';
1314
import * as semver from 'semver';
@@ -29,7 +30,16 @@ export interface ChangelogOptions {
2930
stdout?: boolean;
3031
}
3132

32-
export default function(args: ChangelogOptions, logger: logging.Logger) {
33+
function exec(command: string, input?: string): string {
34+
return execSync(command, {
35+
encoding: 'utf8',
36+
stdio: 'pipe',
37+
input,
38+
maxBuffer: 10 * 1024 * 1024,
39+
}).trim();
40+
}
41+
42+
export default async function(args: ChangelogOptions, logger: logging.Logger) {
3343
const commits: JsonObject[] = [];
3444
let toSha: string | null = null;
3545

@@ -39,6 +49,35 @@ export default function(args: ChangelogOptions, logger: logging.Logger) {
3949
''
4050
).trim();
4151

52+
// Validate and scrub commit range options
53+
const from = exec(`git rev-parse --verify "${args.from.replace(/"/g, '')}"`);
54+
if (!from) {
55+
logger.error(`"from" value [${args.from}] is invalid.`);
56+
57+
return;
58+
}
59+
const to = exec(`git rev-parse --verify "${args.to?.replace(/"/g, '') || 'HEAD'}"`);
60+
if (!to) {
61+
logger.error(`"to" value [${args.to}] is invalid.`);
62+
63+
return;
64+
}
65+
66+
// Collect patch identifiers for cherry-pick exclusion
67+
const cherryPicked = new Set<string>();
68+
const patchIds = new Map<string, string>();
69+
const hashes = exec(`git rev-list ${from}...${to}`).split(/\s+/);
70+
for (const hash of hashes) {
71+
const [patchId] = exec('git patch-id', exec('git show ' + hash)).split(/\s+/);
72+
const existing = patchIds.get(patchId);
73+
if (existing) {
74+
cherryPicked.add(existing);
75+
cherryPicked.add(hash);
76+
} else {
77+
patchIds.set(patchId, hash);
78+
}
79+
}
80+
4281
return new Promise(resolve => {
4382
(gitRawCommits({
4483
from: args.from,
@@ -78,8 +117,9 @@ export default function(args: ChangelogOptions, logger: logging.Logger) {
78117
if (tags && tags.find(x => x == args.to)) {
79118
toSha = chunk.hash as string;
80119
}
81-
82-
commits.push(chunk);
120+
if (!cherryPicked.has(chunk.hash as string)) {
121+
commits.push(chunk);
122+
}
83123
cb();
84124
} catch (err) {
85125
cb(err);

0 commit comments

Comments
 (0)