Skip to content

Commit 4029650

Browse files
committed
ci(release): automate release preparation and publishing
1 parent 027affc commit 4029650

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Publish Release
2+
3+
on:
4+
pull_request_target:
5+
branches:
6+
- development
7+
types:
8+
- closed
9+
10+
permissions:
11+
contents: write
12+
13+
jobs:
14+
publish-release:
15+
if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'release/next'
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Checkout merged release commit
20+
uses: actions/checkout@v4
21+
with:
22+
ref: ${{ github.event.pull_request.merge_commit_sha }}
23+
fetch-depth: 0
24+
25+
- name: Read release version
26+
id: version
27+
run: |
28+
version="$(tr -d '\n' < VERSION)"
29+
echo "version=${version}" >> "$GITHUB_OUTPUT"
30+
echo "tag=v${version}" >> "$GITHUB_OUTPUT"
31+
32+
- name: Export release notes
33+
run: |
34+
python3 tools/release.py latest-notes > .release-notes.md
35+
cat .release-notes.md >> "$GITHUB_STEP_SUMMARY"
36+
37+
- name: Check whether the tag already exists
38+
id: tag
39+
run: |
40+
if git rev-parse "${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
41+
echo "exists=true" >> "$GITHUB_OUTPUT"
42+
else
43+
echo "exists=false" >> "$GITHUB_OUTPUT"
44+
fi
45+
46+
- name: Create git tag
47+
if: steps.tag.outputs.exists != 'true'
48+
run: |
49+
git config user.name "github-actions[bot]"
50+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
51+
git tag "${{ steps.version.outputs.tag }}" "${{ github.event.pull_request.merge_commit_sha }}"
52+
git push origin "${{ steps.version.outputs.tag }}"
53+
54+
- name: Check whether the GitHub release already exists
55+
id: release
56+
env:
57+
GH_TOKEN: ${{ github.token }}
58+
run: |
59+
if gh release view "${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
60+
echo "exists=true" >> "$GITHUB_OUTPUT"
61+
else
62+
echo "exists=false" >> "$GITHUB_OUTPUT"
63+
fi
64+
65+
- name: Create GitHub release
66+
if: steps.release.outputs.exists != 'true'
67+
env:
68+
GH_TOKEN: ${{ github.token }}
69+
run: |
70+
prerelease_flag=""
71+
case "${{ steps.version.outputs.version }}" in
72+
*-*)
73+
prerelease_flag="--prerelease"
74+
;;
75+
esac
76+
77+
gh release create "${{ steps.version.outputs.tag }}" \
78+
--title "${{ steps.version.outputs.tag }}" \
79+
--notes-file .release-notes.md \
80+
${prerelease_flag}

.github/workflows/release-pr.yml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
name: Prepare Release PR
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- development
8+
9+
permissions:
10+
contents: write
11+
pull-requests: write
12+
13+
concurrency:
14+
group: release-pr-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
prepare-release-pr:
19+
runs-on: ubuntu-latest
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Compute release state
28+
id: versions
29+
run: |
30+
current_version="$(tr -d '\n' < VERSION)"
31+
next_version="$(python3 tools/release.py next-version)"
32+
echo "current_version=${current_version}" >> "$GITHUB_OUTPUT"
33+
echo "next_version=${next_version}" >> "$GITHUB_OUTPUT"
34+
35+
- name: Skip when nothing releasable is pending
36+
if: steps.versions.outputs.current_version == steps.versions.outputs.next_version
37+
run: |
38+
echo "No releasable changesets are pending."
39+
python3 tools/release.py preview --format markdown >> "$GITHUB_STEP_SUMMARY"
40+
41+
- name: Prepare release branch
42+
if: steps.versions.outputs.current_version != steps.versions.outputs.next_version
43+
id: prepare
44+
run: |
45+
python3 tools/release.py apply --output .release-version
46+
release_version="$(tr -d '\n' < .release-version)"
47+
echo "release_version=${release_version}" >> "$GITHUB_OUTPUT"
48+
49+
git config user.name "github-actions[bot]"
50+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
51+
git switch -C release/next
52+
git add VERSION CHANGELOG.md .changesets
53+
git commit -m "chore(release): prepare v${release_version}"
54+
git push --force --set-upstream origin release/next
55+
56+
- name: Create or update release PR
57+
if: steps.versions.outputs.current_version != steps.versions.outputs.next_version
58+
uses: actions/github-script@v7
59+
env:
60+
RELEASE_VERSION: ${{ steps.prepare.outputs.release_version }}
61+
with:
62+
script: |
63+
const owner = context.repo.owner;
64+
const repo = context.repo.repo;
65+
const head = `${owner}:release/next`;
66+
const base = 'development';
67+
const title = `chore(release): prepare v${process.env.RELEASE_VERSION}`;
68+
const marker = '<!-- st-lib-release-pr -->';
69+
const body = `${marker}
70+
71+
This PR was prepared automatically from the pending ST-LIB changesets.
72+
73+
- Version: \`v${process.env.RELEASE_VERSION}\`
74+
- Source of truth: \`VERSION\`
75+
- Release notes source: \`CHANGELOG.md\``;
76+
77+
const { data: pulls } = await github.rest.pulls.list({
78+
owner,
79+
repo,
80+
state: 'open',
81+
head,
82+
base,
83+
});
84+
85+
if (pulls.length > 0) {
86+
await github.rest.pulls.update({
87+
owner,
88+
repo,
89+
pull_number: pulls[0].number,
90+
title,
91+
body,
92+
});
93+
} else {
94+
await github.rest.pulls.create({
95+
owner,
96+
repo,
97+
title,
98+
head: 'release/next',
99+
base,
100+
body,
101+
});
102+
}

0 commit comments

Comments
 (0)