Run #2 got through Checkout, the runtime probe and the whole suite (157 passed, 3 skipped — the `node --check` structural tests skip with no node in a python image, which is the graceful degradation they were written to have) and then failed on `docker build -t mirror:ci .`: with no -f, docker looks for "Dockerfile", finds none, and says "failed to read dockerfile" after transferring a 2-byte context. The publish job never hit this because docker/build-push-action passes `file: Containerfile` on its own. The gate is worth keeping rather than dropping: it is the only step that builds the image on a push, so without it a broken Containerfile surfaces only as a red publish job that quietly leaves :main stale. LLM-Generated: true
109 lines
4.1 KiB
YAML
109 lines
4.1 KiB
YAML
name: Build and Push Containers
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
release:
|
|
types:
|
|
- published
|
|
|
|
jobs:
|
|
# Gate: the image is only published if the suite is green. A failing job here
|
|
# leaves :main on the last good build, which is what `podman auto-update`
|
|
# keeps serving on reeseapps-mirror — so red means "nothing shipped", not
|
|
# "production is broken".
|
|
#
|
|
# The suite runs *inside* a pinned python:3.13-slim container rather than via a
|
|
# `container:` job key. That is not stylistic: actions/checkout is a JavaScript
|
|
# action and a python image has no Node runtime, so run #1 died in Checkout
|
|
# before running a single command. The runner itself has both (it is where
|
|
# build-push-action builds images), so the job stays on the runner and shells
|
|
# into the container it needs.
|
|
#
|
|
# 3.13 is deliberate: it is the floor declared in pyproject's requires-python,
|
|
# so CI verifies the floor while development happens on 3.14.
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Locate the container runtime
|
|
id: runtime
|
|
run: |
|
|
set -euo pipefail
|
|
runtime="$(command -v podman || command -v docker || true)"
|
|
if [ -z "$runtime" ]; then
|
|
echo "Neither podman nor docker is on this runner, so this job cannot"
|
|
echo "run the suite in a pinned interpreter. Fix here rather than"
|
|
echo "falling back to whatever python the runner image happens to ship."
|
|
exit 1
|
|
fi
|
|
echo "path=$runtime" >> "$GITHUB_OUTPUT"
|
|
echo "using $runtime"
|
|
|
|
# Unit + API only. tests/e2e drives a real Chromium through capture ->
|
|
# encode -> SRTP -> decode and needs a browser install and, for the
|
|
# realdisplay rung, an X server; both stay local gates (see AGENTS.md).
|
|
# --ignore keeps them out of collection entirely: -m filtering happens
|
|
# after import, and tests/e2e/conftest.py imports playwright.
|
|
- name: Lint and test
|
|
run: |
|
|
set -euo pipefail
|
|
"${{ steps.runtime.outputs.path }}" run --rm \
|
|
-v "$GITHUB_WORKSPACE:/src" -w /src \
|
|
docker.io/library/python:3.13-slim \
|
|
/bin/bash -euo pipefail -c '
|
|
pip install --no-cache-dir -q .
|
|
pip install --no-cache-dir -q \
|
|
pytest pytest-asyncio pytest-cov pytest-timeout httpx ruff
|
|
ruff check .
|
|
ruff format --check .
|
|
pytest -q --no-cov --ignore=tests/e2e
|
|
'
|
|
|
|
- name: Smoke the image build
|
|
# Catches a broken Containerfile (a missing COPY source, a failing uv
|
|
# install step) here rather than in the publish job below.
|
|
run: |
|
|
set -euo pipefail
|
|
# -f is not optional: without it docker looks for "Dockerfile", finds
|
|
# none, and reports "failed to read dockerfile" with an empty context —
|
|
# which is exactly how run #2 failed. The publish job gets away without
|
|
# naming it because docker/build-push-action passes `file:` for us.
|
|
"${{ steps.runtime.outputs.path }}" build -f Containerfile -t mirror:ci .
|
|
"${{ steps.runtime.outputs.path }}" run --rm mirror:ci --help >/dev/null
|
|
|
|
build-and-push-app:
|
|
needs: test
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Login to Gitea Container Registry
|
|
uses: docker/login-action@v3
|
|
with:
|
|
registry: gitea.reeseapps.com
|
|
username: ${{ secrets.REGISTRY_USERNAME }}
|
|
password: ${{ secrets.REGISTRY_PASSWORD }}
|
|
|
|
- name: Extract metadata
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: gitea.reeseapps.com/experimental/mirror
|
|
tags: |
|
|
type=raw,value=main,enable=${{ github.ref == 'refs/heads/main' }}
|
|
type=ref,event=tag
|
|
|
|
- name: Build and push app image
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
file: Containerfile
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|