Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Woodpecker's k8s backend runs every step through /bin/sh. crane:debug carries only /busybox/sh, so the fetch-courier step died at container init (pipeline 10). The release step now fetches the manifest by digest from zot, tries each blob as a gzip tar for usr/local/bin/courier and stops at the one that has it — busybox wget, tar and gzip, which alpine/git has. Proven in that image before this push.
111 lines
5.0 KiB
YAML
111 lines
5.0 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:
|
|
# 100, not 1: the release step renders `git log <serving>..<this>` 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. `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
|
|
- |
|
|
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
|