src/actionsCache.ts — cache paths + cache-first read/write #113

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

Summary

New module src/actionsCache.ts providing deterministic cache paths and cache-first read/write for downloaded job logs and run-log ZIPs, so repeated tool calls don't re-download.

Background

Part of the Forgejo Actions tooling feature (tracking issue #111 — branch feature/issue-111/forgejo-actions-tools, commits issue-111: ...). The forgejo_action_job_log and forgejo_action_run_logs tools are cache-first: they must not hit the network when the computed cache path already exists (unless refresh is passed). This module is the pure, unit-testable core of that behavior — it must not import fetch or do any HTTP. It builds on the existing project structure (src/ + tests/, jest, ts-jest). Reuse the existing Result types from src/errors.ts where needed; do not reinvent error helpers.

Implementation Details

  • Cache root resolution (first match wins), exposed as a pure function taking an env object so tests can inject values (e.g. cacheRoot(env?)):
    1. $FORGEJO_ACTIONS_CACHE_DIR (also used by tests to point at a temp dir)
    2. $XDG_CACHE_HOME/forgejo-actions (Unix) / platform-appropriate equivalent elsewhere
    3. ~/.cache/forgejo-actions
  • Path layout:
    • Job log: <root>/<owner>/<repo>/<run_id>/<job_id>[-attempt-<n>][-step-<s>].log — attempt/step are part of the key so historical attempts never collide.
    • Run ZIP: <root>/<owner>/<repo>/<run_id>/run.zip
  • Pure functions (no I/O — unit-testable without touching disk):
    • cachedLogPath({root, owner, repo, runId, jobId, attempt?, step?}) -> string
    • runZipPath({root, owner, repo, runId}) -> string
  • I/O helpers:
    • readCachedLog(path) -> string | null (null when missing/unreadable)
    • writeLog(path, content) with mkdir -p of parent dirs
  • Keep types consistent with the repo's style (explicit interfaces, no any).

Acceptance Criteria

  • cacheRoot() resolves $FORGEJO_ACTIONS_CACHE_DIR$XDG_CACHE_HOME/forgejo-actions~/.cache/forgejo-actions in that priority, honoring an injected env for tests.
  • cachedLogPath() embeds attempt/step in the key so attempt=2 and attempt=3 (and different steps) map to distinct paths; omitting attempt/step yields the base .log path.
  • runZipPath() returns <root>/<owner>/<repo>/<run_id>/run.zip.
  • readCachedLog() returns file content when present and null when absent.
  • writeLog() creates parent directories (mkdir -p) and writes content.
  • Unit tests cover path computation (attempt/step/key) and a real-fs read/write round-trip in an os.tmpdir() subdir (per the plan's 7.2/7.5 pattern).
  • npm run check passes.

Test Plan

  • cd extensions/forgejo && npm test — new tests in tests/actionsCache.test.ts (path math is pure; I/O tests use os.tmpdir() subdirs, cleaned up in teardown).
  • Manual: FORGEJO_ACTIONS_CACHE_DIR=/tmp/fjcache node -e "..." sanity-check the resolved root.
### Summary New module `src/actionsCache.ts` providing deterministic cache paths and cache-first read/write for downloaded job logs and run-log ZIPs, so repeated tool calls don't re-download. ### Background Part of the Forgejo Actions tooling feature (tracking issue **#111** — branch `feature/issue-111/forgejo-actions-tools`, commits `issue-111: ...`). The `forgejo_action_job_log` and `forgejo_action_run_logs` tools are cache-first: they must not hit the network when the computed cache path already exists (unless `refresh` is passed). This module is the pure, unit-testable core of that behavior — it must **not** import `fetch` or do any HTTP. It builds on the existing project structure (src/ + tests/, jest, ts-jest). Reuse the existing `Result` types from `src/errors.ts` where needed; do not reinvent error helpers. ### Implementation Details - **Cache root resolution** (first match wins), exposed as a pure function taking an env object so tests can inject values (e.g. `cacheRoot(env?)`): 1. `$FORGEJO_ACTIONS_CACHE_DIR` (also used by tests to point at a temp dir) 2. `$XDG_CACHE_HOME/forgejo-actions` (Unix) / platform-appropriate equivalent elsewhere 3. `~/.cache/forgejo-actions` - **Path layout**: - Job log: `<root>/<owner>/<repo>/<run_id>/<job_id>[-attempt-<n>][-step-<s>].log` — attempt/step are part of the key so historical attempts never collide. - Run ZIP: `<root>/<owner>/<repo>/<run_id>/run.zip` - **Pure functions** (no I/O — unit-testable without touching disk): - `cachedLogPath({root, owner, repo, runId, jobId, attempt?, step?}) -> string` - `runZipPath({root, owner, repo, runId}) -> string` - **I/O helpers**: - `readCachedLog(path) -> string | null` (null when missing/unreadable) - `writeLog(path, content)` with `mkdir -p` of parent dirs - Keep types consistent with the repo's style (explicit interfaces, no `any`). ### Acceptance Criteria - [ ] `cacheRoot()` resolves `$FORGEJO_ACTIONS_CACHE_DIR` → `$XDG_CACHE_HOME/forgejo-actions` → `~/.cache/forgejo-actions` in that priority, honoring an injected env for tests. - [ ] `cachedLogPath()` embeds attempt/step in the key so `attempt=2` and `attempt=3` (and different steps) map to distinct paths; omitting attempt/step yields the base `.log` path. - [ ] `runZipPath()` returns `<root>/<owner>/<repo>/<run_id>/run.zip`. - [ ] `readCachedLog()` returns file content when present and `null` when absent. - [ ] `writeLog()` creates parent directories (mkdir -p) and writes content. - [ ] Unit tests cover path computation (attempt/step/key) and a real-fs read/write round-trip in an `os.tmpdir()` subdir (per the plan's 7.2/7.5 pattern). - [ ] `npm run check` passes. ### Test Plan - `cd extensions/forgejo && npm test` — new tests in `tests/actionsCache.test.ts` (path math is pure; I/O tests use `os.tmpdir()` subdirs, cleaned up in teardown). - Manual: `FORGEJO_ACTIONS_CACHE_DIR=/tmp/fjcache node -e "..."` sanity-check the resolved root.
david closed this issue 2026-08-29 07:27:00 +00:00
Author
Owner

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

pi-loop opened and merged a pull request for this issue: https://git.excelera.net/david/pi-extensions-and-skills/pulls/125
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#113
No description provided.