|
| 1 | +# Shared Build Entrypoint Plan |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Create one repository-owned build entrypoint that all site render paths use: |
| 6 | + |
| 7 | +- local production-style build |
| 8 | +- htmltest render |
| 9 | +- GitHub Pages build |
| 10 | + |
| 11 | +The entrypoint should centralize the Hugo invocation, container environment, cache configuration, and output-path handling so future fixes are made once. |
| 12 | + |
| 13 | +## Current state |
| 14 | + |
| 15 | +- Local development uses `make serve`, which starts the container default `hugo server` command. |
| 16 | +- Local shell access uses `make shell`, which opens an interactive shell in the same container. |
| 17 | +- `run-htmltest.yml` duplicates a Docker Compose + `hugo build` command. |
| 18 | +- `gh-pages.yml` duplicates a similar Docker Compose + `hugo build` command with Pages-specific `BASE_URL` handling. |
| 19 | +- Shared infrastructure already exists at the container/image level via `docker-compose.yml` and `Dockerfile`, but the build command itself is duplicated. |
| 20 | + |
| 21 | +## Target design |
| 22 | + |
| 23 | +Introduce a single script entrypoint under the repository, for example: |
| 24 | + |
| 25 | +- `.github/scripts/build-site.sh` |
| 26 | + |
| 27 | +Responsibilities: |
| 28 | + |
| 29 | +- enforce strict shell behavior |
| 30 | +- normalize environment variables and defaults |
| 31 | +- configure git safe-directory behavior inside the container |
| 32 | +- require absolute Hugo cache path inside the container |
| 33 | +- accept output directory as an argument or env var |
| 34 | +- accept optional base URL override |
| 35 | +- run a single canonical `hugo build` command |
| 36 | + |
| 37 | +Example interface: |
| 38 | + |
| 39 | +- `OUTPUT_DIR=/src/public BASE_URL=https://example.test/ .github/scripts/build-site.sh` |
| 40 | +- `OUTPUT_DIR=/src/dist .github/scripts/build-site.sh` |
| 41 | + |
| 42 | +## Implementation phases |
| 43 | + |
| 44 | +### Phase 1: Create canonical build script |
| 45 | + |
| 46 | +- Add a shell script to the repo and make it the only place that calls `hugo build` for CI-style production renders. |
| 47 | +- Set defaults for: |
| 48 | + - `HUGO_ENV=production` |
| 49 | + - `HUGO_CACHEDIR=/src/.hugo_cache` |
| 50 | + - `OUTPUT_DIR=/src/public` |
| 51 | +- Build the Hugo command incrementally so optional flags like `--baseURL` are only added when present. |
| 52 | +- Keep the script container-oriented; assume execution happens inside the `hugo` service with `/src` mounted. |
| 53 | + |
| 54 | +Success criteria: |
| 55 | + |
| 56 | +- No workflow contains a long inline `hugo build` command anymore. |
| 57 | +- The script can render successfully for both default and overridden output directories. |
| 58 | + |
| 59 | +### Phase 2: Route GitHub Pages through the script |
| 60 | + |
| 61 | +- Replace the inline Hugo command in `gh-pages.yml` with a call to the shared script. |
| 62 | +- Keep Pages-only concerns in the workflow: |
| 63 | + - `actions/configure-pages` |
| 64 | + - cache restore/save |
| 65 | + - artifact upload |
| 66 | + - deploy action |
| 67 | +- Pass only the parameters the shared script needs: |
| 68 | + - `BASE_URL` |
| 69 | + - `HUGO_CACHEDIR` |
| 70 | + - optional explicit `OUTPUT_DIR=/src/public` |
| 71 | + |
| 72 | +Success criteria: |
| 73 | + |
| 74 | +- `gh-pages.yml` still owns deployment orchestration. |
| 75 | +- The actual site build command lives only in the shared script. |
| 76 | + |
| 77 | +### Phase 3: Route htmltest through the script |
| 78 | + |
| 79 | +- Replace the inline Hugo command in `run-htmltest.yml` with a call to the shared script. |
| 80 | +- Decide whether htmltest should build to `/src/public` for exact parity or continue using `/src/dist`. |
| 81 | +- Preferred direction: build to `/src/public` and point htmltest at that output if feasible, because it reduces environment drift. |
| 82 | +- If htmltest must keep `/src/dist`, use the shared script with `OUTPUT_DIR=/src/dist`. |
| 83 | + |
| 84 | +Success criteria: |
| 85 | + |
| 86 | +- htmltest and gh-pages differ only in workflow-specific orchestration, not in core site build logic. |
| 87 | + |
| 88 | +### Phase 4: Add a local production-build entrypoint |
| 89 | + |
| 90 | +- Add a Make target such as `make render` or `make build-site` that runs the same shared script inside the `hugo` service. |
| 91 | +- Keep `make serve` as the fast feedback path for local content work. |
| 92 | +- Document that `make render` is the local equivalent of CI production rendering. |
| 93 | + |
| 94 | +Example target behavior: |
| 95 | + |
| 96 | +- `docker compose build --pull hugo` |
| 97 | +- `docker compose run --rm --no-deps --entrypoint sh hugo -c '.github/scripts/build-site.sh'` |
| 98 | + |
| 99 | +Success criteria: |
| 100 | + |
| 101 | +- There is a documented local command that exercises the same production build path as CI. |
| 102 | +- Contributors no longer need to reconstruct the CI build command manually. |
| 103 | + |
| 104 | +### Phase 5: Document the contract |
| 105 | + |
| 106 | +- Update `README.md` to distinguish: |
| 107 | + - local live preview via `make serve` |
| 108 | + - local production-equivalent render via `make render` |
| 109 | + - CI consumers of the shared build entrypoint |
| 110 | +- Document the required environment variables and defaults. |
| 111 | +- Note that the deploy job publishes artifacts only; it does not build the site. |
| 112 | + |
| 113 | +Success criteria: |
| 114 | + |
| 115 | +- Repository docs match actual workflow behavior. |
| 116 | +- The shared-entrypoint contract is easy to extend for future checks. |
| 117 | + |
| 118 | +## Design constraints |
| 119 | + |
| 120 | +- Keep project commands container-based, consistent with `AGENTS.md`. |
| 121 | +- Do not move GitHub Pages deployment logic into the shared script. |
| 122 | +- Keep host-path concerns in workflows and Make targets; keep container-path concerns in the script. |
| 123 | +- Preserve the current absolute container cache directory requirement. |
| 124 | +- Avoid introducing host-level dependencies on local `hugo`, `go`, `node`, or `npm`. |
| 125 | + |
| 126 | +## Recommended normalization choices |
| 127 | + |
| 128 | +- Canonical container cache dir: `/src/.hugo_cache` |
| 129 | +- Canonical default output dir: `/src/public` |
| 130 | +- Canonical local production command: `make render` |
| 131 | +- Canonical live-preview command: `make serve` |
| 132 | +- Canonical script location: `.github/scripts/build-site.sh` |
| 133 | + |
| 134 | +## Open decisions |
| 135 | + |
| 136 | +- Whether htmltest should consume `/src/public` instead of `/src/dist` for exact deploy parity. |
| 137 | +- Whether the local render target should run as the host UID/GID to avoid root-owned artifacts. |
| 138 | +- Whether git safe-directory setup should remain inline in the container command or be fully absorbed by the script. |
| 139 | + |
| 140 | +## Suggested implementation order |
| 141 | + |
| 142 | +1. Add the shared script. |
| 143 | +2. Switch `gh-pages.yml` to use it. |
| 144 | +3. Switch `run-htmltest.yml` to use it. |
| 145 | +4. Add `make render`. |
| 146 | +5. Update `README.md`. |
| 147 | + |
| 148 | +## Validation plan |
| 149 | + |
| 150 | +1. Run the shared script locally in the `hugo` container with default settings. |
| 151 | +2. Run it locally with `OUTPUT_DIR=/src/dist`. |
| 152 | +3. Confirm `gh-pages.yml` still builds and uploads the Pages artifact. |
| 153 | +4. Confirm `run-htmltest.yml` renders and htmltest reads the intended output directory. |
| 154 | +5. Compare generated `public` output between the local render path and the Pages workflow path for parity. |
0 commit comments