Skip to content

Latest commit

 

History

History
228 lines (170 loc) · 7.97 KB

File metadata and controls

228 lines (170 loc) · 7.97 KB

Release Process Guide

This guide outlines the complete release process for the repos project, from development and pull requests to creating a new versioned release. Our strategy is built on semantic versioning, conventional commits, and a release branch workflow to ensure releases are intentional and well-documented.

Overview

  • Main Branch (main): The main branch is the primary development branch. All new features and fixes are merged here. No releases are created directly from main.
  • Release Branches (release/**): Releases are created by pushing a branch with the release/ prefix (e.g., release/2025.09). This triggers the release workflow.
  • Semantic Versioning: The release workflow automatically determines the new version number based on the commit messages since the last release.
  • Squash Merges: We use squash merges for pull requests to maintain a clean, meaningful commit history on the main branch, which is essential for accurate semantic versioning.

The Release Workflow: Step-by-Step

The process is designed to be simple and automated, with clear quality gates.

Step 1: Development & Pull Requests

All development happens on feature branches. When a feature or fix is ready, open a Pull Request (PR) against the main branch.

PR Best Practices: Squash Merging

When merging a PR, always use the "Squash and merge" option.

Why?

Squash merging combines all of a PR's commits into a single commit on the main branch. This is critical for our release process because:

  1. Clean History: It keeps the main branch history clean and readable.
  2. Accurate Versioning: It allows us to craft a single, precise conventional commit message that the semantic versioning tool can parse to determine the correct version bump. Merge commits often hide the original feat: or fix: prefixes.

How to Squash Merge:

  1. From the GitHub UI:

    • In the PR, select "Squash and merge" from the merge dropdown.
    • Crucially, edit the commit title to follow the Conventional Commits format (e.g., feat: add new command).
    • Confirm the merge.
  2. From the GitHub CLI:

    # Example for PR #42
    gh pr merge 42 \
      --squash \
      --subject "feat: add a new feature" \
      --body "Detailed description of the feature."

Step 2: Creating a Release

When you are ready to release the features and fixes that have been merged into main, you create a release branch.

  1. Ensure your main branch is up-to-date:

    git checkout main
    git pull origin main
  2. Create and push a release branch: The branch name can be anything, but it must start with release/. A good practice is to name it after the expected version or date.

    # Create a release branch (e.g., release/2025.10)
    git checkout -b release/prepare-release
    
    # Push the branch to GitHub
    git push -u origin release/prepare-release

Step 3: Automated Release Workflow

Pushing the release/ branch automatically triggers the release.yml GitHub Actions workflow, which performs the following steps:

  1. Compute Version: Analyzes commit messages on main since the last tag and determines the new semantic version (e.g., v1.3.0).
  2. Run Quality Gates: Runs the full test suite, linter (clippy), and format checks. The release fails if any of these checks do not pass.
  3. Update Cargo.toml: Bumps the version in Cargo.toml and pushes the change to the release branch.
  4. Create GitHub Release:
    • Creates a new Git tag (e.g., v1.3.0).
    • Generates a new GitHub Release with a "What's Changed" section populated from the conventional commit messages.
  5. Build Release Assets: Compiles the application and creates binaries for Linux and macOS (x86_64, aarch64, and universal). These are attached to the GitHub Release.
  6. Sync main Branch: After the release is successfully created, the version bump in Cargo.toml is automatically merged back into the main branch to keep it in sync.

Conventional Commits

To ensure the automation works correctly, all commits merged into main must follow the Conventional Commits specification.

Commit Message Structure

<type>[optional scope]: <description>
  • <type>: Must be one of the following.
  • <description>: A short, imperative-tense description of the change.

Commit Types and Version Bumps

  • feat: A new feature. Triggers a minor version bump (e.g., 1.2.31.3.0).

    • feat: add a new 'run' command
  • fix: A bug fix. Triggers a patch version bump (e.g., 1.2.31.2.4).

    • fix: correct an issue with path resolution
  • BREAKING CHANGE: A commit that introduces a breaking API change. This can be added to the footer of any commit type and triggers a major version bump (e.g., 1.2.32.0.0).

    feat: change CLI argument structure
    
    BREAKING CHANGE: The '--repo' argument has been renamed to '--repository'.
    
  • Other Types: These trigger a patch version bump and are great for organizing your work.

    • docs:: Documentation changes.
    • style:: Code style changes (formatting, etc.).
    • refactor:: Code changes that neither fix a bug nor add a feature.
    • perf:: A code change that improves performance.
    • test:: Adding or correcting tests.
    • ci:: Changes to CI configuration files and scripts.
    • chore:: Other changes that don't modify src or test files.

A guide for curated (cherry-pick) release

This strategy allows for creating a release that includes only specific, hand-picked features or fixes. It is the recommended approach for creating patch releases or when you need to control the exact contents of a new version, rather than releasing everything that has been merged to main.

How it works

Instead of creating a release branch from main, you will create it from the most recent release tag. This gives you a clean starting point. You then cherry-pick the specific commits you want to include in the release onto this new branch.

The automated release workflow will then calculate the new version and changelog based only on the commits you cherry-picked.

Step 1: Create a release branch from the latest tag

First, ensure your local repository is up-to-date and find the latest release tag.

# Fetch all the latest tags and branches from the remote
git fetch --all --tags

# Find the latest tag (e.g., v0.0.8)
LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
echo "Latest tag is: $LATEST_TAG"

# Create a new release branch from that tag.
# Name it something descriptive, like 'release/v0.0.9' or 'release/patch-for-x'
git checkout -b release/v0.0.9 $LATEST_TAG

You are now on a new branch that is an exact copy of your last release.

Step 2: Cherry-pick your commits

Identify the commits you want to include in the release. You can find the commit SHAs from the main branch's log or from a pull request.

# Example: Cherry-pick two specific commits
git cherry-pick <commit-sha-for-feature-A>
git cherry-pick <commit-sha-for-fix-B>

Tip for pull requests: If a PR was squash-merged, it will be a single commit *on main. You can simply cherry-pick that one merge commit.

If you encounter any merge conflicts during cherry-picking, resolve them, and then continue:

# After resolving conflicts...
git add .
git cherry-pick --continue

Step 3: Push the branch to trigger the release

Once you have cherry-picked all the desired commits, push the release branch to GitHub. This will trigger the automated release workflow.

git push -u origin release/v0.0.9

The workflow will now:

  1. Analyze only the cherry-picked commits.
  2. Calculate the correct semantic version (e.g., v0.0.9 if you picked a fix, or v0.1.0 if you picked a feat).
  3. Run tests, build the binaries, and publish the new GitHub Release with a changelog containing only the changes you selected.