name: Build Syncthing on: pull_request: push: branches-ignore: - release - release-rc* workflow_call: workflow_dispatch: env: # The go version to use for builds. We set check-latest to true when # installing, so we get the latest patch version that matches the # expression. GO_VERSION: "~1.24.0" # Optimize compatibility on the slow architectures. GOMIPS: softfloat GOARM: "6" # Avoid hilarious amounts of obscuring log output when running tests. LOGGER_DISCARD: "1" # Our build metadata BUILD_USER: builder BUILD_HOST: github.syncthing.net TAGS: "netgo osusergo sqlite_omit_load_extension sqlite_dbstat" # A note on actions and third party code... The actions under actions/ (like # `uses: actions/checkout`) are maintained by GitHub, and we need to trust # GitHub to maintain their code and infrastructure or we're in deep shit in # general. The same doesn't necessarily apply to other actions authors, so # some care needs to be taken when adding steps, especially in the paths # that lead up to code being packaged and signed. jobs: # # Source # facts: name: Gather common facts runs-on: ubuntu-latest outputs: version: ${{ steps.get-version.outputs.version }} release-kind: ${{ steps.get-version.outputs.release-kind }} release-generation: ${{ steps.get-version.outputs.release-generation }} go-version: ${{ steps.get-go.outputs.go-version }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882 - uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} cache: false check-latest: true - name: Get Syncthing version id: get-version run: | version=$(go run build.go version) echo "version=$version" >> "$GITHUB_OUTPUT" echo "Version: $version" kind=stable if [[ $version == *-rc.[0-9] || $version == *-rc.[0-9][0-9] ]] ; then kind=candidate elif [[ $version == *-* ]] ; then kind=nightly fi echo "release-kind=$kind" >> "$GITHUB_OUTPUT" echo "Release kind: $kind" generation=v1 if [[ $version == v2.* ]] ; then generation=v2 fi echo "release-generation=$generation" >> "$GITHUB_OUTPUT" echo "Release generation: $generation" - name: Get Go version id: get-go run: | go version echo "go-version=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_OUTPUT # # Tests for all platforms. Runs a matrix build on Windows, Linux and Mac, # with the list of expected supported Go versions (current, previous). # build-test: name: Build and test strategy: fail-fast: false matrix: runner: ["windows-latest", "ubuntu-latest", "macos-latest"] # The oldest version in this list should match what we have in our go.mod. # Variables don't seem to be supported here, or we could have done something nice. go: ["~1.23.0", "~1.24.0"] runs-on: ${{ matrix.runner }} steps: - name: Set git to use LF if: matrix.runner == 'windows-latest' # Without this, the Windows checkout will happen with CRLF line # endings, which is fine for the source code but messes up tests # that depend on data on disk being as expected. Ideally, those # tests should be fixed, but not today. run: | git config --global core.autocrlf false git config --global core.eol lf - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} cache: true check-latest: true - name: Build run: | go run build.go - name: Install go-test-json-to-loki run: | go install calmh.dev/go-test-json-to-loki@latest - name: Test run: | go version go run build.go test | go-test-json-to-loki env: GOFLAGS: "-json" LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_USER: ${{ secrets.LOKI_USER }} LOKI_PASSWORD: ${{ secrets.LOKI_PASSWORD }} LOKI_LABELS: "go=${{ matrix.go }},runner=${{ matrix.runner }},repo=${{ github.repository }},ref=${{ github.ref }}" CGO_ENABLED: "1" # # The basic checks job is a virtual one that depends on the matrix tests, # the correctness checks, and various builds that we always do. This makes # it easy to have the PR process have a single test as a gatekeeper for # merging, instead of having to add all the matrix tests and update them # each time the version changes. (The top level test is not available for # choosing there, only the matrix "children".) # basics: name: Basic checks passed runs-on: ubuntu-latest needs: - build-test - package-linux - package-cross - package-source - package-debian - package-windows - govulncheck - golangci - meta steps: - uses: actions/checkout@v4 # # Windows # package-windows: name: Package for Windows runs-on: ubuntu-latest needs: - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - uses: mlugg/setup-zig@v2 - uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-windows-${{ hashFiles('**/go.sum') }} - name: Install dependencies run: | go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.4.0 - name: Create packages run: | for tgt in syncthing stdiscosrv strelaysrv ; do go run build.go -tags "${{env.TAGS}}" -goos windows -goarch amd64 -cc "zig cc -target x86_64-windows" zip $tgt go run build.go -tags "${{env.TAGS}}" -goos windows -goarch 386 -cc "zig cc -target x86-windows" zip $tgt go run build.go -tags "${{env.TAGS}}" -goos windows -goarch arm64 -cc "zig cc -target aarch64-windows" zip $tgt # go run build.go -tags "${{env.TAGS}}" -goos windows -goarch arm -cc "zig cc -target thumb-windows" zip $tgt # fails with linker errors done env: CGO_ENABLED: "1" - name: Archive artifacts uses: actions/upload-artifact@v4 with: name: unsigned-packages-windows path: "*.zip" # # Codesign binaries for Windows. This job runs only when called in the # Syncthing repo for release branches and tags, as it requires our # specific code signing keys etc. # codesign-windows: name: Codesign for Windows if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v')) environment: release runs-on: windows-latest needs: - package-windows steps: - name: Download artifacts uses: actions/download-artifact@v4 with: name: unsigned-packages-windows path: packages - name: Extract packages working-directory: packages run: | $files = Get-ChildItem "." -Filter *.zip foreach ($file in $files) { 7z x $file.Name } - name: Sign files with Trusted Signing uses: azure/trusted-signing-action@v0.5.1 with: azure-tenant-id: ${{ secrets.AZURE_TRUSTED_SIGNING_TENANT_ID }} azure-client-id: ${{ secrets.AZURE_TRUSTED_SIGNING_CLIENT_ID }} azure-client-secret: ${{ secrets.AZURE_TRUSTED_SIGNING_CLIENT_SECRET }} endpoint: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }} trusted-signing-account-name: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT }} certificate-profile-name: ${{ secrets.AZURE_TRUSTED_SIGNING_PROFILE }} files-folder: ${{ github.workspace }}\packages files-folder-filter: exe files-folder-recurse: true file-digest: SHA256 timestamp-rfc3161: http://timestamp.acs.microsoft.com timestamp-digest: SHA256 - name: Repackage packages working-directory: packages run: | $files = Get-ChildItem "." -Filter *.zip foreach ($file in $files) { Remove-Item $file.Name 7z a -tzip $file.Name $file.BaseName } - name: Archive artifacts uses: actions/upload-artifact@v4 with: name: packages-windows path: "packages/*.zip" # # Linux # package-linux: name: Package for Linux runs-on: ubuntu-latest needs: - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - uses: mlugg/setup-zig@v2 - uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-${{ hashFiles('**/go.sum') }} - name: Create packages run: | sudo apt-get install -y gcc-mips64-linux-gnuabi64 gcc-mips64el-linux-gnuabi64 for tgt in syncthing stdiscosrv strelaysrv ; do go run build.go -tags "${{env.TAGS}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch 386 -cc "zig cc -target x86-linux-musl" tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch arm -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips -cc "zig cc -target mips-linux-musleabi" tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mipsle -cc "zig cc -target mipsel-linux-musleabi" tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips64 -cc mips64-linux-gnuabi64-gcc tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch mips64le -cc mips64el-linux-gnuabi64-gcc tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch riscv64 -cc "zig cc -target riscv64-linux-musl" tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch s390x -cc "zig cc -target s390x-linux-musl" tar "$tgt" go run build.go -tags "${{env.TAGS}}" -goos linux -goarch loong64 -cc "zig cc -target loongarch64-linux-musl" tar "$tgt" # go run build.go -tags "${{env.TAGS}}" -goos linux -goarch ppc64 -cc "zig cc -target powerpc64-linux-musl" tar "$tgt" # fails with linkmode not supported go run build.go -tags "${{env.TAGS}}" -goos linux -goarch ppc64le -cc "zig cc -target powerpc64le-linux-musl" tar "$tgt" done env: CGO_ENABLED: "1" EXTRA_LDFLAGS: "-linkmode=external -extldflags=-static" - name: Archive artifacts uses: actions/upload-artifact@v4 with: name: packages-linux path: | *.tar.gz compat.json # # macOS. The entire build runs in the release environment because code # signing is part of the build process, so it is limited to release # branches on the Syncthing repo. # package-macos: name: Package for macOS if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v')) environment: release runs-on: macos-latest needs: - facts env: CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }} VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-package-${{ hashFiles('**/go.sum') }} - name: Import signing certificate if: env.CODESIGN_IDENTITY != '' run: | # Set up a run-specific keychain, making it available for the # `codesign` tool. umask 066 KEYCHAIN_PATH=$RUNNER_TEMP/codesign.keychain KEYCHAIN_PASSWORD=$(uuidgen) security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security default-keychain -s "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" # Import the certificate CERTIFICATE_PATH=$RUNNER_TEMP/codesign.p12 echo "$DEVELOPER_ID_CERTIFICATE_BASE64" | base64 -d -o "$CERTIFICATE_PATH" security import "$CERTIFICATE_PATH" -k "$KEYCHAIN_PATH" -P "$DEVELOPER_ID_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign security set-key-partition-list -S apple-tool:,apple: -s -k actions "$KEYCHAIN_PATH" # Set the codesign identity for following steps echo "CODESIGN_IDENTITY=$CODESIGN_IDENTITY" >> $GITHUB_ENV env: DEVELOPER_ID_CERTIFICATE_BASE64: ${{ secrets.DEVELOPER_ID_CERTIFICATE_BASE64 }} DEVELOPER_ID_CERTIFICATE_PASSWORD: ${{ secrets.DEVELOPER_ID_CERTIFICATE_PASSWORD }} CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }} - name: Create package (amd64) run: | for tgt in syncthing stdiscosrv strelaysrv ; do go run build.go -tags "${{env.TAGS}}" -goarch amd64 zip "$tgt" done env: CGO_ENABLED: "1" - name: Create package (arm64 cross) run: | cat < xgo.sh #!/bin/bash CGO_ENABLED=1 \ CGO_CFLAGS="-target arm64-apple-macos10.15" \ CGO_LDFLAGS="-target arm64-apple-macos10.15" \ go "\$@" EOT chmod 755 xgo.sh for tgt in syncthing stdiscosrv strelaysrv ; do go run build.go -tags "${{env.TAGS}}" -gocmd ./xgo.sh -goarch arm64 zip "$tgt" done env: CGO_ENABLED: "1" - name: Create package (universal) run: | rm -rf _tmp mkdir _tmp pushd _tmp unzip ../syncthing-macos-amd64-*.zip unzip ../syncthing-macos-arm64-*.zip lipo -create syncthing-macos-amd64-*/syncthing syncthing-macos-arm64-*/syncthing -o syncthing amd64=(syncthing-macos-amd64-*) universal="${amd64/amd64/universal}" mv "$amd64" "$universal" mv syncthing "$universal" zip -r "../$universal.zip" "$universal" - name: Archive artifacts uses: actions/upload-artifact@v4 with: name: packages-macos path: "*.zip" notarize-macos: name: Notarize for macOS if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v')) environment: release needs: - package-macos runs-on: macos-latest steps: - name: Download artifacts uses: actions/download-artifact@v4 with: name: packages-macos - name: Notarize binaries run: | APPSTORECONNECT_API_KEY_PATH="$RUNNER_TEMP/apikey.p8" echo "$APPSTORECONNECT_API_KEY" | base64 -d -o "$APPSTORECONNECT_API_KEY_PATH" for file in *-macos-*.zip ; do xcrun notarytool submit \ -k "$APPSTORECONNECT_API_KEY_PATH" \ -d "$APPSTORECONNECT_API_KEY_ID" \ -i "$APPSTORECONNECT_API_KEY_ISSUER" \ $file done env: APPSTORECONNECT_API_KEY: ${{ secrets.APPSTORECONNECT_API_KEY }} APPSTORECONNECT_API_KEY_ID: ${{ secrets.APPSTORECONNECT_API_KEY_ID }} APPSTORECONNECT_API_KEY_ISSUER: ${{ secrets.APPSTORECONNECT_API_KEY_ISSUER }} # # Cross compile other unixes # package-cross: name: Package cross compiled runs-on: ubuntu-latest needs: - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-cross-${{ hashFiles('**/go.sum') }} - name: Create packages run: | platforms=$(go tool dist list \ | grep -v aix/ppc64 \ | grep -v android/ \ | grep -v darwin/ \ | grep -v ios/ \ | grep -v js/ \ | grep -v linux/ \ | grep -v nacl/ \ | grep -v plan9/ \ | grep -v windows/ \ | grep -v /wasm \ ) # Build for each platform with errors silenced, because we expect # some oddball platforms to fail. This avoids a bunch of errors in # the GitHub Actions output, instead summarizing each build # failure as a warning. for plat in $platforms; do goos="${plat%/*}" goarch="${plat#*/}" echo "::group ::$plat" for tgt in syncthing stdiscosrv strelaysrv ; do if ! go run build.go -goos "$goos" -goarch "$goarch" tar "$tgt" ; then echo "::warning ::Failed to build $tgt for $plat" fi done echo "::endgroup::" done env: CGO_ENABLED: "0" - name: Archive artifacts uses: actions/upload-artifact@v4 with: name: packages-other path: "*.tar.gz" # # Source # package-source: name: Package source code runs-on: ubuntu-latest needs: - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - name: Package source run: | echo "$VERSION" > RELEASE go mod vendor go run build.go assets cd .. tar c -z -f "syncthing-source-$VERSION.tar.gz" \ --exclude .git \ syncthing mv "syncthing-source-$VERSION.tar.gz" syncthing - name: Archive artifacts uses: actions/upload-artifact@v4 with: name: packages-source path: syncthing-source-*.tar.gz # # Sign binaries for auto upgrade, generate ASC signature files # sign-for-upgrade: name: Sign for upgrade if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v')) environment: release needs: - codesign-windows - package-linux - package-macos - package-cross - package-source - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/checkout@v4 with: repository: syncthing/release-tools path: tools - name: Download artifacts uses: actions/download-artifact@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - name: Install signing tool run: | go install ./cmd/dev/stsigtool - name: Sign archives run: | export PRIVATE_KEY="$RUNNER_TEMP/privkey.pem" export PATH="$PATH:$(go env GOPATH)/bin" echo "$STSIGTOOL_PRIVATE_KEY" | base64 -d > "$PRIVATE_KEY" mkdir packages mv packages-*/* packages pushd packages "$GITHUB_WORKSPACE/tools/sign-only" rm -f "$PRIVATE_KEY" env: STSIGTOOL_PRIVATE_KEY: ${{ secrets.STSIGTOOL_PRIVATE_KEY }} - name: Create shasum files run: | pushd packages files=(*.tar.gz *.zip) sha1sum "${files[@]}" > sha1sum.txt sha256sum "${files[@]}" > sha256sum.txt popd - name: Sign shasum files uses: docker://ghcr.io/kastelo/ezapt:latest with: args: sign packages/sha1sum.txt packages/sha256sum.txt env: EZAPT_KEYRING_BASE64: ${{ secrets.APT_GPG_KEYRING_BASE64 }} - name: Sign source uses: docker://ghcr.io/kastelo/ezapt:latest with: args: sign --detach --ascii packages/syncthing-source-${{ env.VERSION }}.tar.gz env: EZAPT_KEYRING_BASE64: ${{ secrets.APT_GPG_KEYRING_BASE64 }} - name: Archive artifacts uses: actions/upload-artifact@v4 with: name: packages-signed path: | packages/*.tar.gz packages/*.zip packages/*.asc packages/*.json # # Debian # package-debian: name: Package for Debian runs-on: ubuntu-latest needs: - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - uses: ruby/setup-ruby@v1 with: ruby-version: '3.0' - name: Install fpm run: | gem install fpm - uses: mlugg/setup-zig@v2 - uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-debian-${{ hashFiles('**/go.sum') }} - name: Package for Debian (CGO) run: | for tgt in syncthing stdiscosrv strelaysrv ; do go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch amd64 -cc "zig cc -target x86_64-linux-musl" deb "$tgt" go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch armel -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt" go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch armhf -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" deb "$tgt" go run build.go -no-upgrade -installsuffix=no-upgrade -tags "${{env.TAGS}}" -goos linux -goarch arm64 -cc "zig cc -target aarch64-linux-musl" deb "$tgt" done env: BUILD_USER: debian CGO_ENABLED: "1" EXTRA_LDFLAGS: "-linkmode=external -extldflags=-static" - name: Archive artifacts uses: actions/upload-artifact@v4 with: name: debian-packages path: "*.deb" # # Nightlies # publish-nightly: name: Publish nightly build if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && startsWith(github.ref, 'refs/heads/release-nightly') environment: release needs: - sign-for-upgrade - facts runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: repository: syncthing/release-tools path: tools - name: Download artifacts uses: actions/download-artifact@v4 with: name: packages-signed path: packages - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - name: Create release json run: | cd packages "$GITHUB_WORKSPACE/tools/generate-release-json" "$BASE_URL" > nightly.json env: BASE_URL: ${{ secrets.NIGHTLY_BASE_URL }} - name: Push artifacts uses: docker://docker.io/rclone/rclone:latest env: RCLONE_CONFIG_OBJSTORE_TYPE: s3 RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }} RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }} RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }} RCLONE_CONFIG_OBJSTORE_ACL: public-read with: args: sync -v --no-update-modtime packages objstore:nightly # # Push release artifacts to Spaces # publish-release-files: name: Publish release files if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/tags/v')) environment: release permissions: contents: write needs: - sign-for-upgrade - package-debian - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ github.ref }} # https://github.com/actions/checkout/issues/882 - name: Download signed packages uses: actions/download-artifact@v4 with: name: packages-signed path: packages - name: Download debian packages uses: actions/download-artifact@v4 with: name: debian-packages path: packages - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - name: Push to object store (${{ env.VERSION }}) uses: docker://docker.io/rclone/rclone:latest env: RCLONE_CONFIG_OBJSTORE_TYPE: s3 RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }} RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }} RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }} RCLONE_CONFIG_OBJSTORE_ACL: public-read with: args: sync -v --no-update-modtime packages objstore:release/${{ env.VERSION }} - name: Push to object store (latest) uses: docker://docker.io/rclone/rclone:latest env: RCLONE_CONFIG_OBJSTORE_TYPE: s3 RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }} RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }} RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }} RCLONE_CONFIG_OBJSTORE_ACL: public-read with: args: sync -v --no-update-modtime objstore:release/${{ env.VERSION }} objstore:release/latest - name: Create GitHub releases and push binaries run: | maybePrerelease="" if [[ $VERSION == *-* ]]; then maybePrerelease="--prerelease" fi export GH_PROMPT_DISABLED=1 if ! gh release view --json name "$VERSION" >/dev/null 2>&1 ; then gh release create "$VERSION" \ $maybePrerelease \ --title "$VERSION" \ --notes-from-tag fi gh release upload --clobber "$VERSION" \ packages/*.asc packages/*.json \ packages/syncthing-*.tar.gz \ packages/syncthing-*.zip \ packages/syncthing_*.deb PKGS=$(pwd)/packages cd /tmp # gh will not release for repo x while inside repo y for repo in relaysrv discosrv ; do export GH_REPO="syncthing/$repo" if ! gh release view --json name "$VERSION" >/dev/null 2>&1 ; then gh release create "$VERSION" \ $maybePrerelease \ --title "$VERSION" \ --notes "https://github.com/syncthing/syncthing/releases/tag/$VERSION" fi gh release upload --clobber "$VERSION" \ $PKGS/*.asc \ $PKGS/*${repo}* done env: GH_TOKEN: ${{ secrets.ACTIONS_GITHUB_TOKEN }} # # Push Debian/APT archive # publish-apt: name: Publish APT if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release-nightly' || startsWith(github.ref, 'refs/tags/v')) environment: release needs: - package-debian - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} RELEASE_GENERATION: ${{ needs.facts.outputs.release-generation }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Download packages uses: actions/download-artifact@v4 with: name: debian-packages path: packages # Decide whether packages should go to stable, candidate or nightly - name: Prepare packages run: | if [[ $RELEASE_KIND == stable && $RELEASE_GENERATION == v2 ]] ; then RELEASE_KIND=stable-v2 fi mkdir -p packages/syncthing/$RELEASE_KIND mv packages/*.deb packages/syncthing/$RELEASE_KIND - name: Pull archive uses: docker://docker.io/rclone/rclone:latest env: RCLONE_CONFIG_OBJSTORE_TYPE: s3 RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }} RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }} RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }} RCLONE_CONFIG_OBJSTORE_ACL: public-read with: args: sync objstore:apt/dists dists - name: Update archive uses: docker://ghcr.io/kastelo/ezapt:latest with: args: publish --add packages --dists dists env: EZAPT_KEYRING_BASE64: ${{ secrets.APT_GPG_KEYRING_BASE64 }} - name: Push archive uses: docker://docker.io/rclone/rclone:latest env: RCLONE_CONFIG_OBJSTORE_TYPE: s3 RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }} RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }} RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }} RCLONE_CONFIG_OBJSTORE_ACL: public-read with: args: sync -v --no-update-modtime dists objstore:apt/dists # # Build and push (except for PRs) to GHCR. # docker-ghcr: name: Build and push Docker images (GHCR) runs-on: ubuntu-latest permissions: contents: read packages: write needs: - facts env: VERSION: ${{ needs.facts.outputs.version }} RELEASE_KIND: ${{ needs.facts.outputs.release-kind }} strategy: matrix: pkg: - syncthing - strelaysrv - stdiscosrv include: - pkg: syncthing dockerfile: Dockerfile image: syncthing - pkg: strelaysrv dockerfile: Dockerfile.strelaysrv image: relaysrv - pkg: stdiscosrv dockerfile: Dockerfile.stdiscosrv image: discosrv steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - uses: mlugg/setup-zig@v2 - uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ needs.facts.outputs.go-version }}-docker-${{ matrix.pkg }}-${{ hashFiles('**/go.sum') }} - name: Build binaries (CGO) run: | # amd64 go run build.go -goos linux -goarch amd64 -tags "${{env.TAGS}}" -cc "zig cc -target x86_64-linux-musl" -no-upgrade build ${{ matrix.pkg }} mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-amd64 # arm64 go run build.go -goos linux -goarch arm64 -tags "${{env.TAGS}}" -cc "zig cc -target aarch64-linux-musl" -no-upgrade build ${{ matrix.pkg }} mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-arm64 # arm go run build.go -goos linux -goarch arm -tags "${{env.TAGS}}" -cc "zig cc -target arm-linux-musleabi -mcpu=arm1136j_s" -no-upgrade build ${{ matrix.pkg }} mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-arm env: CGO_ENABLED: "1" BUILD_USER: docker EXTRA_LDFLAGS: "-linkmode=external -extldflags=-static" - name: Login to GHCR uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Set version tags run: | version=${VERSION#v} repo=ghcr.io/${{ github.repository_owner }}/${{ matrix.image }} ref="${{github.ref_name}}" ref=${ref//\//-} # slashes to dashes # List of tags for ghcr.io if [[ $version == @([0-9]|[0-9][0-9]).@([0-9]|[0-9][0-9]).@([0-9]|[0-9][0-9]) ]] ; then major=${version%.*.*} minor=${version%.*} tags=$repo:$version,$repo:$major,$repo:$minor,$repo:latest elif [[ $version == *-rc.@([0-9]|[0-9][0-9]) ]] ; then tags=$repo:$version,$repo:rc elif [[ $ref == "main" ]] ; then tags=$repo:edge else tags=$repo:$ref fi echo Pushing to $tags echo "DOCKER_TAGS=$tags" >> $GITHUB_ENV - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: ${{ matrix.dockerfile }} platforms: linux/amd64,linux/arm64,linux/arm/7 tags: ${{ env.DOCKER_TAGS }} push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} labels: | org.opencontainers.image.version=${{ env.VERSION }} org.opencontainers.image.revision=${{ github.sha }} # # Sync images to Docker hub. This takes the images already pushed to GHCR # and copies them to Docker hub. Runs for releases only. # docker-hub: name: Sync images to Docker hub if: github.repository_owner == 'syncthing' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/release-nightly' || github.ref == 'refs/heads/infrastructure' || startsWith(github.ref, 'refs/tags/v')) runs-on: ubuntu-latest needs: - docker-ghcr environment: docker env: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} steps: - uses: actions/checkout@v4 - name: Sync images uses: docker://docker.io/regclient/regsync:latest with: args: -c ./.github/regsync.yml once # # Check for known vulnerabilities in Go dependencies # govulncheck: runs-on: ubuntu-latest name: Run govulncheck needs: - facts steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: ${{ needs.facts.outputs.go-version }} cache: false - name: run govulncheck run: | go run build.go assets go install golang.org/x/vuln/cmd/govulncheck@latest govulncheck ./... # # golangci-lint runs a suite of static analysis checks on the code # golangci: runs-on: ubuntu-latest name: Run golangci-lint if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: 'stable' - name: ensure asset generation run: go run build.go assets - name: golangci-lint uses: golangci/golangci-lint-action@v8 with: only-new-issues: true # # Meta checks for formatting, copyright, etc # meta: name: Run meta checks runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: 'stable' - run: | go run build.go assets go test -v ./meta