navidrome/.github/workflows/pipeline.yml
Deluan 16b9f60a21 ci: close change-detection gaps found in review
Four changes, three of them gaps in the filters added by the previous commit.

Go tests execute db/migrations/*.sql for real: persistence_suite_test.go calls
db.Init, which runs goose against an in-memory database. `make migration-sql`
produces a .sql-only diff, and six such commits exist in history, so those PRs
would have run zero Go tests. Added ^db/migrations/ to the Go filter.

validate-translations.sh reads ui/src/i18n/en.json as its reference, not
resources/i18n/en.json, which does not exist. A commit that only removes an
English key (dd4802c0c is one) would have skipped the only check that reports
the orphaned keys left in all 36 translations.

The coverage-artifact probe was unpaginated. A full Go pipeline run produces
exactly 30 artifacts, the API default page size, and octocov-pr sorts to index
27 because the test jobs finish first. Run 33503006884 already produced 33 and
pushed all three coverage artifacts off page one. Server-side ?name= filtering
has no count ceiling.

The script also now fails closed if the base ref cannot be resolved. The fetch
itself stays non-fatal: actions/checkout already created the ref, so a failed
refresh is harmless, and making it fatal would turn a transient blip into a red
pipeline.

Also adds workflow_dispatch, so a manual run is possible and gets every flag.
2026-09-05 13:47:20 -04:00

763 lines
No EOL
26 KiB
YAML

name: "Pipeline: Test, Lint, Build"
on:
push:
branches:
- master
tags:
- "v*"
pull_request:
branches:
- master
workflow_dispatch:
concurrency:
group: ${{ startsWith(github.ref, 'refs/tags/v') && 'tag' || 'branch' }}-${{ github.ref }}
cancel-in-progress: true
env:
IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/') && 'true' || 'false' }}
jobs:
git-version:
name: Get version info
runs-on: ubuntu-latest
outputs:
git_tag: ${{ steps.git-version.outputs.GIT_TAG }}
git_sha: ${{ steps.git-version.outputs.GIT_SHA }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- name: Show git version info
run: |
echo "git describe (dirty): $(git describe --dirty --always --tags)"
echo "git describe --tags --abbrev=0: $(git describe --tags --abbrev=0)"
echo "git tag: $(git tag --sort=-committerdate | head -n 1)"
echo "github_ref: $GITHUB_REF"
echo "github_head_sha: ${{ github.event.pull_request.head.sha }}"
git tag -l
- name: Determine git current SHA and latest tag
id: git-version
run: |
GIT_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
if [ -n "$GIT_TAG" ]; then
if [[ "$GITHUB_REF" != refs/tags/* ]]; then
GIT_TAG=${GIT_TAG}-SNAPSHOT
fi
echo "GIT_TAG=$GIT_TAG" >> $GITHUB_OUTPUT
fi
GIT_SHA=$(git rev-parse --short HEAD)
PR_NUM=$(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
if [[ $PR_NUM != "null" ]]; then
GIT_SHA=$(echo "${{ github.event.pull_request.head.sha }}" | cut -c1-8)
GIT_SHA="pr-${PR_NUM}/${GIT_SHA}"
fi
echo "GIT_SHA=$GIT_SHA" >> $GITHUB_OUTPUT
echo "GIT_TAG=$GIT_TAG"
echo "GIT_SHA=$GIT_SHA"
# Outputs gate steps, never jobs: a job-level skip propagates through the needs
# chain (actions/runner#491) and would skip all release jobs on tag pushes.
changes:
name: Detect changed areas
runs-on: ubuntu-latest
outputs:
go: ${{ steps.detect.outputs.go }}
js: ${{ steps.detect.outputs.js }}
i18n: ${{ steps.detect.outputs.i18n }}
build: ${{ steps.detect.outputs.build }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Detect changed areas
id: detect
env:
BASE_REF: ${{ github.event.pull_request.base.ref }}
run: ./.github/workflows/detect-changes.sh
go-lint:
name: Lint Go code
runs-on: ubuntu-latest
needs: [changes]
steps:
- uses: actions/checkout@v7
if: needs.changes.outputs.go == 'true'
- uses: actions/setup-go@v6
if: needs.changes.outputs.go == 'true'
with:
go-version-file: go.mod
# Keep CI on the same version `make lint` installs, so a clean local run
# cannot turn red in CI just because a new golangci-lint was released.
- name: Resolve golangci-lint version
id: golangci-version
if: needs.changes.outputs.go == 'true'
run: echo "version=$(grep '^GOLANGCI_LINT_VERSION' Makefile | cut -d ' ' -f 3)" >> "$GITHUB_OUTPUT"
- name: golangci-lint
if: needs.changes.outputs.go == 'true'
uses: golangci/golangci-lint-action@v9
with:
version: ${{ steps.golangci-version.outputs.version }}
problem-matchers: true
args: --timeout 2m
- name: Run go goimports
if: needs.changes.outputs.go == 'true'
run: go run golang.org/x/tools/cmd/goimports@latest -w `find . -name '*.go' | grep -v '_gen.go$' | grep -v '.pb.go$'`
- if: needs.changes.outputs.go == 'true'
run: go mod tidy
- name: Verify no changes from goimports and go mod tidy
if: needs.changes.outputs.go == 'true'
run: |
git status --porcelain
if [ -n "$(git status --porcelain)" ]; then
echo 'To fix this check, run "make format" and commit the changes'
exit 1
fi
- name: Run go generate
if: needs.changes.outputs.go == 'true'
run: go generate ./...
- name: Verify no changes from go generate
if: needs.changes.outputs.go == 'true'
run: |
git status --porcelain
if [ -n "$(git status --porcelain)" ]; then
echo 'Generated code is out of date. Run "make gen" and commit the changes'
exit 1
fi
validate-migrations:
name: Validate DB migrations
runs-on: ubuntu-latest
# PR-only gate is at step level: a job-level skip would propagate through
# the needs chain (actions/runner#491) and skip all release jobs on tag pushes.
steps:
- uses: actions/checkout@v7
if: github.event_name == 'pull_request'
with:
fetch-depth: 0
# Refresh the base branch so the check compares against its CURRENT tip,
# not the (possibly stale) commit the PR was opened against.
- name: Fetch latest base branch
if: github.event_name == 'pull_request'
run: git fetch --no-tags origin "+refs/heads/${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}"
- name: Validate migration ordering and naming
if: github.event_name == 'pull_request'
env:
BASE_REF: origin/${{ github.event.pull_request.base.ref }}
run: ./.github/workflows/validate-migrations.sh
go:
name: Test Go code
runs-on: ubuntu-latest
needs: [changes]
steps:
- name: Check out code into the Go module directory
if: needs.changes.outputs.go == 'true'
uses: actions/checkout@v7
- uses: actions/setup-go@v6
if: needs.changes.outputs.go == 'true'
with:
go-version-file: go.mod
- name: Download dependencies
if: needs.changes.outputs.go == 'true'
run: go mod download
# Name must stay unique across the workflow: octocov matches step names
# by name across every job, and waits for each match to finish.
- name: Test with coverage
if: needs.changes.outputs.go == 'true'
run: go test -shuffle=on -tags netgo,sqlite_fts5 -race -v -covermode=atomic -coverprofile=coverage.out $(go list ./... | grep -v '/plugins$')
- name: Test ndpgen
if: needs.changes.outputs.go == 'true'
run: |
cd plugins/cmd/ndpgen
go test -shuffle=on -v
go build -o ndpgen .
./ndpgen --help
- name: Upload coverage profile
if: needs.changes.outputs.go == 'true'
uses: actions/upload-artifact@v7
with:
name: octocov-go
path: coverage.out
if-no-files-found: error
go-plugins:
name: Test Go plugins
runs-on: ubuntu-latest
needs: [changes]
steps:
- name: Check out code into the Go module directory
if: needs.changes.outputs.go == 'true'
uses: actions/checkout@v7
- uses: actions/setup-go@v6
id: setup-go
if: needs.changes.outputs.go == 'true'
with:
go-version-file: go.mod
# Without this, the suite recompiles every test plugin WASM module,
# which dominates its runtime under -race.
- name: Cache the WASM compilation cache
if: needs.changes.outputs.go == 'true'
uses: actions/cache@v6
with:
path: plugins/testdata/.wazero-cache
key: wazero-${{ runner.os }}-go${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('plugins/testdata/*/*.go', 'plugins/testdata/*/go.*', 'plugins/pdk/go/**/*.go', 'plugins/pdk/go/go.*') }}
restore-keys: wazero-${{ runner.os }}-
- name: Test plugins
if: needs.changes.outputs.go == 'true'
run: go tool ginkgo -p -race -tags netgo,sqlite_fts5 --cover --covermode=atomic --coverprofile=coverage.out --output-dir=. ./plugins/
- name: Upload coverage profile
if: needs.changes.outputs.go == 'true'
uses: actions/upload-artifact@v7
with:
name: octocov-plugins
path: coverage.out
if-no-files-found: error
coverage:
name: Report coverage
runs-on: ubuntu-latest
needs: [changes, go, go-plugins]
permissions:
contents: read
actions: write
env:
COVERAGE_COMMENT: 'false'
steps:
- uses: actions/checkout@v7
if: needs.changes.outputs.go == 'true'
- uses: actions/download-artifact@v8
if: needs.changes.outputs.go == 'true'
with:
pattern: octocov-*
# Merge here rather than letting octocov do it: octocov reports statement
# coverage for a single profile, but switches to line counting for several.
- name: Merge coverage profiles
if: needs.changes.outputs.go == 'true'
run: |
echo "mode: atomic" > coverage.out
awk 'FNR==1 && /^mode:/ {next} {k=$1" "$2; c[k]+=$3} END {for (k in c) print k, c[k]}' \
octocov-*/coverage.out | sort >> coverage.out
- uses: k1LoW/octocov-action@v1
if: needs.changes.outputs.go == 'true'
- name: Save the PR number for the comment workflow
if: github.event_name == 'pull_request' && needs.changes.outputs.go == 'true'
run: echo "${{ github.event.pull_request.number }}" > pr_number
- name: Upload the merged profile for the comment workflow
if: github.event_name == 'pull_request' && needs.changes.outputs.go == 'true'
uses: actions/upload-artifact@v7
with:
name: octocov-pr
path: |
coverage.out
pr_number
if-no-files-found: error
go-windows:
name: Test Go code (Windows)
runs-on: windows-2022
needs: [changes]
env:
FFMPEG_VERSION: "7.1"
FFMPEG_REPOSITORY: navidrome/ffmpeg-windows-builds
steps:
- uses: actions/checkout@v7
if: needs.changes.outputs.go == 'true'
- uses: actions/setup-go@v6
if: needs.changes.outputs.go == 'true'
with:
go-version-file: go.mod
- uses: msys2/setup-msys2@v2
if: needs.changes.outputs.go == 'true'
with:
msystem: MINGW64
install: mingw-w64-x86_64-gcc
update: false
- name: Add mingw64 to PATH
if: needs.changes.outputs.go == 'true'
shell: bash
run: echo "C:/msys64/mingw64/bin" >> $GITHUB_PATH
- name: Cache ffmpeg
if: needs.changes.outputs.go == 'true'
id: ffmpeg-cache
uses: actions/cache@v6
with:
path: C:\ffmpeg
key: ffmpeg-${{ env.FFMPEG_VERSION }}-win64
- name: Download ffmpeg
if: needs.changes.outputs.go == 'true' && steps.ffmpeg-cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
$asset = "ffmpeg-n${env:FFMPEG_VERSION}-latest-win64-gpl-${env:FFMPEG_VERSION}"
$url = "https://github.com/${env:FFMPEG_REPOSITORY}/releases/download/latest/$asset.zip"
Invoke-WebRequest -Uri $url -OutFile ffmpeg.zip
Expand-Archive ffmpeg.zip -DestinationPath C:\ffmpeg-extracted
New-Item -ItemType Directory -Force -Path C:\ffmpeg\bin | Out-Null
Copy-Item "C:\ffmpeg-extracted\$asset\bin\ffmpeg.exe" C:\ffmpeg\bin
Copy-Item "C:\ffmpeg-extracted\$asset\bin\ffprobe.exe" C:\ffmpeg\bin
- name: Add ffmpeg to PATH
if: needs.changes.outputs.go == 'true'
shell: bash
run: echo "C:/ffmpeg/bin" >> $GITHUB_PATH
- name: Verify toolchain
if: needs.changes.outputs.go == 'true'
shell: pwsh
run: |
go version
where.exe gcc
gcc --version
ffmpeg -version
ffprobe -version
- name: Download dependencies
if: needs.changes.outputs.go == 'true'
shell: bash
run: go mod download
- name: Test
if: needs.changes.outputs.go == 'true'
shell: bash
env:
CGO_ENABLED: "1"
run: go test -shuffle=on -tags netgo,sqlite_fts5 ./... -v
- name: Test ndpgen
if: needs.changes.outputs.go == 'true'
shell: bash
run: |
cd plugins/cmd/ndpgen
go test -shuffle=on -v
go build -o ndpgen.exe .
./ndpgen.exe --help
js:
name: Test JS code
runs-on: ubuntu-latest
needs: [changes]
env:
NODE_OPTIONS: "--max_old_space_size=4096"
steps:
- uses: actions/checkout@v7
if: needs.changes.outputs.js == 'true'
- uses: actions/setup-node@v6
if: needs.changes.outputs.js == 'true'
with:
node-version: 24
cache: "npm"
cache-dependency-path: "**/package-lock.json"
- name: npm install dependencies
if: needs.changes.outputs.js == 'true'
run: |
cd ui
npm ci
- name: npm lint
if: needs.changes.outputs.js == 'true'
run: |
cd ui
npm run check-formatting && npm run lint
- name: npm test
if: needs.changes.outputs.js == 'true'
run: |
cd ui
npm test
- name: npm build
if: needs.changes.outputs.js == 'true'
run: |
cd ui
npm run build
i18n-lint:
name: Lint i18n files
runs-on: ubuntu-latest
needs: [changes]
steps:
- uses: actions/checkout@v7
if: needs.changes.outputs.i18n == 'true'
- if: needs.changes.outputs.i18n == 'true'
run: |
set -e
for file in resources/i18n/*.json; do
echo "Validating $file"
if ! jq empty "$file" 2>error.log; then
error_message=$(cat error.log)
line_number=$(echo "$error_message" | grep -oP 'line \K[0-9]+')
echo "::error file=$file,line=$line_number::$error_message"
exit 1
fi
done
- run: ./.github/workflows/validate-translations.sh -v
if: needs.changes.outputs.i18n == 'true'
check-push-enabled:
name: Check Docker configuration
runs-on: ubuntu-latest
outputs:
is_enabled: ${{ steps.check.outputs.is_enabled }}
steps:
- name: Check if Docker push is configured
id: check
run: echo "is_enabled=${{ secrets.DOCKER_HUB_USERNAME != '' }}" >> $GITHUB_OUTPUT
build:
name: Build
needs: [changes, js, go, go-plugins, go-windows, go-lint, i18n-lint, git-version, check-push-enabled, validate-migrations]
strategy:
matrix:
platform: [ linux/amd64, linux/arm64, linux/arm/v5, linux/arm/v6, linux/arm/v7, linux/386, linux/riscv64, darwin/amd64, darwin/arm64, windows/amd64, windows/386 ]
runs-on: ubuntu-latest
env:
IS_LINUX: ${{ startsWith(matrix.platform, 'linux/') && 'true' || 'false' }}
IS_ARMV5: ${{ matrix.platform == 'linux/arm/v5' && 'true' || 'false' }}
IS_DOCKER_PUSH_CONFIGURED: ${{ needs.check-push-enabled.outputs.is_enabled == 'true' }}
SHOULD_BUILD: ${{ needs.changes.outputs.build }}
DOCKER_BUILD_SUMMARY: false
GIT_SHA: ${{ needs.git-version.outputs.git_sha }}
GIT_TAG: ${{ needs.git-version.outputs.git_tag }}
steps:
- name: Sanitize platform name
if: env.SHOULD_BUILD == 'true'
id: set-platform
run: |
PLATFORM=$(echo ${{ matrix.platform }} | tr '/' '_')
echo "PLATFORM=$PLATFORM" >> $GITHUB_ENV
- uses: actions/checkout@v7
if: env.SHOULD_BUILD == 'true'
- name: Prepare Docker Buildx
if: env.SHOULD_BUILD == 'true'
uses: ./.github/actions/prepare-docker
id: docker
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
hub_repository: ${{ vars.DOCKER_HUB_REPO }}
hub_username: ${{ secrets.DOCKER_HUB_USERNAME }}
hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Build Binaries
if: env.SHOULD_BUILD == 'true'
uses: docker/build-push-action@v7
with:
context: .
file: Dockerfile
platforms: ${{ matrix.platform }}
outputs: |
type=local,dest=./output/${{ env.PLATFORM }}
target: binary
build-args: |
GIT_SHA=${{ env.GIT_SHA }}
GIT_TAG=${{ env.GIT_TAG }}
- name: Set up QEMU for smoke test
if: env.SHOULD_BUILD == 'true' && env.IS_LINUX == 'true'
uses: docker/setup-qemu-action@v4
# The binary is static, so binfmt+qemu runs it directly on the runner.
# Catches startup crashes in cross-compiled binaries before they ship,
# e.g. the broken ifunc relocations on 32-bit arm from issue #5738.
- name: Smoke-test binary
if: env.SHOULD_BUILD == 'true' && env.IS_LINUX == 'true'
run: |
BIN=./output/${{ env.PLATFORM }}/navidrome
chmod +x "$BIN"
"$BIN" --help >/dev/null
echo "OK: ${{ matrix.platform }} binary starts"
- name: Upload Binaries
if: env.SHOULD_BUILD == 'true'
uses: actions/upload-artifact@v7
with:
name: navidrome-${{ env.PLATFORM }}
path: ./output
retention-days: 7
- name: Build and push image by digest
id: push-image
if: env.SHOULD_BUILD == 'true' && env.IS_LINUX == 'true' && env.IS_DOCKER_PUSH_CONFIGURED == 'true' && env.IS_ARMV5 == 'false'
uses: docker/build-push-action@v7
with:
context: .
file: Dockerfile
platforms: ${{ matrix.platform }}
labels: ${{ steps.docker.outputs.labels }}
build-args: |
GIT_SHA=${{ env.GIT_SHA }}
GIT_TAG=${{ env.GIT_TAG }}
outputs: |
type=image,name=${{ steps.docker.outputs.hub_repository }},push-by-digest=true,name-canonical=true,push=${{ steps.docker.outputs.hub_enabled }}
type=image,name=ghcr.io/${{ github.repository }},push-by-digest=true,name-canonical=true,push=true
- name: Export digest
if: env.SHOULD_BUILD == 'true' && env.IS_LINUX == 'true' && env.IS_DOCKER_PUSH_CONFIGURED == 'true' && env.IS_ARMV5 == 'false'
run: |
mkdir -p /tmp/digests
digest="${{ steps.push-image.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v7
if: env.SHOULD_BUILD == 'true' && env.IS_LINUX == 'true' && env.IS_DOCKER_PUSH_CONFIGURED == 'true' && env.IS_ARMV5 == 'false'
with:
name: digests-${{ env.PLATFORM }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
push-manifest-ghcr:
name: Push to GHCR
permissions:
contents: read
packages: write
runs-on: ubuntu-latest
needs: [changes, build, check-push-enabled]
if: needs.check-push-enabled.outputs.is_enabled == 'true' && needs.changes.outputs.build == 'true'
env:
REGISTRY_IMAGE: ghcr.io/${{ github.repository }}
steps:
- uses: actions/checkout@v7
- name: Download digests
uses: actions/download-artifact@v8
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Prepare Docker Buildx
uses: ./.github/actions/prepare-docker
id: docker
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Create manifest list and push to ghcr.io
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map(select(startswith("ghcr.io"))) | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image in ghcr.io
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.docker.outputs.version }}
push-manifest-dockerhub:
name: Push to Docker Hub
runs-on: ubuntu-latest
permissions:
contents: read
needs: [changes, build, check-push-enabled]
if: needs.check-push-enabled.outputs.is_enabled == 'true' && vars.DOCKER_HUB_REPO != '' && needs.changes.outputs.build == 'true'
continue-on-error: true
steps:
- uses: actions/checkout@v7
- name: Download digests
uses: actions/download-artifact@v8
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Prepare Docker Buildx
uses: ./.github/actions/prepare-docker
id: docker
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
hub_repository: ${{ vars.DOCKER_HUB_REPO }}
hub_username: ${{ secrets.DOCKER_HUB_USERNAME }}
hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Create manifest list and push to Docker Hub
uses: nick-fields/retry@v4
with:
timeout_minutes: 5
max_attempts: 3
retry_wait_seconds: 30
command: |
cd /tmp/digests
docker buildx imagetools create $(jq -cr '.tags | map(select(startswith("ghcr.io") | not)) | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *)
- name: Inspect image in Docker Hub
run: |
docker buildx imagetools inspect ${{ vars.DOCKER_HUB_REPO }}:${{ steps.docker.outputs.version }}
cleanup-digests:
name: Cleanup digest artifacts
runs-on: ubuntu-latest
needs: [push-manifest-ghcr, push-manifest-dockerhub]
if: always() && needs.push-manifest-ghcr.result == 'success'
steps:
- name: Delete unnecessary digest artifacts
env:
GH_TOKEN: ${{ github.token }}
run: |
for artifact in $(gh api repos/${{ github.repository }}/actions/artifacts | jq -r '.artifacts[] | select(.name | startswith("digests-")) | .id'); do
gh api --method DELETE repos/${{ github.repository }}/actions/artifacts/$artifact
done
msi:
name: Build Windows installers
needs: [changes, build, git-version]
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
if: needs.changes.outputs.build == 'true'
- uses: actions/download-artifact@v8
if: needs.changes.outputs.build == 'true'
with:
path: ./binaries
pattern: navidrome-windows*
merge-multiple: true
- name: Install Wix
if: needs.changes.outputs.build == 'true'
run: sudo apt-get install -y wixl jq
- name: Build MSI
if: needs.changes.outputs.build == 'true'
env:
GIT_TAG: ${{ needs.git-version.outputs.git_tag }}
run: |
rm -rf binaries/msi
sudo GIT_TAG=$GIT_TAG release/wix/build_msi.sh ${GITHUB_WORKSPACE} 386
sudo GIT_TAG=$GIT_TAG release/wix/build_msi.sh ${GITHUB_WORKSPACE} amd64
du -h binaries/msi/*.msi
- name: Upload MSI files
if: needs.changes.outputs.build == 'true'
uses: actions/upload-artifact@v7
with:
name: navidrome-windows-installers
path: binaries/msi/*.msi
retention-days: 7
release:
name: Package/Release
needs: [changes, build, msi]
runs-on: ubuntu-latest
outputs:
package_list: ${{ steps.set-package-list.outputs.package_list }}
steps:
- uses: actions/checkout@v7
if: needs.changes.outputs.build == 'true'
with:
fetch-depth: 0
fetch-tags: true
- uses: actions/download-artifact@v8
if: needs.changes.outputs.build == 'true'
with:
path: ./binaries
pattern: navidrome-*
merge-multiple: true
- run: ls -lR ./binaries
if: needs.changes.outputs.build == 'true'
- name: Set RELEASE_FLAGS for snapshot releases
if: needs.changes.outputs.build == 'true' && env.IS_RELEASE == 'false'
run: echo 'RELEASE_FLAGS=--skip=publish --snapshot' >> $GITHUB_ENV
- name: Run GoReleaser
if: needs.changes.outputs.build == 'true'
uses: goreleaser/goreleaser-action@v7
with:
version: '2.16.0'
args: "release --clean -f release/goreleaser.yml ${{ env.RELEASE_FLAGS }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Remove build artifacts
if: needs.changes.outputs.build == 'true'
run: |
ls -l ./dist
rm ./dist/*.tar.gz ./dist/*.zip
- name: Upload all-packages artifact
if: needs.changes.outputs.build == 'true'
uses: actions/upload-artifact@v7
with:
name: packages
path: dist/navidrome_0*
- id: set-package-list
if: needs.changes.outputs.build == 'true'
name: Export list of generated packages
run: |
cd dist
set +x
ITEMS=$(ls navidrome_0* | sed 's/^navidrome_0[^_]*_linux_//' | jq -R -s -c 'split("\n")[:-1]')
echo $ITEMS
echo "package_list=${ITEMS}" >> $GITHUB_OUTPUT
upload-packages:
name: Upload Linux PKG
runs-on: ubuntu-latest
needs: [changes, release]
# Job-level skip is safe here: nothing needs this job, and fromJson would
# error on the empty package_list a skipped release leaves behind.
if: needs.changes.outputs.build == 'true'
strategy:
matrix:
item: ${{ fromJson(needs.release.outputs.package_list) }}
steps:
- name: Download all-packages artifact
uses: actions/download-artifact@v8
with:
name: packages
path: ./dist
- name: Upload all-packages artifact
uses: actions/upload-artifact@v7
with:
name: navidrome_linux_${{ matrix.item }}
path: dist/navidrome_0*_linux_${{ matrix.item }}
# delete-artifacts:
# name: Delete unused artifacts
# runs-on: ubuntu-latest
# needs: [upload-packages]
# steps:
# - name: Delete all-packages artifact
# env:
# GH_TOKEN: ${{ github.token }}
# run: |
# for artifact in $(gh api repos/${{ github.repository }}/actions/artifacts | jq -r '.artifacts[] | select(.name | startswith("packages")) | .id'); do
# gh api --method DELETE repos/${{ github.repository }}/actions/artifacts/$artifact
# done