Skip to content

feat(actions): add publish-docs and share one library between both actions - #82

Merged
oto-macenauer-absa merged 1 commit into
chore/source-only-registryfrom
chore/publish-docs-action
Sep 4, 2026
Merged

feat(actions): add publish-docs and share one library between both actions#82
oto-macenauer-absa merged 1 commit into
chore/source-only-registryfrom
chore/publish-docs-action

Conversation

@oto-macenauer-absa

Copy link
Copy Markdown
Collaborator

Closes #76. Part of #73.

Stacked on #81 (chore/source-only-registry) → #80#79. Review in that order; the diff here is only the actions work.

Why

Packaged docs repos assembled the release asset by hand. The example repo's pack.yml validated the manifest with an inline Python snippet, grepped the HTML for the headless marker, ran tar -czf dist.tar.gz dist/ marketplace.json and uploaded through a third-party action. Every new docs repo copied that file, so every contract change had to be chased across N repositories.

The reusable validate-doc-app.yml did not help: it assumed npm run build -- --headless, which the Python example repo cannot run, so it was not what any real doc repo used.

Single-page docs already had this solved. Packaged sites now do too.

actions/publish-docs

Takes an already-built headless site and owns everything after it. It never builds the site: doc repos use mkdocs, Starlight, Jekyll and hand-rolled scripts, and the contract is about the output, not the toolchain.

- uses: actions/checkout@v4
- run: npm ci && npm run build -- --headless
- uses: AbsaOSS/knowledge-base/actions/publish-docs@v1
  with:
    manifest: kb-docs.json
    dist: dist

What it rejects, all reported at once rather than one per CI run:

  • a manifest that fails the contract schema
  • an app with no built output, or a missing entryPoint
  • a pages entry naming a file that was not built
  • a page without the headless marker, naming the pre-v1 marker specifically when it finds that instead
  • a <base> element, and root-relative href/src/action/poster

Inline <script> is a warning, not a failure. The knowledge base hoists them so it can serve script-src 'self', but the repo should know they are there.

One library, so the two actions cannot drift

actions/lib/ holds manifest validation, HTML verification, deterministic packing and the runner plumbing. Both actions run that same code for the parts that are the contract. publish-single-page-docs keeps its own markdown pipeline and emits the unified manifest through the shared builder; its bundle.json is gone.

This is the same failure mode #75 fixed in the build, one layer out: two implementations of one idea, drifting.

Three details worth a look in review

Packing is deterministic. --sort=name plus a fixed mtime and uid/gid. Without it, republishing an unchanged doc set produced different bytes every time and nobody could tell a real change from a rebuild. Members are named explicitly rather than packing ., so anything that reached the staging directory without being part of the artifact is left out.

The schema is read from the checkout, not fetched. A remote uses: checks out this whole repository at the ref the caller pinned, so the schema always matches the action's own version and a publish never depends on raw.githubusercontent being reachable. The old validate-doc-app.yml fetched it and skipped validation with a warning when the fetch failed.

dist is the app's directory when the manifest declares one app. A repo publishing a single site should not have to invent a subdirectory named after its own slug. With several apps, dist holds one subdirectory per slug, and the error says which one is missing.

Also here

Verification

Suite Result
publish-docs self-test 18 passed
publish-single-page-docs self-test 19 passed
npm test (embedded) 118 passed
playwright.config.ci.js (standalone) 22 passed
All action.yml / workflow YAML parses 6 files

The self-tests assert the error messages as much as the happy path. This action is the whole interface a docs repo has with the contract, so a message that does not say which file is wrong costs somebody a CI round trip.

Not in this PR

Migrating AbsaOSS/knowledge-base-docs-example onto the action, tracked in AbsaOSS/knowledge-base-docs-example#3. Until that lands and a v1 tag is cut, the @v1 references in the contract docs point at a tag that does not exist yet.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PYtmxSeSXFg4wEXRcKCmAi

…tions

Packaged docs repos assembled the release asset by hand. The example repo's
pack.yml validated the manifest with an inline Python snippet, grepped the HTML
for the headless marker, ran `tar -czf dist.tar.gz dist/ marketplace.json` and
uploaded through a third-party action. Every new docs repo copied that file, so
every contract change had to be chased across N repositories by hand — and the
reusable validate-doc-app.yml did not help, because it assumed
`npm run build -- --headless`, which the Python example repo cannot run.

Single-page docs already had this solved. Packaged sites now do too.

actions/publish-docs takes an already-built headless site and owns everything
after it: validate the manifest against the contract schema, verify the HTML,
pack kb-docs.tar.gz, upload, optionally notify a deployment repo. It never
builds the site — doc repos use mkdocs, Starlight, Jekyll and hand-rolled
scripts, and the contract is about the output, not the toolchain.

What it rejects, all reported at once rather than one per CI run: a manifest
that fails the schema, an app with no built output, a missing entryPoint, a
`pages` entry naming a file that was not built, a page without the headless
marker (naming the pre-v1 marker specifically when it finds that instead), a
<base> element, and root-relative URLs. Inline scripts are a warning, not a
failure: the knowledge base hoists them, but the repo should know they are there.

Both actions now run the same code for the parts that are the contract —
actions/lib/ holds manifest validation, HTML verification, deterministic packing
and the runner plumbing — so the two cannot drift the way the build's two
install paths did. publish-single-page-docs keeps its own markdown pipeline and
emits the unified manifest through the shared builder; its bundle.json is gone.

Packing is deterministic: --sort=name plus a fixed mtime and uid/gid. Without
that, republishing an unchanged doc set produced a different asset every time and
nobody could tell a real change from a rebuild. Members are named explicitly
rather than packing `.`, so anything that reached the staging directory without
being part of the artifact is left out.

The schema is read from the action's own checkout rather than fetched at
runtime. A remote `uses:` checks out this whole repository at the ref the caller
pinned, so the schema always matches the action's version and a publish never
depends on raw.githubusercontent being reachable.

Also here:

  * One pinned dependency tree in actions/, replacing the per-action one. Both
    actions install from it; CI caches and runs against it.
  * release-actions.yml moves the floating major tag, so consuming repos pin @v1
    rather than @master. A branch means every doc repo picks up an unreleased
    change the moment it merges, which is what a contract must not do.
  * validate-doc-app.yml deleted. #74 had already reduced it to a deprecation
    notice; the action it points at now exists.

Self-tests: 18 for publish-docs, 19 for publish-single-page-docs, both run by
CI. They assert the error messages as much as the happy path, because those
messages are the whole interface a docs repo has with the contract.

Suites green: 118 embedded, 22 standalone, both self-tests, all YAML manifests
parse.

Part of #73. Closes #76.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYtmxSeSXFg4wEXRcKCmAi
@oto-macenauer-absa
oto-macenauer-absa merged commit 88a2f7d into master Sep 4, 2026
14 checks passed
@oto-macenauer-absa
oto-macenauer-absa deleted the chore/publish-docs-action branch September 4, 2026 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

actions/publish-docs: one reusable action that validates, packs and publishes kb-docs.tar.gz for packaged doc sites

1 participant