# builds.sr.ht manifest for cov.sr.ht. One linear pipeline: assemble SCSS, # start a Postgres in the VM, test, package with abuild, publish, upload the # coverage profile to cov.sr.ht itself. # # 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. 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: # The UUIDs -> ~/.s3-cache-key-{id,secret} and ~/.srht-token. # See docs/ci.md#secrets. # ~/.srht-token holds a tokens.sr.ht WORKING TOKEN, one secret shared with # bench.sr.ht's pipeline rather than a per-service one: minted once, for a # person, carrying the grants of every service it reaches. This build needs # three of them — cov:upload for the coverage upload, bench:upload for the # benchmark upload, artifacts:upload for the apk — and bench's build needs the # same three from the same file. A token missing one fails that service's # upload and no other. # # The grant was spelled cover:upload before the rename and grants are compared # literally, so a token minted then uploads nothing here. That, and the # ~/.cover-token plane this replaced, are in 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: coverage DIR: services/coverage PROJDIR: sr-ht-monorepo/services/coverage CACHE_NS: sr-ht-cover PG_DB: coversrht # CORE_VER must track the deployment's SRHT_CORE_VER; BOOTSTRAP_REV is the # submodule commit core.sr.ht pins at that tag. See docs/ci.md#environment. CORE_VER: "0.84.7" BOOTSTRAP_REV: 779ad9f174ea5ab7e755f6df0ec9e5912d67dd16 COVER_ORIGIN: https://cov.srht.bigb.es COVER_REPO: "~bigbes/sr-ht-cover" # The other half of the cross: the same repository name on the sibling that # stores benchmarks, because it is the repository `sources:` clones. # See docs/ci.md#bench. BENCH_ORIGIN: https://bench.srht.bigb.es BENCH_REPO: "~bigbes/sr-ht-cover" # 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: "no" ARTIFACTS_ENDPOINT: https://artifacts.srht.bigb.es ARTIFACTS_CHANNEL: "~bigbes/main" ARTIFACTS_DIST: v3.22 # Literal paths relative to $HOME, and not a fallback for the upload — the # trade-off is argued in 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 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" # An empty DSN would skip every database suite and leave the build green # over untested code — that is the 12.6% vs 87.4% gap. docs/ci.md#test. if [ -z "$COVERSRHT_TEST_PG" ]; then echo "COVERSRHT_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 # -covermode=atomic (real hit counts) and $HOME (that is where artifacts: # looks, and abuild packages this checkout in place). docs/ci.md#test. go test -covermode=atomic -coverprofile="$HOME/cover.out" ./... go tool cover -func="$HOME/cover.out" | tail -1 - build: | cd "$PROJDIR" # -d: makedepends come from `packages:`. 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 - bench: | # The other half of the dogfooding cross (SPEC ch. 13): this service's own # benchmarks, uploaded to bench.sr.ht. Before coverage and not after, # because that one is this service's own and stays last. docs/ci.md#bench. cd "$PROJDIR" # BenchmarkTrend needs a database and SKIPS without the DSN, printing no # line at all, so the test task's guard stands here too. # docs/ci.md#the-dsn-guard-and-the-two-greps. if [ -z "$COVERSRHT_TEST_PG" ]; then echo "COVERSRHT_TEST_PG is unset: BenchmarkTrend would skip silently," >&2 echo "and this build would upload part of a file without saying so." >&2 exit 1 fi # A redirect and a cat and NOT `| tee`, which would hand the task tee's # exit status. $HOME is where artifacts look. docs/ci.md#bench. make -s bench > "$HOME/bench.txt" cat "$HOME/bench.txt" # One name per package with benchmarks in it: `go test -bench` matching # nothing prints ok and exits 0, and an empty file is valid benchfmt, so # without these the build would upload nothing and report success. # docs/ci.md#the-dsn-guard-and-the-two-greps. grep -q '^BenchmarkParse' "$HOME/bench.txt" grep -q '^BenchmarkTrend' "$HOME/bench.txt" if [ ! -r ~/.srht-token ]; then echo "no ~/.srht-token: this build has no bench.sr.ht credentials" echo "the benchmarks ran and are above; nothing was uploaded" exit 0 fi # GIT_REF is absent on a manual build and ref is optional; key is the # idempotency key; visibility acts only on the POST that creates # $BENCH_REPO. Both prefixes: this pipeline builds tags too. # docs/ci.md#the-bench-request. 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" # Tracing off to the end: the header must not reach the log. set +x curl -sS --fail-with-body -X POST \ -H "Authorization: Bearer $(cat ~/.srht-token)" \ --data-binary "@$HOME/bench.txt" \ "$url" echo - coverage: | # Dogfooding (SPEC ch. 13), LIVE: the instance is deployed and the token # secret is listed above. The guard below now only covers a build running # without secrets (a manual submission that did not ask for them); with # the file present the upload is fatal on purpose, and this task is last # on purpose. See docs/ci.md#coverage. cd "$PROJDIR" if [ ! -r ~/.srht-token ]; then echo "no ~/.srht-token: this build runs without secrets (see docs/ci.md#coverage)" echo "the profile is still available as this build's cover.out artifact" exit 0 fi # GIT_REF is absent on a manually submitted build; ref is optional for the # API. key is SPEC ch. 4's idempotency key. docs/ci.md#the-request. # Both prefixes are stripped: this pipeline builds tags too, and a tag # build would otherwise report ref=refs/tags/v0.10.0. 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" # Tracing off to the end: the Authorization header must not reach the log. # No Content-Type (the service sniffs); --fail-with-body prints the JSON # error and still exits non-zero. docs/ci.md#the-request. set +x curl -sS --fail-with-body -X POST \ -H "Authorization: Bearer $(cat ~/.srht-token)" \ --data-binary "@$HOME/cover.out" \ "$url" echo