Skip to content

release pipeline

Kadyapam edited this page May 30, 2026 · 1 revision

Release pipeline

How a merge to main reaches crates.io, the GitHub Release page, and the container registry.

Two-stage flow

PR merged to main
        │
        ▼
┌────────────────────────────┐
│ Semantic Release ⚙️         │  .github/workflows/semantic-release.yml
│  - reads commit messages   │
│  - bumps Cargo.toml version│
│  - generates CHANGELOG.md  │
│  - commits + pushes        │
│  - creates GitHub Release  │
│  - tags v<VERSION>         │
│  - triggers release-worker │  ← R-1.2 fix: explicit gh workflow run
└────────────────────────────┘
        │
        ▼
┌────────────────────────────┐
│ release-worker             │  .github/workflows/release.yml
│  - cargo publish to crates │
│  - build release tarballs  │
│  - update Cloud Build      │
└────────────────────────────┘

The GitHub Actions safeguard gotcha

release-worker is configured to run on push: tags: ['v*']. Without explicit intervention, a v1.1.0 tag created by semantic-release on the bot's GITHUB_TOKEN does not trigger release-worker — GitHub Actions prevents GITHUB_TOKEN-created refs from firing workflows to avoid recursion.

Symptom: a release-worthy PR merges, the tag appears in the repo, but the crate never reaches crates.io. Discovered during R-1.2 PR-2c when noetl-worker 1.1.0 tagged cleanly but stayed at 1.0.0 on crates.io for hours.

The fix ([noetl/worker#4](https://github.com/noetl/worker/pull/4))

Add an explicit dispatch step to semantic-release.yml:

      - name: Release
        id: semantic                        # ← gives the step an id
        uses: cycjimmy/semantic-release-action@v4
        # ... (rest unchanged)

      - name: Trigger release-worker workflow
        if: ${{ steps.semantic.outputs.new_release_published == 'true' }}
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail
          VERSION="$(grep -E '^version = ' Cargo.toml | head -1 | cut -d'"' -f2)"
          gh workflow run release.yml --ref main -f version="${VERSION}"

The gh workflow run call does fire downstream workflows because it's an explicit workflow_dispatch event, not a tag push.

Same pattern in noetl/cli

The cli adopted this fix during R-1.2 PR-1 (noetl/cli#32) after its own pipeline had been silently broken for 3 consecutive runs (cli stuck at 2.17.1 on crates.io while local Cargo.toml progressed through 2.18.0 … 2.24.0). See cli wiki — executor-crate-architecture, R-1.2 PR-1.

One-time manual unblock for stuck versions

If a release fell through the cracks before the fix landed, dispatch the workflow manually:

gh workflow run release.yml --repo noetl/worker --ref main -f version=1.1.0

Replace 1.1.0 with whichever version is stuck. The job's first step verifies the version matches Cargo.toml; if not, it exits cleanly.

Distribution channels

After release-worker succeeds, the new version is on:

  • crates.iocargo install noetl-worker --version X.Y.Z
  • GitHub Release — tarballs for linux x86_64, linux aarch64, darwin arm64
  • Cloud Build / GHCR — container image (separate trigger path)

Conventional commit prefixes that bump versions

The conventionalcommits preset in .releaserc.json:

Commit prefix Bump
feat: minor (0.1.0 → 0.2.0)
fix: patch (0.1.0 → 0.1.1)
feat!: or BREAKING CHANGE: footer major (0.1.0 → 1.0.0)
chore: / docs: / test: / ci: no bump

chore(release): version X.Y.Z commits are written by semantic-release itself and don't trigger further bumps.

Related