diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh new file mode 100755 index 00000000..3b067572 --- /dev/null +++ b/scripts/bump-version.sh @@ -0,0 +1,315 @@ +#!/bin/bash +set -e + +# ============================================================================= +# VERSION BUMP SCRIPT FOR GAS TOWN +# ============================================================================= +# +# This script handles version bumping for Gas Town releases. +# It updates version numbers across all components. +# +# QUICK START: +# ./scripts/bump-version.sh X.Y.Z --commit --tag --push --install +# +# WHAT IT UPDATES: +# - internal/cmd/version.go - CLI version constant +# - npm-package/package.json - npm package version +# - CHANGELOG.md - Creates release entry from [Unreleased] +# +# ============================================================================= + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Usage message +usage() { + echo "Usage: $0 [--commit] [--tag] [--push] [--install]" + echo "" + echo "Bump version across all Gas Town components." + echo "" + echo "Arguments:" + echo " Semantic version (e.g., 0.2.0, 1.0.0)" + echo " --commit Automatically create a git commit" + echo " --tag Create annotated git tag (requires --commit)" + echo " --push Push commit and tag to origin (requires --tag)" + echo " --install Rebuild and install gt binary to GOPATH/bin" + echo "" + echo "Examples:" + echo " $0 0.2.0 # Update versions and show diff" + echo " $0 0.2.0 --install # Update versions and rebuild/install gt" + echo " $0 0.2.0 --commit # Update versions and commit" + echo " $0 0.2.0 --commit --tag # Update, commit, and tag" + echo " $0 0.2.0 --commit --tag --push # Full release preparation" + echo "" + echo "Recommended release command:" + echo " $0 X.Y.Z --commit --tag --push --install" + exit 1 +} + +# Validate semantic versioning +validate_version() { + local version=$1 + if ! [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo -e "${RED}Error: Invalid version format '$version'${NC}" + echo "Expected semantic version format: MAJOR.MINOR.PATCH (e.g., 0.2.0)" + exit 1 + fi +} + +# Get current version from version.go +get_current_version() { + grep 'Version = ' internal/cmd/version.go | sed 's/.*"\(.*\)".*/\1/' +} + +# Update a file with sed (cross-platform compatible) +update_file() { + local file=$1 + local old_pattern=$2 + local new_text=$3 + + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s|$old_pattern|$new_text|g" "$file" + else + sed -i "s|$old_pattern|$new_text|g" "$file" + fi +} + +# Update CHANGELOG.md: move [Unreleased] to [version] +update_changelog() { + local version=$1 + local date=$(date +%Y-%m-%d) + + if [ ! -f "CHANGELOG.md" ]; then + echo -e "${YELLOW}Warning: CHANGELOG.md not found, skipping${NC}" + return + fi + + # Check if there's an [Unreleased] section + if ! grep -q "## \[Unreleased\]" CHANGELOG.md; then + echo -e "${YELLOW}Warning: No [Unreleased] section in CHANGELOG.md${NC}" + echo -e "${YELLOW}You may need to manually update CHANGELOG.md${NC}" + return + fi + + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/## \[Unreleased\]/## [Unreleased]\n\n## [$version] - $date/" CHANGELOG.md + else + sed -i "s/## \[Unreleased\]/## [Unreleased]\n\n## [$version] - $date/" CHANGELOG.md + fi +} + +# Main script +main() { + if [ $# -lt 1 ]; then + usage + fi + + NEW_VERSION=$1 + AUTO_COMMIT=false + AUTO_TAG=false + AUTO_PUSH=false + AUTO_INSTALL=false + + # Parse flags + shift + while [ $# -gt 0 ]; do + case "$1" in + --commit) + AUTO_COMMIT=true + ;; + --tag) + AUTO_TAG=true + ;; + --push) + AUTO_PUSH=true + ;; + --install) + AUTO_INSTALL=true + ;; + *) + echo -e "${RED}Error: Unknown option '$1'${NC}" + usage + ;; + esac + shift + done + + # Validate flag dependencies + if [ "$AUTO_TAG" = true ] && [ "$AUTO_COMMIT" = false ]; then + echo -e "${RED}Error: --tag requires --commit${NC}" + exit 1 + fi + if [ "$AUTO_PUSH" = true ] && [ "$AUTO_TAG" = false ]; then + echo -e "${RED}Error: --push requires --tag${NC}" + exit 1 + fi + + # Validate version format + validate_version "$NEW_VERSION" + + # Check if we're in the repo root + if [ ! -f "internal/cmd/version.go" ]; then + echo -e "${RED}Error: Must run from repository root${NC}" + exit 1 + fi + + # Get current version + CURRENT_VERSION=$(get_current_version) + + echo -e "${YELLOW}Bumping version: $CURRENT_VERSION → $NEW_VERSION${NC}" + echo "" + + # Check for uncommitted changes + if ! git diff-index --quiet HEAD --; then + echo -e "${YELLOW}Warning: You have uncommitted changes${NC}" + if [ "$AUTO_COMMIT" = true ]; then + echo -e "${RED}Error: Cannot auto-commit with existing uncommitted changes${NC}" + exit 1 + fi + read -p "Continue anyway? (y/N) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi + fi + + echo "Updating version files..." + + # 1. Update internal/cmd/version.go + echo " • internal/cmd/version.go" + update_file "internal/cmd/version.go" \ + "Version = \"$CURRENT_VERSION\"" \ + "Version = \"$NEW_VERSION\"" + + # 2. Update npm-package/package.json + echo " • npm-package/package.json" + update_file "npm-package/package.json" \ + "\"version\": \"$CURRENT_VERSION\"" \ + "\"version\": \"$NEW_VERSION\"" + + # 3. Update CHANGELOG.md + echo " • CHANGELOG.md" + update_changelog "$NEW_VERSION" + + echo "" + echo -e "${GREEN}✓ Version updated to $NEW_VERSION${NC}" + echo "" + + # Show diff + echo "Changed files:" + git diff --stat + echo "" + + # Verify versions match + echo "Verifying version consistency..." + VERSION_GO=$(grep 'Version = ' internal/cmd/version.go | sed 's/.*"\(.*\)".*/\1/') + VERSION_NPM=$(grep '"version"' npm-package/package.json | head -1 | sed 's/.*"\([0-9.]*\)".*/\1/') + + if [ "$VERSION_GO" = "$NEW_VERSION" ] && [ "$VERSION_NPM" = "$NEW_VERSION" ]; then + echo -e "${GREEN}✓ All versions match: $NEW_VERSION${NC}" + else + echo -e "${RED}✗ Version mismatch detected!${NC}" + echo " version.go: $VERSION_GO" + echo " package.json: $VERSION_NPM" + exit 1 + fi + + echo "" + + # Auto-install if requested + if [ "$AUTO_INSTALL" = true ]; then + echo "Rebuilding and installing gt..." + GOPATH_BIN="$(go env GOPATH)/bin" + + if ! go build -o /tmp/gt-new ./cmd/gt; then + echo -e "${RED}✗ go build failed${NC}" + exit 1 + fi + + # Codesign on macOS + if [[ "$OSTYPE" == "darwin"* ]]; then + xattr -cr /tmp/gt-new 2>/dev/null + codesign -f -s - /tmp/gt-new 2>/dev/null + echo -e "${GREEN}✓ gt codesigned for macOS${NC}" + fi + + cp /tmp/gt-new "$GOPATH_BIN/gt" + if [[ "$OSTYPE" == "darwin"* ]]; then + codesign -f -s - "$GOPATH_BIN/gt" 2>/dev/null + fi + rm -f /tmp/gt-new + + echo -e "${GREEN}✓ gt installed to $GOPATH_BIN/gt${NC}" + + # Verify + INSTALLED_VERSION=$("$GOPATH_BIN/gt" version 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) + if [ "$INSTALLED_VERSION" = "$NEW_VERSION" ]; then + echo -e "${GREEN}✓ Verified: gt version $INSTALLED_VERSION${NC}" + else + echo -e "${YELLOW}⚠ gt reports $INSTALLED_VERSION (expected $NEW_VERSION)${NC}" + fi + echo "" + fi + + # Auto-commit if requested + if [ "$AUTO_COMMIT" = true ]; then + echo "Creating git commit..." + + git add internal/cmd/version.go \ + npm-package/package.json + + if [ -f "CHANGELOG.md" ]; then + git add CHANGELOG.md + fi + + git commit -m "chore: Bump version to $NEW_VERSION + +Updated all component versions: +- gt CLI: $CURRENT_VERSION → $NEW_VERSION +- npm package: $CURRENT_VERSION → $NEW_VERSION + +Generated by scripts/bump-version.sh" + + echo -e "${GREEN}✓ Commit created${NC}" + echo "" + + # Auto-tag if requested + if [ "$AUTO_TAG" = true ]; then + echo "Creating git tag v$NEW_VERSION..." + git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION" + echo -e "${GREEN}✓ Tag created${NC}" + echo "" + fi + + # Auto-push if requested + if [ "$AUTO_PUSH" = true ]; then + echo "Pushing to origin..." + git push origin main + git push origin "v$NEW_VERSION" + echo -e "${GREEN}✓ Pushed to origin${NC}" + echo "" + echo -e "${GREEN}Release v$NEW_VERSION initiated!${NC}" + echo "GitHub Actions will build artifacts in ~5-10 minutes." + echo "Monitor: https://github.com/steveyegge/gastown/actions" + elif [ "$AUTO_TAG" = true ]; then + echo "Next steps:" + echo " git push origin main" + echo " git push origin v$NEW_VERSION" + else + echo "Next steps:" + echo " git push origin main" + echo " git tag -a v$NEW_VERSION -m 'Release v$NEW_VERSION'" + echo " git push origin v$NEW_VERSION" + fi + else + echo "Review the changes above." + echo "" + echo "To commit and release:" + echo " $0 $NEW_VERSION --commit --tag --push --install" + fi +} + +main "$@"