Skip to content

Commit 55cb5a1

Browse files
authored
ci: update comment flow (remix-run#9405)
1 parent 5f3cfb7 commit 55cb5a1

14 files changed

+1774
-284
lines changed

.github/workflows/postrelease.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: 🕊 Post-release
2+
3+
on:
4+
push:
5+
tags:
6+
# only run on `react-router` tags
7+
- "react-router@*"
8+
9+
jobs:
10+
comment:
11+
name: 📝 Comment on related issues and pull requests
12+
if: github.repository == 'remix-run/react-router'
13+
uses: ./.github/workflows/release-comments.yml
14+
with:
15+
ref: ${{ github.ref }}
16+
# this should match the above tag to watch excluding the trailing "@"
17+
packageVersionToFollow: "react-router"

.github/workflows/release-comments.yml

+12-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ on:
66
ref:
77
required: true
88
type: string
9+
packageVersionToFollow:
10+
required: true
11+
type: string
912

1013
jobs:
1114
comment:
@@ -20,16 +23,20 @@ jobs:
2023
uses: actions/setup-node@v3
2124
with:
2225
node-version-file: ".nvmrc"
23-
cache: "yarn"
26+
cache: "npm"
27+
cache-dependency-path: scripts/release/package-lock.json
2428

2529
- name: 📥 Install deps
26-
# even though this is called "npm-install" it does use yarn to install
27-
# because we have a yarn.lock and caches efficiently.
28-
uses: bahmutov/npm-install@v1
30+
run: npm ci
31+
working-directory: ./scripts/release
2932

3033
- name: 📝 Comment on issues
31-
run: node ./scripts/release/comment.mjs
34+
working-directory: ./scripts/release
35+
run: node -r esbuild-register ./comment.ts
3236
env:
3337
GITHUB_REPOSITORY: ${{ github.repository }}
3438
GITHUB_TOKEN: ${{ github.token }}
3539
VERSION: ${{ inputs.ref }}
40+
DEFAULT_BRANCH: "main"
41+
NIGHTLY_BRANCH: "dev"
42+
PACKAGE_VERSION_TO_FOLLOW: ${{ inputs.packageVersionToFollow }}

.github/workflows/release.yml

+1-9
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,5 @@ jobs:
5555
publish: yarn release
5656
createGithubReleases: false
5757
env:
58-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN_SO_OTHER_ACTIONS_RUN }}
5959
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
60-
61-
comment:
62-
needs: [release]
63-
name: 📝 Comment on related issues and pull requests
64-
if: github.repository == 'remix-run/react-router'
65-
uses: remix-run/react-router/.github/workflows/release-comments.yml@main
66-
with:
67-
ref: ${{ github.ref }}

scripts/release/comment.mjs

-66
This file was deleted.

scripts/release/comment.ts

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import {
2+
VERSION,
3+
OWNER,
4+
REPO,
5+
PR_FILES_STARTS_WITH,
6+
IS_NIGHTLY_RELEASE,
7+
AWAITING_RELEASE_LABEL,
8+
} from "./constants";
9+
import {
10+
closeIssue,
11+
commentOnIssue,
12+
commentOnPullRequest,
13+
getIssuesClosedByPullRequests,
14+
prsMergedSinceLastTag,
15+
removeLabel,
16+
} from "./github";
17+
import { getGitHubUrl } from "./utils";
18+
19+
async function commentOnIssuesAndPrsAboutRelease() {
20+
if (VERSION.includes("experimental")) {
21+
return;
22+
}
23+
24+
let { merged, previousTag } = await prsMergedSinceLastTag({
25+
owner: OWNER,
26+
repo: REPO,
27+
githubRef: VERSION,
28+
});
29+
30+
let suffix = merged.length === 1 ? "" : "s";
31+
let prFilesDirs = PR_FILES_STARTS_WITH.join(", ");
32+
console.log(
33+
`Found ${merged.length} PR${suffix} merged ` +
34+
`that touched \`${prFilesDirs}\` since ` +
35+
`previous release (current: ${VERSION}, previous: ${previousTag})`
36+
);
37+
38+
let promises: Array<ReturnType<typeof commentOnIssue>> = [];
39+
let issuesCommentedOn = new Set();
40+
41+
for (let pr of merged) {
42+
console.log(`commenting on pr ${getGitHubUrl("pull", pr.number)}`);
43+
44+
promises.push(
45+
commentOnPullRequest({
46+
owner: OWNER,
47+
repo: REPO,
48+
pr: pr.number,
49+
version: VERSION,
50+
})
51+
);
52+
53+
let prLabels = pr.labels.map((label) => label.name);
54+
let prIsAwaitingRelease = prLabels.includes(AWAITING_RELEASE_LABEL);
55+
56+
if (!IS_NIGHTLY_RELEASE && prIsAwaitingRelease) {
57+
promises.push(
58+
removeLabel({ owner: OWNER, repo: REPO, issue: pr.number })
59+
);
60+
}
61+
62+
let issuesClosed = await getIssuesClosedByPullRequests(
63+
pr.html_url,
64+
pr.body
65+
);
66+
67+
for (let issue of issuesClosed) {
68+
if (issuesCommentedOn.has(issue.number)) {
69+
// we already commented on this issue
70+
// so we don't need to do it again
71+
continue;
72+
}
73+
74+
issuesCommentedOn.add(issue.number);
75+
let issueUrl = getGitHubUrl("issue", issue.number);
76+
77+
if (IS_NIGHTLY_RELEASE || !prIsAwaitingRelease) {
78+
console.log(`commenting on ${issueUrl}`);
79+
promises.push(
80+
commentOnIssue({
81+
owner: OWNER,
82+
repo: REPO,
83+
issue: issue.number,
84+
version: VERSION,
85+
})
86+
);
87+
} else {
88+
console.log(`commenting on and closing ${issueUrl}`);
89+
promises.push(
90+
commentOnIssue({
91+
owner: OWNER,
92+
repo: REPO,
93+
issue: issue.number,
94+
version: VERSION,
95+
})
96+
);
97+
promises.push(
98+
closeIssue({ owner: OWNER, repo: REPO, issue: issue.number })
99+
);
100+
}
101+
}
102+
}
103+
104+
let result = await Promise.allSettled(promises);
105+
let rejected = result.filter((r) => r.status === "rejected");
106+
if (rejected.length > 0) {
107+
console.log(
108+
"🚨 failed to comment on some issues/prs - the most likely reason is they were issues that were turned into discussions, which don't have an api to comment with"
109+
);
110+
console.log(rejected);
111+
}
112+
}
113+
114+
commentOnIssuesAndPrsAboutRelease();

scripts/release/constants.mjs

-18
This file was deleted.

scripts/release/constants.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { cleanupRef, cleanupTagName, isNightly } from "./utils";
2+
3+
if (!process.env.DEFAULT_BRANCH) {
4+
throw new Error("DEFAULT_BRANCH is required");
5+
}
6+
if (!process.env.NIGHTLY_BRANCH) {
7+
throw new Error("NIGHTLY_BRANCH is required");
8+
}
9+
if (!process.env.GITHUB_TOKEN) {
10+
throw new Error("GITHUB_TOKEN is required");
11+
}
12+
if (!process.env.GITHUB_REPOSITORY) {
13+
throw new Error("GITHUB_REPOSITORY is required");
14+
}
15+
if (!process.env.VERSION) {
16+
throw new Error("VERSION is required");
17+
}
18+
if (!/^refs\/tags\//.test(process.env.VERSION)) {
19+
throw new Error("VERSION must start with refs/tags/");
20+
}
21+
if (!process.env.PACKAGE_VERSION_TO_FOLLOW) {
22+
throw new Error("PACKAGE_VERSION_TO_FOLLOW is required");
23+
}
24+
25+
export const [OWNER, REPO] = process.env.GITHUB_REPOSITORY.split("/");
26+
export const PACKAGE_VERSION_TO_FOLLOW = process.env.PACKAGE_VERSION_TO_FOLLOW;
27+
export const VERSION = cleanupTagName(cleanupRef(process.env.VERSION));
28+
export const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
29+
export const GITHUB_REPOSITORY = process.env.GITHUB_REPOSITORY;
30+
export const DEFAULT_BRANCH = process.env.DEFAULT_BRANCH;
31+
export const NIGHTLY_BRANCH = process.env.NIGHTLY_BRANCH;
32+
export const PR_FILES_STARTS_WITH = ["packages/"];
33+
export const IS_NIGHTLY_RELEASE = isNightly(VERSION);
34+
export const AWAITING_RELEASE_LABEL = "awaiting release";

0 commit comments

Comments
 (0)