# pipelines/tech Publishes tech blog posts from `novoyuuparosk-wiki/tech-blogs` to `https://wiki.novoyuuparosk.org`. - Source-file contract (frontmatter and body conventions): [SCHEMA.md](SCHEMA.md) - Cross-cutting setup (wiki URL, bot identity, runner, Gitea secrets/variables): [repo root README](../../README.md) ## What the renderer does - YAML frontmatter parsing per [SCHEMA.md](SCHEMA.md) - Pandoc-based markdown → wikitext body rendering (h1 elements preserved) - Auto-generated banner (`{{Auto-generated|source=...|commit=}}`) - Category injection: `[[Category:Tech blog]]` on every page; `[[Category:Blog:]]` from `date` field (falling back to the action's execution year); `[[Category:]]` per tag entry - No title prefix — pages live at their bare title - MediaWiki bot API write with idempotency — no-op if wiki content matches generated output - Files without `wiki.publish: true` silently skipped - Pages with existing non-auto-generated content skipped (logged to stderr) ## Source repo Source repo: `novoyuuparosk-wiki/tech-blogs`, triggering on push to `master`, with `workflow_dispatch` for manual runs. No branch convention enforced. There is no `wip/` exclusion — `wiki.publish: true` is the only publishing gate. **Excluded paths** (won't trigger the pipeline): - `README.md`, `.gitignore`, `.claude/**` ## Invocation `novoyuuparosk-wiki/tech-blogs/.gitea/workflows/publish.yml` is a thin caller: it triggers, then `uses:` [`publish-tech.yml`](../../.gitea/workflows/publish-tech.yml) here, which clones both repos and runs `publish.py`. Editing `publish-tech.yml` requires a runner cache flush before it takes effect; the renderer itself is cloned fresh every run. See *Callee workflow cache* in the [root README](../../README.md). Triggers: - `push` to `master` (path-filtered as above) - `workflow_dispatch` — manual trigger from the Gitea Actions UI ### Publish scope Every run publishes every file with `wiki.publish: true`; there is no diff detection. Writes are idempotent — the banner carries the commit SHA rather than a timestamp, so a re-run at the same commit rewrites nothing. ### Environment (secrets and variables) | Name | Kind | Source | Purpose | |---|---|---|---| | `WIKI_API_URL` | variable | Gitea (cross-cutting) | MediaWiki action API endpoint | | `WIKI_BASE_URL` | variable | Gitea (cross-cutting) | Wiki base URL | | `WIKI_BOT_USER` | secret | Gitea (cross-cutting) | Bot login | | `WIKI_BOT_PASSWORD` | secret | Gitea (cross-cutting) | BotPasswords value | | `URL_TO_GITEA` | variable | Gitea (cross-cutting) | Runner-internal Gitea base URL, for cloning only | | `PUBLIC_URL_TO_GITEA` | variable | Gitea (cross-cutting) | Public Gitea base URL, for the banner source link only | | `FAPAT` | secret | Gitea (cross-cutting) | Full-Access PAT for cloning private repos | | `SOURCE_REF` | env (set in workflow) | `github.sha` | Pushed commit SHA, used in banner and edit summary | | `GITEA_REPO_URL` | env (set in workflow) | `PUBLIC_URL_TO_GITEA` + repo path | Source-file URL base for the banner link. Validated by `public_source_base()`: a loopback, mDNS or private-range host aborts the run rather than publishing an unreachable link | ## Dependencies Job container image and its build are described in the [root README](../../README.md#job-container-image). Python packages for this pipeline are in `requirements.txt` here; changing it triggers an image rebuild. Shared render and MediaWiki helpers live in `lib/wiki.py` at the repo root. ## Wiki-side prerequisites **`Template:Auto-generated`** must exist on the wiki. It is shared across all three pipelines; the wikitext source lives in [`pipelines/songs/template_auto_generated.wikitext`](../songs/template_auto_generated.wikitext).