name: Release # Cut a release by pushing a bare-semver tag from main — see RELEASING.md. on: push: tags: ['[0-9]+.[0-9]+.[0-9]+'] # contents: write creates the release; id-token + attestations let the # provenance step sign a statement binding the artifacts to this workflow run. permissions: contents: write id-token: write attestations: write jobs: release: name: build + publish runs-on: windows-latest steps: # Full history and tags, not the default shallow checkout: the build # script derives the displayed version from `git describe`, and without # the tag it would stamp the release binary as a dev build. - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 # master with: toolchain: stable - name: Cache cargo registry and build artifacts uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 # A tag that disagrees with the manifest would publish a mislabeled # binary; fail fast instead. The same step cuts the tag's section out of # CHANGELOG.md for the release body, so a tag without a dated changelog # heading fails here rather than after the build. - name: Verify tag matches Cargo.toml version and has a changelog section run: | $version = (cargo metadata --no-deps --format-version 1 | ConvertFrom-Json).packages[0].version if ($version -ne $env:GITHUB_REF_NAME) { throw "Tag $env:GITHUB_REF_NAME does not match Cargo.toml version $version" } $changelog = Get-Content CHANGELOG.md -Raw $heading = [regex]::Escape("## [$env:GITHUB_REF_NAME]") $match = [regex]::Match($changelog, "(?ms)^$heading[^\r\n]*\r?\n(.*?)(?=^## \[|\z)") if (-not $match.Success) { throw "CHANGELOG.md has no section for $env:GITHUB_REF_NAME" } $section = $match.Groups[1].Value.Trim() if (-not $section) { throw "The CHANGELOG.md section for $env:GITHUB_REF_NAME is empty" } Set-Content -Path changelog-section.md -Value $section -NoNewline Get-Content changelog-section.md # The push that got tagged already passed CI on main, but nothing # enforces that the tag points at such a commit — re-run the suite on # exactly the tagged tree before shipping it. - name: Test run: cargo test --locked - name: Build release binary run: cargo build --release --locked - name: Install cargo-about uses: taiki-e/install-action@83ac0ad63c0167e6f06796fab0fce28db1bf3db0 # v2.87.22 with: tool: cargo-about@0.9.1 # MIT/Apache-2.0 notices must accompany the shipped binary. --fail turns # an unresolvable (or newly introduced, unaccepted) license into a # release failure instead of silently incomplete attribution. - name: Generate third-party license notices run: cargo about generate --fail -o THIRD-PARTY-NOTICES.html about.hbs - name: Package release zip run: | $zip = "darkbright-helper-$env:GITHUB_REF_NAME-windows-x64.zip" New-Item -ItemType Directory dist | Out-Null Copy-Item target/release/darkbright-helper.exe, LICENSE-MIT, LICENSE-APACHE, THIRD-PARTY-NOTICES.html dist/ Compress-Archive -Path dist/* -DestinationPath $zip "ZIP_NAME=$zip" | Out-File -FilePath $env:GITHUB_ENV -Append # Signed provenance: lets anyone check that a downloaded artifact was # built by this workflow from this commit (`gh attestation verify`). # Covers both the zip and the exe inside it, so an extracted binary can # be verified on its own. - name: Attest build provenance uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 with: subject-path: | ${{ env.ZIP_NAME }} target/release/darkbright-helper.exe # The release body opens with the version's CHANGELOG.md section, copied # verbatim by the verify step above, so the changelog stays the only # place the notes are written. The binary is unsigned, so a downloader # has nothing to check it against. Publishing the hash in the release # body at least makes tampering between GitHub and the disk detectable. - name: Create GitHub release with zip attached env: GH_TOKEN: ${{ github.token }} run: | $zip = $env:ZIP_NAME $hash = (Get-FileHash $zip -Algorithm SHA256).Hash.ToLower() $section = Get-Content changelog-section.md -Raw $notes = "$section`n`n" + "See CHANGELOG.md for the full history.`n`n" + "The zip contains the executable together with its license files and third-party notices.`n`n" + "SHA-256 of $zip`n`n" + " $hash`n`n" + "Verify with: Get-FileHash $zip -Algorithm SHA256`n`n" + "Build provenance: gh attestation verify $zip --repo $env:GITHUB_REPOSITORY" gh release create $env:GITHUB_REF_NAME $zip --title $env:GITHUB_REF_NAME --notes $notes