-
Notifications
You must be signed in to change notification settings - Fork 155
feat: publish pre-built binaries with releases #209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| --- | ||
| name: build | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] # pushes TO main | ||
| pull_request: | ||
| branches: [main] # pull requests AGAINST main | ||
| release: | ||
| types: [published] # for release build | ||
|
|
||
| # cancel CI runs when a new commit is pushed to any branch except main | ||
| concurrency: | ||
| group: 'build-${{ github.ref }}' | ||
| cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
|
|
||
| permissions: | ||
| contents: read # for uses: actions/checkout | ||
| id-token: write # for actions/attest-build-provenance | ||
| attestations: write # for actions/attest-build-provenance | ||
|
|
||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| # Static binaries are built with the `stable` version | ||
| # If you want to add a target, add it below. | ||
| include: | ||
| - {goos: 'darwin', goarch: 'amd64'} | ||
| - {goos: 'darwin', goarch: 'arm64'} | ||
| - {goos: 'linux', goarch: 'amd64'} | ||
| - {goos: 'linux', goarch: 'arm', goarm: '6'} | ||
| - {goos: 'linux', goarch: 'arm', goarm: '7'} | ||
| - {goos: 'linux', goarch: 'arm64'} | ||
| - {goos: 'linux', goarch: 'riscv64'} | ||
| - {goos: 'windows', goarch: 'amd64'} | ||
| - {goos: 'windows', goarch: 'arm64',} | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| # Security measures | ||
| # See also: https://github.com/actions/checkout/issues/485 | ||
| persist-credentials: false | ||
|
|
||
| - name: Setup golang | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: stable | ||
| # Disabled in multi-platform builds due to complex caching strategies | ||
| cache: false | ||
|
|
||
| - run: make release | ||
| env: | ||
| DIST_PATH: dist | ||
| GOOS: ${{ matrix.goos }} | ||
| GOARCH: ${{ matrix.goarch }} | ||
| GOARM: ${{ matrix.goarch == 'arm' && matrix.goarm || '' }} | ||
|
|
||
| - name: Generate artifact attestation | ||
| uses: actions/attest-build-provenance@v2 | ||
| # Since the necessary permissions cannot be set in the pull_request event, it is limited to push events. | ||
| if: ${{ github.event_name != 'pull_request' }} | ||
| with: | ||
| subject-path: dist/go-httpbin-* | ||
|
|
||
| - name: Check artifacts | ||
| run: | | ||
| file dist/go-httpbin-* | ||
| stat dist/go-httpbin-* | ||
|
|
||
| - name: Upload artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: go-httpbin-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarch == 'arm' && format('v{0}', matrix.goarm) || '' }} | ||
| path: dist/ | ||
|
|
||
| checksum: | ||
| needs: [build] | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
|
|
||
| permissions: | ||
| id-token: write # for uses: aactions/attest-build-provenance | ||
| attestations: write # for uses: aactions/attest-build-provenance | ||
|
|
||
| steps: | ||
| - name: Download artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| path: dist/ | ||
| pattern: go-httpbin-* | ||
| merge-multiple: true | ||
|
|
||
| - name: Check artifacts | ||
| run: tree --charset ASCII dist/ | ||
|
|
||
| - name: Verify artifacts | ||
| # Since the necessary permissions cannot be set in the pull_request event, it is limited to push events. | ||
| if: ${{ !startsWith(github.event_name, 'pull') }} | ||
| run: | | ||
| cd dist | ||
| for f in go-httpbin-*; do | ||
| gh attestation verify "$f" -R "${GITHUB_REPOSITORY}"; | ||
| done | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Generate sha256 checksums | ||
| run: | | ||
| cd dist | ||
| for f in $(find . -type f -name 'go-httpbin-*' -printf '%f\n' | sort); do | ||
| sha256sum "$f" | tee -a SHA256SUMS; | ||
| done | ||
|
|
||
| - name: Verify sha256 checksums | ||
| run: cd dist && sha256sum -c SHA256SUMS | ||
|
Comment on lines
+121
to
+122
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a dumb question: What's the value in separating this step from the previous step? |
||
|
|
||
| - name: Generate artifact attestation | ||
| # Since the necessary permissions cannot be set in the pull_request event, it is limited to push events. | ||
| if: ${{ !startsWith(github.event_name, 'pull') }} | ||
| uses: actions/attest-build-provenance@v2 | ||
| with: | ||
| subject-path: dist/SHA256SUMS | ||
|
|
||
| - name: Upload sha256 checksum | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: checksum-sha256sums | ||
| path: dist/SHA256SUMS | ||
|
|
||
| publish: | ||
| needs: [build, checksum] | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
|
|
||
| permissions: | ||
| contents: write # for gh release upload | ||
| id-token: write # for actions/attest-build-provenance | ||
| attestations: write # for actions/attest-build-provenance | ||
|
|
||
| steps: | ||
| - name: Download binary artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| path: dist/ | ||
| pattern: go-httpbin-* | ||
| merge-multiple: true | ||
|
|
||
| - name: Download checksum artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| path: dist/ | ||
| pattern: checksum-* | ||
| merge-multiple: true | ||
|
|
||
| - name: Check artifacts | ||
| run: tree --charset ASCII dist/ | ||
|
|
||
| - name: Publish artifacts | ||
| if: startsWith(github.ref, 'refs/tags/') | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we gate this on the |
||
| run: |- | ||
| gh release upload "$(echo "${GITHUB_REF}" | sed -E 's!refs/tags/!!')" dist/* -R "${GITHUB_REPOSITORY}" | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just trying to make sure I understand the mechanics here: This will attach the prebuilt & attested binaries and checksums to an existing release, right? And we can be sure the release exists because this step will only be executed when triggered by the |
||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,21 @@ STATICCHECK := go run honnef.co/go/tools/cmd/[email protected] | |
| HOST ?= 127.0.0.1 | ||
| PORT ?= 8080 | ||
|
|
||
| # Determine the name of the static binary for the release build | ||
| GOOS ?= $(shell go env GOOS) | ||
| GOARCH ?= $(shell go env GOARCH) | ||
| ifeq (x$(GOOS)x,xwindowsx) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume this is some arcane make-specific nuance, but why the surrounding |
||
| GOENVS ?= GOOS=$(GOOS) GOARCH=$(GOARCH) | ||
| BINNAME ?= go-httpbin-$(GOOS)-$(GOARCH).exe | ||
| else | ||
| ifeq (x$(GOARCH)x,xarmx) | ||
| GOENVS ?= GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) | ||
| BINNAME ?= go-httpbin-$(GOOS)-$(GOARCH)v$(GOARM) | ||
| else | ||
| GOENVS ?= GOOS=$(GOOS) GOARCH=$(GOARCH) | ||
| BINNAME ?= go-httpbin-$(GOOS)-$(GOARCH) | ||
| endif | ||
| endif | ||
|
|
||
| # ============================================================================= | ||
| # build | ||
|
|
@@ -99,3 +114,11 @@ imagepush: | |
| docker buildx build --push --platform linux/amd64,linux/arm64 -t $(DOCKER_TAG) . | ||
| docker buildx rm httpbin | ||
| .PHONY: imagepush | ||
|
|
||
| # ============================================================================= | ||
| # release build | ||
| # ============================================================================= | ||
| release: | ||
| mkdir -p $(DIST_PATH) | ||
| CGO_ENABLED=0 $(GOENVS) go build -trimpath -ldflags '-s -w -buildid=' -o $(DIST_PATH)/$(BINNAME) ./cmd/go-httpbin | ||
| .PHONY: release | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes me vaguely uneasy that this step needs to be able to generate the exact same name that
make releasewill generate, and needs to stay in sync over time.What if we do something like
make releaseto emit the built binary name as the last line on stdoutmake releasestep above to capture that last line as an output${{ steps.make-release.outputs.release_name }}(or whatever)Would that make any sense to you?