ci.yml RawHistoryFolder
1name: CI
2
3on:
4 push:
5 branches: [main]
6 pull_request:
7
8env:
9 # Test the module alone, with the versions in go.mod (never a go.work).
10 GOWORK: "off"
11
12jobs:
13 lint:
14 name: Lint
15 runs-on: ubuntu-latest
16 steps:
17 - uses: actions/checkout@v6
18 - uses: actions/setup-go@v5
19 with:
20 go-version-file: go.mod
21 cache: true
22 - uses: golangci/golangci-lint-action@v9
23 with:
24 version: v2.14.0
25
26 test:
27 name: Test
28 # ermite needs git >= 2.45; the ubuntu-latest image (Debian bookworm) has 2.39.
29 # The job runs in archlinux:latest as root, with a current git.
30 runs-on: ubuntu-latest
31 container: archlinux:latest
32 steps:
33 # openssh provides ssh-keygen, which the tests use to check that the squash
34 # commits verify (git verify-commit, ADR 0022). The tests fail without it when CI is set.
35 # nodejs runs the tests of the file finder (internal/adapters/web/jstest).
36 - name: System packages
37 run: pacman -Syu --noconfirm --needed git gcc openssh nodejs
38 - uses: actions/checkout@v6
39 # The workspace belongs to the runner user, not root: without this, git does not
40 # treat it as a repository and `git diff a b` compares the two files instead.
41 - name: Trust the workspace
42 run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
43 - uses: actions/setup-go@v5
44 with:
45 go-version-file: go.mod
46 cache: true
47 - name: Git is at least 2.45
48 run: |
49 git --version
50 v=$(git --version | sed -E 's/^git version ([0-9]+)\.([0-9]+).*/\1 \2/')
51 set -- $v
52 if [ "$1" -lt 2 ] || { [ "$1" -eq 2 ] && [ "$2" -lt 45 ]; }; then
53 echo "git 2.45 or newer is required" >&2
54 exit 1
55 fi
56 - name: Verify tidy
57 run: |
58 go mod tidy
59 git diff --exit-code -- go.mod go.sum
60 - name: Generated templ code is up to date
61 run: scripts/templ-drift.sh
62 - run: go vet ./...
63 # The end-to-end tests (internal/app, a real server per test) run before a
64 # PR is opened (README, Build) and here on main only: they are most of the
65 # time of a PR run.
66 - name: Tests
67 run: go test -race $(go list ./... | grep -vx 'bnema.dev/ermite/internal/app')
68 - name: End-to-end tests
69 if: github.event_name == 'push'
70 run: go test -race ./internal/app/
71 - name: Architecture
72 run: go tool hexcheck -fail-on warn ./...
73 # The core of the file finder (static/js/files.js) runs in Node.
74 - name: JavaScript tests
75 run: node --test 'internal/adapters/web/jstest/*.test.mjs'
76
77 proto:
78 name: Protobuf and generated code
79 runs-on: ubuntu-latest
80 steps:
81 - uses: actions/checkout@v6
82 with:
83 # buf breaking compares with the base branch.
84 fetch-depth: 0
85 - uses: actions/setup-go@v5
86 with:
87 go-version-file: go.mod
88 cache: true
89 - run: go tool buf lint
90 - name: Breaking changes
91 if: github.event_name == 'pull_request'
92 # Skipped by the script while the base branch has no proto/ directory.
93 run: scripts/buf-breaking.sh "origin/${{ github.base_ref }}"
94 - name: Generated protobuf code is up to date
95 run: |
96 go tool buf generate
97 git diff --exit-code -- gen/
98 test -z "$(git status --porcelain -- gen/)"
99 - name: Generated mocks are up to date
100 run: |
101 go generate ./internal/ports
102 git diff --exit-code -- internal/ports/mocks/
103 test -z "$(git status --porcelain -- internal/ports/mocks/)"
104
105 image:
106 name: Image
107 # Build only, nothing is pushed. A plain ubuntu-latest job (not a container):
108 # the runner image provides the docker CLI and daemon.
109 runs-on: ubuntu-latest
110 steps:
111 - uses: actions/checkout@v6
112 with:
113 # git describe needs the tags for the image version.
114 fetch-depth: 0
115 - name: Build the image
116 run: |
117 docker build \
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 | tee /dev/stderr | grep -qF "ermite $(git describe --tags --always --dirty)"
123 docker run --rm --entrypoint git ermite:ci --version