Merge pull request #91 from camunda/feat/embed-spec-hash #95
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: Release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - 'stable/**' | |
| workflow_dispatch: | |
| concurrency: | |
| group: orchestration-cluster-api-js-release-${{ github.ref_name }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write # required for pushing version bump commit, tags, CHANGELOG | |
| packages: write # required for npm publish via semantic-release | |
| pull-requests: write | |
| issues: write | |
| id-token: write # Required for OIDC | |
| jobs: | |
| generate: | |
| name: Generate & Test (Node ${{ matrix.node }} ${{ matrix.stack }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| node: [24.x] | |
| stack: [simple] | |
| include: | |
| - node: 24.x | |
| stack: full | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Export stable line config | |
| run: | | |
| echo "CAMUNDA_SDK_CURRENT_STABLE_MINOR=${{ vars['CAMUNDA_SDK_CURRENT_STABLE_MINOR'] }}" >> $GITHUB_ENV | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| cache: 'npm' | |
| cache-dependency-path: package.json | |
| - name: Install deps | |
| run: npm ci | |
| - name: Generate & Build | |
| run: npm run build | |
| - name: Unit Tests | |
| run: npm test | |
| - name: Start Integration Stack | |
| working-directory: docker | |
| run: | | |
| if [ "${{ matrix.stack }}" == "full" ]; then | |
| docker compose -f docker-compose-full.yaml up -d | |
| else | |
| docker compose -f docker-compose.yaml up -d | |
| fi | |
| - name: Wait for Services Healthy | |
| run: | | |
| set -e | |
| attempts=0 | |
| max_attempts=60 | |
| while [ $attempts -lt $max_attempts ]; do | |
| code=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:9600/actuator/health/status || true) | |
| [ "$code" = "200" ] && echo "Broker healthy" && break | |
| sleep 5 | |
| attempts=$((attempts+1)) | |
| done | |
| [ $attempts -ge $max_attempts ] && echo "Broker not healthy" && exit 1 || true | |
| - name: Integration Tests | |
| run: npm run test:integration | |
| - name: Snapshot Spec & Metadata | |
| run: | | |
| set -e | |
| SPEC_DIR=external-spec/upstream/zeebe/gateway-protocol/src/main/proto/v2 | |
| # Deterministic hash over the whole spec directory (multi-file refs). | |
| HASH=$(find "$SPEC_DIR" -type f -print0 | sort -z | xargs -0 sha256sum | sha256sum | cut -d ' ' -f1) | |
| SNAP=spec-snapshots/spec-${HASH}.tgz | |
| mkdir -p spec-snapshots | |
| if [ ! -f "$SNAP" ]; then | |
| tar -czf "$SNAP" -C "$SPEC_DIR" . | |
| echo "Created new spec snapshot: $SNAP" | |
| else | |
| echo "Spec snapshot already exists: $SNAP (no overwrite)" | |
| fi | |
| echo "spec snapshot: spec-snapshots/spec-${HASH}.tgz" | |
| - name: Detect generated drift | |
| id: detect | |
| run: | | |
| if git diff --quiet; then echo "changed=false" >> $GITHUB_OUTPUT; else echo "changed=true" >> $GITHUB_OUTPUT; fi | |
| - name: Smoke GitHub OIDC token exchange for npm publish (before committing drift) | |
| if: steps.detect.outputs.changed == 'true' && matrix.stack == 'simple' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| REG=$(npm -s config get registry||:); REG=${REG%/}; : "${REG:=https://registry.npmjs.org}" | |
| HOST=${REG#*://}; HOST=${HOST%%/*} | |
| ID=$(curl -fsS -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=npm:${HOST}" | jq -er .value) | |
| PKG=$(jq -r '.name|@uri' package.json) | |
| RESP=$(curl -fsS -H "Authorization: Bearer $ID" "$REG/-/npm/v1/oidc/token/exchange/package/$PKG" -d "") | |
| TOKEN=$(echo "$RESP" | jq -er '.token') | |
| echo "::add-mask::$TOKEN" | |
| [ -n "$TOKEN" ] | |
| - name: Commit generated artifacts (canonical) | |
| if: steps.detect.outputs.changed == 'true' && matrix.stack == 'simple' | |
| run: | | |
| git config user.name 'github-actions' | |
| git config user.email 'actions@github.com' | |
| # Exclude workflow files from auto-format drift commits | |
| git restore .github/workflows/release.yml || true | |
| git add -A | |
| git commit -m "fix(gen): regenerate artifacts" | |
| - name: Upload logs (always) | |
| if: always() | |
| working-directory: docker | |
| run: docker compose logs || true | |
| - name: Shutdown Integration Stack (always) | |
| if: always() | |
| working-directory: docker | |
| run: docker compose down -v || true | |
| outputs: | |
| changed: ${{ steps.detect.outputs.changed }} | |
| merge: | |
| name: Fast-forward ${{ github.ref_name }} (if drift) | |
| needs: generate | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Fast-forward ${{ github.ref_name }} | |
| if: needs.generate.outputs.changed == 'true' | |
| run: | | |
| set -e | |
| # Generation committed directly on the triggering branch by pushing from the action runner; no staging branch | |
| echo "Drift committed during generate; ${{ github.ref_name }} already updated." | |
| - name: No drift – skip fast-forward | |
| if: needs.generate.outputs.changed != 'true' | |
| run: echo "No generated drift detected; fast-forward skipped." | |
| publish: | |
| name: Version & Publish (${{ github.ref_name }}) | |
| needs: merge | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Fetch remote refs for semantic-release | |
| run: | | |
| set -euo pipefail | |
| # semantic-release validates that configured release branches exist on the remote. | |
| # actions/checkout may only fetch the triggering ref, so fetch all heads explicitly. | |
| git fetch origin '+refs/heads/*:refs/remotes/origin/*' --prune | |
| # semantic-release stores channel information in git notes. | |
| git fetch origin '+refs/notes/*:refs/notes/*' || true | |
| - name: Export stable line config | |
| run: | | |
| echo "CAMUNDA_SDK_CURRENT_STABLE_MINOR=${{ vars['CAMUNDA_SDK_CURRENT_STABLE_MINOR'] }}" >> $GITHUB_ENV | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24.x | |
| registry-url: 'https://registry.npmjs.org' | |
| cache: 'npm' | |
| cache-dependency-path: package-lock.json | |
| - name: Install deps | |
| run: npm ci --ignore-scripts | |
| - name: Determine next version (dry-run) | |
| id: next_version | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -e | |
| node scripts/next-version.mjs > next-version.out 2>&1 || { | |
| echo 'Semantic-release dry-run failed:' | |
| cat next-version.out | |
| exit 1 | |
| } | |
| echo "semantic-release summary:"; | |
| grep -E '^(release_branch|release_channel|next_version)=' next-version.out || true | |
| VER=$(grep -E '^next_version=' next-version.out | tail -n 1 | cut -d '=' -f2) | |
| if [ -z "$VER" ]; then | |
| echo "No release required" | |
| echo "publish_needed=false" >> $GITHUB_OUTPUT | |
| echo "version=" >> $GITHUB_OUTPUT | |
| else | |
| echo "Next version: $VER" | |
| echo "publish_needed=true" >> $GITHUB_OUTPUT | |
| echo "version=$VER" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Bump version & regenerate artifacts | |
| if: steps.next_version.outputs.publish_needed == 'true' | |
| run: | | |
| npm version ${{ steps.next_version.outputs.version }} --no-git-tag-version | |
| npm run build | |
| - name: Smoke tests (post-bump) | |
| if: steps.next_version.outputs.publish_needed == 'true' | |
| run: npm test -- --run | |
| - name: Prepare GitHub release assets | |
| if: steps.next_version.outputs.publish_needed == 'true' | |
| run: | | |
| set -euo pipefail | |
| mkdir -p release-assets | |
| VER="${{ steps.next_version.outputs.version }}" | |
| OUT="release-assets/orchestration-cluster-api-${VER}-sources.tgz" | |
| # Include the generated SDK sources and version markers as a single asset. | |
| tar -czf "$OUT" package.json src/runtime/version.ts src/gen dist | |
| echo "Prepared $OUT" | |
| - name: Commit version bump & regenerated artifacts | |
| if: steps.next_version.outputs.publish_needed == 'true' | |
| run: | | |
| git config user.name 'github-actions' | |
| git config user.email 'actions@github.com' | |
| git add -A | |
| git commit -m "chore(release): v${{ steps.next_version.outputs.version }}" | |
| git push origin "HEAD:${{ github.ref_name }}" | |
| - name: Publish (semantic-release) | |
| if: steps.next_version.outputs.publish_needed == 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| NPM_CONFIG_PROVENANCE: true | |
| run: NODE_AUTH_TOKEN="" npx semantic-release | |
| - name: Build Docs | |
| if: github.ref_name == 'main' | |
| run: npm run docs:api | |
| - name: Deploy Docs | |
| if: github.ref_name == 'main' | |
| uses: JamesIves/github-pages-deploy-action@v4 | |
| with: | |
| folder: docs | |
| branch: gh-pages | |
| - name: Upload release analysis logs (always) | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-analysis | |
| path: | | |
| next-version.out |