Actions-based wiki-sync workflow (retire the post-receive hook) #2
Labels
No labels
needs-info
needs-triage
ready-for-agent
ready-for-human
wontfix
needs-info
needs-triage
ready-for-agent
ready-for-human
review/merge-ready
review/needs-fix
review/needs-human
review/needs-review
wayfinder:grilling
wayfinder:map
wayfinder:prototype
wayfinder:research
wayfinder:task
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
olympus/infra-forge#2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem Statement
Docs are mirrored into the Forgejo wiki by a server-side
post-receivehook on the main repo. It works and is tested, but it couples the forgejo Ansible role to one repo's doc layout, offers no visibility (no run logs or history in the Forgejo UI — a failed sync is a silent stale wiki), and exists only because Actions was believed permanently disabled. Pedro wants doc publishing to become a first-class, observable pipeline: an Actions workflow that runs the sync with visible logs and history in the Forgejo UI, after which the hook is retired, reversibly.Solution
Once platform enablement lands (#3: instance Actions toggle, per-repo flag, pinned runner on the Prod Guest), a wiki-sync workflow runs on every push to
main(plus manual dispatch). The workflow maps the canonical repo docs to wiki pages — the same mapping and mirror semantics as the hook — and pushes them to the wiki's backing git repo. Run logs and history are visible in the Forgejo UI. Once a green sync is observed, the post-receive hook is retired, reversibly, via a role toggle.User Stories
main, so that the wiki stays in sync with no manual step.mainbranches, so that in-flight branch docs never fight over the published pages.Implementation Decisions
Platform enablement — the instance-wide Actions toggle in the app.ini template, the per-repo
has_actionsflag, runner install/registration/systemd — is specced and tracked in #3. This issue assumes #3 is done and does not touch the enablement tasks.Auth: a Forgejo token with write access to this repo, stored as a repository secret; the workflow pushes to the wiki backing repo over HTTPS using it. No personal tokens in the workflow file.
The sync core is refactored out of the post-receive hook into a standalone script the workflow invokes. The page mapping is the contract and moves unchanged:
NNNN-slugfileADR-NNNN-slugThe script keeps the empty-index tree rebuild proven by the current tests, so mirror semantics and no-op detection (tree comparison against the last synced tree) hold by construction.
The workflow is thin glue — trigger (push to
main+ manual dispatch), checkout, invoke the script, push the wiki repo — because the workflow layer is the one part that cannot be unit-tested without a runner. All logic lives in the script.Hook retirement: the role gains a boolean toggle for the wiki-sync hook; flipping it removes the hook from the repo's hooks directory. The default flips only after the first successful workflow sync is observed.
ADR-0001 is amended or superseded once the workflow is live: its "no runners available" premise changes, and the new trade-off (observable pipeline vs. a zero-runtime hook) is recorded. (The enablement-and-labels ADR belongs to #3.)
Testing Decisions
mainbranch filtering moves from hook stdin handling to workflow trigger filtering, tested at the workflow contract level only by inspection.Out of Scope
Further Notes
From #12 (publish manifest, PR #18). This issue owns the sync, so the page mapping and the numbering collision are recorded here rather than built there.
The mapping has a manifest now
The set of documents published to the wiki, and the page each becomes, now lives in the repo at
docs/wiki-pages.yml— allowlist by default, carrying the exclusions. The sync (this issue) should read that file instead of hardcoding the map.tests/check-wiki-pages.pyfails when a document is neither published nor excluded, so adding, renaming or moving a doc forces a decision here.docs/index.mddocs/architecture.mddocs/ARCHITECTURE.mddocs/runbooks/index.mddocs/runbooks/0001-deploy-and-rollback.mdRunbook-NNNN-*for runbook pagesdocs/adr/index.mddocs/adr/0001-forgejo-actions-runner-on-guest.mdADR-NNNN-*, as the hook already diddocs/actions/index.mdGLOSSARY.mddocs/agents/*What changed from the parked hook's contract: Home is now the docs entry point, not the README;
docs/ARCHITECTURE.mdbecamedocs/architecture.md; the runbooks, decisions and actions indexes are published too. Mirror semantics are unchanged. A sidebar listing the published sections is still this issue's to define.ADR-0001 numbering collision
The parked wiki-sync branch adds
docs/adr/0001-repo-docs-canonical-wiki-mirror.md, whilemainalready carriesdocs/adr/0001-forgejo-actions-runner-on-guest.md. Two ADR-0001s. It has to be resolved before both land — renumber the parked one (it is unmerged, so it is the cheap one to move). #12 deliberately did not touch it, because the parked ADR is this issue's file.From #11. The coverage check the manifest promises is not in the repo (PR #18 landed
docs/wiki-pages.ymlwithout it) and #11 deliberately excluded tests, so it is filed here with the sync that has to read the manifest.A first pass was implemented and verified (not committed anywhere yet):
tests/check-wiki-pages.py, ~114 lines, stdlib only. It parses the manifest's exact shape, discovers everydocs/**/*.mdplusGLOSSARY.md, and fails (exit 1) with a per-document message when a document is neither published nor excluded — plus when an entry names a file that no longer exists (the rename case). Verified:Two known gaps to settle when this lands, so the check is not mistaken for complete:
docs/**/*.md+GLOSSARY.md.README.md,AGENTS.md,LICENSEandtests/sit outside the invariant, so the check would not flag them.main(a consequence of ADR 0002's "status checks off for now" is that nothing can require it). It belongs with the sync workflow this issue builds, which is where it would get exercised in CI.The script text is available on request; it was left out of #11's PR to keep that change documentation-scoped per its ticket.
Done —
docs/adr/*replaces the three individual ADR entries, so a new decision no longer edits the manifest. The header comment now says entries may be globs (a whole section published the same way, withexcludefor a specific one).Note for the sync in #2: the manifest now carries globs, so the sync has to expand them rather than treat entries as exact paths. Left as-is rather than a second mechanism (e.g. a
publish_dirslist) — the exclusion case you mention works unchanged underexclude: list the specific ADR path there and it wins.pit referenced this issue2026-10-06 12:46:08 +00:00