All checks were successful
check / check (push) Successful in 1m9s
Add a root Dockerfile.lint that carries the checks as build steps -- a `lint` stage running `hugo --minify --printPathWarnings` and a `fmt-check` stage running the prettier check -- and reduce script/lint and script/fmt-check to building their stage. A successful build is a clean check. There is no host path and deliberately no "am I already inside a container?" branch, which would be a host lint path in disguise. The two stages share a `base` whose first four instructions are byte-identical to the main Dockerfile's, so the expensive `RUN script/bootstrap` layer that compiles the pinned Hugo from source is a cache hit against the main image instead of a second build of the same thing. Resolve the resulting recursion by splitting the checks by where they run, not with an escape hatch. `make check` runs script/lint, so the main Dockerfile can no longer `RUN make check`: that would be docker-in-docker inside a bare Alpine with no docker client and no daemon socket, and script/cibuild is what CI runs on every push. The main Dockerfile therefore runs `make test`, the production build, and script/cibuild builds it and then calls script/lint and script/fmt-check. CI still covers the production build, lint and the format check, and it runs exactly what a developer runs. script/fmt stays on the host because it rewrites the working tree, which a container build cannot do. That makes it the authoritative copy of the prettier version, scope and flags that the fmt-check stage duplicates; both sides carry a keep-in-sync note. The duplication is forced: any `RUN script/fmt-check` inside the image is the recursion again. Caching is waived for the checks in the shape this repo already settled: `ARG CHECK_EPOCH` with no default, declared and guarded separately in each stage because ARG does not cross a FROM, with the value expanded into the checked command as well as the guard so invalidation does not rest on BuildKit's treatment of an unreferenced ARG. All four image-building entrypoints now generate and pass it -- script/cibuild, script/docker, script/lint, script/fmt-check. Verified: two consecutive script/lint runs on an unchanged tree both executed hugo for real, with script/bootstrap CACHED; a constant-epoch counterfactual restored the false green (exit 0, lint layer CACHED, no hugo output); an empty epoch failed closed on the guard; a broken template failed the lint stage and an unformatted README failed the fmt-check stage, both reverted and re-run clean; script/cibuild and `make check` are green with all three checks demonstrably executing.
143 lines
5.7 KiB
Markdown
143 lines
5.7 KiB
Markdown
# lora.vegas
|
|
|
|
`lora.vegas` is the website of the Las Vegas Meshtastic and LoRa community: an
|
|
MIT-licensed single-page static site, built with Hugo, by
|
|
[@sneak](https://sneak.berlin).
|
|
|
|
It publishes what the local mesh needs in one linkable place:
|
|
|
|
- Mesh channel configurations
|
|
- Community coordination links (Discord, Signal)
|
|
- Meetup information
|
|
- Local resources
|
|
|
|
## Getting Started
|
|
|
|
From a fresh clone, `make setup` installs every build dependency (git, make, go,
|
|
the pinned Hugo, node/npm) and the git pre-commit hook, and `make serve` starts
|
|
the Hugo development server:
|
|
|
|
```bash
|
|
git clone git@git.eeqj.de:sneak/lora.vegas.git
|
|
cd lora.vegas
|
|
make setup
|
|
make serve
|
|
```
|
|
|
|
Then open <http://localhost:1313> to preview the site.
|
|
|
|
To produce the production build, which writes the rendered site to `public/`:
|
|
|
|
```bash
|
|
make test
|
|
```
|
|
|
|
Before committing, run the full check suite — the production build, the lint
|
|
build, and the formatting check:
|
|
|
|
```bash
|
|
make check
|
|
```
|
|
|
|
The lint build and the formatting check run inside Docker, so `make check` needs
|
|
a working Docker daemon; there is no host fallback.
|
|
|
|
`make fmt` rewrites the repo's markdown and CSS to the project's prettier
|
|
settings; run it if `make check` fails on formatting. It runs on the host,
|
|
because it writes to your working tree.
|
|
|
|
To contribute to this site, contact **sneak@sneak.berlin** for git repository
|
|
access.
|
|
|
|
## 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, go, hugo,
|
|
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
|
|
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,
|
|
run inside Docker: it builds the `lint` stage of `Dockerfile.lint`, where the
|
|
check is a build step, so a successful build is a clean lint
|
|
- `script/fmt` — format every markdown and CSS file in the repo with prettier;
|
|
the exclusions live in `.prettierignore` with the reason for each. The one
|
|
prettier entrypoint that runs on the host, because it writes to your working
|
|
tree
|
|
- `script/fmt-check` — check that formatting (read-only), also inside Docker:
|
|
the `fmt-check` stage of `Dockerfile.lint`
|
|
- `script/check` — run `script/test`, `script/lint`, then `script/fmt-check`;
|
|
modifies no tracked files
|
|
- `script/docker` — build the Docker image tagged with the project name
|
|
- `script/cibuild` — the CI build: the main image (the production build), then
|
|
`script/lint` and `script/fmt-check`
|
|
- `script/install-precommit` — install the git pre-commit hook that runs
|
|
`script/check`
|
|
|
|
Every lint run for this repo happens inside a container. `script/lint` and
|
|
`script/fmt-check` have no host path and no "already inside a container?"
|
|
branch, so what a developer runs and what CI runs are the same build.
|
|
|
|
That is also why the main `Dockerfile` runs `make test` rather than
|
|
`make check`: `make check` calls `script/lint`, which is itself a
|
|
`docker build`, so a `make check` inside an image would be docker-in-docker in a
|
|
bare Alpine with no docker client and no daemon socket. The checks are split by
|
|
where they run — the production build in `Dockerfile`, lint and the format check
|
|
in `Dockerfile.lint` — and `script/cibuild` drives all three, so CI coverage is
|
|
unchanged.
|
|
|
|
Build any image through `script/cibuild`, `script/docker`, `script/lint` or
|
|
`script/fmt-check` only. All four pass a per-invocation `CHECK_EPOCH` build
|
|
argument that the Dockerfiles require, so a check layer can never be served from
|
|
cache — without it Docker returns a green it did not earn. A bare `docker build`
|
|
fails closed on the `CHECK_EPOCH` guard rather than caching its way to a false
|
|
success.
|
|
|
|
A convenience `make serve` target runs `hugo server` for local preview.
|
|
|
|
## Rationale
|
|
|
|
The Las Vegas Meshtastic and LoRa community needs one durable, linkable place
|
|
for its channel configurations and group links. Those details otherwise live
|
|
inside a Discord or Signal thread, where they scroll away, cannot be linked to
|
|
from outside, are invisible to anyone who has not already joined, and quietly go
|
|
stale. A static site at a stable domain is the opposite of that: one URL to hand
|
|
to a newcomer, and one place to correct when a channel changes.
|
|
|
|
## Design
|
|
|
|
The site is a single page. All of its content is one Hugo content file,
|
|
`content/_index.md`, rendered by a minimal theme vendored in-repo at
|
|
`themes/loravega/` — there is no upstream theme dependency and no submodule.
|
|
|
|
The theme's `layouts/_default/baseof.html` inlines
|
|
`themes/loravega/static/css/style.css` into a `<style>` block with Hugo's
|
|
`readFile`, so the whole site ships as a single HTML document with no external
|
|
CSS request and no second round trip.
|
|
|
|
`hugo --minify` builds the site into `public/`. Deployment is automatic: on push
|
|
to `main`, the Gitea Actions workflow `.gitea/workflows/deploy.yml` builds the
|
|
site and publishes `public/` to Cloudflare Pages.
|
|
|
|
## TODO
|
|
|
|
The live task list is in [TODO.md](TODO.md).
|
|
|
|
## License
|
|
|
|
MIT. See [LICENSE](LICENSE). This covers everything in the repository — the Hugo
|
|
configuration, the `script/` entrypoints, the vendored `themes/loravega/`
|
|
templates and CSS, and the site content in `content/`.
|
|
|
|
## Author
|
|
|
|
[@sneak](https://sneak.berlin)
|