Skip to content

Commit 0eefc4d

Browse files
committed
ci: sync release automation
1 parent 1d384dd commit 0eefc4d

3 files changed

Lines changed: 115 additions & 1 deletion

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ jobs:
1818
default:
1919
name: CI
2020
runs-on: ubuntu-latest
21+
if: >-
22+
github.event_name != 'pull_request' ||
23+
github.event.pull_request.title != '[Release] Version packages'
2124
2225
steps:
2326
- name: Checkout

.github/workflows/release.yml

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,85 @@ jobs:
3131
# @link https://github.com/actions/checkout#fetch-all-history-for-all-tags-and-branches
3232
fetch-depth: 0
3333

34+
- name: 🔎 Detect auto-release opt-in
35+
id: auto_release
36+
uses: actions/github-script@v7
37+
with:
38+
script: |
39+
const { pathToFileURL } = await import('node:url');
40+
const helperUrl = pathToFileURL(
41+
`${process.env.GITHUB_WORKSPACE}/tooling/auto-release-pr.mjs`
42+
).href;
43+
const { hasChangesetFile, isAutoReleaseChecked } = await import(helperUrl);
44+
45+
const owner = context.repo.owner;
46+
const repo = context.repo.repo;
47+
const pullNumbers = new Set();
48+
49+
const { data: associatedPullRequests } =
50+
await github.rest.repos.listPullRequestsAssociatedWithCommit({
51+
owner,
52+
repo,
53+
commit_sha: context.sha,
54+
});
55+
56+
for (const pullRequest of associatedPullRequests) {
57+
pullNumbers.add(pullRequest.number);
58+
}
59+
60+
const headCommitMessage = context.payload.head_commit?.message ?? '';
61+
for (const match of headCommitMessage.matchAll(/\(#(\d+)\)|#(\d+)/g)) {
62+
const pullNumber = Number(match[1] ?? match[2]);
63+
64+
if (pullNumber) pullNumbers.add(pullNumber);
65+
}
66+
67+
for (const pullNumber of pullNumbers) {
68+
let pullRequest;
69+
70+
try {
71+
const { data } = await github.rest.pulls.get({
72+
owner,
73+
repo,
74+
pull_number: pullNumber,
75+
});
76+
77+
pullRequest = data;
78+
} catch (error) {
79+
core.warning(`Could not read PR #${pullNumber}: ${error.message}`);
80+
continue;
81+
}
82+
83+
if (!pullRequest.merged_at) {
84+
core.info(`Skipping PR #${pullRequest.number}; it is not merged.`);
85+
continue;
86+
}
87+
88+
if (!isAutoReleaseChecked(pullRequest.body ?? '')) {
89+
core.info(`Skipping PR #${pullRequest.number}; auto-release is unchecked.`);
90+
continue;
91+
}
92+
93+
const files = await github.paginate(github.rest.pulls.listFiles, {
94+
owner,
95+
repo,
96+
pull_number: pullRequest.number,
97+
per_page: 100,
98+
});
99+
100+
if (!hasChangesetFile(files)) {
101+
core.info(`Skipping PR #${pullRequest.number}; no changeset file found.`);
102+
continue;
103+
}
104+
105+
core.setOutput('enabled', 'true');
106+
core.setOutput('source_pr', String(pullRequest.number));
107+
core.notice(`Auto-release enabled by PR #${pullRequest.number}.`);
108+
return;
109+
}
110+
111+
core.setOutput('enabled', 'false');
112+
34113
- uses: oven-sh/setup-bun@v2
35114
name: Install bun
36115
with:
@@ -69,5 +148,20 @@ jobs:
69148
# See https://github.com/changesets/action/issues/147
70149
HOME: ${{ github.workspace }}
71150
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
72-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
151+
GITHUB_TOKEN: ${{ secrets.API_TOKEN_GITHUB || secrets.GITHUB_TOKEN }}
73152
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
153+
154+
- name: 🤖 Merge Version Packages PR
155+
if: ${{ steps.auto_release.outputs.enabled == 'true' && steps.changesets.outputs.pullRequestNumber != '' }}
156+
env:
157+
GH_TOKEN: ${{ secrets.API_TOKEN_GITHUB }}
158+
RELEASE_PR: ${{ steps.changesets.outputs.pullRequestNumber }}
159+
SOURCE_PR: ${{ steps.auto_release.outputs.source_pr }}
160+
run: |
161+
if [[ -z "${GH_TOKEN}" ]]; then
162+
echo "API_TOKEN_GITHUB is required so the merged release PR can trigger publish workflows."
163+
exit 1
164+
fi
165+
166+
gh pr comment "$RELEASE_PR" --body "Merging because PR #${SOURCE_PR} checked auto release."
167+
gh pr merge "$RELEASE_PR" --squash --delete-branch --admin

tooling/auto-release-pr.mjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const checkedAutoReleasePattern = /-\s*\[[xX]\]\s*Auto release/;
2+
3+
export function hasChangesetFile(files) {
4+
return files.some((file) => {
5+
const filename = typeof file === 'string' ? file : file.filename;
6+
7+
return (
8+
filename?.startsWith('.changeset/') &&
9+
filename.endsWith('.md') &&
10+
filename !== '.changeset/README.md'
11+
);
12+
});
13+
}
14+
15+
export function isAutoReleaseChecked(body = '') {
16+
return checkedAutoReleasePattern.test(body);
17+
}

0 commit comments

Comments
 (0)