Files
Andris Enins 273d3f9dba
All checks were successful
CI / Build & test backend (push) Successful in 42m58s
fix: install Maven 3.9.9 in docker build job — same fix as ci.yml
actions/setup-java@v4 installs the JDK but not Maven itself.
pi-runner does not have mvn pre-installed. Add an explicit curl
install step matching the approach used in backend/Dockerfile.
2026-05-19 12:47:49 +00:00

178 lines
7.2 KiB
YAML

# Generated by GitHub Copilot
#
# docker.yml — Build and push Docker image to Gitea Container Registry
#
# Triggers after CI passes on main (workflow_run) to prevent this heavyweight job
# from competing with the Maven+test job on the single-capacity Pi runner.
#
# Produces images tagged with the short SHA and 'latest'.
# Immediately deploys to the Pi production stack via docker.sock.
#
# Required Gitea repository secrets (Settings → Actions → Secrets):
# REGISTRY_USERNAME — Gitea username (andrisenins)
# REGISTRY_PASSWORD — Gitea access token (package:write + repo:write scope)
name: Docker
on:
# Only run after CI succeeds — prevents OOM kills on the Pi from parallel jobs.
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [main]
workflow_dispatch:
# Cancel any in-progress docker build for the same branch so stale BuildKit
# containers from the previous run are cleaned up before the new build starts.
concurrency:
group: docker-${{ gitea.event.workflow_run.head_branch || gitea.ref }}
cancel-in-progress: true
env:
REGISTRY: git.amlab.dev
jobs:
build-api:
name: Build & push API image
runs-on: pi-runner
# For workflow_run events: only build if CI succeeded.
# For workflow_dispatch (manual): always run.
if: >
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# In a workflow_run context, checkout the commit that triggered CI.
ref: ${{ gitea.event.workflow_run.head_sha || gitea.sha }}
- name: Log in to Gitea Container Registry
# Login BEFORE the Maven build while the Pi CPU is idle.
# When login is attempted after a long Maven build the host Docker daemon
# exhausts its 30s HTTP timeout on every attempt (confirmed in MYPHOTOS
# task logs — same issue applies here).
# NOTE: use 'if' not '&&' — act_runner uses 'bash -e', so 'cmd && break'
# exits the entire script on the first non-zero cmd result.
env:
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
run: |
for i in 1 2 3 4 5 6 7 8 9 10; do
if echo "$REGISTRY_PASSWORD" | docker login --username "$REGISTRY_USERNAME" --password-stdin "$REGISTRY"; then
break
fi
if [ "$i" -eq 10 ]; then
echo "ERROR: All 10 docker login attempts failed"
exit 1
fi
echo "Login attempt $i failed, retrying in 30s..."
sleep 30
done
# Build JAR natively (inside the job container, outside BuildKit/QEMU).
# Without this, Maven runs under QEMU cross-emulation during the Docker build
# RUN step, causing TLS connections to Maven Central to break after ~20 min.
- name: Set up Java 21 LTS
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
cache: maven
# actions/setup-java installs the JDK but not Maven.
# pi-runner has no pre-installed mvn — download the same version used
# in backend/Dockerfile to keep the build environment consistent.
- name: Install Maven 3.9.9
run: |
curl -fsSL https://archive.apache.org/dist/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz \
| tar -xz -C /opt
echo "/opt/apache-maven-3.9.9/bin" >> $GITHUB_PATH
- name: Build JAR (native — avoids QEMU Maven download)
working-directory: backend
run: mvn -q -ntp clean package -DskipTests
- name: Build and push API image
# Use plain docker build+push (no buildx, no JS action) to avoid
# docker/build-push-action@v6 crashing silently in act_runner v0.5.0.
# DOCKER_BUILDKIT=0 uses legacy builder — no gRPC DeadlineExceeded on RPi.
env:
DOCKER_BUILDKIT: "0"
SHA: ${{ gitea.event.workflow_run.head_sha || gitea.sha }}
OWNER: ${{ gitea.repository_owner }}
run: |
SHORT_SHA="${SHA:0:7}"
IMAGE="${REGISTRY}/${OWNER}/calorie-counter-api"
docker build \
--target ci-image \
--build-arg JAR_FILE=target/calorie-counter-backend-1.0.0-SNAPSHOT.jar \
-t "${IMAGE}:${SHORT_SHA}" \
-t "${IMAGE}:latest" \
backend/
docker push "${IMAGE}:${SHORT_SHA}"
docker push "${IMAGE}:latest"
deploy:
name: Deploy to Pi — pull & restart stack
runs-on: pi-runner
needs: [build-api]
if: >
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
steps:
- name: Pull and restart production stack
# Run docker compose against the Pi HOST's homelab directory.
# Volume paths in a `docker run` issued via the mounted socket are
# resolved against the Docker DAEMON's filesystem (the Pi host), not
# the job container's filesystem — standard DinD-via-socket behaviour.
# The .env file in that directory supplies all production secrets so
# no secrets need to be passed into this job.
env:
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
run: |
docker run --rm \
-v /home/andris/homelab/calorie-counter:/project \
-v /var/run/docker.sock:/var/run/docker.sock \
-e REGISTRY_PASSWORD \
-e REGISTRY_USERNAME \
-e "REGISTRY=${REGISTRY}" \
-w /project \
docker:27.5.1-cli \
sh -c '
echo "$REGISTRY_PASSWORD" | docker login \
--username "$REGISTRY_USERNAME" \
--password-stdin "$REGISTRY" &&
docker compose pull &&
docker compose up -d &&
echo "=== Stack status ===" &&
docker compose ps
'
# ── Build failure notification ──────────────────────────────────────────────
notify-failure:
name: Notify — build failure
runs-on: ubuntu-latest
needs: [build-api, deploy]
# Only run when something failed; skip on success or cancellation
if: failure()
steps:
- name: Post commit comment on failure
env:
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
OWNER: ${{ gitea.repository_owner }}
SHA: ${{ gitea.event.workflow_run.head_sha || gitea.sha }}
RUN_URL: ${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_id }}
run: |
BODY="❌ **Docker build failed** for \`${SHA:0:7}\`\n\nSee the failed run: ${RUN_URL}"
curl -sf -X POST \
"https://git.amlab.dev/api/v1/repos/${OWNER}/calorie-counter/commits/${SHA}/comments" \
-H "Authorization: token ${REGISTRY_PASSWORD}" \
-H "Content-Type: application/json" \
-d "{\"body\": \"${BODY}\"}" \
&& echo "Failure comment posted" \
|| echo "Warning: could not post comment (non-fatal)"