diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c88dd3a..03716e0d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,6 +20,15 @@ on: description: New version default: patch required: true + prerelease: + type: boolean + description: Release as rc (prerelease) + default: false + +env: + NEW_VERSION_TYPE: ${{ inputs.newversion }} + PRERELEASE: ${{ inputs.prerelease }} + DRY_RUN: ${{ inputs.environment == 'dry-run' }} permissions: contents: read @@ -41,6 +50,7 @@ jobs: outputs: new_tag: ${{ steps.bump_version.outputs.new_tag }} previous_tag: ${{ steps.get_latest_tag.outputs.latest_tag }} + previous_stable_tag: ${{ steps.get_latest_tag.outputs.latest_stable_tag }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -56,15 +66,28 @@ jobs: latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") echo "latest_tag=${latest_tag}" >> "$GITHUB_OUTPUT" + latest_stable_tag=$(git tag --list 'v*' --sort=-v:refname | grep -v '-' | head -n 1) + latest_stable_tag="${latest_stable_tag:-v0.0.0}" + echo "latest_stable_tag=${latest_stable_tag}" >> "$GITHUB_OUTPUT" + - name: Bump version id: bump_version working-directory: apps/cli env: LATEST_TAG: ${{ steps.get_latest_tag.outputs.latest_tag }} - NEW_VERSION_TYPE: ${{ github.event.inputs.newversion }} run: | npm version "$LATEST_TAG" --no-git-tag-version --allow-same-version - npm version "$NEW_VERSION_TYPE" --no-git-tag-version + + if [ "$PRERELEASE" = "true" ]; then + current_version=$(node -p "require('./package.json').version") + if echo "$current_version" | grep -q -- "-rc\."; then + npm version prerelease --preid rc --no-git-tag-version + else + npm version "pre${NEW_VERSION_TYPE}" --preid rc --no-git-tag-version + fi + else + npm version "$NEW_VERSION_TYPE" --no-git-tag-version + fi new_version=$(node -p "require('./package.json').version") new_tag="v${new_version}" @@ -90,6 +113,10 @@ jobs: permissions: contents: write id-token: write + env: + NEW_TAG: ${{ needs.build.outputs.new_tag }} + PREVIOUS_TAG: ${{ needs.build.outputs.previous_tag }} + PREVIOUS_STABLE_TAG: ${{ needs.build.outputs.previous_stable_tag }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -104,14 +131,16 @@ jobs: path: apps/cli - name: Publish to npm - if: inputs.environment != 'dry-run' - working-directory: apps/cli - run: npm publish --provenance --access public - - - name: Publish dry run - if: inputs.environment == 'dry-run' working-directory: apps/cli - run: npm publish --provenance --access public --dry-run + run: | + flags="--provenance --access public" + if [ "$PRERELEASE" = "true" ]; then + flags="$flags --tag rc" + fi + if [ "$DRY_RUN" = "true" ]; then + flags="$flags --dry-run" + fi + npm publish $flags - name: Configure git if: inputs.environment != 'dry-run' @@ -122,7 +151,6 @@ jobs: - name: Push version commit and tag if: inputs.environment != 'dry-run' env: - NEW_TAG: ${{ needs.build.outputs.new_tag }} REF_NAME: ${{ github.ref_name }} run: | git add apps/cli/package.json @@ -132,26 +160,29 @@ jobs: git push origin "${NEW_TAG}" - name: Create GitHub release - if: inputs.environment != 'dry-run' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NEW_TAG: ${{ needs.build.outputs.new_tag }} - PREVIOUS_TAG: ${{ needs.build.outputs.previous_tag }} - run: gh release create "$NEW_TAG" --generate-notes --notes-start-tag "$PREVIOUS_TAG" - - - name: Preview release notes (dry-run) - if: inputs.environment == 'dry-run' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NEW_TAG: ${{ needs.build.outputs.new_tag }} - PREVIOUS_TAG: ${{ needs.build.outputs.previous_tag }} REPOSITORY: ${{ github.repository }} TARGET_COMMITISH: ${{ github.sha }} run: | - echo "## Release notes for ${NEW_TAG}" >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - gh api "repos/${REPOSITORY}/releases/generate-notes" \ - -f tag_name="$NEW_TAG" \ - -f target_commitish="$TARGET_COMMITISH" \ - -f previous_tag_name="$PREVIOUS_TAG" \ - --jq '.body' >> "$GITHUB_STEP_SUMMARY" + if [ "$PRERELEASE" = "true" ]; then + notes_start_tag="$PREVIOUS_TAG" + else + notes_start_tag="$PREVIOUS_STABLE_TAG" + fi + + if [ "$DRY_RUN" = "true" ]; then + echo "## Release notes for ${NEW_TAG}" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + gh api "repos/${REPOSITORY}/releases/generate-notes" \ + -f tag_name="$NEW_TAG" \ + -f target_commitish="$TARGET_COMMITISH" \ + -f previous_tag_name="$notes_start_tag" \ + --jq '.body' >> "$GITHUB_STEP_SUMMARY" + else + flags="--generate-notes --notes-start-tag $notes_start_tag" + if [ "$PRERELEASE" = "true" ]; then + flags="$flags --prerelease" + fi + gh release create "$NEW_TAG" $flags + fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 021506ab..0345ce4a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,9 +64,11 @@ pnpm --filter @nulab/bee build Releases are triggered manually via the [Release workflow](https://github.com/nulab/bee/actions/workflows/release.yml) (`workflow_dispatch`). 1. Go to **Actions > Release > Run workflow**. -2. Select the **environment** (`dry-run` or production). -3. Select the **version bump** (`patch`, `minor`, or `major`). -4. The workflow will: +2. Select the inputs: + - **environment** — `dry-run` (default) or `production` + - **newversion** — `patch`, `minor`, or `major` + - **prerelease** — check to release as rc (prerelease) +3. The workflow will: - Bump the version in `apps/cli/package.json` - Build the CLI - Publish to npm with provenance @@ -74,6 +76,18 @@ Releases are triggered manually via the [Release workflow](https://github.com/nu Dry-run mode publishes with `--dry-run` and skips git tag/push, so it's safe to test. +### Input combinations + +| newversion | prerelease | Example result | npm tag | +| ---------- | ---------- | --------------------------------------------------------- | -------- | +| `minor` | unchecked | `1.0.0` → `1.1.0` | `latest` | +| `major` | unchecked | `1.0.0` → `2.0.0` | `latest` | +| `patch` | unchecked | `1.0.1` → `1.0.2` | `latest` | +| `minor` | checked | `1.0.0` → `1.1.0-rc.0` | `rc` | +| `major` | checked | `1.0.0` → `2.0.0-rc.0` | `rc` | +| `minor` | checked | `1.1.0-rc.0` → `1.1.0-rc.1` (already rc: bumps rc number) | `rc` | +| `minor` | unchecked | `1.1.0-rc.1` → `1.1.0` (promote to stable) | `latest` | + ## Documentation Site 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.