From a91334f75d7f687ae66468927b8a6eb4a5692c6d Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 08:24:24 +0800 Subject: [PATCH 01/20] ci: switch Build & Release to git tag driven flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - trigger: push tags v* (instead of push to main with paths filter) - version: parsed from tag (v0.7.0-beta.1 → 0.7.0-beta.1) - docker tags: sha + semver + major.minor + latest (stable only) - bump-chart: version comes directly from tag, no more GITHUB_RUN_NUMBER - workflow_dispatch: kept for manual trigger with explicit tag input --- .github/workflows/build.yml | 103 ++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 57 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c73084ae..7b067be0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,32 +2,16 @@ name: Build & Release on: push: - branches: - - main - paths: - - "src/**" - - "Cargo.toml" - - "Cargo.lock" - - "Dockerfile" - - "Dockerfile.*" + tags: + - "v*" workflow_dispatch: inputs: - chart_bump: - description: 'Chart version bump type' + tag: + description: 'Version tag (e.g. v0.7.0-beta.1 or v0.7.0)' required: true - type: choice - options: - - patch - - minor - - major - default: patch - release: - description: 'Stable release (no beta suffix)' - required: false - type: boolean - default: false + type: string dry_run: - description: 'Dry run (show changes without committing)' + description: 'Dry run (build only, no push or chart bump)' required: false type: boolean default: false @@ -63,6 +47,15 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Resolve version tag + id: tag + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "value=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" + else + echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + fi + - name: Docker metadata id: meta uses: docker/metadata-action@v5 @@ -109,8 +102,6 @@ jobs: permissions: contents: read packages: write - outputs: - version: ${{ steps.meta.outputs.version }} steps: - name: Download digests uses: actions/download-artifact@v4 @@ -127,6 +118,15 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Resolve version tag + id: tag + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "value=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" + else + echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + fi + - name: Docker metadata id: meta uses: docker/metadata-action@v5 @@ -134,7 +134,9 @@ jobs: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }} tags: | type=sha,prefix= - type=raw,value=latest + type=semver,pattern={{version}},value=${{ steps.tag.outputs.value }} + type=semver,pattern={{major}}.{{minor}},value=${{ steps.tag.outputs.value }} + type=raw,value=latest,enable=${{ !contains(steps.tag.outputs.value, '-') }} - name: Create manifest list working-directory: /tmp/digests @@ -161,40 +163,26 @@ jobs: with: fetch-depth: 0 - - name: Get current chart version - id: current + - name: Resolve version tag + id: tag run: | - chart_version=$(grep '^version:' charts/openab/Chart.yaml | awk '{print $2}') - echo "chart_version=$chart_version" >> "$GITHUB_OUTPUT" - - - name: Bump chart version - id: bump - run: | - current="${{ steps.current.outputs.chart_version }}" - # Strip any existing pre-release suffix for base version - base="${current%%-*}" - IFS='.' read -r major minor patch <<< "$base" - bump_type="${{ inputs.chart_bump }}" - bump_type="${bump_type:-patch}" - case "$bump_type" in - major) major=$((major + 1)); minor=0; patch=0 ;; - minor) minor=$((minor + 1)); patch=0 ;; - patch) patch=$((patch + 1)) ;; - esac - # Stable release: clean version. Otherwise: beta with run number. - if [ "${{ inputs.release }}" = "true" ]; then - new_version="${major}.${minor}.${patch}" + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "value=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" else - new_version="${major}.${minor}.${patch}-beta.${GITHUB_RUN_NUMBER}" + echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" fi - echo "new_version=$new_version" >> "$GITHUB_OUTPUT" + + - name: Parse chart version from tag + id: version + run: | + # Strip leading 'v' → chart version (e.g. v0.7.0-beta.1 → 0.7.0-beta.1) + chart_version="${{ steps.tag.outputs.value }}" + chart_version="${chart_version#v}" + echo "chart_version=${chart_version}" >> "$GITHUB_OUTPUT" - name: Resolve image SHA id: image-sha run: | - # Use the commit SHA that triggered this build — this is the SHA - # that merge-manifests tagged the Docker image with (type=sha,prefix=). - # We capture it here explicitly so it survives the bump commit. IMAGE_SHA="${{ github.sha }}" IMAGE_SHA="${IMAGE_SHA:0:7}" echo "sha=${IMAGE_SHA}" >> "$GITHUB_OUTPUT" @@ -202,7 +190,8 @@ jobs: - name: Update Chart.yaml and values.yaml run: | IMAGE_SHA="${{ steps.image-sha.outputs.sha }}" - sed -i "s/^version: .*/version: ${{ steps.bump.outputs.new_version }}/" charts/openab/Chart.yaml + CHART_VERSION="${{ steps.version.outputs.chart_version }}" + sed -i "s/^version: .*/version: ${CHART_VERSION}/" charts/openab/Chart.yaml sed -i "s/^appVersion: .*/appVersion: \"${IMAGE_SHA}\"/" charts/openab/Chart.yaml sed -i "s|repository: .*|repository: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}|" charts/openab/values.yaml sed -i "s/tag: .*/tag: \"${IMAGE_SHA}\"/" charts/openab/values.yaml @@ -211,19 +200,19 @@ jobs: env: GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | - VERSION="${{ steps.bump.outputs.new_version }}" + CHART_VERSION="${{ steps.version.outputs.chart_version }}" IMAGE_SHA="${{ steps.image-sha.outputs.sha }}" - BRANCH="chore/chart-${VERSION}" + BRANCH="chore/chart-${CHART_VERSION}" git config user.name "openab-app[bot]" git config user.email "274185012+openab-app[bot]@users.noreply.github.com" git checkout -b "$BRANCH" git add charts/openab/Chart.yaml charts/openab/values.yaml - git commit -m "chore: bump chart to ${VERSION} + git commit -m "chore: bump chart to ${CHART_VERSION} image: ${IMAGE_SHA}" git push origin "$BRANCH" PR_URL=$(gh pr create \ - --title "chore: bump chart to ${VERSION}" \ + --title "chore: bump chart to ${CHART_VERSION}" \ --body "Auto-generated chart version bump for image \`${IMAGE_SHA}\`." \ --base main --head "$BRANCH") gh pr merge "$PR_URL" --squash --delete-branch From c7ee28d7029581f7015720424bf2aebca330f3f8 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 08:31:38 +0800 Subject: [PATCH 02/20] ci: mark beta chart releases as pre-release --- .github/workflows/release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 534bb7ab..09e987c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -93,3 +93,8 @@ jobs: printf '%s\n' "${EXISTING}" > /tmp/existing.md cat /tmp/existing.md /tmp/notes.md > /tmp/final.md gh release edit "${TAG}" --repo "${OWNER}/${REPO}" --notes-file /tmp/final.md + + # Mark beta versions as pre-release + case "$VERSION" in + *-*) gh release edit "${TAG}" --repo "${OWNER}/${REPO}" --prerelease ;; + esac From aebdc3ba13d5abdfca0bd7e09b49d1e4c214b66c Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 08:36:51 +0800 Subject: [PATCH 03/20] =?UTF-8?q?ci:=20split=20chart=20release=20=E2=80=94?= =?UTF-8?q?=20beta=20pushes=20OCI=20only,=20stable=20opens=20PR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Beta (tag contains '-'): → release-chart-beta: helm package + push to OCI registry → no PR, main branch untouched Stable (tag without '-'): → bump-chart-stable: update Chart.yaml + values.yaml → PR → auto merge → release.yml picks up Chart.yaml change → publish to GitHub Pages + OCI --- .github/workflows/build.yml | 72 ++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b067be0..78c0534e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -144,9 +144,52 @@ jobs: docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}@sha256:%s ' *) - bump-chart: + release-chart-beta: needs: merge-manifests - if: inputs.dry_run != true + if: ${{ inputs.dry_run != true && contains(github.ref_name, '-') }} + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + + - uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Resolve version tag + id: tag + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "value=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" + else + echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + fi + + - name: Build and push beta chart to OCI + run: | + TAG="${{ steps.tag.outputs.value }}" + CHART_VERSION="${TAG#v}" + IMAGE_SHA="${{ github.sha }}" + IMAGE_SHA="${IMAGE_SHA:0:7}" + + sed -i "s/^version: .*/version: ${CHART_VERSION}/" charts/openab/Chart.yaml + sed -i "s/^appVersion: .*/appVersion: \"${IMAGE_SHA}\"/" charts/openab/Chart.yaml + sed -i "s|repository: .*|repository: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}|" charts/openab/values.yaml + sed -i "s/tag: .*/tag: \"${IMAGE_SHA}\"/" charts/openab/values.yaml + + helm package charts/openab + helm push openab-${CHART_VERSION}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts + + bump-chart-stable: + needs: merge-manifests + if: ${{ inputs.dry_run != true && !contains(github.ref_name, '-') }} runs-on: ubuntu-latest permissions: contents: write @@ -172,25 +215,12 @@ jobs: echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" fi - - name: Parse chart version from tag - id: version - run: | - # Strip leading 'v' → chart version (e.g. v0.7.0-beta.1 → 0.7.0-beta.1) - chart_version="${{ steps.tag.outputs.value }}" - chart_version="${chart_version#v}" - echo "chart_version=${chart_version}" >> "$GITHUB_OUTPUT" - - - name: Resolve image SHA - id: image-sha + - name: Update Chart.yaml and values.yaml run: | + TAG="${{ steps.tag.outputs.value }}" + CHART_VERSION="${TAG#v}" IMAGE_SHA="${{ github.sha }}" IMAGE_SHA="${IMAGE_SHA:0:7}" - echo "sha=${IMAGE_SHA}" >> "$GITHUB_OUTPUT" - - - name: Update Chart.yaml and values.yaml - run: | - IMAGE_SHA="${{ steps.image-sha.outputs.sha }}" - CHART_VERSION="${{ steps.version.outputs.chart_version }}" sed -i "s/^version: .*/version: ${CHART_VERSION}/" charts/openab/Chart.yaml sed -i "s/^appVersion: .*/appVersion: \"${IMAGE_SHA}\"/" charts/openab/Chart.yaml sed -i "s|repository: .*|repository: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}|" charts/openab/values.yaml @@ -200,8 +230,10 @@ jobs: env: GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | - CHART_VERSION="${{ steps.version.outputs.chart_version }}" - IMAGE_SHA="${{ steps.image-sha.outputs.sha }}" + TAG="${{ steps.tag.outputs.value }}" + CHART_VERSION="${TAG#v}" + IMAGE_SHA="${{ github.sha }}" + IMAGE_SHA="${IMAGE_SHA:0:7}" BRANCH="chore/chart-${CHART_VERSION}" git config user.name "openab-app[bot]" git config user.email "274185012+openab-app[bot]@users.noreply.github.com" From 160a7297d5bfa7442c6eddb452b69e3984868885 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 08:43:53 +0800 Subject: [PATCH 04/20] ci: add resolve-tag job, fix workflow_dispatch bug, deduplicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add resolve-tag job: validates tag format, parses chart_version, image_sha, is_beta — single source of truth for all downstream jobs - Fix: workflow_dispatch now uses inputs.tag instead of github.ref_name for beta/stable branching (github.ref_name is branch name, not tag) - Remove 3× duplicated 'Resolve version tag' steps - IMAGE_SHA computed once in resolve-tag, not repeated per job --- .github/workflows/build.yml | 110 ++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 56 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78c0534e..165b7cf1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,47 @@ env: IMAGE_NAME: ${{ github.repository }} jobs: + resolve-tag: + runs-on: ubuntu-latest + outputs: + tag: ${{ steps.resolve.outputs.tag }} + chart_version: ${{ steps.resolve.outputs.chart_version }} + image_sha: ${{ steps.resolve.outputs.image_sha }} + is_beta: ${{ steps.resolve.outputs.is_beta }} + steps: + - name: Resolve and validate tag + id: resolve + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + TAG="${{ inputs.tag }}" + else + TAG="${GITHUB_REF_NAME}" + fi + + # Validate tag format + if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then + echo "::error::Invalid tag format '${TAG}'. Expected v{major}.{minor}.{patch}[-prerelease]" + exit 1 + fi + + CHART_VERSION="${TAG#v}" + IMAGE_SHA="${{ github.sha }}" + IMAGE_SHA="${IMAGE_SHA:0:7}" + + # Beta if version contains '-' (e.g. 0.7.0-beta.1) + if [[ "$CHART_VERSION" == *-* ]]; then + IS_BETA="true" + else + IS_BETA="false" + fi + + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT" + echo "image_sha=${IMAGE_SHA}" >> "$GITHUB_OUTPUT" + echo "is_beta=${IS_BETA}" >> "$GITHUB_OUTPUT" + build-image: + needs: resolve-tag strategy: matrix: variant: @@ -47,15 +87,6 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Resolve version tag - id: tag - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "value=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" - else - echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" - fi - - name: Docker metadata id: meta uses: docker/metadata-action@v5 @@ -89,7 +120,7 @@ jobs: retention-days: 1 merge-manifests: - needs: build-image + needs: [resolve-tag, build-image] if: inputs.dry_run != true strategy: matrix: @@ -118,15 +149,6 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Resolve version tag - id: tag - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "value=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" - else - echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" - fi - - name: Docker metadata id: meta uses: docker/metadata-action@v5 @@ -134,9 +156,9 @@ jobs: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }} tags: | type=sha,prefix= - type=semver,pattern={{version}},value=${{ steps.tag.outputs.value }} - type=semver,pattern={{major}}.{{minor}},value=${{ steps.tag.outputs.value }} - type=raw,value=latest,enable=${{ !contains(steps.tag.outputs.value, '-') }} + type=semver,pattern={{version}},value=${{ needs.resolve-tag.outputs.tag }} + type=semver,pattern={{major}}.{{minor}},value=${{ needs.resolve-tag.outputs.tag }} + type=raw,value=latest,enable=${{ needs.resolve-tag.outputs.is_beta == 'false' }} - name: Create manifest list working-directory: /tmp/digests @@ -145,8 +167,8 @@ jobs: $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}@sha256:%s ' *) release-chart-beta: - needs: merge-manifests - if: ${{ inputs.dry_run != true && contains(github.ref_name, '-') }} + needs: [resolve-tag, merge-manifests] + if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'true' }} runs-on: ubuntu-latest permissions: contents: read @@ -163,21 +185,10 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Resolve version tag - id: tag - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "value=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" - else - echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" - fi - - name: Build and push beta chart to OCI run: | - TAG="${{ steps.tag.outputs.value }}" - CHART_VERSION="${TAG#v}" - IMAGE_SHA="${{ github.sha }}" - IMAGE_SHA="${IMAGE_SHA:0:7}" + CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" + IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" sed -i "s/^version: .*/version: ${CHART_VERSION}/" charts/openab/Chart.yaml sed -i "s/^appVersion: .*/appVersion: \"${IMAGE_SHA}\"/" charts/openab/Chart.yaml @@ -188,8 +199,8 @@ jobs: helm push openab-${CHART_VERSION}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts bump-chart-stable: - needs: merge-manifests - if: ${{ inputs.dry_run != true && !contains(github.ref_name, '-') }} + needs: [resolve-tag, merge-manifests] + if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'false' }} runs-on: ubuntu-latest permissions: contents: write @@ -206,21 +217,10 @@ jobs: with: fetch-depth: 0 - - name: Resolve version tag - id: tag - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "value=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" - else - echo "value=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" - fi - - name: Update Chart.yaml and values.yaml run: | - TAG="${{ steps.tag.outputs.value }}" - CHART_VERSION="${TAG#v}" - IMAGE_SHA="${{ github.sha }}" - IMAGE_SHA="${IMAGE_SHA:0:7}" + CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" + IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" sed -i "s/^version: .*/version: ${CHART_VERSION}/" charts/openab/Chart.yaml sed -i "s/^appVersion: .*/appVersion: \"${IMAGE_SHA}\"/" charts/openab/Chart.yaml sed -i "s|repository: .*|repository: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}|" charts/openab/values.yaml @@ -230,10 +230,8 @@ jobs: env: GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | - TAG="${{ steps.tag.outputs.value }}" - CHART_VERSION="${TAG#v}" - IMAGE_SHA="${{ github.sha }}" - IMAGE_SHA="${IMAGE_SHA:0:7}" + CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" + IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" BRANCH="chore/chart-${CHART_VERSION}" git config user.name "openab-app[bot]" git config user.email "274185012+openab-app[bot]@users.noreply.github.com" From 2d58aff6f2f1039111b88a55dce648a5047eea97 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 09:10:27 +0800 Subject: [PATCH 05/20] ci: stable release promotes beta image instead of rebuilding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - build-image + merge-manifests: only run for beta tags - promote-stable: retag existing beta image with stable tags (version, major.minor, latest) using imagetools create - verify beta image exists before promoting — fail fast if not - bump-chart-stable now depends on promote-stable This ensures "what you tested is what you ship" — the stable release uses the exact same image artifact validated during beta. --- .github/workflows/build.yml | 52 ++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 165b7cf1..d4d25625 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,6 +62,7 @@ jobs: build-image: needs: resolve-tag + if: ${{ needs.resolve-tag.outputs.is_beta == 'true' }} strategy: matrix: variant: @@ -121,7 +122,7 @@ jobs: merge-manifests: needs: [resolve-tag, build-image] - if: inputs.dry_run != true + if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'true' }} strategy: matrix: variant: @@ -157,8 +158,6 @@ jobs: tags: | type=sha,prefix= type=semver,pattern={{version}},value=${{ needs.resolve-tag.outputs.tag }} - type=semver,pattern={{major}}.{{minor}},value=${{ needs.resolve-tag.outputs.tag }} - type=raw,value=latest,enable=${{ needs.resolve-tag.outputs.is_beta == 'false' }} - name: Create manifest list working-directory: /tmp/digests @@ -166,6 +165,51 @@ jobs: docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}@sha256:%s ' *) + promote-stable: + needs: resolve-tag + if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'false' }} + strategy: + matrix: + variant: + - { suffix: "" } + - { suffix: "-codex" } + - { suffix: "-claude" } + - { suffix: "-gemini" } + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: docker/setup-buildx-action@v3 + + - uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Verify beta image exists + run: | + IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}" + IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" + echo "Checking ${IMAGE}:${IMAGE_SHA} ..." + docker buildx imagetools inspect "${IMAGE}:${IMAGE_SHA}" || \ + { echo "::error::Image ${IMAGE}:${IMAGE_SHA} not found — build a beta on this commit first"; exit 1; } + + - name: Promote to stable tags + run: | + IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}" + IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" + CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" + MAJOR_MINOR="${CHART_VERSION%.*}" + + echo "Promoting ${IMAGE}:${IMAGE_SHA} → ${CHART_VERSION}, ${MAJOR_MINOR}, latest" + docker buildx imagetools create \ + -t "${IMAGE}:${CHART_VERSION}" \ + -t "${IMAGE}:${MAJOR_MINOR}" \ + -t "${IMAGE}:latest" \ + "${IMAGE}:${IMAGE_SHA}" + release-chart-beta: needs: [resolve-tag, merge-manifests] if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'true' }} @@ -199,7 +243,7 @@ jobs: helm push openab-${CHART_VERSION}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts bump-chart-stable: - needs: [resolve-tag, merge-manifests] + needs: [resolve-tag, promote-stable] if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'false' }} runs-on: ubuntu-latest permissions: From 74e63089b59b87bf83c9b1c1b7514737d3ec823a Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 10:23:39 +0800 Subject: [PATCH 06/20] ci: add tagpr workflow and config for automated release PR --- .github/workflows/tagpr.yml | 23 +++++++++++++++++++++++ .tagpr | 8 ++++++++ RELEASING.md | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 .github/workflows/tagpr.yml create mode 100644 .tagpr diff --git a/.github/workflows/tagpr.yml b/.github/workflows/tagpr.yml new file mode 100644 index 00000000..0de717a5 --- /dev/null +++ b/.github/workflows/tagpr.yml @@ -0,0 +1,23 @@ +name: tagpr + +on: + push: + branches: + - main + +permissions: + contents: write + pull-requests: write + +concurrency: + group: tagpr + cancel-in-progress: false + +jobs: + tagpr: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: Songmu/tagpr@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.tagpr b/.tagpr new file mode 100644 index 00000000..3df2f89c --- /dev/null +++ b/.tagpr @@ -0,0 +1,8 @@ +# tagpr configuration +# see: https://github.com/Songmu/tagpr + +[tagpr] +versionFile = "Cargo.toml" +tagPrefix = "v" +releaseBranch = "main" +changelog = true diff --git a/RELEASING.md b/RELEASING.md index 7061d0ec..fec89263 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -43,6 +43,41 @@ Users running `helm install` only see stable versions. Beta versions require `-- helm install ... (gets 0.2.1 🎉) ``` +## Release Flow (Tag-Driven) + +``` + 1. PR merged to main + │ + ▼ + ┌──────────────────────────────────────────────────────┐ + │ tagpr 自動累積 commits,開 Release PR │ + │ (chore: release vX.Y.Z) │ + └──────────────────────────────────────────────────────┘ + │ + ▼ + 2. Maintainer review Release PR,確認版本號與 changelog + → merge Release PR + │ + ▼ + ┌──────────────────────────────────────────────────────┐ + │ tagpr 自動打 tag (e.g. v0.7.0-beta.1) │ + │ → build.yml 觸發 (tag-driven) │ + └──────────────────────────────────────────────────────┘ + │ + ▼ + 3. Beta 測試通過後,在同一個 commit 打 stable tag: + git tag v0.7.0 + git push origin v0.7.0 + │ + ▼ + ┌──────────────────────────────────────────────────────┐ + │ build.yml promote-stable 觸發 │ + └──────────────────────────────────────────────────────┘ +``` + +> ⚠️ **重要約束**:stable tag 必須打在跟 beta 完全相同的 commit 上, +> 否則 promote-stable 會驗證失敗。 + ## Image Tags Each build produces three multi-arch images tagged with the git short SHA: From 3c628f36802c46d3b159453db8892363afaf4452 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 10:26:17 +0800 Subject: [PATCH 07/20] ci: pin tagpr action to commit hash and bump checkout to v6 --- .github/workflows/tagpr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tagpr.yml b/.github/workflows/tagpr.yml index 0de717a5..64f7d00a 100644 --- a/.github/workflows/tagpr.yml +++ b/.github/workflows/tagpr.yml @@ -17,7 +17,7 @@ jobs: tagpr: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: Songmu/tagpr@v1 + - uses: actions/checkout@v6 + - uses: Songmu/tagpr@9d0f650553240dab1fa907eca27e3fd5b586e538 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 4ec6a6306b966b35480db55b1eef12d889a60283 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 11:19:47 +0800 Subject: [PATCH 08/20] ci: add tagpr workflow and config for automated release PR - Add tagpr.yml with GitHub App token (so tags trigger build.yml) - Simplify build.yml: remove beta/stable two-stage, all tags do full build - Add pre-release support: manual tags like v0.7.0-rc.1 won't overwrite latest - Configure .tagpr to sync Cargo.toml + Chart.yaml version/appVersion - Simplify release.yml: keep chart-releaser + install instructions - Align Cargo.toml and Chart.yaml versions to 0.6.0 - Rewrite RELEASING.md with new tag-driven flow --- .github/workflows/build.yml | 159 +++++++----------------------- .github/workflows/release.yml | 25 +---- .github/workflows/tagpr.yml | 12 ++- .tagpr | 3 +- Cargo.toml | 2 +- RELEASING.md | 177 +++++++++++++++++++++------------- charts/openab/Chart.yaml | 4 +- 7 files changed, 163 insertions(+), 219 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4d25625..50a810e5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,11 +7,11 @@ on: workflow_dispatch: inputs: tag: - description: 'Version tag (e.g. v0.7.0-beta.1 or v0.7.0)' + description: 'Version tag (e.g. v0.7.0)' required: true type: string dry_run: - description: 'Dry run (build only, no push or chart bump)' + description: 'Dry run (build only, no push)' required: false type: boolean default: false @@ -26,8 +26,7 @@ jobs: outputs: tag: ${{ steps.resolve.outputs.tag }} chart_version: ${{ steps.resolve.outputs.chart_version }} - image_sha: ${{ steps.resolve.outputs.image_sha }} - is_beta: ${{ steps.resolve.outputs.is_beta }} + is_prerelease: ${{ steps.resolve.outputs.is_prerelease }} steps: - name: Resolve and validate tag id: resolve @@ -45,24 +44,20 @@ jobs: fi CHART_VERSION="${TAG#v}" - IMAGE_SHA="${{ github.sha }}" - IMAGE_SHA="${IMAGE_SHA:0:7}" - # Beta if version contains '-' (e.g. 0.7.0-beta.1) + # Pre-release if version contains '-' (e.g. 0.7.0-rc.1) if [[ "$CHART_VERSION" == *-* ]]; then - IS_BETA="true" + IS_PRERELEASE="true" else - IS_BETA="false" + IS_PRERELEASE="false" fi echo "tag=${TAG}" >> "$GITHUB_OUTPUT" echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT" - echo "image_sha=${IMAGE_SHA}" >> "$GITHUB_OUTPUT" - echo "is_beta=${IS_BETA}" >> "$GITHUB_OUTPUT" + echo "is_prerelease=${IS_PRERELEASE}" >> "$GITHUB_OUTPUT" build-image: needs: resolve-tag - if: ${{ needs.resolve-tag.outputs.is_beta == 'true' }} strategy: matrix: variant: @@ -78,11 +73,11 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: docker/setup-buildx-action@v3 - - uses: docker/login-action@v3 + - uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.repository_owner }} @@ -90,7 +85,7 @@ jobs: - name: Docker metadata id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }} @@ -122,7 +117,7 @@ jobs: merge-manifests: needs: [resolve-tag, build-image] - if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'true' }} + if: ${{ inputs.dry_run != true }} strategy: matrix: variant: @@ -144,15 +139,28 @@ jobs: - uses: docker/setup-buildx-action@v3 - - uses: docker/login-action@v3 + - uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Docker metadata - id: meta - uses: docker/metadata-action@v5 + - name: Docker metadata (stable) + if: ${{ needs.resolve-tag.outputs.is_prerelease == 'false' }} + id: meta-stable + uses: docker/metadata-action@v6 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }} + tags: | + type=sha,prefix= + type=semver,pattern={{version}},value=${{ needs.resolve-tag.outputs.tag }} + type=semver,pattern={{major}}.{{minor}},value=${{ needs.resolve-tag.outputs.tag }} + type=raw,value=latest + + - name: Docker metadata (pre-release) + if: ${{ needs.resolve-tag.outputs.is_prerelease == 'true' }} + id: meta-prerelease + uses: docker/metadata-action@v6 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }} tags: | @@ -165,128 +173,27 @@ jobs: docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}@sha256:%s ' *) - promote-stable: - needs: resolve-tag - if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'false' }} - strategy: - matrix: - variant: - - { suffix: "" } - - { suffix: "-codex" } - - { suffix: "-claude" } - - { suffix: "-gemini" } - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - uses: docker/setup-buildx-action@v3 - - - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Verify beta image exists - run: | - IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}" - IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" - echo "Checking ${IMAGE}:${IMAGE_SHA} ..." - docker buildx imagetools inspect "${IMAGE}:${IMAGE_SHA}" || \ - { echo "::error::Image ${IMAGE}:${IMAGE_SHA} not found — build a beta on this commit first"; exit 1; } - - - name: Promote to stable tags - run: | - IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}" - IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" - CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" - MAJOR_MINOR="${CHART_VERSION%.*}" - - echo "Promoting ${IMAGE}:${IMAGE_SHA} → ${CHART_VERSION}, ${MAJOR_MINOR}, latest" - docker buildx imagetools create \ - -t "${IMAGE}:${CHART_VERSION}" \ - -t "${IMAGE}:${MAJOR_MINOR}" \ - -t "${IMAGE}:latest" \ - "${IMAGE}:${IMAGE_SHA}" - - release-chart-beta: + release-chart: needs: [resolve-tag, merge-manifests] - if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'true' }} + if: ${{ inputs.dry_run != true }} runs-on: ubuntu-latest permissions: contents: read packages: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Helm uses: azure/setup-helm@v4 - - uses: docker/login-action@v3 + - uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push beta chart to OCI + - name: Build and push chart to OCI run: | CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" - IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" - - sed -i "s/^version: .*/version: ${CHART_VERSION}/" charts/openab/Chart.yaml - sed -i "s/^appVersion: .*/appVersion: \"${IMAGE_SHA}\"/" charts/openab/Chart.yaml - sed -i "s|repository: .*|repository: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}|" charts/openab/values.yaml - sed -i "s/tag: .*/tag: \"${IMAGE_SHA}\"/" charts/openab/values.yaml - helm package charts/openab helm push openab-${CHART_VERSION}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts - - bump-chart-stable: - needs: [resolve-tag, promote-stable] - if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_beta == 'false' }} - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - name: Generate App token - id: app-token - uses: actions/create-github-app-token@v1 - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Update Chart.yaml and values.yaml - run: | - CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" - IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" - sed -i "s/^version: .*/version: ${CHART_VERSION}/" charts/openab/Chart.yaml - sed -i "s/^appVersion: .*/appVersion: \"${IMAGE_SHA}\"/" charts/openab/Chart.yaml - sed -i "s|repository: .*|repository: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}|" charts/openab/values.yaml - sed -i "s/tag: .*/tag: \"${IMAGE_SHA}\"/" charts/openab/values.yaml - - - name: Create and auto-merge bump PR - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" - IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" - BRANCH="chore/chart-${CHART_VERSION}" - git config user.name "openab-app[bot]" - git config user.email "274185012+openab-app[bot]@users.noreply.github.com" - git checkout -b "$BRANCH" - git add charts/openab/Chart.yaml charts/openab/values.yaml - git commit -m "chore: bump chart to ${CHART_VERSION} - - image: ${IMAGE_SHA}" - git push origin "$BRANCH" - PR_URL=$(gh pr create \ - --title "chore: bump chart to ${CHART_VERSION}" \ - --body "Auto-generated chart version bump for image \`${IMAGE_SHA}\`." \ - --base main --head "$BRANCH") - gh pr merge "$PR_URL" --squash --delete-branch diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 09e987c4..c2be4c13 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,10 +14,9 @@ jobs: permissions: contents: write pages: write - packages: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 @@ -29,13 +28,6 @@ jobs: - name: Install Helm uses: azure/setup-helm@v4 - - name: Login to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Run chart-releaser uses: helm/chart-releaser-action@v1.6.0 with: @@ -43,15 +35,7 @@ jobs: env: CR_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Push chart to OCI registry - run: | - CHART=charts/openab - NAME=$(grep '^name:' ${CHART}/Chart.yaml | awk '{print $2}') - VERSION=$(grep '^version:' ${CHART}/Chart.yaml | awk '{print $2}') - helm package ${CHART} - helm push ${NAME}-${VERSION}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts - - - name: Append OCI install instructions to release notes + - name: Append install instructions to release notes env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -93,8 +77,3 @@ jobs: printf '%s\n' "${EXISTING}" > /tmp/existing.md cat /tmp/existing.md /tmp/notes.md > /tmp/final.md gh release edit "${TAG}" --repo "${OWNER}/${REPO}" --notes-file /tmp/final.md - - # Mark beta versions as pre-release - case "$VERSION" in - *-*) gh release edit "${TAG}" --repo "${OWNER}/${REPO}" --prerelease ;; - esac diff --git a/.github/workflows/tagpr.yml b/.github/workflows/tagpr.yml index 64f7d00a..004e33a6 100644 --- a/.github/workflows/tagpr.yml +++ b/.github/workflows/tagpr.yml @@ -17,7 +17,17 @@ jobs: tagpr: runs-on: ubuntu-latest steps: + - name: Generate App token + id: app-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + - uses: actions/checkout@v6 + with: + token: ${{ steps.app-token.outputs.token }} + - uses: Songmu/tagpr@9d0f650553240dab1fa907eca27e3fd5b586e538 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.tagpr b/.tagpr index 3df2f89c..87681eae 100644 --- a/.tagpr +++ b/.tagpr @@ -2,7 +2,8 @@ # see: https://github.com/Songmu/tagpr [tagpr] -versionFile = "Cargo.toml" +versionFile = "Cargo.toml,charts/openab/Chart.yaml" tagPrefix = "v" releaseBranch = "main" changelog = true +postVersionCommand = "sed -i 's/^appVersion: .*/appVersion: \"'\"$TAGPR_NEXT_VERSION\"'\"/' charts/openab/Chart.yaml" diff --git a/Cargo.toml b/Cargo.toml index 11f7dadc..27f30527 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openab" -version = "0.1.0" +version = "0.6.0" edition = "2021" [dependencies] diff --git a/RELEASING.md b/RELEASING.md index fec89263..b59658b5 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -2,90 +2,137 @@ ## Version Scheme -Chart versions follow SemVer with beta pre-releases: +Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本號: -- **Beta**: `0.2.1-beta.12345` — auto-generated on every push to main -- **Stable**: `0.2.1` — manually triggered, visible to `helm install` +| Label | 效果 | 範例 | +|---|---|---| +| (無) | patch bump | `0.6.0 → 0.6.1` | +| `tagpr:minor` | minor bump | `0.6.0 → 0.7.0` | +| `tagpr:major` | major bump | `0.6.0 → 1.0.0` | -Users running `helm install` only see stable versions. Beta versions require `--devel` or explicit `--version`. - -## Development Flow +## Release Flow (Tag-Driven) ``` - PR merged to main + ┌─────────────────────────────────────────────────────────────────┐ + │ 1. 貢獻者 PR merge to main │ + │ → tagpr.yml 觸發 │ + │ → tagpr 累積 commits,自動開 Release PR │ + │ (更新 Cargo.toml + Chart.yaml version/appVersion │ + │ + CHANGELOG.md) │ + └─────────────────────────────────────────────────────────────────┘ │ ▼ - ┌─────────────┐ ┌──────────────────┐ ┌─────────────────────┐ - │ CI: Build │────>│ CI: Bump PR │────>│ Merge bump PR │ - │ 3 images │ │ 0.2.1-beta.12345 │ │ → publishes beta │ - └─────────────┘ └──────────────────┘ └─────────────────────┘ - │ - ┌───────────────────────────────────────────────┘ + ┌─────────────────────────────────────────────────────────────────┐ + │ 2. Maintainer review Release PR │ + │ 確認版本號 / changelog 後 merge │ + │ → tagpr 自動打 tag (e.g. v0.7.0) + 建立 GitHub Release │ + └─────────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────────┐ + │ 3. build.yml 被 tag push 觸發 │ + │ → build-image: 4 variants × 2 platforms (amd64 + arm64) │ + │ → merge-manifests: 建立 multi-arch manifest │ + │ → release-chart: 打包 helm chart → OCI registry │ + └─────────────────────────────────────────────────────────────────┘ + │ ▼ - helm install ... --version 0.2.1-beta.12345 (explicit only) - helm install ... (still gets 0.2.0 stable) + ┌─────────────────────────────────────────────────────────────────┐ + │ 4. release.yml 偵測到 Chart.yaml 變更 push to main │ + │ → chart-releaser 更新 GitHub Pages helm repo index │ + │ → 附加 install instructions 到 chart release notes │ + └─────────────────────────────────────────────────────────────────┘ ``` -## Stable Release +## GitHub Releases + +每次 release 會產生兩個 GitHub Release: + +| Release | Tag 格式 | 內容 | +|---|---|---| +| tagpr | `v0.7.0` | CHANGELOG(自動從 commits 產生) | +| chart-releaser | `openab-0.7.0` | Version Info + Installation instructions | + +## Workflow 對應表 + +| Workflow | 觸發條件 | 用途 | +|---|---|---| +| `tagpr.yml` | push to main | 自動開 Release PR、打 tag、建立 GitHub Release | +| `build.yml` | tag push `v*` | build image + push helm chart to OCI | +| `release.yml` | Chart.yaml 變更 push to main | chart-releaser 更新 GitHub Pages index + install instructions | + +## Version 同步 (tagpr) + +tagpr 在 Release PR 中自動更新以下檔案的版本: + +| 檔案 | 欄位 | 更新方式 | +|---|---|---| +| `Cargo.toml` | `version` | tagpr 內建 (`versionFile`) | +| `charts/openab/Chart.yaml` | `version` | tagpr 內建 (`versionFile`) | +| `charts/openab/Chart.yaml` | `appVersion` | `postVersionCommand` | + +三者統一為同一個 semver(e.g. `0.7.0`)。 + +## Image Variants + +每次 build 產出 4 個 multi-arch image (linux/amd64 + linux/arm64): ``` - Actions → Build & Release → Run workflow - [bump: patch] [✅ Stable release] - │ - ▼ - ┌─────────────┐ ┌──────────────────┐ ┌─────────────────────┐ - │ CI: Build │────>│ CI: Bump PR │────>│ Merge bump PR │ - │ 3 images │ │ 0.2.1 │ │ → publishes stable │ - └─────────────┘ └──────────────────┘ └─────────────────────┘ - │ - ┌───────────────────────────────────────────────┘ - ▼ - helm install ... (gets 0.2.1 🎉) +ghcr.io/openabdev/openab # default (kiro-cli) +ghcr.io/openabdev/openab-codex # codex +ghcr.io/openabdev/openab-claude # claude +ghcr.io/openabdev/openab-gemini # gemini ``` -## Release Flow (Tag-Driven) +Image tags 依 release 類型不同: -``` - 1. PR merged to main - │ - ▼ - ┌──────────────────────────────────────────────────────┐ - │ tagpr 自動累積 commits,開 Release PR │ - │ (chore: release vX.Y.Z) │ - └──────────────────────────────────────────────────────┘ - │ - ▼ - 2. Maintainer review Release PR,確認版本號與 changelog - → merge Release PR - │ - ▼ - ┌──────────────────────────────────────────────────────┐ - │ tagpr 自動打 tag (e.g. v0.7.0-beta.1) │ - │ → build.yml 觸發 (tag-driven) │ - └──────────────────────────────────────────────────────┘ - │ - ▼ - 3. Beta 測試通過後,在同一個 commit 打 stable tag: - git tag v0.7.0 - git push origin v0.7.0 - │ - ▼ - ┌──────────────────────────────────────────────────────┐ - │ build.yml promote-stable 觸發 │ - └──────────────────────────────────────────────────────┘ +| Tag | Stable (`v0.7.0`) | Pre-release (`v0.7.0-rc.1`) | +|---|---|---| +| `` | v | v | +| `0.7.0` / `0.7.0-rc.1` | v | v | +| `0.7` | v | x | +| `latest` | v | x | + +## Installation + +##### Helm Repository (GitHub Pages) + +```bash +helm repo add openab https://openabdev.github.io/openab +helm repo update +helm install openab openab/openab --version 0.7.0 ``` -> ⚠️ **重要約束**:stable tag 必須打在跟 beta 完全相同的 commit 上, -> 否則 promote-stable 會驗證失敗。 +##### OCI Registry + +```bash +helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0 +``` -## Image Tags +## Pre-release -Each build produces three multi-arch images tagged with the git short SHA: +tagpr 不支援 pre-release tag。需要手動操作: +```bash +git tag v0.7.0-rc.1 +git push origin v0.7.0-rc.1 ``` -ghcr.io/openabdev/openab: # kiro-cli -ghcr.io/openabdev/openab-codex: # codex -ghcr.io/openabdev/openab-claude: # claude + +build.yml 會觸發完整 build,但 **不會** 覆蓋 `latest` 和 `major.minor` tag。 +Pre-release image 只有 `` 和 `0.7.0-rc.1` 兩個 tag。 + +安裝 pre-release chart: + +```bash +helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0-rc.1 ``` -The `latest` tag always points to the most recent build. +## 手動操作 + +| 時機 | 做什麼 | +|---|---| +| tagpr 開 Release PR 後 | Review 版本號 / CHANGELOG | +| 需要調整版本升級幅度 | 在 Release PR 加 `tagpr:minor` 或 `tagpr:major` label | +| 決定 release | Merge Release PR(之後全自動) | +| 需要 pre-release | 手動打 tag(e.g. `git tag v0.7.0-rc.1 && git push origin v0.7.0-rc.1`) | +| build 失敗或需重跑 | Actions → Build & Release → Run workflow(填入 tag) | diff --git a/charts/openab/Chart.yaml b/charts/openab/Chart.yaml index af5733cb..4452d5c4 100644 --- a/charts/openab/Chart.yaml +++ b/charts/openab/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: openab description: Discord ↔ ACP coding CLI bridge (Kiro CLI, Claude Code, Codex, Gemini) type: application -version: 0.6.3-beta.39 -appVersion: "94253a5" +version: 0.6.0 +appVersion: "0.6.0" From c11bcfe9e87751ecfbc71033f2c69778758e20ec Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 11:38:39 +0800 Subject: [PATCH 09/20] ci: add promote-stable to guarantee pre-release = stable image - Pre-release tag (v0.7.0-rc.1): full build, image tags = sha + version - Stable tag (v0.7.0): promote (re-tag) pre-release image, no rebuild - Verify pre-release image exists before promote, fail if not found - Update RELEASING.md with two-path flow diagram --- .github/workflows/build.yml | 83 ++++++++++++++++++++++++++++--------- RELEASING.md | 57 ++++++++++++++++++------- 2 files changed, 107 insertions(+), 33 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 50a810e5..064e3075 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ on: workflow_dispatch: inputs: tag: - description: 'Version tag (e.g. v0.7.0)' + description: 'Version tag (e.g. v0.7.0-rc.1 or v0.7.0)' required: true type: string dry_run: @@ -26,6 +26,7 @@ jobs: outputs: tag: ${{ steps.resolve.outputs.tag }} chart_version: ${{ steps.resolve.outputs.chart_version }} + image_sha: ${{ steps.resolve.outputs.image_sha }} is_prerelease: ${{ steps.resolve.outputs.is_prerelease }} steps: - name: Resolve and validate tag @@ -44,6 +45,8 @@ jobs: fi CHART_VERSION="${TAG#v}" + IMAGE_SHA="${{ github.sha }}" + IMAGE_SHA="${IMAGE_SHA:0:7}" # Pre-release if version contains '-' (e.g. 0.7.0-rc.1) if [[ "$CHART_VERSION" == *-* ]]; then @@ -54,10 +57,14 @@ jobs: echo "tag=${TAG}" >> "$GITHUB_OUTPUT" echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT" + echo "image_sha=${IMAGE_SHA}" >> "$GITHUB_OUTPUT" echo "is_prerelease=${IS_PRERELEASE}" >> "$GITHUB_OUTPUT" + # ── Pre-release path: full build ────────────────────────────── + build-image: needs: resolve-tag + if: ${{ needs.resolve-tag.outputs.is_prerelease == 'true' }} strategy: matrix: variant: @@ -117,7 +124,7 @@ jobs: merge-manifests: needs: [resolve-tag, build-image] - if: ${{ inputs.dry_run != true }} + if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_prerelease == 'true' }} strategy: matrix: variant: @@ -145,21 +152,8 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Docker metadata (stable) - if: ${{ needs.resolve-tag.outputs.is_prerelease == 'false' }} - id: meta-stable - uses: docker/metadata-action@v6 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }} - tags: | - type=sha,prefix= - type=semver,pattern={{version}},value=${{ needs.resolve-tag.outputs.tag }} - type=semver,pattern={{major}}.{{minor}},value=${{ needs.resolve-tag.outputs.tag }} - type=raw,value=latest - - - name: Docker metadata (pre-release) - if: ${{ needs.resolve-tag.outputs.is_prerelease == 'true' }} - id: meta-prerelease + - name: Docker metadata + id: meta uses: docker/metadata-action@v6 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }} @@ -173,9 +167,60 @@ jobs: docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}@sha256:%s ' *) + # ── Stable path: promote pre-release image (no rebuild) ────── + + promote-stable: + needs: resolve-tag + if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_prerelease == 'false' }} + strategy: + matrix: + variant: + - { suffix: "" } + - { suffix: "-codex" } + - { suffix: "-claude" } + - { suffix: "-gemini" } + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: docker/setup-buildx-action@v3 + + - uses: docker/login-action@v4 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Verify pre-release image exists + run: | + IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}" + IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" + echo "Checking ${IMAGE}:${IMAGE_SHA} ..." + docker buildx imagetools inspect "${IMAGE}:${IMAGE_SHA}" || \ + { echo "::error::Image ${IMAGE}:${IMAGE_SHA} not found — build a pre-release on this commit first"; exit 1; } + + - name: Promote to stable tags + run: | + IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}" + IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" + CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" + MAJOR_MINOR="${CHART_VERSION%.*}" + + echo "Promoting ${IMAGE}:${IMAGE_SHA} → ${CHART_VERSION}, ${MAJOR_MINOR}, latest" + docker buildx imagetools create \ + -t "${IMAGE}:${CHART_VERSION}" \ + -t "${IMAGE}:${MAJOR_MINOR}" \ + -t "${IMAGE}:latest" \ + "${IMAGE}:${IMAGE_SHA}" + + # ── Chart release (runs after either path) ─────────────────── + release-chart: - needs: [resolve-tag, merge-manifests] - if: ${{ inputs.dry_run != true }} + needs: [resolve-tag, merge-manifests, promote-stable] + if: >- + ${{ always() && inputs.dry_run != true && + (needs.merge-manifests.result == 'success' || needs.promote-stable.result == 'success') }} runs-on: ubuntu-latest permissions: contents: read diff --git a/RELEASING.md b/RELEASING.md index b59658b5..befabbbf 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -12,6 +12,31 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 ## Release Flow (Tag-Driven) +##### Pre-release path(測試用,完整 build) + +``` + ┌─────────────────────────────────────────────────────────────────┐ + │ 1. Maintainer 手動打 pre-release tag │ + │ git tag v0.7.0-rc.1 && git push origin v0.7.0-rc.1 │ + └─────────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────────┐ + │ 2. build.yml 被 tag push 觸發 (is_prerelease=true) │ + │ → build-image: 4 variants × 2 platforms (amd64 + arm64) │ + │ → merge-manifests: image tags = + 0.7.0-rc.1 │ + │ → release-chart: helm chart → OCI registry │ + └─────────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────────────────────────────────┐ + │ 3. 內部測試驗證 pre-release │ + │ helm install openab oci://... --version 0.7.0-rc.1 │ + └─────────────────────────────────────────────────────────────────┘ +``` + +##### Stable path(正式發布,promote 不 rebuild) + ``` ┌─────────────────────────────────────────────────────────────────┐ │ 1. 貢獻者 PR merge to main │ @@ -30,10 +55,11 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 │ ▼ ┌─────────────────────────────────────────────────────────────────┐ - │ 3. build.yml 被 tag push 觸發 │ - │ → build-image: 4 variants × 2 platforms (amd64 + arm64) │ - │ → merge-manifests: 建立 multi-arch manifest │ - │ → release-chart: 打包 helm chart → OCI registry │ + │ 3. build.yml 被 tag push 觸發 (is_prerelease=false) │ + │ → promote-stable: 驗證 pre-release image 存在 │ + │ re-tag → 0.7.0 / 0.7 / latest │ + │ ⚠️ 不 rebuild,跟 pre-release 是同一個 artifact │ + │ → release-chart: helm chart → OCI registry │ └─────────────────────────────────────────────────────────────────┘ │ ▼ @@ -44,6 +70,10 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 └─────────────────────────────────────────────────────────────────┘ ``` +> ⚠️ **核心原則:測過什麼就發什麼 (what you tested is what you ship)** +> stable release 不重新 build,直接 promote pre-release 驗證過的 image。 +> stable tag 必須打在跟 pre-release 完全相同的 commit 上,否則 promote 會驗證失敗。 + ## GitHub Releases 每次 release 會產生兩個 GitHub Release: @@ -58,7 +88,7 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 | Workflow | 觸發條件 | 用途 | |---|---|---| | `tagpr.yml` | push to main | 自動開 Release PR、打 tag、建立 GitHub Release | -| `build.yml` | tag push `v*` | build image + push helm chart to OCI | +| `build.yml` | tag push `v*` | pre-release: 完整 build / stable: promote image + push chart | | `release.yml` | Chart.yaml 變更 push to main | chart-releaser 更新 GitHub Pages index + install instructions | ## Version 同步 (tagpr) @@ -109,22 +139,21 @@ helm install openab openab/openab --version 0.7.0 helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0 ``` -## Pre-release - -tagpr 不支援 pre-release tag。需要手動操作: +## Pre-release → Stable 範例 ```bash +# 1. 打 pre-release tag → 完整 build git tag v0.7.0-rc.1 git push origin v0.7.0-rc.1 -``` -build.yml 會觸發完整 build,但 **不會** 覆蓋 `latest` 和 `major.minor` tag。 -Pre-release image 只有 `` 和 `0.7.0-rc.1` 兩個 tag。 +# 2. 內部測試 +helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0-rc.1 -安裝 pre-release chart: +# 3. 測試通過 → merge tagpr 的 Release PR +# tagpr 打 v0.7.0 tag → promote 同一個 image(不 rebuild) -```bash -helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0-rc.1 +# 4. 外部用戶安裝(拿到的是跟 rc.1 一模一樣的 image) +helm install openab openab/openab --version 0.7.0 ``` ## 手動操作 From 5ba32426ff8823380d9038b08de2af54df9ddd43 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 11:48:56 +0800 Subject: [PATCH 10/20] docs: rewrite RELEASING.md with complete release flow and constraints --- RELEASING.md | 153 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 61 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index befabbbf..fadf211b 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -12,67 +12,107 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 ## Release Flow (Tag-Driven) -##### Pre-release path(測試用,完整 build) +> **核心原則:測過什麼就發什麼 (what you tested is what you ship)** +> stable release 不重新 build,直接 promote pre-release 驗證過的 image。 + +##### Step 1 — 累積變更 ``` ┌─────────────────────────────────────────────────────────────────┐ - │ 1. Maintainer 手動打 pre-release tag │ - │ git tag v0.7.0-rc.1 && git push origin v0.7.0-rc.1 │ + │ 貢獻者 PR merge to main │ + │ → tagpr.yml 觸發 │ + │ → tagpr 累積 commits,自動開 Release PR │ + │ (更新 Cargo.toml + Chart.yaml version/appVersion + CHANGELOG) │ └─────────────────────────────────────────────────────────────────┘ - │ - ▼ - ┌─────────────────────────────────────────────────────────────────┐ - │ 2. build.yml 被 tag push 觸發 (is_prerelease=true) │ - │ → build-image: 4 variants × 2 platforms (amd64 + arm64) │ - │ → merge-manifests: image tags = + 0.7.0-rc.1 │ - │ → release-chart: helm chart → OCI registry │ - └─────────────────────────────────────────────────────────────────┘ - │ - ▼ +``` + +##### Step 2 — Merge Release PR + +``` ┌─────────────────────────────────────────────────────────────────┐ - │ 3. 內部測試驗證 pre-release │ - │ helm install openab oci://... --version 0.7.0-rc.1 │ + │ Maintainer review Release PR │ + │ 確認版本號 / changelog 後 merge │ + │ → tagpr 自動打 tag (e.g. v0.7.0) + 建立 GitHub Release │ + │ → build.yml 觸發 (is_prerelease=false) │ + │ → promote-stable 失敗(預期中,還沒有 pre-release image) │ └─────────────────────────────────────────────────────────────────┘ ``` -##### Stable path(正式發布,promote 不 rebuild) +##### Step 3 — Pre-release(在同一個 commit 上) ``` ┌─────────────────────────────────────────────────────────────────┐ - │ 1. 貢獻者 PR merge to main │ - │ → tagpr.yml 觸發 │ - │ → tagpr 累積 commits,自動開 Release PR │ - │ (更新 Cargo.toml + Chart.yaml version/appVersion │ - │ + CHANGELOG.md) │ + │ 在 tagpr 的 stable tag 同一個 commit 上打 pre-release tag: │ + │ │ + │ git tag v0.7.0-rc.1 v0.7.0 │ + │ git push origin v0.7.0-rc.1 │ + │ │ + │ → build.yml 觸發 (is_prerelease=true) │ + │ → build-image: 4 variants × 2 platforms (amd64 + arm64) │ + │ → merge-manifests: image tags = + 0.7.0-rc.1 │ + │ → release-chart: helm chart → OCI registry │ └─────────────────────────────────────────────────────────────────┘ - │ - ▼ +``` + +> **關鍵**:`git tag v0.7.0-rc.1 v0.7.0` 用 stable tag 當 ref, +> 確保 pre-release 跟 stable 在完全相同的 commit 上。 + +##### Step 4 — 內部測試 + +``` ┌─────────────────────────────────────────────────────────────────┐ - │ 2. Maintainer review Release PR │ - │ 確認版本號 / changelog 後 merge │ - │ → tagpr 自動打 tag (e.g. v0.7.0) + 建立 GitHub Release │ + │ 部署 pre-release 進行測試: │ + │ │ + │ helm install openab \ │ + │ oci://ghcr.io/openabdev/charts/openab \ │ + │ --version 0.7.0-rc.1 │ + │ │ + │ 發現 bug?→ 修復 → 回到 Step 1(下一輪 release cycle) │ └─────────────────────────────────────────────────────────────────┘ - │ - ▼ +``` + +##### Step 5 — 測試通過,Promote to Stable + +``` ┌─────────────────────────────────────────────────────────────────┐ - │ 3. build.yml 被 tag push 觸發 (is_prerelease=false) │ - │ → promote-stable: 驗證 pre-release image 存在 │ - │ re-tag → 0.7.0 / 0.7 / latest │ - │ ⚠️ 不 rebuild,跟 pre-release 是同一個 artifact │ - │ → release-chart: helm chart → OCI registry │ + │ 重新觸發 stable build: │ + │ │ + │ gh workflow run build.yml -f tag=v0.7.0 │ + │ │ + │ → promote-stable: 驗證 pre-release image 存在 │ + │ re-tag → 0.7.0 / 0.7 / latest │ + │ ⚠️ 不 rebuild,跟 pre-release 是同一個 artifact │ + │ → release-chart: helm chart → OCI registry │ └─────────────────────────────────────────────────────────────────┘ - │ - ▼ +``` + +##### Step 6 — Chart Release + +``` ┌─────────────────────────────────────────────────────────────────┐ - │ 4. release.yml 偵測到 Chart.yaml 變更 push to main │ - │ → chart-releaser 更新 GitHub Pages helm repo index │ - │ → 附加 install instructions 到 chart release notes │ + │ release.yml 偵測到 Chart.yaml 變更 push to main │ + │ → chart-releaser 更新 GitHub Pages helm repo index │ + │ → 附加 install instructions 到 chart release notes │ └─────────────────────────────────────────────────────────────────┘ ``` -> ⚠️ **核心原則:測過什麼就發什麼 (what you tested is what you ship)** -> stable release 不重新 build,直接 promote pre-release 驗證過的 image。 -> stable tag 必須打在跟 pre-release 完全相同的 commit 上,否則 promote 會驗證失敗。 +## 快速指令參考 + +```bash +# ── Pre-release(Step 3)────────────────────────────── +git tag v0.7.0-rc.1 v0.7.0 +git push origin v0.7.0-rc.1 + +# ── 第二輪 pre-release(如果 rc.1 有 bug)──────────── +# 修 bug → PR merge → 重新走 Step 1-3 +# tagpr 會開新的 Release PR (v0.7.1) + +# ── Promote to stable(Step 5)──────────────────────── +gh workflow run build.yml -f tag=v0.7.0 + +# ── 手動重跑(build 失敗時)────────────────────────── +gh workflow run build.yml -f tag=v0.7.0-rc.1 +``` ## GitHub Releases @@ -118,7 +158,7 @@ Image tags 依 release 類型不同: | Tag | Stable (`v0.7.0`) | Pre-release (`v0.7.0-rc.1`) | |---|---|---| -| `` | v | v | +| `` | v (from pre-release) | v | | `0.7.0` / `0.7.0-rc.1` | v | v | | `0.7` | v | x | | `latest` | v | x | @@ -139,29 +179,20 @@ helm install openab openab/openab --version 0.7.0 helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0 ``` -## Pre-release → Stable 範例 - -```bash -# 1. 打 pre-release tag → 完整 build -git tag v0.7.0-rc.1 -git push origin v0.7.0-rc.1 - -# 2. 內部測試 -helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0-rc.1 - -# 3. 測試通過 → merge tagpr 的 Release PR -# tagpr 打 v0.7.0 tag → promote 同一個 image(不 rebuild) - -# 4. 外部用戶安裝(拿到的是跟 rc.1 一模一樣的 image) -helm install openab openab/openab --version 0.7.0 -``` - ## 手動操作 | 時機 | 做什麼 | |---|---| | tagpr 開 Release PR 後 | Review 版本號 / CHANGELOG | | 需要調整版本升級幅度 | 在 Release PR 加 `tagpr:minor` 或 `tagpr:major` label | -| 決定 release | Merge Release PR(之後全自動) | -| 需要 pre-release | 手動打 tag(e.g. `git tag v0.7.0-rc.1 && git push origin v0.7.0-rc.1`) | +| 決定 release | Merge Release PR(tagpr 打 stable tag) | +| Pre-release | `git tag v0.7.0-rc.1 v0.7.0 && git push origin v0.7.0-rc.1` | +| 測試通過,promote stable | `gh workflow run build.yml -f tag=v0.7.0` | | build 失敗或需重跑 | Actions → Build & Release → Run workflow(填入 tag) | + +## 限制與注意事項 + +- **Stable release 必須先有 pre-release**:promote-stable 會驗證 image 是否存在,沒有 pre-release build 過就無法 promote +- **Pre-release 必須在同一 commit**:用 `git tag v0.7.0-rc.1 v0.7.0` 確保跟 stable tag 指向同一 commit +- **Promote 需手動觸發**:tagpr 打 stable tag 時 promote 會失敗(還沒 pre-release),測試通過後用 `gh workflow run` 重跑 +- **外部用戶不會裝到 pre-release**:`helm install` 預設只拿 stable 版本,pre-release 需明確指定 `--version` From 84c1902cf9759d65fc9d98e5b76845478e8b17c5 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 11:56:17 +0800 Subject: [PATCH 11/20] ci: promote-stable finds pre-release image by version tag, not commit SHA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - promote-stable uses git tag -l to find latest pre-release tag (e.g. v0.7.0-rc.*) - re-tags pre-release image to stable tags (no rebuild, same artifact) - removes commit SHA dependency — pre-release and stable can be on different commits - natural flow: pre-release first → test → merge Release PR → auto promote --- .github/workflows/build.yml | 36 +++++++++++------ RELEASING.md | 77 +++++++++++++++---------------------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 064e3075..49a12314 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,6 @@ jobs: outputs: tag: ${{ steps.resolve.outputs.tag }} chart_version: ${{ steps.resolve.outputs.chart_version }} - image_sha: ${{ steps.resolve.outputs.image_sha }} is_prerelease: ${{ steps.resolve.outputs.is_prerelease }} steps: - name: Resolve and validate tag @@ -45,8 +44,6 @@ jobs: fi CHART_VERSION="${TAG#v}" - IMAGE_SHA="${{ github.sha }}" - IMAGE_SHA="${IMAGE_SHA:0:7}" # Pre-release if version contains '-' (e.g. 0.7.0-rc.1) if [[ "$CHART_VERSION" == *-* ]]; then @@ -57,7 +54,6 @@ jobs: echo "tag=${TAG}" >> "$GITHUB_OUTPUT" echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT" - echo "image_sha=${IMAGE_SHA}" >> "$GITHUB_OUTPUT" echo "is_prerelease=${IS_PRERELEASE}" >> "$GITHUB_OUTPUT" # ── Pre-release path: full build ────────────────────────────── @@ -184,6 +180,10 @@ jobs: contents: read packages: write steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: docker/setup-buildx-action@v3 - uses: docker/login-action@v4 @@ -192,27 +192,41 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Find pre-release image + id: find-prerelease + run: | + CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" + # Find latest pre-release tag matching this version (e.g. v0.7.0-rc.1) + PRERELEASE_TAG=$(git tag -l "v${CHART_VERSION}-*" --sort=-v:refname | head -1) + if [ -z "$PRERELEASE_TAG" ]; then + echo "::error::No pre-release tag found for v${CHART_VERSION}-*. Run a pre-release build first." + exit 1 + fi + PRERELEASE_VERSION="${PRERELEASE_TAG#v}" + echo "Found pre-release: ${PRERELEASE_TAG} (${PRERELEASE_VERSION})" + echo "prerelease_version=${PRERELEASE_VERSION}" >> "$GITHUB_OUTPUT" + - name: Verify pre-release image exists run: | IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}" - IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" - echo "Checking ${IMAGE}:${IMAGE_SHA} ..." - docker buildx imagetools inspect "${IMAGE}:${IMAGE_SHA}" || \ - { echo "::error::Image ${IMAGE}:${IMAGE_SHA} not found — build a pre-release on this commit first"; exit 1; } + PRERELEASE_VERSION="${{ steps.find-prerelease.outputs.prerelease_version }}" + echo "Checking ${IMAGE}:${PRERELEASE_VERSION} ..." + docker buildx imagetools inspect "${IMAGE}:${PRERELEASE_VERSION}" || \ + { echo "::error::Image ${IMAGE}:${PRERELEASE_VERSION} not found — build the pre-release first"; exit 1; } - name: Promote to stable tags run: | IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }}" - IMAGE_SHA="${{ needs.resolve-tag.outputs.image_sha }}" + PRERELEASE_VERSION="${{ steps.find-prerelease.outputs.prerelease_version }}" CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" MAJOR_MINOR="${CHART_VERSION%.*}" - echo "Promoting ${IMAGE}:${IMAGE_SHA} → ${CHART_VERSION}, ${MAJOR_MINOR}, latest" + echo "Promoting ${IMAGE}:${PRERELEASE_VERSION} → ${CHART_VERSION}, ${MAJOR_MINOR}, latest" docker buildx imagetools create \ -t "${IMAGE}:${CHART_VERSION}" \ -t "${IMAGE}:${MAJOR_MINOR}" \ -t "${IMAGE}:latest" \ - "${IMAGE}:${IMAGE_SHA}" + "${IMAGE}:${PRERELEASE_VERSION}" # ── Chart release (runs after either path) ─────────────────── diff --git a/RELEASING.md b/RELEASING.md index fadf211b..6af096dc 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -26,25 +26,13 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 └─────────────────────────────────────────────────────────────────┘ ``` -##### Step 2 — Merge Release PR +##### Step 2 — Pre-release Build & 測試 ``` ┌─────────────────────────────────────────────────────────────────┐ - │ Maintainer review Release PR │ - │ 確認版本號 / changelog 後 merge │ - │ → tagpr 自動打 tag (e.g. v0.7.0) + 建立 GitHub Release │ - │ → build.yml 觸發 (is_prerelease=false) │ - │ → promote-stable 失敗(預期中,還沒有 pre-release image) │ - └─────────────────────────────────────────────────────────────────┘ -``` - -##### Step 3 — Pre-release(在同一個 commit 上) - -``` - ┌─────────────────────────────────────────────────────────────────┐ - │ 在 tagpr 的 stable tag 同一個 commit 上打 pre-release tag: │ + │ 針對要測試的 commit 打 pre-release tag: │ │ │ - │ git tag v0.7.0-rc.1 v0.7.0 │ + │ git tag v0.7.0-rc.1 │ │ git push origin v0.7.0-rc.1 │ │ │ │ → build.yml 觸發 (is_prerelease=true) │ @@ -52,14 +40,8 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 │ → merge-manifests: image tags = + 0.7.0-rc.1 │ │ → release-chart: helm chart → OCI registry │ └─────────────────────────────────────────────────────────────────┘ -``` - -> **關鍵**:`git tag v0.7.0-rc.1 v0.7.0` 用 stable tag 當 ref, -> 確保 pre-release 跟 stable 在完全相同的 commit 上。 - -##### Step 4 — 內部測試 - -``` + │ + ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 部署 pre-release 進行測試: │ │ │ @@ -67,26 +49,28 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 │ oci://ghcr.io/openabdev/charts/openab \ │ │ --version 0.7.0-rc.1 │ │ │ - │ 發現 bug?→ 修復 → 回到 Step 1(下一輪 release cycle) │ + │ 發現 bug?→ 修復 PR merge → 打 v0.7.0-rc.2 → 重新測試 │ └─────────────────────────────────────────────────────────────────┘ ``` -##### Step 5 — 測試通過,Promote to Stable +##### Step 3 — 測試通過,Merge Release PR ``` ┌─────────────────────────────────────────────────────────────────┐ - │ 重新觸發 stable build: │ - │ │ - │ gh workflow run build.yml -f tag=v0.7.0 │ + │ Maintainer merge Release PR │ + │ → tagpr 自動打 tag (e.g. v0.7.0) + 建立 GitHub Release │ │ │ - │ → promote-stable: 驗證 pre-release image 存在 │ - │ re-tag → 0.7.0 / 0.7 / latest │ + │ → build.yml 觸發 (is_prerelease=false) │ + │ → promote-stable: │ + │ 1. 找到最新的 pre-release tag (v0.7.0-rc.2) │ + │ 2. 驗證 pre-release image 存在 │ + │ 3. re-tag 0.7.0-rc.2 → 0.7.0 / 0.7 / latest │ │ ⚠️ 不 rebuild,跟 pre-release 是同一個 artifact │ │ → release-chart: helm chart → OCI registry │ └─────────────────────────────────────────────────────────────────┘ ``` -##### Step 6 — Chart Release +##### Step 4 — Chart Release(自動) ``` ┌─────────────────────────────────────────────────────────────────┐ @@ -99,19 +83,22 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 ## 快速指令參考 ```bash -# ── Pre-release(Step 3)────────────────────────────── -git tag v0.7.0-rc.1 v0.7.0 +# ── Pre-release(Step 2)────────────────────────────── +git tag v0.7.0-rc.1 git push origin v0.7.0-rc.1 -# ── 第二輪 pre-release(如果 rc.1 有 bug)──────────── -# 修 bug → PR merge → 重新走 Step 1-3 -# tagpr 會開新的 Release PR (v0.7.1) +# ── 第二輪 pre-release(rc.1 有 bug 時)───────────── +# 修 bug → PR merge to main → 打新 rc tag +git tag v0.7.0-rc.2 +git push origin v0.7.0-rc.2 -# ── Promote to stable(Step 5)──────────────────────── -gh workflow run build.yml -f tag=v0.7.0 +# ── Stable release(Step 3)─────────────────────────── +# 直接在 GitHub merge tagpr 的 Release PR 即可 +# tagpr 自動打 v0.7.0 tag → promote 最新的 rc image # ── 手動重跑(build 失敗時)────────────────────────── gh workflow run build.yml -f tag=v0.7.0-rc.1 +gh workflow run build.yml -f tag=v0.7.0 ``` ## GitHub Releases @@ -128,7 +115,7 @@ gh workflow run build.yml -f tag=v0.7.0-rc.1 | Workflow | 觸發條件 | 用途 | |---|---|---| | `tagpr.yml` | push to main | 自動開 Release PR、打 tag、建立 GitHub Release | -| `build.yml` | tag push `v*` | pre-release: 完整 build / stable: promote image + push chart | +| `build.yml` | tag push `v*` | pre-release: 完整 build / stable: promote pre-release image | | `release.yml` | Chart.yaml 變更 push to main | chart-releaser 更新 GitHub Pages index + install instructions | ## Version 同步 (tagpr) @@ -185,14 +172,12 @@ helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0 |---|---| | tagpr 開 Release PR 後 | Review 版本號 / CHANGELOG | | 需要調整版本升級幅度 | 在 Release PR 加 `tagpr:minor` 或 `tagpr:major` label | -| 決定 release | Merge Release PR(tagpr 打 stable tag) | -| Pre-release | `git tag v0.7.0-rc.1 v0.7.0 && git push origin v0.7.0-rc.1` | -| 測試通過,promote stable | `gh workflow run build.yml -f tag=v0.7.0` | -| build 失敗或需重跑 | Actions → Build & Release → Run workflow(填入 tag) | +| Pre-release | `git tag v0.7.0-rc.1 && git push origin v0.7.0-rc.1` | +| 測試通過 | Merge Release PR(tagpr 打 stable tag → 自動 promote) | +| build 失敗或需重跑 | `gh workflow run build.yml -f tag=` | ## 限制與注意事項 -- **Stable release 必須先有 pre-release**:promote-stable 會驗證 image 是否存在,沒有 pre-release build 過就無法 promote -- **Pre-release 必須在同一 commit**:用 `git tag v0.7.0-rc.1 v0.7.0` 確保跟 stable tag 指向同一 commit -- **Promote 需手動觸發**:tagpr 打 stable tag 時 promote 會失敗(還沒 pre-release),測試通過後用 `gh workflow run` 重跑 +- **Stable release 必須先有 pre-release**:promote-stable 會查找 `v{version}-*` 的 pre-release tag,找不到就失敗 +- **promote 用 version tag 找 image**:不依賴 commit SHA,pre-release 和 stable 可以在不同 commit 上 - **外部用戶不會裝到 pre-release**:`helm install` 預設只拿 stable 版本,pre-release 需明確指定 `--version` From aa0933340b862e6e85647e3250e11ffa82a907cd Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Thu, 9 Apr 2026 13:42:00 +0800 Subject: [PATCH 12/20] chore: update openab version to 0.6.0 in Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ac944efe..5fad25ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -763,7 +763,7 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "openab" -version = "0.1.0" +version = "0.6.0" dependencies = [ "anyhow", "base64", From e3169f895ee71955ea840908c583debb904dd804 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Sat, 11 Apr 2026 13:27:15 +0800 Subject: [PATCH 13/20] ci: upgrade tagpr to v1.18.1 and use vPrefix config --- .github/workflows/tagpr.yml | 2 +- .tagpr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tagpr.yml b/.github/workflows/tagpr.yml index 004e33a6..b9dc8593 100644 --- a/.github/workflows/tagpr.yml +++ b/.github/workflows/tagpr.yml @@ -28,6 +28,6 @@ jobs: with: token: ${{ steps.app-token.outputs.token }} - - uses: Songmu/tagpr@9d0f650553240dab1fa907eca27e3fd5b586e538 + - uses: Songmu/tagpr@v1.18.1 env: GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.tagpr b/.tagpr index 87681eae..e58885af 100644 --- a/.tagpr +++ b/.tagpr @@ -3,7 +3,7 @@ [tagpr] versionFile = "Cargo.toml,charts/openab/Chart.yaml" -tagPrefix = "v" +vPrefix = true releaseBranch = "main" changelog = true postVersionCommand = "sed -i 's/^appVersion: .*/appVersion: \"'\"$TAGPR_NEXT_VERSION\"'\"/' charts/openab/Chart.yaml" From ce48efafd6bc37276cc4c915cf6d6a9037d66d94 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Sat, 11 Apr 2026 13:31:03 +0800 Subject: [PATCH 14/20] ci: replace deprecated app-id with client-id in create-github-app-token --- .github/workflows/tagpr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tagpr.yml b/.github/workflows/tagpr.yml index b9dc8593..4e6372b4 100644 --- a/.github/workflows/tagpr.yml +++ b/.github/workflows/tagpr.yml @@ -21,7 +21,7 @@ jobs: id: app-token uses: actions/create-github-app-token@v3 with: - app-id: ${{ secrets.APP_ID }} + client-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} - uses: actions/checkout@v6 From 2a1bc5dbd252eafaeb54d5e1c4ec8d761e3b7fcb Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Sat, 11 Apr 2026 13:34:52 +0800 Subject: [PATCH 15/20] ci: add CI workflow for PR validation on source and Dockerfile changes --- .github/workflows/ci.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..4239edd9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,33 @@ +name: CI + +on: + pull_request: + paths: + - "src/**" + - "Cargo.toml" + - "Cargo.lock" + - "Dockerfile*" + +env: + CARGO_TERM_COLOR: always + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - uses: Swatinem/rust-cache@v2 + + - name: cargo check + run: cargo check + + - name: cargo clippy + run: cargo clippy -- -D warnings + + - name: cargo test + run: cargo test From e79d71a46b951a65ea9182ab29a410419eaff472 Mon Sep 17 00:00:00 2001 From: Neil Kuan Date: Sat, 11 Apr 2026 13:44:29 +0800 Subject: [PATCH 16/20] docs: add GitHub App permissions to RELEASING.md --- RELEASING.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/RELEASING.md b/RELEASING.md index 6af096dc..b9d2c5a4 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -176,6 +176,23 @@ helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0 | 測試通過 | Merge Release PR(tagpr 打 stable tag → 自動 promote) | | build 失敗或需重跑 | `gh workflow run build.yml -f tag=` | +## GitHub App 權限 + +tagpr 使用 GitHub App token 來推送 tag 和建立 Release PR。App 需要以下 Repository permissions: + +| Permission | Access | +|---|---| +| Actions | Read and write | +| Commit statuses | Read-only | +| Contents | Read and write | +| Issues | Read and write | +| Merge queues | Read and write | +| Metadata | Read-only (mandatory) | +| Packages | Read and write | +| Pull requests | Read and write | + +對應的 secrets:`APP_ID`(Client ID)、`APP_PRIVATE_KEY`。 + ## 限制與注意事項 - **Stable release 必須先有 pre-release**:promote-stable 會查找 `v{version}-*` 的 pre-release tag,找不到就失敗 From 7fb9cdea971f88e5380427b7404ef2c076e69329 Mon Sep 17 00:00:00 2001 From: thepagent Date: Sat, 11 Apr 2026 14:15:11 +0800 Subject: [PATCH 17/20] ci: replace tagpr with native GitHub workflows - Remove tagpr.yml and .tagpr (third-party dependency) - Add release-pr.yml: workflow_dispatch with auto/manual version bump - Add tag-on-merge.yml: auto-tag on release PR merge - Update RELEASING.md: document new flow, simplify App permissions --- .github/workflows/release-pr.yml | 80 ++++++++++++++++++++++ .github/workflows/tag-on-merge.yml | 34 ++++++++++ .github/workflows/tagpr.yml | 33 --------- .tagpr | 9 --- RELEASING.md | 104 +++++++++++++++-------------- 5 files changed, 167 insertions(+), 93 deletions(-) create mode 100644 .github/workflows/release-pr.yml create mode 100644 .github/workflows/tag-on-merge.yml delete mode 100644 .github/workflows/tagpr.yml delete mode 100644 .tagpr diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml new file mode 100644 index 00000000..098297fb --- /dev/null +++ b/.github/workflows/release-pr.yml @@ -0,0 +1,80 @@ +name: Release PR + +on: + workflow_dispatch: + inputs: + version: + description: "Version (leave empty for auto bump, or specify e.g. 0.8.0-rc.1)" + required: false + type: string + bump: + description: "Auto bump type (ignored when version is specified)" + required: false + type: choice + options: + - patch + - minor + - major + default: patch + +jobs: + create-release-pr: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Generate App token + id: app-token + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - uses: actions/checkout@v6 + with: + token: ${{ steps.app-token.outputs.token }} + fetch-depth: 0 + + - name: Resolve version + id: version + run: | + if [ -n "${{ inputs.version }}" ]; then + VERSION="${{ inputs.version }}" + else + CURRENT=$(grep '^version = ' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/') + BASE="${CURRENT%%-*}" + IFS='.' read -r major minor patch <<< "$BASE" + case "${{ inputs.bump }}" in + major) major=$((major + 1)); minor=0; patch=0 ;; + minor) minor=$((minor + 1)); patch=0 ;; + patch) patch=$((patch + 1)) ;; + esac + VERSION="${major}.${minor}.${patch}-rc.1" + fi + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "::notice::Release version: ${VERSION}" + + - name: Update version files + run: | + VERSION="${{ steps.version.outputs.version }}" + sed -i "s/^version = .*/version = \"${VERSION}\"/" Cargo.toml + sed -i "s/^version: .*/version: ${VERSION}/" charts/openab/Chart.yaml + sed -i "s/^appVersion: .*/appVersion: \"${VERSION}\"/" charts/openab/Chart.yaml + + - name: Create release PR + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + VERSION="${{ steps.version.outputs.version }}" + BRANCH="release/v${VERSION}" + git config user.name "openab-app[bot]" + git config user.email "274185012+openab-app[bot]@users.noreply.github.com" + git checkout -b "$BRANCH" + git add -A + git commit -m "release: v${VERSION}" + git push origin "$BRANCH" + gh pr create \ + --title "release: v${VERSION}" \ + --body "Merge this PR to tag \`v${VERSION}\` and trigger the build pipeline." \ + --base main --head "$BRANCH" diff --git a/.github/workflows/tag-on-merge.yml b/.github/workflows/tag-on-merge.yml new file mode 100644 index 00000000..65c492b9 --- /dev/null +++ b/.github/workflows/tag-on-merge.yml @@ -0,0 +1,34 @@ +name: Tag on Release PR merge + +on: + pull_request: + types: [closed] + branches: [main] + +jobs: + tag: + if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Generate App token + id: app-token + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - uses: actions/checkout@v6 + with: + token: ${{ steps.app-token.outputs.token }} + + - name: Create and push tag + run: | + # release/v0.8.0-rc.1 → v0.8.0-rc.1 + VERSION="${GITHUB_HEAD_REF#release/}" + git config user.name "openab-app[bot]" + git config user.email "274185012+openab-app[bot]@users.noreply.github.com" + git tag "$VERSION" + git push origin "$VERSION" + echo "::notice::Tagged ${VERSION}" diff --git a/.github/workflows/tagpr.yml b/.github/workflows/tagpr.yml deleted file mode 100644 index 4e6372b4..00000000 --- a/.github/workflows/tagpr.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: tagpr - -on: - push: - branches: - - main - -permissions: - contents: write - pull-requests: write - -concurrency: - group: tagpr - cancel-in-progress: false - -jobs: - tagpr: - runs-on: ubuntu-latest - steps: - - name: Generate App token - id: app-token - uses: actions/create-github-app-token@v3 - with: - client-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - uses: actions/checkout@v6 - with: - token: ${{ steps.app-token.outputs.token }} - - - uses: Songmu/tagpr@v1.18.1 - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.tagpr b/.tagpr deleted file mode 100644 index e58885af..00000000 --- a/.tagpr +++ /dev/null @@ -1,9 +0,0 @@ -# tagpr configuration -# see: https://github.com/Songmu/tagpr - -[tagpr] -versionFile = "Cargo.toml,charts/openab/Chart.yaml" -vPrefix = true -releaseBranch = "main" -changelog = true -postVersionCommand = "sed -i 's/^appVersion: .*/appVersion: \"'\"$TAGPR_NEXT_VERSION\"'\"/' charts/openab/Chart.yaml" diff --git a/RELEASING.md b/RELEASING.md index b9d2c5a4..afc4a78c 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -2,39 +2,43 @@ ## Version Scheme -Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本號: +Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflow_dispatch`: -| Label | 效果 | 範例 | +| Method | 效果 | 範例 | |---|---|---| -| (無) | patch bump | `0.6.0 → 0.6.1` | -| `tagpr:minor` | minor bump | `0.6.0 → 0.7.0` | -| `tagpr:major` | major bump | `0.6.0 → 1.0.0` | +| Auto patch (default) | patch bump + rc | `0.6.0 → 0.6.1-rc.1` | +| Auto minor | minor bump + rc | `0.6.0 → 0.7.0-rc.1` | +| Auto major | major bump + rc | `0.6.0 → 1.0.0-rc.1` | +| Manual | 自行指定 | `0.8.0-rc.1` or `0.8.0` | ## Release Flow (Tag-Driven) > **核心原則:測過什麼就發什麼 (what you tested is what you ship)** > stable release 不重新 build,直接 promote pre-release 驗證過的 image。 -##### Step 1 — 累積變更 +##### Step 1 — 建立 Release PR ``` ┌─────────────────────────────────────────────────────────────────┐ - │ 貢獻者 PR merge to main │ - │ → tagpr.yml 觸發 │ - │ → tagpr 累積 commits,自動開 Release PR │ - │ (更新 Cargo.toml + Chart.yaml version/appVersion + CHANGELOG) │ + │ Maintainer 到 Actions → Release PR → Run workflow │ + │ │ + │ 選項 A: 留空 version,選 bump type → 自動算 (e.g. 0.7.0-rc.1) │ + │ 選項 B: 手動填 version (e.g. 0.8.0-rc.1 or 0.8.0) │ + │ │ + │ → release-pr.yml 觸發 │ + │ → 更新 Cargo.toml + Chart.yaml version/appVersion │ + │ → 建立 Release PR (branch: release/v0.7.0-rc.1) │ └─────────────────────────────────────────────────────────────────┘ ``` -##### Step 2 — Pre-release Build & 測試 +##### Step 2 — Merge Release PR → 自動打 Tag → Build ``` ┌─────────────────────────────────────────────────────────────────┐ - │ 針對要測試的 commit 打 pre-release tag: │ - │ │ - │ git tag v0.7.0-rc.1 │ - │ git push origin v0.7.0-rc.1 │ + │ Maintainer review & merge Release PR │ │ │ + │ → tag-on-merge.yml 偵測 release/ branch merge │ + │ → 自動打 tag (e.g. v0.7.0-rc.1) │ │ → build.yml 觸發 (is_prerelease=true) │ │ → build-image: 4 variants × 2 platforms (amd64 + arm64) │ │ → merge-manifests: image tags = + 0.7.0-rc.1 │ @@ -49,16 +53,19 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 │ oci://ghcr.io/openabdev/charts/openab \ │ │ --version 0.7.0-rc.1 │ │ │ - │ 發現 bug?→ 修復 PR merge → 打 v0.7.0-rc.2 → 重新測試 │ + │ 發現 bug?→ 修復 PR merge → 再跑一次 Release PR workflow │ + │ → 手動指定 v0.7.0-rc.2 → merge → 重新測試 │ └─────────────────────────────────────────────────────────────────┘ ``` -##### Step 3 — 測試通過,Merge Release PR +##### Step 3 — Stable Release(Promote) ``` ┌─────────────────────────────────────────────────────────────────┐ - │ Maintainer merge Release PR │ - │ → tagpr 自動打 tag (e.g. v0.7.0) + 建立 GitHub Release │ + │ 測試通過後,再跑一次 Release PR workflow │ + │ → 手動指定 version: 0.7.0 (不帶 rc) │ + │ → merge Release PR │ + │ → tag-on-merge.yml 打 tag v0.7.0 │ │ │ │ → build.yml 觸發 (is_prerelease=false) │ │ → promote-stable: │ @@ -83,18 +90,20 @@ Versions follow SemVer (e.g. `0.7.0`)。tagpr 根據 PR label 自動決定版本 ## 快速指令參考 ```bash -# ── Pre-release(Step 2)────────────────────────────── -git tag v0.7.0-rc.1 -git push origin v0.7.0-rc.1 +# ── Pre-release ─────────────────────────────────────── +# 到 Actions → Release PR → Run workflow +# 留空 version,選 patch → 自動算 0.7.0-rc.1 +# 或手動填 version: 0.7.0-rc.1 +# → merge 產生的 Release PR → 自動打 tag → build # ── 第二輪 pre-release(rc.1 有 bug 時)───────────── -# 修 bug → PR merge to main → 打新 rc tag -git tag v0.7.0-rc.2 -git push origin v0.7.0-rc.2 +# 修 bug → PR merge to main +# 再跑 Release PR workflow,手動填 version: 0.7.0-rc.2 +# → merge → 自動打 tag → build -# ── Stable release(Step 3)─────────────────────────── -# 直接在 GitHub merge tagpr 的 Release PR 即可 -# tagpr 自動打 v0.7.0 tag → promote 最新的 rc image +# ── Stable release ──────────────────────────────────── +# 跑 Release PR workflow,手動填 version: 0.7.0 +# → merge → 自動打 tag → promote rc image (不 rebuild) # ── 手動重跑(build 失敗時)────────────────────────── gh workflow run build.yml -f tag=v0.7.0-rc.1 @@ -103,30 +112,29 @@ gh workflow run build.yml -f tag=v0.7.0 ## GitHub Releases -每次 release 會產生兩個 GitHub Release: - | Release | Tag 格式 | 內容 | |---|---|---| -| tagpr | `v0.7.0` | CHANGELOG(自動從 commits 產生) | | chart-releaser | `openab-0.7.0` | Version Info + Installation instructions | ## Workflow 對應表 | Workflow | 觸發條件 | 用途 | |---|---|---| -| `tagpr.yml` | push to main | 自動開 Release PR、打 tag、建立 GitHub Release | -| `build.yml` | tag push `v*` | pre-release: 完整 build / stable: promote pre-release image | -| `release.yml` | Chart.yaml 變更 push to main | chart-releaser 更新 GitHub Pages index + install instructions | +| `ci.yml` | pull_request (src/Cargo/Dockerfile) | cargo check + clippy + test | +| `release-pr.yml` | workflow_dispatch | 建立 Release PR(更新版本檔案) | +| `tag-on-merge.yml` | release/ PR merge to main | 自動打 tag | +| `build.yml` | tag push `v*` | pre-release: 完整 build / stable: promote | +| `release.yml` | Chart.yaml 變更 push to main | chart-releaser 更新 GitHub Pages index | -## Version 同步 (tagpr) +## Version 同步 -tagpr 在 Release PR 中自動更新以下檔案的版本: +release-pr.yml 在 Release PR 中自動更新以下檔案的版本: -| 檔案 | 欄位 | 更新方式 | -|---|---|---| -| `Cargo.toml` | `version` | tagpr 內建 (`versionFile`) | -| `charts/openab/Chart.yaml` | `version` | tagpr 內建 (`versionFile`) | -| `charts/openab/Chart.yaml` | `appVersion` | `postVersionCommand` | +| 檔案 | 欄位 | +|---|---| +| `Cargo.toml` | `version` | +| `charts/openab/Chart.yaml` | `version` | +| `charts/openab/Chart.yaml` | `appVersion` | 三者統一為同一個 semver(e.g. `0.7.0`)。 @@ -170,25 +178,19 @@ helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0 | 時機 | 做什麼 | |---|---| -| tagpr 開 Release PR 後 | Review 版本號 / CHANGELOG | -| 需要調整版本升級幅度 | 在 Release PR 加 `tagpr:minor` 或 `tagpr:major` label | -| Pre-release | `git tag v0.7.0-rc.1 && git push origin v0.7.0-rc.1` | -| 測試通過 | Merge Release PR(tagpr 打 stable tag → 自動 promote) | +| 準備 release | Actions → Release PR → Run workflow | +| 需要 rc 測試 | 指定 version 如 `0.7.0-rc.1` | +| 測試通過 | 指定 stable version 如 `0.7.0` → promote | | build 失敗或需重跑 | `gh workflow run build.yml -f tag=` | ## GitHub App 權限 -tagpr 使用 GitHub App token 來推送 tag 和建立 Release PR。App 需要以下 Repository permissions: +release-pr.yml 和 tag-on-merge.yml 使用 GitHub App token 來建立 PR 和推送 tag。App 需要以下 Repository permissions: | Permission | Access | |---|---| -| Actions | Read and write | -| Commit statuses | Read-only | | Contents | Read and write | -| Issues | Read and write | -| Merge queues | Read and write | | Metadata | Read-only (mandatory) | -| Packages | Read and write | | Pull requests | Read and write | 對應的 secrets:`APP_ID`(Client ID)、`APP_PRIVATE_KEY`。 From fef071a4109dff1c43bab0b32d63ac0126390b96 Mon Sep 17 00:00:00 2001 From: thepagent Date: Sat, 11 Apr 2026 14:25:49 +0800 Subject: [PATCH 18/20] ci: address review feedback - release-chart: add resolve-tag.result == 'success' to if-condition - release-pr: add rust-toolchain + cargo generate-lockfile for Cargo.lock sync - tag-on-merge: validate version format before pushing tag - build: add default placeholder for workflow_dispatch tag input --- .github/workflows/build.yml | 2 ++ .github/workflows/release-pr.yml | 3 +++ .github/workflows/tag-on-merge.yml | 4 ++++ charts/openab/Chart.yaml | 4 ++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49a12314..74b5098e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,7 @@ on: description: 'Version tag (e.g. v0.7.0-rc.1 or v0.7.0)' required: true type: string + default: 'v' dry_run: description: 'Dry run (build only, no push)' required: false @@ -234,6 +235,7 @@ jobs: needs: [resolve-tag, merge-manifests, promote-stable] if: >- ${{ always() && inputs.dry_run != true && + needs.resolve-tag.result == 'success' && (needs.merge-manifests.result == 'success' || needs.promote-stable.result == 'success') }} runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index 098297fb..47517e09 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -55,12 +55,15 @@ jobs: echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "::notice::Release version: ${VERSION}" + - uses: dtolnay/rust-toolchain@stable + - name: Update version files run: | VERSION="${{ steps.version.outputs.version }}" sed -i "s/^version = .*/version = \"${VERSION}\"/" Cargo.toml sed -i "s/^version: .*/version: ${VERSION}/" charts/openab/Chart.yaml sed -i "s/^appVersion: .*/appVersion: \"${VERSION}\"/" charts/openab/Chart.yaml + cargo generate-lockfile - name: Create release PR env: diff --git a/.github/workflows/tag-on-merge.yml b/.github/workflows/tag-on-merge.yml index 65c492b9..3aa1ad02 100644 --- a/.github/workflows/tag-on-merge.yml +++ b/.github/workflows/tag-on-merge.yml @@ -27,6 +27,10 @@ jobs: run: | # release/v0.8.0-rc.1 → v0.8.0-rc.1 VERSION="${GITHUB_HEAD_REF#release/}" + if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then + echo "::error::Invalid version format '${VERSION}'. Expected v{major}.{minor}.{patch}[-prerelease]" + exit 1 + fi git config user.name "openab-app[bot]" git config user.email "274185012+openab-app[bot]@users.noreply.github.com" git tag "$VERSION" diff --git a/charts/openab/Chart.yaml b/charts/openab/Chart.yaml index 4452d5c4..bf2f1b38 100644 --- a/charts/openab/Chart.yaml +++ b/charts/openab/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: openab description: Discord ↔ ACP coding CLI bridge (Kiro CLI, Claude Code, Codex, Gemini) type: application -version: 0.6.0 -appVersion: "0.6.0" +version: 0.6.3 +appVersion: "0.6.3" From f7c98da2cf7886b7ef58c4b3b6ebbc0b16eaa736 Mon Sep 17 00:00:00 2001 From: thepagent Date: Sat, 11 Apr 2026 14:50:21 +0800 Subject: [PATCH 19/20] fix: replace map_or with is_some_and to satisfy clippy --- src/discord.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/discord.rs b/src/discord.rs index b8d7e53e..77539173 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -54,7 +54,7 @@ impl EventHandler for Handler { Ok(serenity::model::channel::Channel::Guild(gc)) => { let result = gc .parent_id - .map_or(false, |pid| self.allowed_channels.contains(&pid.get())); + .is_some_and(|pid| self.allowed_channels.contains(&pid.get())); tracing::debug!(channel_id = %msg.channel_id, parent_id = ?gc.parent_id, result, "thread check"); result } From 530c520fa35b35d1dac5e954209c6613df8b4ddc Mon Sep 17 00:00:00 2001 From: thepagent Date: Sat, 11 Apr 2026 15:01:07 +0800 Subject: [PATCH 20/20] chore: use beta instead of rc for pre-release naming --- .github/workflows/build.yml | 6 ++-- .github/workflows/release-pr.yml | 4 +-- .github/workflows/tag-on-merge.yml | 2 +- RELEASING.md | 44 +++++++++++++++--------------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74b5098e..51301bfd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,7 +7,7 @@ on: workflow_dispatch: inputs: tag: - description: 'Version tag (e.g. v0.7.0-rc.1 or v0.7.0)' + description: 'Version tag (e.g. v0.7.0-beta.1 or v0.7.0)' required: true type: string default: 'v' @@ -46,7 +46,7 @@ jobs: CHART_VERSION="${TAG#v}" - # Pre-release if version contains '-' (e.g. 0.7.0-rc.1) + # Pre-release if version contains '-' (e.g. 0.7.0-beta.1) if [[ "$CHART_VERSION" == *-* ]]; then IS_PRERELEASE="true" else @@ -197,7 +197,7 @@ jobs: id: find-prerelease run: | CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" - # Find latest pre-release tag matching this version (e.g. v0.7.0-rc.1) + # Find latest pre-release tag matching this version (e.g. v0.7.0-beta.1) PRERELEASE_TAG=$(git tag -l "v${CHART_VERSION}-*" --sort=-v:refname | head -1) if [ -z "$PRERELEASE_TAG" ]; then echo "::error::No pre-release tag found for v${CHART_VERSION}-*. Run a pre-release build first." diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index 47517e09..b6c3658f 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: inputs: version: - description: "Version (leave empty for auto bump, or specify e.g. 0.8.0-rc.1)" + description: "Version (leave empty for auto bump, or specify e.g. 0.8.0-beta.1)" required: false type: string bump: @@ -50,7 +50,7 @@ jobs: minor) minor=$((minor + 1)); patch=0 ;; patch) patch=$((patch + 1)) ;; esac - VERSION="${major}.${minor}.${patch}-rc.1" + VERSION="${major}.${minor}.${patch}-beta.1" fi echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "::notice::Release version: ${VERSION}" diff --git a/.github/workflows/tag-on-merge.yml b/.github/workflows/tag-on-merge.yml index 3aa1ad02..e414d933 100644 --- a/.github/workflows/tag-on-merge.yml +++ b/.github/workflows/tag-on-merge.yml @@ -25,7 +25,7 @@ jobs: - name: Create and push tag run: | - # release/v0.8.0-rc.1 → v0.8.0-rc.1 + # release/v0.8.0-beta.1 → v0.8.0-beta.1 VERSION="${GITHUB_HEAD_REF#release/}" if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then echo "::error::Invalid version format '${VERSION}'. Expected v{major}.{minor}.{patch}[-prerelease]" diff --git a/RELEASING.md b/RELEASING.md index afc4a78c..8e2f35d6 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -6,10 +6,10 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo | Method | 效果 | 範例 | |---|---|---| -| Auto patch (default) | patch bump + rc | `0.6.0 → 0.6.1-rc.1` | -| Auto minor | minor bump + rc | `0.6.0 → 0.7.0-rc.1` | -| Auto major | major bump + rc | `0.6.0 → 1.0.0-rc.1` | -| Manual | 自行指定 | `0.8.0-rc.1` or `0.8.0` | +| Auto patch (default) | patch bump + beta | `0.6.0 → 0.6.1-beta.1` | +| Auto minor | minor bump + beta | `0.6.0 → 0.7.0-beta.1` | +| Auto major | major bump + beta | `0.6.0 → 1.0.0-beta.1` | +| Manual | 自行指定 | `0.8.0-beta.1` or `0.8.0` | ## Release Flow (Tag-Driven) @@ -22,12 +22,12 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo ┌─────────────────────────────────────────────────────────────────┐ │ Maintainer 到 Actions → Release PR → Run workflow │ │ │ - │ 選項 A: 留空 version,選 bump type → 自動算 (e.g. 0.7.0-rc.1) │ - │ 選項 B: 手動填 version (e.g. 0.8.0-rc.1 or 0.8.0) │ + │ 選項 A: 留空 version,選 bump type → 自動算 (e.g. 0.7.0-beta.1) │ + │ 選項 B: 手動填 version (e.g. 0.8.0-beta.1 or 0.8.0) │ │ │ │ → release-pr.yml 觸發 │ │ → 更新 Cargo.toml + Chart.yaml version/appVersion │ - │ → 建立 Release PR (branch: release/v0.7.0-rc.1) │ + │ → 建立 Release PR (branch: release/v0.7.0-beta.1) │ └─────────────────────────────────────────────────────────────────┘ ``` @@ -38,10 +38,10 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo │ Maintainer review & merge Release PR │ │ │ │ → tag-on-merge.yml 偵測 release/ branch merge │ - │ → 自動打 tag (e.g. v0.7.0-rc.1) │ + │ → 自動打 tag (e.g. v0.7.0-beta.1) │ │ → build.yml 觸發 (is_prerelease=true) │ │ → build-image: 4 variants × 2 platforms (amd64 + arm64) │ - │ → merge-manifests: image tags = + 0.7.0-rc.1 │ + │ → merge-manifests: image tags = + 0.7.0-beta.1 │ │ → release-chart: helm chart → OCI registry │ └─────────────────────────────────────────────────────────────────┘ │ @@ -51,10 +51,10 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo │ │ │ helm install openab \ │ │ oci://ghcr.io/openabdev/charts/openab \ │ - │ --version 0.7.0-rc.1 │ + │ --version 0.7.0-beta.1 │ │ │ │ 發現 bug?→ 修復 PR merge → 再跑一次 Release PR workflow │ - │ → 手動指定 v0.7.0-rc.2 → merge → 重新測試 │ + │ → 手動指定 v0.7.0-beta.2 → merge → 重新測試 │ └─────────────────────────────────────────────────────────────────┘ ``` @@ -69,9 +69,9 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo │ │ │ → build.yml 觸發 (is_prerelease=false) │ │ → promote-stable: │ - │ 1. 找到最新的 pre-release tag (v0.7.0-rc.2) │ + │ 1. 找到最新的 pre-release tag (v0.7.0-beta.2) │ │ 2. 驗證 pre-release image 存在 │ - │ 3. re-tag 0.7.0-rc.2 → 0.7.0 / 0.7 / latest │ + │ 3. re-tag 0.7.0-beta.2 → 0.7.0 / 0.7 / latest │ │ ⚠️ 不 rebuild,跟 pre-release 是同一個 artifact │ │ → release-chart: helm chart → OCI registry │ └─────────────────────────────────────────────────────────────────┘ @@ -92,21 +92,21 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo ```bash # ── Pre-release ─────────────────────────────────────── # 到 Actions → Release PR → Run workflow -# 留空 version,選 patch → 自動算 0.7.0-rc.1 -# 或手動填 version: 0.7.0-rc.1 +# 留空 version,選 patch → 自動算 0.7.0-beta.1 +# 或手動填 version: 0.7.0-beta.1 # → merge 產生的 Release PR → 自動打 tag → build -# ── 第二輪 pre-release(rc.1 有 bug 時)───────────── +# ── 第二輪 pre-release(beta.1 有 bug 時)───────────── # 修 bug → PR merge to main -# 再跑 Release PR workflow,手動填 version: 0.7.0-rc.2 +# 再跑 Release PR workflow,手動填 version: 0.7.0-beta.2 # → merge → 自動打 tag → build # ── Stable release ──────────────────────────────────── # 跑 Release PR workflow,手動填 version: 0.7.0 -# → merge → 自動打 tag → promote rc image (不 rebuild) +# → merge → 自動打 tag → promote beta image (不 rebuild) # ── 手動重跑(build 失敗時)────────────────────────── -gh workflow run build.yml -f tag=v0.7.0-rc.1 +gh workflow run build.yml -f tag=v0.7.0-beta.1 gh workflow run build.yml -f tag=v0.7.0 ``` @@ -151,10 +151,10 @@ ghcr.io/openabdev/openab-gemini # gemini Image tags 依 release 類型不同: -| Tag | Stable (`v0.7.0`) | Pre-release (`v0.7.0-rc.1`) | +| Tag | Stable (`v0.7.0`) | Pre-release (`v0.7.0-beta.1`) | |---|---|---| | `` | v (from pre-release) | v | -| `0.7.0` / `0.7.0-rc.1` | v | v | +| `0.7.0` / `0.7.0-beta.1` | v | v | | `0.7` | v | x | | `latest` | v | x | @@ -179,7 +179,7 @@ helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0 | 時機 | 做什麼 | |---|---| | 準備 release | Actions → Release PR → Run workflow | -| 需要 rc 測試 | 指定 version 如 `0.7.0-rc.1` | +| 需要 beta 測試 | 指定 version 如 `0.7.0-beta.1` | | 測試通過 | 指定 stable version 如 `0.7.0` → promote | | build 失敗或需重跑 | `gh workflow run build.yml -f tag=` |