# builds.sr.ht manifest for spec.sr.ht. One linear pipeline: install the cache # helper, assemble the shared SCSS, stamp a version, restore caches, start a # Postgres in the VM, test, package with abuild, publish, save caches, upload # this build's own coverage and benchmarks to cov.sr.ht and bench.sr.ht. # # The reasoning behind every task lives in docs/ci.md, not here: builds.sr.ht # stores the submitted manifest in a varchar(16384), so a manifest over 16 KiB # cannot be submitted at all — and the failure is a branch with no CI, not a red # build. Add paragraphs to docs/ci.md and a pointer here. image: alpine/edge packages: - abuild - curl - go - git - sassc - minify # For the database suites, not for the package — see docs/ci.md#packages. - postgresql - postgresql-client secrets: # One tokens.sr.ht working token, the same one the siblings mount, carrying # artifacts:upload, cov:upload and bench:upload. See docs/ci.md#secrets. - c7968415-1a6d-4ca0-a188-150fb7f57b65 # ~/.srht-token sources: - https://git.srht.bigb.es/~bigbes/sr-ht-monorepo#ed91e78236153e042fca4722812191969e86ae0f environment: # A package build must not depend on the workspace. GOWORK=off makes this job # resolve lib/core, lib/ecore and lib/thistle from the pseudo-versions in this # module's own go.mod — the versions the released apk is actually built from — # instead of from whatever is in the tree. It also stops the build writing to # go.work.sum, which is what stamped fedgw's binary -dirty and failed its # check-version. Workspace compatibility is the dispatcher's job: it smoke- # builds every project against the tree on each push. GOWORK: "off" # What ci/lib/*.sh needs to know about this project. REPO: sr-ht-monorepo PROJECT: specs DIR: services/specs PROJDIR: sr-ht-monorepo/services/specs CACHE_NS: sr-ht-spec PG_DB: specsrht # Where the apk goes, and the only place it goes: one channel of # artifacts.sr.ht holds the packages of every sibling service, so a consumer # adds one repository line. See docs/ci.md#publish. # A branch build tests and does not publish: ci/lib/dispatch.sh rewrites this # to "yes" for a master or tag push and for nothing else. docs/ci.md#publish PUBLISH: "yes" ARTIFACTS_ENDPOINT: https://artifacts.srht.bigb.es ARTIFACTS_CHANNEL: "~bigbes/main" ARTIFACTS_DIST: v3.22 # Must track the srht deployment's SRHT_CORE_VER, or this service's theme # drifts from the rest of the instance. BOOTSTRAP_REV is the submodule commit # core.sr.ht pins at that tag; bump the two together. CORE_VER: "0.84.7" BOOTSTRAP_REV: 779ad9f174ea5ab7e755f6df0ec9e5912d67dd16 # Dogfooding. Both repo names are the `sources:` line read as ~owner/repo. # docs/ci.md#coverage, docs/ci.md#bench. COVER_ORIGIN: https://cov.srht.bigb.es COVER_REPO: "~bigbes/sr-ht-spec" BENCH_ORIGIN: https://bench.srht.bigb.es BENCH_REPO: "~bigbes/sr-ht-spec" # Literal paths relative to $HOME, and not a fallback. docs/ci.md#artifacts. artifacts: - cover.out - bench.txt submitter: git.sr.ht: allow-refs: - refs/heads/master # Tags build too, now that the version task reads them: pushing v0.9.0 is # what produces the 0.9.0 apk. See docs/ci.md#version. - "refs/tags/v*" tasks: # S3-backed CI cache helper; installed first so scss can already use it. # install.sh's PATH export goes to ~/.buildenv, which only the NEXT task # sources — hence two tasks and not one. See ci/lib/art.sh. - art_install: | "$HOME/$REPO"/ci/lib/art.sh install - art_init: | "$HOME/$REPO"/ci/lib/art.sh init - scss: | "$HOME/$REPO"/ci/lib/scss.sh - keygen: | "$HOME/$REPO"/ci/lib/keygen.sh - version: | "$HOME/$REPO"/ci/lib/version.sh - cache_restore: | "$HOME/$REPO"/ci/lib/cache.sh restore - postgres: | "$HOME/$REPO"/ci/lib/postgres.sh - test: | cd "$PROJDIR" # Two gates, and the second is the one that closes the hole: the guard # proves the DSN was exported, REQUIRE_PG proves the suites ran on it — # under it a skip becomes a failure naming the test. `options="!check"` # means this task is the only place they run at all. docs/ci.md#test. if [ -z "$SPECSRHT_TEST_PG" ]; then echo "SPECSRHT_TEST_PG is unset: the postgres task did not export it," >&2 echo "so every database suite would skip and this build would lie." >&2 exit 1 fi export SPECSRHT_TEST_REQUIRE_PG=1 test -z "$(gofmt -l .)" || { gofmt -l .; echo "gofmt: files above need formatting" >&2; exit 1; } go vet ./... # `make cover`, not a bare `go test ./...`: the Makefile names the -timeout # and the coverage flags, and it is the suites `make test` runs, so the # profile is a by-product of the gate. docs/ci.md#test. make cover COVERPROFILE="$HOME/cover.out" - build: | cd "$PROJDIR" # -d: makedepends come from `packages:`. The APKBUILD runs `make css` # before `make build` and asserts the result with `make check-css`. # See docs/ci.md#build. REPODEST=$HOME/packages abuild -d find "$HOME/packages" -name '*.apk' - publish: | "$HOME/$REPO"/ci/lib/publish.sh - cache_save: | "$HOME/$REPO"/ci/lib/cache.sh save - coverage: | # Dogfooding: the profile the test task wrote, POSTed to this instance's # own cov.sr.ht. Before bench, whose run is minutes. docs/ci.md#coverage. cd "$PROJDIR" # Missing or empty is a 400 about a body rather than about the build. test -s "$HOME/cover.out" || { echo "no ~/cover.out" >&2; exit 1; } if [ ! -r ~/.srht-token ]; then echo "no ~/.srht-token: no cov.sr.ht credentials in this build" echo "the profile is this build's cover.out artifact and is not lost" exit 0 fi # Both ref prefixes stripped (this builds tags too), key is the idempotency # key, no Content-Type (the service sniffs), set +x so the header stays out # of the log, --fail-with-body so a rejection is loud and readable. # docs/ci.md#the-two-requests. ref="${GIT_REF#refs/heads/}"; ref="${ref#refs/tags/}" url="$COVER_ORIGIN/api/v1/repos/$COVER_REPO/reports" url="$url?commit=$(git rev-parse HEAD)&ref=$ref&key=$JOB_ID&job_url=$JOB_URL" echo "uploading cover.out to $url" set +x curl -sS --fail-with-body -X POST \ -H "Authorization: Bearer $(cat ~/.srht-token)" \ --data-binary "@$HOME/cover.out" \ "$url" echo - bench: | # Dogfooding: this service's own benchmarks, to this instance's own # bench.sr.ht. Last and its own task on purpose, and this VM measures a # shape rather than a number. docs/ci.md#bench. cd "$PROJDIR" # -s so the recipe is not echoed into the body, and a redirect and a cat # and NOT `| tee` — tee's exit status would let a failed run pass. make -s bench > "$HOME/bench.txt" cat "$HOME/bench.txt" # `go test -bench` matching nothing prints `ok` and exits 0, and an empty # body is valid benchfmt, so the names are checked. docs/ci.md#the-two-greps grep -q '^BenchmarkCompare' "$HOME/bench.txt" grep -q '^BenchmarkLinkPass' "$HOME/bench.txt" if [ ! -r ~/.srht-token ]; then echo "no ~/.srht-token: no bench.sr.ht credentials in this build" echo "the run is above and is this build's bench.txt artifact" exit 0 fi # The coverage request's shape, plus visibility= — which acts only on the # POST that creates $BENCH_REPO. ref="${GIT_REF#refs/heads/}"; ref="${ref#refs/tags/}" url="$BENCH_ORIGIN/api/v1/repos/$BENCH_REPO/runs" url="$url?commit=$(git rev-parse HEAD)&ref=$ref&key=$JOB_ID&job_url=$JOB_URL" url="$url&visibility=public" echo "uploading bench.txt to $url" set +x curl -sS --fail-with-body -X POST \ -H "Authorization: Bearer $(cat ~/.srht-token)" \ --data-binary "@$HOME/bench.txt" \ "$url" echo