Files
copr-publish/CLAUDE.md
rob thijssen 3701a483af fix: take the build verdict from COPR, not from watch-build
`copr-cli watch-build` holds a long-lived connection to COPR and can stop
responding while the build carries on and finishes normally. The script
treated its exit status as the build's outcome, so a watcher that lost its
connection was reported as a failed build.

Seen in monsoon run 48: COPR build 10835047 succeeded at 08:30:30, the
watcher went silent after 08:09:11, and the runner killed the step at
08:35:50. The job was marked failed even though the RPM built and published
fine, and that false failure also blocked the dependent version-bump job
from running at all.

Keep watch-build for its progress stream, but move it to the background,
bound it with a timeout, and ignore its exit code. Poll `copr-cli status`
for the authoritative state and derive the exit code from that. Polling also
means the script returns as soon as the build settles instead of waiting on
the watcher to notice.

succeeded and skipped (already built) pass; failed and canceled fail; and
never reaching a terminal state within COPR_BUILD_TIMEOUT is reported as a
timeout rather than silently as a build failure.

Adds tests/test-copr-build.sh, which drives the script against a stub
copr-cli. The regression case — hung watcher, successful build — fails
against the previous script by hanging until killed, which is the production
symptom.
2026-08-07 11:57:44 +03:00

3.8 KiB

CLAUDE.md

Context for future agent work in this repo. The README covers consumer-facing usage; this file covers things that aren't obvious from reading the code.

Where this action runs

Hosted on a self-hosted Gitea at git.lair.cafe (remote name origin, SSH url gitea@git.internal:actions/copr-publish.git). Consumers reference it by fully-qualified URL (uses: https://git.lair.cafe/actions/copr-publish@v1) because Gitea's DEFAULT_ACTIONS_URL points at github.com.

There is no CI on this repo itself. The action is tested by running it from a consumer repo (primarily helexa/cortex). When debugging, fetch job logs via the gitea-mcp tools against the consumer repo, not this one — e.g. mcp__gitea-mcp__actions_run_read with owner=helexa, repo=cortex.

tests/test-copr-build.sh covers the parts that don't need a real COPR: it puts a stub copr-cli on PATH and drives scripts/copr-build.sh through succeeded / failed / canceled / skipped / never-settles, plus the case where watch-build hangs. Run it directly (./tests/test-copr-build.sh); it needs nothing but bash and takes a few seconds.

Why the verdict does not come from watch-build

copr-cli watch-build holds a long-lived connection and can stop responding while the build carries on and finishes normally. Observed in monsoon run 48: COPR build 10835047 succeeded at 08:30:30, the watcher went silent after 08:09:11, and the runner killed the step at 08:35:50 — reported as a failed build, which also blocked the dependent version-bump job.

So the script polls copr-cli status for the authoritative state and treats watch-build purely as a progress stream whose exit code is ignored. If you are tempted to simplify this back into if copr-cli watch-build; then, don't.

Tagging & release workflow

We use a floating major tag alongside specific semver tags:

  • v1.0.0, v1.0.1, ... — immutable, annotated, per release.
  • v1 — floating annotated tag, moved forward to the latest v1.x.y on every v1 release. This is what @v1 consumers resolve to.

When cutting a patch/minor release within v1:

git tag -a v1.0.N -m "v1.0.N\n\n<summary>" <sha>
git tag -a v1 -f -m "v1 (floating): latest v1.x release" <sha>
git push origin main v1.0.N
git push origin v1 --force     # floating tag move requires --force

The --force on the v1 push is expected and authorized — that's how the floating tag works. Do not force-push main or immutable vX.Y.Z tags.

A v2 is reserved for the live-streaming behaviour change tracked in issue #1 (stdout timing differs enough that consumers should opt in). Do not quietly land that on v1.

The COPR builder-live.log gotcha

The on-mirror file served by copr-cli download-build is builder-live.log.gz for completed builds — not plain builder-live.log. The script in scripts/copr-build.sh handles both, preferring .gz with zcat. If you add log handling for other COPR artifacts (build.log, root.log, backend.log), assume they are gzipped too.

The HTTP live endpoint at https://download.copr.fedorainfracloud.org/results/<owner>/<project>/<chroot>/<build_id>-<pkg>/builder-live.log serves plaintext during and after the build — that's the path issue #1's live-streaming approach would use, sidestepping the .gz-on-disk issue.

Testing a change

There is no local harness. To verify a change end-to-end:

  1. Commit + push + tag as above (or push a branch and reference it by commit SHA from the consumer).
  2. Trigger a workflow in the consumer repo (e.g. push to helexa/cortex).
  3. Inspect the job log via gitea-mcp — note that job logs come back base64-ish wrapped in a JSON envelope and with \r/\n escapes; pipe through jq -r '.[].text' then sed 's/\\r/\n/g; s/\\n/\n/g' to get something greppable.

Syntax-only check locally: bash -n scripts/copr-build.sh.