mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
refactor: Use Go version from go.mod in workflows
- Remove Go version matrix from CI workflow - Use go-version-file option to read from go.mod - Update cache keys to use go.mod hash - Ensure single source of truth for Go version - Simplify maintenance by centralizing version management
This commit is contained in:
+167
-171
@@ -2,74 +2,70 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: ['1.21', '1.22', '1.23']
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-${{ matrix.go-version }}-
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Verify dependencies
|
||||
run: go mod verify
|
||||
- name: Verify dependencies
|
||||
run: go mod verify
|
||||
|
||||
- name: Run tests
|
||||
run: go test -v -race -coverprofile=coverage.out ./...
|
||||
- name: Run tests
|
||||
run: go test -v -race -coverprofile=coverage.out ./...
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
if: matrix.go-version == '1.23'
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
file: ./coverage.out
|
||||
flags: unittests
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
file: ./coverage.out
|
||||
flags: unittests
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v4
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout=5m
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v4
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout=5m
|
||||
|
||||
build:
|
||||
name: Build
|
||||
@@ -84,89 +80,89 @@ jobs:
|
||||
goarch: arm64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Build CLI
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
run: |
|
||||
output_name="soundtouch-cli-${{ matrix.goos }}-${{ matrix.goarch }}"
|
||||
if [ "${{ matrix.goos }}" = "windows" ]; then
|
||||
output_name="${output_name}.exe"
|
||||
fi
|
||||
go build -o "$output_name" ./cmd/soundtouch-cli
|
||||
- name: Build CLI
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
run: |
|
||||
output_name="soundtouch-cli-${{ matrix.goos }}-${{ matrix.goarch }}"
|
||||
if [ "${{ matrix.goos }}" = "windows" ]; then
|
||||
output_name="${output_name}.exe"
|
||||
fi
|
||||
go build -o "$output_name" ./cmd/soundtouch-cli
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: soundtouch-cli-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
path: soundtouch-cli-*
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: soundtouch-cli-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
path: soundtouch-cli-*
|
||||
|
||||
security:
|
||||
name: Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Run Gosec Security Scanner
|
||||
uses: securecodewarrior/github-action-gosec@master
|
||||
with:
|
||||
args: ./...
|
||||
- name: Run Gosec Security Scanner
|
||||
uses: securecodewarrior/github-action-gosec@master
|
||||
with:
|
||||
args: ./...
|
||||
|
||||
- name: Run Nancy vulnerability scanner
|
||||
run: |
|
||||
go install github.com/sonatypecommunity/nancy@latest
|
||||
go list -json -deps ./... | nancy sleuth
|
||||
- name: Run Nancy vulnerability scanner
|
||||
run: |
|
||||
go install github.com/sonatypecommunity/nancy@latest
|
||||
go list -json -deps ./... | nancy sleuth
|
||||
|
||||
docs:
|
||||
name: Documentation Check
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check documentation links
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@v1
|
||||
with:
|
||||
use-quiet-mode: 'yes'
|
||||
use-verbose-mode: 'yes'
|
||||
config-file: '.github/markdown-link-check.json'
|
||||
- name: Check documentation links
|
||||
uses: gaurav-nelson/github-action-markdown-link-check@v1
|
||||
with:
|
||||
use-quiet-mode: "yes"
|
||||
use-verbose-mode: "yes"
|
||||
config-file: ".github/markdown-link-check.json"
|
||||
|
||||
- name: Validate API documentation
|
||||
run: |
|
||||
# Check that all documented endpoints exist in code
|
||||
echo "Validating API documentation consistency..."
|
||||
- name: Validate API documentation
|
||||
run: |
|
||||
# Check that all documented endpoints exist in code
|
||||
echo "Validating API documentation consistency..."
|
||||
|
||||
# Extract endpoint patterns from cookbook
|
||||
if [ -f "docs/API-COOKBOOK.md" ]; then
|
||||
echo "✓ API Cookbook exists"
|
||||
else
|
||||
echo "✗ API Cookbook missing"
|
||||
exit 1
|
||||
fi
|
||||
# Extract endpoint patterns from cookbook
|
||||
if [ -f "docs/API-COOKBOOK.md" ]; then
|
||||
echo "✓ API Cookbook exists"
|
||||
else
|
||||
echo "✗ API Cookbook missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check getting started guide
|
||||
if [ -f "docs/GETTING-STARTED.md" ]; then
|
||||
echo "✓ Getting Started guide exists"
|
||||
else
|
||||
echo "✗ Getting Started guide missing"
|
||||
exit 1
|
||||
fi
|
||||
# Check getting started guide
|
||||
if [ -f "docs/GETTING-STARTED.md" ]; then
|
||||
echo "✓ Getting Started guide exists"
|
||||
else
|
||||
echo "✗ Getting Started guide missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
integration:
|
||||
name: Integration Test
|
||||
@@ -174,50 +170,50 @@ jobs:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Test CLI build and help
|
||||
run: |
|
||||
go build -o soundtouch-cli ./cmd/soundtouch-cli
|
||||
./soundtouch-cli -help
|
||||
- name: Test CLI build and help
|
||||
run: |
|
||||
go build -o soundtouch-cli ./cmd/soundtouch-cli
|
||||
./soundtouch-cli -help
|
||||
|
||||
- name: Test library imports
|
||||
run: |
|
||||
cat > test_import.go << 'EOF'
|
||||
package main
|
||||
- name: Test library imports
|
||||
run: |
|
||||
cat > test_import.go << 'EOF'
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/user_account/bose-soundtouch/pkg/client"
|
||||
"github.com/user_account/bose-soundtouch/pkg/models"
|
||||
"github.com/user_account/bose-soundtouch/pkg/discovery"
|
||||
)
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/user_account/bose-soundtouch/pkg/client"
|
||||
"github.com/user_account/bose-soundtouch/pkg/models"
|
||||
"github.com/user_account/bose-soundtouch/pkg/discovery"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Test basic client creation
|
||||
c := client.New("192.168.1.100", 8090)
|
||||
fmt.Printf("Client created for %s\n", c.BaseURL())
|
||||
func main() {
|
||||
// Test basic client creation
|
||||
c := client.New("192.168.1.100", 8090)
|
||||
fmt.Printf("Client created for %s\n", c.BaseURL())
|
||||
|
||||
// Test models can be imported
|
||||
var info models.Info
|
||||
fmt.Printf("Info model available: %T\n", info)
|
||||
// Test models can be imported
|
||||
var info models.Info
|
||||
fmt.Printf("Info model available: %T\n", info)
|
||||
|
||||
// Test discovery can be imported
|
||||
var scanner discovery.Scanner
|
||||
fmt.Printf("Scanner available: %T\n", scanner)
|
||||
// Test discovery can be imported
|
||||
var scanner discovery.Scanner
|
||||
fmt.Printf("Scanner available: %T\n", scanner)
|
||||
|
||||
fmt.Println("All imports successful!")
|
||||
}
|
||||
EOF
|
||||
fmt.Println("All imports successful!")
|
||||
}
|
||||
EOF
|
||||
|
||||
go run test_import.go
|
||||
rm test_import.go
|
||||
go run test_import.go
|
||||
rm test_import.go
|
||||
|
||||
notify:
|
||||
name: Notify Status
|
||||
@@ -226,35 +222,35 @@ jobs:
|
||||
if: always()
|
||||
|
||||
steps:
|
||||
- name: Check overall status
|
||||
run: |
|
||||
if [[ "${{ needs.test.result }}" == "success" && \
|
||||
"${{ needs.lint.result }}" == "success" && \
|
||||
"${{ needs.build.result }}" == "success" && \
|
||||
"${{ needs.security.result }}" == "success" && \
|
||||
"${{ needs.docs.result }}" == "success" ]]; then
|
||||
echo "✅ All CI checks passed!"
|
||||
echo "status=success" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "❌ Some CI checks failed"
|
||||
echo "status=failure" >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
fi
|
||||
id: status
|
||||
- name: Check overall status
|
||||
run: |
|
||||
if [[ "${{ needs.test.result }}" == "success" && \
|
||||
"${{ needs.lint.result }}" == "success" && \
|
||||
"${{ needs.build.result }}" == "success" && \
|
||||
"${{ needs.security.result }}" == "success" && \
|
||||
"${{ needs.docs.result }}" == "success" ]]; then
|
||||
echo "✅ All CI checks passed!"
|
||||
echo "status=success" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "❌ Some CI checks failed"
|
||||
echo "status=failure" >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
fi
|
||||
id: status
|
||||
|
||||
- name: Update commit status
|
||||
if: always()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const state = '${{ steps.status.outputs.status }}' === 'success' ? 'success' : 'failure';
|
||||
const description = state === 'success' ? 'All checks passed' : 'Some checks failed';
|
||||
- name: Update commit status
|
||||
if: always()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const state = '${{ steps.status.outputs.status }}' === 'success' ? 'success' : 'failure';
|
||||
const description = state === 'success' ? 'All checks passed' : 'Some checks failed';
|
||||
|
||||
github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: context.sha,
|
||||
state: state,
|
||||
description: description,
|
||||
context: 'CI Pipeline'
|
||||
});
|
||||
github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: context.sha,
|
||||
state: state,
|
||||
description: description,
|
||||
context: 'CI Pipeline'
|
||||
});
|
||||
|
||||
+257
-257
@@ -3,18 +3,18 @@ name: Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- "v*"
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Tag to release (e.g., v1.0.0)'
|
||||
description: "Tag to release (e.g., v1.0.0)"
|
||||
required: true
|
||||
default: 'v1.0.0'
|
||||
default: "v1.0.0"
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23'
|
||||
GO_VERSION_FILE: "go.mod"
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
@@ -25,52 +25,52 @@ jobs:
|
||||
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
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
|
||||
- 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"
|
||||
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
|
||||
# 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
|
||||
# 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
|
||||
# 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@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
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"
|
||||
- name: Run tests before release
|
||||
run: |
|
||||
echo "Running final tests before release..."
|
||||
go test -v ./...
|
||||
echo "✅ All tests passed"
|
||||
|
||||
build:
|
||||
name: Build Release Binaries
|
||||
@@ -96,64 +96,64 @@ jobs:
|
||||
goarch: amd64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: ${{ env.GO_VERSION_FILE }}
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
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 }}"
|
||||
- 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.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
|
||||
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"
|
||||
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
|
||||
# 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"
|
||||
# Verify binary was created and is executable
|
||||
ls -la "$OUTPUT_NAME"
|
||||
file "$OUTPUT_NAME"
|
||||
|
||||
echo "binary_name=$OUTPUT_NAME" >> $GITHUB_OUTPUT
|
||||
id: build
|
||||
echo "binary_name=$OUTPUT_NAME" >> $GITHUB_OUTPUT
|
||||
id: build
|
||||
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.build.outputs.binary_name }}
|
||||
path: ${{ steps.build.outputs.binary_name }}
|
||||
retention-days: 1
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.build.outputs.binary_name }}
|
||||
path: ${{ steps.build.outputs.binary_name }}
|
||||
retention-days: 1
|
||||
|
||||
checksums:
|
||||
name: Generate Checksums
|
||||
@@ -161,57 +161,57 @@ jobs:
|
||||
needs: [validate, build]
|
||||
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./binaries
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./binaries
|
||||
|
||||
- name: Generate checksums
|
||||
run: |
|
||||
cd binaries
|
||||
- name: Generate checksums
|
||||
run: |
|
||||
cd binaries
|
||||
|
||||
# Flatten directory structure (artifacts are in subdirs)
|
||||
find . -name "soundtouch-cli-*" -exec mv {} . \;
|
||||
# Flatten directory structure (artifacts are in subdirs)
|
||||
find . -name "soundtouch-cli-*" -exec mv {} . \;
|
||||
|
||||
# Remove empty directories
|
||||
find . -type d -empty -delete
|
||||
# Remove empty directories
|
||||
find . -type d -empty -delete
|
||||
|
||||
# Generate SHA256 checksums
|
||||
sha256sum soundtouch-cli-* > checksums.sha256
|
||||
# Generate SHA256 checksums
|
||||
sha256sum soundtouch-cli-* > checksums.sha256
|
||||
|
||||
# Generate SHA512 checksums
|
||||
sha512sum soundtouch-cli-* > checksums.sha512
|
||||
# Generate SHA512 checksums
|
||||
sha512sum soundtouch-cli-* > checksums.sha512
|
||||
|
||||
echo "📋 Generated checksums:"
|
||||
cat checksums.sha256
|
||||
echo "📋 Generated checksums:"
|
||||
cat checksums.sha256
|
||||
|
||||
# Verify all expected files are present
|
||||
EXPECTED_COUNT=7 # Based on build matrix
|
||||
ACTUAL_COUNT=$(ls soundtouch-cli-* | wc -l)
|
||||
# Verify all expected files are present
|
||||
EXPECTED_COUNT=7 # Based on build matrix
|
||||
ACTUAL_COUNT=$(ls soundtouch-cli-* | wc -l)
|
||||
|
||||
if [[ $ACTUAL_COUNT -ne $EXPECTED_COUNT ]]; then
|
||||
echo "❌ Expected $EXPECTED_COUNT binaries, found $ACTUAL_COUNT"
|
||||
ls -la
|
||||
exit 1
|
||||
fi
|
||||
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"
|
||||
echo "✅ All $ACTUAL_COUNT binaries present"
|
||||
|
||||
- name: Upload checksums
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: checksums
|
||||
path: |
|
||||
binaries/checksums.sha256
|
||||
binaries/checksums.sha512
|
||||
retention-days: 1
|
||||
- name: Upload checksums
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: checksums
|
||||
path: |
|
||||
binaries/checksums.sha256
|
||||
binaries/checksums.sha512
|
||||
retention-days: 1
|
||||
|
||||
- name: Upload all release assets
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-assets
|
||||
path: binaries/
|
||||
retention-days: 1
|
||||
- name: Upload all release assets
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-assets
|
||||
path: binaries/
|
||||
retention-days: 1
|
||||
|
||||
create_release:
|
||||
name: Create GitHub Release
|
||||
@@ -220,138 +220,138 @@ jobs:
|
||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download release assets
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-assets
|
||||
path: ./release-assets
|
||||
- name: Download release assets
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-assets
|
||||
path: ./release-assets
|
||||
|
||||
- name: Generate release notes
|
||||
id: release_notes
|
||||
run: |
|
||||
TAG_NAME="${GITHUB_REF#refs/tags/}"
|
||||
VERSION="${TAG_NAME#v}"
|
||||
- name: Generate release notes
|
||||
id: release_notes
|
||||
run: |
|
||||
TAG_NAME="${GITHUB_REF#refs/tags/}"
|
||||
VERSION="${TAG_NAME#v}"
|
||||
|
||||
# Generate comprehensive release notes
|
||||
cat > release_notes.md << EOF
|
||||
# Bose SoundTouch Go Library $TAG_NAME
|
||||
# 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.
|
||||
A comprehensive Go library for controlling Bose SoundTouch speakers with 100% API coverage, real-time WebSocket events, and production-ready features.
|
||||
|
||||
## 🎯 Key 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
|
||||
- **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
|
||||
## 🚀 Quick Start
|
||||
|
||||
\`\`\`bash
|
||||
go get github.com/user_account/bose-soundtouch@$TAG_NAME
|
||||
\`\`\`
|
||||
\`\`\`bash
|
||||
go get github.com/user_account/bose-soundtouch@$TAG_NAME
|
||||
\`\`\`
|
||||
|
||||
\`\`\`go
|
||||
package main
|
||||
\`\`\`go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/user_account/bose-soundtouch/pkg/client"
|
||||
)
|
||||
"github.com/user_account/bose-soundtouch/pkg/client"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create client
|
||||
c := client.New("192.168.1.100", 8090)
|
||||
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)
|
||||
}
|
||||
// Get device info
|
||||
info, err := c.GetInfo()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Device: %s\\n", info.Name)
|
||||
}
|
||||
\`\`\`
|
||||
fmt.Printf("Device: %s\\n", info.Name)
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## 📚 Documentation
|
||||
## 📚 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)
|
||||
- [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
|
||||
## 🔧 CLI Tool
|
||||
|
||||
Download the CLI tool for your platform from the assets below:
|
||||
Download the CLI tool for your platform from the assets below:
|
||||
|
||||
\`\`\`bash
|
||||
# Quick device discovery
|
||||
./soundtouch-cli -discover
|
||||
\`\`\`bash
|
||||
# Quick device discovery
|
||||
./soundtouch-cli -discover
|
||||
|
||||
# Get device information
|
||||
./soundtouch-cli -host 192.168.1.100 -info
|
||||
# Get device information
|
||||
./soundtouch-cli -host 192.168.1.100 -info
|
||||
|
||||
# Monitor real-time events
|
||||
./soundtouch-cli -host 192.168.1.100 -nowplaying
|
||||
\`\`\`
|
||||
# Monitor real-time events
|
||||
./soundtouch-cli -host 192.168.1.100 -nowplaying
|
||||
\`\`\`
|
||||
|
||||
## 🧪 Tested Hardware
|
||||
## 🧪 Tested Hardware
|
||||
|
||||
- Bose SoundTouch 10
|
||||
- Bose SoundTouch 20
|
||||
- All core functionality validated on real devices
|
||||
- Bose SoundTouch 10
|
||||
- Bose SoundTouch 20
|
||||
- All core functionality validated on real devices
|
||||
|
||||
## 📈 What's New in $TAG_NAME
|
||||
## 📈 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")
|
||||
$(git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 HEAD^)..HEAD 2>/dev/null || echo "- Initial release with complete feature set")
|
||||
|
||||
## 🏗️ Supported Platforms
|
||||
## 🏗️ Supported Platforms
|
||||
|
||||
This release includes pre-built binaries for:
|
||||
- Linux (amd64, arm64, armv7)
|
||||
- macOS (Intel & Apple Silicon)
|
||||
- Windows (amd64)
|
||||
- FreeBSD (amd64)
|
||||
This release includes pre-built binaries for:
|
||||
- Linux (amd64, arm64, armv7)
|
||||
- macOS (Intel & Apple Silicon)
|
||||
- Windows (amd64)
|
||||
- FreeBSD (amd64)
|
||||
|
||||
## 🔐 Checksums
|
||||
## 🔐 Checksums
|
||||
|
||||
SHA256 checksums are provided in \`checksums.sha256\` to verify download integrity.
|
||||
SHA256 checksums are provided in \`checksums.sha256\` to verify download integrity.
|
||||
|
||||
## 🤝 Contributing
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions welcome! See our documentation for examples and patterns.
|
||||
Contributions welcome! See our documentation for examples and patterns.
|
||||
|
||||
## 📄 License
|
||||
## 📄 License
|
||||
|
||||
MIT License - see [LICENSE](LICENSE) file.
|
||||
EOF
|
||||
MIT License - see [LICENSE](LICENSE) file.
|
||||
EOF
|
||||
|
||||
echo "release_notes_file=release_notes.md" >> $GITHUB_OUTPUT
|
||||
echo "release_notes_file=release_notes.md" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: "Bose SoundTouch Go Library ${{ github.ref_name }}"
|
||||
body_path: ${{ steps.release_notes.outputs.release_notes_file }}
|
||||
draft: false
|
||||
prerelease: ${{ needs.validate.outputs.is_prerelease == 'true' }}
|
||||
files: |
|
||||
release-assets/soundtouch-cli-*
|
||||
release-assets/checksums.sha256
|
||||
release-assets/checksums.sha512
|
||||
fail_on_unmatched_files: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: "Bose SoundTouch Go Library ${{ github.ref_name }}"
|
||||
body_path: ${{ steps.release_notes.outputs.release_notes_file }}
|
||||
draft: false
|
||||
prerelease: ${{ needs.validate.outputs.is_prerelease == 'true' }}
|
||||
files: |
|
||||
release-assets/soundtouch-cli-*
|
||||
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
|
||||
@@ -360,23 +360,23 @@ jobs:
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
|
||||
steps:
|
||||
- name: Download release assets
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-assets
|
||||
path: ./release-assets
|
||||
- name: Download release assets
|
||||
uses: actions/download-artifact@v4
|
||||
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-*
|
||||
release-assets/checksums.sha256
|
||||
release-assets/checksums.sha512
|
||||
fail_on_unmatched_files: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- 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-*
|
||||
release-assets/checksums.sha256
|
||||
release-assets/checksums.sha512
|
||||
fail_on_unmatched_files: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
notify:
|
||||
name: Post-Release Notifications
|
||||
@@ -385,16 +385,16 @@ jobs:
|
||||
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 ""
|
||||
echo "🔗 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "- Monitor download metrics"
|
||||
echo "- Update documentation if needed"
|
||||
echo "- Announce to community (see scripts/post-release.md)"
|
||||
- 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 ""
|
||||
echo "🔗 Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "- Monitor download metrics"
|
||||
echo "- Update documentation if needed"
|
||||
echo "- Announce to community (see scripts/post-release.md)"
|
||||
|
||||
Reference in New Issue
Block a user