Files
vantage-docs/docs/operations/ci-cd.md
T
2026-07-28 16:18:50 +01:00

4.1 KiB

id, title, sidebar_label
id title sidebar_label
ci-cd CI/CD CI/CD

Two Gitea Actions workflows: one releases agents, one builds images.

Agent releases

Triggered by an agent/v* tag.

git tag agent/v1.0.0 && git push origin agent/v1.0.0

Builds linux/amd64, linux/arm64 and windows/amd64, writes checksums.txt and creates a Gitea release. A second job on Windows packages the WiX MSI.

The install and update scripts read the newest agent/v* release from the Gitea API, so tagging is what makes a new agent available to every install.

Image builds

Triggered on every push to main. Builds and pushes seven images: server, web, site, sitesvc, admin, adminsite and docsite.

:::warning Despite the name, this workflow does not deploy There is no SSH step. Rolling images out is a manual step on the host:

cd /opt/vantage && \
  docker compose -f docker-compose.yml -f docker-compose.site.yml pull && \
  docker compose -f docker-compose.yml -f docker-compose.site.yml up -d --remove-orphans

:::

Each image rebuilds only when its own inputs change

A git diff against the previous head decides. That is why the checkout uses fetch-depth: 0 — a shallow clone has one commit and nothing to diff against.

Image Rebuilds when
server server/, shared/, proto/, go.work
admin admin/, shared/, go.work
sitesvc sitesvc/, shared/, go.work
web · site · adminsite · docsite their own directory only

shared/ fans out to all three Go images because each of their Dockerfiles copies it from a root context. If a fourth service ever imports shared/, it must be added to that list or it will ship stale.

Everything rebuilds when there is no trustworthy base commit to diff against: a manual workflow_dispatch, a new branch, or a force-push whose old head is gone. Changing the workflow file itself also rebuilds everything, since a build argument is baked into each image.

The gap: repository variables

:::danger Editing a repository variable pushes no commit, so nothing rebuilds Values like ADMIN_API_URL, HQ_URL, ADMIN_ENV, PADDLE_ENV, PADDLE_CLIENT_TOKEN, DOCS_URL and DOCS_BASE_URL are baked into images at build time. After editing one, run the workflow manually — that is what workflow_dispatch is for.

The symptom is a frontend that keeps using the old value with no error anywhere, which is a long afternoon if you do not know about this. :::

The same applies to base images: a service nobody touches stops being rebuilt on newer base layers. A periodic manual run covers it.

Secrets and variables

Name Type Purpose
RELEASE_TOKEN Secret Gitea API token, write:release
REGISTRY_USER / REGISTRY_PASSWORD Secret Registry push credentials
PADDLE_API_KEY Secret Read by admin at runtime
PADDLE_WEBHOOK_SECRET Secret Webhook signature verification
GITEA_HOST / DOCKER_HOST Variable Hosts used in tags and URLs
HQ_URL Variable Baked into web; empty on self-hosted
SITE_API_URL / SITE_CONTACT_EMAIL Variable Baked into site
ADMIN_API_URL Variable Baked into adminsite and site
ADMIN_ENV Variable Environment badge in the portal
PADDLE_ENV Variable Baked into adminsite, read by admin. Must match on both sides
PADDLE_CLIENT_TOKEN Variable Browser Paddle token for checkout
DOCS_URL / DOCS_BASE_URL Variable Baked into docsite

Anything marked "browser-reachable" must be an origin a browser can actually resolve — not an internal service name. Get it wrong and every request fails at runtime with a not-connected panel rather than at build time.

The documentation site

docsite/ builds to static files and is served by nginx under /docs on the marketing host, routed by its own proxy location.

DOCS_BASE_URL has to agree with three things at once: that proxy location, the directory the runtime image serves from, and the value baked into the build. When they disagree the page loads and every stylesheet and script 404s.