Skip to content

Commit ca7de73

Browse files
committed
chore: automate sdk release from stable
1 parent bbf2cbb commit ca7de73

5 files changed

Lines changed: 52 additions & 11 deletions

File tree

.github/workflows/release-cli.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ permissions:
2929
packages: write
3030

3131
concurrency:
32-
group: release-cli-${{ github.ref }}
33-
cancel-in-progress: true
32+
group: ${{ github.ref_name == 'stable' && 'release-stable-writeback' || format('{0}-{1}', github.workflow, github.ref) }}
33+
cancel-in-progress: ${{ github.ref_name != 'stable' }}
3434

3535
jobs:
3636
release:
@@ -48,6 +48,12 @@ jobs:
4848
fetch-depth: 0
4949
token: ${{ steps.generate_token.outputs.token }}
5050

51+
- name: Refresh stable branch head
52+
if: github.ref_name == 'stable'
53+
run: |
54+
git fetch origin "${{ github.ref_name }}" --tags
55+
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"
56+
5157
- uses: pnpm/action-setup@v4
5258

5359
- uses: actions/setup-node@v6

.github/workflows/release-sdk.yml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
# Auto-releases SDK on push to main (@next channel).
2-
# Stable releases are local-only (pnpm run release:local).
1+
# Auto-releases SDK on push to:
2+
# - main (@next channel)
3+
# - stable (@latest channel)
34
# Also supports manual dispatch as a fallback for one-off releases.
45
name: "\U0001F4E6 Release SDK"
56

67
on:
78
push:
89
branches:
910
- main
11+
- stable
1012
paths:
1113
# Keep in sync with packages/sdk/.releaserc.cjs includePaths (patch-commit-filter).
1214
- 'packages/sdk/**'
@@ -44,8 +46,8 @@ permissions:
4446
id-token: write # PyPI trusted publishing (OIDC)
4547

4648
concurrency:
47-
group: release-sdk-${{ github.ref }}
48-
cancel-in-progress: false
49+
group: ${{ github.ref_name == 'stable' && 'release-stable-writeback' || format('{0}-{1}', github.workflow, github.ref) }}
50+
cancel-in-progress: ${{ github.ref_name != 'stable' }}
4951

5052
jobs:
5153
# -------------------------------------------------------------------
@@ -71,6 +73,12 @@ jobs:
7173
fetch-depth: 0
7274
token: ${{ steps.generate_token.outputs.token }}
7375

76+
- name: Refresh stable branch head
77+
if: github.ref_name == 'stable'
78+
run: |
79+
git fetch origin "${{ github.ref_name }}" --tags
80+
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"
81+
7482
- uses: pnpm/action-setup@v4
7583

7684
- uses: actions/setup-node@v6

.github/workflows/release-superdoc.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ permissions:
2424
packages: write
2525

2626
concurrency:
27-
group: release-superdoc-${{ github.ref }}
28-
cancel-in-progress: true
27+
group: ${{ github.ref_name == 'stable' && 'release-stable-writeback' || format('{0}-{1}', github.workflow, github.ref) }}
28+
cancel-in-progress: ${{ github.ref_name != 'stable' }}
2929

3030
jobs:
3131
release:
@@ -43,6 +43,12 @@ jobs:
4343
fetch-depth: 0
4444
token: ${{ steps.generate_token.outputs.token }}
4545

46+
- name: Refresh stable branch head
47+
if: github.ref_name == 'stable'
48+
run: |
49+
git fetch origin "${{ github.ref_name }}" --tags
50+
git checkout -B "${{ github.ref_name }}" "origin/${{ github.ref_name }}"
51+
4652
- uses: pnpm/action-setup@v4
4753

4854
- uses: actions/setup-node@v6

packages/sdk/.releaserc.cjs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ require('../../scripts/semantic-release/patch-commit-filter.cjs')([
2020
]);
2121

2222
const branch = process.env.GITHUB_REF_NAME || process.env.CI_COMMIT_BRANCH;
23+
const isCiRelease = Boolean(process.env.CI);
2324

2425
const branches = [
2526
{ name: 'stable', channel: 'latest' },
@@ -62,12 +63,12 @@ const config = {
6263
],
6364
};
6465

65-
// On prerelease (main), PyPI is handled by GHA OIDC — keep --npm-only.
66-
// On stable (local release), sdk-release-publish.mjs uploads to PyPI via twine.
66+
// In CI (main/stable), PyPI is handled by the workflow via OIDC — keep --npm-only.
67+
// For local stable releases, sdk-release-publish.mjs uploads to PyPI via twine.
6768
const execPlugin = config.plugins.find(
6869
(p) => Array.isArray(p) && p[0] === '@semantic-release/exec',
6970
);
70-
if (isPrerelease) {
71+
if (isCiRelease || isPrerelease) {
7172
execPlugin[1].publishCmd =
7273
'node scripts/sdk-release-publish.mjs --tag ${nextRelease.channel || "latest"} --npm-only';
7374
} else {

packages/sdk/scripts/__tests__/release-order.test.mjs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ test('release-sdk auto workflow resumes releases from sdk-v tags at HEAD', async
9494
);
9595
});
9696

97+
test('release-sdk auto workflow runs on stable and main', async () => {
98+
const content = await readRepoFile('.github/workflows/release-sdk.yml');
99+
assert.ok(
100+
content.includes(' - main'),
101+
'.github/workflows/release-sdk.yml: auto-release must continue to run on main',
102+
);
103+
assert.ok(
104+
content.includes(' - stable'),
105+
'.github/workflows/release-sdk.yml: auto-release must run on stable',
106+
);
107+
});
108+
97109
test('sdk semantic-release prepareCmd builds Node SDK before validate', async () => {
98110
const content = await readRepoFile('packages/sdk/.releaserc.cjs');
99111
assertOrder(
@@ -120,6 +132,14 @@ test('sdk semantic-release matches CLI channel model (next/next on main, latest
120132
content.includes("{ name: 'main', prerelease: 'next', channel: 'next' }"),
121133
"packages/sdk/.releaserc.cjs: main branch must release next versions on next channel",
122134
);
135+
assert.ok(
136+
content.includes('const isCiRelease = Boolean(process.env.CI);'),
137+
'packages/sdk/.releaserc.cjs: CI releases must be detected explicitly',
138+
);
139+
assert.ok(
140+
content.includes('if (isCiRelease || isPrerelease) {'),
141+
'packages/sdk/.releaserc.cjs: CI releases must keep Python publishing in the workflow',
142+
);
123143
});
124144

125145
test('sdk-release-publish validates local PyPI prerequisites before Node publish', async () => {

0 commit comments

Comments
 (0)