Files
Bose-SoundTouch/.github/workflows/release.yml
T
Tobias Gesellchen 1a1d37b885 fix: resolve directory overwrite error in checksums generation
Use find -mindepth 2 to only move files from subdirectories, avoiding
the 'mv: cannot overwrite directory' error when flattening the artifact
directory structure. This ensures only the actual binary and checksum
files are moved, not the directories themselves.

Fixes the sha256sum failure in the Generate Checksums workflow step.
2026-01-10 01:04:49 +01:00

460 lines
15 KiB
YAML

name: Release
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: "Tag to release (e.g., v1.0.0)"
required: true
default: "v1.0.0"
env:
GO_VERSION_FILE: "go.mod"
jobs:
validate:
name: Validate Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Validate tag format
id: version
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG_NAME="${{ github.event.inputs.tag }}"
else
TAG_NAME="${GITHUB_REF#refs/tags/}"
fi
echo "Tag name: $TAG_NAME"
# Validate semantic versioning format
if [[ ! "$TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "❌ Invalid tag format: $TAG_NAME"
echo "Expected format: v1.2.3 or v1.2.3-beta.1"
exit 1
fi
# Extract version without 'v' prefix
VERSION=${TAG_NAME#v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
# Check if prerelease (contains hyphen)
if [[ "$TAG_NAME" =~ - ]]; then
echo "is_prerelease=true" >> $GITHUB_OUTPUT
echo "📦 Prerelease detected: $TAG_NAME"
else
echo "is_prerelease=false" >> $GITHUB_OUTPUT
echo "🚀 Stable release detected: $TAG_NAME"
fi
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: ${{ env.GO_VERSION_FILE }}
- name: Run tests before release
run: |
echo "Running final tests before release..."
go test -v ./...
echo "✅ All tests passed"
build:
name: Build Release Binaries
runs-on: ubuntu-latest
needs: validate
strategy:
matrix:
include:
- goos: linux
goarch: amd64
- goos: linux
goarch: arm64
- goos: linux
goarch: arm
goarm: 7
- goos: darwin
goarch: amd64
- goos: darwin
goarch: arm64
- goos: windows
goarch: amd64
- goos: freebsd
goarch: amd64
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: ${{ env.GO_VERSION_FILE }}
- name: Cache Go modules
uses: actions/cache@v5
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }}
- name: Build binary
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
GOARM: ${{ matrix.goarm }}
CGO_ENABLED: 0
run: |
# Determine output filename
BINARY_NAME="soundtouch-cli"
ARCH_SUFFIX="${{ matrix.goos }}-${{ matrix.goarch }}"
if [[ "${{ matrix.goarm }}" != "" ]]; then
ARCH_SUFFIX="${ARCH_SUFFIX}v${{ matrix.goarm }}"
fi
if [[ "${{ matrix.goos }}" == "windows" ]]; then
OUTPUT_NAME="${BINARY_NAME}-v${{ needs.validate.outputs.version }}-${ARCH_SUFFIX}.exe"
else
OUTPUT_NAME="${BINARY_NAME}-v${{ needs.validate.outputs.version }}-${ARCH_SUFFIX}"
fi
echo "Building: $OUTPUT_NAME"
# Build with optimizations and version info
go build \
-ldflags="-s -w -X main.version=v${{ needs.validate.outputs.version }} -X main.commit=${{ github.sha }} -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o "$OUTPUT_NAME" \
./cmd/soundtouch-cli
# Verify binary was created and is executable
ls -la "$OUTPUT_NAME"
file "$OUTPUT_NAME"
echo "binary_name=$OUTPUT_NAME" >> $GITHUB_OUTPUT
id: build
- name: Generate individual checksum
run: |
OUTPUT_NAME="${{ steps.build.outputs.binary_name }}"
sha256sum "$OUTPUT_NAME" > "$OUTPUT_NAME.sha256"
sha512sum "$OUTPUT_NAME" > "$OUTPUT_NAME.sha512"
echo "📋 Generated individual checksums:"
cat "$OUTPUT_NAME.sha256"
cat "$OUTPUT_NAME.sha512"
- name: Upload build artifact
uses: actions/upload-artifact@v6
with:
name: ${{ steps.build.outputs.binary_name }}
path: |
${{ steps.build.outputs.binary_name }}
${{ steps.build.outputs.binary_name }}.sha256
${{ steps.build.outputs.binary_name }}.sha512
retention-days: 1
checksums:
name: Generate Checksums
runs-on: ubuntu-latest
needs: [validate, build]
steps:
- name: Download all artifacts
uses: actions/download-artifact@v7
with:
path: ./binaries
- name: Generate checksums
run: |
cd binaries
# Debug: Show the downloaded structure
echo "📁 Downloaded artifact structure:"
find . -type f -name "soundtouch-cli-*"
# Flatten directory structure (artifacts are in subdirs)
# Move all binary and checksum files to current directory
find . -mindepth 2 -type f -name "soundtouch-cli-*" -exec mv {} . \;
# Remove empty directories
find . -type d -empty -delete
# Debug: Show flattened structure
echo "📁 Flattened structure:"
ls -la soundtouch-cli-* || echo "No files found matching pattern"
# Generate combined checksums (exclude individual .sha256/.sha512 files)
if ls soundtouch-cli-v* 1> /dev/null 2>&1; then
# Only checksum the actual binaries, not the .sha256/.sha512 files
ls soundtouch-cli-v* | grep -v '\.sha256$' | grep -v '\.sha512$' | xargs sha256sum > checksums.sha256
ls soundtouch-cli-v* | grep -v '\.sha256$' | grep -v '\.sha512$' | xargs sha512sum > checksums.sha512
echo "📋 Generated combined checksums:"
cat checksums.sha256
# Verify all expected files are present (binaries only, not checksum files)
EXPECTED_COUNT=7 # Based on build matrix
ACTUAL_COUNT=$(ls soundtouch-cli-v* | grep -v '\.sha256$' | grep -v '\.sha512$' | wc -l)
if [[ $ACTUAL_COUNT -ne $EXPECTED_COUNT ]]; then
echo "❌ Expected $EXPECTED_COUNT binaries, found $ACTUAL_COUNT"
ls -la
exit 1
fi
echo "✅ All $ACTUAL_COUNT binaries present"
else
echo "❌ No binary files found"
echo "Directory contents:"
ls -la
exit 1
fi
- name: Upload checksums
uses: actions/upload-artifact@v6
with:
name: checksums
path: |
binaries/checksums.sha256
binaries/checksums.sha512
binaries/*.sha256
binaries/*.sha512
retention-days: 1
- name: Upload all release assets
uses: actions/upload-artifact@v6
with:
name: release-assets
path: binaries/
retention-days: 1
create_release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [validate, checksums]
if: github.event_name == 'workflow_dispatch'
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Download release assets
uses: actions/download-artifact@v7
with:
name: release-assets
path: ./release-assets
- name: Generate release notes
id: release_notes
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG_NAME="${{ github.event.inputs.tag }}"
else
TAG_NAME="${{ github.event.release.tag_name }}"
fi
VERSION="${TAG_NAME#v}"
# Generate comprehensive release notes
cat > release_notes.md << EOF
# Bose SoundTouch Go Library $TAG_NAME
A comprehensive Go library for controlling Bose SoundTouch speakers with 100% API coverage, real-time WebSocket events, and production-ready features.
## 🎯 Key Features
- **100% API Coverage**: All 19 official endpoints + 6 useful extensions (25 total)
- **Real-time Events**: WebSocket support with auto-reconnect and comprehensive event handling
- **Multiroom Control**: Complete zone management and coordination
- **Production Ready**: Connection pooling, error handling, circuit breakers, monitoring
- **Excellent Documentation**: 4000+ lines including Getting Started, Cookbook, Troubleshooting, and Deployment guides
- **CLI Tool**: Full-featured command-line interface with all endpoints
## 🚀 Quick Start
\`\`\`bash
go get github.com/gesellix/bose-soundtouch@$TAG_NAME
\`\`\`
\`\`\`go
package main
import (
"fmt"
"log"
"github.com/gesellix/bose-soundtouch/pkg/client"
)
func main() {
// Create client
c := client.New("192.168.1.100", 8090)
// Get device info
info, err := c.GetInfo()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Device: %s\\n", info.Name)
}
\`\`\`
## 📚 Documentation
- [Getting Started Guide](docs/GETTING-STARTED.md) - 10-minute tutorial from discovery to WebSocket monitoring
- [API Cookbook](docs/API-COOKBOOK.md) - 1000+ lines of real-world patterns and examples
- [Troubleshooting Guide](docs/TROUBLESHOOTING.md) - Systematic issue resolution
- [Deployment Guide](docs/DEPLOYMENT.md) - Production deployment examples (Docker, K8s, systemd)
## 🔧 CLI Tool
Download the CLI tool for your platform from the assets below:
\`\`\`bash
# Quick device discovery
./soundtouch-cli -discover
# Get device information
./soundtouch-cli -host 192.168.1.100 -info
# Monitor real-time events
./soundtouch-cli -host 192.168.1.100 -nowplaying
\`\`\`
## 🧪 Tested Hardware
- Bose SoundTouch 10
- Bose SoundTouch 20
- All core functionality validated on real devices
## 📈 What's New in $TAG_NAME
$(git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 HEAD^)..HEAD 2>/dev/null || echo "- Initial release with complete feature set")
## 🏗️ Supported Platforms
This release includes pre-built binaries for:
- Linux (amd64, arm64, armv7)
- macOS (Intel & Apple Silicon)
- Windows (amd64)
- FreeBSD (amd64)
## 🔐 Checksums
Multiple checksum options are provided for download verification:
### Combined Checksums (Recommended)
- \`checksums.sha256\` - SHA256 checksums for all binaries
- \`checksums.sha512\` - SHA512 checksums for all binaries
\`\`\`bash
# Download any binary + combined checksums
curl -L -O https://github.com/.../soundtouch-cli-v$TAG_NAME-linux-amd64
curl -L -O https://github.com/.../checksums.sha256
# Verify your specific download
sha256sum -c checksums.sha256 --ignore-missing
\`\`\`
### Individual Checksums (Per Binary)
Each binary also has its own dedicated checksum files:
- \`soundtouch-cli-v$TAG_NAME-platform.sha256\`
- \`soundtouch-cli-v$TAG_NAME-platform.sha512\`
\`\`\`bash
# Download binary + its individual checksum
curl -L -O https://github.com/.../soundtouch-cli-v$TAG_NAME-linux-amd64
curl -L -O https://github.com/.../soundtouch-cli-v$TAG_NAME-linux-amd64.sha256
# Verify with individual checksum
sha256sum -c soundtouch-cli-v$TAG_NAME-linux-amd64.sha256
\`\`\`
## 🤝 Contributing
Contributions welcome! See our documentation for examples and patterns.
## 📄 License
MIT License - see [LICENSE](LICENSE) file.
EOF
echo "release_notes_file=release_notes.md" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event.inputs.tag }}
name: "Bose SoundTouch Go Library ${{ github.event.inputs.tag }}"
body_path: ${{ steps.release_notes.outputs.release_notes_file }}
draft: false
prerelease: ${{ needs.validate.outputs.is_prerelease == 'true' }}
files: |
release-assets/soundtouch-cli-v*
release-assets/checksums.sha256
release-assets/checksums.sha512
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
update_release:
name: Update Existing Release
runs-on: ubuntu-latest
needs: [validate, checksums]
if: github.event_name == 'release' && github.event.action == 'published'
steps:
- name: Download release assets
uses: actions/download-artifact@v7
with:
name: release-assets
path: ./release-assets
- name: Upload additional assets to existing release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event.release.tag_name }}
files: |
release-assets/soundtouch-cli-v*
release-assets/checksums.sha256
release-assets/checksums.sha512
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
notify:
name: Post-Release Notifications
runs-on: ubuntu-latest
needs: [validate, create_release, update_release]
if: always() && (needs.create_release.result == 'success' || needs.update_release.result == 'success')
steps:
- name: Notify success
run: |
echo "🎉 Release ${{ needs.validate.outputs.version }} completed successfully!"
echo "📦 Binaries built for 7 platforms"
echo "🔐 Checksums generated and verified"
echo "📋 Release notes automatically generated"
echo ""
TAG_NAME="${{ github.event.inputs.tag || github.event.release.tag_name }}"
echo "🔗 Release URL: https://github.com/${{ github.repository }}/releases/tag/${TAG_NAME}"
echo ""
echo "Next steps:"
echo "- Monitor download metrics"
echo "- Update documentation if needed"
echo "- Announce to community (see scripts/post-release.md)"