From 50eb9ce5507c8c219e86c8f1040a3500146e3ebd Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Thu, 23 Oct 2025 19:02:12 -0700 Subject: [PATCH] feat: Add GoReleaser workflow for cross-platform binary releases - Add .goreleaser.yml for automated releases - Add .github/workflows/release.yml triggered on version tags - Build matrix: darwin/linux/windows for amd64/arm64 - Update install.sh to download from GitHub releases first - Add install.sh symlink at root for convenience - Update RELEASING.md with automation documentation Closes #89 (vendorable executables as releases) Implements bd-85 Amp-Thread-ID: https://ampcode.com/threads/T-02baad43-7e97-4710-bc60-777643d2eb77 Co-authored-by: Amp --- .github/workflows/release.yml | 32 ++++++++ .goreleaser.yml | 102 ++++++++++++++++++++++++ RELEASING.md | 38 ++++++--- install.sh | 1 + scripts/install.sh | 142 ++++++++++++++++++++++++++++------ 5 files changed, 281 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .goreleaser.yml create mode 120000 install.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..fbd2f38c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,32 @@ +name: Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.24' + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + distribution: goreleaser + version: '~> v2' + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 00000000..f1eff7dc --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,102 @@ +# GoReleaser configuration for beads +# See https://goreleaser.com for documentation + +version: 2 + +before: + hooks: + # Ensure dependencies are up to date + - go mod tidy + # Run tests before building + - go test ./... + +builds: + - id: bd + main: ./cmd/bd + binary: bd + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + # Ignore combinations that don't make sense + ignore: + - goos: windows + goarch: arm64 + ldflags: + - -s -w + - -X main.Version={{.Version}} + - -X main.Build={{.ShortCommit}} + +archives: + - id: bd-archive + format: tar.gz + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + format_overrides: + - goos: windows + format: zip + files: + - LICENSE + - README.md + - CHANGELOG.md + +checksum: + name_template: "checksums.txt" + algorithm: sha256 + +snapshot: + version_template: "{{ incpatch .Version }}-next" + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + - "^chore:" + - "Merge pull request" + - "Merge branch" + groups: + - title: "Features" + regexp: "^.*feat[(\\w)]*:+.*$" + order: 0 + - title: "Bug Fixes" + regexp: "^.*fix[(\\w)]*:+.*$" + order: 1 + - title: "Others" + order: 999 + +release: + github: + owner: steveyegge + name: beads + draft: false + prerelease: auto + name_template: "v{{.Version}}" + header: | + ## beads v{{.Version}} + + Pre-compiled binaries for Linux, macOS (Intel & Apple Silicon), and Windows. + + ### Installation + + **macOS/Linux:** + ```bash + curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash + ``` + + **Windows (PowerShell):** + ```powershell + irm https://raw.githubusercontent.com/steveyegge/beads/main/install.ps1 | iex + ``` + + **Manual Install:** + Download the appropriate binary for your platform below, extract it, and place it in your PATH. + +# Announce the release +announce: + skip: false diff --git a/RELEASING.md b/RELEASING.md index 86b23362..06a608a9 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -110,14 +110,25 @@ brew install --build-from-source bd bd version # Verify it shows new version ``` -### 4. Create GitHub Release +### 4. GitHub Releases (Automated) -1. Go to https://github.com/steveyegge/beads/releases/new -2. Choose tag: `v0.9.X` -3. Title: `v0.9.X` -4. Description: Copy from CHANGELOG.md -5. Attach binaries (optional - GitHub Actions can automate this) -6. Publish release +**GoReleaser automatically creates releases when you push tags!** + +The `.github/workflows/release.yml` workflow: +- Triggers on `v*` tags +- Builds cross-platform binaries (Linux, macOS, Windows for amd64/arm64) +- Generates checksums +- Creates GitHub release with binaries and changelog +- Publishes release automatically + +Just push your tag and wait ~5 minutes: +```bash +git push origin v0.9.X +``` + +Monitor at: https://github.com/steveyegge/beads/actions + +The release will appear at: https://github.com/steveyegge/beads/releases ## Post-Release @@ -150,13 +161,16 @@ Wait a few seconds after pushing tag for GitHub to make tarball available, then ### Missing PyPI credentials Set up API token at https://pypi.org/manage/account/token/ and use `__token__` as username. -## Automation Ideas (Future) +## Automation Status -Consider GitHub Actions to: -- Run tests on tag push -- Auto-build and publish to PyPI +✅ **Automated:** +- GitHub releases with binaries (GoReleaser + GitHub Actions) +- Cross-platform builds (Linux, macOS, Windows) +- Checksums and changelog generation + +🔄 **TODO:** +- Auto-publish to PyPI - Auto-update Homebrew formula -- Create GitHub release with binaries ## Related Documentation diff --git a/install.sh b/install.sh new file mode 120000 index 00000000..2b8a1b13 --- /dev/null +++ b/install.sh @@ -0,0 +1 @@ +scripts/install.sh \ No newline at end of file diff --git a/scripts/install.sh b/scripts/install.sh index 1e6ae9a9..b20ab111 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # # Beads (bd) installation script -# Usage: curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/install.sh | bash +# Usage: curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash # set -e @@ -59,7 +59,98 @@ detect_platform() { ;; esac - echo "${os}-${arch}" + echo "${os}_${arch}" +} + +# Download and install from GitHub releases +install_from_release() { + log_info "Installing bd from GitHub releases..." + + local platform=$1 + local tmp_dir + tmp_dir=$(mktemp -d) + + # Get latest release version + log_info "Fetching latest release..." + local latest_url="https://api.github.com/repos/steveyegge/beads/releases/latest" + local version + + if command -v curl &> /dev/null; then + version=$(curl -fsSL "$latest_url" | grep '"tag_name"' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/') + elif command -v wget &> /dev/null; then + version=$(wget -qO- "$latest_url" | grep '"tag_name"' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/') + else + log_error "Neither curl nor wget found. Please install one of them." + return 1 + fi + + if [ -z "$version" ]; then + log_error "Failed to fetch latest version" + return 1 + fi + + log_info "Latest version: $version" + + # Download URL + local archive_name="beads_${version#v}_${platform}.tar.gz" + local download_url="https://github.com/steveyegge/beads/releases/download/${version}/${archive_name}" + + log_info "Downloading $archive_name..." + + cd "$tmp_dir" + if command -v curl &> /dev/null; then + if ! curl -fsSL -o "$archive_name" "$download_url"; then + log_error "Download failed" + rm -rf "$tmp_dir" + return 1 + fi + elif command -v wget &> /dev/null; then + if ! wget -q -O "$archive_name" "$download_url"; then + log_error "Download failed" + rm -rf "$tmp_dir" + return 1 + fi + fi + + # Extract archive + log_info "Extracting archive..." + if ! tar -xzf "$archive_name"; then + log_error "Failed to extract archive" + rm -rf "$tmp_dir" + return 1 + fi + + # Determine install location + local install_dir + if [[ -w /usr/local/bin ]]; then + install_dir="/usr/local/bin" + else + install_dir="$HOME/.local/bin" + mkdir -p "$install_dir" + fi + + # Install binary + log_info "Installing to $install_dir..." + if [[ -w "$install_dir" ]]; then + mv bd "$install_dir/" + else + sudo mv bd "$install_dir/" + fi + + log_success "bd installed to $install_dir/bd" + + # Check if install_dir is in PATH + if [[ ":$PATH:" != *":$install_dir:"* ]]; then + log_warning "$install_dir is not in your PATH" + echo "" + echo "Add this to your shell profile (~/.bashrc, ~/.zshrc, etc.):" + echo " export PATH=\"\$PATH:$install_dir\"" + echo "" + fi + + cd - > /dev/null + rm -rf "$tmp_dir" + return 0 } # Check if Go is installed and meets minimum version @@ -89,7 +180,7 @@ check_go() { fi } -# Install using go install +# Install using go install (fallback) install_with_go() { log_info "Installing bd using 'go install'..." @@ -113,7 +204,7 @@ install_with_go() { fi } -# Build from source +# Build from source (last resort) build_from_source() { log_info "Building bd from source..." @@ -171,21 +262,6 @@ build_from_source() { fi } -# Install Go if not present (optional) -offer_go_installation() { - log_warning "Go is not installed" - echo "" - echo "bd requires Go 1.24 or later. You can:" - echo " 1. Install Go from https://go.dev/dl/" - echo " 2. Use your package manager:" - echo " - macOS: brew install go" - echo " - Ubuntu/Debian: sudo apt install golang" - echo " - Other Linux: Check your distro's package manager" - echo "" - echo "After installing Go, run this script again." - exit 1 -} - # Verify installation verify_installation() { if command -v bd &> /dev/null; then @@ -216,7 +292,15 @@ main() { platform=$(detect_platform) log_info "Platform: $platform" - # Try go install first + # Try downloading from GitHub releases first + if install_from_release "$platform"; then + verify_installation + exit 0 + fi + + log_warning "Failed to install from releases, trying alternative methods..." + + # Try go install as fallback if check_go; then if install_with_go; then verify_installation @@ -224,11 +308,21 @@ main() { fi fi - # If go install failed or Go not present, try building from source + # Try building from source as last resort log_warning "Falling back to building from source..." if ! check_go; then - offer_go_installation + log_warning "Go is not installed" + echo "" + echo "bd requires Go 1.24 or later to build from source. You can:" + echo " 1. Install Go from https://go.dev/dl/" + echo " 2. Use your package manager:" + echo " - macOS: brew install go" + echo " - Ubuntu/Debian: sudo apt install golang" + echo " - Other Linux: Check your distro's package manager" + echo "" + echo "After installing Go, run this script again." + exit 1 fi if build_from_source; then @@ -240,6 +334,10 @@ main() { log_error "Installation failed" echo "" echo "Manual installation:" + echo " 1. Download from https://github.com/steveyegge/beads/releases/latest" + echo " 2. Extract and move 'bd' to your PATH" + echo "" + echo "Or install from source:" echo " 1. Install Go from https://go.dev/dl/" echo " 2. Run: go install github.com/steveyegge/beads/cmd/bd@latest" echo ""