feat(site-publish): scope publication with an artifacts selection
Test / contract (pull_request) Successful in 7s

A repository whose artifacts ship on different cadences has no way to
publish one of them. Baseline needs it: every merge to main must put the
catalogue live in under five minutes, while `dist/` is content-addressed
and may only be written by a tag release. Today the action iterates
cfg["artifacts"] unconditionally, so the only lever is deleting the
distributions artifact from site.yaml — which changes the stored
publication contract and drives the route-retirement path.

The new `artifacts:` input names the subset this run builds and
publishes. Selection scopes the build, the immutable preflight, the CORS
reconcile, the S3 sync, and credential resolution. It deliberately does
not scope manifest rendering or the immutable-path history: those stay
whole, so a scoped run can never retire another artifact's route or
delete its bucket contents. An undeclared name fails before the first
bucket is touched; `enabled: false` refuses a selection because
decommissioning is whole-site.

Default is unchanged: no input publishes every declared artifact.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjQqc4qFmdpAWaYfy2Aypb
This commit is contained in:
Evelyn Chen
2026-09-06 00:53:35 +00:00
co-authored by Claude Fable 5.1
parent 9287e4861a
commit 3dfee64335
6 changed files with 217 additions and 9 deletions
+21
View File
@@ -234,10 +234,31 @@ my-site.fritzlab.net 300 IN CNAME gateway.sjc001.fritzlab.net.
| `garage-admin-token` | legacy aliases only | | Garage admin API token (`admin-token` from `garage-rpc-secret` in `storage` ns) |
| `garage-admin-endpoint` | no | `http://garage.storage.svc:3903` | Garage admin API endpoint |
| `username` | no | `ci-bot` | Gitea username |
| `artifacts` | no | every declared artifact | Space- or comma-separated subset of `site.yaml` artifacts to build and publish |
Org secrets in `websites`: `CI_BOT_TOKEN`, `GARAGE_S3_ACCESS_KEY`,
`GARAGE_S3_SECRET_KEY`, `GARAGE_ADMIN_TOKEN`.
### Publishing a subset of artifacts
A repository whose branches ship on different cadences names the ones this run
owns:
```yaml
- uses: https://code.fritzlab.net/action/site-publish@<sha>
with:
token: ${{ secrets.CI_BOT_TOKEN }}
artifacts: catalogue
```
Selection scopes the build and the S3 publication only. Ingresses, Services,
Certificates and the immutable-path history are always rendered from the whole
`site.yaml`, so a scoped run cannot retire another artifact's route or delete
its bucket contents. Credentials are resolved for the selected artifacts alone,
so a workflow need not carry secrets for artifacts it does not publish. An
undeclared name fails before the first bucket is touched, and `enabled: false`
refuses a selection because decommissioning is whole-site.
## Tools
- **`new-site.sh`** — create a new site: Gitea repo, Garage bucket, web hosting enabled.