mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-09-07 15:07:17 +00:00
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 /> [](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>
600 lines
23 KiB
YAML
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)"
|