Skip to content

Spec: phpboyscout/cicd v0.12.0 — hugo-pages component

  • Repository: gitlab.com/phpboyscout/cicd
  • Released as: v0.12.0 (minor — a new component / feat).
  • Driver: the portfolio CI audit (2026-06-22). blog, dusthole, and shutterandstove each hand-roll a near-identical pages job (pinned hugomods/hugo image, GIT_DEPTH: 0, nightly-schedule rebuild) with no MR build gate — a broken Hugo build only surfaces after it lands on the default branch. No reusable component covers Hugo; zensical-pages only covers the Zensical docs framework.

Decisions

D1 — Two-job build + deploy split (mirror zensical-pages)

  • hugo-build — builds the site to public/. Carries an explicit rules: ($CI_COMMIT_TAG → never, else when: on_success) so it runs in merge-request pipelines too. This is the new value: an MR build gate. interruptible: true (a superseding push cancels it — consistent with v0.11.5 D1). Produces the public/ artifact.
  • pages — deploys the public/ artifact (pages: true). Runs on deploy_branch and on schedule, never on merge requests. Uses GIT_STRATEGY: none (it only republishes the artifact, no clone needed). Not interruptible (it is a deploy).

D2 — schedule deploys, deliberately (exception to v0.10.8)

Every other component carries a leading schedule → never guard so it does not fire on the Renovate schedule (specs/2026-06-21-schedule-pipeline-scoping-v0.10.8.md). hugo-pages is the deliberate exception: a nightly pipeline schedule is the mechanism by which future-dated, non-draft posts go live once their date arrives — Hugo excludes future-dated content from production builds until then, so a scheduled rebuild+deploy is what publishes them. The schedule is the feature. These Hugo sites carry no Renovate schedule, so there is no Renovate run to suppress.

D3 — Inputs

  • image (default hugomods/hugo:debian-git-0.163.1) — the -git variant bundles git for .GitInfo/.Lastmod; the extended debian build covers SCSS/Sass themes.
  • stage (default deploy — a GitLab default stage, so consumers need not declare a stages: list).
  • working_directory (default .) — site root containing hugo.toml. Passed to hugo --source; output is forced to $CI_PROJECT_DIR/public via --destination so Pages finds it regardless of source dir.
  • base_url (default $CI_PAGES_URL/) — hugo --baseURL. Resolves to a custom domain automatically once configured in Pages settings.
  • flags (default --gc --minify) — extra hugo flags; add --buildFuture to surface future-dated content (e.g. a pre-launch showcase). String, word-split in the shell (per authoring rule 4).
  • hugo_env (default production) — HUGO_ENV; production excludes drafts + future-dated content.
  • tz (default Europe/London) — TZ; affects how "future-dated" is compared against now.
  • submodule_strategy (default none) — GIT_SUBMODULE_STRATEGY for the build clone. Set recursive for a theme that is a git submodule (e.g. blog).
  • deploy_branch (default main).

D4 — GIT_DEPTH: 0 on the build

Hugo's enableGitInfo / .Lastmod need full history, so the build job sets GIT_DEPTH: 0. (The deploy job sets GIT_STRATEGY: none — no clone at all.)

D5 — Consumer migration (follow-on, separate MRs)

blog, dusthole, shutterandstove migrate to the component in their own repos: - blog: submodule_strategy: recursive (theme submodule), schedule enabled (nightly). - dusthole: defaults; no schedule (it has no time-bound content). - shutterandstove: flags: "--gc --minify --buildFuture" (pre-launch showcase), schedule enabled.

D6 — Versioning

New component → feat(hugo-pages):v0.12.0 (minor). Should land after the pending v0.11.5 patch is tagged, so the perf/cache work keeps its own release rather than being absorbed into the minor.