Compare commits

...
Author SHA1 Message Date
butler-git-steward 3ab6169ed4 Use the governed CI toolchain
Build and Push Container / build-and-push (pull_request) Successful in 43s
2026-09-14 00:40:35 +00:00
wayfinderak da154648ef Merge pull request 'Scope delivery checks and isolate build jobs' (#1) from feat/delivery-streamlining-20260911 into master
Build and Push Container / build-and-push (push) Successful in 40s
2026-09-11 09:46:04 +00:00
wayfinderak 9c981036d1 Resolve upstream Actions explicitly and check out the exact event revision
Build and Push Container / build-and-push (pull_request) Successful in 44s
2026-09-11 09:14:35 +00:00
wayfinderak bd5e58d8f4 feat(delivery): publish immutable source images and declare release
Build and Push Container / build-and-push (pull_request) Failing after 3s
2026-09-11 08:53:23 +00:00
wayfinderak 8c73f3b464 Cancel superseded pull request validation without cancelling releases 2026-09-11 08:47:06 +00:00
wayfinderak dc5429b697 Scope documentation CI and isolate delivery job resources 2026-09-11 08:10:35 +00:00
4 changed files with 91 additions and 45 deletions
+5
View File
@@ -0,0 +1,5 @@
# Service release contract
Butler resolves this repository's protected source revision to verified immutable images. The platform updates only image references in the existing production Compose file and restarts only the already running application services. It preserves current environment, storage, routes, and provider configuration. It retains previous application images and restores them if readiness fails.
Migration and maintenance images are pinned when declared, but this release operation does not run database migrations or maintenance jobs. A release requiring a schema change needs the corresponding explicit platform migration first. No homelab image-pin commit is required for an ordinary compatible application release.
+12
View File
@@ -0,0 +1,12 @@
{
"version": 1,
"deployment": "goff-release",
"environment": "production",
"images": {
"goff_release_goff_image": {
"name": "goff",
"tag": "sha-{revision}"
}
},
"revision_variable": "goff_release_revision"
}
+35 -45
View File
@@ -3,15 +3,22 @@ name: Build and Push Container
on:
push:
branches:
- master
- main
- master
tags:
- v*
workflow_dispatch:
- v*
workflow_dispatch: null
pull_request:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number
|| github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
build-and-push:
runs-on: ubuntu-latest
runs-on: butler-ci
env:
REGISTRY: gitea.wayfinderak.com
IMAGE_NAME: gitea.wayfinderak.com/wayfinderak/goff
@@ -19,52 +26,32 @@ jobs:
options: --dns 172.16.30.10
steps:
- name: Checkout
uses: actions/checkout@v4
uses: https://github.com/actions/checkout@v4
- name: Install Go and Docker CLI if needed
- name: Select relevant delivery work
id: delivery
env:
DELIVERY_EVENT: ${{ github.event_name }}
DELIVERY_REF: ${{ github.ref }}
DELIVERY_SHA: ${{ github.sha }}
DELIVERY_BASE: ${{ github.event.pull_request.base.sha || github.event.before }}
run: |
cd .
bash scripts/ci-select.sh
- name: Verify governed runner toolchain
if: ${{ steps.delivery.outputs.run == 'true' }}
shell: bash
run: |
set -euo pipefail
need_apt=0
need_apk=0
if ! command -v go >/dev/null 2>&1 || ! command -v docker >/dev/null 2>&1; then
if command -v apt-get >/dev/null 2>&1; then
need_apt=1
elif command -v apk >/dev/null 2>&1; then
need_apk=1
else
echo "No supported package manager found" >&2
exit 1
fi
fi
if [ "$need_apt" -eq 1 ]; then
apt-get update
if ! command -v go >/dev/null 2>&1; then
apt-get install -y golang-go
fi
if ! command -v docker >/dev/null 2>&1; then
apt-get install -y docker.io curl dnsutils iputils-ping
fi
fi
if [ "$need_apk" -eq 1 ]; then
if ! command -v go >/dev/null 2>&1; then
apk add --no-cache go
fi
if ! command -v docker >/dev/null 2>&1; then
apk add --no-cache docker-cli curl bind-tools iputils
fi
fi
go version
docker version
test "$(go version)" = 'go version go1.25.13 linux/amd64'
docker version >/dev/null
- name: Run tests
if: ${{ steps.delivery.outputs.run == 'true' }}
run: go test ./...
- name: Log in to Gitea Container Registry
if: ${{ (steps.delivery.outputs.run == 'true') && github.event_name != 'pull_request' }}
shell: bash
run: |
set -euo pipefail
@@ -79,6 +66,7 @@ jobs:
exit 1
- name: Determine image tags
if: ${{ steps.delivery.outputs.run == 'true' }}
id: meta
shell: bash
env:
@@ -87,7 +75,7 @@ jobs:
SHA: ${{ gitea.sha }}
run: |
set -euo pipefail
tags=()
tags=("$IMAGE_NAME:sha-$SHA")
if [[ "$REF" == refs/tags/* ]]; then
version="$REF_NAME"
@@ -109,6 +97,7 @@ jobs:
printf 'EOF\n' >> "$GITHUB_OUTPUT"
- name: Build image
if: ${{ steps.delivery.outputs.run == 'true' }}
shell: bash
run: |
set -euo pipefail
@@ -121,9 +110,10 @@ jobs:
build_args+=(--tag "$tag")
done
docker build "${build_args[@]}" .
docker build --label "org.opencontainers.image.revision=$GITHUB_SHA" "${build_args[@]}" .
- name: Push image
if: ${{ (steps.delivery.outputs.run == 'true') && github.event_name != 'pull_request' }}
shell: bash
run: |
set -euo pipefail
@@ -132,4 +122,4 @@ jobs:
docker push "$tag"
done <<'EOF'
${{ steps.meta.outputs.tags }}
EOF
EOF
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# Keep required jobs alive; only skip reviewed non-runtime documentation paths.
set -euo pipefail
base="${DELIVERY_BASE:-}"
head="$(git rev-parse HEAD)"
run=true
if [[ "${DELIVERY_REF:-}" != refs/tags/* && "$head" == "${DELIVERY_SHA:-}" && "${DELIVERY_EVENT:-}" =~ ^(push|pull_request)$ && "$base" =~ ^[0-9a-f]{40}$ && "$base" != 0000000000000000000000000000000000000000 ]]; then
if ! git cat-file -e "$base^{commit}" 2>/dev/null; then
if [[ -n "${DELIVERY_FETCH_TOKEN:-}" ]]; then
git -c "http.extraHeader=Authorization: token ${DELIVERY_FETCH_TOKEN}" fetch --quiet --depth=1 origin "$base" >/dev/null 2>&1 || true
else
git fetch --quiet --depth=1 origin "$base" >/dev/null 2>&1 || true
fi
fi
if git cat-file -e "$base^{commit}" 2>/dev/null; then
paths="$(mktemp)"
trap 'rm -f -- "$paths"' EXIT
# Snapshot comparison is conservative when main advanced during a PR.
# Both rename sides remain visible, including names containing newlines.
if git diff --no-renames --name-only -z "$base" "$head" > "$paths"; then
run=false
while IFS= read -r -d '' path; do
case "$path" in
README.md|CHANGELOG.md|LICENSE|LICENSE.md) ;;
*) run=true; break ;;
esac
done < "$paths"
fi
fi
fi
if [[ "$run" == false ]]; then
echo 'Only reviewed non-runtime documentation changed; build and validation are not applicable.'
else
echo 'Runtime, unknown inputs, or unavailable event history: run required validation.'
fi
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
echo "run=$run" >> "$GITHUB_OUTPUT"
fi
printf '%s\n' "$run"