Files
vibe-kanban/.gitea/workflows/container.yml
rob thijssen ccff6fc539
All checks were successful
container / vibe-kanban-remote (push) Successful in 4m31s
ci: build and publish the remote-server image from this repo
The build lived in lair/containers, which is for third-party images built
from someone else's source. We own this fork now, so it belongs next to
the code it builds: a source change and the image it produces become one
commit rather than two repos that can drift.

Differences from the lair/containers job it replaces:

- Builds the checked-out tree instead of resolving a tag from the mirror
  and building `<mirror-url>#<tag>`. There is no upstream release to track
  any more; what is on main is what ships.
- Publishes an immutable ${version}-g${sha} tag alongside :latest, and
  prints the pin. A floating tag decides which build you are running based
  on whenever something last pulled, which is not a deployment strategy.
- Drops the `skopeo inspect` already-published guard. skopeo is not
  installed on the metal runner, so that check silently failed and always
  fell through to a build -- an accident, not a policy. Building every
  push to main is the intent here anyway.
- Adds a guard that greps the built bundle for the sunset page and refuses
  to publish if it reappears. This fork exists to remove it; a bad merge
  should fail the build, not ship a dead product. Verified against the
  currently-deployed image, where it correctly fires.

concurrency keeps two builds from racing over :latest.
2026-07-21 15:46:49 +03:00

111 lines
4.2 KiB
YAML

name: container
# Build the self-hosted remote-server image from THIS repo and publish it to the
# Gitea registry as git.lair.cafe/lair/vibe-kanban-remote.
#
# This build used to live in lair/containers, which is for *third-party* images
# built from someone else's source. We own this fork now, so the build belongs
# next to the code it builds — a source change and its image are one commit.
#
# vibe-kanban ships its own Dockerfile (crates/remote/Dockerfile, context = repo
# root), so there is no vendored Containerfile here. Nothing in this workflow
# reaches out to GitHub: upstream is sunset and may disappear, and a build that
# asks github.com what to build would disappear with it.
on:
push:
branches: [main]
paths:
- "crates/**"
- "packages/**"
- "shared/**"
- "assets/**"
- "patches/**"
- "Cargo.toml"
- "Cargo.lock"
- "package.json"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "rust-toolchain.toml"
- ".gitea/workflows/container.yml"
workflow_dispatch:
# Never let two builds race: they would fight over the :latest tag and the
# loser's digest would win at random.
concurrency:
group: container
cancel-in-progress: false
jobs:
vibe-kanban-remote:
runs-on:
- metal
- podman
# The Rust workspace builds in release mode from a cold cache on a fresh
# runner; the default job timeout is not enough headroom.
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- name: derive image tags
id: meta
run: |
set -euo pipefail
version=$(jq -r .version package.json)
short=$(git rev-parse --short HEAD)
# Immutable tag first. :latest is a convenience for humans, never a
# deployment target -- a floating tag decides which build you are
# running based on whenever something last pulled.
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "immutable=${version}-g${short}" >> "$GITHUB_OUTPUT"
- name: login to registry
run: podman login -u ${{ gitea.actor }} -p ${{ secrets.REGISTRY_TOKEN }} git.lair.cafe
- name: build
env:
IMMUTABLE: ${{ steps.meta.outputs.immutable }}
run: |
set -euo pipefail
IMAGE=git.lair.cafe/lair/vibe-kanban-remote
# FEATURES is deliberately unset: the Dockerfile strips the private
# billing crate only when it is empty (the self-host path), and we have
# no access to BloopAI/vibe-kanban-private.
# VITE_RELAY_API_BASE_URL is baked into the SPA at build time; empty
# disables the relay/tunnel features, which we do not deploy. Changing
# it requires a rebuild, not a restart.
podman build --pull=newer \
-f crates/remote/Dockerfile \
--build-arg VITE_RELAY_API_BASE_URL= \
-t "${IMAGE}:${IMMUTABLE}" \
-t "${IMAGE}:latest" \
.
- name: verify the sunset really is gone
env:
IMMUTABLE: ${{ steps.meta.outputs.immutable }}
run: |
set -euo pipefail
IMAGE=git.lair.cafe/lair/vibe-kanban-remote
# This fork exists because upstream replaced the board with an
# export-only page. If a merge or a bad rebase ever reinstates it, fail
# here rather than publish an image that greets us with a dead product.
if podman run --rm --entrypoint sh "${IMAGE}:${IMMUTABLE}" -c \
'grep -rlq "Project functionality has been retired" /srv/static' 2>/dev/null; then
echo "ERROR: the sunset page is present in the built bundle."
echo "The revert of #3387 has been lost -- refusing to publish."
exit 1
fi
echo "ok: no sunset page in the bundle"
- name: push
env:
IMMUTABLE: ${{ steps.meta.outputs.immutable }}
run: |
set -euo pipefail
IMAGE=git.lair.cafe/lair/vibe-kanban-remote
podman push "${IMAGE}:${IMMUTABLE}"
podman push "${IMAGE}:latest"
echo "published ${IMAGE}:${IMMUTABLE} (and :latest)"
echo
echo "pin the quadlet to the immutable tag:"
echo " Image=${IMAGE}:${IMMUTABLE}"