# builds.sr.ht manifest for sr-ht-ecore. One linear pipeline: restore the Go # caches, refuse an unformatted or vet-dirty tree, test with a coverage profile, # run the benchmarks, then upload both to the instance's own cov.sr.ht and # bench.sr.ht. # # This repository is a LIBRARY — no cmd/, no daemon, no stylesheet, no apk — and # seven services pin it by pseudo-version, which is exactly why it needs a # pipeline of its own: a break here is discovered in whichever service next runs # `go get -u`, at the moment that service is being released. Everything a # sibling manifest carries for its package (scss, keygen, abuild, publish) has # no meaning here and is absent rather than stubbed, and # there is no postgres task because nothing in this module imports database/sql: # no test opens a database, no test skips on a missing DSN. # # The reasoning lives in comments here rather than in a docs/ci.md, because this # repository has no docs/ tree. Keep it under 16 KiB: builds.sr.ht stores the # submitted manifest in a varchar(16384), and a manifest over that cannot be # submitted at all — the failure is a branch with no CI, not a red build. image: alpine/edge packages: - go - git # Every task below drives the Makefile. The sibling manifests never list this # and their `make test` works, so the image evidently ships one — but abuild's # 14 dependencies do not include it (checked on pkgs.alpinelinux.org), so what # they rely on is the image's furniture rather than a package they asked for. # A build that needs make asks for make. - make # For fetching the art binary and for the two uploads, and for nothing else. - curl secrets: # ~/.srht-token holds a tokens.sr.ht WORKING TOKEN, and it is one secret shared # with the cov.sr.ht and bench.sr.ht pipelines rather than a per-repository # one: the credential is minted once, for a person, and carries the grants of # every service it is meant to reach. This build needs cov:upload and # bench:upload from it; a token missing one fails that upload and no other. # The grant was cover:upload before the service was renamed to cov.sr.ht, and # grants are compared literally, so a token minted before the rename uploads # no coverage here — re-mint it on tokens.sr.ht and replace this secret. - c7968415-1a6d-4ca0-a188-150fb7f57b65 # ~/.srht-token sources: - https://git.srht.bigb.es/~bigbes/sr-ht-monorepo#0129ee07d84676509189d9dd3cfacbebb0a75b09 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: ecore DIR: lib/ecore PROJDIR: sr-ht-monorepo/lib/ecore ARTIFACTS_ENDPOINT: https://artifacts.srht.bigb.es CACHE_NS: sr-ht-ecore COVER_ORIGIN: https://cov.srht.bigb.es COVER_REPO: "~bigbes/sr-ht-ecore" BENCH_ORIGIN: https://bench.srht.bigb.es BENCH_REPO: "~bigbes/sr-ht-ecore" # Literal paths relative to $HOME — which is why the two tasks below write there # and not into the checkout. They are not a fallback for the uploads: a build # submitted without secrets still leaves both files downloadable, and a POST # that failed leaves the body that was meant to be sent. artifacts: - cover.out - bench.txt submitter: git.sr.ht: allow-refs: - refs/heads/master # A library is consumed by tag as well as by pseudo-version, so a pushed # tag has to be tested too. Without this line it starts no build at all. - "refs/tags/v*" tasks: # The art cache client. Its PATH export goes to ~/.buildenv, # which only the NEXT task sources — hence two tasks and not one. # # The guard is not in the donors' copies of this task, and it is here because # this repository is a library: a contributor's manually submitted build asks # for no secrets, and art init would then die on a missing token # before a single test had run. Without the cache the build is slower and # exactly as truthful. - art_install: | "$HOME/$REPO"/ci/lib/art.sh install - art_init: | "$HOME/$REPO"/ci/lib/art.sh init - cache_restore: | "$HOME/$REPO"/ci/lib/cache.sh restore - lint: | cd "$PROJDIR" # check-fmt and not fmt: `gofmt -l` prints the offending files and STILL # EXITS 0, so a task that ran plain gofmt could not fail, and `make fmt` # rewrites — a gate that edits the tree it is judging is not a gate. make check-fmt make vet - test: | cd "$PROJDIR" # -covermode=atomic (real hit counts, which is what cov.sr.ht reads) and # $HOME, because that is where artifacts: looks. The Makefile owns the # command; this task owns the destination. `make cover` also refuses an # empty profile, which would otherwise upload a report covering nothing # and call it a success. make cover COVERPROFILE="$HOME/cover.out" - bench: | cd "$PROJDIR" # -s so make does not echo the recipe into the body; a redirect and a cat # and NOT `| tee`, which would hand this task tee's exit status and let a # failing benchmark pass. # # What lands in the file is benchfmt and nothing else because the Makefile # filters it (see BENCH_FILTER there): a benchmark that provokes logging # in the code under test writes those lines into this same stream, and one # of the benchmarks in this tree currently produces hundreds of megabytes # of them. The command that ran is echoed to stderr, so it is in this # task's log and not in the body being uploaded. make -s bench > "$HOME/bench.txt" cat "$HOME/bench.txt" # `go test -bench` that matches nothing prints `ok` and exits 0, and a # file with no benchmark lines is still valid benchfmt — so a renamed or # deleted benchmark would upload an empty run and report success. One # name per benchmark file, so that losing any one file is caught: grep -q '^BenchmarkValidate' "$HOME/bench.txt" # bearer grep -q '^BenchmarkRequestLogger' "$HOME/bench.txt" # chimw grep -q '^BenchmarkRequire' "$HOME/bench.txt" # csrf grep -q '^BenchmarkParse' "$HOME/bench.txt" # grants grep -q '^BenchmarkChain' "$HOME/bench.txt" # middleware - cache_save: | "$HOME/$REPO"/ci/lib/cache.sh save - coverage: | cd "$PROJDIR" # The gate is the honest answer to a build that was handed no secrets: the # profile is made, it is this build's cover.out artifact, and it can be # POSTed by hand. With the file present the upload is fatal on purpose. if [ ! -r ~/.srht-token ]; then echo "no ~/.srht-token: this build has no cov.sr.ht credentials" 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 and ref is optional for # the API; key is the idempotency key, so a resubmitted job replaces its # own report instead of adding a second one. Both prefixes are stripped # because this pipeline builds tags too, and a tag build would otherwise # report ref=refs/tags/v0.1.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 of the task: the Authorization header must not # reach the log. No Content-Type — the service sniffs the format, and a # wrong one is a 400. --fail-with-body prints the JSON error AND still # exits non-zero, which plain --fail does not. set +x curl -sS --fail-with-body -X POST \ -H "Authorization: Bearer $(cat ~/.srht-token)" \ --data-binary "@$HOME/cover.out" \ "$url" echo - bench_upload: | cd "$PROJDIR" if [ ! -r ~/.srht-token ]; then echo "no ~/.srht-token: this build has no bench.sr.ht credentials" echo "the benchmarks ran and are in the bench task's log" echo "the file is this build's bench.txt artifact, and can be POSTed by hand" exit 0 fi # visibility acts only on the POST that creates $BENCH_REPO; on every # later run it is ignored. 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