# Release Process
This document describes the release process for **ofsht**.
## Overview
Releases are fully automated using [release-plz](https://release-plz.ieni.dev/) and GitHub Actions. The workflow handles:
- Version bumping based on Conventional Commits
- CHANGELOG.md generation and updates
- Publishing to crates.io
- Creating GitHub Releases with binary assets
- Building cross-platform binaries (Linux, macOS)
## Release Workflow
### Fully Automated Release Process
The release process is **completely automated** using release-plz. You don't need to manually create tags or trigger workflows.
#### How It Works
1. **Development**: Work on features/fixes on feature branches
2. **Commit**: Use Conventional Commits format (see below)
3. **Merge to main**: Merge pull requests to the main branch
4. **Automatic Release PR Creation**:
- GitHub Actions automatically creates/updates a release PR
- The PR includes version bumps and CHANGELOG updates
- Review the release PR to verify changes
5. **Merge Release PR**: Once approved, merge the release PR
6. **Automatic Publishing**:
- GitHub Actions automatically publishes to crates.io
- Builds binaries for all platforms (Linux GNU/MUSL, macOS x86_64/ARM64)
- Creates GitHub Release with binary assets
- Tags the release
#### Workflow Jobs
The `.github/workflows/release.yaml` workflow runs on every push to `main`:
1. **`release-plz-pr`**: Creates/updates a release PR with version bumps and CHANGELOG
2. **`release-plz-release`**: Publishes unpublished packages to crates.io
3. **`build-binaries`**: Builds cross-platform binaries (only when a release is created)
4. **`attach-assets`**: Attaches binaries to the GitHub Release and publishes it
### No Manual Tag Creation Needed
Unlike traditional workflows, you **do not** need to manually create or push version tags. The release-plz automation handles this automatically when you merge the release PR.
## Conventional Commits
This project follows the [Conventional Commits](https://www.conventionalcommits.org/) specification for commit messages. This enables automatic changelog generation and semantic versioning.
### Commit Message Format
```
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
### Commit Types
| `feat` | New feature | Added | Minor (0.x.0) |
| `fix` | Bug fix | Fixed | Patch (0.0.x) |
| `perf` | Performance improvement | Performance | Patch |
| `refactor` | Code refactoring | Changed | Patch |
| `docs` | Documentation changes | Documentation | Patch |
| `test` | Test additions/changes | Testing | Patch |
| `build` | Build system changes | Build | Patch |
| `deps` | Dependency updates | Dependencies | Patch |
| `ci` | CI/CD changes | CI/CD | Patch |
| `chore` | Other maintenance | Miscellaneous | Patch |
| `style` | Code style changes | Styling | Patch |
### Breaking Changes
Breaking changes trigger a major version bump (x.0.0):
```bash
# Method 1: Use BREAKING CHANGE in footer
git commit -m "feat: redesign config file format
BREAKING CHANGE: Config file format changed from JSON to TOML"
# Method 2: Add ! after type
git commit -m "feat!: redesign config file format"
```
### Examples
```bash
# Feature addition (bumps minor version)
git commit -m "feat: add --all flag to list command"
# Bug fix (bumps patch version)
git commit -m "fix: handle empty worktree list gracefully"
# Performance improvement
git commit -m "perf: optimize worktree path resolution"
# Documentation update
git commit -m "docs: add examples to README"
# Dependency update
git commit -m "deps: update clap to 4.5.0"
# Breaking change (bumps major version)
git commit -m "feat!: change default worktree directory template"
```
### Scope (Optional)
Add scope to provide additional context:
```bash
git commit -m "feat(tmux): add pane creation support"
git commit -m "fix(config): resolve XDG_CONFIG_HOME path correctly"
git commit -m "docs(hooks): document run/copy/link actions"
```
## Version Management
This project follows [Semantic Versioning 2.0.0](https://semver.org/):
- **Major (x.0.0)**: Breaking changes (incompatible API changes)
- **Minor (0.x.0)**: New features (backward compatible)
- **Patch (0.0.x)**: Bug fixes (backward compatible)
### Pre-1.0 Versioning
While in 0.x.y versions:
- Breaking changes bump the minor version (0.x.0)
- Features bump the minor version (0.x.0)
- Bug fixes bump the patch version (0.0.x)
## Release Checklist
Before creating a release tag:
- [ ] All CI checks pass on main branch
- [ ] Manual testing completed (see `docs/TEST.md`)
- [ ] CHANGELOG.md reviewed (ensure unreleased section is ready)
- [ ] Version number determined based on changes
- [ ] Documentation updated if needed
After release:
- [ ] Verify GitHub Release created successfully
- [ ] Verify all 4 binary assets attached
- [ ] Verify crates.io publication
- [ ] Test installation: `cargo install ofsht`
- [ ] Update any external documentation/announcements
## Platform Support
Binary releases are provided for:
- **Linux**:
- `x86_64-unknown-linux-gnu` (dynamically linked)
- `x86_64-unknown-linux-musl` (statically linked)
- **macOS**:
- `x86_64-apple-darwin` (Intel)
- `aarch64-apple-darwin` (Apple Silicon)
Windows support may be added in the future.
## Rollback Procedure
### If release fails during workflow execution:
1. Check workflow logs in GitHub Actions
2. Fix the issue in a new commit
3. Delete the failed tag:
```bash
git tag -d v0.x.0
git push origin :refs/tags/v0.x.0
```
4. Create a new tag after fixing
### If release workflow fails at a specific step:
**During draft release creation** (Run release-plz):
- The draft release may be partially created
- Check GitHub Releases page to see if a draft exists
- If draft exists but is incomplete:
```bash
gh release delete v0.x.0 --yes
git tag -d v0.x.0
git push origin :refs/tags/v0.x.0
```
**During asset upload** (Upload release assets):
- The draft release exists but some/all assets are missing
- You can manually upload missing assets:
```bash
gh release upload v0.x.0 path/to/asset.tar.gz --clobber
gh release edit v0.x.0 --draft=false --latest
```
- Or delete and retry:
```bash
gh release delete v0.x.0 --yes
git tag -d v0.x.0
git push origin :refs/tags/v0.x.0
```
**After release is published**:
- With Immutable releases enabled, you CANNOT modify published releases
- You must create a new patch version
### If release completed but has critical issues:
**Note**: With Immutable releases enabled, you cannot modify or delete existing releases.
1. **Yank the version from crates.io**:
```bash
cargo yank --vers 0.x.0 ofsht
```
This prevents new users from installing the broken version.
2. **Create a patch release**:
- Fix the issue
- Commit with appropriate message
- Tag and release the fixed version (e.g., v0.x.1)
3. **Document the issue**:
- Note the problem in the new release notes
- Update README/docs if necessary
## Troubleshooting
### Workflow fails at "Build release binary"
- Check Rust compilation errors in logs
- Ensure all dependencies are compatible with target platform
- Verify `Cargo.lock` is committed
### Workflow fails at "Run release-plz"
- Verify `CARGO_REGISTRY_TOKEN` secret is set and valid
- Check crates.io status: https://status.crates.io/
- Ensure version doesn't already exist on crates.io
### Workflow fails at "Upload release assets"
- Verify workflow has `contents: write` permission
- Check that artifacts were created in previous jobs
- Ensure the draft release was created successfully by release-plz
- Verify GitHub CLI (`gh`) is available in the runner
### Workflow fails at "Verify release assets"
This step checks that exactly 4 binary assets were uploaded. If it fails:
- Check the error message to see how many assets were found
- Review the "Upload release assets" step logs
- Verify all 4 build matrix jobs completed successfully
- Check artifact names match the expected pattern: `ofsht-{target}.tar.gz`
Manual verification:
```bash
gh release view v0.x.0 --json assets --jq '.assets[].name'
```
### Workflow fails at "Publish release"
- Verify the draft release exists
- Check workflow has `contents: write` permission
- Ensure Immutable releases is enabled in repository settings
- Verify all assets are attached before publishing
### Release published but binaries missing
This should not happen due to the verification step, but if it does:
- **DO NOT** try to add assets to a published release (Immutable releases prevents this)
- Create a new patch version with the missing binaries
- Document the issue in the new release notes
### Workflow fails at "Update Homebrew Tap"
The Homebrew tap update uses a GitHub App for authentication:
- Verify `OFSHT_APP_ID` variable is set correctly
- Verify `OFSHT_APP_PRIVATE_KEY` secret is set with the full PEM content
- Check that the GitHub App is installed on both repositories (ofsht, homebrew-tap)
- Verify App permissions: `actions: write`, `actions: read`, `contents: read`
- Check App installation status: https://github.com/settings/installations
**Note**: Homebrew tap update failures emit warnings but don't fail the release. The main release will succeed even if tap update fails.
Manual tap update:
```bash
TAG="v0.x.0"
gh workflow run update.yaml \
--repo wadackel/homebrew-tap \
--field formula=ofsht \
--field version="$TAG" \
--field repository=wadackel/ofsht
```
## References
- [release-plz Documentation](https://release-plz.ieni.dev/)
- [Conventional Commits Specification](https://www.conventionalcommits.org/)
- [Semantic Versioning](https://semver.org/)
- [Keep a Changelog](https://keepachangelog.com/)
- [GitHub Immutable Releases](https://github.blog/changelog/2024-11-12-immutable-releases-general-availability/)