CI-02 probe A: ask the gate what ref it grades, on a conflicted PR
checks / unit (pull_request) Failing after 2m33s
checks / unit (pull_request) Failing after 2m33s
This commit is contained in:
+86
-115
@@ -1,24 +1,15 @@
|
||||
# CI-01: this repository's FIRST automated check. Before this file, admin/goodwe-addon
|
||||
# had no `.gitea/workflows/` directory at all - eight runnable test files, ~100 s
|
||||
# of real coverage including a wall-clock cadence test, and not one machine ever
|
||||
# ran them. Every merge here was a human reading a diff.
|
||||
# CI-02 PROBE WORKFLOW - THROWAWAY. This branch is deleted after the run.
|
||||
#
|
||||
# ⚠️ NO `paths:` FILTER, AND ITS ABSENCE IS LOAD-BEARING. Branch protection on
|
||||
# release/1.0 requires the context `checks / unit (pull_request)`. Gitea leaves a
|
||||
# required context it never receives PENDING forever, so the moment this workflow
|
||||
# learns to sit a PR out, that PR becomes unmergeable. Condition a STEP if you
|
||||
# must; never the workflow.
|
||||
# It replaces the real gate with a set of one-bit steps, because this Gitea
|
||||
# 404s its Actions log endpoints and the ONLY machine-readable channel out of a
|
||||
# job is /api/v1/repos/.../actions/runs/<id>/jobs, which carries a per-STEP
|
||||
# conclusion. So each question this ticket has to answer is asked as its own
|
||||
# step, and the answer is read as that step's success or failure.
|
||||
#
|
||||
# ⚠️ THE RUNNER IS SHARED WITH THE OTHER REPO'S RIG. `goodwe-runner` on
|
||||
# 192.168.2.147 carries the labels `self-hosted` and `goodwe-rig` and is
|
||||
# registered `:host`, and it is the only runner there is - so this job wears the
|
||||
# rig label without wanting a rig. Nothing below starts, stops, or reads the
|
||||
# `goodwe-sim` compose project or takes `sim/riglock.py`; it runs one short
|
||||
# container and exits. It does occupy the runner's single slot (`capacity: 1`),
|
||||
# so it QUEUES behind a rig campaign - a delayed verdict, never a destroyed one.
|
||||
#
|
||||
# NO JS ACTIONS: the runner image has no node, so `actions/checkout` cannot run.
|
||||
# Checkout is seven lines of git below.
|
||||
# There is deliberately NO `concurrency:` block: the point of pushes B and C is
|
||||
# to find out whether a still-WAITING run is cancelled by the next push even
|
||||
# when the workflow asks for no concurrency at all. If it is, the cancellation
|
||||
# is the server's and no edit to this file can prevent it.
|
||||
name: checks
|
||||
|
||||
on:
|
||||
@@ -26,111 +17,91 @@ on:
|
||||
branches: [release/1.0, master]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
# ⚠️ PER PULL REQUEST, NOT A BARE NAME. A shared group holds one running and
|
||||
# one pending run, so a bare name lets a second PR supersede a first PR's run
|
||||
# before any runner has picked it up - which is exactly what happened to the
|
||||
# other repo's run 521 (four jobs, `started_at` at the Unix epoch,
|
||||
# `runner_id: 0`, concluded `cancelled`, and the PR merged anyway). Do not
|
||||
# replace this with a constant.
|
||||
group: addon-checks-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
unit:
|
||||
runs-on: [self-hosted, goodwe-rig]
|
||||
timeout-minutes: 70 # ~4 to run; the rest is queueing for the single slot
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
# ⚠️ UNDER /home/homelab, NOT $GITHUB_WORKSPACE (ENV-01, and re-measured
|
||||
# during CI-01). act's workspace is `/root/.cache/act/<id>/hostexecutor`, a
|
||||
# path that exists only INSIDE the runner container. Hand it to the host's
|
||||
# snap-confined dockerd and the build fails with "failed to read
|
||||
# dockerfile", or - worse, and this is the documented case - a bind mount
|
||||
# resolves to an EMPTY DIRECTORY with no error at all. /home/homelab is
|
||||
# mirrored 1:1 into the runner and is under $HOME, where snap confinement
|
||||
# accepts it. The same probe under /tmp failed and under $HOME succeeded.
|
||||
WS: /home/homelab/ci/addon-checks-${{ github.run_number }}
|
||||
WS: /home/homelab/ci/ci02probe-${{ github.run_number }}
|
||||
PRNUM: ${{ github.event.pull_request.number }}
|
||||
PRHEAD: ${{ github.event.pull_request.head.sha }}
|
||||
BASEREF: ${{ github.base_ref }}
|
||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
URL: ${{ github.server_url }}/${{ github.repository }}.git
|
||||
steps:
|
||||
# ⚠️ THE CHECKOUT IS TWO LEVELS BELOW THE MOUNT ROOT, DELIBERATELY.
|
||||
# test_freeze.py's find_hwsim() reads `HERE.parents[1] / "goodwe" / "sim"`,
|
||||
# looking for the infra repo as a SIBLING of this one. Check out flat -
|
||||
# goodwe_controller directly at the mount root - and `parents[1]` does not
|
||||
# exist, so the test dies on `IndexError: 1` before its first assertion.
|
||||
# Measured during CI-01; the flat layout was tried first and did exactly
|
||||
# that. $WS/goodwe-addon/goodwe_controller gives parents[1] == $WS.
|
||||
- name: checkout into a path the host shares (git; no node for actions/checkout)
|
||||
env:
|
||||
URL: ${{ github.server_url }}/${{ github.repository }}.git
|
||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: P00 an empty clone to ask the server questions from
|
||||
run: |
|
||||
set -eu
|
||||
rm -rf "$WS" && mkdir -p "$WS/goodwe-addon" && cd "$WS/goodwe-addon"
|
||||
rm -rf "$WS" && mkdir -p "$WS" && cd "$WS"
|
||||
git init -q .
|
||||
git remote add origin "$(echo "$URL" | sed "s#://#://x-access-token:${TOKEN}@#")"
|
||||
git fetch -q --depth 1 origin "$GITHUB_REF" || git fetch -q --depth 1 origin "$GITHUB_SHA"
|
||||
git checkout -qf FETCH_HEAD
|
||||
echo "checked out $(git log --oneline -1)"
|
||||
echo "GITHUB_REF=$GITHUB_REF"
|
||||
echo "GITHUB_SHA=$GITHUB_SHA"
|
||||
echo "PRNUM=$PRNUM PRHEAD=$PRHEAD BASEREF=$BASEREF"
|
||||
|
||||
- name: build the test image (shipped deps, from apk - see .gitea/ci/Dockerfile)
|
||||
run: |
|
||||
set -eu
|
||||
docker build -q -t goodwe-addon-checks:1 "$WS/goodwe-addon/.gitea/ci" >/dev/null
|
||||
docker run --rm goodwe-addon-checks:1 python3 -c \
|
||||
'import aiohttp, paho.mqtt.client as m, sys; print("python", sys.version.split()[0], "aiohttp", aiohttp.__version__)'
|
||||
|
||||
# ⚠️ THE FILE LIST IS DERIVED FROM THE TREE, NOT TYPED HERE. A hand-written
|
||||
# list is how a new test file joins the repo and is never run - the exact
|
||||
# shape of failure this ticket exists to close. The step globs `test_*.py`,
|
||||
# prints the count, and REFUSES A COUNT OF ZERO: a loop over an empty glob
|
||||
# exits 0 and would report a green gate that examined nothing.
|
||||
#
|
||||
# ⚠️ test_loop.py TAKES ~93 SECONDS OF WALL CLOCK ON PURPOSE (its own
|
||||
# docstring says so, and says why: it drives the real `run_control()`
|
||||
# against a real wall-clock floor, and mocking the clock would leave the
|
||||
# assertion testing the mock). It is not hung. Do not "fix" it with a
|
||||
# shorter timeout - a 60 s limit was tried during CI-01 and reported
|
||||
# exactly the false hang the docstring predicts.
|
||||
#
|
||||
# ⚠️ WHAT THIS RUN DOES NOT COVER, stated because a pass here would
|
||||
# otherwise over-claim. test_freeze.py's third section wants the infra
|
||||
# repo's `sim/hwsim.py` to drive a real HTTP meter through the real
|
||||
# transport. admin/goodwe is PRIVATE (checked via the API) and this
|
||||
# workflow's GITHUB_TOKEN is minted for THIS repository only, so hwsim is
|
||||
# absent here and `find_hwsim()` returns None. The rest of the file runs
|
||||
# and passes. It does so SILENTLY - the file prints nothing to say the
|
||||
# hwsim section was skipped - so "test_freeze.py: PASS" below is a weaker
|
||||
# claim than it looks. That belongs to whoever owns test_freeze.py next;
|
||||
# naming it here is the least this gate can do about it.
|
||||
- name: the add-on's own tests
|
||||
run: |
|
||||
set -eu
|
||||
docker run --rm -v "$WS:/w:ro" goodwe-addon-checks:1 sh -eu -c '
|
||||
cd /w/goodwe-addon/goodwe_controller
|
||||
set -- test_*.py
|
||||
if [ "$1" = "test_*.py" ]; then
|
||||
echo "NO test_*.py FOUND - the mount is empty or the layout moved. NOTHING has been checked."
|
||||
exit 1
|
||||
fi
|
||||
echo "$# test file(s) to run"
|
||||
rc=0
|
||||
for f in "$@"; do
|
||||
start=$(date +%s)
|
||||
if python3 "$f" > /tmp/out 2>&1; then
|
||||
echo "PASS $f ($(( $(date +%s) - start ))s)"
|
||||
else
|
||||
echo "FAIL $f ($(( $(date +%s) - start ))s)"
|
||||
tail -40 /tmp/out
|
||||
rc=1
|
||||
fi
|
||||
done
|
||||
exit $rc
|
||||
'
|
||||
|
||||
- name: clean up
|
||||
- name: P01 GITHUB_REF is refs-pull-N-head (the bare head)
|
||||
if: always()
|
||||
run: |
|
||||
rm -rf "$WS" || true
|
||||
# Root-owned by this runner inside a directory the `homelab` user owns,
|
||||
# and sudo on that box is interactive-only, so the user cannot clean
|
||||
# this up and the job that made it has to.
|
||||
ls -1dt /home/homelab/ci/addon-checks-*/ 2>/dev/null | tail -n +6 | xargs -r rm -rf || true
|
||||
set -eu
|
||||
test "$GITHUB_REF" = "refs/pull/$PRNUM/head"
|
||||
|
||||
- name: P02 GITHUB_REF is refs-pull-N-merge (merged content)
|
||||
if: always()
|
||||
run: |
|
||||
set -eu
|
||||
test "$GITHUB_REF" = "refs/pull/$PRNUM/merge"
|
||||
|
||||
- name: P03 GITHUB_SHA equals the PR head sha
|
||||
if: always()
|
||||
run: |
|
||||
set -eu
|
||||
test "$GITHUB_SHA" = "$PRHEAD"
|
||||
|
||||
- name: P04 the first half of the shipped fallback fetches at all
|
||||
if: always()
|
||||
run: |
|
||||
set -eu
|
||||
cd "$WS"
|
||||
git fetch -q --depth 1 origin "$GITHUB_REF"
|
||||
|
||||
- name: P05 ...and what it lands on IS the bare PR head
|
||||
if: always()
|
||||
run: |
|
||||
set -eu
|
||||
cd "$WS"
|
||||
git fetch -q --depth 1 origin "$GITHUB_REF"
|
||||
test "$(git rev-parse FETCH_HEAD)" = "$PRHEAD"
|
||||
|
||||
- name: P06 refs-pull-N-merge exists on the server for an OPEN pr
|
||||
if: always()
|
||||
run: |
|
||||
set -eu
|
||||
cd "$WS"
|
||||
git fetch -q --depth 1 origin "refs/pull/$PRNUM/merge"
|
||||
|
||||
- name: P07 a real merge of this head into the base tip applies cleanly
|
||||
if: always()
|
||||
run: |
|
||||
set -eu
|
||||
cd "$WS"
|
||||
git fetch -q origin "+refs/heads/$BASEREF:refs/remotes/origin/base"
|
||||
git fetch -q origin "+refs/pull/$PRNUM/head:refs/remotes/origin/pr"
|
||||
git checkout -qf refs/remotes/origin/base
|
||||
git -c user.email=ci@local -c user.name=ci merge --no-edit --no-ff refs/remotes/origin/pr
|
||||
|
||||
- name: P08 the base tip is already an ancestor of the head
|
||||
if: always()
|
||||
run: |
|
||||
set -eu
|
||||
cd "$WS"
|
||||
git fetch -q origin "+refs/heads/$BASEREF:refs/remotes/origin/base"
|
||||
git fetch -q origin "+refs/pull/$PRNUM/head:refs/remotes/origin/pr"
|
||||
git merge-base --is-ancestor refs/remotes/origin/base refs/remotes/origin/pr
|
||||
|
||||
- name: P09 hold the single runner slot so the next push has to wait
|
||||
if: always()
|
||||
run: sleep 150
|
||||
|
||||
- name: P99 clean up
|
||||
if: always()
|
||||
run: rm -rf "$WS" || true
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
**CI-02 PROBE - THROWAWAY, DO NOT MERGE.** This paragraph exists only to
|
||||
collide with the entries release/1.0 has gained since this branch point, so
|
||||
that the pull request is genuinely unmergeable and the gate can be observed
|
||||
reporting on it. The branch and its pull request are deleted afterwards.
|
||||
|
||||
**Thirty days of the real meter, and the acceptance criterion three cards
|
||||
deferred is now a number (DATA-01).** TARIFF-01 and SAFETY-07 both merged with
|
||||
AC 3 - *"monthly peak held under the soft limit in >= 95 % of intervals over a
|
||||
|
||||
Reference in New Issue
Block a user