|
| 1 | +# Release Process |
| 2 | + |
| 3 | +This document describes the automated release process for Spec Kit. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The release process is split into two workflows to ensure version consistency: |
| 8 | + |
| 9 | +1. **Release Trigger Workflow** (`release-trigger.yml`) - Manages versioning and triggers release |
| 10 | +2. **Release Workflow** (`release.yml`) - Builds and publishes artifacts |
| 11 | + |
| 12 | +This separation ensures that git tags always point to commits with the correct version in `pyproject.toml`. |
| 13 | + |
| 14 | +## Before Creating a Release |
| 15 | + |
| 16 | +**Important**: Write clear, descriptive commit messages! |
| 17 | + |
| 18 | +### How CHANGELOG.md Works |
| 19 | + |
| 20 | +The CHANGELOG is **automatically generated** from your git commit messages: |
| 21 | + |
| 22 | +1. **During Development**: Write clear, descriptive commit messages: |
| 23 | + ```bash |
| 24 | + git commit -m "feat: Add new authentication feature" |
| 25 | + git commit -m "fix: Resolve timeout issue in API client (#123)" |
| 26 | + git commit -m "docs: Update installation instructions" |
| 27 | + ``` |
| 28 | + |
| 29 | +2. **When Releasing**: The release trigger workflow automatically: |
| 30 | + - Finds all commits since the last release tag |
| 31 | + - Formats them as changelog entries |
| 32 | + - Inserts them into CHANGELOG.md |
| 33 | + - Commits the updated changelog before creating the new tag |
| 34 | + |
| 35 | +### Commit Message Best Practices |
| 36 | + |
| 37 | +Good commit messages make good changelogs: |
| 38 | +- **Be descriptive**: "Add user authentication" not "Update files" |
| 39 | +- **Reference issues/PRs**: Include `(#123)` for automated linking |
| 40 | +- **Use conventional commits** (optional): `feat:`, `fix:`, `docs:`, `chore:` |
| 41 | +- **Keep it concise**: One line is ideal, details go in commit body |
| 42 | + |
| 43 | +**Example commits that become good changelog entries:** |
| 44 | +``` |
| 45 | +fix: prepend YAML frontmatter to Cursor .mdc files (#1699) |
| 46 | +feat: add generic agent support with customizable command directories (#1639) |
| 47 | +docs: document dual-catalog system for extensions (#1689) |
| 48 | +``` |
| 49 | + |
| 50 | +## Creating a Release |
| 51 | + |
| 52 | +### Option 1: Auto-Increment (Recommended for patches) |
| 53 | + |
| 54 | +1. Go to **Actions** → **Release Trigger** |
| 55 | +2. Click **Run workflow** |
| 56 | +3. Leave the version field **empty** |
| 57 | +4. Click **Run workflow** |
| 58 | + |
| 59 | +The workflow will: |
| 60 | +- Auto-increment the patch version (e.g., `0.1.10` → `0.1.11`) |
| 61 | +- Update `pyproject.toml` |
| 62 | +- Update `CHANGELOG.md` by adding a new section for the release based on commits since the last tag |
| 63 | +- Commit changes to a `chore/release-vX.Y.Z` branch |
| 64 | +- Create and push the git tag from that branch |
| 65 | +- Open a PR to merge the version bump into `main` |
| 66 | +- Trigger the release workflow automatically via the tag push |
| 67 | + |
| 68 | +### Option 2: Manual Version (For major/minor bumps) |
| 69 | + |
| 70 | +1. Go to **Actions** → **Release Trigger** |
| 71 | +2. Click **Run workflow** |
| 72 | +3. Enter the desired version (e.g., `0.2.0` or `v0.2.0`) |
| 73 | +4. Click **Run workflow** |
| 74 | + |
| 75 | +The workflow will: |
| 76 | +- Use your specified version |
| 77 | +- Update `pyproject.toml` |
| 78 | +- Update `CHANGELOG.md` by adding a new section for the release based on commits since the last tag |
| 79 | +- Commit changes to a `chore/release-vX.Y.Z` branch |
| 80 | +- Create and push the git tag from that branch |
| 81 | +- Open a PR to merge the version bump into `main` |
| 82 | +- Trigger the release workflow automatically via the tag push |
| 83 | + |
| 84 | +## What Happens Next |
| 85 | + |
| 86 | +Once the release trigger workflow completes: |
| 87 | + |
| 88 | +1. A `chore/release-vX.Y.Z` branch is pushed with the version bump commit |
| 89 | +2. The git tag is pushed, pointing to that commit |
| 90 | +3. The **Release Workflow** is automatically triggered by the tag push |
| 91 | +4. Release artifacts are built for all supported agents |
| 92 | +5. A GitHub Release is created with all assets |
| 93 | +6. A PR is opened to merge the version bump branch into `main` |
| 94 | + |
| 95 | +> **Note**: Merge the auto-opened PR after the release is published to keep `main` in sync. |
| 96 | +
|
| 97 | +## Workflow Details |
| 98 | + |
| 99 | +### Release Trigger Workflow |
| 100 | + |
| 101 | +**File**: `.github/workflows/release-trigger.yml` |
| 102 | + |
| 103 | +**Trigger**: Manual (`workflow_dispatch`) |
| 104 | + |
| 105 | +**Permissions Required**: `contents: write` |
| 106 | + |
| 107 | +**Steps**: |
| 108 | +1. Checkout repository |
| 109 | +2. Determine version (manual or auto-increment) |
| 110 | +3. Check if tag already exists (prevents duplicates) |
| 111 | +4. Create `chore/release-vX.Y.Z` branch |
| 112 | +5. Update `pyproject.toml` |
| 113 | +6. Update `CHANGELOG.md` from git commits |
| 114 | +7. Commit changes |
| 115 | +8. Push branch and tag |
| 116 | +9. Open PR to merge version bump into `main` |
| 117 | + |
| 118 | +### Release Workflow |
| 119 | + |
| 120 | +**File**: `.github/workflows/release.yml` |
| 121 | + |
| 122 | +**Trigger**: Tag push (`v*`) |
| 123 | + |
| 124 | +**Permissions Required**: `contents: write` |
| 125 | + |
| 126 | +**Steps**: |
| 127 | +1. Checkout repository at tag |
| 128 | +2. Extract version from tag name |
| 129 | +3. Check if release already exists |
| 130 | +4. Build release package variants (all agents × shell/powershell) |
| 131 | +5. Generate release notes from commits |
| 132 | +6. Create GitHub Release with all assets |
| 133 | + |
| 134 | +## Version Constraints |
| 135 | + |
| 136 | +- Tags must follow format: `v{MAJOR}.{MINOR}.{PATCH}` |
| 137 | +- Example valid versions: `v0.1.11`, `v0.2.0`, `v1.0.0` |
| 138 | +- Auto-increment only bumps patch version |
| 139 | +- Cannot create duplicate tags (workflow will fail) |
| 140 | + |
| 141 | +## Benefits of This Approach |
| 142 | + |
| 143 | +✅ **Version Consistency**: Git tags point to commits with matching `pyproject.toml` version |
| 144 | + |
| 145 | +✅ **Single Source of Truth**: Version set once, used everywhere |
| 146 | + |
| 147 | +✅ **Prevents Drift**: No more manual version synchronization needed |
| 148 | + |
| 149 | +✅ **Clean Separation**: Versioning logic separate from artifact building |
| 150 | + |
| 151 | +✅ **Flexibility**: Supports both auto-increment and manual versioning |
| 152 | + |
| 153 | +## Troubleshooting |
| 154 | + |
| 155 | +### No Commits Since Last Release |
| 156 | + |
| 157 | +If you run the release trigger workflow when there are no new commits since the last tag: |
| 158 | +- The workflow will still succeed |
| 159 | +- The CHANGELOG will show "- Initial release" if it's the first release |
| 160 | +- Or it will be empty if there are no commits |
| 161 | +- Consider adding meaningful commits before releasing |
| 162 | + |
| 163 | +**Best Practice**: Use descriptive commit messages - they become your changelog! |
| 164 | + |
| 165 | +### Tag Already Exists |
| 166 | + |
| 167 | +If you see "Error: Tag vX.Y.Z already exists!", you need to: |
| 168 | +- Choose a different version number, or |
| 169 | +- Delete the existing tag if it was created in error |
| 170 | + |
| 171 | +### Release Workflow Didn't Trigger |
| 172 | + |
| 173 | +Check that: |
| 174 | +- The release trigger workflow completed successfully |
| 175 | +- The tag was pushed (check repository tags) |
| 176 | +- The release workflow is enabled in Actions settings |
| 177 | + |
| 178 | +### Version Mismatch |
| 179 | + |
| 180 | +If `pyproject.toml` doesn't match the latest tag: |
| 181 | +- Run the release trigger workflow to sync versions |
| 182 | +- Or manually update `pyproject.toml` and push changes before running the release trigger |
| 183 | + |
| 184 | +## Legacy Behavior (Pre-v0.1.10) |
| 185 | + |
| 186 | +Before this change, the release workflow: |
| 187 | +- Created tags automatically on main branch pushes |
| 188 | +- Updated `pyproject.toml` AFTER creating the tag |
| 189 | +- Resulted in tags pointing to commits with outdated versions |
| 190 | + |
| 191 | +This has been fixed in v0.1.10+. |
0 commit comments