Release Process¶
This guide explains how to create and publish new releases of scmd using our automated distribution pipeline.
Overview¶
scmd uses GoReleaser for automated multi-platform releases. When you push a git tag, GitHub Actions automatically:
- Runs tests
- Builds binaries for all platforms
- Creates Linux packages (deb, rpm, apk)
- Updates Homebrew tap
- Publishes to npm
- Creates Docker images
- Generates release notes
Prerequisites¶
Required Tools¶
# Install GoReleaser
make install-goreleaser
# Or manually
go install github.com/goreleaser/goreleaser/v2@latest
Required GitHub Secrets¶
Set these in your repository settings (Settings → Secrets and variables → Actions):
| Secret | Purpose | How to Get |
|---|---|---|
GITHUB_TOKEN | Auto-generated | Automatically available in GitHub Actions |
HOMEBREW_TAP_GITHUB_TOKEN | Update Homebrew tap | Personal Access Token with repo scope |
NPM_TOKEN | Publish to npm | Create at npmjs.com |
DOCKERHUB_USERNAME | Docker Hub login | Your Docker Hub username |
DOCKERHUB_TOKEN | Docker Hub authentication | Create at hub.docker.com |
Release Workflow¶
1. Prepare the Release¶
Update Version Information¶
No manual version updates are needed. GoReleaser automatically uses the git tag as the version.
Update CHANGELOG.md¶
Document all changes since the last release:
## [1.2.0] - 2025-01-15
### Added
- New feature X
- Support for Y
### Changed
- Updated Z for better performance
### Fixed
- Bug in component A
- Issue with B
### Security
- Patched vulnerability CVE-2025-XXXX
Commit Changes¶
2. Create a Git Tag¶
# Create and push tag using Makefile
make tag VERSION=v1.2.0
# Push the tag to trigger release
git push origin v1.2.0
Or manually:
3. Monitor the Release¶
- Go to the Actions tab
- Find the "Release" workflow
- Monitor progress through each step:
- ✅ Run Tests
- ✅ Build with GoReleaser
- ✅ Publish to npm
- ✅ Create install script
- ✅ Notify
4. Verify the Release¶
Once the workflow completes, verify:
GitHub Release¶
- Go to Releases
- Check that the new release appears with:
- Release notes
- All platform binaries
- Checksums
- Linux packages
Homebrew¶
# Test Homebrew installation
brew uninstall scmd
brew tap scmd/tap
brew install scmd
scmd --version # Should show v1.2.0
npm¶
# Test npm installation
npm uninstall -g scmd-cli
npm install -g scmd-cli
scmd --version # Should show 1.2.0 (without 'v')
Docker¶
Install Script¶
# Test install script
curl -fsSL https://raw.githubusercontent.com/scmd/scmd/v1.2.0/scripts/install.sh | bash
scmd --version
Testing Releases Locally¶
Snapshot Release (No Publishing)¶
Test the full release process without publishing:
# Create a snapshot release
make release-snapshot
# Check dist/ directory for artifacts
ls -lh dist/
This creates:
- Binaries for all platforms in
dist/ - Archives and checksums
- Linux packages
- Test the installation locally
Dry Run (Test Without Publishing)¶
Test GoReleaser configuration:
Local Testing Workflow¶
# 1. Validate GoReleaser config
make check-goreleaser
# 2. Run tests
make test
# 3. Create snapshot
make release-snapshot
# 4. Test binary locally
./dist/scmd-darwin-arm64 --version
# 5. Test install script locally
./scripts/install.sh
Distribution Channels¶
Homebrew Tap¶
Repository: scmd/homebrew-tap
GoReleaser automatically updates the tap with:
- New formula version
- Updated checksums
- Binary URLs
Users install with:
To submit to homebrew-core (future):
- Fork Homebrew/homebrew-core
- Copy formula from tap to
Formula/scmd.rb - Update URLs to point to main release
- Submit PR
npm Registry¶
Package: scmd-cli
The npm package is a wrapper that:
- Downloads the correct binary for the user's platform
- Installs it to npm's bin directory
- Automatically adds to PATH
Publishing is automated via GitHub Actions.
Linux Package Repositories¶
Packages are created for:
- Debian/Ubuntu (
.deb) - Red Hat/Fedora/CentOS (
.rpm) - Alpine Linux (
.apk)
Packages include:
- Binary in
/usr/bin/scmd - Shell completions
- Man pages (future)
- Post-install/remove scripts
Docker Hub¶
Repository: scmd/scmd
Multi-arch images are built for:
scmd/scmd:latestscmd/scmd:1.2.0scmd/scmd:1.2.0-amd64scmd/scmd:1.2.0-arm64
Version Strategy¶
Semantic Versioning¶
We follow Semantic Versioning 2.0.0:
- Major (v2.0.0): Breaking changes
- Minor (v1.2.0): New features, backward compatible
- Patch (v1.2.1): Bug fixes, backward compatible
Pre-release Versions¶
For testing:
# Alpha
git tag -a v1.3.0-alpha.1 -m "Alpha release"
# Beta
git tag -a v1.3.0-beta.1 -m "Beta release"
# Release candidate
git tag -a v1.3.0-rc.1 -m "Release candidate"
Pre-releases are marked as "pre-release" on GitHub and not promoted as "latest".
Version Tags¶
- Use
vprefix:v1.2.0(not1.2.0) - Create annotated tags (not lightweight)
- Include meaningful tag message
Release Checklist¶
Before creating a release:
- All tests pass (
make test) - Documentation is updated
- CHANGELOG.md is updated
- Breaking changes are documented
- Security advisories are published (if applicable)
- Migration guide exists (for breaking changes)
After creating a release:
- GitHub release created successfully
- All binaries are uploaded
- Checksums are correct
- Homebrew tap updated
- npm package published
- Docker images pushed
- Installation methods verified
- Release notes reviewed
- Announcements posted (if major release)
Hotfix Releases¶
For urgent fixes:
# 1. Create hotfix branch from tag
git checkout -b hotfix/v1.2.1 v1.2.0
# 2. Make fix
git commit -m "fix: critical bug in X"
# 3. Create tag
git tag -a v1.2.1 -m "Hotfix: critical bug in X"
# 4. Push tag
git push origin v1.2.1
# 5. Merge back to main
git checkout main
git merge hotfix/v1.2.1
git push origin main
Rollback¶
If a release has issues:
Delete GitHub Release¶
# Delete tag locally
git tag -d v1.2.0
# Delete tag remotely
git push origin :refs/tags/v1.2.0
# Delete GitHub release via UI or API
gh release delete v1.2.0
Revert npm Package¶
# Deprecate version
npm deprecate scmd-cli@1.2.0 "This version has been deprecated due to critical bug"
# Publish fixed version
# ... fix code ...
npm version patch
npm publish
Update Homebrew¶
The tap will auto-update, but for homebrew-core:
Troubleshooting¶
GoReleaser Fails¶
Check configuration:
Common issues:
- Missing GITHUB_TOKEN
- Invalid .goreleaser.yml syntax
- Build failures for specific platforms
Debug:
npm Publish Fails¶
Check token:
Manual publish (if automation fails):
Homebrew Tap Not Updated¶
Check:
- Verify
HOMEBREW_TAP_GITHUB_TOKENis set - Check token has
reposcope - Verify repository exists:
scmd/homebrew-tap
Manual update:
# Clone tap
git clone https://github.com/scmd/homebrew-tap
cd homebrew-tap
# Update formula
# Edit Formula/scmd.rb with new version and checksums
# Commit and push
git commit -am "Update to v1.2.0"
git push
Docker Build Fails¶
Check Docker Hub credentials:
- Verify
DOCKERHUB_USERNAMEandDOCKERHUB_TOKEN
Manual build and push:
Advanced Topics¶
Custom Binary Names¶
Edit .goreleaser.yml:
Platform-Specific Builds¶
Skip platforms:
Signing Binaries¶
Add GPG signing:
signs:
- artifacts: checksum
args:
- "--batch"
- "--local-user"
- "{{ .Env.GPG_FINGERPRINT }}"
- "--output"
- "${signature}"
- "--detach-sign"
- "${artifact}"
Custom Release Notes¶
Edit .goreleaser.yml:
changelog:
filters:
exclude:
- '^docs:'
- '^test:'
groups:
- title: 'Features'
regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$'
order: 0
- title: 'Bug Fixes'
regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$'
order: 1