# hush CI/CD. Origin must be Gitea (git.threesix.ai) — that remote carries the # webhook. Pushing to the GitHub mirror does not deploy anything. # # push to main → test → Kaniko amd64 build → Zot → kubectl set image on `projects` clone: git: image: woodpeckerci/plugin-git settings: # 100, not 1: the release step renders `git log ..` for the # release channel, and a depth-1 clone cannot name the commit it replaced. depth: 100 steps: test: # 1.26, not the 1.25 in the template: go-chassis declares `go 1.26.0` and an # older toolchain refuses to build it. image: golang:1.26-alpine environment: # Hermetic, and deliberately so. go-chassis is a PRIVATE module and this # container has no git credential, so a build that reached for the network # would fail here — the vendored tree is what makes CI possible at all. # GOPROXY=off turns "silently fetched from a proxy" into a hard error. GOFLAGS: -mod=vendor GOPROXY: "off" commands: - go vet ./... - go test ./... # gofmt as a gate, not a suggestion. -l lists offenders; the test fails if # the list is non-empty. vendor/ is excluded because it is not ours. - test -z "$(gofmt -l ./cmd ./internal)" || { gofmt -l ./cmd ./internal; echo "gofmt"; exit 1; } when: branch: main event: push build: image: woodpeckerci/plugin-kaniko settings: registry: registry.threesix.ai repo: hush/api tags: - latest # SHA-tagged as well as latest: `latest` cannot pin a rollback. - ${CI_COMMIT_SHA:0:8} context: . dockerfile: Dockerfile cache: true skip_tls_verify: true # internal Zot registry, self-signed cert when: branch: main event: push deploy: image: bitnami/kubectl:latest commands: # What is serving NOW, before it is replaced: the left edge of the release # notes and the `prev_sha` on the record. A first deploy leaves it empty. - prev="$(kubectl -n projects get deployment hush -o jsonpath='{.spec.template.spec.containers[0].image}' 2>/dev/null || true)"; prev="$${prev##*:}"; echo "$${prev%%@*}" > .prev-sha - kubectl set image deployment/hush hushd=registry.threesix.ai/hush/api:${CI_COMMIT_SHA:0:8} -n projects - kubectl rollout status deployment/hush -n projects --timeout=120s # Prove the rolled pod actually serves, not merely that it became Ready. # A pod can pass readiness and still be the wrong image if `set image` # silently matched nothing. - kubectl -n projects get deployment hush -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}' when: branch: main event: push # The release channel. Two steps because courier's image is distroless — the # binary is exported out of it, then run from an image that has sh and git. # `courier deployed` appends a version to the document releases/hush.prod # (the changelog, `git log ..`) and posts one message on the # `deploys` topic, as the `releases` agent, whose credential can send and do # nothing else. The same call every other substrate makes — see # orchard9-k3sf scripts/lib/release.sh; this is the Woodpecker copy. fetch-courier: image: gcr.io/go-containerregistry/crane:debug commands: - crane export registry.threesix.ai/courier/courierd:3d490785@sha256:9d1ce76216a93f3d3808fc208179aaa2eb6c3eda20332095a28c3893b2ff5bdf - | tar -xf - usr/local/bin/courier - mv usr/local/bin/courier ./courier && rmdir -p usr/local/bin 2>/dev/null || true when: branch: main event: push release: image: alpine/git environment: COURIER_URL: https://courier.orchard9.ai COURIER_TOKEN: from_secret: courier_releases_token commands: - | set -- hush prod ${CI_COMMIT_SHA} \ -image registry.threesix.ai/hush/api:${CI_COMMIT_SHA:0:8} -substrate k3s \ -by "woodpecker pipeline ${CI_PIPELINE_NUMBER}" -link "${CI_PIPELINE_URL}" prev="$$(cat .prev-sha 2>/dev/null || true)" if [ -n "$$prev" ] && [ "$$prev" != "${CI_COMMIT_SHA:0:8}" ]; then set -- "$$@" -prev "$$prev" -notes-from-git -repo . elif [ -n "$$prev" ]; then set -- "$$@" -prev "$$prev" -notes "re-roll of ${CI_COMMIT_SHA:0:8}: the same build, rolled again" else set -- "$$@" -notes "first recorded release of hush to prod" fi ./courier deployed "$$@" when: branch: main event: push