CI deploys every commit. But sometimes you need a formal release — versioned, tagged, with a changelog. This lesson teaches the release pipeline pattern used by professional software teams.

Semantic Versioning (SemVer)

2 . 4 . 1 MAJOR Breaking changes MINOR New features (backward-compat) PATCH Bug fixes only
Commit MessageVersion BumpExample
fix: correct null checkPATCH (1.0.0 → 1.0.1)Bug fix
feat: add search APIMINOR (1.0.1 → 1.1.0)New feature
feat!: change auth formatMAJOR (1.1.0 → 2.0.0)Breaking change

Release Pipeline Flow

Tag: v2.1.0 git push --tags CI (full) test + build Push image tag: 2.1.0 GitHub Release changelog + artifacts Deploy prod if not pre-release

🏋️ Release Workflow

name: Release

on:
  push:
    tags: ['v*']

permissions:
  contents: write
  id-token: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }  # Full history for changelog

      - name: Get version
        id: ver
        run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT

      - name: Build & push image with version tag
        run: |
          # ... docker build + push with tag ${{ steps.ver.outputs.version }}
          echo "Pushed image: api:${{ steps.ver.outputs.version }}"

      - name: Generate changelog
        id: changelog
        run: |
          PREV_TAG=$(git tag --sort=-version:refname | sed -n '2p')
          echo "## Changes since $PREV_TAG" > changelog.md
          git log --pretty="- %s (%h)" $PREV_TAG..HEAD >> changelog.md

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: v${{ steps.ver.outputs.version }}
          body_path: changelog.md
          generate_release_notes: true

Creating a release:

# Bump version in package.json, then:
git tag -a v2.1.0 -m "Release v2.1.0: Added search API"
git push origin v2.1.0
# → Release pipeline triggers automatically

🧠 Recall Check

  1. What trigger starts a release pipeline?
  2. What's the difference between a CI deploy (every commit) and a release?
  3. In SemVer, when do you bump MAJOR?
Reveal answers
  1. A tag push matching v* (e.g., git push origin v2.1.0).
  2. CI deploy ships every commit (usually to staging by SHA). A release is a formal versioned milestone — tagged, changelogged, announced, and typically what goes to production.
  3. When you make a breaking change — something that requires consumers to change their code to upgrade. Signaled by feat!: or BREAKING CHANGE: in commit messages.

Next lesson: The Capstone — Architecture Decisions.