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]>
93 lines
2.6 KiB
YAML
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
|