diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..eab80bc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git +public +resources +.hugo_build.lock diff --git a/.gitea/workflows/check.yml b/.gitea/workflows/check.yml new file mode 100644 index 0000000..a55bc55 --- /dev/null +++ b/.gitea/workflows/check.yml @@ -0,0 +1,9 @@ +name: check +on: [push] +jobs: + check: + runs-on: ubuntu-latest + steps: + # actions/checkout v4.2.2, 2026-02-28 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - run: script/cibuild diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..572b041 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# Hugo static-site build image. The build runs `make check` (the +# read-only prettier docs check plus a clean `hugo --minify` production +# build), so the image build fails on any formatting or Hugo build +# error. This is what CI (script/cibuild) runs on every push. +# alpine 3.21, 2026-02-28 +FROM alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709 + +WORKDIR /src + +# Install build dependencies first so the layer caches until the +# scripts change (script/bootstrap installs git, make, hugo, node/npm). +COPY script/ script/ +RUN script/bootstrap + +COPY . . + +# Run all checks - build fails if any check fails. +RUN make check diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..31ae122 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +.PHONY: bootstrap setup test lint fmt fmt-check check docker hooks serve + +bootstrap: + @script/bootstrap + +setup: + @script/setup + +test: + @script/test + +lint: + @script/lint + +fmt: + @script/fmt + +fmt-check: + @script/fmt-check + +check: + @script/check + +docker: + @script/docker + +hooks: + @script/install-precommit + +serve: + @hugo server diff --git a/README.md b/README.md index 60ddb63..dff20fc 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ Las Vegas Meshtastic and LoRa community website. ## About -This site provides information about the Las Vegas mesh networking community, including: +This site provides information about the Las Vegas mesh networking community, +including: - Mesh channel configurations - Community coordination (Discord, Signal) @@ -13,11 +14,13 @@ This site provides information about the Las Vegas mesh networking community, in ## Contributing -To contribute to this site, contact **sneak@sneak.berlin** for git repository access. +To contribute to this site, contact **sneak@sneak.berlin** for git repository +access. ## Technical Details -This is a static site built with Hugo. The site is deployed automatically via GitHub Actions. +This is a static site built with Hugo. The site is deployed automatically via +GitHub Actions. ### Local Development @@ -35,6 +38,32 @@ hugo Output will be in the `public/` directory. +## Entrypoints + +This repository adheres to the +[Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all) +standard: normalized scripts in `script/` are the entrypoints for the +development workflow, and the Makefile targets are thin shims that call them. We +provide: + +- `script/bootstrap` — install all build dependencies (git, make, hugo, + node/npm) idempotently +- `script/setup` — prepare a fresh clone: run `script/bootstrap` and install the + git pre-commit hook +- `script/test` — the correctness check: a clean `hugo --minify` production + build +- `script/lint` — a clean build that surfaces broken links and path collisions +- `script/fmt` — format the repo's own top-level markdown docs with prettier +- `script/fmt-check` — check that formatting (read-only) +- `script/check` — run `script/fmt-check` then `script/test`; modifies nothing +- `script/docker` — build the Docker image tagged with the project name +- `script/cibuild` — the CI build (`docker build .`); the Dockerfile runs + `make check` +- `script/install-precommit` — install the git pre-commit hook that runs + `script/check` + +A convenience `make serve` target runs `hugo server` for local preview. + ## License Content is provided as-is for community use. diff --git a/TODO.md b/TODO.md index 5c70c4c..c8a581c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,51 +1,53 @@ # Workflow -* branch (from `main`) -* do the work in Next Step -* move Next Step to the top of Completed Steps -* move the top item of Future Steps into Next Step -* commit (`TODO.md` changes in the same commit as the work) -* merge to `main` if the branch is not protected, otherwise open a PR -* push +- branch (from `main`) +- do the work in Next Step +- move Next Step to the top of Completed Steps +- move the top item of Future Steps into Next Step +- commit (`TODO.md` changes in the same commit as the work) +- merge to `main` if the branch is not protected, otherwise open a PR +- push # Status pre-1.0 -No git tags. The site is live, but the repo lacks the standard scaffold -(Makefile, LICENSE, Dockerfile, policy files). +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 +policy files. # Next Step -Add the policy scaffold in one commit: Makefile with Hugo-appropriate -targets (test builds the site with hugo --minify, lint/fmt/fmt-check via -prettier over content and theme, check, hooks), .prettierrc and -.prettierignore, LICENSE, REPO_POLICIES.md, .editorconfig, and a -Dockerfile plus .dockerignore that builds the site and runs make check, -images pinned by sha256. Update README to mention the new workflow. +Add the remaining policy scaffold: `LICENSE`, `REPO_POLICIES.md`, +`.editorconfig`, and prettier config files (`.prettierrc`, `.prettierignore`). +Update `README.md` accordingly. # Completed Steps -* 2026-02-10: design pass: minimal light theme with inline CSS, grey - wells for mesh channels and signal groups, horizontal overflow fix, - body width tuning, map link update -* 2026-02-10: added README and footer contribute link -* 2026-02-10: added Gitea workflow that builds the site and deploys to - Cloudflare Pages -* 2026-02-08: initial Hugo static site for lora.vegas +- 2026-07-25: added the scripts-to-rule-them-all scaffold (closes #4): `script/` + entrypoints, `Makefile` shims, a Hugo `Dockerfile` (sha256-pinned alpine) plus + `.dockerignore` that runs `make check`, `.gitea/workflows/check.yml` running + `script/cibuild`, and a README Entrypoints section. `test`/`lint` are a clean + `hugo --minify` build; `fmt`/`fmt-check` run prettier over the repo's own + top-level markdown only +- 2026-02-10: design pass: minimal light theme with inline CSS, grey wells for + mesh channels and signal groups, horizontal overflow fix, body width tuning, + map link update +- 2026-02-10: added README and footer contribute link +- 2026-02-10: added Gitea workflow that builds the site and deploys to + Cloudflare Pages +- 2026-02-08: initial Hugo static site for lora.vegas # Future Steps -* Add .gitea/workflows/check.yml that runs make check; pin the images - and actions in deploy.yml by sha256 (klakegg/hugo:ext-alpine, - node:20, actions/checkout, upload/download-artifact are all - unpinned) -* Rework README.md into the standard sections: Description, Getting - Started, Rationale, Design, TODO, License, Author (currently About, - Contributing, Technical Details, License) -* Replace the "content is provided as-is" README note with the text of - the committed LICENSE -* Expand .gitignore beyond Hugo outputs (OS and editor files) -* Verify the Cloudflare Pages deploy still works after the workflow - changes -* Keep mesh channel and signal group listings current +- Pin the images and actions in `deploy.yml` by sha256 + (`klakegg/hugo:ext-alpine`, `node:20`, `actions/checkout`, + `upload`/`download-artifact` are all unpinned) +- Rework README.md into the standard sections: Description, Getting Started, + Rationale, Design, TODO, License, Author (currently About, Contributing, + Technical Details, License) +- Replace the "content is provided as-is" README note with the text of the + committed LICENSE +- Expand .gitignore beyond Hugo outputs (OS and editor files) +- Verify the Cloudflare Pages deploy still works after the workflow changes +- Keep mesh channel and signal group listings current diff --git a/script/bootstrap b/script/bootstrap new file mode 100755 index 0000000..cd4ca97 --- /dev/null +++ b/script/bootstrap @@ -0,0 +1,76 @@ +#!/bin/sh +# script/bootstrap: install all dependencies needed to build and develop +# this Hugo site, idempotently. Base tooling comes from nix, apt, brew, +# or apk (detected in that order); assumes NOTHING is present (not git, +# make, hugo, or node). Installs hugo (the site build) and node/npm +# (prettier, used to format the repo's own markdown docs). Every install +# is guarded by a check so already-installed tools are skipped. +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" + +PKGMGR="" +SUDO="" + +detect_pkgmgr() { + [ -n "$PKGMGR" ] && return 0 + if command -v nix-env >/dev/null 2>&1; then + PKGMGR="nix" + elif command -v apt-get >/dev/null 2>&1; then + PKGMGR="apt" + elif command -v brew >/dev/null 2>&1; then + PKGMGR="brew" + elif command -v apk >/dev/null 2>&1; then + PKGMGR="apk" + else + echo "bootstrap: no supported package manager (nix, apt, brew, apk)" >&2 + exit 1 + fi + if [ "$PKGMGR" = "apt" ]; then + export DEBIAN_FRONTEND=noninteractive + if [ "$(id -u)" != "0" ]; then + SUDO="sudo" + fi + $SUDO env DEBIAN_FRONTEND=noninteractive apt-get update + fi +} + +# pkg_install +pkg_install() { + detect_pkgmgr + case "$PKGMGR" in + nix) nix-env -iA "nixpkgs.$1" ;; + apt) $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y "$2" ;; + brew) brew install "$3" ;; + apk) apk add --no-cache "$4" ;; + esac +} + +missing() { + ! command -v "$1" >/dev/null 2>&1 +} + +main() { + cd "$ROOT" + + # Base tooling. + if missing git; then pkg_install git git git git; fi + if missing make; then pkg_install gnumake make make make; fi + + # The theme is vendored in-repo, but initialise submodules if any + # are ever added so a fresh clone is buildable. + if [ -f .gitmodules ]; then + git submodule update --init --recursive + fi + + # Site build. + if missing hugo; then pkg_install hugo hugo hugo hugo; fi + + # node/npm provide prettier (via npx) for formatting the docs. + if missing node; then pkg_install nodejs nodejs node nodejs; fi + if missing npx; then pkg_install nodejs npm npm npm; fi + + echo "bootstrap complete" +} + +main "$@" diff --git a/script/check b/script/check new file mode 100755 index 0000000..7f218e5 --- /dev/null +++ b/script/check @@ -0,0 +1,14 @@ +#!/bin/sh +# script/check: run all checks. Our own extension to +# scripts-to-rule-them-all. Must not modify any files. Runs the +# read-only formatting check first, then the clean production build. +set -eu + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" + +main() { + "$SCRIPT_DIR/fmt-check" + "$SCRIPT_DIR/test" +} + +main "$@" diff --git a/script/cibuild b/script/cibuild new file mode 100755 index 0000000..968fae1 --- /dev/null +++ b/script/cibuild @@ -0,0 +1,14 @@ +#!/bin/sh +# script/cibuild: run the CI build. The Dockerfile runs `make check`, +# so a successful build implies all checks pass. The Gitea workflow +# runs this on push. +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" + +main() { + cd "$ROOT" + docker build . +} + +main "$@" diff --git a/script/docker b/script/docker new file mode 100755 index 0000000..b7de6ec --- /dev/null +++ b/script/docker @@ -0,0 +1,14 @@ +#!/bin/sh +# script/docker: build the Docker image tagged with the project name. +# The tag comes from script/projectname. +set -eu + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" +ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)" + +main() { + cd "$ROOT" + docker build -t "$("$SCRIPT_DIR/projectname")" . +} + +main "$@" diff --git a/script/fmt b/script/fmt new file mode 100755 index 0000000..b0ffb97 --- /dev/null +++ b/script/fmt @@ -0,0 +1,18 @@ +#!/bin/sh +# script/fmt: format the repo's own top-level markdown docs (README.md, +# TODO.md, ...) with prettier, using our standard settings. Scope is +# deliberately limited to top-level docs: site content under content/ +# is left untouched so rendered output cannot change. +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" + +PRETTIER_VERSION="3.4.2" + +main() { + cd "$ROOT" + npx --yes "prettier@${PRETTIER_VERSION}" --write \ + '*.md' --tab-width 4 --prose-wrap always +} + +main "$@" diff --git a/script/fmt-check b/script/fmt-check new file mode 100755 index 0000000..f696312 --- /dev/null +++ b/script/fmt-check @@ -0,0 +1,17 @@ +#!/bin/sh +# script/fmt-check: check the formatting of the repo's own top-level +# markdown docs (read-only). Same scope as script/fmt, but fails +# instead of writing. +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" + +PRETTIER_VERSION="3.4.2" + +main() { + cd "$ROOT" + npx --yes "prettier@${PRETTIER_VERSION}" --check \ + '*.md' --tab-width 4 --prose-wrap always +} + +main "$@" diff --git a/script/install-precommit b/script/install-precommit new file mode 100755 index 0000000..c2b43fb --- /dev/null +++ b/script/install-precommit @@ -0,0 +1,15 @@ +#!/bin/sh +# script/install-precommit: install the git pre-commit hook that runs +# script/precommit. Our own extension to scripts-to-rule-them-all. +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" + +main() { + cd "$ROOT" + printf '#!/bin/sh\nset -e\nscript/precommit\n' > .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit + echo "pre-commit hook installed: runs script/precommit" +} + +main "$@" diff --git a/script/lint b/script/lint new file mode 100755 index 0000000..ac4760e --- /dev/null +++ b/script/lint @@ -0,0 +1,15 @@ +#!/bin/sh +# script/lint: this Hugo site has no dedicated linter, so the lint gate +# is a clean build that surfaces broken internal links and template +# path problems. It is a real check: `hugo` fails on build errors, and +# --printPathWarnings reports render-target collisions. +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" + +main() { + cd "$ROOT" + hugo --minify --printPathWarnings +} + +main "$@" diff --git a/script/precommit b/script/precommit new file mode 100755 index 0000000..c0a7867 --- /dev/null +++ b/script/precommit @@ -0,0 +1,12 @@ +#!/bin/sh +# script/precommit: run by the git pre-commit hook; fails the commit if +# checks fail. Our own extension to scripts-to-rule-them-all. +set -eu + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" + +main() { + "$SCRIPT_DIR/check" +} + +main "$@" diff --git a/script/projectname b/script/projectname new file mode 100755 index 0000000..6f673df --- /dev/null +++ b/script/projectname @@ -0,0 +1,12 @@ +#!/bin/sh +# script/projectname: output the name of this project. Our own +# extension to scripts-to-rule-them-all. Other scripts that need the +# name (e.g. script/docker) call this, so they can stay identical +# across all repos. +set -eu + +main() { + echo "lora.vegas" +} + +main "$@" diff --git a/script/setup b/script/setup new file mode 100755 index 0000000..6f9724c --- /dev/null +++ b/script/setup @@ -0,0 +1,13 @@ +#!/bin/sh +# script/setup: set up the repo for development after a fresh clone: +# installs dependencies (script/bootstrap) and the git pre-commit hook. +set -eu + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" + +main() { + "$SCRIPT_DIR/bootstrap" + "$SCRIPT_DIR/install-precommit" +} + +main "$@" diff --git a/script/test b/script/test new file mode 100755 index 0000000..d16cc18 --- /dev/null +++ b/script/test @@ -0,0 +1,14 @@ +#!/bin/sh +# script/test: the correctness check for this static site is a clean +# production build. `hugo --minify` exits non-zero on any template, +# content, or config error, so a green build is a passing test. +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" + +main() { + cd "$ROOT" + hugo --minify +} + +main "$@"