feat: Add comprehensive CI/CD pipeline with GitHub Actions

- Add CI workflow with multi-version Go testing, linting, security scans
- Add automated release workflow triggered on tag push
- Include Dependabot for dependency management
- Add professional issue templates for bugs and features
- Configure golangci-lint with production-ready settings
- Update local release script to complement automation
- Support cross-platform builds for 7 platforms
- Automated release notes and checksum generation
This commit is contained in:
Tobias Gesellchen
2026-01-09 12:58:35 +01:00
parent 8b3f759dc4
commit b6adf51767
9 changed files with 1748 additions and 13 deletions
+201
View File
@@ -0,0 +1,201 @@
name: Bug Report
description: File a bug report to help us improve the library
title: "[Bug]: "
labels: ["bug", "triage"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please provide as much detail as possible to help us diagnose and fix the issue.
- type: input
id: version
attributes:
label: Library Version
description: What version of the library are you using?
placeholder: "v1.0.0"
validations:
required: true
- type: dropdown
id: go-version
attributes:
label: Go Version
description: What version of Go are you using?
options:
- "1.23"
- "1.22"
- "1.21"
- "1.20"
- "Other (please specify in description)"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: Operating System
description: What operating system are you running on?
options:
- "Linux"
- "macOS"
- "Windows"
- "FreeBSD"
- "Other (please specify in description)"
validations:
required: true
- type: input
id: device-model
attributes:
label: Bose Device Model
description: What Bose SoundTouch device are you trying to control?
placeholder: "SoundTouch 10, SoundTouch 20, etc."
validations:
required: true
- type: input
id: device-firmware
attributes:
label: Device Firmware Version
description: What firmware version is your device running? (Check in Bose app or via /info endpoint)
placeholder: "4.8.1.4567.891234567"
- type: textarea
id: description
attributes:
label: Bug Description
description: A clear and concise description of what the bug is.
placeholder: "Describe what happened and what you expected to happen..."
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Steps to Reproduce
description: Steps to reproduce the behavior
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
placeholder: "What should have happened instead?"
validations:
required: true
- type: textarea
id: code-sample
attributes:
label: Code Sample
description: Please provide a minimal code sample that reproduces the issue
render: go
placeholder: |
package main
import (
"fmt"
"github.com/user_account/bose-soundtouch/pkg/client"
)
func main() {
// Your code that demonstrates the issue
}
validations:
required: false
- type: textarea
id: logs
attributes:
label: Error Messages / Logs
description: Please include any relevant error messages, stack traces, or log output
render: shell
placeholder: |
Error: connection refused
at github.com/user_account/bose-soundtouch/pkg/client.(*Client).makeRequest
...
validations:
required: false
- type: dropdown
id: component
attributes:
label: Component
description: Which component is affected?
multiple: true
options:
- "Client Library (pkg/client)"
- "WebSocket Events"
- "Device Discovery"
- "CLI Tool"
- "Models/XML Parsing"
- "Documentation"
- "Examples"
- "Build/Release"
validations:
required: false
- type: dropdown
id: severity
attributes:
label: Severity
description: How severe is this bug?
options:
- "Low - Minor inconvenience"
- "Medium - Affects functionality but workaround exists"
- "High - Blocks major functionality"
- "Critical - Application crashes or data loss"
validations:
required: true
- type: textarea
id: network-info
attributes:
label: Network Configuration
description: Details about your network setup (if relevant to the issue)
placeholder: |
- Device IP: 192.168.1.100
- Network type: WiFi/Ethernet
- Router model:
- Any firewalls or network restrictions:
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context about the problem here
placeholder: "Screenshots, network traces, related issues, etc."
validations:
required: false
- type: checkboxes
id: troubleshooting
attributes:
label: Troubleshooting Steps
description: Have you tried these troubleshooting steps?
options:
- label: "I have checked the [Troubleshooting Guide](docs/TROUBLESHOOTING.md)"
- label: "I have verified my device is reachable (ping test)"
- label: "I have tested with the CLI tool"
- label: "I have checked for similar existing issues"
- label: "I am using the latest version of the library"
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our Code of Conduct
options:
- label: "I agree to follow this project's Code of Conduct"
required: true
+205
View File
@@ -0,0 +1,205 @@
name: Feature Request
description: Suggest an idea or enhancement for this project
title: "[Feature]: "
labels: ["enhancement", "triage"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a new feature! Please provide as much detail as possible to help us understand your request and its potential impact.
- type: input
id: version
attributes:
label: Library Version
description: What version of the library are you currently using?
placeholder: "v1.0.0"
validations:
required: true
- type: textarea
id: problem
attributes:
label: Problem Description
description: Is your feature request related to a problem? Please describe what you're trying to accomplish.
placeholder: "I'm always frustrated when... / I need to be able to... / Currently it's not possible to..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: Describe the solution you'd like to see implemented.
placeholder: "I would like to see... / A new function that... / An option to..."
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Describe any alternative solutions or features you've considered.
placeholder: "I considered... / Another approach could be... / Workaround I'm currently using..."
validations:
required: false
- type: dropdown
id: component
attributes:
label: Component
description: Which component would this feature affect?
multiple: true
options:
- "Client Library (pkg/client)"
- "WebSocket Events"
- "Device Discovery"
- "CLI Tool"
- "Models/XML Parsing"
- "Documentation"
- "Examples"
- "New API Endpoint"
- "Performance Optimization"
- "Developer Experience"
validations:
required: true
- type: dropdown
id: device-compatibility
attributes:
label: Device Compatibility
description: Which Bose SoundTouch devices should this feature support?
multiple: true
options:
- "All SoundTouch devices"
- "SoundTouch 10"
- "SoundTouch 20"
- "SoundTouch 30"
- "SoundTouch Portable"
- "SoundTouch Wave"
- "Other (specify in description)"
validations:
required: false
- type: dropdown
id: priority
attributes:
label: Priority
description: How important is this feature to you?
options:
- "Low - Nice to have"
- "Medium - Would improve my workflow"
- "High - Important for my use case"
- "Critical - Blocking my project"
validations:
required: true
- type: dropdown
id: api-type
attributes:
label: API Type (if applicable)
description: What type of API enhancement is this?
options:
- "Not applicable"
- "New Bose SoundTouch endpoint"
- "Enhancement to existing endpoint"
- "Client library improvement"
- "WebSocket event enhancement"
- "Discovery enhancement"
- "CLI command addition"
validations:
required: false
- type: textarea
id: use-case
attributes:
label: Use Case / User Story
description: Describe your specific use case or user story
placeholder: |
As a [type of user], I want to [goal] so that [benefit].
Example: As a home automation developer, I want to create custom zones so that I can group speakers dynamically based on user preferences.
validations:
required: true
- type: textarea
id: example-api
attributes:
label: Desired API Example
description: Show how you'd like the API to work (if applicable)
render: go
placeholder: |
// Example of how you envision using this feature
client := soundtouch.New("192.168.1.100", 8090)
// Your desired API call
result, err := client.NewFeature(options)
if err != nil {
// handle error
}
// Use the result
fmt.Println(result)
validations:
required: false
- type: textarea
id: technical-details
attributes:
label: Technical Details
description: Any technical considerations, constraints, or implementation ideas?
placeholder: |
- Should this be backward compatible?
- Any performance considerations?
- Integration with existing features?
- External dependencies needed?
validations:
required: false
- type: checkboxes
id: implementation
attributes:
label: Implementation
description: Are you willing to help implement this feature?
options:
- label: "I can help implement this feature"
- label: "I can provide testing/feedback"
- label: "I can help with documentation"
- label: "I need someone else to implement this"
- type: textarea
id: research
attributes:
label: Research & References
description: Have you found any relevant resources, similar implementations, or Bose documentation?
placeholder: |
- Links to relevant documentation
- Similar features in other libraries
- Bose SoundTouch API references
- Related GitHub issues or discussions
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Checklist
description: Please confirm the following
options:
- label: "I have searched for existing issues and feature requests"
required: true
- label: "I have checked the [API Cookbook](docs/API-COOKBOOK.md) for existing functionality"
required: true
- label: "This feature is related to Bose SoundTouch functionality"
required: true
- label: "I have considered backward compatibility"
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this feature request, you agree to follow our Code of Conduct
options:
- label: "I agree to follow this project's Code of Conduct"
required: true
+135
View File
@@ -0,0 +1,135 @@
# Dependabot configuration for Bose SoundTouch Go Library
# See: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
# Go modules dependency updates
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "09:00"
timezone: "UTC"
open-pull-requests-limit: 5
reviewers:
- "user_account"
assignees:
- "user_account"
commit-message:
prefix: "deps"
prefix-development: "deps-dev"
include: "scope"
labels:
- "dependencies"
- "go"
pull-request-branch-name:
separator: "/"
rebase-strategy: "auto"
allow:
# Allow all dependency types
- dependency-type: "all"
ignore:
# Ignore major version updates for stable dependencies (manual review preferred)
- dependency-name: "github.com/gorilla/websocket"
update-types: ["version-update:semver-major"]
- dependency-name: "github.com/hashicorp/mdns"
update-types: ["version-update:semver-major"]
groups:
# Group Go standard library and toolchain updates
golang:
patterns:
- "golang.org/*"
update-types:
- "patch"
- "minor"
# Group testing dependencies
testing:
patterns:
- "*test*"
- "*mock*"
- "*assert*"
update-types:
- "patch"
- "minor"
# GitHub Actions workflow dependency updates
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "tuesday"
time: "09:00"
timezone: "UTC"
open-pull-requests-limit: 3
reviewers:
- "user_account"
assignees:
- "user_account"
commit-message:
prefix: "ci"
include: "scope"
labels:
- "dependencies"
- "github-actions"
- "ci"
pull-request-branch-name:
separator: "/"
rebase-strategy: "auto"
allow:
- dependency-type: "all"
groups:
# Group actions from the same organization
actions-core:
patterns:
- "actions/*"
update-types:
- "patch"
- "minor"
# Group setup actions
setup-actions:
patterns:
- "*setup-*"
update-types:
- "patch"
- "minor"
# Group security-related actions
security-actions:
patterns:
- "*security*"
- "*scan*"
- "securecodewarrior/*"
- "codecov/*"
update-types:
- "patch"
- "minor"
# Docker dependencies (if we add Dockerfiles in the future)
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
day: "wednesday"
time: "09:00"
timezone: "UTC"
open-pull-requests-limit: 2
reviewers:
- "user_account"
assignees:
- "user_account"
commit-message:
prefix: "docker"
include: "scope"
labels:
- "dependencies"
- "docker"
pull-request-branch-name:
separator: "/"
rebase-strategy: "auto"
allow:
- dependency-type: "all"
# Only check if Dockerfile exists
ignore:
# Ignore base image major updates (requires manual testing)
- dependency-name: "*"
update-types: ["version-update:semver-major"]
+45
View File
@@ -0,0 +1,45 @@
{
"timeout": "20s",
"retryOn429": true,
"retryCount": 3,
"fallbackRetryDelay": "30s",
"aliveStatusCodes": [200, 206],
"ignorePatterns": [
{
"pattern": "^http://localhost"
},
{
"pattern": "^https://localhost"
},
{
"pattern": "^http://127.0.0.1"
},
{
"pattern": "^http://192.168."
},
{
"pattern": "^http://10."
},
{
"pattern": "^http://172."
},
{
"pattern": "^https://pkg.go.dev.*badge"
}
],
"replacementPatterns": [
{
"pattern": "^/",
"replacement": "{{BASEURL}}/"
}
],
"httpHeaders": [
{
"urls": ["https://github.com", "https://api.github.com"],
"headers": {
"Accept-Encoding": "zstd, br, gzip, deflate",
"User-Agent": "Mozilla/5.0 (compatible; LinkChecker)"
}
}
]
}
+260
View File
@@ -0,0 +1,260 @@
name: CI
on:
push:
branches: [ main ]
pull_request:
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: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- 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: Download dependencies
run: go mod download
- name: Verify dependencies
run: go mod verify
- 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
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v4
with:
version: latest
args: --timeout=5m
build:
name: Build
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux, darwin, windows]
goarch: [amd64, arm64]
exclude:
# Windows ARM64 builds are experimental
- goos: windows
goarch: arm64
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- 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-*
security:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- 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
docs:
name: Documentation Check
runs-on: ubuntu-latest
steps:
- 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: 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
# 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
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- 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
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())
// 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)
fmt.Println("All imports successful!")
}
EOF
go run test_import.go
rm test_import.go
notify:
name: Notify Status
runs-on: ubuntu-latest
needs: [test, lint, build, security, docs]
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: 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'
});
+400
View File
@@ -0,0 +1,400 @@
name: Release
on:
push:
tags:
- 'v*'
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: '1.23'
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@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
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@v5
with:
go-version: ${{ env.GO_VERSION }}
- 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@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- 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: 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: 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
runs-on: ubuntu-latest
needs: [validate, build]
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./binaries
- name: Generate checksums
run: |
cd binaries
# Flatten directory structure (artifacts are in subdirs)
find . -name "soundtouch-cli-*" -exec mv {} . \;
# Remove empty directories
find . -type d -empty -delete
# Generate SHA256 checksums
sha256sum soundtouch-cli-* > checksums.sha256
# Generate SHA512 checksums
sha512sum soundtouch-cli-* > checksums.sha512
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)
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"
- 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
create_release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [validate, checksums]
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
steps:
- 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: 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
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/user_account/bose-soundtouch@$TAG_NAME
\`\`\`
\`\`\`go
package main
import (
"fmt"
"log"
"github.com/user_account/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
SHA256 checksums are provided in \`checksums.sha256\` to verify download integrity.
## 🤝 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.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
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@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 }}
notify:
name: Post-Release Notifications
runs-on: ubuntu-latest
needs: [validate, create_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 ""
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)"
+230
View File
@@ -0,0 +1,230 @@
# golangci-lint configuration for Bose SoundTouch Go Library
# See: https://golangci-lint.run/usage/configuration/
run:
timeout: 5m
issues-exit-code: 1
tests: true
skip-dirs:
- vendor
- build
- scripts
skip-files:
- ".*\\.pb\\.go$"
- ".*_gen\\.go$"
output:
format: colored-line-number
print-issued-lines: true
print-linter-name: true
uniq-by-line: true
sort-results: true
linters:
enable:
# Default linters
- errcheck # Check for unchecked errors
- gosimple # Simplify code
- govet # Vet examines Go source code
- ineffassign # Detect ineffectual assignments
- staticcheck # Go static analysis
- typecheck # Parse and type-check Go code
- unused # Check for unused constants, variables, functions and types
# Additional useful linters for production code
- gofmt # Check whether code was gofmt-ed
- goimports # Check import sorting
- misspell # Find commonly misspelled English words
- unconvert # Remove unnecessary type conversions
- unparam # Report unused function parameters
- gocyclo # Compute cyclomatic complexities
- gocritic # Most opinionated Go source code linter
- gosec # Inspect source code for security problems
- exportloopref # Check for pointers to enclosing loop variables
- nolintlint # Reports ill-formed or insufficient nolint directives
- revive # Fast, configurable, extensible, flexible, and beautiful linter
- stylecheck # Stylecheck is a replacement for golint
- whitespace # Tool for detection of leading and trailing whitespace
- wsl # Whitespace Linter - Forces you to use empty lines
- predeclared # Find code that shadows one of Go's predeclared identifiers
- thelper # Detect golang test helpers without t.Helper() call
- tparallel # Detect inappropriate usage of t.Parallel() method in tests
- bodyclose # Check whether HTTP response body is closed successfully
- nilerr # Find the code that returns nil even if it checks that the error is not nil
- nilnil # Check that there is no simultaneous return of nil error and an invalid value
- errchkjson # Check types passed to the json encoding functions
- errorlint # Find code that will cause problems with the error wrapping scheme
- contextcheck # Check the function whether use a non-inherited context
disable:
- gocognit # Can be too strict for some cases
- funlen # Function length can vary based on complexity
- lll # Line length limit - we'll handle this with gofmt
- gomnd # Magic numbers detector - can be overly aggressive
- exhaustive # Can be too strict for enums
- testpackage # Not always necessary to put tests in separate package
- wrapcheck # Error wrapping can be context-dependent
- nlreturn # Can conflict with other formatting preferences
- gofumpt # Use standard gofmt instead
linters-settings:
errcheck:
check-type-assertions: true
check-blank: false
exclude-functions:
- (*os.File).Close
- (*bytes.Buffer).Write
- (*bytes.Buffer).WriteString
govet:
check-shadowing: true
enable-all: true
disable:
- fieldalignment # Can be overly aggressive
gocyclo:
min-complexity: 15
gocritic:
enabled-checks:
- appendAssign
- argOrder
- assignOp
- badCond
- boolExprSimplify
- builtinShadow
- captLocal
- caseOrder
- defaultCaseOrder
- dupArg
- dupBranchBody
- dupCase
- dupSubExpr
- elseif
- emptyFallthrough
- equalFold
- exitAfterDefer
- flagDeref
- flagName
- hexLiteral
- indexAlloc
- initClause
- methodExprCall
- nestingReduce
- newDeref
- nilValReturn
- offBy1
- paramTypeCombine
- ptrToRefParam
- rangeExprCopy
- rangeValCopy
- regexpMust
- singleCaseSwitch
- sloppyLen
- stringXbytes
- switchTrue
- typeAssertChain
- typeSwitchVar
- underef
- unlambda
- unslice
- valSwap
- weakCond
- yodaStyleExpr
gosec:
excludes:
- G104 # Audit errors not checked - handled by errcheck
config:
G301: "0755" # Poor file permissions
G302: "0755" # Poor file permissions
G306: "0755" # Poor file permissions
revive:
rules:
- name: var-naming
arguments: [["ID", "URL", "HTTP", "JSON", "XML", "API", "UUID", "SQL"], []]
- name: exported
arguments: [true]
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: empty-block
- name: error-naming
- name: error-return
- name: error-strings
- name: errorf
- name: increment-decrement
- name: indent-error-flow
- name: package-comments
- name: range
- name: receiver-naming
- name: redefines-builtin-id
- name: superfluous-else
- name: time-naming
- name: unexported-return
- name: unreachable-code
- name: unused-parameter
- name: var-declaration
- name: waitgroup-by-value
stylecheck:
checks: ["all", "-ST1003"] # Disable ST1003 (should not use underscores in Go names)
whitespace:
multi-if: false
multi-func: false
wsl:
strict-append: true
allow-assign-and-call: true
allow-assign-and-anything: false
allow-multiline-assign: true
force-case-trailing-whitespace: 0
issues:
exclude-rules:
# Exclude some linters from running on tests files
- path: _test\.go
linters:
- gosec # Security issues less critical in tests
- gocritic # Can be overly strict for test code
- wsl # Whitespace less critical in tests
- gocyclo # Complexity less critical in tests
# Exclude specific rules for generated files
- path: ".*\\.pb\\.go$"
linters:
- all
# Exclude some staticcheck messages
- linters:
- staticcheck
text: "SA9003:" # Empty branch
# Exclude some gosimple messages
- linters:
- gosimple
text: "S1002:" # Omit comparison with boolean constant
# Allow main functions to not check errors in examples
- path: cmd/.*\.go
text: "Error return value of.*is not checked"
linters:
- errcheck
# Allow long lines in CLI help text and similar
- path: cmd/.*\.go
text: "Line is.*characters"
linters:
- lll
exclude-use-default: false
max-issues-per-linter: 0
max-same-issues: 0
new: false
severity:
default-severity: error
case-sensitive: false
+210
View File
@@ -0,0 +1,210 @@
# Post-Release Promotion Checklist
After successfully releasing v1.0.0, follow this checklist to maximize visibility and adoption.
## ✅ Immediate Actions (Within 24 hours)
### Go Package Registry
- [ ] Verify pkg.go.dev indexing: https://pkg.go.dev/github.com/user_account/bose-soundtouch
- [ ] If not indexed, submit via: `go get github.com/user_account/bose-soundtouch@v1.0.0`
- [ ] Check documentation rendering on pkg.go.dev
### Community Engagement
- [ ] **r/golang** Reddit post:
```
Title: "Bose SoundTouch Go Library v1.0.0 - 100% API Coverage + WebSocket Events"
Content: Highlight production-ready features, real hardware testing, excellent docs
```
- [ ] **Gopher Slack** (#general, #show-and-tell):
```
"Just released a comprehensive Go library for Bose SoundTouch speakers 🎵
✅ 100% API coverage (19/19 official endpoints)
✅ Real-time WebSocket events
✅ 4000+ lines of documentation
✅ CLI tool with cross-platform binaries
Tested on real hardware! https://github.com/user_account/bose-soundtouch"
```
- [ ] **Hacker News** submission:
```
Title: "Bose SoundTouch Go Library Complete API with WebSocket Events"
URL: https://github.com/user_account/bose-soundtouch
```
### Social Media
- [ ] **Twitter/X** announcement:
```
"🎵 Just released Bose SoundTouch Go Library v1.0.0!
✅ 100% API coverage
✅ Real-time WebSocket events
✅ Production-ready patterns
✅ Comprehensive docs & CLI
✅ Real hardware tested
Perfect for home automation & music control apps
#golang #IoT #music #opensource
https://github.com/user_account/bose-soundtouch"
```
- [ ] **LinkedIn** professional post (if applicable)
## 📋 Medium-term Actions (Within 1 week)
### Documentation & Examples
- [ ] **Blog post** on personal site/Medium:
```
Title ideas:
- "Building a Production-Ready Go Library for IoT Devices"
- "100% API Coverage: Lessons from Building the Bose SoundTouch Go Client"
- "Real Hardware Testing: Why It Matters for IoT Libraries"
```
- [ ] **Dev.to article** with practical examples
- [ ] Create **example projects** repository:
- Home automation integration
- Discord bot for music control
- Web dashboard example
### Community Lists & Directories
- [ ] Submit to **awesome-go**: https://github.com/avelino/awesome-go
```
Category: Audio and Music
Entry: [bose-soundtouch](https://github.com/user_account/bose-soundtouch) - Go library for controlling Bose SoundTouch speakers with 100% API coverage and WebSocket events.
```
- [ ] Submit to **go-awesome**: https://github.com/shivammg/go-awesome
- [ ] List on **awesome-home-assistant**: https://github.com/frenck/awesome-home-assistant
- [ ] Add to **IoT awesome lists**: Search for IoT/smart home Go libraries lists
### Technical Communities
- [ ] **Go Forum** announcement: https://forum.golangbridge.org/
- [ ] **Home Assistant Community**: https://community.home-assistant.io/
- [ ] **Bose Community Forums** (if they exist)
- [ ] **Smart Home subreddits**: r/homeautomation, r/smarthome
## 🚀 Long-term Growth (Ongoing)
### Integration Examples
- [ ] **Home Assistant** custom component example
- [ ] **Node-RED** integration guide
- [ ] **Docker Compose** stack for monitoring multiple speakers
- [ ] **Kubernetes** operator for speaker management
### Technical Content
- [ ] **YouTube video**: "Building Go Libraries for IoT Devices"
- [ ] **Conference talk** submission: GopherCon, local Go meetups
- [ ] **Podcast appearances**: Go Time, other tech podcasts
### Package Ecosystem
- [ ] Create **Docker Hub** official image
- [ ] **Helm chart** for Kubernetes deployment
- [ ] **Homebrew formula** for easy CLI installation:
```bash
brew install user_account/tap/soundtouch-cli
```
## 📊 Success Metrics to Track
### Immediate (1 week)
- [ ] GitHub stars: Target 50+
- [ ] pkg.go.dev page views: Monitor via GitHub insights
- [ ] CLI downloads: Track release download counts
- [ ] Reddit/HN engagement: Upvotes, comments, discussions
### Medium-term (1 month)
- [ ] GitHub stars: Target 100+
- [ ] Issues/PRs from community: Sign of adoption
- [ ] Mentions in other projects: Search GitHub for imports
- [ ] Blog post views/shares
### Long-term (3 months)
- [ ] Featured in awesome-go lists
- [ ] Integration examples from community
- [ ] Forks and derivative projects
- [ ] Speaking opportunities
## 📝 Content Templates
### GitHub Issue Template for Feature Requests
```markdown
**Is your feature request related to a problem?**
A clear description of what the problem is.
**Describe the solution you'd like**
What you want to happen.
**Additional context**
Any other context or screenshots.
**Hardware tested**
Which Bose SoundTouch model(s) you're using.
```
### Email Template for Bloggers/Podcasters
```
Subject: Go Library for Bose SoundTouch Speakers - 100% API Coverage
Hi [Name],
I recently released a comprehensive Go library for controlling Bose SoundTouch speakers that might interest your audience:
🎯 Key highlights:
- 100% API coverage with real hardware validation
- Production-ready patterns and extensive documentation
- WebSocket events for real-time control
- Cross-platform CLI tool
The project demonstrates several interesting engineering challenges:
- IoT device discovery and control
- WebSocket event handling with auto-reconnect
- XML parsing and validation for legacy APIs
- Cross-platform binary distribution
Would this be interesting for [blog/podcast]? I'd be happy to discuss the technical details and lessons learned.
GitHub: https://github.com/user_account/bose-soundtouch
Best regards,
[Your name]
```
## 🎯 Priority Ranking
**High Impact, Low Effort:**
1. Reddit r/golang post
2. Gopher Slack announcement
3. awesome-go submission
4. Twitter announcement
**High Impact, Medium Effort:**
5. Blog post on Dev.to
6. Home automation community posts
7. Example projects repository
**Medium Impact, High Effort:**
8. YouTube video/conference talk
9. Podcast appearances
10. Advanced integration examples
## 🚨 Common Pitfalls to Avoid
- [ ] **Don't spam**: Space out announcements across communities
- [ ] **Provide value**: Focus on technical merit, not just promotion
- [ ] **Engage genuinely**: Respond to comments and questions promptly
- [ ] **Keep improving**: Address feedback and issues quickly
- [ ] **Document learnings**: Track what promotion strategies work best
---
## ✅ Completion Checklist
When you've completed a section, check it off and note the date:
- [ ] Immediate Actions completed: ___/___/___
- [ ] Medium-term Actions completed: ___/___/___
- [ ] First success metrics achieved: ___/___/___
**Remember**: Great libraries grow through genuine utility and community engagement, not just promotion. Focus on helping developers solve real problems! 🚀
+62 -13
View File
@@ -1,14 +1,17 @@
#!/bin/bash
# Bose SoundTouch Go Library - Release Preparation Script
# This script prepares everything needed for a GitHub release
# Bose SoundTouch Go Library - Local Release Preparation Script
# This script prepares everything needed for a local release build
# Note: GitHub workflows handle automated releases on tag push
set -e
VERSION=${1:-"v1.0.0"}
GITHUB_REPO="user_account/bose-soundtouch"
echo "🚀 Preparing release $VERSION for $GITHUB_REPO"
echo "🚀 Preparing local release build $VERSION for $GITHUB_REPO"
echo "💡 Note: This is for local testing. Use 'git tag && git push --tags' for automated release"
echo ""
# Verify we're in the right directory
if [ ! -f "go.mod" ] || [ ! -d "pkg/client" ]; then
@@ -39,24 +42,51 @@ echo "✅ All tests passed"
echo "🔨 Building CLI for multiple platforms..."
mkdir -p build/releases
# Build for common platforms
# Build for common platforms (same as CI)
PLATFORMS=(
"linux/amd64"
"linux/arm64"
"linux/arm"
"darwin/amd64"
"darwin/arm64"
"windows/amd64"
"freebsd/amd64"
)
for platform in "${PLATFORMS[@]}"; do
GOARM_VALUES=(
"" # linux/amd64
"" # linux/arm64
"7" # linux/arm
"" # darwin/amd64
"" # darwin/arm64
"" # windows/amd64
"" # freebsd/amd64
)
for i in "${!PLATFORMS[@]}"; do
platform="${PLATFORMS[$i]}"
goarm="${GOARM_VALUES[$i]}"
IFS="/" read -r GOOS GOARCH <<< "$platform"
OUTPUT_NAME="soundtouch-cli-$VERSION-$GOOS-$GOARCH"
ARCH_SUFFIX="$GOOS-$GOARCH"
if [[ "$goarm" != "" ]]; then
ARCH_SUFFIX="${ARCH_SUFFIX}v$goarm"
fi
OUTPUT_NAME="soundtouch-cli-$VERSION-$ARCH_SUFFIX"
if [ "$GOOS" = "windows" ]; then
OUTPUT_NAME="$OUTPUT_NAME.exe"
fi
echo " Building for $GOOS/$GOARCH..."
GOOS=$GOOS GOARCH=$GOARCH go build -o "build/releases/$OUTPUT_NAME" ./cmd/soundtouch-cli
echo " Building for $GOOS/$GOARCH${goarm:+v$goarm}..."
env_vars="GOOS=$GOOS GOARCH=$GOARCH CGO_ENABLED=0"
if [[ "$goarm" != "" ]]; then
env_vars="$env_vars GOARM=$goarm"
fi
eval "$env_vars go build -ldflags='-s -w -X main.version=$VERSION' -o 'build/releases/$OUTPUT_NAME' ./cmd/soundtouch-cli"
done
echo "✅ Built CLI for all platforms"
@@ -83,6 +113,7 @@ A comprehensive Go library for controlling Bose SoundTouch speakers with 100% AP
- **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
- **CI/CD Pipeline**: Automated testing, linting, security scans, and releases
## 🚀 Quick Start
@@ -162,7 +193,19 @@ MIT License - see [LICENSE](LICENSE) file.
## 🙏 Acknowledgments
Built with real hardware testing and community feedback. Special thanks to the Bose developer community.
EOF
## 🏗️ Supported Platforms
This release includes pre-built binaries for:
- Linux (amd64, arm64, armv7)
- macOS (Intel & Apple Silicon)
- Windows (amd64)
- FreeBSD (amd64)
## 🔐 Checksums
SHA256 checksums are provided to verify download integrity.
EOF
echo "✅ Generated release notes"
@@ -173,11 +216,17 @@ echo ""
echo "📦 Files ready for release:"
ls -la build/releases/
echo ""
echo "📋 Next steps:"
echo "📋 Next steps for automated release:"
echo "1. Push any remaining commits: git push origin main"
echo "2. Create and push tag: git tag $VERSION && git push origin $VERSION"
echo "3. Create GitHub release with files in build/releases/"
echo "4. Use build/RELEASE_NOTES.md as release description"
echo "3. GitHub Actions will automatically:"
echo " - Run full CI pipeline (tests, linting, security)"
echo " - Build binaries for all platforms"
echo " - Generate checksums and release notes"
echo " - Create GitHub release with all assets"
echo ""
echo "🔗 Release URL will be: https://github.com/$GITHUB_REPO/releases/tag/$VERSION"
echo "🔗 Release will be at: https://github.com/$GITHUB_REPO/releases/tag/$VERSION"
echo "📊 Monitor CI at: https://github.com/$GITHUB_REPO/actions"
echo ""
echo "🧪 Local build completed - use for testing before tagging!"
EOF