Skip to content

CI/CD

paper-board CI runs through reusable workflows hosted in paper-board/.github. Service repos consume them via uses: — they never inline go test or golangci-lint directly.

Workflow fileTriggered byDoes
go-ci.ymlpush / pull_request in service reposlint, unit, integration (testcontainers), coverage gate, mocks-verify, sqlc-verify, arch-check
docker-publish.ymlGitHub Release publishedbuildx multi-arch build + GHCR push; cosign signing (Phase 5)
helm-publish.ymlGitHub Release publishedhelm lint + package + push OCI to ghcr.io/paper-board/helm/<svc>
release-please.ymlpush to mainparse Conventional Commits → open release PR with CHANGELOG + tag bump
standards-sync.ymlnightly 04:00 UTCdiff service-template vs standards docs; open issue on mismatch
docs-deploy.ymlpush to main (paths: docs/**) + repository_dispatchaggregate + Astro build + Cloudflare Pages deploy

Each service repo carries only a thin wrapper that delegates to the reusable workflow:

# from paper-board/agents/.github/workflows/ci.yml:1-10
name: ci
on: [push, pull_request]
jobs:
ci:
uses: paper-board/.github/.github/workflows/go-ci.yml@main
with:
service: agents
coverage_threshold: "70"
secrets: inherit

Service repos MUST NOT duplicate lint or test steps outside this wrapper.

All commits to any paper-board repo MUST follow Conventional Commits. commitlint runs as a pre-commit hook (installed by make hooks). CI enforces it on PR title via go-ci.yml.

TypeTriggers version bumpExample
fix:patchfix(sessions): handle EOF on SSE flush
feat:minorfeat(agents): add agent clone endpoint
BREAKINGmajor (footer token)feat!: rename x-org-id header
chore:nonechore(deps): bump sdk to v0.2.0
docs:nonedocs(agents): add API reference
refactor:nonerefactor(store): extract WithTx helper

Footer token for breaking changes: BREAKING CHANGE: <description> in the commit body.

sequenceDiagram
autonumber
participant Dev as Developer
participant GH as GitHub main
participant RP as release-please
participant DR as Docker registry (GHCR)
participant HC as Helm OCI (GHCR)
Dev->>GH: squash-merge PR (Conventional Commit title)
GH->>RP: push event
RP->>GH: open/update release PR (CHANGELOG + version bump)
Dev->>GH: squash-merge release PR
GH->>GH: create git tag vX.Y.Z + GitHub Release
GH->>DR: docker-publish.yml — build + push 3 tags
GH->>HC: helm-publish.yml — lint + push chart OCI

release-please reads commit history since the last tag, computes the next SemVer, and writes CHANGELOG.md. Squash-merging the release PR publishes the GitHub Release, which triggers image and chart publishing in parallel.

Every service image is pushed with three tags on release:

TagSourceUse
vX.Y.Zgit describe --tags --exact-matchprod (immutable)
sha-<7-char>first 7 chars of HEADstaging / preview
latestmain branch HEADdev only

Naming pattern: ghcr.io/paper-board/<svc>-<binary>:<tag>.

Examples:

ghcr.io/paper-board/agents-server:v0.3.0
ghcr.io/paper-board/agents-server:sha-7c1d4a2
ghcr.io/paper-board/agents-migrator:v0.3.0

latest MUST NOT appear in any committed deployment manifest. Helm appVersion pins the exact git tag at release time; chart version is an independent SemVer bumped on chart edits.

LayerMechanismCache key
Go modulesactions/setup-go@v5 with cache: truehash of go.sum
Go buildactions/cache@v4 on GOCACHEOS + Go version + go.sum hash
Docker layerBuildKit registry cache (--cache-from/--cache-to)branch-scoped
SecretScopePurpose
GHCR_TOKENorg, all repospush to ghcr.io/paper-board
CLOUDFLARE_API_TOKENorg, .githubCloudflare Pages / Edit
CLOUDFLARE_ACCOUNT_IDorg, .githubCloudflare account scoping for Wrangler
DOCS_DISPATCH_PATorg, all reposrepository_dispatch:write on paper-board/.github
COSIGN_KEYorg, plannedimage signing (Phase 5)
ANTHROPIC_API_KEY_TESTorg, optionalagents E2E layer

Proto: buf breaking runs in CI on PRs touching proto/<svc>/v*/*.proto.

REST: URL-versioned. /v1 and /v2 coexist. Removing /v1 requires:

  1. Deprecation: <RFC date> header on /v1 responses for ≥ 90 days.
  2. Sunset: <removal date> header pointing at the removal date.
  3. Migration note in the service’s CHANGELOG.md.
  • Commit title follows Conventional Commits.
  • No inline go test / golangci-lint added to the service CI wrapper.
  • latest tag not referenced in Helm values.yaml or kustomize overlays.
  • Breaking REST change includes Deprecation + Sunset headers + CHANGELOG note.