diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0997f39 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,144 @@ +name: Release + +# Runs on a pushed v* tag and creates a DRAFT pre-release. A maintainer +# reviews the attached archives, SHA256SUMS and provenance attestation before +# publishing it. Only targets that CI tests are built; Windows is compile-only +# in CI and is not released. + +on: + push: + tags: ['v*'] + +permissions: + contents: read + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +env: + GO_VERSION: "1.26.6" + GOTOOLCHAIN: local + GOWORK: "off" + +jobs: + build: + strategy: + fail-fast: true + matrix: + include: + - os: ubuntu-latest + goos: linux + goarch: amd64 + - os: macos-latest + goos: darwin + goarch: arm64 + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: ${{ env.GO_VERSION }} + cache: false + - name: Tag matches source version + shell: bash + run: | + set -euo pipefail + source_version="$(tr -d '\r\n' < VERSION)" + binary_version="$(go run ./cmd/across version)" + if [ "v${source_version}" != "${GITHUB_REF_NAME}" ] || [ "${binary_version}" != "${source_version}" ]; then + echo "::error::tag ${GITHUB_REF_NAME}, VERSION ${source_version} and 'across version' ${binary_version} must agree" + exit 1 + fi + - name: Runner matches target + shell: bash + run: | + set -euo pipefail + actual="$(go env GOOS)/$(go env GOARCH)" + if [ "${actual}" != "${{ matrix.goos }}/${{ matrix.goarch }}" ]; then + echo "::error::runner builds ${actual}, expected ${{ matrix.goos }}/${{ matrix.goarch }}" + exit 1 + fi + - name: Test + run: go test -count=1 ./... + - name: Build and package + shell: bash + env: + CGO_ENABLED: "1" + COPYFILE_DISABLE: "1" + run: | + set -euo pipefail + name="across_${GITHUB_REF_NAME#v}_${{ matrix.goos }}_${{ matrix.goarch }}" + stage="dist/${name}" + mkdir -p "${stage}" + go build -trimpath -o "${stage}/across" ./cmd/across + for agent in claude-code codex cursor gemini opencode qwen factory-droid amp goose; do + go build -trimpath -o "${stage}/across-agent-${agent}" "./cmd/across-agent-${agent}" + done + cp LICENSE README.md CHANGELOG.md "${stage}/" + tar -C dist -czf "dist/${name}.tar.gz" "${name}" + rm -rf "${stage}" + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: across-${{ matrix.goos }}-${{ matrix.goarch }} + path: dist/*.tar.gz + if-no-files-found: error + + publish: + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + attestations: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: ${{ env.GO_VERSION }} + cache: false + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + path: dist + pattern: across-* + merge-multiple: true + - name: Module inventory + run: go list -m -json all > dist/go-modules.json + - uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 + with: + path: . + format: spdx-json + output-file: dist/sbom.spdx.json + syft-version: v1.51.1 + upload-artifact: false + upload-release-assets: false + - name: Checksums + shell: bash + run: | + set -euo pipefail + cd dist + archives=(across_*.tar.gz) + if [ "${#archives[@]}" -ne 2 ]; then + echo "::error::expected 2 archives, found ${#archives[@]}: ${archives[*]}" + exit 1 + fi + sha256sum across_*.tar.gz go-modules.json sbom.spdx.json > SHA256SUMS + cat SHA256SUMS + - uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 + with: + subject-checksums: dist/SHA256SUMS + - uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 + with: + draft: true + prerelease: true + generate_release_notes: true + fail_on_unmatched_files: true + files: | + dist/across_*.tar.gz + dist/SHA256SUMS + dist/go-modules.json + dist/sbom.spdx.json