-
Notifications
You must be signed in to change notification settings - Fork 11
232 lines (203 loc) · 10.7 KB
/
Copy pathrelease.yml
File metadata and controls
232 lines (203 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
name: Release
on:
push:
branches: [master]
workflow_dispatch:
inputs:
force:
description: "Force publish even if not a release branch merge"
required: false
default: "false"
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check commit type
id: check
run: |
MERGE_MSG=$(git log -1 --pretty=%B)
MERGE_TITLE=$(echo "$MERGE_MSG" | head -1)
echo "Commit title: $MERGE_TITLE"
FORCE="${{ github.event.inputs.force }}"
IS_RELEASE="false"
IS_PROMOTE_STABLE="false"
# Pattern 1: Standard merge of release branch
# "Merge pull request #171 from ranxianglei/2026-07-21_release-v1.13.2"
if echo "$MERGE_TITLE" | grep -qE 'Merge pull request #[0-9]+ from .*[0-9]{4}-[0-9]{2}-[0-9]{2}_release-v'; then
IS_RELEASE="true"
echo "Release branch detected (standard merge)"
# Pattern 2: Squash merge of a release PR
# "release: v1.13.4 — ... (#186)"
elif echo "$MERGE_TITLE" | grep -qE '^release: v[0-9]+\.[0-9]+\.[0-9]+'; then
IS_RELEASE="true"
echo "Release branch detected (squash merge)"
# Pattern 3: Squash merge of a promote-stable PR
# "promote: stable v1.14.7 — ... (#231)"
elif echo "$MERGE_TITLE" | grep -qE '^promote: stable v[0-9]+\.[0-9]+\.[0-9]+'; then
IS_PROMOTE_STABLE="true"
STABLE_VERSION=$(echo "$MERGE_TITLE" | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1 | sed 's/^v//')
echo "Promote-stable detected: version $STABLE_VERSION"
echo "stable_version=$STABLE_VERSION" >> "$GITHUB_OUTPUT"
# Pattern 4: Standard merge of promote-stable branch
# "Merge pull request #231 from ranxianglei/2026-07-29_promote-stable-v1.14.7"
elif echo "$MERGE_TITLE" | grep -qE 'Merge pull request #[0-9]+ from .*promote-stable-v[0-9]+\.[0-9]+\.[0-9]+'; then
IS_PROMOTE_STABLE="true"
STABLE_VERSION=$(echo "$MERGE_TITLE" | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1 | sed 's/^v//')
echo "Promote-stable detected (standard merge): version $STABLE_VERSION"
echo "stable_version=$STABLE_VERSION" >> "$GITHUB_OUTPUT"
elif [ "$FORCE" = "true" ]; then
IS_RELEASE="true"
echo "Force publish requested"
else
echo "Not a release or promote-stable branch merge — skipping"
fi
echo "is_release=$IS_RELEASE" >> "$GITHUB_OUTPUT"
echo "is_promote_stable=$IS_PROMOTE_STABLE" >> "$GITHUB_OUTPUT"
- name: Read version
if: steps.check.outputs.is_release == 'true'
id: version
run: |
VERSION=$(node -p "require('./package.json').version")
TAG="v${VERSION}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
# Detect prerelease versions (e.g. 1.13.0-dev.1, 1.13.0-beta.2)
if echo "$VERSION" | grep -q -- '-'; then
echo "is_prerelease=true" >> "$GITHUB_OUTPUT"
echo "npm_tag=dev" >> "$GITHUB_OUTPUT"
echo "Prerelease detected: $VERSION → npm tag: dev"
else
echo "is_prerelease=false" >> "$GITHUB_OUTPUT"
echo "npm_tag=latest" >> "$GITHUB_OUTPUT"
echo "Stable release: $VERSION → npm tag: latest"
fi
- uses: actions/setup-node@v4
if: steps.check.outputs.is_release == 'true' || steps.check.outputs.is_promote_stable == 'true'
with:
node-version: 22
cache: npm
registry-url: https://registry.npmjs.org
# ── Promote to npm stable tag ──────────────────────────
# Branch naming: YYYY-MM-DD_promote-stable-v{VERSION}
# Commit message: "promote: stable v{VERSION} — reason"
# CI runs `npm dist-tag add opencode-acp@VERSION stable`
- name: Promote to npm stable tag
if: steps.check.outputs.is_promote_stable == 'true'
run: |
VERSION="${{ steps.check.outputs.stable_version }}"
echo "Promoting opencode-acp@$VERSION to 'stable' tag"
npm dist-tag add "opencode-acp@$VERSION" stable
echo "✓ Done. Users can now install via opencode-acp@stable"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# ── Normal release flow (unchanged) ────────────────────
- if: steps.check.outputs.is_release == 'true'
run: npm ci
- if: steps.check.outputs.is_release == 'true'
run: npm run check:package
- if: steps.check.outputs.is_release == 'true'
run: npm test
- name: Create tag
if: steps.check.outputs.is_release == 'true'
run: |
TAG="${{ steps.version.outputs.tag }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG already exists — skipping"
else
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "$TAG" -m "release $TAG (auto-tagged on merge)"
git push origin "$TAG"
echo "Created tag $TAG"
fi
- name: Publish to npm
if: steps.check.outputs.is_release == 'true'
run: |
NPM_TAG="${{ steps.version.outputs.npm_tag }}"
echo "Publishing ${{ steps.version.outputs.version }} with tag: $NPM_TAG"
npm publish --tag "$NPM_TAG"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create GitHub Release
if: steps.check.outputs.is_release == 'true'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.version.outputs.tag }}
generate_release_notes: true
prerelease: ${{ steps.version.outputs.is_prerelease }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Report published version on PR
if: steps.check.outputs.is_release == 'true' && success()
uses: actions/github-script@v7
with:
script: |
const version = '${{ steps.version.outputs.version }}';
const npmTag = '${{ steps.version.outputs.npm_tag }}';
const isPrerelease = '${{ steps.version.outputs.is_prerelease }}' === 'true';
// Find the merged PR associated with this commit
const prs = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha
});
const prNumber = prs.data[0]?.number;
if (!prNumber) {
core.info('No associated PR found — skipping comment');
return;
}
const installCmd = isPrerelease
? 'opencode plugin opencode-acp@dev --global'
: 'opencode plugin opencode-acp@latest --global';
const body = [
`✅ **Published \`opencode-acp@${version}\`** to npm \`${npmTag}\` tag.`,
'',
'```bash',
installCmd,
'```',
'',
`[npm](https://www.npmjs.com/package/opencode-acp/v/${version}) | [GitHub Release](https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/v${version})`
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body
});
core.info(`Commented on PR #${prNumber}: published ${version} to ${npmTag}`);
- name: Report promote-stable on PR
if: steps.check.outputs.is_promote_stable == 'true' && success()
uses: actions/github-script@v7
with:
script: |
const version = '${{ steps.check.outputs.stable_version }}';
const prs = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha
});
const prNumber = prs.data[0]?.number;
if (!prNumber) {
core.info('No associated PR found — skipping comment');
return;
}
const body = [
`✅ **Promoted \`opencode-acp@${version}\`** to npm \`stable\` tag.`,
'',
'```bash',
'opencode plugin opencode-acp@stable --global',
'```'
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body
});
core.info(`Commented on PR #${prNumber}: promoted ${version} to stable`);