detached a873e08

ci: build the image

commit
a873e08622b13cbb3ed3d25b2fa06ddd4def80b5
author
brice · · 2026-10-10 11:55 UTC
parent
63f8a7f
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +45 -0
M .forgejo/workflows/ci.yml +27 -0
@@ -94,3 +94,30 @@ jobs:
9494 go generate ./internal/ports
9595 git diff --exit-code -- internal/ports/mocks/
9696 test -z "$(git status --porcelain -- internal/ports/mocks/)"
97+
98+ image:
99+ name: Image
100+ # Build only, nothing is pushed. The arch job container gets the runner's rootless
101+ # Podman socket as /var/run/docker.sock (docker_host in ci-runner/config.yml), so the
102+ # docker CLI builds through Podman.
103+ runs-on: arch
104+ steps:
105+ - name: System packages
106+ run: pacman -Syu --noconfirm --needed git docker
107+ - uses: actions/checkout@v6
108+ with:
109+ # git describe needs the tags for the image version.
110+ fetch-depth: 0
111+ # The build container is a nested container: it reaches Forgejo on the host loopback
112+ # the same way the job container does (10.0.2.2, see vps-infra homelab/igor/ci-runner).
113+ - name: Build the image
114+ run: |
115+ docker build \
116+ --add-host git.bnema.dev:10.0.2.2 \
117+ --build-arg GIT_REWRITE_BASE=http://git.bnema.dev:8088/ \
118+ --build-arg VERSION="$(git describe --tags --always --dirty)" \
119+ -t ermite:ci .
120+ - name: Smoke test
121+ run: |
122+ docker run --rm ermite:ci version
123+ docker run --rm --entrypoint git ermite:ci --version
@@ -94,3 +94,30 @@ jobs:
94 go generate ./internal/ports94 go generate ./internal/ports
95 git diff --exit-code -- internal/ports/mocks/95 git diff --exit-code -- internal/ports/mocks/
96 test -z "$(git status --porcelain -- internal/ports/mocks/)"96 test -z "$(git status --porcelain -- internal/ports/mocks/)"
97+
98+ image:
99+ name: Image
100+ # Build only, nothing is pushed. The arch job container gets the runner's rootless
101+ # Podman socket as /var/run/docker.sock (docker_host in ci-runner/config.yml), so the
102+ # docker CLI builds through Podman.
103+ runs-on: arch
104+ steps:
105+ - name: System packages
106+ run: pacman -Syu --noconfirm --needed git docker
107+ - uses: actions/checkout@v6
108+ with:
109+ # git describe needs the tags for the image version.
110+ fetch-depth: 0
111+ # The build container is a nested container: it reaches Forgejo on the host loopback
112+ # the same way the job container does (10.0.2.2, see vps-infra homelab/igor/ci-runner).
113+ - name: Build the image
114+ run: |
115+ docker build \
116+ --add-host git.bnema.dev:10.0.2.2 \
117+ --build-arg GIT_REWRITE_BASE=http://git.bnema.dev:8088/ \
118+ --build-arg VERSION="$(git describe --tags --always --dirty)" \
119+ -t ermite:ci .
120+ - name: Smoke test
121+ run: |
122+ docker run --rm ermite:ci version
123+ docker run --rm --entrypoint git ermite:ci --version
M README.md +18 -0
@@ -53,6 +53,24 @@ Use the admin token (`ERMITE_ADMIN_TOKEN`) or a stored token as the password; th
5353
5454 The server keeps its runtime files in `$ERMITE_DATA_DIR/run/` (the hook socket and scripts that git calls on each push); the hook socket path must stay under about 100 bytes.
5555
56+## Run with Docker
57+
58+```sh
59+docker build --build-arg VERSION="$(git describe --tags --always --dirty)" -t ermite .
60+docker run -d -p 7341:7341 -v ermite-data:/data \
61+ -e ERMITE_PUBLIC_URL=http://localhost:7341 -e ERMITE_ADMIN_TOKEN="$(head -c 32 /dev/urandom | base64)" ermite
62+```
63+
64+The image is alpine with git, runs as uid 10001 and keeps its data in the `/data` volume. Logs are JSON by default. The build fetches `bnema.dev/ermite-*` from `git.bnema.dev`, so the host must reach it (NetBird); the build container uses the host's DNS and routes. Behind another route, pass `--build-arg GIT_REWRITE_BASE=http://git.bnema.dev:8088/` (and `--add-host`), as the CI job does.
65+
66+## Develop with compose
67+
68+```sh
69+docker compose up
70+```
71+
72+Serves on `http://localhost:7341` with the development admin token in `compose.yaml`. The source is mounted and [air](https://github.com/air-verse/air) (`go tool air`, `.air.toml`) rebuilds and restarts the server on each change to a `.go` or `.templ` file; the module and build caches and the data live in named volumes. `docker compose down -v` removes them.
73+
5674 ## Build
5775
5876 ```sh
@@ -53,6 +53,24 @@ Use the admin token (`ERMITE_ADMIN_TOKEN`) or a stored token as the password; th
53 53
54 The server keeps its runtime files in `$ERMITE_DATA_DIR/run/` (the hook socket and scripts that git calls on each push); the hook socket path must stay under about 100 bytes.54 The server keeps its runtime files in `$ERMITE_DATA_DIR/run/` (the hook socket and scripts that git calls on each push); the hook socket path must stay under about 100 bytes.
55 55
56+## Run with Docker
57+
58+```sh
59+docker build --build-arg VERSION="$(git describe --tags --always --dirty)" -t ermite .
60+docker run -d -p 7341:7341 -v ermite-data:/data \
61+ -e ERMITE_PUBLIC_URL=http://localhost:7341 -e ERMITE_ADMIN_TOKEN="$(head -c 32 /dev/urandom | base64)" ermite
62+```
63+
64+The image is alpine with git, runs as uid 10001 and keeps its data in the `/data` volume. Logs are JSON by default. The build fetches `bnema.dev/ermite-*` from `git.bnema.dev`, so the host must reach it (NetBird); the build container uses the host's DNS and routes. Behind another route, pass `--build-arg GIT_REWRITE_BASE=http://git.bnema.dev:8088/` (and `--add-host`), as the CI job does.
65+
66+## Develop with compose
67+
68+```sh
69+docker compose up
70+```
71+
72+Serves on `http://localhost:7341` with the development admin token in `compose.yaml`. The source is mounted and [air](https://github.com/air-verse/air) (`go tool air`, `.air.toml`) rebuilds and restarts the server on each change to a `.go` or `.templ` file; the module and build caches and the data live in named volumes. `docker compose down -v` removes them.
73+
56 ## Build74 ## Build
57 75
58 ```sh76 ```sh

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 3

Tags 44

↑↓ moveenter openesc close