All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Pipeline 11 recorded nothing: the clone plugin ran `git fetch --depth=1 --filter=tree:0` with depth: 100 set, so `git log <serving>..<this>` could not name the commit it replaced. The repo is anonymously readable on Gitea, so the release step deepens by 100 itself before it renders the notes. The clone setting goes back to what it was.
115 lines
5.3 KiB
YAML
115 lines
5.3 KiB
YAML
# 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:
|
|
depth: 1
|
|
|
|
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. `courier deployed` appends a version to the document
|
|
# releases/hush.prod (the changelog, `git log <serving>..<this>`) 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.
|
|
#
|
|
# The CLI comes out of courier's own image, pinned by digest, pulled with the
|
|
# bare OCI protocol (zot allows anonymous pulls): the image is distroless and
|
|
# the k8s backend runs steps through /bin/sh, so neither the image itself nor
|
|
# crane:debug (/busybox/sh only) can be the step — measured on pipeline 10.
|
|
release:
|
|
image: alpine/git
|
|
environment:
|
|
COURIER_URL: https://courier.orchard9.ai
|
|
COURIER_TOKEN:
|
|
from_secret: courier_releases_token
|
|
commands:
|
|
- |
|
|
R=https://registry.threesix.ai/v2/courier/courierd
|
|
D=sha256:9d1ce76216a93f3d3808fc208179aaa2eb6c3eda20332095a28c3893b2ff5bdf # courierd:3d490785
|
|
wget -qO manifest.json --header='Accept: application/vnd.oci.image.manifest.v1+json,application/vnd.docker.distribution.manifest.v2+json' "$$R/manifests/$$D"
|
|
for l in $$(grep -o '"digest":"sha256:[a-f0-9]*"' manifest.json | cut -d'"' -f4); do
|
|
wget -qO- "$$R/blobs/$$l" | tar -xzf - usr/local/bin/courier 2>/dev/null && break
|
|
done
|
|
test -x usr/local/bin/courier || { echo "courier CLI not found in any layer of courierd@$$D"; exit 1; }
|
|
mv usr/local/bin/courier ./courier; rm -rf usr manifest.json
|
|
# The clone is `--depth=1 --filter=tree:0` whatever `depth:` says (measured on
|
|
# pipeline 11: the plugin fetched depth 1 with depth: 100 set), and the notes are
|
|
# `git log <serving>..<this>`, which needs the commit it replaced. The repo is
|
|
# anonymously readable on Gitea, so deepen it here; 100 covers any gap between
|
|
# two deploys, and the fallbacks below say so if it does not.
|
|
- git fetch -q --deepen=100 origin 2>/dev/null || git fetch -q --unshallow origin 2>/dev/null || true
|
|
- |
|
|
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
|