i used to write CI pipelines in yaml. eight hundred lines of indented despair. nested anchors. shell snippets escaped six times. a job called 'maybe-deploy-if-tuesday'. then one day, on a long flight, i deleted all of it.
the manifesto, in one breath
"yaml is a configuration format. it is not, despite appearances, a programming language. when you find yourself programming in yaml you are not in the configuration business anymore. you are in the suffering business."
the entire ci, in 80 lines
#!/usr/bin/env bash
set -euo pipefail
stage() { echo; echo "::: $1"; }
stage "lint" && shellcheck ./**/*.sh && ruff check .
stage "test" && go test ./... && pytest -q
stage "build" && make release
stage "sign" && cosign sign-blob --yes dist/*.tar.gz
stage "publish" && gh release create "v$(cat VERSION)" dist/*
# (80 lines once you handle caching, retries, and matrix builds)
of course it's not 80 lines anymore. it's 142. it does parallel matrix runs, caches between stages with a local mtime check, retries with backoff, and posts a summary to slack. it's still bash. it's still legible.
what you give up
the cloud provider's marketplace. nice green checkmarks in PRs (we have a tiny pr-status binary that does this, also 40 lines). free spinners. the ability to say 'yeah we use circleci'. all worth it. all worth it.