mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
The checksums job was downloading all artifacts including Docker build artifacts, but it was only designed to process binary artifacts. This caused failures when the Docker job created artifacts that didn't match the expected soundtouch-* binary file patterns. Changed the artifact download to use pattern: binaries-* to only download the binary artifacts that the checksums generation logic expects.
543 lines
17 KiB
YAML
543 lines
17 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"
|
|
|
|
permissions:
|
|
contents: write
|
|
actions: read
|
|
packages: write
|
|
|
|
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 binaries
|
|
env:
|
|
GOOS: ${{ matrix.goos }}
|
|
GOARCH: ${{ matrix.goarch }}
|
|
GOARM: ${{ matrix.goarm }}
|
|
CGO_ENABLED: 0
|
|
run: |
|
|
# Common variables
|
|
ARCH_SUFFIX="${{ matrix.goos }}-${{ matrix.goarch }}"
|
|
if [[ "${{ matrix.goarm }}" != "" ]]; then
|
|
ARCH_SUFFIX="${ARCH_SUFFIX}v${{ matrix.goarm }}"
|
|
fi
|
|
|
|
# Function to build a binary
|
|
build_binary() {
|
|
local BINARY_NAME=$1
|
|
local CMD_PATH=$2
|
|
local OUTPUT_NAME
|
|
|
|
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 $BINARY_NAME: $OUTPUT_NAME"
|
|
|
|
# Ensure clean build environment for this binary
|
|
rm -f "$OUTPUT_NAME" "$OUTPUT_NAME.sha256" "$OUTPUT_NAME.sha512"
|
|
|
|
if ! go build \
|
|
-ldflags="-s -w" \
|
|
-o "$OUTPUT_NAME" \
|
|
"$CMD_PATH"; then
|
|
echo "❌ Build failed for $BINARY_NAME"
|
|
exit 1
|
|
fi
|
|
|
|
# Verify binary was created
|
|
ls -la "$OUTPUT_NAME"
|
|
echo "$BINARY_NAME=$OUTPUT_NAME" >> $GITHUB_OUTPUT
|
|
}
|
|
|
|
# Build CLI
|
|
build_binary "soundtouch-cli" "./cmd/soundtouch-cli"
|
|
|
|
# Build Service
|
|
build_binary "soundtouch-service" "./cmd/soundtouch-service"
|
|
id: build
|
|
|
|
- name: Generate individual checksums
|
|
run: |
|
|
CLI_NAME="${{ steps.build.outputs.soundtouch-cli }}"
|
|
SVC_NAME="${{ steps.build.outputs.soundtouch-service }}"
|
|
|
|
# Use atomic operations to avoid conflicts
|
|
TEMP_DIR=$(mktemp -d)
|
|
|
|
generate_checksums() {
|
|
local FILE=$1
|
|
echo "Building checksums for: $FILE"
|
|
sha256sum "$FILE" > "${TEMP_DIR}/$(basename "$FILE").sha256"
|
|
sha512sum "$FILE" > "${TEMP_DIR}/$(basename "$FILE").sha512"
|
|
mv "${TEMP_DIR}/$(basename "$FILE").sha256" "$FILE.sha256"
|
|
mv "${TEMP_DIR}/$(basename "$FILE").sha512" "$FILE.sha512"
|
|
}
|
|
|
|
generate_checksums "$CLI_NAME"
|
|
generate_checksums "$SVC_NAME"
|
|
|
|
# Cleanup
|
|
rm -rf "$TEMP_DIR"
|
|
echo "✅ Checksums generated successfully"
|
|
|
|
- name: Upload build artifact
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: binaries-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarm }}
|
|
path: |
|
|
soundtouch-cli-v*
|
|
soundtouch-service-v*
|
|
retention-days: 1
|
|
|
|
checksums:
|
|
name: Generate Checksums
|
|
runs-on: ubuntu-latest
|
|
needs: [validate, build]
|
|
|
|
steps:
|
|
- name: Download binary artifacts
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
pattern: binaries-*
|
|
path: ./binaries
|
|
|
|
- name: Generate checksums
|
|
run: |
|
|
cd binaries
|
|
|
|
# Debug: Show the downloaded structure
|
|
echo "📁 Downloaded artifact structure:"
|
|
ls -R
|
|
|
|
# Create a collection directory to avoid naming conflicts
|
|
mkdir -p release-files
|
|
|
|
# Move all files from subdirectories to the collection directory
|
|
find . -mindepth 2 -type f \( -name "soundtouch-cli-*" -o -name "soundtouch-service-*" \) -exec mv {} release-files/ \;
|
|
|
|
# Remove empty directories
|
|
find . -type d -empty -delete
|
|
|
|
# Move to the collection directory for the rest of the processing
|
|
cd release-files
|
|
|
|
# Debug: Show flattened structure
|
|
echo "📁 Flattened structure:"
|
|
ls -la soundtouch-* || echo "No files found matching pattern"
|
|
|
|
# Generate combined checksums (exclude individual .sha256/.sha512 files)
|
|
if ls soundtouch-* 1> /dev/null 2>&1; then
|
|
# Only checksum the actual binaries, not the .sha256/.sha512 files
|
|
ls soundtouch-* | grep -v '\.sha256$' | grep -v '\.sha512$' | xargs sha256sum > checksums.sha256
|
|
ls soundtouch-* | 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=14 # 7 platforms * 2 binaries
|
|
ACTUAL_COUNT=$(ls soundtouch-* | 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/release-files/checksums.sha256
|
|
binaries/release-files/checksums.sha512
|
|
binaries/release-files/*.sha256
|
|
binaries/release-files/*.sha512
|
|
retention-days: 1
|
|
|
|
- name: Upload all release assets
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: release-assets
|
|
path: binaries/release-files/
|
|
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 & Service Tools
|
|
|
|
Download the tools for your platform from the assets below:
|
|
|
|
### CLI Tool
|
|
\`\`\`bash
|
|
# Quick device discovery
|
|
./soundtouch-cli -discover
|
|
\`\`\`
|
|
|
|
### SoundTouch Service
|
|
\`\`\`bash
|
|
# Start the service
|
|
./soundtouch-service
|
|
\`\`\`
|
|
|
|
## 🧪 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)
|
|
|
|
Both `soundtouch-cli` and `soundtouch-service` are included.
|
|
|
|
## 🔐 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/soundtouch-service-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/soundtouch-service-v*
|
|
release-assets/checksums.sha256
|
|
release-assets/checksums.sha512
|
|
fail_on_unmatched_files: true
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
docker:
|
|
name: Build and Push Docker Image
|
|
runs-on: ubuntu-latest
|
|
needs: validate
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to GitHub Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Extract metadata (tags, labels) for Docker
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ghcr.io/${{ github.repository }}
|
|
tags: |
|
|
type=semver,pattern={{version}},value=v${{ needs.validate.outputs.version }}
|
|
type=semver,pattern={{major}}.{{minor}},value=v${{ needs.validate.outputs.version }}
|
|
type=raw,value=latest,enable=${{ needs.validate.outputs.is_prerelease == 'false' }}
|
|
|
|
- name: Build and push Docker image
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
|
|
notify:
|
|
name: Post-Release Notifications
|
|
runs-on: ubuntu-latest
|
|
needs: [validate, create_release, update_release, docker]
|
|
if: always() && (needs.create_release.result == 'success' || needs.update_release.result == 'success' || needs.docker.result == 'success')
|
|
|
|
steps:
|
|
- name: Notify success
|
|
run: |
|
|
echo "🎉 Release ${{ needs.validate.outputs.version }} completed successfully!"
|
|
echo "📦 Binaries built for 7 platforms (CLI and Service)"
|
|
echo "🐳 Docker image published to ghcr.io"
|
|
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)"
|