feat(hive-forge): add artifact-get verb to download CI run artifacts

Forgejo 15 has no REST endpoint to download an Actions artifact — the
only path is the web UI download route, which is keyed by the run's
global id rather than the per-repo run number shown in run-page URLs.
The REST artifacts list route keys off the run number instead, so the
two can't be chained directly.

artifact-get takes the run number (what pr-status surfaces as a CI
context target_url), translates it to the global run id via the REST
runs list by matching each run's html_url tail, then GETs the web
download route with the agent's forge token. Saves the artifact zip to
a path (default /tmp/forge-artifact-<name>.zip) or streams to stdout
with -o -.

The artifact name is percent-encoded into the path. The encoder that
list already used for query-string filters is promoted to a shared
verbs::pct_encode helper so both call sites stay in sync.

Lets an agent pull a CI-built artifact (e.g. a paper PDF) into /shared
without host access.
This commit is contained in:
atlas 2026-06-15 17:29:07 +02:00 committed by mara
commit 6490fc422e
6 changed files with 184 additions and 41 deletions

View file

@ -120,6 +120,11 @@ enum Verb {
/// Download an attachment by UUID or URL. Saves to a temp file and
/// prints the path (pass `-o -` to stream raw bytes to stdout).
AttachmentGet(verbs::attachment_get::Args),
/// Download a CI Actions artifact from a run (`<name> --run <n>`).
/// Forgejo serves artifacts only via the web route, not REST; the
/// caller supplies the run number + artifact name. Saves a zip
/// (or `-o -` to stream).
ArtifactGet(verbs::artifact_get::Args),
}
fn main() -> Result<()> {
@ -156,5 +161,6 @@ fn main() -> Result<()> {
Verb::AttachIssue(a) => verbs::attach::run_issue(&client, a),
Verb::AttachComment(a) => verbs::attach::run_comment(&client, a),
Verb::AttachmentGet(a) => verbs::attachment_get::run(&client, a),
Verb::ArtifactGet(a) => verbs::artifact_get::run(&client, a),
}
}