Skip to content

Mise tasks

Everything here is built, tested and linted through Mise ⧉ monorepo tasks.

mise run //croesus:build        # one task in one project
mise run '//...:lint'           # that task in every project defining it
mise tasks --all                # everything available

Run a bare task name from inside a project directory, or address any project from anywhere with //<project>:<task>. Quote the wildcard, or the shell globs it.

Rules: build rules. The tool itself, and the mise/tasks/ trap: Mise.

Where a task comes from

Piece Holds
mise/includes/{go,python}.toml the task definitions, once per language family
mise/includes/{go,python}-service-image.toml the container-image tasks
mise/scripts/*.bash the logic every task body calls
<project>/mise.toml the includes, and the project's identity
root mise.toml tool pins, [env], and config_roots

Shared configuration lives in the root mise.toml because an [env] block inside an include is a parse error: Mise reads it as a task named env.

Go projects

Via mise/includes/go.toml.

Task Does
proto Generate Go protobuf sources. A fast no-op where there is nothing to generate
build Generate protobuf, then build every cmd/ binary natively and for amd64
install Copy the amd64 binaries into infra/build_artifacts/bin/amd64/
lint gofmt -s -l, go vet and golangci-lint, against the repository .golangci.yml. All three run, and every finding is reported
format gofmt -s -w .
test-fast go test -short -race
test-integration testsintegration/ only, caching disabled
test-all Both test tasks
clean Remove generated protobuf files and build artefacts
  • Test tasks do not depend on build. go test compiles what it needs, and the dependency would double the compile under --jobs.
  • On amd64 Linux, build hard-links the native binaries into build/amd64/ instead of compiling twice. Hard links, not symlinks (the Make rules do the same): same tree, same filesystem, so the link always succeeds and is a real directory entry.
  • install handles amd64 only. Nothing wrote or read bin/native/. It does not clear the directory first: a --jobs run has several projects writing there at once, and binary names are distinct across the repository.
  • build and install stay separate. install aggregates each project's output into one flat directory keyed by binary name. That is the shape Ansible and release-infra-deploy.yml resolve against.
  • An unstamped binary reports unknown, not empty. go-env.bash falls back when git rev-parse is unavailable, which is every container build.

Python projects

Via mise/includes/python.toml.

Task Does
lint ruff format --check, ruff check and ty check, from the repository root
format ruff format and ruff check --fix
test-fast pytest over the project's tests/. Skips cleanly where there is none
test-all test-fast. There is no Python integration suite yet
build Build wheels for native and amd64 Linux. Nothing without a [build-system]
install Copy the wheels into infra/build_artifacts/wheels/amd64/

install is local. Publishing is a separate task

Neither build nor install touches a registry. Publishing is always its own named task, normally run by CI: push-image for container images, and nothing yet for binaries and wheels, which is tracked debt. See BUILD-8.

build and install serve the Python services Ansible deploys onto VMs: the copy_python_wheels role installs the gateway's wheel. Python service images build through sync-venv instead.

Container images

Via mise/includes/{go,python}-service-image.toml.

Task Does
build-image Build this service's image from the shared Dockerfile for its family
push-image Build, then push to the service's repository. Skips a pushed commit
sync-venv (Python) Sync the venv the image runs from. Called by the Dockerfile

A service declares only DOCKER_PROJECT_DIR/DOCKER_IMAGE_NAME/DOCKER_BINARY (Go) or DOCKER_PACKAGE/DOCKER_IMAGE_NAME (Python). mise/scripts/docker-env.bash derives the region, repository, Dockerfile, tag, version stamp and build arguments, so mise run '//...:push-image' needs no per-service parameters. The caller supplies DOCKER_GCP_PROJECT.

Base images and pins

Under //infra/docker:

Task Does
repin-base-images Rewrite our base-image digests in every file naming them
open-base-image-repin-pr Repin, then open the pull request
check-image-pins Static: every copy of a digest agrees, Python base tag matches .python-version
check-pinned-tags Pull each pinned image, confirm the tag beside it is honest
//infra/docker/go-service:check-base-image Confirm the pinned builder matches mise.lock

check-image-pins runs in pre-commit. check-pinned-tags needs a registry, so it runs in check-image-pins.yml.

GitHub repositories

Under //infra/terraform/github. See GitHub repositories.

Task Does
check-inventory Validate infra/inventory/repositories.yaml and responsible against people/
lint-terraform Format-check, validate and tflint the unit and its module, offline
lint check-inventory, ruff on the check script, and lint-terraform
format ruff and terraform fmt, the mutating twin of lint
plan Compare the repositories on GitHub with the inventory, through neph
apply Update GitHub to match the inventory, through neph. Prompts first

lint-terraform and format call mise/scripts/terraform-lint.bash and terraform-format.bash. Both take the unit from the working directory and the environment from LYC_DEPLOY_ENV, so any Terragrunt unit can adopt them. plan and apply authenticate through gh auth login, or as a GitHub App through GITHUB_APP_*.

Platform state bucket

Under //infra/terraform/platform/state_bucket. One unit for every platform project. DO name the environment: LYC_DEPLOY_ENV=platform-staging mise run //infra/terraform/platform/state_bucket:apply. See bootstrapping platform images.

Task Does
lint-terraform, lint Format-check, validate and tflint the unit and its module, offline
format Format the unit and its module
bootstrap-backend terragrunt backend bootstrap. The bare bucket, in the env file's location
plan Compare the bucket with the reference settings
apply bootstrap-backend, then adopt the bucket and set the rest

Staging service images

Also under //infra/docker:

Task Does
push-staging-images Build and push every staging service image, or the project dirs given, then repin
repin-staging-images Rewrite the digest pins in staging.env from the recorded digests
pin-staging-images Rewrite the digest pins in staging.env to the registry's images for one commit
list-staging-images List the newest commits' images and every pinned image, and mark the pinned ones

A pin whose image was not pushed does not move. pin-staging-images <commit> <service>... moves only the named pins, by directory or image name. It fails instead if one has no image for that commit. See Deploying staging for the promotion steps.

Infrastructure and repository tasks

Task Does
//infra/ansible:env Install Ansible collections
//infra/ansible:lint Lint, failing on warnings as CI does
//infra/ansible:format Format and auto-fix
//infra/k8s:build Render an overlay to stdout (--env, defaults to devel)
//infra/k8s:apply / :delete Render and apply or delete. --env required
//infra/neph:deploy-staging Apply the staging service units with neph terraform
//infra/neph:move-state Move a unit's state to the backend it names now, with neph
//people:list-emails List addresses, optionally filtered by group
//people:import-keys Import and ultimately trust every GPG key
//mise:lint shellcheck over the shared bash
//docs/wiki:build Build this wiki into docs/wiki/site/. Needs Graphviz's dot
//docs/wiki:serve Serve this wiki with live reload on localhost:8000
//docs/wiki:deploy Upload site/ to Cloudflare Pages. --branch required

//infra/k8s:build takes a default environment so a '//...:build' sweep can include it. apply and delete do not: an unnamed environment must never be applied.