Files
terdut-server/.gitea/workflows/ci.yaml
T
Niklas Ye 69fcc24a4d
CI / chart (push) Successful in 0s
CI / test (push) Successful in 57s
Drive the pipeline through make, the way riksdata and rd-web do
Both workflows restated the build in YAML: gofmt, go vet and go test inline
in two places, buildx inline in a third, and the chart's version sed'd into
Chart.yaml before packaging. The Makefile added in 1081260 then described
the same checks a second time for local use, which made "green locally means
green in CI" a promise about keeping two files in step rather than a
property of the setup.

riksdata and rd-web never had that problem — their workflows call make and
have done all along. This repo was the odd one out, and only because it had
no Makefile until today. Now ci.yaml runs `make fmt lint test`, release.yaml
runs the same plus `make binaries`, `make push`, `make helm-package` and
`make helm-push`, and the reasoning behind each check lives on the target
rather than in whichever YAML file was edited last.

Three things change rather than just move:

The chart is linted before it is published. release.yaml packaged and pushed
without ever rendering the templates, so a chart that did not compile would
have reached the registry and been found by Flux. ci.yaml gained a chart job
for the same reason.

helm package --version --app-version replaces the sed. The published
metadata is identical, but the tree is no longer mutated mid-build, and it
is what the rest of the release process already assumed happened.

`make push` refuses VERSION=dev. Publishing is one command now, so it is
also one command to run by accident; dev is not a version anyone releases.

Deliberately not moved: uploading the release assets. Compiling them is
`make binaries` and runs anywhere, but the upload needs a token and the
Gitea release API, which is the workflow's business and not something worth
a target.

`push` builds and pushes in one step, unlike riksdata's separate build and
push, because buildx cannot load a multi-platform image into the local store
— it can only push it. `build` stays single-platform and local-only.

Claude-Session: https://claude.ai/code/session_01S7R4gWTz5wh5xCY4nCSJjN
2026-09-01 22:36:54 +02:00

98 lines
4.1 KiB
YAML

name: CI
# The release workflow gates a tag, which is late: a broken commit sits green until
# somebody decides to publish. This runs the same checks on the way in.
#
# push is scoped to main rather than all branches so that a branch pushed as part of a
# pull request is not checked twice.
#
# No actions/checkout, deliberately -- same as the letsvisit and charts workflows. The
# runner image is ubuntu:22.04 whose `nodejs` package is Node 12, and actions/checkout@v4
# is built with ES2022 static initialiser blocks, so it dies with
# `SyntaxError: Unexpected token '{'` before running. Cloning with git directly avoids JS
# actions entirely. This repo is public, so the clone needs no credential at all.
#
# `${{ }}` values are passed through `env:` and referenced as quoted shell variables: a
# ref name is attacker-influenced by anyone who can push a branch or open a PR, and
# expanding one straight into `run:` is a shell-injection vector.
on:
push:
branches: [main]
pull_request:
# A rapid series of pushes only needs the last one checked.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
env:
REPO_URL: https://git.ryuvia.com/niklas/terdut-server.git
jobs:
test:
runs-on: ubuntu-latest
container:
# Runs inside the toolchain image rather than installing Go per job. Note this puts
# the job on the dind bridge, which cannot reach github.com or get.helm.sh --
# proxy.golang.org and git.ryuvia.com are reachable, which is all this job needs.
image: golang:1.26.6-bookworm
# act_runner destroys a job's own volumes when it finishes, so without these every
# run re-downloads the whole module graph. The names must appear in the runner's
# container.valid_volumes allowlist (charts/act-runner in the k8s repo); unlisted
# volumes are dropped silently, so a workflow that looks correct can still be
# running uncached.
volumes:
- go-mod-cache:/go/pkg/mod
- go-build-cache:/root/.cache/go-build
- gobin-cache:/go/bin
steps:
- name: Checkout
env:
REF_NAME: ${{ github.ref_name }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
if [ -n "$HEAD_SHA" ]; then
# A pull_request ref_name is "<n>/merge", which is not a fetchable branch.
git clone "$REPO_URL" .
git checkout -q "$HEAD_SHA"
else
git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" .
fi
# The gate is the Makefile's rather than a second copy of it here, the way riksdata
# and rd-web already do it. `make fmt lint test` is exactly what a developer runs, so
# a green pipeline and a green working copy mean the same thing by construction
# instead of by remembering to update two files together.
#
# The reasoning that used to live here moved with the targets: why gofmt is checked
# at all (import order survives `go vet`, and both repos sat unformatted through a
# green run and a release -- 9046f6e), why both of gofmt's failure modes need
# handling, and why `test` adds -race when this job does not have to.
- name: Format, vet and test
run: make fmt lint test
# Host mode, no `container:`: helm is baked into the runner image, and a container job
# could not install it -- get.helm.sh is unreachable from the dind bridge. Same reason
# release.yaml's chart job runs on the host.
#
# The chart had no lint step in any workflow until 2026-09-01: release.yaml packaged and
# pushed it without rendering it first, so a template that did not compile would have
# been found by Flux rather than here.
chart:
runs-on: ubuntu-latest
steps:
- name: Checkout
env:
REF_NAME: ${{ github.ref_name }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
if [ -n "$HEAD_SHA" ]; then
git clone "$REPO_URL" .
git checkout -q "$HEAD_SHA"
else
git clone --depth=1 --branch "$REF_NAME" "$REPO_URL" .
fi
- name: Lint and render the chart
run: make helm-lint