diff --git a/RELEASING.md b/RELEASING.md index 314b365d..15fd8113 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -2,7 +2,25 @@ Quick guide for releasing a new version of beads. -## Pre-Release Checklist +## 🚀 The Easy Way (Recommended) + +Use the fully automated release script: + +```bash +./scripts/release.sh 0.9.3 +``` + +This does **everything**: version bump, tests, git tag, Homebrew update, and local installation. + +See [scripts/README.md](scripts/README.md#releasesh--the-easy-button) for details. + +--- + +## 📋 The Manual Way + +If you prefer step-by-step control: + +### Pre-Release Checklist 1. **Kill all running daemons (CRITICAL)**: ```bash diff --git a/scripts/README.md b/scripts/README.md index aa74128d..bfd88a18 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -2,6 +2,71 @@ Utility scripts for maintaining the beads project. +## release.sh (⭐ The Easy Button) + +**One-command release** from version bump to local installation. + +### Usage + +```bash +# Full release (does everything) +./scripts/release.sh 0.9.3 + +# Preview what would happen +./scripts/release.sh 0.9.3 --dry-run +``` + +### What It Does + +This master script automates the **entire release process**: + +1. ✅ Kills running daemons (avoids version conflicts) +2. ✅ Runs tests and linting +3. ✅ Bumps version in all files +4. ✅ Commits and pushes version bump +5. ✅ Creates and pushes git tag +6. ✅ Updates Homebrew formula +7. ✅ Upgrades local brew installation +8. ✅ Verifies everything works + +**After this script completes, your system is running the new version!** + +### Examples + +```bash +# Release version 0.9.3 +./scripts/release.sh 0.9.3 + +# Preview a release (no changes made) +./scripts/release.sh 1.0.0 --dry-run +``` + +### Prerequisites + +- Clean git working directory +- All changes committed +- golangci-lint installed +- Homebrew installed (for local upgrade) +- Push access to steveyegge/beads and steveyegge/homebrew-beads + +### Output + +The script provides colorful, step-by-step progress output: +- 🟨 Yellow: Current step +- 🟩 Green: Step completed +- 🟥 Red: Errors +- 🟦 Blue: Section headers + +### What Happens Next + +After the script finishes: +- GitHub Actions builds binaries for all platforms (~5 minutes) +- PyPI package is published automatically +- Users can `brew upgrade bd` to get the new version +- GitHub Release is created with binaries and changelog + +--- + ## bump-version.sh Bumps the version number across all beads components in a single command. diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 00000000..61f220bd --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,222 @@ +#!/bin/bash +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +usage() { + cat << EOF +Usage: $0 [--dry-run] + +Fully automate a beads release from version bump to local installation. + +Arguments: + version Version number (e.g., 0.9.3) + --dry-run Show what would happen without making changes + +This script performs the complete release workflow: + 1. Kill running daemons + 2. Run tests and linting + 3. Bump version in all files + 4. Commit and push version bump + 5. Create and push git tag + 6. Update Homebrew formula + 7. Upgrade local brew installation + 8. Verify everything is working + +Examples: + $0 0.9.3 # Full release + $0 0.9.3 --dry-run # Preview what would happen + +After this script completes, your system will be running the new version! +EOF + exit 1 +} + +# Parse arguments +DRY_RUN=false +VERSION="" + +for arg in "$@"; do + case $arg in + --dry-run) + DRY_RUN=true + shift + ;; + *) + if [ -z "$VERSION" ]; then + VERSION="$arg" + fi + shift + ;; + esac +done + +if [ -z "$VERSION" ]; then + usage +fi + +# Strip 'v' prefix if present +VERSION="${VERSION#v}" + +echo -e "${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}║${NC} ${GREEN}Beads Full Release Automation${NC} ${BLUE}║${NC}" +echo -e "${BLUE}║${NC} Version: ${YELLOW}v${VERSION}${NC} ${BLUE}║${NC}" +if [ "$DRY_RUN" = true ]; then + echo -e "${BLUE}║${NC} ${YELLOW}Mode: DRY RUN (no changes will be made)${NC} ${BLUE}║${NC}" +fi +echo -e "${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}" +echo "" + +# Step 1: Kill daemons +echo -e "${YELLOW}Step 1/8: Killing running daemons...${NC}" +if [ "$DRY_RUN" = true ]; then + echo "[DRY RUN] Would run: pkill -f 'bd.*daemon'" +else + pkill -f "bd.*daemon" 2>/dev/null || true + sleep 1 + if pgrep -lf "bd.*daemon" > /dev/null 2>&1; then + echo -e "${RED}✗ Daemons still running${NC}" + pgrep -lf "bd.*daemon" + exit 1 + fi +fi +echo -e "${GREEN}✓ All daemons stopped${NC}\n" + +# Step 2: Run tests +echo -e "${YELLOW}Step 2/8: Running tests and linting...${NC}" +if [ "$DRY_RUN" = true ]; then + echo "[DRY RUN] Would run: TMPDIR=/tmp go test ./..." + echo "[DRY RUN] Would run: golangci-lint run ./..." +else + if ! TMPDIR=/tmp go test ./...; then + echo -e "${RED}✗ Tests failed${NC}" + exit 1 + fi + if ! golangci-lint run ./...; then + echo -e "${YELLOW}⚠ Linting warnings (see LINTING.md for baseline)${NC}" + fi +fi +echo -e "${GREEN}✓ Tests passed${NC}\n" + +# Step 3: Bump version +echo -e "${YELLOW}Step 3/8: Bumping version to ${VERSION}...${NC}" +if [ "$DRY_RUN" = true ]; then + echo "[DRY RUN] Would run: $SCRIPT_DIR/bump-version.sh $VERSION --commit" + $SCRIPT_DIR/bump-version.sh "$VERSION" 2>/dev/null || true +else + if ! $SCRIPT_DIR/bump-version.sh "$VERSION" --commit; then + echo -e "${RED}✗ Version bump failed${NC}" + exit 1 + fi +fi +echo -e "${GREEN}✓ Version bumped and committed${NC}\n" + +# Step 4: Rebuild local binary +echo -e "${YELLOW}Step 4/8: Rebuilding local binary...${NC}" +if [ "$DRY_RUN" = true ]; then + echo "[DRY RUN] Would run: go build -o bd ./cmd/bd" +else + if ! go build -o bd ./cmd/bd; then + echo -e "${RED}✗ Build failed${NC}" + exit 1 + fi + BUILT_VERSION=$(./bd version 2>/dev/null | head -1) + echo "Built version: $BUILT_VERSION" +fi +echo -e "${GREEN}✓ Binary rebuilt${NC}\n" + +# Step 5: Push version bump +echo -e "${YELLOW}Step 5/8: Pushing version bump to GitHub...${NC}" +if [ "$DRY_RUN" = true ]; then + echo "[DRY RUN] Would run: git push origin main" +else + if ! git push origin main; then + echo -e "${RED}✗ Push failed${NC}" + exit 1 + fi +fi +echo -e "${GREEN}✓ Version bump pushed${NC}\n" + +# Step 6: Create and push tag +echo -e "${YELLOW}Step 6/8: Creating and pushing git tag v${VERSION}...${NC}" +if [ "$DRY_RUN" = true ]; then + echo "[DRY RUN] Would run: git tag v${VERSION}" + echo "[DRY RUN] Would run: git push origin v${VERSION}" +else + if git rev-parse "v${VERSION}" >/dev/null 2>&1; then + echo -e "${YELLOW}⚠ Tag v${VERSION} already exists, skipping tag creation${NC}" + else + git tag "v${VERSION}" + fi + + if ! git push origin "v${VERSION}"; then + echo -e "${RED}✗ Tag push failed${NC}" + exit 1 + fi +fi +echo -e "${GREEN}✓ Tag v${VERSION} pushed${NC}\n" + +# Wait for GitHub to generate tarball +if [ "$DRY_RUN" = false ]; then + echo -e "${YELLOW}Waiting 10 seconds for GitHub to generate release tarball...${NC}" + sleep 10 +fi + +# Step 7: Update Homebrew formula +echo -e "${YELLOW}Step 7/8: Updating Homebrew formula...${NC}" +if [ "$DRY_RUN" = true ]; then + echo "[DRY RUN] Would run: $SCRIPT_DIR/update-homebrew.sh ${VERSION}" +else + if ! $SCRIPT_DIR/update-homebrew.sh "$VERSION"; then + echo -e "${RED}✗ Homebrew update failed${NC}" + exit 1 + fi +fi +echo -e "${GREEN}✓ Homebrew formula updated${NC}\n" + +# Step 8: Upgrade local installation +echo -e "${YELLOW}Step 8/8: Upgrading local Homebrew installation...${NC}" +if [ "$DRY_RUN" = true ]; then + echo "[DRY RUN] Would run: brew update" + echo "[DRY RUN] Would run: brew upgrade bd" +else + brew update + + # Check if bd is installed via brew + if brew list bd >/dev/null 2>&1; then + brew upgrade bd || brew reinstall bd + else + echo -e "${YELLOW}⚠ bd not installed via Homebrew, skipping upgrade${NC}" + echo "To install: brew install steveyegge/beads/bd" + fi +fi +echo -e "${GREEN}✓ Local installation upgraded${NC}\n" + +# Final verification +echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" +echo -e "${GREEN}✓ Release Complete!${NC}\n" + +if [ "$DRY_RUN" = false ]; then + echo "Verification:" + echo " Installed version: $(bd version 2>/dev/null | head -1 || echo 'Error getting version')" + echo "" + echo "Next steps:" + echo " • GitHub Actions is building release binaries" + echo " • Monitor: https://github.com/steveyegge/beads/actions" + echo " • PyPI publish happens automatically" + echo " • Update CHANGELOG.md if not done yet" + echo "" + echo "Your system is now running v${VERSION}!" +else + echo "[DRY RUN] No changes were made." + echo "Run without --dry-run to perform the actual release." +fi + +echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"