Skip to content

Commit ff3f697

Browse files
lollipop-onlclaude
andauthored
Add prerelease support to release workflow (#61)
* feat: add prerelease (rc) support to release workflow https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H * fix: use latest stable tag for release notes on stable releases When promoting from rc to stable, release notes now cover all changes since the last stable version, not just since the last rc. https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H * refactor: replace prerelease input with preminor/premajor/prerelease version types Instead of a separate prerelease input, add preminor, premajor, and prerelease directly to the newversion options. This maps directly to npm version commands and avoids confusion about input combinations. https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H * refactor: use boolean checkbox for prerelease instead of version type options Simpler UI: newversion stays as patch/minor/major, and a separate checkbox controls whether to release as rc. When checked and the current version is already an rc, it bumps the rc number instead. https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H * refactor: consolidate duplicate dry-run and production steps Merge publish and release note steps by using DRY_RUN flag to conditionally add --dry-run or switch to preview mode, eliminating step duplication. https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H * refactor: deduplicate env vars using workflow-level and job-level env - PRERELEASE and DRY_RUN → workflow-level env - NEW_TAG, PREVIOUS_TAG, PREVIOUS_STABLE_TAG → publish job-level env - Remove redundant step-level env definitions https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H * docs: add release input combinations table to CONTRIBUTING.md https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H * refactor: move NEW_VERSION_TYPE to workflow-level env All input-derived env vars are now consistently defined at workflow level: NEW_VERSION_TYPE, PRERELEASE, DRY_RUN. https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H * style: fix markdown table formatting in CONTRIBUTING.md https://claude.ai/code/session_01ULoEJZPc1AfKpew9Pz8w9H --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0bd368b commit ff3f697

2 files changed

Lines changed: 76 additions & 31 deletions

File tree

.github/workflows/release.yml

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ on:
2020
description: New version
2121
default: patch
2222
required: true
23+
prerelease:
24+
type: boolean
25+
description: Release as rc (prerelease)
26+
default: false
27+
28+
env:
29+
NEW_VERSION_TYPE: ${{ inputs.newversion }}
30+
PRERELEASE: ${{ inputs.prerelease }}
31+
DRY_RUN: ${{ inputs.environment == 'dry-run' }}
2332

2433
permissions:
2534
contents: read
@@ -41,6 +50,7 @@ jobs:
4150
outputs:
4251
new_tag: ${{ steps.bump_version.outputs.new_tag }}
4352
previous_tag: ${{ steps.get_latest_tag.outputs.latest_tag }}
53+
previous_stable_tag: ${{ steps.get_latest_tag.outputs.latest_stable_tag }}
4454
steps:
4555
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
4656
with:
@@ -56,15 +66,28 @@ jobs:
5666
latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
5767
echo "latest_tag=${latest_tag}" >> "$GITHUB_OUTPUT"
5868
69+
latest_stable_tag=$(git tag --list 'v*' --sort=-v:refname | grep -v '-' | head -n 1)
70+
latest_stable_tag="${latest_stable_tag:-v0.0.0}"
71+
echo "latest_stable_tag=${latest_stable_tag}" >> "$GITHUB_OUTPUT"
72+
5973
- name: Bump version
6074
id: bump_version
6175
working-directory: apps/cli
6276
env:
6377
LATEST_TAG: ${{ steps.get_latest_tag.outputs.latest_tag }}
64-
NEW_VERSION_TYPE: ${{ github.event.inputs.newversion }}
6578
run: |
6679
npm version "$LATEST_TAG" --no-git-tag-version --allow-same-version
67-
npm version "$NEW_VERSION_TYPE" --no-git-tag-version
80+
81+
if [ "$PRERELEASE" = "true" ]; then
82+
current_version=$(node -p "require('./package.json').version")
83+
if echo "$current_version" | grep -q -- "-rc\."; then
84+
npm version prerelease --preid rc --no-git-tag-version
85+
else
86+
npm version "pre${NEW_VERSION_TYPE}" --preid rc --no-git-tag-version
87+
fi
88+
else
89+
npm version "$NEW_VERSION_TYPE" --no-git-tag-version
90+
fi
6891
6992
new_version=$(node -p "require('./package.json').version")
7093
new_tag="v${new_version}"
@@ -90,6 +113,10 @@ jobs:
90113
permissions:
91114
contents: write
92115
id-token: write
116+
env:
117+
NEW_TAG: ${{ needs.build.outputs.new_tag }}
118+
PREVIOUS_TAG: ${{ needs.build.outputs.previous_tag }}
119+
PREVIOUS_STABLE_TAG: ${{ needs.build.outputs.previous_stable_tag }}
93120
steps:
94121
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
95122

@@ -104,14 +131,16 @@ jobs:
104131
path: apps/cli
105132

106133
- name: Publish to npm
107-
if: inputs.environment != 'dry-run'
108-
working-directory: apps/cli
109-
run: npm publish --provenance --access public
110-
111-
- name: Publish dry run
112-
if: inputs.environment == 'dry-run'
113134
working-directory: apps/cli
114-
run: npm publish --provenance --access public --dry-run
135+
run: |
136+
flags="--provenance --access public"
137+
if [ "$PRERELEASE" = "true" ]; then
138+
flags="$flags --tag rc"
139+
fi
140+
if [ "$DRY_RUN" = "true" ]; then
141+
flags="$flags --dry-run"
142+
fi
143+
npm publish $flags
115144
116145
- name: Configure git
117146
if: inputs.environment != 'dry-run'
@@ -122,7 +151,6 @@ jobs:
122151
- name: Push version commit and tag
123152
if: inputs.environment != 'dry-run'
124153
env:
125-
NEW_TAG: ${{ needs.build.outputs.new_tag }}
126154
REF_NAME: ${{ github.ref_name }}
127155
run: |
128156
git add apps/cli/package.json
@@ -132,26 +160,29 @@ jobs:
132160
git push origin "${NEW_TAG}"
133161
134162
- name: Create GitHub release
135-
if: inputs.environment != 'dry-run'
136-
env:
137-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
138-
NEW_TAG: ${{ needs.build.outputs.new_tag }}
139-
PREVIOUS_TAG: ${{ needs.build.outputs.previous_tag }}
140-
run: gh release create "$NEW_TAG" --generate-notes --notes-start-tag "$PREVIOUS_TAG"
141-
142-
- name: Preview release notes (dry-run)
143-
if: inputs.environment == 'dry-run'
144163
env:
145164
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
146-
NEW_TAG: ${{ needs.build.outputs.new_tag }}
147-
PREVIOUS_TAG: ${{ needs.build.outputs.previous_tag }}
148165
REPOSITORY: ${{ github.repository }}
149166
TARGET_COMMITISH: ${{ github.sha }}
150167
run: |
151-
echo "## Release notes for ${NEW_TAG}" >> "$GITHUB_STEP_SUMMARY"
152-
echo "" >> "$GITHUB_STEP_SUMMARY"
153-
gh api "repos/${REPOSITORY}/releases/generate-notes" \
154-
-f tag_name="$NEW_TAG" \
155-
-f target_commitish="$TARGET_COMMITISH" \
156-
-f previous_tag_name="$PREVIOUS_TAG" \
157-
--jq '.body' >> "$GITHUB_STEP_SUMMARY"
168+
if [ "$PRERELEASE" = "true" ]; then
169+
notes_start_tag="$PREVIOUS_TAG"
170+
else
171+
notes_start_tag="$PREVIOUS_STABLE_TAG"
172+
fi
173+
174+
if [ "$DRY_RUN" = "true" ]; then
175+
echo "## Release notes for ${NEW_TAG}" >> "$GITHUB_STEP_SUMMARY"
176+
echo "" >> "$GITHUB_STEP_SUMMARY"
177+
gh api "repos/${REPOSITORY}/releases/generate-notes" \
178+
-f tag_name="$NEW_TAG" \
179+
-f target_commitish="$TARGET_COMMITISH" \
180+
-f previous_tag_name="$notes_start_tag" \
181+
--jq '.body' >> "$GITHUB_STEP_SUMMARY"
182+
else
183+
flags="--generate-notes --notes-start-tag $notes_start_tag"
184+
if [ "$PRERELEASE" = "true" ]; then
185+
flags="$flags --prerelease"
186+
fi
187+
gh release create "$NEW_TAG" $flags
188+
fi

CONTRIBUTING.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,30 @@ pnpm --filter @nulab/bee build
6464
Releases are triggered manually via the [Release workflow](https://github.com/nulab/bee/actions/workflows/release.yml) (`workflow_dispatch`).
6565

6666
1. Go to **Actions > Release > Run workflow**.
67-
2. Select the **environment** (`dry-run` or production).
68-
3. Select the **version bump** (`patch`, `minor`, or `major`).
69-
4. The workflow will:
67+
2. Select the inputs:
68+
- **environment**`dry-run` (default) or `production`
69+
- **newversion**`patch`, `minor`, or `major`
70+
- **prerelease** — check to release as rc (prerelease)
71+
3. The workflow will:
7072
- Bump the version in `apps/cli/package.json`
7173
- Build the CLI
7274
- Publish to npm with provenance
7375
- Create a git tag and GitHub release with auto-generated notes
7476

7577
Dry-run mode publishes with `--dry-run` and skips git tag/push, so it's safe to test.
7678

79+
### Input combinations
80+
81+
| newversion | prerelease | Example result | npm tag |
82+
| ---------- | ---------- | --------------------------------------------------------- | -------- |
83+
| `minor` | unchecked | `1.0.0``1.1.0` | `latest` |
84+
| `major` | unchecked | `1.0.0``2.0.0` | `latest` |
85+
| `patch` | unchecked | `1.0.1``1.0.2` | `latest` |
86+
| `minor` | checked | `1.0.0``1.1.0-rc.0` | `rc` |
87+
| `major` | checked | `1.0.0``2.0.0-rc.0` | `rc` |
88+
| `minor` | checked | `1.1.0-rc.0``1.1.0-rc.1` (already rc: bumps rc number) | `rc` |
89+
| `minor` | unchecked | `1.1.0-rc.1``1.1.0` (promote to stable) | `latest` |
90+
7791
## Documentation Site
7892

7993
The documentation site (`apps/docs`) uses Astro Starlight. Command reference pages are auto-generated from CLI source code — do not create markdown files under `apps/docs/src/content/docs/commands/`. See [CLAUDE.md](CLAUDE.md#documentation-site-appsdocs) for details.

0 commit comments

Comments
 (0)