Files
flamenet-relay/.gitea/workflows/ci.yml
T
Paul HittandClaude Opus 5 15737e05b4
ci / checks (pull_request) Successful in 14s
ci / swift (pull_request) Successful in 11m51s
ci / image (pull_request) Successful in 51s
ci / deploy (pull_request) Skipped
ci: run the image job on mac2, and make the staging gate say what failed
The image job failed on PR #252 and passed on main with no code difference
between them that touches CI. The runner is the difference: run 434 built on
mac2 and passed, run 441 built on mac1 and failed at "staging postgres never
became ready", on the same two commits. mac1 has the smaller OrbStack
allocation, and the gate starts three sibling containers on the host daemon.
The job now names mac2 rather than taking whichever runner is free.

The gate also prints the container's state and log when Postgres does not come
up. "Never became ready" covered both a Postgres still starting and a
container that never ran, which need different fixes, and mac1 said nothing
further, so 90 seconds of waiting read as a relay bug.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-14 10:59:31 -04:00

162 lines
7.4 KiB
YAML

# flamenet-relay CI/CD on Gitea Actions (mac1/mac2, amd64).
#
# Replaces .gitlab-ci.yml (runner ovh-flamenetmessenger on the production
# box) and the build half of Scripts/staging-gate.sh, which compiled the relay
# on the box from a copied src/ tree. Now:
#
# test secret sweep, swift build + test (swift:6.1-noble, matching the
# Dockerfile), section 8 conformance at the pinned e2e commit,
# generated-page hashes, configuration doc, package completeness.
# conformance-head and doc-pages-head stay advisory.
# image docker build with FN_RELEASE=<sha>, then the staging gate
# (Scripts/ci-staging-gate.sh) against that exact image, then push
# :<short sha> and :latest to git.extant2000.com/extant2000/flamenet-relay.
# deploy main only: deploy/gitea-deploy.sh on the box pulls the gated
# image, tags it flamenet-relay:prod, checks the edge, rolls back
# to :previous on failure, then recreates the test fleet.
#
# Secrets never reach the image or CI: /srv/prod/messenger/.env on the box is
# the source of truth and nothing here writes it.
name: ci
on:
push:
branches: [main]
pull_request:
env:
REGISTRY: git.extant2000.com
IMAGE: git.extant2000.com/extant2000/flamenet-relay
jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 20 }
- name: secret sweep
run: bash Scripts/secret-sweep.sh
- name: package complete
run: |
for f in Package.swift Dockerfile LICENSE .env.example; do test -f "$f" || { echo "missing $f"; exit 1; }; done
test -d Sources && test -d Tests
- name: configuration doc
run: python3 Scripts/check-configuration-doc.py
- name: e2e at the pin
run: |
bash Scripts/ci-fetch-e2e.sh /tmp/e2e
- name: doc pages
run: python3 Scripts/check-doc-pages.py --engine /tmp/e2e
- name: doc pages at e2e HEAD (advisory)
continue-on-error: true
run: |
bash Scripts/ci-fetch-e2e.sh /tmp/e2e-head HEAD
echo "pinned $(cat .e2e-ref)"
python3 Scripts/check-doc-pages.py --engine /tmp/e2e-head
swift:
runs-on: ubuntu-latest
container: swift:6.1-noble
steps:
- name: checkout
run: |
git clone -q "${{ gitea.server_url }}/${{ gitea.repository }}.git" src
cd src && git fetch -q origin "${{ gitea.sha }}" && git checkout -q "${{ gitea.sha }}"
- name: build
run: cd src && swift build
# swift-testing results print separately from XCTest's "Executed 0
# tests"; an empty run must not pass.
- name: test
run: |
cd src
swift test 2>&1 | tee /tmp/test.log
grep -qE 'Test run with [0-9]+ tests? .*passed' /tmp/test.log || { echo "no passing swift-testing run found"; exit 1; }
# Node 22 from nodejs.org (Noble ships 18, which lacks globalThis.crypto
# for ML-DSA). The swift image has no curl or xz, so those come from apt.
- name: node
run: |
apt-get update -qq && apt-get install -y -qq --no-install-recommends curl ca-certificates xz-utils >/dev/null
curl -fsSL https://nodejs.org/dist/v22.20.0/node-v22.20.0-linux-x64.tar.xz | tar xJ -C /opt
ln -sf /opt/node-v22.20.0-linux-x64/bin/node /usr/local/bin/node
node --version
- name: conformance (pinned e2e)
run: |
R="$PWD/src"
bash "$R/Scripts/ci-fetch-e2e.sh" /tmp/e2e
cd /tmp/e2e && FN_RELAY_DIR="$R" node test/relay.mjs
- name: conformance at e2e HEAD (advisory)
continue-on-error: true
run: |
R="$PWD/src"
bash "$R/Scripts/ci-fetch-e2e.sh" /tmp/e2e-head HEAD
cd /tmp/e2e-head && FN_RELAY_DIR="$R" node test/relay.mjs
image:
needs: [checks, swift]
# mac2, by name. The staging gate starts a throwaway Postgres, a Redis and
# the candidate relay as sibling containers on the host daemon. On mac1 the
# Postgres never reached `pg_isready` inside the gate's 90 s window (runs
# 441 and 434 differ in nothing but the runner: mac2 passed, mac1 failed on
# the same two commits), and mac1 has the smaller OrbStack allocation.
# Named here rather than left to whichever runner is free, so the result
# does not depend on which machine picks the job up.
runs-on: [ubuntu-latest, mac2]
steps:
- uses: actions/checkout@v4
# The Dockerfile uses RUN --mount (BuildKit). The static docker tarball
# has no buildx plugin, so `docker build` fell back to the legacy
# builder and refused --mount. Same apt install as the suite workflows.
- name: docker cli
run: |
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bookworm stable" > /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -y -qq --no-install-recommends docker-ce-cli docker-buildx-plugin >/dev/null
docker version --format 'client {{.Client.Version}} server {{.Server.Version}}'
docker buildx version
- name: build (amd64, FN_RELEASE=${{ gitea.sha }})
run: docker build --build-arg FN_RELEASE="$GITHUB_SHA" -t "$IMAGE:${GITHUB_SHA::8}" .
- name: staging gate
run: bash Scripts/ci-staging-gate.sh "$IMAGE:${GITHUB_SHA::8}"
- name: push
if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main'
run: |
printf '%s' "${{ secrets.REGISTRY_TOKEN }}" | docker login "$REGISTRY" -u extant2000git --password-stdin
docker tag "$IMAGE:${GITHUB_SHA::8}" "$IMAGE:latest"
for i in 1 2 3; do
docker push "$IMAGE:${GITHUB_SHA::8}" && docker push "$IMAGE:latest" && break
[ $i = 3 ] && exit 1; sleep 10
done
docker logout "$REGISTRY"
deploy:
if: gitea.event_name == 'push' && gitea.ref == 'refs/heads/main'
needs: [image]
runs-on: ubuntu-latest
concurrency: deploy-relay
steps:
- uses: actions/checkout@v4
- name: ssh
run: |
mkdir -p ~/.ssh && chmod 700 ~/.ssh
printf '%s' "${{ secrets.OVH_DEPLOY_KEY_B64 }}" | base64 -d > ~/.ssh/id_ed25519 && chmod 600 ~/.ssh/id_ed25519
printf '%s\n' "${{ secrets.OVH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
ssh -o StrictHostKeyChecking=yes -o BatchMode=yes "${{ secrets.OVH_USER }}@${{ secrets.OVH_HOST }}" true
- name: deploy
run: |
H="${{ secrets.OVH_USER }}@${{ secrets.OVH_HOST }}"
STAGE="/tmp/relay-deploy-$GITHUB_SHA"
ssh -o BatchMode=yes "$H" "mkdir -p $STAGE"
scp -o BatchMode=yes deploy/gitea-deploy.sh "$H:$STAGE/"
printf '%s\n%s\n' extant2000git "${{ secrets.REGISTRY_TOKEN }}" | ssh -o BatchMode=yes "$H" "bash $STAGE/gitea-deploy.sh $GITHUB_SHA $STAGE"
- name: smoke test (public edge)
run: |
set -eu
for u in https://flamenetmessenger.com/health https://messenger.flamenet.io/health; do
b=$(curl -fsS -m 10 "$u"); echo "$u -> $b"; [ "$b" = ok ] || exit 1
done
for p in / /about /privacy /metadata /releases /es/; do
c=$(curl -s -o /dev/null -m 10 -w '%{http_code}' "https://flamenetmessenger.com$p"); echo "$p $c"; [ "$c" = 200 ] || exit 1
done