release: v0.8.3-beta.9 (#812) #113
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build & Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Version tag (e.g. v0.7.0-beta.1 or v0.7.0)' | |
| required: true | |
| type: string | |
| default: 'v' | |
| dry_run: | |
| description: 'Dry run (build only, no push)' | |
| required: false | |
| type: boolean | |
| default: false | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| resolve-tag: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag: ${{ steps.resolve.outputs.tag }} | |
| chart_version: ${{ steps.resolve.outputs.chart_version }} | |
| is_prerelease: ${{ steps.resolve.outputs.is_prerelease }} | |
| 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}" | |
| # Pre-release if version contains '-' (e.g. 0.7.0-beta.1) | |
| if [[ "$CHART_VERSION" == *-* ]]; then | |
| IS_PRERELEASE="true" | |
| else | |
| IS_PRERELEASE="false" | |
| fi | |
| echo "tag=${TAG}" >> "$GITHUB_OUTPUT" | |
| echo "chart_version=${CHART_VERSION}" >> "$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: | |
| - { suffix: "", dockerfile: "Dockerfile", artifact: "default" } | |
| - { suffix: "-codex", dockerfile: "Dockerfile.codex", artifact: "codex" } | |
| - { suffix: "-claude", dockerfile: "Dockerfile.claude", artifact: "claude" } | |
| - { suffix: "-gemini", dockerfile: "Dockerfile.gemini", artifact: "gemini" } | |
| - { suffix: "-copilot", dockerfile: "Dockerfile.copilot", artifact: "copilot" } | |
| - { suffix: "-opencode", dockerfile: "Dockerfile.opencode", artifact: "opencode" } | |
| - { suffix: "-cursor", dockerfile: "Dockerfile.cursor", artifact: "cursor" } | |
| platform: | |
| - { os: linux/amd64, runner: ubuntu-latest } | |
| - { os: linux/arm64, runner: ubuntu-24.04-arm } | |
| runs-on: ${{ matrix.platform.runner }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: docker/setup-buildx-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@v6 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: ${{ matrix.variant.dockerfile }} | |
| platforms: ${{ matrix.platform.os }} | |
| outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}${{ matrix.variant.suffix }},push-by-digest=true,name-canonical=true,push=${{ inputs.dry_run != true }} | |
| cache-from: type=gha,scope=${{ matrix.variant.suffix }}-${{ matrix.platform.os }} | |
| cache-to: type=gha,scope=${{ matrix.variant.suffix }}-${{ matrix.platform.os }},mode=max | |
| - name: Export digest | |
| if: inputs.dry_run != true | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| if: inputs.dry_run != true | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: digests-${{ matrix.variant.artifact }}-${{ matrix.platform.runner }} | |
| path: /tmp/digests/* | |
| retention-days: 1 | |
| merge-manifests: | |
| needs: [resolve-tag, build-image] | |
| if: ${{ inputs.dry_run != true && needs.resolve-tag.outputs.is_prerelease == 'true' }} | |
| strategy: | |
| matrix: | |
| variant: | |
| - { suffix: "", artifact: "default" } | |
| - { suffix: "-codex", artifact: "codex" } | |
| - { suffix: "-claude", artifact: "claude" } | |
| - { suffix: "-gemini", artifact: "gemini" } | |
| - { suffix: "-copilot", artifact: "copilot" } | |
| - { suffix: "-opencode", artifact: "opencode" } | |
| - { suffix: "-cursor", artifact: "cursor" } | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Download digests | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests-${{ matrix.variant.artifact }}-* | |
| merge-multiple: true | |
| - uses: docker/setup-buildx-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@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 }} | |
| - name: Create manifest list | |
| working-directory: /tmp/digests | |
| run: | | |
| 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" } | |
| - { suffix: "-copilot" } | |
| - { suffix: "-opencode" } | |
| - { suffix: "-cursor" } | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - uses: docker/setup-buildx-action@v3 | |
| - uses: docker/login-action@v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| 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-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." | |
| 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 }}" | |
| 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 }}" | |
| PRERELEASE_VERSION="${{ steps.find-prerelease.outputs.prerelease_version }}" | |
| CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" | |
| MAJOR_MINOR="${CHART_VERSION%.*}" | |
| 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}:${PRERELEASE_VERSION}" | |
| # ── Chart release (runs after either path) ─────────────────── | |
| release-chart: | |
| 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: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Helm | |
| uses: azure/setup-helm@v4 | |
| - uses: docker/login-action@v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push chart to OCI | |
| run: | | |
| CHART_VERSION="${{ needs.resolve-tag.outputs.chart_version }}" | |
| helm package charts/openab | |
| helm push openab-${CHART_VERSION}.tgz oci://ghcr.io/${{ github.repository_owner }}/charts |