Skip to content

Release Management

Semantic Versioning

The standard versioning scheme for software releases.

MAJOR.MINOR.PATCH

2.1.3
│ │ └── 3: Backwards-compatible bug fix
│ └──── 1: New backwards-compatible feature
└────── 2: Breaking change

Rules

Change Type Version Bump Example
Bug fix, no API change PATCH 1.4.2 → 1.4.3
New feature, no breaking change MINOR 1.4.3 → 1.5.0
Breaking API change MAJOR 1.5.0 → 2.0.0

Pre-Release Tags

1.5.0-alpha.1    # very early, not for production
1.5.0-beta.2     # feature complete, testing phase
1.5.0-rc.1       # release candidate — production-like testing
1.5.0            # stable release

Automated Versioning in CI

Conventional Commits + semantic-release

semantic-release reads commit messages and bumps versions automatically:

feat: add OAuth2 login       MINOR bump
fix: correct email validation  PATCH bump
feat!: redesign auth API     MAJOR bump (! = breaking)
# GitHub Actions — automated release
- name: Semantic Release
  uses: cycjimmy/semantic-release-action@v4
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Output: creates git tag, GitHub Release, generates CHANGELOG.md.

Git Tag-Based Release

on:
  push:
    tags:
      - 'v[0-9]+.[0-9]+.[0-9]+'

jobs:
  release:
    steps:
      - name: Extract version
        run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV

      - name: Build and push release image
        run: |
          docker build -t ghcr.io/org/api:${{ env.VERSION }} .
          docker push ghcr.io/org/api:${{ env.VERSION }}

Release Strategies

Release Trains

Fixed-schedule releases. Every Monday at 10:00, whatever is in main ships.

Benefits: - Predictable for stakeholders - Encourages small, frequent commits - Reduces big-bang release risk

Drawbacks: - Bug fix may wait for next train - Requires feature flags for unfinished work

On-Demand Releases

Release whenever a change is ready and all gates pass. This is Continuous Deployment when fully automated.

Merge to main → gates pass → automatic deploy

Benefits: - Fastest time-to-production - Smaller batches = easier to debug

Drawbacks: - Requires high confidence in automated testing - Requires fast rollback capability


CHANGELOG Generation

Changelog documents what changed in each release.

# Using git-cliff to generate CHANGELOG.md
- name: Generate CHANGELOG
  uses: orhun/git-cliff-action@v3
  with:
    config: cliff.toml
    args: --verbose
  env:
    OUTPUT: CHANGELOG.md

- name: Commit CHANGELOG
  run: |
    git config user.name "github-actions[bot]"
    git config user.email "github-actions[bot]@users.noreply.github.com"
    git add CHANGELOG.md
    git commit -m "chore: update CHANGELOG for ${{ github.ref_name }}"
    git push

GitHub Release

- name: Create GitHub Release
  uses: softprops/action-gh-release@v2
  with:
    tag_name: ${{ env.VERSION }}
    name: "Release ${{ env.VERSION }}"
    body_path: CHANGELOG.md
    files: |
      dist/*.whl
      dist/*.tar.gz
    draft: false
    prerelease: ${{ contains(env.VERSION, '-') }}