-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Release Automation Plan for redisctl
Executive Summary
Based on the issues encountered during the v0.5.1 release and requirements from issue #284, this plan outlines a comprehensive release automation strategy to reduce release time from ~30 minutes to ~5 minutes with minimal human intervention.
Problems Identified from v0.5.1 Release
-
Version Synchronization Failure
- Workspace version updated but individual crate versions missed
- cargo-dist couldn't find packages with correct version
- Required emergency PR fix: update crate versions to 0.5.1 for release #331 to fix
-
Manual Steps Required
- Create release PR manually
- Update changelog manually
- Update version numbers in 4 places manually
- Push tags manually after PR merge
-
Protected Branch Restrictions
- Cannot push directly to main
- All changes require PR with CI passes
- Complicates automated version bumping
Proposed Solution: release-plz
After evaluating options, release-plz is the recommended tool because:
- Designed specifically for Rust workspace projects
- Handles version bumping across all crates automatically
- Generates changelogs from conventional commits
- Creates release PRs automatically
- Integrates well with GitHub Actions
- Supports our protected branch workflow
Implementation Plan
Phase 1: Setup release-plz (Week 1)
1.1 Configuration File
Create release-plz.toml:
[workspace]
# Update all crates together
allow_dirty = false
consolidate_commits = true
git_release_enable = true
git_tag_enable = true
publish_allow_dirty = false
# Changelog generation
changelog_update = true
changelog_include = ["feat", "fix", "perf", "refactor", "docs", "test", "chore"]
# Version bumping rules
version_scheme = "semver"
dependencies_update = true
[[package]]
name = "redisctl"
# Main CLI gets its own tag format
tag_name = "v{{ version }}"
[[package]]
name = "redis-cloud"
# Library crates get prefixed tags
tag_name = "redis-cloud-v{{ version }}"
[[package]]
name = "redis-enterprise"
tag_name = "redis-enterprise-v{{ version }}"1.2 GitHub Action Workflow
Create .github/workflows/release-plz.yml:
name: Release-plz
permissions:
contents: write
pull-requests: write
on:
push:
branches: [ main ]
schedule:
# Run weekly to check for updates
- cron: '0 9 * * 1'
workflow_dispatch:
jobs:
release-plz:
name: Release-plz
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: MarcoIeni/release-plz-action@v0.5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}Phase 2: Integration with cargo-dist (Week 1)
2.1 Update Release Workflow
Modify .github/workflows/release.yml to trigger on release-plz tags:
on:
push:
tags:
- 'v[0-9]+.*' # Main CLI releases
- '*-v[0-9]+.*' # Library releases
workflow_dispatch:2.2 Version Validation
Add pre-release checks:
- name: Validate versions
run: |
# Ensure all versions match the tag
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name == "redisctl") | .version')
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
echo "Version mismatch: tag=$TAG_VERSION cargo=$CARGO_VERSION"
exit 1
fiPhase 3: Automated Testing & Validation (Week 2)
3.1 Pre-release Checklist Script
Create scripts/pre-release-check.sh:
#!/bin/bash
set -e
echo "🔍 Running pre-release checks..."
# 1. Check all versions are synchronized
echo "Checking version synchronization..."
WORKSPACE_VERSION=$(grep "^version" Cargo.toml | head -1 | cut -d'"' -f2)
for crate in redisctl redis-cloud redis-enterprise; do
CRATE_VERSION=$(grep "^version" crates/$crate/Cargo.toml | cut -d'"' -f2)
if [ "$WORKSPACE_VERSION" != "$CRATE_VERSION" ]; then
echo "❌ Version mismatch: workspace=$WORKSPACE_VERSION $crate=$CRATE_VERSION"
exit 1
fi
done
echo "✅ All versions synchronized: $WORKSPACE_VERSION"
# 2. Run full test suite
echo "Running tests..."
cargo test --workspace --all-features
# 3. Check for uncommitted changes
if ! git diff --quiet; then
echo "❌ Uncommitted changes detected"
exit 1
fi
echo "✅ All pre-release checks passed!"3.2 Add to CI Pipeline
- name: Pre-release validation
run: ./scripts/pre-release-check.shPhase 4: Rollback & Recovery (Week 2)
4.1 State Tracking
Create .release-state.json to track release progress:
{
"version": "0.5.1",
"stage": "preparation",
"started": "2024-01-15T10:00:00Z",
"pr_number": 330,
"tag_pushed": false,
"crates_published": []
}4.2 Rollback Script
Create scripts/rollback-release.sh:
#!/bin/bash
# Rollback a failed release based on current state
STATE_FILE=".release-state.json"
if [ ! -f "$STATE_FILE" ]; then
echo "No release in progress"
exit 0
fi
STAGE=$(jq -r '.stage' $STATE_FILE)
case $STAGE in
"preparation")
echo "Rolling back version changes..."
git reset --hard HEAD~1
;;
"staging")
echo "Closing PR and deleting branch..."
PR_NUMBER=$(jq -r '.pr_number' $STATE_FILE)
gh pr close $PR_NUMBER
git push origin --delete release/v$(jq -r '.version' $STATE_FILE)
;;
*)
echo "Cannot rollback from stage: $STAGE"
exit 1
;;
esac
rm $STATE_FILE
echo "✅ Rollback complete"Phase 5: Manual Override & Dry Run (Week 3)
5.1 Manual Release Script
For emergency releases or special cases:
# scripts/manual-release.sh
#!/bin/bash
VERSION=${1:-patch}
DRY_RUN=${2:-false}
if [ "$DRY_RUN" = "true" ]; then
echo "🔍 DRY RUN MODE"
release-plz release --dry-run
else
release-plz release
fi5.2 Interactive Release CLI
Create a Rust binary for guided releases:
// crates/release-tool/src/main.rs
use clap::Parser;
use dialoguer::{Select, Confirm};
#[derive(Parser)]
struct Args {
#[arg(long)]
dry_run: bool,
}
fn main() -> Result<()> {
let args = Args::parse();
let version_type = Select::new()
.with_prompt("Select version bump type")
.items(&["patch", "minor", "major", "custom"])
.default(0)
.interact()?;
if !args.dry_run {
let confirm = Confirm::new()
.with_prompt("Ready to create release?")
.interact()?;
if !confirm {
return Ok(());
}
}
// Execute release-plz
Ok(())
}Migration Strategy
Week 1: Setup & Testing
- Install release-plz locally
- Test with dry-run on feature branch
- Configure GitHub Actions
- Document process in RELEASING.md
Week 2: Pilot Release
- Create v0.5.2 as pilot release
- Monitor automated PR creation
- Verify changelog generation
- Test rollback procedures
Week 3: Full Automation
- Remove manual release documentation
- Archive old release scripts
- Train team on new process
- Create runbook for edge cases
Success Metrics
| Metric | Current | Target | Measurement |
|---|---|---|---|
| Release Time | ~30 min | <5 min | GitHub Action runtime |
| Manual Steps | 8+ | 1 (merge PR) | Count of human actions |
| Version Sync Errors | 1 in v0.5.1 | 0 | Release failures due to versions |
| Rollback Time | N/A | <2 min | Time to revert failed release |
Risk Mitigation
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| release-plz bugs | Low | High | Maintain manual fallback |
| CI token permissions | Medium | Medium | Use fine-grained PATs |
| Partial publish failure | Low | High | State tracking & rollback |
| Wrong version bump | Medium | Low | PR review before merge |
Decision Points
-
Q: Should we version all crates together or independently?
- A: Together initially, can split later if needed
-
Q: How to handle hotfixes?
- A: Manual override with
release-plz release --version X.Y.Z
- A: Manual override with
-
Q: What about pre-releases (RC, beta)?
- A: Use
--pre-releaseflag and manual workflow
- A: Use
Implementation Checklist
- Create release-plz.toml configuration
- Set up GitHub Action for release-plz
- Add CARGO_REGISTRY_TOKEN secret
- Update release.yml for new tag format
- Create pre-release validation script
- Implement state tracking
- Write rollback procedures
- Test dry-run on feature branch
- Document in RELEASING.md
- Archive manual release docs
- Pilot release v0.5.2
- Team training session
- Create emergency runbook
Next Steps
- Immediate: Get v0.5.1 released with current manual process
- This Week: Create feature branch with release-plz setup
- Next Week: Test automation with v0.5.2 pilot
- Two Weeks: Full automation live
References
- release-plz documentation
- cargo-dist integration
- Conventional Commits
- Issue #284: Release Automation
References
- Closes Automate release process #284
- Based on lessons learned from v0.5.1 release issues (PRs chore: release v0.5.1 #330, fix: update crate versions to 0.5.1 for release #331)
This plan synthesizes the requirements from #284 with real-world experience from our v0.5.1 release problems.