name: Release # GitHub version of the release pipeline. The build half mirrors the Gitea one # in .gitea/workflows/release.yml (static musl Linux via cargo-zigbuild, native # macOS and Windows); only the publish half differs: GitHub needs the v4 # artifact backend and fills the release with `gh`. # # Every job is gated on `github.server_url == 'https://github.com'`, so this file # runs only on GitHub. Gitea runs its own copy in .gitea/workflows; should a # Gitea instance also read .github/workflows, the guard skips these jobs there # so they never fail on the @v4 artifact backend or `gh`. on: push: tags: ["v*"] permissions: contents: write env: CARGO_TERM_COLOR: always CARGO_NET_RETRY: "10" jobs: build: name: ${{ matrix.asset }} if: ${{ github.server_url == 'https://github.com' }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: - os: ubuntu-latest target: x86_64-unknown-linux-musl asset: tsunagi-linux-x86_64 archive: tar.gz zig: true - os: ubuntu-latest target: aarch64-unknown-linux-musl asset: tsunagi-linux-aarch64 archive: tar.gz zig: true - os: macos-latest target: aarch64-apple-darwin asset: tsunagi-macos-aarch64 archive: tar.gz zig: false - os: windows-latest target: x86_64-pc-windows-msvc asset: tsunagi-windows-x86_64 archive: zip zig: false steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} # aws-lc-sys (iroh's rustls backend) and the bundled sqlite are C, and the # musl targets have no prebuilt bindings, so bindgen needs libclang and the # C build needs cmake. zig is the cross C compiler cargo-zigbuild drives. - name: Install musl build tooling if: matrix.zig run: sudo apt-get update && sudo apt-get install -y --no-install-recommends cmake clang libclang-dev - name: Install zig if: matrix.zig uses: mlugg/setup-zig@v2 with: # Pin a real, archived Zig release. Left unpinned the action resolves # to the newest version it knows of (a yet-unreleased 0.16.0-dev), # whose tarball 404s on ziglang.org while the community mirrors flake. version: 0.14.1 - name: Install cargo-zigbuild if: matrix.zig uses: taiki-e/install-action@v2 with: tool: cargo-zigbuild - name: Build shell: bash run: | set -euo pipefail if [[ "${{ matrix.zig }}" == "true" ]]; then # zig's linker ignores the `-O1` GNU-ld optimization flag Rust passes # and says so on stderr, which rustc now surfaces as a linker_messages # warning. It is cosmetic — the binary is correct — so quiet just that # one lint to keep the musl build log clean. A real link error still # fails the build. export RUSTFLAGS="${RUSTFLAGS:-} -A linker_messages" cargo zigbuild --release --locked --target "${{ matrix.target }}" --bin tsunagi else cargo build --release --locked --target "${{ matrix.target }}" --bin tsunagi fi - name: Package shell: bash run: | set -euo pipefail version="${GITHUB_REF_NAME#v}" stage="dist/pkg/${{ matrix.asset }}" mkdir -p "$stage" bin="tsunagi" [[ "${{ runner.os }}" == "Windows" ]] && bin="tsunagi.exe" cp "target/${{ matrix.target }}/release/${bin}" "$stage/" # The top-level README, plus the per-OS install notes and integration # files, so the archive carries what the platform needs to set up. cp README.md "$stage/" case "${{ runner.os }}" in Linux) cp dist/linux/tsunagi.service dist/linux/install.sh "$stage/" cp dist/linux/README.md "$stage/INSTALL.md" ;; macOS) cp dist/macos/cy.hexor.tsunagi.plist "$stage/" cp dist/macos/README.md "$stage/INSTALL.md" ;; Windows) cp dist/windows/README.md "$stage/INSTALL.md" ;; esac archive="${{ matrix.asset }}-${version}.${{ matrix.archive }}" if [[ "${{ matrix.archive }}" == "zip" ]]; then (cd dist/pkg && 7z a "../../${archive}" "${{ matrix.asset }}") else tar -C dist/pkg -czf "${archive}" "${{ matrix.asset }}" fi - name: Upload the archive as a run artifact uses: actions/upload-artifact@v4 with: name: ${{ matrix.asset }} path: ${{ matrix.asset }}-*.* if-no-files-found: error publish: name: Publish release needs: build if: ${{ github.server_url == 'https://github.com' }} runs-on: ubuntu-latest permissions: contents: write steps: - name: Download every build artifact uses: actions/download-artifact@v4 with: path: artifacts - name: Show what was collected run: find artifacts -type f - name: Create the release and upload the archives shell: bash env: GH_TOKEN: ${{ github.token }} TAG: ${{ github.ref_name }} run: | set -euo pipefail # download-artifact@v4 nests each artifact under its own directory, so # the archives are artifacts//. mapfile -t files < <(find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' \)) printf 'asset: %s\n' "${files[@]}" prerelease=() case "$TAG" in *-*) prerelease=(--prerelease) ;; esac # Create the release on the first run; on a re-run, add/replace assets # on the release that is already there. if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then gh release upload "$TAG" "${files[@]}" --repo "$GITHUB_REPOSITORY" --clobber else gh release create "$TAG" "${files[@]}" \ --repo "$GITHUB_REPOSITORY" \ --title "tsunagi $TAG" \ --generate-notes \ --verify-tag \ "${prerelease[@]}" fi