From 147082206fe82b9a16d51dbc42c9f74a1b4a3505 Mon Sep 17 00:00:00 2001 From: James Maes Date: Sun, 8 Nov 2026 08:27:29 -0600 Subject: [PATCH 1/3] ci: build on Gitea with the shared Go workflow Port the GitHub CI gates (gofmt, go vet, golangci-lint, race tests with the coverage profile, the 100% coverage gate, go build) to the shared ci-workflows go.yaml. v* tags build the GoReleaser-equivalent archives with scripts/build-release.sh and attach them with SHA256SUMS to the Gitea release. The GitHub workflows ran on ubuntu-22.04/macos/windows runners that Gitea does not serve; removed. Co-Authored-By: Claude Opus 5.5 --- .gitea/workflows/build.yaml | 20 ++++++ .github/workflows/ci.yml | 121 ---------------------------------- .github/workflows/release.yml | 39 ----------- RELEASES.md | 4 +- RELEASING.md | 52 ++++----------- scripts/build-release.sh | 34 ++++++++++ 6 files changed, 68 insertions(+), 202 deletions(-) create mode 100644 .gitea/workflows/build.yaml delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/release.yml create mode 100755 scripts/build-release.sh diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml new file mode 100644 index 0000000..904b2bf --- /dev/null +++ b/.gitea/workflows/build.yaml @@ -0,0 +1,20 @@ +name: build +on: + push: + branches: ['**'] + tags: ['v*'] +jobs: + go: + uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/go.yaml@small-workflows + secrets: inherit + with: + go-version: '1.26' + golangci-lint: true + race: true + test-args: -coverpkg=./internal/...,./cmd/... -covermode=atomic -coverprofile=cover.out + # 100% coverage gate (.testcoverage.yml), then the plain build. + commands: | + go run github.com/vladopajic/go-test-coverage/v2@v2.18.8 --config=.testcoverage.yml + go build ./... + release-commands: scripts/build-release.sh "${GITHUB_REF_NAME#v}" + artifacts: dist/* diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 25c090b..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,121 +0,0 @@ -name: CI - -on: - pull_request: - branches: - - develop - - main - - release/** - - rc/** - push: - branches: - - develop - - main - - release/** - - rc/** - -permissions: - contents: read - -jobs: - go-checks: - name: Go checks - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version: "1.26" - cache: true - - - name: Check formatting - run: | - unformatted="$(gofmt -l .)" - if [ -n "$unformatted" ]; then - echo "The following files are not gofmt-clean:" - echo "$unformatted" - exit 1 - fi - - - name: Run go vet - run: go vet ./... - - - name: Run golangci-lint - uses: golangci/golangci-lint-action@v9 - with: - # v8 installs golangci-lint v2.x, which understands the v2 .golangci.yml - # schema (version/formatters). latest pulls a build made with a current Go - # toolchain, satisfying the module's go directive. - version: latest - - - name: Run tests with coverage profile - run: | - go test ./... -race \ - -coverpkg=./internal/...,./cmd/... \ - -covermode=atomic \ - -coverprofile=cover.out - - - name: Upload coverage profile - uses: actions/upload-artifact@v7 - with: - name: coverage-profile-${{ github.run_id }}-${{ github.sha }} - path: cover.out - if-no-files-found: error - - - name: Enforce 100% coverage gate - # go-test-coverage is a CI-only tool, run via `go run` so it never becomes a - # go.mod dependency. The gate FAILS the build when total coverage on - # ./internal/...,./cmd/... drops below the 100 threshold in .testcoverage.yml, - # which documents the only two exclusions (the main() shim and gen_spdx.go). - run: go run github.com/vladopajic/go-test-coverage/v2@v2.18.8 --config=.testcoverage.yml - - - name: Build - run: go build ./... - - macos-build: - name: macOS branch build - runs-on: macos-15 - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version: "1.26" - cache: true - - - name: Build binary - run: go build -o license-tool ./cmd/license-tool - - - name: Upload branch binary - uses: actions/upload-artifact@v7 - with: - name: license-tool-${{ github.run_id }}-${{ github.sha }}-macos - path: license-tool - if-no-files-found: error - - windows-build: - name: Windows branch build - runs-on: windows-latest - if: github.event_name == 'push' - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version: "1.26" - cache: true - - - name: Build binary - run: go build -o license-tool.exe ./cmd/license-tool - - - name: Upload branch binary - uses: actions/upload-artifact@v7 - with: - name: license-tool-${{ github.run_id }}-${{ github.sha }}-windows - path: license-tool.exe - if-no-files-found: error diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 5420c6e..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Release - -# Run whenever a semver release tag is pushed (e.g. v1.0.0, v1.2.3-rc.1). -on: - push: - tags: - - "v[0-9]+.[0-9]+.[0-9]+*" - -permissions: - contents: write - -jobs: - goreleaser: - name: GoReleaser - runs-on: ubuntu-22.04 - steps: - - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - # GoReleaser needs full history and all tags to compute the changelog - # and resolve the previous tag. - fetch-depth: 0 - - - name: Set up Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - with: - go-version: "1.26.4" - cache: true - - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 - with: - version: v2.16.0 - args: release --clean - env: - # GITHUB_TOKEN publishes the GitHub Release in this repo. - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # HOMEBREW_TAP_TOKEN pushes the generated cask to KofTwentyTwo/homebrew-tap. - HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} diff --git a/RELEASES.md b/RELEASES.md index d7d6fbf..2a422e7 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -5,8 +5,8 @@ on [RELEASING.md](./RELEASING.md) (which is the short reference) with the comple process: integrating feature work, choosing a version, running the gate, tagging, and verifying the published artifacts. -Releases are built by [GoReleaser](https://goreleaser.com) and published by the -`Release` GitHub Actions workflow. There is **no version constant in source** — the +Releases are built by `scripts/build-release.sh` and published to the Gitea release by +the tag build of `.gitea/workflows/build.yaml` (see RELEASING.md). There is **no version constant in source** — the version is injected at build time via `-ldflags` (`main.version`, `main.commit`, `main.date`) when the workflow runs against a pushed tag. diff --git a/RELEASING.md b/RELEASING.md index bd3c8a5..9a15396 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -4,7 +4,10 @@ > conflict resolution, tagging, and post-release verification) see [RELEASES.md](./RELEASES.md). > This file is the short reference. -Releases are built with [GoReleaser](https://goreleaser.com) and published by GitHub Actions. +CI and releases run on Gitea Actions (`.gitea/workflows/build.yaml`, the shared +`KofTwentyTwo/ci-workflows` Go workflow). A `v*` tag runs every gate, then +`scripts/build-release.sh` builds the archives and CI attaches them with a `SHA256SUMS` +to the tag's Gitea release. `.goreleaser.yaml` remains for local snapshot checks. ## Changelog Management @@ -72,8 +75,8 @@ git tag vX.Y.Z-rc.N git push origin vX.Y.Z-rc.N ``` -The `Release` workflow builds all configured target binaries and creates a GitHub prerelease -(the `release.prerelease: auto` setting marks any tag with a prerelease suffix as a prerelease). +The tag build creates a Gitea prerelease (any tag with a `-` suffix) with the archives and +`SHA256SUMS`. ## Production Release @@ -86,7 +89,7 @@ From `main`: git commit -am "docs: changelog for v$VERSION" ``` -3. Push `main` and wait for CI and CodeQL to pass on the release commit. +3. Push `main` and wait for CI to pass on the release commit. 4. Tag and push. Prefer a signed annotated tag: ```bash @@ -94,41 +97,10 @@ From `main`: git push origin vX.Y.Z ``` -The `Release` workflow runs `goreleaser release --clean`, which cross-compiles the -mac/linux arm64+amd64 and windows amd64 binaries, builds the archives and `checksums.txt`, -creates the GitHub Release, and publishes the Homebrew cask to: +The tag build runs every CI gate, then `scripts/build-release.sh ` cross-compiles the +mac/linux arm64+amd64 and windows amd64 binaries into `dist/` archives, and CI attaches them +and a `SHA256SUMS` to the tag's Gitea release. -```text -KofTwentyTwo/homebrew-tap -``` +The Homebrew cask in `KofTwentyTwo/homebrew-tap` is not updated by CI; update it by hand from +the release's `SHA256SUMS` until the tap has its own workflow. -End users install with: - -```bash -brew install --cask KofTwentyTwo/tap/license-tool -``` - -## Required GitHub Setup - -Create or verify a public Homebrew tap repository: - -```text -KofTwentyTwo/homebrew-tap -``` - -Add a repository Actions secret on `KofTwentyTwo/license-tool` named: - -```text -HOMEBREW_TAP_TOKEN -``` - -The token needs contents write access to `KofTwentyTwo/homebrew-tap`, because the release -workflow checks out that repository and commits cask updates. Do not hardcode this token -in workflow files. - -Before the first production release: - -- Protect or manage the `main` and `develop` branches according to the branch flow above. -- Confirm `HOMEBREW_TAP_TOKEN` can write to `KofTwentyTwo/homebrew-tap`. -- Confirm the local push path works with `git ls-remote --heads origin`. -- Re-run `goreleaser check` and `goreleaser release --snapshot --clean`. diff --git a/scripts/build-release.sh b/scripts/build-release.sh new file mode 100755 index 0000000..c67214f --- /dev/null +++ b/scripts/build-release.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Cross-compile the release archives into dist/ (the Gitea CI runs this on v* tags). +# +# Same targets, names and ldflags as .goreleaser.yaml: darwin/linux amd64+arm64 and +# windows amd64; tar.gz everywhere except Windows, which gets a zip. +# +# Usage: scripts/build-release.sh (for example 1.2.3 or 1.2.3-rc.1) +set -euo pipefail + +version=${1:?usage: scripts/build-release.sh } +commit=$(git rev-parse HEAD) +date=$(date -u +%Y-%m-%dT%H:%M:%SZ) +ldflags="-s -w -X main.version=$version -X main.commit=$commit -X main.date=$date" + +cd "$(dirname "${BASH_SOURCE[0]}")/.." +rm -rf dist && mkdir dist +for target in darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64; do + os=${target%/*} + arch=${target#*/} + name=license-tool_${version}_${os}_${arch} + ext= + [[ $os == windows ]] && ext=.exe + mkdir "dist/$name" + CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -trimpath -ldflags "$ldflags" \ + -o "dist/$name/license-tool$ext" ./cmd/license-tool + cp README.md LICENSE CHANGELOG.md "dist/$name/" + if [[ $os == windows ]]; then + (cd "dist/$name" && python3 -m zipfile -c "../$name.zip" ./*) + else + tar -czf "dist/$name.tar.gz" -C "dist/$name" . + fi + rm -r "dist/${name:?}" +done +ls -l dist -- 2.54.0 From 7da7f93fc7fa1f72a4c73eaa8a98c2ee6e6db141 Mon Sep 17 00:00:00 2001 From: James Maes Date: Sun, 8 Nov 2026 08:56:21 -0600 Subject: [PATCH 2/3] ci: call the shared workflow from ci-workflows main Co-Authored-By: Claude Opus 5.5 --- .gitea/workflows/build.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 904b2bf..df181ec 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -5,8 +5,7 @@ on: tags: ['v*'] jobs: go: - uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/go.yaml@small-workflows - secrets: inherit + uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/go.yaml@main with: go-version: '1.26' golangci-lint: true -- 2.54.0 From 48bf47d4a80c20dd7e2cf0b1dfdbde289afe8631 Mon Sep 17 00:00:00 2001 From: James Maes Date: Sun, 8 Nov 2026 09:00:29 -0600 Subject: [PATCH 3/3] ci: pin the shared workflow to v1 Co-Authored-By: Claude Opus 5.5 --- .gitea/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index df181ec..235fc75 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -5,7 +5,7 @@ on: tags: ['v*'] jobs: go: - uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/go.yaml@main + uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/go.yaml@v1 with: go-version: '1.26' golangci-lint: true -- 2.54.0