From ccbf4ab24a7f9ec95fa4c7793f5da79dd8a0cc62 Mon Sep 17 00:00:00 2001 From: Phundahl <89451493+Phundahl@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:37:17 +0200 Subject: [PATCH 1/3] ci: run build, vet and tests on push and pull requests release.yml was the only workflow and it fires solely on v* tags, so nothing verified a commit until a release was already being cut -- and a bad .goreleaser.yaml surfaced as a failed release job after the tag already existed. Adds a ci workflow running on pushes to main, on pull requests, and via workflow_dispatch: - test: gofmt gate, `go mod tidy` drift gate, build, vet, and `go test -race ./...` (the View layer is TTY-free, so the suite runs headless; -race covers the async polling commands). - goreleaser-config: `goreleaser check`, so config errors fail on a pull request instead of on a tag. Both jobs resolve Go from go-version-file so CI tracks the pinned toolchain rather than drifting with "stable". Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 82 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..55a94fd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,82 @@ +name: ci + +on: + push: + branches: + - main + pull_request: + # Allow running the suite by hand, e.g. to sanity-check before tagging a release. + workflow_dispatch: + +permissions: + contents: read + +concurrency: + # Supersede in-flight runs for the same branch/PR; a stale run has nothing to say. + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + # Honor the toolchain pinned in go.mod rather than drifting with + # whatever "stable" happens to mean on release day. + go-version-file: go.mod + cache: true + + - name: Verify gofmt + run: | + unformatted="$(gofmt -l .)" + if [ -n "$unformatted" ]; then + echo "::error::These files are not gofmt'd:" + echo "$unformatted" + exit 1 + fi + + - name: Verify go.mod is tidy + run: | + go mod tidy + if ! git diff --quiet -- go.mod go.sum; then + echo "::error::go.mod/go.sum are out of date — run 'go mod tidy' and commit the result." + git diff -- go.mod go.sum + exit 1 + fi + + - name: Build + run: go build ./... + + - name: Vet + run: go vet ./... + + # The View layer is testable without a TTY, so the whole suite runs + # headless. -race catches the async tea.Cmd paths (status/ping polling). + - name: Test + run: go test -race ./... + + # Catch .goreleaser.yaml errors here rather than on a tag push, where the + # only symptom is a failed release job after the tag already exists. + goreleaser-config: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Check GoReleaser config + uses: goreleaser/goreleaser-action@v6 + with: + distribution: goreleaser + version: latest + args: check From 3bbf5a941ebfee328fc7b5fc81f9057512056466 Mon Sep 17 00:00:00 2001 From: Phundahl <89451493+Phundahl@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:39:14 +0200 Subject: [PATCH 2/3] fix(release): correct goreleaser config errors Found by the goreleaser-config job added in this branch. `goreleaser check` rejects the config outright, so the release job would have failed after a tag was already pushed. - nfpms.files -> nfpms.contents. `files` is a v1 name and is not part of the v2 schema; this was the hard failure. - archives.format -> archives.formats. Singular is deprecated in v2 and becomes an error once the deprecation window closes. - Drop -extldflags "{{.Env.LDFLAGS}}". It required an LDFLAGS env var to be set at release time and is a no-op under CGO_ENABLED=0, since no external linker is involved. - Translate the one non-English comment. Co-Authored-By: Claude Opus 5 (1M context) --- .goreleaser.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 957e519..4e3b5af 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -13,13 +13,13 @@ builds: - amd64 - arm64 ldflags: - - -X main.version={{.Version}} -s -w -extldflags "{{.Env.LDFLAGS}}" + - -X main.version={{.Version}} -s -w archives: - - format: tar.gz + - formats: [tar.gz] name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" -# nfpm genererer officielle .deb (Debian/Ubuntu) og .rpm (Fedora/RedHat) pakker +# nfpm builds official .deb (Debian/Ubuntu) and .rpm (Fedora/RedHat) packages nfpms: - id: tailtui-packages homepage: https://github.com/Phundahl/tailtui @@ -32,7 +32,7 @@ nfpms: dependencies: - tailscale bindir: /usr/bin - files: + contents: - src: LICENSE dst: /usr/share/licenses/tailtui/LICENSE From 05d1df63f716d58217e0ea5ebc4e34803266b7bc Mon Sep 17 00:00:00 2001 From: Phundahl <89451493+Phundahl@users.noreply.github.com> Date: Thu, 20 Aug 2026 13:40:22 +0200 Subject: [PATCH 3/3] fix(release): rename deprecated snapshot.name_template goreleaser check treats deprecated properties as a failure (exit 2), so this kept the config job red even though the schema was otherwise valid. version_template is the v2 name. Co-Authored-By: Claude Opus 5 (1M context) --- .goreleaser.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 4e3b5af..40fe4da 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -40,7 +40,7 @@ checksum: name_template: 'checksums.txt' snapshot: - name_template: "{{ .Version }}-snapshot" + version_template: "{{ .Version }}-snapshot" changelog: sort: asc