From dc53d49c3e1ed94133f68c305cea64d7d9dbf9d2 Mon Sep 17 00:00:00 2001 From: Niklas Ye Date: Wed, 19 Aug 2026 21:29:36 +0200 Subject: [PATCH] ci: fail on code that is not gofmt'd go vet says nothing about import order, so when the move to git.ryuvia.com rewrote every import path without re-sorting them -- the new path sorts before github.com/..., where the old one sorted after -- both repos went through a green CI run and a release unformatted. Added to the release workflow as well as CI, so the two keep running the same checks; ci.yaml's header claims exactly that, and a check in one but not the other would quietly make it false. The step handles gofmt's two failure modes separately because they do not look alike: a misformatted file is listed on stdout with exit 0, so the failure has to be raised by hand, while a file that does not parse prints nothing to stdout and exits 2 -- which a plain emptiness test reads as success. Verified against all three cases (clean, misformatted, unparseable) before committing. --- .gitea/workflows/ci.yaml | 24 ++++++++++++++++++++++++ .gitea/workflows/release.yaml | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 59e48c7..7643857 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -56,6 +56,30 @@ jobs: git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" . fi + # This exists because `go vet` does not look at import order: the move to + # git.ryuvia.com rewrote every import path without re-sorting, the new path sorts + # before github.com/..., and both repos sat unformatted through a green CI run and + # a release before anyone noticed. + # + # Both of gofmt's failure modes need handling, and they are not alike. A file that + # is merely misformatted is listed on stdout with exit 0 -- so the failure has to + # be raised by hand. A file that does not parse is the opposite: nothing on stdout + # and exit 2, which a naive `[ -n "$unformatted" ]` reads as success. The first + # draft of this step had exactly that hole. + - name: Format + run: | + if ! unformatted=$(gofmt -l .); then + echo "::error::gofmt could not parse the tree" + gofmt -l . # re-run unredirected so the parse errors reach the log + exit 1 + fi + if [ -n "$unformatted" ]; then + echo "::error::not gofmt'd:" + echo "$unformatted" + gofmt -d . + exit 1 + fi + - name: Vet run: go vet ./... diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml index bcd1f46..c22a24b 100644 --- a/.gitea/workflows/release.yaml +++ b/.gitea/workflows/release.yaml @@ -41,6 +41,30 @@ jobs: REF_NAME: ${{ github.ref_name }} run: git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" . + # This exists because `go vet` does not look at import order: the move to + # git.ryuvia.com rewrote every import path without re-sorting, the new path sorts + # before github.com/..., and both repos sat unformatted through a green CI run and + # a release before anyone noticed. + # + # Both of gofmt's failure modes need handling, and they are not alike. A file that + # is merely misformatted is listed on stdout with exit 0 -- so the failure has to + # be raised by hand. A file that does not parse is the opposite: nothing on stdout + # and exit 2, which a naive `[ -n "$unformatted" ]` reads as success. The first + # draft of this step had exactly that hole. + - name: Format + run: | + if ! unformatted=$(gofmt -l .); then + echo "::error::gofmt could not parse the tree" + gofmt -l . # re-run unredirected so the parse errors reach the log + exit 1 + fi + if [ -n "$unformatted" ]; then + echo "::error::not gofmt'd:" + echo "$unformatted" + gofmt -d . + exit 1 + fi + - name: Vet run: go vet ./...