name: Release on: push: tags: - "v[0-9]+.[0-9]+.[0-9]+" permissions: contents: read jobs: create-release: name: Create Release runs-on: ubuntu-24.04 timeout-minutes: 10 permissions: contents: write env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} TAG: ${{ github.ref_name }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Validate tag matches Cargo.toml version id: version run: | VERSION="${TAG#v}" CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/') if [ "$VERSION" != "$CARGO_VERSION" ]; then echo "::error::Tag $TAG does not match Cargo.toml version $CARGO_VERSION" exit 1 fi echo "version=$VERSION" >> "$GITHUB_OUTPUT" - name: Generate release notes run: gh api "repos/$REPO/releases/generate-notes" -f tag_name="$TAG" --jq .body > RELEASE_NOTES.md - name: Create GitHub release run: gh release create "$TAG" --draft --verify-tag --title "$TAG" --notes-file RELEASE_NOTES.md outputs: version: ${{ steps.version.outputs.version }} build-release: name: Build ${{ matrix.target }} needs: [create-release] runs-on: ${{ matrix.os }} timeout-minutes: 90 permissions: contents: write id-token: write attestations: write strategy: fail-fast: false matrix: include: - target: x86_64-unknown-linux-gnu os: ubuntu-24.04 - target: aarch64-unknown-linux-gnu os: ubuntu-24.04-arm - target: aarch64-apple-darwin os: macos-latest - target: x86_64-apple-darwin os: macos-15-intel - target: x86_64-pc-windows-msvc os: windows-2022 env: RUST_BACKTRACE: 1 CARGO_INCREMENTAL: 0 SCCACHE_GHA_ENABLED: "true" RUSTC_WRAPPER: sccache CCACHE: sccache TARGET: ${{ matrix.target }} VERSION: ${{ needs.create-release.outputs.version }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG: ${{ github.ref_name }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1 with: toolchain: "1.95.0" targets: ${{ matrix.target }} - uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 - name: Install system dependencies (Linux) if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y cmake clang llvm pkg-config libfontconfig-dev libfreetype-dev \ libssl-dev libglib2.0-dev libegl1-mesa-dev \ xvfb libegl1 libgles2 libgl1-mesa-dri mesa-utils \ libfontconfig1 libfreetype6 libharfbuzz0b libx11-6 libxcb1 libxcb-render0 libxcb-shape0 libxcb-xfixes0 - name: Set LIBCLANG_PATH (Windows) if: runner.os == 'Windows' shell: bash run: printf 'LIBCLANG_PATH=C:\\Program Files\\LLVM\\bin\n' >> "$GITHUB_ENV" - name: Build release binary shell: bash run: cargo build --release --locked --target "$TARGET" - name: Bundle Windows ANGLE DLLs if: runner.os == 'Windows' shell: bash run: | set -eu shopt -s failglob BIN_DIR="target/$TARGET/release" cp "$BIN_DIR"/build/mozangle-*/out/libEGL.dll "$BIN_DIR"/ cp "$BIN_DIR"/build/mozangle-*/out/libGLESv2.dll "$BIN_DIR"/ - name: Smoke test (CLI only, no network) shell: bash run: | set -euo pipefail BIN="target/$TARGET/release/servo-fetch" [[ "${{ runner.os }}" == "Windows" ]] && BIN="$BIN.exe" "$BIN" --version | grep -q '^servo-fetch ' "$BIN" --help >/dev/null - name: Strip binary (Unix) if: runner.os != 'Windows' shell: bash run: strip "target/$TARGET/release/servo-fetch" - name: Determine archive name shell: bash run: echo "ARCHIVE=servo-fetch-v${VERSION}-${TARGET}" >> "$GITHUB_ENV" - name: Build archive (Unix) if: runner.os != 'Windows' shell: bash run: | set -eu mkdir "$ARCHIVE" cp "target/$TARGET/release/servo-fetch" "$ARCHIVE"/ cp README.md LICENSE "$ARCHIVE"/ tar czf "$ARCHIVE.tar.gz" "$ARCHIVE" shasum -a 256 "$ARCHIVE.tar.gz" > "$ARCHIVE.tar.gz.sha256" - name: Build archive (Windows) if: runner.os == 'Windows' shell: bash run: | set -eu mkdir "$ARCHIVE" cp "target/$TARGET/release/servo-fetch.exe" "$ARCHIVE"/ cp "target/$TARGET/release/libEGL.dll" "$ARCHIVE"/ cp "target/$TARGET/release/libGLESv2.dll" "$ARCHIVE"/ cp README.md LICENSE "$ARCHIVE"/ 7z a "$ARCHIVE.zip" "$ARCHIVE" certutil -hashfile "$ARCHIVE.zip" SHA256 > "$ARCHIVE.zip.sha256" - name: Attest build provenance (Unix) if: runner.os != 'Windows' uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 with: subject-path: ${{ env.ARCHIVE }}.tar.gz - name: Attest build provenance (Windows) if: runner.os == 'Windows' uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 with: subject-path: ${{ env.ARCHIVE }}.zip - name: Upload release archive shell: bash run: | set -eu if [[ "${{ runner.os }}" == "Windows" ]]; then gh release upload "$TAG" "$ARCHIVE.zip" "$ARCHIVE.zip.sha256" else gh release upload "$TAG" "$ARCHIVE.tar.gz" "$ARCHIVE.tar.gz.sha256" fi publish-crate: name: Publish to crates.io needs: [create-release, build-release] runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: id-token: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1 with: toolchain: "1.95.0" - name: Dry-run package (gate for --no-verify below) run: cargo package --locked --list >/dev/null - uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4 id: auth - name: Publish to crates.io env: CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} run: cargo publish --locked --no-verify publish-release: name: Publish Release needs: [create-release, build-release, publish-crate] runs-on: ubuntu-24.04 timeout-minutes: 5 permissions: contents: write env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} TAG: ${{ github.ref_name }} steps: - name: Mark release as non-draft run: gh release edit "$TAG" --repo "$REPO" --draft=false