Add retention prune utility for recorded retention-days (#1) #2

Merged
stephen merged 1 commit from feat/1-retention-prune into main 2026-06-17 00:15:58 +00:00
Owner

What changed

retention-days is recorded in artifact metadata but never enforced by the upload step, leaving operators on a local directory or a bucket without lifecycle rules no first-party way to expire artifacts (#1). This adds a prune CLI (src/prune.js) that scans the artifacts subtree, reads each .meta.json, computes age from the recorded createdAt, and deletes the archive plus sidecar once retention-days has elapsed.

  • Works on both backends: adds remove() and a recursive listTree() to the local and S3 backends.
  • Safe by default: --dry-run reports without deleting; only entries whose recorded window has elapsed are pruned.
  • Artifacts with no retention record (or no usable createdAt) are skipped, never deleted, unless --force --max-age=<days> supplies a fallback window for record-less entries.
  • config can resolve the backend without a run id (requireRun: false) so prune scans across all runs under one repo scope.
  • README, CHANGELOG, and a prune npm script document it.

How it was tested

  • make lint clean (shellcheck/yaml; actionlint and yq not installed locally)
  • make test green: 19 tests, including the new prune suite
  • new behavior has tests: expired pruned, not-yet-expired kept, missing-retention skipped, dry-run writes nothing, --force --max-age, missing-timestamp skipped, multi-run pass, arg parsing, and a CLI dry-run/real-run subprocess test

CHANGELOG updated? yes

**What changed** `retention-days` is recorded in artifact metadata but never enforced by the upload step, leaving operators on a local directory or a bucket without lifecycle rules no first-party way to expire artifacts (#1). This adds a prune CLI (`src/prune.js`) that scans the artifacts subtree, reads each `.meta.json`, computes age from the recorded `createdAt`, and deletes the archive plus sidecar once `retention-days` has elapsed. - Works on both backends: adds `remove()` and a recursive `listTree()` to the local and S3 backends. - Safe by default: `--dry-run` reports without deleting; only entries whose recorded window has elapsed are pruned. - Artifacts with no retention record (or no usable `createdAt`) are skipped, never deleted, unless `--force --max-age=<days>` supplies a fallback window for record-less entries. - `config` can resolve the backend without a run id (`requireRun: false`) so prune scans across all runs under one repo scope. - README, CHANGELOG, and a `prune` npm script document it. **How it was tested** - [x] `make lint` clean (shellcheck/yaml; actionlint and yq not installed locally) - [x] `make test` green: 19 tests, including the new prune suite - [x] new behavior has tests: expired pruned, not-yet-expired kept, missing-retention skipped, dry-run writes nothing, `--force --max-age`, missing-timestamp skipped, multi-run pass, arg parsing, and a CLI dry-run/real-run subprocess test **CHANGELOG updated?** yes
Add retention prune utility for recorded retention-days (#1)
All checks were successful
test / e2e (pull_request) Successful in 5s
test / unit (pull_request) Successful in 6s
c9529da678
retention-days is recorded in artifact metadata but never enforced by the
upload step. Operators on a local directory or a bucket without lifecycle
rules had no first-party way to expire artifacts. Add a prune CLI that scans
the artifacts subtree, reads each metadata sidecar, computes age from the
recorded createdAt, and deletes the archive plus sidecar once retention-days
has elapsed.

Safe by default: --dry-run changes nothing, only entries whose recorded
window has elapsed are deleted, and artifacts with no retention record (or no
usable timestamp) are skipped unless --force --max-age is given. Backends gain
remove() and listTree() to support recursive scan and deletion.
Sign in to join this conversation.
No reviewers
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/upload-artifact-action!2
No description provided.