-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaskfile.yml
More file actions
346 lines (315 loc) · 14.7 KB
/
Copy pathTaskfile.yml
File metadata and controls
346 lines (315 loc) · 14.7 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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# DevCell Taskfile. See README.md
#
# Taxonomy (post DIMM-205 refactor):
# noun-first, variant-first inside `image:*`
# image:impure:* ← Dockerfile/bake path (legacy, opt-in)
# image:pure:* ← nix2container path (default)
# image:{build,push} — aggregates over both variants
# image:{mirror,manifest} — variant-agnostic utilities
#
# Back-compat aliases for muscle memory + external refs are preserved
# on each renamed task. See `task --list` for the full canonical surface.
version: '3'
vars:
GIT_COMMIT_HASH:
sh: git rev-parse --short HEAD 2>/dev/null || echo "unknown"
BUILD_DATE:
sh: date -u +%Y%m%dT%H%M%SZ
CELL_LDFLAGS: -s -w -X github.com/DimmKirr/devcell/internal/version.GitCommit={{.GIT_COMMIT_HASH}} -X github.com/DimmKirr/devcell/internal/version.BuildDate={{.BUILD_DATE}}
env:
BUILDKIT_PROGRESS: plain
tasks:
# ── Generation (artefacts derived from source) ─────────────────────────
swagger:generate:
aliases: [swag:generate] # back-compat
desc: Regenerate Swagger docs from Go annotations
dir: "{{.TASKFILE_DIR}}"
silent: true
cmds:
- go run github.com/swaggo/swag/cmd/swag@latest init -g cmd/serve.go -o docs --parseDependency --parseInternal
docs:generate:
aliases: [web:docs] # back-compat
desc: Generate cell CLI markdown reference for the web site (requires Go)
dir: "{{.TASKFILE_DIR}}"
silent: true
cmds:
- go run $(ls cmd/*.go | grep -Ev '(_test|main)\.go') web/src/content/cell
# ── Validation (CI-cheap, no build) ────────────────────────────────────
nix:validate:
desc: Validate all nixhome stacks — syntax check then attr check (no build, no activation)
dir: "{{.TASKFILE_DIR}}"
cmds:
- |
set -e
NIX_BIN=/opt/devcell/.local/state/nix/profiles/profile/bin
FLAKE="{{.TASKFILE_DIR}}/nixhome"
echo "=== 1/2 Syntax check (nix-instantiate --parse) ==="
FAIL=0
for f in $(find nixhome -name '*.nix'); do
if sudo "$NIX_BIN/nix-instantiate" --parse "$f" >/dev/null 2>&1; then
echo " OK $f"
else
echo " FAIL $f"
sudo "$NIX_BIN/nix-instantiate" --parse "$f" 2>&1 | grep 'error:' >&2
FAIL=1
fi
done
[ "$FAIL" -eq 0 ] || exit 1
echo ""
echo "=== 2/2 Attr check (nix eval, no build) ==="
ARCH=$(uname -m)
[ "$ARCH" = "aarch64" ] && SUFFIX="-aarch64" || SUFFIX=""
for stack in base go node python fullstack electronics ultimate; do
CFG="devcell-${stack}${SUFFIX}"
printf " %-40s" "$CFG"
COUNT=$(sudo "$NIX_BIN/nix" eval \
"${FLAKE}#homeConfigurations.${CFG}.config.home.packages" \
--apply 'builtins.length' --json 2>/dev/null) \
&& echo "OK ($COUNT packages)" \
|| { echo "FAIL"; sudo "$NIX_BIN/nix" eval \
"${FLAKE}#homeConfigurations.${CFG}.config.home.packages" \
--apply 'builtins.length' --json 2>&1 | grep 'error:' >&2; exit 1; }
done
echo ""
echo "All stacks valid."
bake:validate:
desc: Print resolved docker-bake config (HCL parse check, no build)
dir: "{{.TASKFILE_DIR}}"
silent: true
cmds:
- GIT_COMMIT={{.GIT_COMMIT_HASH}} docker buildx bake --file {{.TASKFILE_DIR}}/docker-bake.hcl --print ci
# ── cell CLI binary ────────────────────────────────────────────────────
# macOS Sequoia (15.x) launch-constraint guard: after `go build`, the OS-
# recorded provenance for the freshly written file doesn't match the new
# binary's content → kernel SIGKILLs the process at exec time, before
# main() runs. Symptom: `cell --version` dies with `zsh: killed`, exit 137,
# no output. Strip xattrs + re-sign ad-hoc so the OS re-registers the
# binary's current state. No-op on Linux (uname guard) where neither
# `xattr` nor `codesign` exists.
cell:build:
desc: Build cell CLI binary → ./bin/cell
dir: "{{.TASKFILE_DIR}}"
deps: [swagger:generate]
silent: true
cmds:
- mkdir -p bin
- CGO_ENABLED=0 go build -ldflags "{{.CELL_LDFLAGS}}" -o ./bin/cell ./cmd/
- '[ "$(uname -s)" != "Darwin" ] || xattr -c ./bin/cell'
- '[ "$(uname -s)" != "Darwin" ] || codesign --force --sign - ./bin/cell'
cell:install:
aliases: [install]
desc: Build + copy ./bin/cell → ~/.local/bin/cell
dir: "{{.TASKFILE_DIR}}"
deps: [cell:build]
silent: true
cmds:
- mkdir -p ~/.local/bin
- cp ./bin/cell ~/.local/bin/cell
# Re-apply xattr/codesign at the destination — OS provenance is path-
# keyed, so the just-copied file needs its own re-registration even
# though the source was already cleaned.
- '[ "$(uname -s)" != "Darwin" ] || xattr -c ~/.local/bin/cell'
- '[ "$(uname -s)" != "Darwin" ] || codesign --force --sign - ~/.local/bin/cell'
- echo "Installed to ~/.local/bin/cell"
# ── image (aggregates over both variants) ──────────────────────────────
# When we deprecate the impure path, `rm -rf image:impure:*` and these
# aggregates degrade gracefully to pure-only.
image:build:
desc: Build both impure + pure images (host platform, no push)
cmds:
- task: image:impure:build
- task: image:pure:build
image:push:
desc: Push both impure + pure images to registry
cmds:
- task: image:impure:push
- task: image:pure:push
# ── image:impure (Dockerfile/bake — legacy, opt-in) ────────────────────
image:impure:build:
desc: Build all impure local images (base + ultimate)
cmds:
- task: image:impure:build:base
- task: image:impure:build:ultimate
image:impure:build:base:
aliases: [bake:local, image:build:base] # back-compat
desc: Build local impure base image (host platform only, no push)
silent: true
cmds:
- >-
USER_UID=$(id -u) USER_GID=$(id -g)
GIT_COMMIT={{.GIT_COMMIT_HASH}}
NIX_CACHE_IMAGE=public.ecr.aws/docker/library/debian:trixie-slim
PLATFORMS=""
docker buildx bake --file {{.TASKFILE_DIR}}/docker-bake.hcl --load local-core {{.CLI_ARGS}}
image:impure:build:ultimate:
aliases: [image:build:ultimate] # back-compat
desc: Build local impure ultimate image (FROM base, adds nix ultimate stack + KiCad)
silent: true
cmds:
- >-
USER_UID=$(id -u) USER_GID=$(id -g)
GIT_COMMIT={{.GIT_COMMIT_HASH}}
NIX_CACHE_IMAGE=public.ecr.aws/docker/library/debian:trixie-slim
PLATFORMS=""
docker buildx bake --file {{.TASKFILE_DIR}}/docker-bake.hcl --load local-ultimate {{.CLI_ARGS}}
image:impure:push:
aliases: [image:push:debian] # back-compat (pre-rename name)
desc: Build + push impure ci group to registry with OCI manifest (fixes skopeo zstd/v2s2 — DIMM-212)
silent: true
cmds:
# oci-mediatypes=true: publish with OCI manifest so zstd-compressed
# layers are legal. Without this, downstream skopeo trips:
# "unsupported docker v2s2 media type:
# application/vnd.docker.image.rootfs.diff.tar.zstd"
# because zstd is not a legal media type under Docker v2s2 (gzip only).
- >-
GIT_COMMIT={{.GIT_COMMIT_HASH}}
docker buildx bake --file {{.TASKFILE_DIR}}/docker-bake.hcl --push
--set '*.output=type=image,push=true,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true'
ci {{.CLI_ARGS}}
# ── image:pure (nix2container — default) ───────────────────────────────
image:pure:build:
desc: Build all pure local images (base + ultimate, load into Docker daemon)
cmds:
- task: image:pure:build:base
- task: image:pure:build:ultimate
image:pure:build:base:
desc: Build pure base image locally
cmds:
- task: image:pure:build:stack
vars: { STACK: base }
image:pure:build:ultimate:
desc: Build pure ultimate image locally
cmds:
- task: image:pure:build:stack
vars: { STACK: ultimate }
image:pure:build:stack:
aliases: [image:build:pure] # back-compat (cited in internal/runner/pure_build.go:381)
desc: "Build a pure image (single stack), load to Docker. STACK={base|ultimate|go|node|python|fullstack|electronics}"
dir: "{{.TASKFILE_DIR}}"
silent: true
vars:
STACK: '{{.STACK | default "base"}}'
# SUDO: empty in CI (Determinate Systems single-user nix on PATH) and on
# the host (Determinate or upstream single-user). Override SUDO=sudo for
# devcell containers where DEVCELL_NIX_DAEMON=false (pre-DIMM-210 builds).
SUDO: '{{.SUDO | default ""}}'
# NIX: defaults to "nix" on PATH. Override NIX=/full/path/to/nix when the
# binary isn't on PATH (uncommon — devcell, CI, and host all expose nix).
NIX: '{{.NIX | default "nix"}}'
NIX_ARCH:
sh: '[ "$(uname -m)" = "aarch64" ] && echo aarch64-linux || echo x86_64-linux'
env:
DEVCELL_BUILD_DATE: '{{.DEVCELL_BUILD_DATE | default "auto"}}'
DEVCELL_BUILD_REV: '{{.DEVCELL_BUILD_REV | default .GIT_COMMIT_HASH}}'
cmds:
- echo ">> Building devcell-{{.STACK}}-pure-image for {{.NIX_ARCH}}"
# --impure required so image.nix can read DEVCELL_BUILD_{DATE,REV} via builtins.getEnv.
- '{{.SUDO}} {{.NIX}} build --impure "path:{{.TASKFILE_DIR}}/nixhome#packages.{{.NIX_ARCH}}.devcell-{{.STACK}}-pure-image" --out-link "{{.TASKFILE_DIR}}/result-{{.STACK}}-pure"'
- echo ">> Loading into Docker daemon as devcell-user:{{.STACK}}-pure"
- '{{.SUDO}} {{.NIX}} run --impure "path:{{.TASKFILE_DIR}}/nixhome#packages.{{.NIX_ARCH}}.devcell-{{.STACK}}-pure-image.copyToDockerDaemon"'
- docker images devcell-user:{{.STACK}}-pure
image:pure:push:
desc: Build + push all pure images (base + ultimate)
cmds:
- task: image:pure:push:base
- task: image:pure:push:ultimate
image:pure:push:base:
desc: Build + push pure base image to registry
cmds:
- task: image:pure:push:stack
vars: { STACK: base }
image:pure:push:ultimate:
desc: Build + push pure ultimate image to registry
cmds:
- task: image:pure:push:stack
vars: { STACK: ultimate }
image:pure:push:stack:
desc: "Build + push a pure image (single stack). STACK= ARCH=auto|amd64|arm64 TAG= REGISTRY=… SUDO= NIX="
dir: "{{.TASKFILE_DIR}}"
silent: true
vars:
STACK: '{{.STACK | default "ultimate"}}'
REGISTRY: '{{.REGISTRY | default "ghcr.io/dimmkirr/devcell"}}'
TAG: '{{.TAG | default (printf "v0.0.0-%s-pure" .STACK)}}'
SUDO: '{{.SUDO | default ""}}' # see image:pure:build:stack notes
NIX: '{{.NIX | default "nix"}}'
NIX_ARCH:
sh: |
case "{{.ARCH | default ""}}" in
amd64|x86_64) echo x86_64-linux ;;
arm64|aarch64) echo aarch64-linux ;;
*) [ "$(uname -m)" = "aarch64" ] && echo aarch64-linux || echo x86_64-linux ;;
esac
env:
DEVCELL_BUILD_DATE: '{{.DEVCELL_BUILD_DATE | default "auto"}}'
DEVCELL_BUILD_REV: '{{.DEVCELL_BUILD_REV | default .GIT_COMMIT_HASH}}'
cmds:
# nix2container's `.copyTo` runs skopeo from the derivation closure with
# OCI media types end-to-end — zstd layers are legal, no v2s2 mismatch.
# Auth: docker/login-action writes ~/.docker/config.json; --authfile reuses it.
# --retry-times 5 + --retry-delay 5: GHCR occasionally returns 504 Gateway
# Timeout uploading large blobs (~hundreds of MB); without retries skopeo
# bails after a single failure and we lose all the upload progress on the
# remaining blobs. 5×5s = 25s max retry budget per blob is well below the
# GHA job timeout and covers the typical GHCR recovery window.
- >-
{{.SUDO}} {{.NIX}} run --impure
"path:{{.TASKFILE_DIR}}/nixhome#packages.{{.NIX_ARCH}}.devcell-{{.STACK}}-pure-image.copyTo"
--
--authfile "${DOCKER_CONFIG:-$HOME/.docker}/config.json"
--retry-times 5
--retry-delay 5s
"docker://{{.REGISTRY}}:{{.TAG}}"
# ── image: variant-agnostic utilities ──────────────────────────────────
image:mirror:
desc: "Copy a tag between registries (e.g. GHCR → ECR Public). SRC=<full-ref> DST=<full-ref>"
silent: true
cmds:
- docker buildx imagetools create -t "{{.DST}}" "{{.SRC}}"
image:manifest:
desc: "Stitch per-arch tags into multi-arch manifest. REPO= VERSION= SUFFIX=<-core|-ultimate|-base-pure|-ultimate-pure|''> ARCHES=amd64,arm64"
silent: true
vars:
ARCHES: '{{.ARCHES | default "amd64,arm64"}}'
cmds:
- |
srcs=""
for arch in $(echo "{{.ARCHES}}" | tr ',' ' '); do
srcs="$srcs {{.REPO}}:{{.VERSION}}-${arch}{{.SUFFIX}}"
done
docker buildx imagetools create \
-t "{{.REPO}}:{{.VERSION}}{{.SUFFIX}}" \
-t "{{.REPO}}:latest{{.SUFFIX}}" \
-t "{{.REPO}}:dev{{.SUFFIX}}" \
$srcs
# ── Tests ──────────────────────────────────────────────────────────────
test:unit:
desc: Run Go unit tests (cmd/, internal/) — no Docker, no nix
silent: true
dir: "{{.TASKFILE_DIR}}"
cmds:
- go test -timeout 120s ./cmd/... ./internal/... {{.CLI_ARGS}}
test:integration:
aliases: [test] # back-compat (cited in README)
desc: Run the full container integration test suite (./test/...)
silent: true
dir: "{{.TASKFILE_DIR}}"
cmds:
- go test -v -timeout 120s ./test/... {{.CLI_ARGS}}
test:vagrant:
desc: Run E2E install test in a clean Debian VM (QEMU). Requires vagrant + vagrant-qemu plugin.
dir: "{{.TASKFILE_DIR}}/test/vagrant"
cmds:
- vagrant up --provider=qemu
- defer: vagrant destroy -f
env:
CELL_VERSION: '{{.CELL_VERSION | default "0.0.0"}}'
# ── Web site ───────────────────────────────────────────────────────────
web:start:
desc: Start Astro dev server for the DevCell landing page
silent: true
dir: "{{.TASKFILE_DIR}}/web"
cmds:
- npm install
- npm run dev