diff --git a/.dockerignore b/.dockerignore index 8b4f1dbc5..cae903c18 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,5 +6,7 @@ data *.db testDB navidrome -navidrome.db navidrome.toml +tmp +!tmp/taglib +dist \ No newline at end of file diff --git a/.github/actions/download-taglib/action.yml b/.github/actions/download-taglib/action.yml new file mode 100644 index 000000000..ea6de8783 --- /dev/null +++ b/.github/actions/download-taglib/action.yml @@ -0,0 +1,23 @@ +name: 'Download TagLib' +description: 'Downloads and extracts the TagLib library, adding it to PKG_CONFIG_PATH' +inputs: + version: + description: 'Version of TagLib to download' + required: true + platform: + description: 'Platform to download TagLib for' + default: 'linux-amd64' +runs: + using: 'composite' + steps: + - name: Download TagLib + shell: bash + run: | + mkdir -p /tmp/taglib + cd /tmp + FILE=taglib-${{ inputs.platform }}.tar.gz + wget https://github.com/navidrome/cross-taglib/releases/download/v${{ inputs.version }}/${FILE} + tar -xzf ${FILE} -C taglib + PKG_CONFIG_PREFIX=/tmp/taglib + echo "PKG_CONFIG_PREFIX=${PKG_CONFIG_PREFIX}" >> $GITHUB_ENV + echo "PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:${PKG_CONFIG_PREFIX}/lib/pkgconfig" >> $GITHUB_ENV diff --git a/.github/actions/prepare-docker/action.yml b/.github/actions/prepare-docker/action.yml new file mode 100644 index 000000000..760a0528b --- /dev/null +++ b/.github/actions/prepare-docker/action.yml @@ -0,0 +1,84 @@ +name: 'Prepare Docker Buildx environment' +description: 'Downloads and extracts the TagLib library, adding it to PKG_CONFIG_PATH' +inputs: + github_token: + description: 'GitHub token' + required: true + default: '' + hub_repository: + description: 'Docker Hub repository to push images to' + required: false + default: '' + hub_username: + description: 'Docker Hub username' + required: false + default: '' + hub_password: + description: 'Docker Hub password' + required: false + default: '' +outputs: + tags: + description: 'Docker image tags' + value: ${{ steps.meta.outputs.tags }} + labels: + description: 'Docker image labels' + value: ${{ steps.meta.outputs.labels }} + annotations: + description: 'Docker image annotations' + value: ${{ steps.meta.outputs.annotations }} + version: + description: 'Docker image version' + value: ${{ steps.meta.outputs.version }} + hub_repository: + description: 'Docker Hub repository' + value: ${{ env.DOCKER_HUB_REPO }} + hub_enabled: + description: 'Is Docker Hub enabled' + value: ${{ env.DOCKER_HUB_ENABLED }} + +runs: + using: 'composite' + steps: + - name: Check Docker Hub configuration + shell: bash + run: | + if [ -z "${{inputs.hub_repository}}" ]; then + echo "DOCKER_HUB_REPO=none" >> $GITHUB_ENV + echo "DOCKER_HUB_ENABLED=false" >> $GITHUB_ENV + else + echo "DOCKER_HUB_REPO=${{inputs.hub_repository}}" >> $GITHUB_ENV + echo "DOCKER_HUB_ENABLED=true" >> $GITHUB_ENV + fi + + - name: Login to Docker Hub + if: inputs.hub_username != '' && inputs.hub_password != '' + uses: docker/login-action@v3 + with: + username: ${{ inputs.hub_username }} + password: ${{ inputs.hub_password }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ inputs.github_token }} + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract metadata for Docker image + id: meta + uses: docker/metadata-action@v5 + with: + labels: | + maintainer=deluan@navidrome.org + images: | + name=${{env.DOCKER_HUB_REPO}},enable=${{env.DOCKER_HUB_ENABLED}} + name=ghcr.io/${{ github.repository }} + tags: | + type=ref,event=pr + type=semver,pattern={{version}} + type=raw,value=develop,enable={{is_default_branch}} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 948a94643..327ab0dfc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,6 +11,11 @@ updates: interval: weekly open-pull-requests-limit: 10 - package-ecosystem: docker + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 +- package-ecosystem: github-actions directory: "/.github/workflows" schedule: interval: weekly diff --git a/.github/workflows/pipeline.dockerfile b/.github/workflows/pipeline.dockerfile deleted file mode 100644 index 649d1f234..000000000 --- a/.github/workflows/pipeline.dockerfile +++ /dev/null @@ -1,40 +0,0 @@ -##################################################### -### Copy platform specific binary -FROM bash as copy-binary -ARG TARGETPLATFORM - -RUN echo "Target Platform = ${TARGETPLATFORM}" - -COPY dist . -RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then cp navidrome_linux_amd64_linux_amd64_v1/navidrome /navidrome; fi -RUN if [ "$TARGETPLATFORM" = "linux/386" ]; then cp navidrome_linux_386_linux_386/navidrome /navidrome; fi -RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then cp navidrome_linux_arm64_linux_arm64/navidrome /navidrome; fi -RUN if [ "$TARGETPLATFORM" = "linux/arm/v6" ]; then cp navidrome_linux_arm_linux_arm_6/navidrome /navidrome; fi -RUN if [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then cp navidrome_linux_arm_linux_arm_7/navidrome /navidrome; fi -RUN chmod +x /navidrome - - -##################################################### -### Build Final Image -FROM alpine:3.20 -LABEL maintainer="deluan@navidrome.org" - -# Install ffmpeg and mpv -RUN apk add -U --no-cache ffmpeg mpv - -# Show ffmpeg build info, for troubleshooting purposes -RUN ffmpeg -buildconf - -COPY --from=copy-binary /navidrome /app/ - -VOLUME ["/data", "/music"] -ENV ND_MUSICFOLDER /music -ENV ND_DATAFOLDER /data -ENV ND_PORT 4533 -ENV GODEBUG "asyncpreemptoff=1" - -EXPOSE ${ND_PORT} -HEALTHCHECK CMD wget -O- http://localhost:${ND_PORT}/ping || exit 1 -WORKDIR /app - -ENTRYPOINT ["/app/navidrome"] diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 82ec0d95f..f05c12d8d 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -9,16 +9,56 @@ on: branches: - master +env: + CROSS_TAGLIB_VERSION: "2.0.2-1" + 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@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Get Git SHA and last Tag + id: git-version + run: | + GIT_TAG=$(git tag --sort=-committerdate | head -n 1) + if [ -n "$GIT_TAG" ]; then + GIT_TAG=${GIT_TAG}-SNAPSHOT + 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="pr-${PR_NUM}/${GIT_SHA}" + fi + echo "GIT_SHA=$GIT_SHA" >> $GITHUB_OUTPUT + + echo "GIT_TAG=$GIT_TAG" + echo "GIT_SHA=$GIT_SHA" + + echo "git describe (dirty): $(git describe --dirty --always --tags)" + echo "git describe --tags: $(git describe --tags `git rev-list --tags --max-count=1`)" + echo "git tag: $(git tag --sort=-committerdate | head -n 1)" + echo "git tag -l: $(git tag -l)" + go-lint: name: Lint Go code runs-on: ubuntu-latest - container: deluan/ci-goreleaser:1.23.2-1 steps: - uses: actions/checkout@v4 - - name: Config workspace folder as trusted - run: git config --global --add safe.directory $GITHUB_WORKSPACE; git describe --dirty --always --tags + - name: Download TagLib + uses: ./.github/actions/download-taglib + with: + version: ${{ env.CROSS_TAGLIB_VERSION }} - name: golangci-lint uses: golangci/golangci-lint-action@v6 @@ -27,10 +67,8 @@ jobs: problem-matchers: true args: --timeout 2m - - name: Install goimports - run: go install golang.org/x/tools/cmd/goimports@latest - - - run: goimports -w `find . -name '*.go' | grep -v '_gen.go$'` + - name: Run go goimports + run: go run golang.org/x/tools/cmd/goimports@latest -w `find . -name '*.go' | grep -v '_gen.go$'` - run: go mod tidy - name: Verify no changes from goimports and go mod tidy run: | @@ -39,28 +77,29 @@ jobs: echo 'To fix this check, run "make format" and commit the changes' exit 1 fi + go: name: Test Go code runs-on: ubuntu-latest - container: deluan/ci-goreleaser:1.23.2-1 steps: - name: Check out code into the Go module directory uses: actions/checkout@v4 - - name: Config workspace folder as trusted - run: git config --global --add safe.directory $GITHUB_WORKSPACE; git describe --dirty --always --tags + - name: Download TagLib + uses: ./.github/actions/download-taglib + with: + version: ${{ env.CROSS_TAGLIB_VERSION }} - name: Download dependencies - if: steps.cache-go.outputs.cache-hit != 'true' - continue-on-error: ${{contains(matrix.go_version, 'beta') || contains(matrix.go_version, 'rc')}} run: go mod download - name: Test - continue-on-error: ${{contains(matrix.go_version, 'beta') || contains(matrix.go_version, 'rc')}} - run: go test -shuffle=on -race -cover ./... -v + run: | + pkg-config --define-prefix --cflags --libs taglib # for debugging + go test -shuffle=on -race -cover ./... -v js: - name: Build JS bundle + name: Test JS code runs-on: ubuntu-latest env: NODE_OPTIONS: "--max_old_space_size=4096" @@ -92,12 +131,6 @@ jobs: cd ui npm run build - - uses: actions/upload-artifact@v4 - with: - name: js-bundle - path: ui/build - retention-days: 7 - i18n-lint: name: Lint i18n files runs-on: ubuntu-latest @@ -115,63 +148,180 @@ jobs: fi done - binaries: - name: Build binaries - needs: [js, go, go-lint, i18n-lint] + build: + name: Build + needs: [js, go, go-lint, i18n-lint, git-version] + strategy: + matrix: + platform: [ linux/amd64, linux/arm64, linux/arm/v5, linux/arm/v6, linux/arm/v7, linux/386, darwin/amd64, darwin/arm64, windows/amd64, windows/386 ] runs-on: ubuntu-latest - container: deluan/ci-goreleaser:1.23.2-1 + env: + IS_LINUX: ${{ startsWith(matrix.platform, 'linux/') && 'true' || 'false' }} + IS_DOCKER_PUSH_CONFIGURED: ${{ vars.DOCKER_HUB_REPO != '' && 'true' || 'false' }} + DOCKER_BUILD_SUMMARY: false + GIT_SHA: ${{ needs.git-version.outputs.git_sha }} + GIT_TAG: ${{ needs.git-version.outputs.git_tag }} steps: - - name: Checkout Code - uses: actions/checkout@v4 + - name: Sanitize platform name + id: set-platform + run: | + PLATFORM=$(echo ${{ matrix.platform }} | tr '/' '_') + echo "PLATFORM=$PLATFORM" >> $GITHUB_ENV + + - uses: actions/checkout@v4 + + - name: Prepare Docker Buildx + uses: ./.github/actions/prepare-docker + id: docker with: - fetch-depth: 0 + github_token: ${{ secrets.GITHUB_TOKEN }} + hub_repository: ${{ vars.DOCKER_HUB_REPO }} + hub_username: ${{ secrets.DOCKER_HUB_USERNAME }} + hub_password: ${{ secrets.DOCKER_HUB_PASSWORD }} - - name: Config workspace folder as trusted - run: git config --global --add safe.directory $GITHUB_WORKSPACE; git describe --dirty --always --tags - - - uses: actions/download-artifact@v4 + - name: Build Binaries + uses: docker/build-push-action@v6 with: - name: js-bundle - path: ui/build + 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 }} + CROSS_TAGLIB_VERSION=${{ env.CROSS_TAGLIB_VERSION }} - - name: Run GoReleaser - SNAPSHOT - if: startsWith(github.ref, 'refs/tags/') != true - run: goreleaser release --clean --skip=publish --snapshot - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Run GoReleaser - RELEASE - if: startsWith(github.ref, 'refs/tags/') - run: goreleaser release --clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: actions/upload-artifact@v4 + - name: Upload Binaries + uses: actions/upload-artifact@v4 with: - name: binaries - path: | - dist - !dist/*.tar.gz - !dist/*.zip + name: navidrome-${{ env.PLATFORM }} + path: ./output retention-days: 7 + - name: Build and push image by digest + id: push-image + if: env.IS_LINUX == 'true' && env.IS_DOCKER_PUSH_CONFIGURED == 'true' + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile + platforms: ${{ matrix.platform }} + labels: ${{ steps.docker.outputs.labels }} + build-args: | + GIT_SHA=${{ env.GIT_SHA }} + GIT_TAG=${{ env.GIT_TAG }} + CROSS_TAGLIB_VERSION=${{ env.CROSS_TAGLIB_VERSION }} + 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.IS_LINUX == 'true' && env.IS_DOCKER_PUSH_CONFIGURED == 'true' + run: | + mkdir -p /tmp/digests + digest="${{ steps.push-image.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + if: env.IS_LINUX == 'true' && env.IS_DOCKER_PUSH_CONFIGURED == 'true' + with: + name: digests-${{ env.PLATFORM }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + check-push-enabled: + name: Check Docker push + 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=${{ vars.DOCKER_HUB_REPO != '' }}" >> $GITHUB_OUTPUT + + push-manifest: + name: Push Docker manifest + runs-on: ubuntu-latest + needs: [build, check-push-enabled] + if: needs.check-push-enabled.outputs.is_enabled == 'true' + env: + REGISTRY_IMAGE: ghcr.io/${{ github.repository }} + steps: + - uses: actions/checkout@v4 + + - name: Download digests + uses: actions/download-artifact@v4 + 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 ghcr.io + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) + + - name: Create manifest list and push to Docker Hub + working-directory: /tmp/digests + if: vars.DOCKER_HUB_REPO != '' + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ vars.DOCKER_HUB_USERNAME }}@sha256:%s ' *) + + - name: Inspect image in ghcr.io + run: | + docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.docker.outputs.version }} + + - name: Inspect image in Docker Hub + if: vars.DOCKER_HUB_REPO != '' + run: | + docker buildx imagetools inspect ${{ vars.DOCKER_HUB_REPO }}:${{ steps.docker.outputs.version }} + + - 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 and publish MSI files - needs: [binaries] + name: Build Windows Installers + needs: [build, git-version] runs-on: ubuntu-24.04 + env: + GIT_SHA: ${{ needs.git-version.outputs.git_sha }} + GIT_TAG: ${{ needs.git-version.outputs.git_tag }} steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: - name: binaries - path: dist + path: ./binaries + pattern: navidrome-windows* + merge-multiple: true - - name: Build MSI + - name: Build MSI files run: | sudo apt-get install -y wixl jq - - NAVIDROME_BUILD_VERSION=$(jq -r '.version' < $GITHUB_WORKSPACE/dist/metadata.json | sed -e 's/^v//' -e 's/-SNAPSHOT/.1/' ) + + NAVIDROME_BUILD_VERSION=$(echo $GIT_TAG | sed -e 's/^v//' -e 's/-SNAPSHOT/.1/') + echo $NAVIDROME_BUILD_VERSION mkdir -p $GITHUB_WORKSPACE/wix/386 cp $GITHUB_WORKSPACE/LICENSE $GITHUB_WORKSPACE/wix/386 @@ -179,8 +329,8 @@ jobs: cp -r $GITHUB_WORKSPACE/wix/386 $GITHUB_WORKSPACE/wix/amd64 - cp $GITHUB_WORKSPACE/dist/navidrome_windows_386_windows_386/navidrome.exe $GITHUB_WORKSPACE/wix/386 - cp $GITHUB_WORKSPACE/dist/navidrome_windows_amd64_windows_amd64_v1/navidrome.exe $GITHUB_WORKSPACE/wix/amd64 + cp $GITHUB_WORKSPACE/binaries/windows_386/navidrome.exe $GITHUB_WORKSPACE/wix/386 + cp $GITHUB_WORKSPACE/binaries/windows_amd64/navidrome.exe $GITHUB_WORKSPACE/wix/amd64 # workaround for wixl WixVariable not working to override bmp locations sudo cp $GITHUB_WORKSPACE/wix/bmp/banner.bmp /usr/share/wixl-*/ext/ui/bitmaps/bannrbmp.bmp @@ -191,77 +341,39 @@ jobs: cd $GITHUB_WORKSPACE/wix/amd64 wixl ../navidrome.wxs -D Version=$NAVIDROME_BUILD_VERSION -D Platform=x64 --arch x64 --ext ui --output ../navidrome_amd64.msi - + ls -la $GITHUB_WORKSPACE/wix/*.msi - - uses: actions/upload-artifact@v4 + - name: Upload MSI files + uses: actions/upload-artifact@v4 with: - name: installers + name: navidrome-windows-installers path: wix/*.msi retention-days: 7 - docker: - name: Build and publish Docker images - needs: [binaries] + release: + name: Release + needs: [build, msi, push-manifest] runs-on: ubuntu-latest - env: - DOCKER_IMAGE: ${{secrets.DOCKER_IMAGE}} steps: - - name: Set up QEMU - id: qemu - uses: docker/setup-qemu-action@v3 - if: env.DOCKER_IMAGE != '' - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - if: env.DOCKER_IMAGE != '' - - uses: actions/checkout@v4 - if: env.DOCKER_IMAGE != '' - uses: actions/download-artifact@v4 - if: env.DOCKER_IMAGE != '' with: - name: binaries - path: dist + path: ./binaries + pattern: navidrome-* + merge-multiple: true - - name: Login to Docker Hub - if: env.DOCKER_IMAGE != '' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} + - run: ls -lR ./binaries - - name: Login to GitHub Container Registry - if: env.DOCKER_IMAGE != '' - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Set RELEASE_FLAGS for snapshot releases + if: env.IS_RELEASE == 'false' + run: echo 'RELEASE_FLAGS=--skip=publish --snapshot' >> $GITHUB_ENV - - name: Extract metadata for Docker - if: env.DOCKER_IMAGE != '' - id: meta - uses: docker/metadata-action@v5 + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 with: - labels: | - maintainer=deluan - images: | - name=${{secrets.DOCKER_IMAGE}} - name=ghcr.io/${{ github.repository }} - tags: | - type=ref,event=pr - type=semver,pattern={{version}} - type=raw,value=develop,enable={{is_default_branch}} - - - name: Build and Push - if: env.DOCKER_IMAGE != '' - uses: docker/build-push-action@v5 - with: - context: . - file: .github/workflows/pipeline.dockerfile - platforms: linux/amd64,linux/386,linux/arm/v6,linux/arm/v7,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} + version: '~> v2' + args: "release --clean -f release/goreleaser.yml ${{ env.RELEASE_FLAGS }}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 7b97fcb2f..37999c3f9 100644 --- a/.gitignore +++ b/.gitignore @@ -13,16 +13,13 @@ var navidrome.toml master.zip testDB -navidrome.db cache/* *.swp -embedded_gen.go dist music -navidrome.db-shm -navidrome.db-wal -tags +*.db* .gitinfo docker-compose.yml !contrib/docker-compose.yml -test-123.db +binaries +taglib \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml deleted file mode 100644 index 000671390..000000000 --- a/.goreleaser.yml +++ /dev/null @@ -1,172 +0,0 @@ -# GoReleaser config -project_name: navidrome -version: 2 - -builds: - - id: navidrome_linux_amd64 - env: - - CGO_ENABLED=1 - goos: - - linux - goarch: - - amd64 - flags: - - -tags=netgo - ldflags: - - "-extldflags '-static -lz'" - - -s -w -X github.com/navidrome/navidrome/consts.gitSha={{.ShortCommit}} -X github.com/navidrome/navidrome/consts.gitTag={{.Version}} - - - id: navidrome_linux_386 - env: - - CGO_ENABLED=1 - - PKG_CONFIG_PATH=/i386/lib/pkgconfig - goos: - - linux - goarch: - - "386" - flags: - - -tags=netgo - ldflags: - - "-extldflags '-static'" - - -s -w -X github.com/navidrome/navidrome/consts.gitSha={{.ShortCommit}} -X github.com/navidrome/navidrome/consts.gitTag={{.Version}} - - - id: navidrome_linux_arm - env: - - CGO_ENABLED=1 - - CC=arm-linux-gnueabi-gcc - - CXX=arm-linux-gnueabi-g++ - - PKG_CONFIG_PATH=/arm/lib/pkgconfig - goos: - - linux - goarch: - - arm - goarm: - - "5" - - "6" - - "7" - flags: - - -tags=netgo - ldflags: - - "-extldflags '-static'" - - -s -w -X github.com/navidrome/navidrome/consts.gitSha={{.ShortCommit}} -X github.com/navidrome/navidrome/consts.gitTag={{.Version}} - - - id: navidrome_linux_arm64 - env: - - CGO_ENABLED=1 - - CC=aarch64-linux-gnu-gcc - - CXX=aarch64-linux-gnu-g++ - - PKG_CONFIG_PATH=/arm64/lib/pkgconfig - goos: - - linux - goarch: - - arm64 - flags: - - -tags=netgo - ldflags: - - "-extldflags '-static'" - - -s -w -X github.com/navidrome/navidrome/consts.gitSha={{.ShortCommit}} -X github.com/navidrome/navidrome/consts.gitTag={{.Version}} - - - id: navidrome_windows_386 - env: - - CGO_ENABLED=1 - - CC=i686-w64-mingw32-gcc - - CXX=i686-w64-mingw32-g++ - - PKG_CONFIG_PATH=/mingw32/lib/pkgconfig - goos: - - windows - goarch: - - "386" - flags: - - -tags=netgo - ldflags: - - "-extldflags '-static'" - - -s -w -X github.com/navidrome/navidrome/consts.gitSha={{.ShortCommit}} -X github.com/navidrome/navidrome/consts.gitTag={{.Version}} - - - id: navidrome_windows_amd64 - env: - - CGO_ENABLED=1 - - CC=x86_64-w64-mingw32-gcc - - CXX=x86_64-w64-mingw32-g++ - - PKG_CONFIG_PATH=/mingw64/lib/pkgconfig - goos: - - windows - goarch: - - amd64 - flags: - - -tags=netgo - ldflags: - - "-extldflags '-static'" - - -s -w -X github.com/navidrome/navidrome/consts.gitSha={{.ShortCommit}} -X github.com/navidrome/navidrome/consts.gitTag={{.Version}} - - - id: navidrome_darwin_amd64 - env: - - CGO_ENABLED=1 - - CC=o64-clang - - CXX=o64-clang++ - - PKG_CONFIG_PATH=/darwin/lib/pkgconfig - goos: - - darwin - goarch: - - amd64 - flags: - - -tags=netgo - ldflags: - - -s -w -X github.com/navidrome/navidrome/consts.gitSha={{.ShortCommit}} -X github.com/navidrome/navidrome/consts.gitTag={{.Version}} - -archives: - - format_overrides: - - goos: windows - format: zip - -checksum: - name_template: "{{ .ProjectName }}_checksums.txt" - -snapshot: - version_template: "{{ .Tag }}-SNAPSHOT" - -release: - draft: true - mode: append - footer: | - **Full Changelog**: https://github.com/navidrome/navidrome/compare/{{ .PreviousTag }}...{{ .Tag }} - - ## Helping out - - This release is only possible thanks to the support of some **awesome people**! - - Want to be one of them? - You can [sponsor](https://github.com/sponsors/deluan), pay me a [Ko-fi](https://ko-fi.com/deluan) or [contribute with code](https://www.navidrome.org/docs/developers/). - - ## Where to go next? - - * Read installation instructions on our [website](https://www.navidrome.org/docs/installation/). - * Reach out on [Discord](https://discord.gg/xh7j7yF), [Reddit](https://www.reddit.com/r/navidrome/) and [Twitter](https://twitter.com/navidrome)! - -changelog: - sort: asc - use: github - filters: - exclude: - - "^test:" - - Merge pull request - - Merge remote-tracking branch - - Merge branch - - go mod tidy - groups: - - title: "New Features" - regexp: '^.*?feat(\(.+\))??!?:.+$' - order: 100 - - title: "Security updates" - regexp: '^.*?sec(\(.+\))??!?:.+$' - order: 150 - - title: "Bug fixes" - regexp: '^.*?(fix|refactor)(\(.+\))??!?:.+$' - order: 200 - - title: "Documentation updates" - regexp: ^.*?docs?(\(.+\))??!?:.+$ - order: 400 - - title: "Build process updates" - regexp: ^.*?(build|ci)(\(.+\))??!?:.+$ - order: 400 - - title: Other work - order: 9999 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..60b0a6688 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,115 @@ +FROM --platform=$BUILDPLATFORM crazymax/osxcross:14.5-debian AS osxcross +FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.5.0 AS xx + +##################################################### +### Get TagLib +FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/alpine:3.20 AS taglib-build +ARG TARGETPLATFORM +ARG CROSS_TAGLIB_VERSION=2.0.2-1 +ENV CROSS_TAGLIB_RELEASES_URL=https://github.com/navidrome/cross-taglib/releases/download/v${CROSS_TAGLIB_VERSION}/ + +RUN PLATFORM=$(echo ${TARGETPLATFORM} | tr '/' '-') \ + FILE=taglib-${PLATFORM}.tar.gz && \ + DOWNLOAD_URL=${CROSS_TAGLIB_RELEASES_URL}${FILE} && \ + wget ${DOWNLOAD_URL}; \ + mkdir /taglib && \ + tar -xzf ${FILE} -C /taglib + +##################################################### +### Build Navidrome UI +FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/node:lts-alpine3.20 AS ui +WORKDIR /app + +# Install node dependencies +COPY ui/package.json ui/package-lock.json ./ +RUN npm ci + +# Build bundle +COPY ui/ ./ +RUN npm run build -- --outDir=/build + +FROM scratch AS ui-bundle +COPY --from=ui /build /build + +##################################################### +### Build Navidrome binary +FROM --platform=$BUILDPLATFORM public.ecr.aws/docker/library/golang:1.23-bookworm AS base +RUN apt-get update && apt-get install -y clang lld +COPY --from=xx / / +WORKDIR /workspace + +FROM --platform=$BUILDPLATFORM base AS build + +# Install build dependencies for the target platform +ARG TARGETPLATFORM +ARG GIT_SHA +ARG GIT_TAG + +RUN xx-apt install -y binutils gcc g++ libc6-dev zlib1g-dev +RUN xx-verify --setup + +RUN --mount=type=bind,source=. \ + --mount=type=cache,target=/root/.cache \ + --mount=type=cache,target=/go/pkg/mod \ + go mod download + +RUN --mount=type=bind,source=. \ + --mount=from=ui,source=/build,target=./ui/build,ro \ + --mount=from=osxcross,src=/osxcross/SDK,target=/xx-sdk,ro \ + --mount=type=cache,target=/root/.cache \ + --mount=type=cache,target=/go/pkg/mod \ + --mount=from=taglib-build,target=/taglib,src=/taglib,ro < GOARCH= make single"; \ - echo "Options:"; \ - grep -- "- id: navidrome_" .goreleaser.yml | sed 's/- id: navidrome_//g'; \ - exit 1; \ - fi - @echo "Building binaries for ${GOOS}/${GOARCH} using builder ${CI_RELEASER_VERSION}" - docker run -t -v $(PWD):/workspace -e GOOS -e GOARCH -w /workspace deluan/ci-goreleaser:$(CI_RELEASER_VERSION) \ - goreleaser build --clean --snapshot -p 2 --single-target --id navidrome_${GOOS}_${GOARCH} -.PHONY: single +docker-build: ##@Cross_Compilation Cross-compile for any supported platform (check `make list-platforms`) + docker build \ + --platform $(PLATFORMS) \ + --build-arg GIT_TAG=${GIT_TAG} \ + --build-arg GIT_SHA=${GIT_SHA} \ + --build-arg CROSS_TAGLIB_VERSION=${CROSS_TAGLIB_VERSION} \ + --output "./dist" --target binary . +.PHONY: docker-build -docker: buildjs ##@Build Build Docker linux/amd64 image (tagged as `deluan/navidrome:develop`) - GOOS=linux GOARCH=amd64 make single - @echo "Building Docker image" - docker build . --platform linux/amd64 -t deluan/navidrome:develop -f .github/workflows/pipeline.dockerfile -.PHONY: docker +docker-image: ##@Cross_Compilation Build Docker image, tagged as `deluan/navidrome:develop`, override with DOCKER_TAG var. Use IMAGE_PLATFORMS to specify target platforms + @echo $(IMAGE_PLATFORMS) | grep -q "windows" && echo "ERROR: Windows is not supported for Docker builds" && exit 1 || true + @echo $(IMAGE_PLATFORMS) | grep -q "darwin" && echo "ERROR: macOS is not supported for Docker builds" && exit 1 || true + docker build \ + --platform $(IMAGE_PLATFORMS) \ + --build-arg GIT_TAG=${GIT_TAG} \ + --build-arg GIT_SHA=${GIT_SHA} \ + --build-arg CROSS_TAGLIB_VERSION=${CROSS_TAGLIB_VERSION} \ + --tag $(DOCKER_TAG) . +.PHONY: docker-image get-music: ##@Development Download some free music from Navidrome's demo instance mkdir -p music diff --git a/release/goreleaser.yml b/release/goreleaser.yml new file mode 100644 index 000000000..91f9b98bb --- /dev/null +++ b/release/goreleaser.yml @@ -0,0 +1,88 @@ +# GoReleaser config +project_name: navidrome +version: 2 + +builds: + - id: navidrome + # Instead of compiling the binary with goreleaser, we just copy it from `binaries` folder + # This is because we need to compile the binaries with our Dockerfile, and to avoid having to + # compile it twice, we just copy the docker build output.env. The xxgo script handles this for us + gobinary: "./release/xxgo" + + # All available targets compiled by the Dockerfile + targets: + - darwin_amd64 + - darwin_arm64 + - linux_386 + - linux_amd64 + - linux_arm_v5 + - linux_arm_v6 + - linux_arm_v7 + - linux_arm64 + - windows_386 + - windows_amd64 + +archives: + - format_overrides: + - goos: windows + format: zip + +checksum: + name_template: "{{ .ProjectName }}_checksums.txt" + +snapshot: + version_template: "{{ .Tag }}-SNAPSHOT" + +release: + draft: true + mode: append + footer: | + **Full Changelog**: https://github.com/navidrome/navidrome/compare/{{ .PreviousTag }}...{{ .Tag }} + + ## Helping out + + This release is only possible thanks to the support of some **awesome people**! + + Want to be one of them? + You can [sponsor](https://github.com/sponsors/deluan), pay me a [Ko-fi](https://ko-fi.com/deluan) or [contribute with code](https://www.navidrome.org/docs/developers/). + + ## Where to go next? + + * Read installation instructions on our [website](https://www.navidrome.org/docs/installation/). + * Reach out on [Discord](https://discord.gg/xh7j7yF), [Reddit](https://www.reddit.com/r/navidrome/) and [Twitter](https://twitter.com/navidrome)! + + # Add the MSI installers to the release + extra_files: + - glob: binaries/navidrome_386.msi + name_template: navidrome_{{.Version}}_windows_386_installer.msi + - glob: binaries/navidrome_amd64.msi + name_template: navidrome_{{.Version}}_windows_amd64_installer.msi + +changelog: + sort: asc + use: github + filters: + exclude: + - "^test:" + - Merge pull request + - Merge remote-tracking branch + - Merge branch + - go mod tidy + groups: + - title: "New Features" + regexp: '^.*?feat(\(.+\))??!?:.+$' + order: 100 + - title: "Security updates" + regexp: '^.*?sec(\(.+\))??!?:.+$' + order: 150 + - title: "Bug fixes" + regexp: '^.*?(fix|refactor)(\(.+\))??!?:.+$' + order: 200 + - title: "Documentation updates" + regexp: ^.*?docs?(\(.+\))??!?:.+$ + order: 400 + - title: "Build process updates" + regexp: ^.*?(build|ci)(\(.+\))??!?:.+$ + order: 400 + - title: Other work + order: 9999 diff --git a/release/xxgo b/release/xxgo new file mode 100755 index 000000000..15a537f24 --- /dev/null +++ b/release/xxgo @@ -0,0 +1,16 @@ +#!/bin/bash + +# Use sed to extract the value of the -o parameter +output=$(echo "$@" | sed -n 's/.*-o \([^ ]*\).*/\1/p') + +# Ensure the directory part of the output exists +mkdir -p "$(dirname "$output")" + +# Build the source folder name based on GOOS, GOARCH and GOARM. +source="${GOOS}_${GOARCH}" +if [ "$GOARCH" = "arm" ]; then + source="${source}_${GOARM}" +fi + +# Copy the output to the desired location +cp binaries/"${source}"/navidrome* "$output" \ No newline at end of file diff --git a/scanner/metadata/taglib/taglib_wrapper.go b/scanner/metadata/taglib/taglib_wrapper.go index 888c6ac8c..01fea25ef 100644 --- a/scanner/metadata/taglib/taglib_wrapper.go +++ b/scanner/metadata/taglib/taglib_wrapper.go @@ -1,7 +1,7 @@ package taglib /* -#cgo pkg-config: taglib +#cgo pkg-config: --define-prefix taglib #cgo illumos LDFLAGS: -lstdc++ -lsendfile #cgo linux darwin CXXFLAGS: -std=c++11 #cgo darwin LDFLAGS: -L/opt/homebrew/opt/taglib/lib