fj workflow run: return a run handle (--json) plus --watch/--exit-status #139

Closed
opened 2026-06-11 00:57:41 +00:00 by stephen · 0 comments
Owner

Task

Give fj workflow run (workflow_dispatch) a handle on the run it triggers. Since Forgejo answers dispatch with 204 and no body, resolve the run by recency, as gh does:

  • After dispatch, poll actions/runs filtered to the same workflow + ref and pick the newest run whose created_at is at/after the dispatch time.
  • --json: print that resolved run (number, status, url) so scripts get a handle.
  • --watch [--exit-status]: hand the resolved run straight to the existing run watch path so "trigger + stream + gate" is one command.
  • Keep a --no-follow default so today's fire-and-forget behavior is preserved; document the recency match as best-effort.

Source: rasterstate/fj#129.

Priority

p2. "Trigger from outside and wait for the result" (fj workflow run deploy.yml --ref "$TAG" -f env=prod --watch --exit-status || rollback) is the point of workflow_dispatch from a CLI, and today it is impossible: dispatch prints a confirmation and discards the response (src/cli/workflow.rs:83). Held at p2 rather than p1 because the resolution is best-effort (recency heuristic) and it composes on top of the p1 run watch --exit-status (rasterstate/fj#125) and run-list filtering (rasterstate/fj#128) rather than standing alone.

Reason

dispatch returns only a success string and the underlying API call discards the 204 response (src/api/workflow_run.rs:85-119), so there is genuinely no run id handed back. DispatchArgs has no --watch/--json (src/cli/workflow.rs:44-56). The result: the most important automation verb (trigger a workflow) is a dead end for scripting, because there is no returned id and, until run-list filtering lands, no way to narrow fj run list to the run just kicked.

Acceptance

  • After dispatch, --json prints the resolved run (number, status, url) using a recency match on workflow + ref + created_at >= dispatch time.
  • --watch streams the resolved run via the existing run watch path; --exit-status gates on its conclusion.
  • Default behavior stays fire-and-forget (--no-follow); the recency match is documented as best-effort.
  • Builds on endpoints fj already calls (actions/runs, the watch path); no new endpoint.
  • Test coverage for the recency resolution and the watch/exit-status hand-off.
  • cargo fmt --check, cargo clippy --all-targets --all-features -- -D warnings, and cargo test --all pass.

Dependencies

Composes with rasterstate/fj#125 (run watch --exit-status) for the gate and rasterstate/fj#128 (run-list filtering) for the resolution; ship those first for the cleanest implementation, though the recency match can stand alone if needed.

Size

M

## Task Give `fj workflow run` (workflow_dispatch) a handle on the run it triggers. Since Forgejo answers dispatch with `204` and no body, resolve the run by recency, as `gh` does: - After dispatch, poll `actions/runs` filtered to the same `workflow` + `ref` and pick the newest run whose `created_at` is at/after the dispatch time. - `--json`: print that resolved run (number, status, url) so scripts get a handle. - `--watch [--exit-status]`: hand the resolved run straight to the existing `run watch` path so "trigger + stream + gate" is one command. - Keep a `--no-follow` default so today's fire-and-forget behavior is preserved; document the recency match as best-effort. Source: rasterstate/fj#129. ## Priority p2. "Trigger from outside and wait for the result" (`fj workflow run deploy.yml --ref "$TAG" -f env=prod --watch --exit-status || rollback`) is the point of `workflow_dispatch` from a CLI, and today it is impossible: dispatch prints a confirmation and discards the response (`src/cli/workflow.rs:83`). Held at p2 rather than p1 because the resolution is best-effort (recency heuristic) and it composes on top of the p1 `run watch --exit-status` (rasterstate/fj#125) and run-list filtering (rasterstate/fj#128) rather than standing alone. ## Reason `dispatch` returns only a success string and the underlying API call discards the `204` response (`src/api/workflow_run.rs:85-119`), so there is genuinely no run id handed back. `DispatchArgs` has no `--watch`/`--json` (`src/cli/workflow.rs:44-56`). The result: the most important automation verb (trigger a workflow) is a dead end for scripting, because there is no returned id and, until run-list filtering lands, no way to narrow `fj run list` to the run just kicked. ## Acceptance - [ ] After dispatch, `--json` prints the resolved run (number, status, url) using a recency match on `workflow` + `ref` + `created_at >= dispatch time`. - [ ] `--watch` streams the resolved run via the existing `run watch` path; `--exit-status` gates on its conclusion. - [ ] Default behavior stays fire-and-forget (`--no-follow`); the recency match is documented as best-effort. - [ ] Builds on endpoints fj already calls (`actions/runs`, the watch path); no new endpoint. - [ ] Test coverage for the recency resolution and the watch/exit-status hand-off. - [ ] `cargo fmt --check`, `cargo clippy --all-targets --all-features -- -D warnings`, and `cargo test --all` pass. ## Dependencies Composes with rasterstate/fj#125 (`run watch --exit-status`) for the gate and rasterstate/fj#128 (run-list filtering) for the resolution; ship those first for the cleanest implementation, though the recency match can stand alone if needed. ## Size M
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rasterstate/fj#139
No description provided.