Skip to content

Commit e8bb005

Browse files
committed
add validation for dont-land labels
1 parent eae03e3 commit e8bb005

File tree

2 files changed

+42
-11
lines changed

2 files changed

+42
-11
lines changed

.github/workflows/lint-release-proposal.yml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,15 @@ jobs:
6161
gh api \
6262
-H "Accept: application/vnd.github+json" \
6363
-H "X-GitHub-Api-Version: 2022-11-28" \
64-
--jq '.commits | map({ smallSha: .sha[0:10], splitTitle: .commit.message|split("\n\n")|first|split(":") })' \
65-
"/repos/${GITHUB_REPOSITORY}/compare/v${MAJOR}.x...$GITHUB_SHA" --paginate |\
66-
jq -r '.[] | "* [[`" + .smallSha + "`](" + env.GITHUB_SERVER_URL + "/" + env.GITHUB_REPOSITORY + "/commit/" + .smallSha + ")] - **" + (.splitTitle|first) + "**:" + (.splitTitle[1:]|join(":"))' |\
67-
node tools/actions/lint-release-proposal-commit-list.mjs "$CHANGELOG_PATH" "$GITHUB_SHA"
64+
--jq '.commits.[] | { smallSha: .sha[0:10], splitTitle: .commit.message|split("\n\n")|first|split(":") } + (.commit.message|capture("\nPR-URL: (?<prURL>.+)\n"))' \
65+
"/repos/${GITHUB_REPOSITORY}/compare/v${MAJOR}.x...$GITHUB_SHA" --paginate \
66+
| node tools/actions/lint-release-proposal-commit-list.mjs "$CHANGELOG_PATH" "$GITHUB_SHA" \
67+
| while IFS= read -r PR_URL; do
68+
LABEL="dont-land-on-v${MAJOR}.x" gh pr view \
69+
--json labels,url \
70+
--jq 'if (.labels|map(.name==env.LABEL)|any) then error("\(.url) has the \(env.LABEL) label, forbidding it to be in this release proposal") end' \
71+
"$PR_URL" > /dev/null
72+
done
73+
shell: bash # See https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference, we want the pipefail option
6874
env:
6975
GH_TOKEN: ${{ github.token }}
Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,61 @@
11
#!/usr/bin/env node
22

3+
// Takes a stream of JSON objects as inputs, validates the CHANGELOG contains a
4+
// line corresponding, then outputs the prURL value.
5+
//
6+
// $ ./lint-release-proposal-commit-list.mjs "path/to/CHANGELOG.md" "deadbeef00" <<'EOF'
7+
// {"prURL":"https://github.com/nodejs/node/pull/56131","smallSha":"d48b5224c0","splitTitle":["doc"," fix module.md headings"]}
8+
// {"prURL":"https://github.com/nodejs/node/pull/56123","smallSha":"f1c2d2f65e","splitTitle":["doc"," update blog release-post link"]}
9+
// EOF
10+
311
const [,, CHANGELOG_PATH, RELEASE_COMMIT_SHA] = process.argv;
412

513
import assert from 'node:assert';
614
import { readFile } from 'node:fs/promises';
715
import { createInterface } from 'node:readline';
816

9-
// Creating the iterator early to avoid missing any data
17+
// Creating the iterator early to avoid missing any data:
1018
const stdinLineByLine = createInterface(process.stdin)[Symbol.asyncIterator]();
1119

1220
const changelog = await readFile(CHANGELOG_PATH, 'utf-8');
13-
const startCommitListing = changelog.indexOf('\n### Commits\n');
14-
const commitList = changelog.slice(startCommitListing, changelog.indexOf('\n\n<a', startCommitListing))
21+
const commitListingStart = changelog.indexOf('\n### Commits\n');
22+
const commitListingEnd = changelog.indexOf('\n\n<a', commitListingStart);
23+
const commitList = changelog.slice(commitListingStart, commitListingEnd === -1 ? undefined : commitListingEnd + 1)
1524
// Checking for semverness is too expansive, it is left as a exercice for human reviewers.
1625
.replaceAll('**(SEMVER-MINOR)** ', '')
1726
// Correct Markdown escaping is validated by the linter, getting rid of it here helps.
1827
.replaceAll('\\', '');
1928

2029
let expectedNumberOfCommitsLeft = commitList.match(/\n\* \[/g).length;
2130
for await (const line of stdinLineByLine) {
22-
if (line.includes(RELEASE_COMMIT_SHA.slice(0, 10))) {
31+
const { smallSha, splitTitle, prURL } = JSON.parse(line);
32+
33+
if (smallSha === RELEASE_COMMIT_SHA.slice(0, 10)) {
2334
assert.strictEqual(
2435
expectedNumberOfCommitsLeft, 0,
2536
'Some commits are listed without being included in the proposal, or are listed more than once',
2637
);
2738
continue;
2839
}
2940

30-
// Revert commit have a special treatment.
31-
const fixedLine = line.replace(' - **Revert \"', ' - _**Revert**_ "**');
41+
const lineStart = commitList.indexOf(`\n* \[[\`${smallSha}\`]`);
42+
assert.notStrictEqual(lineStart, -1, `Cannot find ${smallSha} on the list`);
43+
const lineEnd = commitList.indexOf('\n', lineStart + 1);
44+
45+
const expectedCommitTitle = `${`**${splitTitle.shift()}`.replace('**Revert \"', '_**Revert**_ "**')}**:${splitTitle.join(':')}`;
46+
try {
47+
assert(commitList.lastIndexOf(`/${smallSha})] - ${expectedCommitTitle} (`, lineEnd) > lineStart, `Commit title doesn't match`);
48+
} catch (e) {
49+
if (e?.code === 'ERR_ASSERTION') {
50+
e.operator = 'includes';
51+
e.expected = expectedCommitTitle;
52+
e.actual = commitList.slice(lineStart + 1, lineEnd);
53+
}
54+
throw e;
55+
}
56+
assert.strictEqual(commitList.slice(lineEnd - prURL.length - 2, lineEnd), `(${prURL})`);
3257

33-
assert(commitList.includes('\n' + fixedLine), `Missing "${fixedLine}" in commit list`);
3458
expectedNumberOfCommitsLeft--;
59+
console.log(prURL);
3560
}
3661
assert.strictEqual(expectedNumberOfCommitsLeft, 0, 'Release commit is not the last commit in the proposal');

0 commit comments

Comments
 (0)