Skip to content

Merge pull request #91 from camunda/feat/embed-spec-hash #95

Merge pull request #91 from camunda/feat/embed-spec-hash

Merge pull request #91 from camunda/feat/embed-spec-hash #95

Workflow file for this run

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