Adds forges/gitea/bin/gitea-actions, a read-only CLI for Gitea Actions
runs and job logs.
Why
runtime.bats builds the image and boots real containers, so it only ever
runs in CI — a dejima session has no Docker daemon by design. That means the
one suite a session cannot run is the one whose failures it most needs to
read, and until now the only route from a red build back into the session was
the operator opening the run in a browser and pasting the log in.
This came up the ordinary way: a runtime.bats test failed in CI on #69,
and getting at the reason took an operator round-trip.
Why a third CLI rather than gitea-pr checks
forges/gitea/bin/gitea-issue already establishes the shape — one
self-contained file per Gitea domain, deliberate copies rather than a shared
library, with the duplicated config/token/curl preamble pinned across them by static.bats. Runs are also repo-scoped rather than PR-scoped: a push to main has runs and no PR to hang them off.
RUN is the number in the web URL (.../actions/runs/52). Left out, it
means the newest run for HEAD's commit — after a push, that is nearly
always the question. logs prints only the jobs that failed unless asked
otherwise, and strips the runner's per-line RFC3339 stamps unless --timestamps is given, since that output usually lands in an agent's
context.
$ gitea-actions jobs 52
run 52:
0 success sandbox (audit)
...
5 failure sandbox (remote)
7 failure host-docker
$ gitea-actions logs 52 --job host-docker | grep 'not ok'
not ok 33 a derived project image gets the package and keeps the base privilege posture
Two API details, neither discoverable
Runs are addressed by an internal id that no URL shows. The number in .../actions/runs/52 is run_number; the API wants the id field, which
was 10306 for that run. resolve_run scans one page of the run list to
map one to the other, so no caller has to know.
limit on the run list is ignored unless page is passed with it. ?limit=5 returned all 53 runs. Caught because runs --limit 4 printed
everything.
The job index in jobs output is likewise not a field — it is the tail of
each job's html_url, and the list does not arrive in that order.
Read-only
It authenticates with the same write-scoped token as gitea-pr, so
"it only fetches runs and logs" is pinned as a property of the file: static.bats fails the build if it ever grows a -X POST/PUT/PATCH/DELETE,
a --data or a -d. It is also added to the existing test that no gitea CLI
puts the token in argv.
Also
forges/gitea/forge.conf's install key names it, which is what makes providers.bats check it exists and is executable. The Dockerfile needed no
change — it already installs everything under forges/*/bin/.
Suites run locally: static 161, providers 34, project 71, audit 139,
config 84. All green.
**Summary generated by LLM agent**
Adds `forges/gitea/bin/gitea-actions`, a read-only CLI for Gitea Actions
runs and job logs.
## Why
`runtime.bats` builds the image and boots real containers, so it only ever
runs in CI — a dejima session has no Docker daemon by design. That means the
one suite a session cannot run is the one whose failures it most needs to
read, and until now the only route from a red build back into the session was
the operator opening the run in a browser and pasting the log in.
This came up the ordinary way: a `runtime.bats` test failed in CI on #69,
and getting at the reason took an operator round-trip.
## Why a third CLI rather than `gitea-pr checks`
`forges/gitea/bin/gitea-issue` already establishes the shape — one
self-contained file per Gitea domain, deliberate copies rather than a shared
library, with the duplicated config/token/curl preamble pinned across them by
`static.bats`. Runs are also repo-scoped rather than PR-scoped: a push to
`main` has runs and no PR to hang them off.
## Usage
```
gitea-actions runs [--limit N]
gitea-actions jobs [RUN]
gitea-actions logs [RUN] [--job NAME|INDEX] [--all] [--timestamps]
```
`RUN` is the number in the web URL (`.../actions/runs/52`). Left out, it
means the newest run for `HEAD`'s commit — after a push, that is nearly
always the question. `logs` prints only the jobs that failed unless asked
otherwise, and strips the runner's per-line RFC3339 stamps unless
`--timestamps` is given, since that output usually lands in an agent's
context.
```
$ gitea-actions jobs 52
run 52:
0 success sandbox (audit)
...
5 failure sandbox (remote)
7 failure host-docker
$ gitea-actions logs 52 --job host-docker | grep 'not ok'
not ok 33 a derived project image gets the package and keeps the base privilege posture
```
## Two API details, neither discoverable
- **Runs are addressed by an internal id that no URL shows.** The number in
`.../actions/runs/52` is `run_number`; the API wants the `id` field, which
was `10306` for that run. `resolve_run` scans one page of the run list to
map one to the other, so no caller has to know.
- **`limit` on the run list is ignored unless `page` is passed with it.**
`?limit=5` returned all 53 runs. Caught because `runs --limit 4` printed
everything.
The job index in `jobs` output is likewise not a field — it is the tail of
each job's `html_url`, and the list does not arrive in that order.
## Read-only
It authenticates with the same write-scoped token as `gitea-pr`, so
"it only fetches runs and logs" is pinned as a property of the file:
`static.bats` fails the build if it ever grows a `-X POST/PUT/PATCH/DELETE`,
a `--data` or a `-d`. It is also added to the existing test that no gitea CLI
puts the token in argv.
## Also
`forges/gitea/forge.conf`'s `install` key names it, which is what makes
`providers.bats` check it exists and is executable. The Dockerfile needed no
change — it already installs everything under `forges/*/bin/`.
Suites run locally: static 161, providers 34, project 71, audit 139,
config 84. All green.
A sandbox has no Docker daemon, so the half of the suite that boots real
containers only ever runs in CI - and until now the only way to see why one
of those failed was for the operator to read the run in a browser and paste
it in. The session that wrote the code could not see what it did.
A third self-contained twin rather than a subcommand of gitea-pr: runs are
repo-scoped, not PR-scoped (a push to main has runs and no PR), and the
existing pair already establishes one file per Gitea domain with a
duplicated preamble pinned by static.bats.
Two things about the API are worth knowing and neither is discoverable:
runs are addressed by an internal id that no URL shows, and `limit` on the
run list is ignored unless `page` is passed with it. Both are handled here
so no caller meets them.
With no run given it resolves HEAD's commit - matched on head_sha, since a
pull_request run reports no branch at all - and prints only the jobs that
failed. It reads and never writes, which static.bats pins: it authenticates
with the same write-scoped token as gitea-pr.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary generated by LLM agent
Adds
forges/gitea/bin/gitea-actions, a read-only CLI for Gitea Actionsruns and job logs.
Why
runtime.batsbuilds the image and boots real containers, so it only everruns in CI — a dejima session has no Docker daemon by design. That means the
one suite a session cannot run is the one whose failures it most needs to
read, and until now the only route from a red build back into the session was
the operator opening the run in a browser and pasting the log in.
This came up the ordinary way: a
runtime.batstest failed in CI on #69,and getting at the reason took an operator round-trip.
Why a third CLI rather than
gitea-pr checksforges/gitea/bin/gitea-issuealready establishes the shape — oneself-contained file per Gitea domain, deliberate copies rather than a shared
library, with the duplicated config/token/curl preamble pinned across them by
static.bats. Runs are also repo-scoped rather than PR-scoped: a push tomainhas runs and no PR to hang them off.Usage
RUNis the number in the web URL (.../actions/runs/52). Left out, itmeans the newest run for
HEAD's commit — after a push, that is nearlyalways the question.
logsprints only the jobs that failed unless askedotherwise, and strips the runner's per-line RFC3339 stamps unless
--timestampsis given, since that output usually lands in an agent'scontext.
Two API details, neither discoverable
.../actions/runs/52isrun_number; the API wants theidfield, whichwas
10306for that run.resolve_runscans one page of the run list tomap one to the other, so no caller has to know.
limiton the run list is ignored unlesspageis passed with it.?limit=5returned all 53 runs. Caught becauseruns --limit 4printedeverything.
The job index in
jobsoutput is likewise not a field — it is the tail ofeach job's
html_url, and the list does not arrive in that order.Read-only
It authenticates with the same write-scoped token as
gitea-pr, so"it only fetches runs and logs" is pinned as a property of the file:
static.batsfails the build if it ever grows a-X POST/PUT/PATCH/DELETE,a
--dataor a-d. It is also added to the existing test that no gitea CLIputs the token in argv.
Also
forges/gitea/forge.conf'sinstallkey names it, which is what makesproviders.batscheck it exists and is executable. The Dockerfile needed nochange — it already installs everything under
forges/*/bin/.Suites run locally: static 161, providers 34, project 71, audit 139,
config 84. All green.