Files
images/.gitea/workflows/build.yaml
T
rmcguireandClaude Opus 5 1878df96ac
Lint / lint (push) Failing after 34s
Build Images / ${{ fromJSON(needs.select.outputs.images) }} (push) Canceled after 7m37s
Build Images / Select images (push) Successful in 17s
Initial commit: image registry structure and node-agent
Set up this repo as a base image registry. Each image is self-contained in
its own directory under images/ (Dockerfile + README.md + optional test.sh);
CI discovers them by glob, so adding an image needs no workflow changes.
template/ is the skeleton to copy.

The Makefile is the single entry point for both local work and CI, so a green
`make all` locally means a green pipeline.

Workflows:
  * lint.yaml  — layout check, hadolint, shellcheck
  * build.yaml — diffs against the base commit to build only the images that
    changed, smoke-tests each one before anything is published, then pushes.
    Releases are per-image tags (<image>/vX.Y.Z); main publishes :edge.

First image, node-agent: node:22-alpine plus a GNU userland (Alpine ships
BusyBox, whose applets take narrower flags than scripts and models expect),
helm, kubectl, jq, yq, bind-tools, curl, git, ripgrep, fd and friends.
Nothing is version-pinned — rebuilding is how upstream updates land, and the
published tag is what pins things for consumers.

Its smoke test asserts the deployment contract as well as tool presence: the
image must work non-root, with a read-only root filesystem and all
capabilities dropped, which is how ToolHive runs it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-09 11:40:29 -04:00

93 lines
2.6 KiB
YAML

name: Build Images
# Only images whose files changed get built. A release is cut by pushing a tag
# named <image>/vX.Y.Z, which publishes that one image.
on:
push:
branches: [main]
tags: ["*/v*"]
pull_request:
branches: [main]
workflow_dispatch:
inputs:
image:
description: Image to build, or "all"
default: all
required: true
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: true
env:
REGISTRY: gitea.libretechconsulting.com
NAMESPACE: rmcguire
DOCKER_USER: rmcguire
jobs:
select:
name: Select images
runs-on: ubuntu-latest
outputs:
images: ${{ steps.select.outputs.images }}
any: ${{ steps.select.outputs.any }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # need history to diff against the base commit
- id: select
run: ./hack/select-images.sh >> "$GITHUB_OUTPUT"
env:
DISPATCH_IMAGE: ${{ github.event.inputs.image }}
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
build:
name: ${{ matrix.image }}
needs: select
if: needs.select.outputs.any == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
image: ${{ fromJSON(needs.select.outputs.images) }}
steps:
- uses: actions/checkout@v7
- id: meta
run: ./hack/docker-tags.sh '${{ matrix.image }}' >> "$GITHUB_OUTPUT"
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
- uses: docker/setup-buildx-action@v4
# Loaded rather than pushed, so the smoke test runs before anything is
# published. provenance is off because Gitea's registry rejects buildkit
# attestation manifests.
- name: Build
uses: docker/build-push-action@v7
with:
context: images/${{ matrix.image }}
load: true
tags: ${{ steps.meta.outputs.tags }}
provenance: false
build-args: |
VERSION=${{ steps.meta.outputs.version }}
REVISION=${{ github.sha }}
CREATED=${{ steps.meta.outputs.created }}
- name: Smoke test
run: make test IMAGE='${{ matrix.image }}' REF='${{ steps.meta.outputs.primary }}'
- name: Log in to ${{ env.REGISTRY }}
if: steps.meta.outputs.push == 'true'
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ env.DOCKER_USER }}
password: ${{ secrets.API_TOKEN }}
- name: Push
if: steps.meta.outputs.push == 'true'
run: printf '%s\n' '${{ steps.meta.outputs.tags }}' | xargs -r -n1 -t docker push