This commit was merged in pull request #27.
This commit is contained in:
@@ -9,7 +9,11 @@ FROM alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4
|
|||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
# Install build dependencies first so the layer caches until the
|
# Install build dependencies first so the layer caches until the
|
||||||
# scripts change (script/bootstrap installs git, make, hugo, node/npm).
|
# scripts change (script/bootstrap installs git, make, go, hugo,
|
||||||
|
# node/npm). Hugo is not an apk package here: script/bootstrap builds
|
||||||
|
# the exact pinned version with `go install`, hash-verified against
|
||||||
|
# sum.golang.org, so the published artifact does not depend on whatever
|
||||||
|
# hugo this base image's repos happen to serve.
|
||||||
COPY script/ script/
|
COPY script/ script/
|
||||||
RUN script/bootstrap
|
RUN script/bootstrap
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,10 @@ standard: normalized scripts in `script/` are the entrypoints for the
|
|||||||
development workflow, and the Makefile targets are thin shims that call them. We
|
development workflow, and the Makefile targets are thin shims that call them. We
|
||||||
provide:
|
provide:
|
||||||
|
|
||||||
- `script/bootstrap` — install all build dependencies (git, make, hugo,
|
- `script/bootstrap` — install all build dependencies (git, make, go, hugo,
|
||||||
node/npm) idempotently
|
node/npm) idempotently. Hugo is pinned to an exact version and installed with
|
||||||
|
`go install`, which verifies it against `sum.golang.org`; the version is the
|
||||||
|
`HUGO_VERSION` constant at the top of the script
|
||||||
- `script/setup` — prepare a fresh clone: run `script/bootstrap` and install the
|
- `script/setup` — prepare a fresh clone: run `script/bootstrap` and install the
|
||||||
git pre-commit hook
|
git pre-commit hook
|
||||||
- `script/test` — the correctness check: a clean `hugo --minify` production
|
- `script/test` — the correctness check: a clean `hugo --minify` production
|
||||||
|
|||||||
27
TODO.md
27
TODO.md
@@ -15,7 +15,9 @@ pre-1.0
|
|||||||
No git tags. The site is live and now has the scripts-to-rule-them-all scaffold
|
No git tags. The site is live and now has the scripts-to-rule-them-all scaffold
|
||||||
(`Makefile`, `script/`, `Dockerfile`, `check.yml`); still missing `LICENSE` and
|
(`Makefile`, `script/`, `Dockerfile`, `check.yml`); still missing `LICENSE` and
|
||||||
policy files. Every external reference in the repo is now pinned by
|
policy files. Every external reference in the repo is now pinned by
|
||||||
cryptographic hash (or, for the wrangler CLI install, an exact version).
|
cryptographic hash (or, for the wrangler CLI install, an exact version), and the
|
||||||
|
Hugo that builds the published site is a deliberate pinned version rather than
|
||||||
|
whatever the base image's package repo serves.
|
||||||
|
|
||||||
# Next Step
|
# Next Step
|
||||||
|
|
||||||
@@ -25,6 +27,29 @@ Update `README.md` accordingly.
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-08-09: replaced `hugo.toml`'s deprecated `languageCode` key with `locale`
|
||||||
|
(closes #18). Hugo deprecated `languageCode` in v0.158.0, so the Hugo pinned
|
||||||
|
in the preceding commit warns about it; left alone it would become a third
|
||||||
|
routinely-ignored warning, and a latent breakage when the key is removed.
|
||||||
|
Deliberately sequenced **after** the Hugo version move and in the same branch:
|
||||||
|
under the apk hugo 0.139.0 that CI ran until now, `locale` is an unknown key
|
||||||
|
that is silently ignored, which downgrades the generated RSS from
|
||||||
|
`<language>en-us</language>` to `<language>en</language>` with no warning and
|
||||||
|
exit 0. Verified on hugo v0.164.0 that the RSS `<language>` still reads
|
||||||
|
`en-us`, the `lang` attribute is unchanged, and `public/` is byte-identical to
|
||||||
|
the preceding commit's output
|
||||||
|
- 2026-08-09: installed Hugo at a deliberate, hash-verified version instead of
|
||||||
|
taking whatever alpine ships (closes #26). `script/bootstrap` no longer does
|
||||||
|
`pkg_install hugo`; it installs `github.com/gohugoio/hugo@v0.164.0` with
|
||||||
|
`go install`, which verifies the module against `sum.golang.org`. The version
|
||||||
|
is a commented constant, as is the Go toolchain (`go1.26.5`) — hugo v0.164.0
|
||||||
|
requires go >= 1.26.0 and alpine 3.21 ships go 1.23.9 with
|
||||||
|
`GOTOOLCHAIN=local`, so a bare `go install` refuses to run. `CGO_ENABLED=0` is
|
||||||
|
deliberate: standard Hugo, not extended, because this site has no SCSS, no
|
||||||
|
`resources.ToCSS`, no PostCSS and no image processing. This moves the build
|
||||||
|
off apk's hugo 0.139.0, about two years behind, onto the current stable.
|
||||||
|
Rendered output across the whole `public/` tree is unchanged except the
|
||||||
|
`meta name=generator` version string
|
||||||
- 2026-08-09: made `script/check` run `script/lint` (closes #9). It previously
|
- 2026-08-09: made `script/check` run `script/lint` (closes #9). It previously
|
||||||
ran only `fmt-check` then `test`, so `script/lint` executed nowhere — not in
|
ran only `fmt-check` then `test`, so `script/lint` executed nowhere — not in
|
||||||
`make check`, not in the pre-commit hook, and not in CI, even though the
|
`make check`, not in the pre-commit hook, and not in CI, even though the
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
baseURL = 'https://lora.vegas/'
|
baseURL = 'https://lora.vegas/'
|
||||||
languageCode = 'en-us'
|
locale = 'en-us'
|
||||||
title = 'LoRa Vegas — Las Vegas Meshtastic Community'
|
title = 'LoRa Vegas — Las Vegas Meshtastic Community'
|
||||||
theme = 'loravega'
|
theme = 'loravega'
|
||||||
|
|
||||||
|
|||||||
115
script/bootstrap
115
script/bootstrap
@@ -2,9 +2,10 @@
|
|||||||
# script/bootstrap: install all dependencies needed to build and develop
|
# script/bootstrap: install all dependencies needed to build and develop
|
||||||
# this Hugo site, idempotently. Base tooling comes from nix, apt, brew,
|
# this Hugo site, idempotently. Base tooling comes from nix, apt, brew,
|
||||||
# or apk (detected in that order); assumes NOTHING is present (not git,
|
# or apk (detected in that order); assumes NOTHING is present (not git,
|
||||||
# make, hugo, or node). Installs hugo (the site build) and node/npm
|
# make, go, hugo, or node). Installs hugo (the site build, at the exact
|
||||||
# (prettier, used to format the repo's own markdown docs). Every install
|
# version pinned below) and node/npm (prettier, used to format the
|
||||||
# is guarded by a check so already-installed tools are skipped.
|
# repo's own markdown docs). Every install is guarded by a check so
|
||||||
|
# already-installed tools are skipped.
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
@@ -12,6 +13,50 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|||||||
PKGMGR=""
|
PKGMGR=""
|
||||||
SUDO=""
|
SUDO=""
|
||||||
|
|
||||||
|
# --- Hugo -------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Hugo produces the published artifact, so its version is a property of
|
||||||
|
# the site's output, not of the build environment. It is therefore
|
||||||
|
# pinned here rather than taken from whatever the distro serves: before
|
||||||
|
# this, alpine 3.21's apk supplied hugo 0.139.0 -- a version chosen by
|
||||||
|
# nobody, roughly two years behind upstream, and liable to change
|
||||||
|
# silently whenever the base image digest moves.
|
||||||
|
#
|
||||||
|
# `go install` is the hash-verified mechanism: Go checks the module
|
||||||
|
# against the sum.golang.org checksum database. That is the mechanism
|
||||||
|
# REPO_POLICIES.md already names for Go, and it needs no hand-maintained
|
||||||
|
# sha256. The other tools this script installs stay on the package
|
||||||
|
# manager, which #19 settled is fine for build-time conveniences.
|
||||||
|
#
|
||||||
|
# hugo v0.164.0, 2026-07-06
|
||||||
|
HUGO_VERSION="v0.164.0"
|
||||||
|
|
||||||
|
# hugo v0.164.0's go.mod requires go >= 1.26.0, and alpine 3.21's `go`
|
||||||
|
# package is 1.23.9 built with GOTOOLCHAIN=local, so a bare `go install`
|
||||||
|
# refuses to run at all. Naming the toolchain explicitly makes Go fetch
|
||||||
|
# it through the module proxy and verify it against sum.golang.org like
|
||||||
|
# any other module, so the chain stays hash-verified end to end -- and
|
||||||
|
# the Go version that compiles hugo becomes deliberate too, instead of
|
||||||
|
# being inherited from whatever the base image happens to ship.
|
||||||
|
# go1.26.5, 2026-08-09
|
||||||
|
HUGO_GOTOOLCHAIN="go1.26.5"
|
||||||
|
|
||||||
|
# Standard hugo, not hugo extended: CGO_ENABLED=0 is deliberate.
|
||||||
|
# Verified that this site uses nothing extended provides -- there are no
|
||||||
|
# .scss/.sass files, no resources.ToCSS, no PostCSS, and no image
|
||||||
|
# processing (.Resize/.Fill/.Fit/images.* are all absent). The CSS is
|
||||||
|
# plain and inlined by `readFile` in baseof.html. The `+extended` on the
|
||||||
|
# apk build this replaces was incidental, not a requirement, so do not
|
||||||
|
# assume a future change needs it without rechecking the above.
|
||||||
|
HUGO_CGO_ENABLED="0"
|
||||||
|
|
||||||
|
# Where the hugo binary lands. It has to be on the default PATH of a
|
||||||
|
# *fresh* shell, not just of this script: the Dockerfile's `RUN make
|
||||||
|
# check` and deploy.yml's `script/test` step each start their own shell
|
||||||
|
# and would never see a GOPATH bin directory. Overridable so an
|
||||||
|
# unprivileged install can point somewhere writable.
|
||||||
|
HUGO_BIN_DIR="${HUGO_BIN_DIR:-/usr/local/bin}"
|
||||||
|
|
||||||
detect_pkgmgr() {
|
detect_pkgmgr() {
|
||||||
[ -n "$PKGMGR" ] && return 0
|
[ -n "$PKGMGR" ] && return 0
|
||||||
if command -v nix-env >/dev/null 2>&1; then
|
if command -v nix-env >/dev/null 2>&1; then
|
||||||
@@ -28,13 +73,17 @@ detect_pkgmgr() {
|
|||||||
fi
|
fi
|
||||||
if [ "$PKGMGR" = "apt" ]; then
|
if [ "$PKGMGR" = "apt" ]; then
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
if [ "$(id -u)" != "0" ]; then
|
detect_sudo
|
||||||
SUDO="sudo"
|
|
||||||
fi
|
|
||||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get update
|
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get update
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detect_sudo() {
|
||||||
|
if [ -z "$SUDO" ] && [ "$(id -u)" != "0" ]; then
|
||||||
|
SUDO="sudo"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# pkg_install <nix-attr> <apt-pkg> <brew-formula> <apk-pkg>
|
# pkg_install <nix-attr> <apt-pkg> <brew-formula> <apk-pkg>
|
||||||
pkg_install() {
|
pkg_install() {
|
||||||
detect_pkgmgr
|
detect_pkgmgr
|
||||||
@@ -50,6 +99,56 @@ missing() {
|
|||||||
! command -v "$1" >/dev/null 2>&1
|
! command -v "$1" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# True when the hugo already on PATH is the pinned version. Unlike the
|
||||||
|
# other tools, mere presence is not good enough here: an older hugo has
|
||||||
|
# to be replaced, not accepted, or the pin means nothing.
|
||||||
|
hugo_pinned() {
|
||||||
|
command -v hugo >/dev/null 2>&1 || return 1
|
||||||
|
# `hugo version` prints e.g. "hugo v0.164.0 linux/amd64 ..." for a
|
||||||
|
# `go install` build, or "hugo v0.164.0-ce2470e+extended ..." for an
|
||||||
|
# official release binary. Compare only the vX.Y.Z part: a build of
|
||||||
|
# the same version that happens to be extended renders this site
|
||||||
|
# identically (see HUGO_CGO_ENABLED above), so there is no reason to
|
||||||
|
# overwrite a developer's existing matching install.
|
||||||
|
have="$(hugo version 2>/dev/null | awk '{print $2}' | sed 's/[-+].*//')"
|
||||||
|
[ "$have" = "$HUGO_VERSION" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
install_hugo() {
|
||||||
|
detect_sudo
|
||||||
|
|
||||||
|
# The Go toolchain is a build-time convenience like git and make, so
|
||||||
|
# it comes from the package manager; the thing that must be
|
||||||
|
# deliberate is what it builds, which HUGO_VERSION and
|
||||||
|
# HUGO_GOTOOLCHAIN pin.
|
||||||
|
if missing go; then pkg_install go golang-go go go; fi
|
||||||
|
|
||||||
|
# Build as the invoking user into a scratch GOBIN, then place the
|
||||||
|
# binary with `install`. Running the whole `go install` under sudo
|
||||||
|
# would work but would populate root's module cache instead of the
|
||||||
|
# user's, which is needlessly slow and surprising on a workstation.
|
||||||
|
gobin="$(mktemp -d)"
|
||||||
|
CGO_ENABLED="$HUGO_CGO_ENABLED" \
|
||||||
|
GOTOOLCHAIN="$HUGO_GOTOOLCHAIN" \
|
||||||
|
GOBIN="$gobin" \
|
||||||
|
go install "github.com/gohugoio/hugo@${HUGO_VERSION}"
|
||||||
|
$SUDO install -d "$HUGO_BIN_DIR"
|
||||||
|
$SUDO install -m 0755 "$gobin/hugo" "$HUGO_BIN_DIR/hugo"
|
||||||
|
rm -rf "$gobin"
|
||||||
|
|
||||||
|
# Drop any cached PATH lookup of the hugo we just replaced, so the
|
||||||
|
# check below tests the new binary and not the old one.
|
||||||
|
hash -r 2>/dev/null || true
|
||||||
|
|
||||||
|
# Fail loudly rather than let a later build run on a shadowing hugo
|
||||||
|
# from somewhere earlier in PATH.
|
||||||
|
if ! hugo_pinned; then
|
||||||
|
echo "bootstrap: installed $HUGO_VERSION into $HUGO_BIN_DIR but" \
|
||||||
|
"'hugo' on PATH is still $(hugo version 2>/dev/null || echo absent)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
|
|
||||||
@@ -63,8 +162,8 @@ main() {
|
|||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Site build.
|
# Site build. Pinned and hash-verified -- see the HUGO_* constants.
|
||||||
if missing hugo; then pkg_install hugo hugo hugo hugo; fi
|
if ! hugo_pinned; then install_hugo; fi
|
||||||
|
|
||||||
# node/npm provide prettier (via npx) for formatting the docs.
|
# node/npm provide prettier (via npx) for formatting the docs.
|
||||||
if missing node; then pkg_install nodejs nodejs node nodejs; fi
|
if missing node; then pkg_install nodejs nodejs node nodejs; fi
|
||||||
|
|||||||
Reference in New Issue
Block a user