-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaskfile.yml
More file actions
208 lines (191 loc) · 10.3 KB
/
Copy pathTaskfile.yml
File metadata and controls
208 lines (191 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
version: "3"
# Build/test/lint/dst orchestration for github.com/spin-stack/storage; `ci` is the
# aggregate gate GitHub Actions runs.
#
# Reproducibility rule: every tool is pinned here and installed into ./.tools/bin by
# `task tools`, so nothing depends on what is on the developer's PATH.
#
# What is left in this file is the vars every group reads and the targets that cross them:
# build, test, and the gates. Each group of targets lives in taskfiles/, included with
# `flatten: true` — so a name is exactly what a human types, with no namespace prefix
# derived from a filename, and moving a target between files never renames it. go-task
# refuses two files that define the same name, so nothing can be shadowed silently.
vars:
SIMULABLE: ./hack/analyzers/simulable/cmd/simulable
# Project-local tool bin. Committed to .gitignore; rebuilt by `task tools`.
TOOLS_BIN: "{{.ROOT_DIR}}/.tools/bin"
OUTPUT_DIR: "{{.ROOT_DIR}}/_output"
# Project-local by default so no task needs root; override for a shared CI cache.
BUILDKIT_CACHE_DIR: '{{.BUILDKIT_CACHE_DIR | default (printf "%s/.cache/buildkit" .ROOT_DIR)}}'
# --- the machine -------------------------------------------------------------------
# QEMU, the guest kernel and the firmware are one versioned artefact built in
# spin-stack/spin-machine. This repository builds none of them: it used to build a QEMU
# from a recipe copied from another project, against a device list that was
# byte-for-byte that project's, and it mirrored that project's kernel through a registry
# so a machine with no sibling checkout could find one. All of that is what having the
# machine in one place replaced.
#
# Pinned by version and by content, for the reason the kernel used to be pinned by hash:
# "which machine did this lane certify?" needs an answer that is not "whatever was
# published that day". Bump both together and say in the commit why the machine changed.
SPIN_MACHINE_VERSION: '{{.SPIN_MACHINE_VERSION | default "v20260908.02"}}'
SPIN_MACHINE_SHA256: '{{.SPIN_MACHINE_SHA256 | default "835c193745db13d3dcbaa4574fa471d967335fc4249302de6e0489dfaba02bdb"}}'
# A sibling checkout that has already built one wins over the published release.
SPIN_MACHINE_DIR: '{{.SPIN_MACHINE_DIR | default "../spin-machine"}}'
# Object-store backend under test (§6.1 conformance suite). Pinned by digest so a
# re-tagged image cannot silently change what the suite certified.
RUSTFS_IMAGE: "rustfs/rustfs:latest@sha256:84ce557a0245a06a9aae5516f55ee0f007fca78d41df356f419306fdc0cb168c"
# Graphviz, pinned by digest like every other image here. The diagrams at the repository
# root are generated from the .dot beside each one; the SVG is output and is committed so
# that reading the repository does not require rendering it.
DOT_IMAGE: "nshine/dot@sha256:17ba91db2197ae4154cdc4b397a263017ce15c7f2c0cb8bf29404d78bcb4bd6d"
# --- pinned tool versions (the single place each is declared) ---
SQLC_VERSION: v1.30.0
PGSCHEMA_VERSION: v1.12.0
# Postgres for every schema task. The same tag the integration lane starts with
# TestContainers, so `task db:plan` and the tests can never disagree about what
# the server accepts.
POSTGRES_IMAGE: postgres:18-alpine
DEVDB_CONTAINER: spin-storage-devdb
DEVDB_PORT: '{{.DEVDB_PORT | default "55432"}}'
# The guest kernel, at the one path the lane reads. Put there by `task machine`.
GUEST_KERNEL: '{{.OUTPUT_DIR}}/kernel/vmlinux'
# Target database for db:plan / db:apply — the local development database by
# default. Point DB_* at a real one to plan or apply against it; the password
# comes from the environment (PGPASSWORD), never from a var in this file.
DB_HOST: '{{.DB_HOST | default "localhost"}}'
DB_PORT: '{{.DB_PORT | default .DEVDB_PORT}}'
DB_NAME: '{{.DB_NAME | default "cp"}}'
DB_USER: '{{.DB_USER | default "cp"}}'
# Flags for the database being changed.
PGSCHEMA_TARGET: --host {{.DB_HOST}} --port {{.DB_PORT}} --db {{.DB_NAME}} --user {{.DB_USER}} --sslmode disable
# Flags for the scratch database pgschema materializes the desired state in while
# diffing. Always given explicitly: with no --plan-host, pgschema downloads and
# runs an embedded PostgreSQL of its own choosing at plan time — unpinned, and not
# the version this project targets.
PGSCHEMA_PLAN: --plan-host {{.DB_HOST}} --plan-port {{.DB_PORT}} --plan-db {{.DB_NAME}} --plan-user {{.DB_USER}} --plan-sslmode disable
# Protobuf/Connect toolchain (ADR-0018). protoc itself is never used: buf
# compiles the schema and drives the two plugins. PROTOC_GEN_GO_VERSION must
# match the google.golang.org/protobuf version in go.mod, and
# PROTOC_GEN_CONNECT_GO_VERSION the connectrpc.com/connect one — a plugin
# newer than its runtime generates code the module cannot compile.
BUF_VERSION: v1.72.0
PROTOC_GEN_GO_VERSION: v1.36.11
PROTOC_GEN_CONNECT_GO_VERSION: v1.20.0
# golangci-lint v2 also owns formatting (gofmt + goimports are configured as
# `formatters` in .golangci.yml), so there is exactly one formatter binary.
GOLANGCI_VERSION: v2.12.2
# `deadcode` ships in golang.org/x/tools, which this module already requires (the
# simulable analyzer is built on go/analysis). It is pinned to the *same* version as
# go.mod's, and `tools:deadcode` refuses to install when the two disagree: an analyzer
# built against a different x/tools than the tree compiles with answers about a
# different program than the one this repository ships.
XTOOLS_VERSION: v0.43.0
includes:
tools: {taskfile: ./taskfiles/tools.yml, flatten: true}
generate: {taskfile: ./taskfiles/generate.yml, flatten: true}
db: {taskfile: ./taskfiles/db.yml, flatten: true}
machine: {taskfile: ./taskfiles/machine.yml, flatten: true}
guest: {taskfile: ./taskfiles/guest.yml, flatten: true}
demo: {taskfile: ./taskfiles/demo.yml, flatten: true}
backend: {taskfile: ./taskfiles/backend.yml, flatten: true}
gates: {taskfile: ./taskfiles/gates.yml, flatten: true}
tasks:
default:
cmds:
- task: ci
build:
desc: Build all packages and commands.
cmds:
- go build ./...
build:cmd:
desc: Build the binaries (volume-agent, control-plane) into _output/bin.
vars:
# The version each binary reports about itself: the Agent sends it in every
# heartbeat (§13.4, fleet-mixed), so "dev" from an untagged build is a
# deliberate answer, not a missing one.
VERSION: '{{.VERSION | default "dev"}}'
cmds:
- mkdir -p {{.OUTPUT_DIR}}/bin
- go build -ldflags "-X main.version={{.VERSION}}" -o {{.OUTPUT_DIR}}/bin/ ./cmd/...
test:
desc: Run the full unit/property test suite with the race detector.
cmds:
- go test -race ./...
test:integration:
desc: Run Docker-gated integration tests (TestContainers Postgres).
cmds:
- go test -tags integration -count=1 ./internal/metadata/pg/...
test:e2e:
desc: >-
Run the deployment, not the library: the real control-plane and volume-agent
as processes, against a real Postgres 18 and the pinned RustFS. It is the only
lane that can see the two binaries disagree — about a key file, about a flag
nobody passes — because everything else drives Go types in-process.
# The Agent creates and inspects every qcow2 chain by running the pinned qemu-img — v6
# forbids a parser of our own — so this lane cannot start one without a machine.
deps: [build:cmd, machine]
cmds:
- RUSTFS_IMAGE={{.RUSTFS_IMAGE}} go test -tags e2e -count=1 -timeout 15m ./integration/e2e/...
test:e2e:aws:
desc: >-
The e2e lane with its object store on real AWS S3: the two binaries publish commits
to S3 rather than to a container. Needs credentials, and creates one bucket per test
that it purges on the way out. Not in ci:full — the merge gate must not need a cloud
account.
deps: [build:cmd, machine]
cmds:
- SPIN_OBJECT_STORE=aws go test -tags e2e -count=1 -timeout 30m ./integration/e2e/...
ci:
desc: Fast local gate — format, build, lint, deadcode, open DEV entries, comment rot, test, dst. No Docker required.
cmds:
- task: fmt:check
- task: build
- task: lint
# Beside lint, and before the race suite: it is static analysis over the built
# program, it costs about two seconds, and an unreachable symbol reported after
# twenty seconds of tests is a report that arrives once nobody is watching.
- task: deadcode
# Beside deadcode: two files read, no toolchain, and it prints the open entries on a
# green run so they are read by whoever runs the gate.
- task: dev:entries
# The same rule pointed at the comments that replaced the deleted Markdown. One `go
# list`, one awk pass.
- task: comment:rot
- task: refs
# Beside it, and the same kind of claim: a rule CLAUDE.md states as part of "done"
# that nothing computed. One `wc`.
- task: status:cap
- task: test
- task: dst
# In the *fast* gate: renaming a Taskfile target is a local edit whose only victim is
# a workflow file, and the person renaming it runs `task ci`, not `ci:full`.
- task: workflows:verify
#
# One gate. `ci:noguest` existed to name the weaker claim while a guest lane could skip
# itself and still report a pass; it went with the vhost-user-blk lanes it arbitrated.
# When the qcow2 lane lands, a machine without the pinned QEMU and kernel must again be
# unable to report a green merge gate — that is what it comes back as.
ci:full:
desc: >-
The merge gate: everything CI runs, including the Docker-gated lanes. `task ci` is
the fast local loop.
cmds:
- task: ci:lanes
ci:lanes:
internal: true
desc: >-
The list of lanes the merge gate runs. It is a target of its own rather than
`ci:full`'s body because it was shared by two public gates and will be again when
the qcow2 lane restores the guest-backed half. The Docker-gated tasks live in it
because a task nobody runs is a task nobody notices going red: backend:conformance
was broken on main for a whole increment because it was documented but not gated.
cmds:
- task: ci
- task: generate:check
- task: diagrams:check
- task: db:verify
- task: cover
- task: test:integration
- task: backend:conformance
- task: test:e2e