Files
Bose-SoundTouch/.github/workflows/release.yml
T
dependabot[bot]andlnx01 85fa9ede2f ci(deps): bump docker/setup-buildx-action from 4.2.0 to 4.3.0 in the setup-actions group (#640)
Bumps the setup-actions group with 1 update:
[docker/setup-buildx-action](https://github.com/docker/setup-buildx-action).

Updates `docker/setup-buildx-action` from 4.2.0 to 4.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/docker/setup-buildx-action/releases">docker/setup-buildx-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.3.0</h2>
<ul>
<li>Bump <code>@​docker/actions-toolkit</code> from 0.92.0 to 0.95.0 in
<a
href="https://redirect.github.com/docker/setup-buildx-action/pull/595">docker/setup-buildx-action#595</a></li>
<li>Bump brace-expansion from 1.1.13 to 1.1.18 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/600">docker/setup-buildx-action#600</a></li>
<li>Bump js-yaml from 5.2.0 to 5.3.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/585">docker/setup-buildx-action#585</a></li>
<li>Bump postcss from 8.5.10 to 8.5.25 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/598">docker/setup-buildx-action#598</a></li>
<li>Bump undici from 6.27.0 to 6.28.0 in <a
href="https://redirect.github.com/docker/setup-buildx-action/pull/601">docker/setup-buildx-action#601</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/docker/setup-buildx-action/compare/v4.2.0...v4.3.0">https://github.com/docker/setup-buildx-action/compare/v4.2.0...v4.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/37fe631027851001ddb9b187196cc803df7f5f0e"><code>37fe631</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/595">#595</a>
from docker/dependabot/npm_and_yarn/docker/actions-to...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/b5c4f91922681cc7c58d15ab7838986951f09d19"><code>b5c4f91</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/3e93b637c6430ba8fa896fad44d3aa6821899d63"><code>3e93b63</code></a>
build(deps): bump <code>@​docker/actions-toolkit</code> from 0.92.0 to
0.95.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/e527031b32c86649307d5d492506855f90470604"><code>e527031</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/600">#600</a>
from docker/dependabot/npm_and_yarn/brace-expansion-1...</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/c68814b33cb66f1f7538e546190d410ae557a640"><code>c68814b</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/3f891b01bd5012a434f582800366972569aa1886"><code>3f891b0</code></a>
build(deps): bump brace-expansion from 1.1.13 to 1.1.18</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/787db26fcde8ddcabd49a81472318028f7113962"><code>787db26</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/585">#585</a>
from docker/dependabot/npm_and_yarn/js-yaml-5.2.1</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/f7793687c711790ca336bd4934f1b1bf5f778e17"><code>f779368</code></a>
[dependabot skip] chore: update generated content</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/7d5e60413489a33d28077e11d71c668580cfaf8d"><code>7d5e604</code></a>
build(deps): bump js-yaml from 5.2.0 to 5.3.0</li>
<li><a
href="https://github.com/docker/setup-buildx-action/commit/292c2fb3837a12d3ac2d1e47bbc5c00712bad939"><code>292c2fb</code></a>
Merge pull request <a
href="https://redirect.github.com/docker/setup-buildx-action/issues/590">#590</a>
from docker/dependabot/github_actions/actions/setup-n...</li>
<li>Additional commits viewable in <a
href="https://github.com/docker/setup-buildx-action/compare/bb05f3f5519dd87d3ba754cc423b652a5edd6d2c...37fe631027851001ddb9b187196cc803df7f5f0e">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=docker/setup-buildx-action&package-manager=github_actions&previous-version=4.2.0&new-version=4.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-23 13:51:28 +02:00

600 lines
23 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:
tag: ${{ steps.version.outputs.tag }}
version: ${{ steps.version.outputs.version }}
is_prerelease: ${{ steps.version.outputs.is_prerelease }}
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Both triggers resolve to the same thing: the release tag. On a
# `release` event inputs.tag is empty, so this falls back to the
# published release's tag. Every other job checks out this same
# tag (via needs.validate.outputs.tag) so the build is always the
# tagged commit, never whatever branch the dispatch ran on (#525).
ref: ${{ github.event.inputs.tag || github.event.release.tag_name }}
fetch-depth: 0
- name: Validate tag format
id: version
run: |
# Single source of truth for the tag, regardless of trigger.
TAG_NAME="${{ github.event.inputs.tag || github.event.release.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
# Confirm the tag actually exists in git. The dispatch path
# re-releases an existing tag; it never creates one from a branch.
if ! git rev-parse -q --verify "refs/tags/$TAG_NAME" >/dev/null; then
echo "❌ Tag $TAG_NAME does not exist in git. Push the tag first, then re-run."
exit 1
fi
echo "tag=$TAG_NAME" >> $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
- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: ${{ env.GO_VERSION_FILE }}
- name: Install libpcap
run: sudo apt-get install -y libpcap-dev
- 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.validate.outputs.tag }}
- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: ${{ env.GO_VERSION_FILE }}
- name: Cache Go modules
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
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
# Single build timestamp shared across every binary in this job.
BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# Commit of the checked-out tag (not GITHUB_SHA, which on a manual
# dispatch is the branch HEAD the run started from, not the tag).
COMMIT_SHA="$(git rev-parse HEAD)"
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
# Ensure build directory exists
mkdir -p build
if [[ "${{ matrix.goos }}" == "windows" ]]; then
OUTPUT_NAME="build/${BINARY_NAME}-v${{ needs.validate.outputs.version }}-${ARCH_SUFFIX}.exe"
else
OUTPUT_NAME="build/${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"
# Inject the validated version (plus commit/date) so the binary
# reports the right version regardless of git checkout state.
# Relying on Go's VCS stamping alone yields v0.0.0-… when built
# from a shallow checkout or a non-tagged commit (see #525).
if ! go build \
-trimpath \
-ldflags="-s -w -X main.version=${{ needs.validate.outputs.tag }} -X main.commit=${COMMIT_SHA} -X main.date=${BUILD_DATE}" \
-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"
# Build Player (formerly soundtouch-web)
build_binary "soundtouch-player" "./cmd/soundtouch-player"
# Build Backup
build_binary "soundtouch-backup" "./cmd/soundtouch-backup"
id: build
- name: Generate individual checksums
run: |
CLI_NAME="${{ steps.build.outputs.soundtouch-cli }}"
SVC_NAME="${{ steps.build.outputs.soundtouch-service }}"
PLAYER_NAME="${{ steps.build.outputs.soundtouch-player }}"
BCK_NAME="${{ steps.build.outputs.soundtouch-backup }}"
# 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"
generate_checksums "$PLAYER_NAME"
generate_checksums "$BCK_NAME"
# Cleanup
rm -rf "$TEMP_DIR"
echo "✅ Checksums generated successfully"
- name: Upload build artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: binaries-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarm }}
path: |
build/soundtouch-cli-v*
build/soundtouch-service-v*
build/soundtouch-player-v*
build/soundtouch-backup-v*
retention-days: 1
checksums:
name: Generate Checksums
runs-on: ubuntu-latest
needs: [validate, build]
steps:
- name: Download binary artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
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-*" -o -name "soundtouch-player-*" -o -name "soundtouch-backup-*" \) -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-cli-* soundtouch-service-* soundtouch-player-* soundtouch-backup-* | grep -v '\.sha256$' | grep -v '\.sha512$' | xargs sha256sum > checksums.sha256
ls soundtouch-cli-* soundtouch-service-* soundtouch-player-* soundtouch-backup-* | 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=28 # 7 platforms * 4 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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.validate.outputs.tag }}
fetch-depth: 0
- name: Download release assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-assets
path: ./release-assets
- name: Generate release notes
id: release_notes
run: |
TAG_NAME="${{ needs.validate.outputs.tag }}"
VERSION="${TAG_NAME#v}"
# Real per-platform links for the two most-used tools, generated
# from the deterministic `<binary>-<tag>-<os>-<arch>[.exe]` asset
# naming convention (see scripts/release/quick-downloads.sh),
# instead of requiring a scroll through the flat, alphabetical
# Assets list. Inline checksum link per row (à la Helm's release
# notes) instead of sending people to the combined checksums file.
QUICK_DOWNLOADS="$(scripts/release/quick-downloads.sh "$TAG_NAME" "${{ github.repository }}")"
# Short, accurate header. GitHub's auto-generated "What's Changed"
# + "Full Changelog" are appended after this (generate_release_notes).
cat > release_notes.md << EOF
# AfterTouch $TAG_NAME
**Bose SoundTouch Toolkit.** Keep your Bose SoundTouch speakers alive after the Bose cloud shutdown. No Bose infrastructure required.
$QUICK_DOWNLOADS
## What's included
Pre-built binaries for Linux (amd64, arm64, armv7), macOS (Intel & Apple Silicon), Windows (amd64), and FreeBSD (amd64):
- **soundtouch-service** (see above)
- **soundtouch-cli** (see above)
- **soundtouch-player**: standalone LAN web UI for device control: play/pause, volume, presets, live status. (Formerly \`soundtouch-web\`.)
- **soundtouch-backup**: back up your Bose cloud account and each speaker's local state. \`soundtouch-backup all\` captures everything in one step.
Not sure which file to grab? The [Downloads page](https://gesellix.github.io/Bose-SoundTouch/docs/downloads/) explains which tool you need and which \`<os>-<arch>\` build matches your computer.
## Documentation
Full guides, setup walkthroughs, and troubleshooting: https://gesellix.github.io/Bose-SoundTouch/
## Use as a Go library
The core client is also importable:
\`\`\`bash
go get github.com/gesellix/bose-soundtouch@$TAG_NAME
\`\`\`
## Verifying downloads
Each binary has its own \`.sha256\`/\`.sha512\`, and combined \`checksums.sha256\` / \`checksums.sha512\` cover all of them:
\`\`\`bash
sha256sum -c checksums.sha256 --ignore-missing
\`\`\`
EOF
echo "release_notes_file=release_notes.md" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
tag_name: ${{ needs.validate.outputs.tag }}
name: ${{ needs.validate.outputs.tag }}
body_path: ${{ steps.release_notes.outputs.release_notes_file }}
generate_release_notes: true
draft: false
prerelease: ${{ needs.validate.outputs.is_prerelease == 'true' }}
files: |
release-assets/soundtouch-cli-v*
release-assets/soundtouch-service-v*
release-assets/soundtouch-player-v*
release-assets/soundtouch-backup-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: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.validate.outputs.tag }}
- name: Download release assets
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-assets
path: ./release-assets
- name: Upgrade the Downloads footer with direct per-platform links
# This is the path real releases take: a maintainer hand-writes
# "Noteworthy" notes and publishes via the GitHub web UI, which
# fires this job, not create_release (workflow_dispatch only).
# _/releases/_TEMPLATE.md's convention is a trailing footer line:
# ---
# 📦 **Downloads / installation:** <downloads page URL>
# Drop that line (if present) and append the quick-downloads
# block in its place. Always goes through the same append path
# (strip block + strip footer + append), whether or not a
# footer line is still there, so re-runs stay byte-for-byte
# idempotent instead of drifting on the 2nd run.
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME="${{ needs.validate.outputs.tag }}"
scripts/release/quick-downloads.sh "$TAG_NAME" "${{ github.repository }}" > quick_downloads.md
gh release view "$TAG_NAME" --json body -q .body > existing_body.md
python3 - << 'PYEOF'
import re
with open("existing_body.md") as f:
body = f.read()
with open("quick_downloads.md") as f:
block = f.read().rstrip("\n")
# Drop a block this automation inserted on a previous run.
body = re.sub(r"\n*<!-- quick-downloads:start -->.*?<!-- quick-downloads:end -->\n*", "\n", body, flags=re.DOTALL)
# Drop the hand-authored footer line (first run only) so both
# cases converge on the same append below and re-runs stay
# byte-for-byte idempotent.
footer = re.compile(r"^📦 \*\*Downloads / installation:\*\*.*\n?", re.MULTILINE)
body = footer.sub("", body, count=1)
body = body.rstrip("\n") + "\n\n" + block + "\n"
with open("combined_notes.md", "w") as f:
f.write(body)
PYEOF
gh release edit "$TAG_NAME" --notes-file combined_notes.md
- name: Upload additional assets to existing release
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
tag_name: ${{ needs.validate.outputs.tag }}
files: |
release-assets/soundtouch-cli-v*
release-assets/soundtouch-service-v*
release-assets/soundtouch-player-v*
release-assets/soundtouch-backup-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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ needs.validate.outputs.tag }}
- name: Set build metadata
id: build_date
run: |
echo "date=$(date -u +%Y-%m-%d)" >> $GITHUB_OUTPUT
# Commit of the checked-out tag, not github.sha (the dispatch HEAD).
echo "commit=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
- name: Log in to GitHub Container Registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for soundtouch-service
id: meta-service
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
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 soundtouch-service Docker image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
target: soundtouch-service
platforms: linux/amd64,linux/arm64,linux/arm64/v8,linux/arm/v7
push: true
tags: ${{ steps.meta-service.outputs.tags }}
labels: ${{ steps.meta-service.outputs.labels }}
build-args: |
VERSION=${{ needs.validate.outputs.tag }}
COMMIT=${{ steps.build_date.outputs.commit }}
DATE=${{ steps.build_date.outputs.date }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Extract metadata (tags, labels) for soundtouch-player
id: meta-player
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ghcr.io/${{ github.repository }}-player
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 soundtouch-player Docker image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
target: soundtouch-player
platforms: linux/amd64,linux/arm64,linux/arm64/v8,linux/arm/v7
push: true
tags: ${{ steps.meta-player.outputs.tags }}
labels: ${{ steps.meta-player.outputs.labels }}
build-args: |
VERSION=${{ needs.validate.outputs.tag }}
COMMIT=${{ steps.build_date.outputs.commit }}
DATE=${{ steps.build_date.outputs.date }}
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, Service, Player, and Backup)"
echo "🐳 Docker image published to ghcr.io"
echo "🔐 Checksums generated and verified"
echo "📋 Release notes automatically generated"
echo ""
TAG_NAME="${{ needs.validate.outputs.tag }}"
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)"