src/actions.ts — downloadJobLog (cache-first, attempt param) #115

Closed
opened 2026-08-29 03:28:27 +00:00 by david · 1 comment
Owner

Summary

downloadJobLog() in src/actions.ts: cache-first download of a single job's log (GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs?attempt=N), returning {path, sizeBytes, lineCount, cached}.

Background

Part of the Forgejo Actions tooling feature (tracking issue #111 — branch feature/issue-111/forgejo-actions-tools, commits issue-111: ...). Builds on the cache module (#113) for path computation and cache-first read/write, and on forgejoApiCall() for HTTP. Powers the forgejo_action_job_log tool. Cache-first contract: if the computed cache path exists and refresh is not set, return it without any network hit. Baseline is Forgejo v16 (?attempt= supported; ?step= / ?q= / ?format=ndjson are v17+ — out of scope).

Documentation Required

A separate process downloads these into docs/reference/forgejo-actions-api/ before this issue is implemented. Check that folder for the actual reference material before starting.

Implementation Details

  • Signature: downloadJobLog({host, owner, repo, runId, jobId, attempt?, refresh?}) -> Result<{path, sizeBytes, lineCount, cached}, ApiError>.
  • Compute the cache path with cachedLogPath() (#113); if the file exists and refresh is falsy → return {path, sizeBytes, lineCount, cached: true} immediately (no fetch).
  • Otherwise GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs with attempt appended when provided; write via writeLog() (#113); return {path, sizeBytes, lineCount, cached: false}.
  • lineCount = number of lines in the log (split on \n); compute after write (cheap for typical logs).
  • Error mapping: 404 unknown job, empty/never-run job log, network failure → ApiError with actionable text (per the existing friendly-error pattern).

Acceptance Criteria

  • Cache hit (path exists, no refresh) returns the cached file without calling fetch (assert via mocked fetch — fetch must not be invoked).
  • Cache miss downloads, writes to the computed path, and returns cached: false with correct sizeBytes / lineCount.
  • refresh: true re-fetches and overwrites even when the path exists.
  • attempt is included in the query string and in the cache key (path).
  • 404 / empty-log / network failure map to ApiError with actionable messages.
  • Unit tests cover the full cache cycle (exists/missing/refresh) with mocked fetch and real fs on an os.tmpdir() subdir.
  • npm run check passes.

Test Plan

  • cd extensions/forgejo && npm test — new cases in tests/actions.test.ts.
  • Manual (Forgejo v16+ instance): run forgejo_action_job_log run_id=... job_id=..., then again — second call returns cached: true with no network; pass refresh: true after a workflow re-run and confirm re-download; verify attempt=2 fetches the second attempt's log.
### Summary `downloadJobLog()` in `src/actions.ts`: cache-first download of a single job's log (`GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs?attempt=N`), returning `{path, sizeBytes, lineCount, cached}`. ### Background Part of the Forgejo Actions tooling feature (tracking issue **#111** — branch `feature/issue-111/forgejo-actions-tools`, commits `issue-111: ...`). Builds on the cache module (**#113**) for path computation and cache-first read/write, and on `forgejoApiCall()` for HTTP. Powers the `forgejo_action_job_log` tool. **Cache-first contract:** if the computed cache path exists and `refresh` is not set, return it without any network hit. Baseline is Forgejo v16 (`?attempt=` supported; `?step=` / `?q=` / `?format=ndjson` are v17+ — out of scope). ### Documentation Required - `docs/reference/forgejo-actions-api/` (same folder as the metadata-queries step — already researched): - https://forgejo.org/docs/latest/user/api/usage/ — API usage guide: base URL, auth header, token scopes (`read:repository`). - https://codeberg.org/forgejo/forgejo/raw/branch/forgejo/templates/swagger/v1_json.tmpl — v16 swagger: `GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs` definition incl. the `attempt` query param and the response (plain-text log). - https://codeberg.org/forgejo/forgejo/src/branch/forgejo/routers/api/v1/repo/action.go — server-side handler; behavior for empty/never-run job logs. A separate process downloads these into `docs/reference/forgejo-actions-api/` before this issue is implemented. **Check that folder for the actual reference material before starting.** ### Implementation Details - Signature: `downloadJobLog({host, owner, repo, runId, jobId, attempt?, refresh?}) -> Result<{path, sizeBytes, lineCount, cached}, ApiError>`. - Compute the cache path with `cachedLogPath()` (**#113**); if the file exists and `refresh` is falsy → return `{path, sizeBytes, lineCount, cached: true}` immediately (no fetch). - Otherwise `GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs` with `attempt` appended when provided; write via `writeLog()` (**#113**); return `{path, sizeBytes, lineCount, cached: false}`. - `lineCount` = number of lines in the log (split on `\n`); compute after write (cheap for typical logs). - Error mapping: 404 unknown job, empty/never-run job log, network failure → `ApiError` with actionable text (per the existing friendly-error pattern). ### Acceptance Criteria - [ ] Cache hit (path exists, no `refresh`) returns the cached file **without calling `fetch`** (assert via mocked fetch — fetch must not be invoked). - [ ] Cache miss downloads, writes to the computed path, and returns `cached: false` with correct `sizeBytes` / `lineCount`. - [ ] `refresh: true` re-fetches and overwrites even when the path exists. - [ ] `attempt` is included in the query string and in the cache key (path). - [ ] 404 / empty-log / network failure map to `ApiError` with actionable messages. - [ ] Unit tests cover the full cache cycle (exists/missing/refresh) with mocked fetch and real fs on an `os.tmpdir()` subdir. - [ ] `npm run check` passes. ### Test Plan - `cd extensions/forgejo && npm test` — new cases in `tests/actions.test.ts`. - Manual (Forgejo v16+ instance): run `forgejo_action_job_log run_id=... job_id=...`, then again — second call returns `cached: true` with no network; pass `refresh: true` after a workflow re-run and confirm re-download; verify `attempt=2` fetches the second attempt's log.
david closed this issue 2026-08-29 07:41:07 +00:00
Author
Owner

pi-loop opened and merged a pull request for this issue: #127

pi-loop opened and merged a pull request for this issue: https://git.excelera.net/david/pi-extensions-and-skills/pulls/127
Sign in to join this conversation.
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
david/pi-extensions-and-skills#115
No description provided.