From ca4da932ef69e4a02f3c5a5904927e33f4a41c5c Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Sat, 11 Apr 2026 11:51:39 +0000 Subject: [PATCH 1/3] doc(GH-Actions): add detailed GitHub Actions vocabulary section with diagrams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing CI architecture doc assumes the reader already knows the GitHub Actions terminology and can parse check-run labels like 'CI-maketest / builds (testgalera)'. A maintainer asked what that label means and where to find it by grep, and the only answer was "re-read the whole doc and work it out yourself, most of the pieces are in different sections". That's not good enough. This commit adds a new §12 'Understanding GitHub Actions vocabulary' that: - Walks through the seven core terms (workflow, workflow run, job, matrix cell, step, check run, caller/reusable split) bottom-up, using ci-maketest.yml as a single concrete example throughout. - Includes an ASCII nesting diagram that shows how workflow -> run -> job -> matrix cell -> steps slot into each other, with check runs as separate objects attached to the commit SHA. - Includes a second ASCII diagram showing the ProxySQL two-branch caller/reusable split: one logical trigger -> two workflow runs, one on v3.0 and one on GH-Actions, sharing the same workflow name. - Includes a third diagram tracing exactly how the check-run label 'CI-maketest / builds (testgalera)' is assembled at runtime from github.workflow + github.job + env.MATRIX, explaining why the literal string exists nowhere on disk and grepping for it or for 'galera' will fail. - Answers five common confusion questions directly (why click-throughs land on GH-Actions, why two check rows per cell, where 'make testgalera' is defined, which file produced a given check row, CI-legacy-g2-genai vs CI-legacy-g2). - Ends with a five-question self-test so the reader can check they have the model right before closing the section. Also: - Added a 'New to GitHub Actions terminology?' pointer at the top of the doc so a confused reader jumps directly to the new section instead of wading through the two-branch architecture explanation first. - Renamed the existing compact Glossary table to 'Glossary (quick reference)' to make clear it is the lookup-by-term reference and the new narrative section is the learn-by-walkthrough explanation. - Both sections are kept: §12 for people who need the model, §13 for people who just need a word defined quickly. No source-code or workflow changes. Doc only. --- doc/GH-Actions/README.md | 538 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 536 insertions(+), 2 deletions(-) diff --git a/doc/GH-Actions/README.md b/doc/GH-Actions/README.md index d626ebf40e..3e81230944 100644 --- a/doc/GH-Actions/README.md +++ b/doc/GH-Actions/README.md @@ -10,6 +10,13 @@ pitfalls. If you touch anything under `.github/workflows/` on either `v3.0` or the `GH-Actions` branch, read this first. +> **New to GitHub Actions terminology, or confused by check-run labels +> like `CI-maketest / builds (testgalera)`?** Jump to +> [§12 Understanding GitHub Actions vocabulary](#understanding-github-actions-vocabulary--read-this-first-if-confused) +> first — it walks through every term (workflow / run / job / matrix / +> check run / caller / reusable) with diagrams and a concrete walkthrough, +> then come back here. + --- ## Table of contents @@ -25,7 +32,8 @@ If you touch anything under `.github/workflows/` on either `v3.0` or the 9. [Adding a new test group end-to-end](#adding-a-new-test-group-end-to-end) 10. [Common pitfalls and historical gotchas](#common-pitfalls-and-historical-gotchas) 11. [Debugging a failing CI run](#debugging-a-failing-ci-run) -12. [Glossary](#glossary) +12. [Understanding GitHub Actions vocabulary — read this first if confused](#understanding-github-actions-vocabulary--read-this-first-if-confused) +13. [Glossary (quick reference)](#glossary-quick-reference) --- @@ -989,7 +997,533 @@ binary directly and print a summary. --- -## Glossary +## Understanding GitHub Actions vocabulary — read this first if confused + +This section is the long-form explanation of the terminology. If you just +want a word defined quickly, skip to the [compact glossary](#glossary-quick-reference) +at the end. If you look at a PR "Checks" tab and can't answer *"what file +on disk corresponds to this row, and why can't I find it by grepping?"*, +read this section. + +We will use **one concrete check label** throughout — the one from issue +that prompted this section — and walk it all the way down from "string on +the PR" to "YAML line on disk": + +``` +CI-maketest / builds (testgalera) +``` + +By the end of the section you should be able to open any PR, look at any +check-run label, and know exactly which file (on which branch) produced it. + +### 12.1 The seven terms you need to keep straight + +These are **not** ProxySQL-specific — they are standard GitHub Actions +vocabulary — except for #7 which is the ProxySQL caller/reusable split. +They are ordered so each one builds on the previous. + +#### 1. Workflow — the YAML file on disk + +A **workflow** is *exactly one file* under `.github/workflows/`. Each file +has a top-level `name:`, an `on:` block listing its triggers, and a `jobs:` +block listing its jobs. + +The workflow's **identity in the GitHub UI is the `name:` field**, not the +filename. Two different files with the same `name:` will look like "the +same workflow" in the UI (this is important — ProxySQL does exactly this, +see #7 below). + +Concrete example — `.github/workflows/ci-maketest.yml` on branch `GH-Actions`: + +```yaml +name: CI-maketest ← ← ← this is the workflow name +on: + workflow_dispatch: + workflow_call: + inputs: + trigger: + type: string + target: + type: string +jobs: + builds: ← there is exactly one job: "builds" + runs-on: ubuntu-22.04 + strategy: + matrix: + target: [ testaurora, testgalera, testgrouprep, + testreadonly, testreplicationlag, testall ] + steps: + - … +``` + +This file *is* a workflow. It will stay a workflow whether it ever runs or +not, whether it has runs on 10 commits or zero commits. It is an +**immutable object at rest on disk**. + +#### 2. Workflow run — one execution of a workflow + +A **workflow run** is what happens when a trigger fires on a specific +commit. Every run is a **mutable object in GitHub's history** with: + +- a unique numeric **run id** (the big number in the URL) +- a single `head_sha` (the commit it ran on) +- a `status` — one of `queued`, `in_progress`, `completed` +- a `conclusion` — one of `success`, `failure`, `cancelled`, `skipped`, … + (only meaningful after `status == completed`) + +If the `CI-maketest` workflow fires on commit `09b97547f` and again on +commit `a1b2c3d4e`, those are **two different workflow runs** of *the same +workflow*. Each has its own run id. You can list runs of a workflow with: + +```bash +gh run list --workflow CI-maketest -R sysown/proxysql --limit 10 +``` + +Workflow runs are what you see in the **Actions** tab of the repo. + +#### 3. Job — one block under `jobs:` + +A run contains one or more **jobs**. Jobs are keys under the `jobs:` block +of the workflow file. Each job runs on its own **runner** (a VM or +container) and contains its own sequence of **steps**. + +In our example, the `CI-maketest` workflow has *one* job definition: +`builds` (look back at the YAML). That single definition is what will +become one-or-more actual job runs once the matrix expands in #4. + +A workflow with two jobs and no matrix produces a run with exactly two +parallel jobs. A workflow with one job and no matrix produces a run with +one job. Simple. + +#### 4. Job matrix — one job definition → N parallel job-runs + +`CI-maketest` is not simple. Its one job (`builds`) declares: + +```yaml +strategy: + matrix: + target: [ testaurora, testgalera, testgrouprep, + testreadonly, testreplicationlag, testall ] +``` + +This says: *"expand this single job definition into six parallel job-runs, +one per value of `target`"*. Each expansion gets its own runner, its own +steps executing top-to-bottom, and its own independent pass/fail. When +matrix expansion happens, the expansions are sometimes called **matrix +jobs** or **matrix cells** — there is no universally-agreed term; in this +doc we use "matrix cell" or "matrix job". + +**One workflow run of `CI-maketest`** therefore contains **one job +definition** (`builds`) which expands to **six matrix cells**, each of +which is its own parallel execution. So `gh run view ` on a +`CI-maketest` run shows: + +``` +builds (testaurora) success +builds (testgalera) success ← the one we care about +builds (testgrouprep) failure +builds (testreadonly) success +builds (testreplicationlag) success +builds (testall) success +``` + +Six lines, one workflow run. *The word "galera" appears exactly once in +the entire workflow file: as the second value in that matrix array.* +There is no `ci-galera.yml`. There is no job called "testgalera". There +is only a matrix value named "testgalera" inside the one `builds` job +inside the one `CI-maketest` workflow. + +#### 5. Step — one `- name:` block inside a job + +A **step** is the smallest unit: one entry in a job's `steps:` list. Steps +run sequentially top-to-bottom inside a single runner, sharing filesystem +and environment. They are the actual shell commands or Action invocations. + +In `CI-maketest`, every matrix cell runs the same five steps: + +``` +1. checks (LouisBrunner) - "in_progress" +2. Checkout repository +3. Make-test ← runs `make $TARGET` inside docker-compose +4. Check build +5. checks (LouisBrunner) - post job.status back +``` + +Steps are **per-matrix-cell**, so across the six cells of one workflow +run, 30 step executions happen in total (6 cells × 5 steps each). + +#### 6. Check run — a status row attached to a commit SHA + +This is the one that is most confusing, because it is **not** in the +workflow hierarchy at all. It is a *separate* object that lives on the +**commit**, not on the workflow. + +GitHub's **Checks API** lets anything (an Action, an external bot, a +webhook) attach a status row to a specific commit SHA with: + +- a `name` (free-form string, author's choice) +- a `status` (`queued` / `in_progress` / `completed`) +- a `conclusion` (`success` / `failure` / …) +- an optional `details_url` (where to click for more info) + +**These check runs are what you see on the PR "Checks" tab.** PR +merge-blocking is based on check runs, not on workflow runs directly. + +By default, GitHub Actions *auto-creates* one check run per job run — +that is, for each matrix cell — with the check name equal to `{workflow +name} / {job name}` or `{workflow name} / {job name} ({matrix values})`. +For `CI-maketest`, the auto-generated labels would look like: + +``` +CI-maketest / builds (testaurora) +CI-maketest / builds (testgalera) ← could be auto-generated this way +… +``` + +**But ProxySQL uses `LouisBrunner/checks-action@v2.0.0` instead**, +which lets the workflow author **manually create their own check runs** +with a custom `name:`. Look at the top of `ci-maketest.yml`: + +```yaml +- uses: LouisBrunner/checks-action@v2.0.0 + id: checks + if: always() + with: + name: '${{ github.workflow }} / ${{ github.job }} ${{ env.MATRIX }}' + sha: ${{ env.SHA }} + status: 'in_progress' +``` + +The `name:` is assembled from three runtime expressions: + +| Piece | Source | Value at runtime | +|---|---|---| +| `${{ github.workflow }}` | the workflow's `name:` field | `CI-maketest` | +| `${{ github.job }}` | the job key | `builds` | +| `${{ env.MATRIX }}` | set earlier by `env:` in the job: `MATRIX: '(${{ matrix.target }})'` | `(testgalera)` | + +So **the literal string `CI-maketest / builds (testgalera)` is constructed +at runtime** by concatenating these three pieces. **It exists nowhere on +disk.** You cannot grep for it and find it. You cannot search the repo +for it. It only exists as a check-run object in GitHub's database, created +after the action runs. + +One more important point: because `LouisBrunner/checks-action` creates the +check runs manually, **GitHub's auto-generated check runs for the same +jobs also exist**. So you often see *two* check rows per matrix cell in +the PR UI — one from GitHub's auto-creation, one from the custom action. +They will usually agree (same status), but they are not the same object. + +#### 7. Reusable workflow vs caller — the ProxySQL two-branch split + +This is not standard GitHub Actions vocabulary — it is a convention +ProxySQL uses to work around GitHub's rule that `workflow_run`-triggered +workflows must live on the default branch (`v3.0`). + +- A **caller** is a `.github/workflows/CI-*.yml` file on `v3.0` (uppercase + `CI-`). Its only job body is `uses: …@GH-Actions`, delegating to a + reusable on the other branch. +- A **reusable** is a `.github/workflows/ci-*.yml` file on `GH-Actions` + (lowercase `ci-`). It declares `on: workflow_call` and contains the + actual logic. + +**Both files share the same `name:` field** — e.g. both `CI-maketest.yml` +(caller on v3.0) and `ci-maketest.yml` (reusable on GH-Actions) declare +`name: CI-maketest`. The GitHub UI groups them together in the Actions tab +and the PR check rollup: you almost always see "CI-maketest" as a single +entry, even though *internally there are two workflow runs per logical +step* — one on each branch. + +See `§2 The two-branch architecture` for why this exists. For this +section what matters is: **every time you click on `CI-maketest` in the +UI, you may land on either the v3.0 caller run or the GH-Actions reusable +run**, depending on which one the link points to. The caller run is +always a thin one-job pass-through; the reusable run is the one with the +matrix, the steps, and the actual test output. + +### 12.2 The full nesting, visualized + +Pin this diagram on the wall of your mental model. Every term from §12.1 +fits into exactly one slot here: + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ WORKFLOW │ +│ (the YAML file on disk, e.g. ci-maketest.yml) │ +│ name: CI-maketest │ +│ lives on a branch (v3.0 if caller, GH-Actions if reusable) │ +│ │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ WORKFLOW RUN │ │ +│ │ (one execution on one commit, has a numeric run-id) │ │ +│ │ head_sha = 09b97547f, status = in_progress, … │ │ +│ │ │ │ +│ │ ┌─────────────────────────────────────────────────┐ │ │ +│ │ │ JOB DEFINITION (key under `jobs:`) │ │ │ +│ │ │ builds │ │ │ +│ │ │ expands via matrix → │ │ │ +│ │ │ │ │ │ +│ │ │ ┌──────────────┐ ┌──────────────┐ ┌───────┐ │ │ │ +│ │ │ │ MATRIX CELL │ │ MATRIX CELL │ │ ... │ │ │ │ +│ │ │ │ target= │ │ target= │ │ │ │ │ │ +│ │ │ │ testaurora │ │ testgalera │ │ │ │ │ │ +│ │ │ │ │ │ │ │ │ │ │ │ +│ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ │ │ │ +│ │ │ │ │ STEPS │ │ │ │ STEPS │ │ │ │ │ │ │ +│ │ │ │ │ 1 2 3 4 │ │ │ │ 1 2 3 4 │ │ │ ... │ │ │ │ +│ │ │ │ │ 5 │ │ │ │ 5 │ │ │ │ │ │ │ +│ │ │ │ └──────────┘ │ │ └──────────┘ │ │ │ │ │ │ +│ │ │ └──────┬───────┘ └──────┬───────┘ └───────┘ │ │ │ +│ │ └─────────┼─────────────────┼──────────...────────┘ │ │ +│ └──────────────┼─────────────────┼──────────...─────────────┘ │ +└───────────────────┼─────────────────┼──────────...──────────────────┘ + │ │ + ▼ ▼ + CHECK RUN CHECK RUN + attached to attached to + commit SHA commit SHA + name: name: + "CI-maketest / "CI-maketest / + builds builds + (testaurora)" (testgalera)" ← you clicked this +``` + +Key reading of the diagram: + +1. The **workflow** is the outermost box — one YAML file on disk. +2. The **workflow run** is the next box in — one execution on a SHA. +3. The **job definition** (`builds`) is the next box — written once in the + YAML. +4. **Matrix cells** are the parallel sub-boxes — six of them here. +5. **Steps** are the innermost list inside each cell — executed top-to- + bottom on one runner. +6. **Check runs** (arrows leaving the bottom) are *separate objects* that + point at the commit. They are created by either GitHub + auto-generation, or manually by `LouisBrunner/checks-action`, or both. + +### 12.3 The ProxySQL two-branch split, visualized + +When ProxySQL's caller/reusable split is layered on top of the above, **the +picture doubles up**: + +``` + PR HEAD COMMIT + ┌──────────────┐ + │ 09b97547f │ ← one SHA that the PR is about + └──────┬───────┘ + │ + │ push event / workflow_run chain fires + ▼ + ┌────────────────────────────────────────────────────────┐ + │ CALLER WORKFLOW RUN on v3.0 │ + │ file: .github/workflows/CI-maketest.yml@v3.0 │ + │ workflow name: CI-maketest │ + │ (20-line stub file — this run has ONE trivial job: │ + │ "run", whose only body is uses: …@GH-Actions) │ + │ │ + │ status: completed conclusion: success │ + │ (but almost nothing happened here!) │ + └──────────────────────┬─────────────────────────────────┘ + │ + │ uses: .github/workflows/ + │ ci-maketest.yml@GH-Actions + ▼ + ┌────────────────────────────────────────────────────────┐ + │ REUSABLE WORKFLOW RUN on GH-Actions │ + │ file: .github/workflows/ci-maketest.yml@GH-Actions │ + │ workflow name: CI-maketest ← same name! │ + │ job: builds │ + │ matrix: 6 cells (testaurora, testgalera, …) │ + │ │ + │ this is where the actual work happens │ + │ this is where the 6 check runs are created │ + └────────────────────────┬───────────────────────────────┘ + │ + ┌────────────────────────┼───────────────────────────────┐ + │ six check runs │ attached to the SHA │ + │ ▼ │ + │ CI-maketest / builds (testaurora) │ + │ CI-maketest / builds (testgalera) ← you clicked this│ + │ CI-maketest / builds (testgrouprep) │ + │ CI-maketest / builds (testreadonly) │ + │ CI-maketest / builds (testreplicationlag) │ + │ CI-maketest / builds (testall) │ + └────────────────────────────────────────────────────────┘ +``` + +So when you click on **`CI-maketest / builds (testgalera)`** from the PR's +Checks tab: + +- The workflow **name** (`CI-maketest`) is the same on both branches. +- The **click-through link** (`details_url` on the check run) is set by + the reusable, so it takes you into the **reusable run on `GH-Actions`**, + not the caller run on `v3.0`. +- To read the YAML that ran, you want the **GH-Actions branch version**. + +### 12.4 How the `CI-maketest / builds (testgalera)` label is built + +Tracing the literal string character-by-character from the YAML to what +you see: + +``` + Literal on disk Runtime value + ────────────── ───────────── + + name: CI-maketest (top of file) + ↓ + ↓ feeds github.workflow + ↓ = "CI-maketest" + ↓ + jobs: + builds: (job key) + ↓ + ↓ feeds github.job + ↓ = "builds" + ↓ + env: + MATRIX: '(${{ matrix.target }})' + ↓ + ↓ matrix.target expands per cell env.MATRIX + ↓ (here: "testgalera") = "(testgalera)" + ↓ + - uses: LouisBrunner/checks-action@v2.0.0 + with: + name: '${{ github.workflow }} / ${{ github.job }} ${{ env.MATRIX }}' + │ │ │ + └───── CI-maketest │ │ + └──── / builds │ + └──── (testgalera) + + final label: "CI-maketest / builds (testgalera)" + │ │ │ + workflow job matrix-cell + name name value +``` + +Three independent pieces, concatenated by one action call, at runtime. +**The full string never appears in the codebase.** This is why grepping +for "CI-maketest / builds (testgalera)" or even just "galera" in the +workflow directory of the v3.0 branch finds nothing useful: + +- The string "galera" appears in **one** workflow file: `ci-maketest.yml`, + and *that file is on the `GH-Actions` branch, not `v3.0`*. If you + grepped only your local `v3.0` checkout, you missed it entirely. +- Even on `GH-Actions`, "galera" is not the file's name, not the job's + name, not the workflow's name — it is *one of six values inside one + `matrix.target` array*. +- The other place "galera" appears in the repo is in the root `Makefile`, + where `testgalera:` is a Make target that compiles proxysql + TAP tests + with `-DTEST_GALERA` defined. Grepping `Makefile` on `v3.0` for + `testgalera` *does* find it, but that hit tells you what the Make target + does, not what the workflow does. + +### 12.5 Common confusions, answered directly + +**Q: "I see `CI-maketest` in the Actions tab, but when I click the run, +the page URL says `/actions/runs/...` on the `GH-Actions` branch. Is that +a bug?"** + +No. Because the caller on `v3.0` delegates via `uses:`, a single logical +trigger creates *two* workflow runs — one on each branch. Click-throughs +land wherever the particular link pointed. The caller run on `v3.0` is +always almost-empty (just the delegation); the meaty one is on +`GH-Actions`. + +**Q: "Why are there two rows in my Checks tab for the same test — e.g. +`CI-maketest / builds (testgalera)` AND a plain `builds (testgalera)`?"** + +Because `LouisBrunner/checks-action` creates its own custom-named check +run in addition to whatever GitHub auto-generates for the matrix cell. +Both attach to the same commit and describe the same execution. If they +disagree in status it usually means the post-job LouisBrunner call failed +(e.g. permissions), not that the job result differs. + +**Q: "I want to know what `make testgalera` actually tests. Where do I +look?"** + +Not in `.github/workflows/`. Look at the root `Makefile` on `v3.0`, +search for `^testgalera:`. You will find (lines ~203-206): + +```make +testgalera: build_src_testgalera + cd test/tap && OPTZ="-O0 -ggdb -DDEBUG -DTEST_GALERA" make + cd test/tap/tests && OPTZ="-O0 -ggdb -DDEBUG -DTEST_GALERA" make +``` + +That tells you: it's a **build target** that compiles proxysql and the TAP +tests with `-DTEST_GALERA` defined. The `CI-maketest` workflow is a +**compile-check matrix** — it verifies the proxysql source still compiles +for each of 6 build flavors (testaurora, testgalera, …). It does **not** +run Galera tests against a Galera cluster. That's what the job being +named `builds` (not `tests`) is telling you. + +**Q: "If the check-run label is assembled at runtime, how do I search +for 'which workflow file produced check X'?"** + +Use this decision table: + +| Check row on PR | What file produced it | +|---|---| +| `CI-foo` (no trailing `/ ...`) | Either the auto-generated top-level check of the caller run `CI-foo.yml@v3.0`, or the top-level rollup of the reusable `ci-foo.yml@GH-Actions`. Usually clicking the row tells you which. | +| `CI-foo / jobname` | The job `jobname` inside `ci-foo.yml` on `GH-Actions`. Read the `jobs.jobname:` block there. | +| `CI-foo / jobname (matrixvalue)` | A matrix cell of that job. Read the `jobs.jobname.strategy.matrix:` block — `matrixvalue` will appear as one of the values. | + +**Rule of thumb: if you see a check name with a workflow prefix +(`CI-foo / ...`), the interesting file is always on `GH-Actions`, never +on `v3.0`.** The `v3.0` caller is always a 20-line stub; the matrix, +steps, and logic are in the reusable on `GH-Actions`. + +**Q: "Where is `CI-legacy-g2-genai` defined? Is it a group, a flavor, a +matrix cell, a workflow?"** + +It is a whole separate **workflow** pair — one caller (`CI-legacy-g2-genai.yml@v3.0`) +and one reusable (`ci-legacy-g2-genai.yml@GH-Actions`). Same pattern as +`CI-legacy-g2.yml` / `ci-legacy-g2.yml`, but for the GenAI-with-coverage +build flavor. So "there are 6 CI-legacy-g* workflows on v3.0" +(`g1, g2, g2-genai, g3, g4, g5`) and each is its own file, not a matrix +cell of a shared workflow. Contrast with `CI-maketest`, where the 6 +build flavors ARE matrix cells of one shared workflow. Both patterns +exist in the repo for historical reasons. + +### 12.6 Sanity-check yourself + +If you understand the vocabulary, you should be able to answer each of +these in one sentence. Answers after each question. + +1. **"How many workflows does `CI-maketest` have?"** + → Two files on disk: `CI-maketest.yml` on v3.0 (caller stub) and + `ci-maketest.yml` on GH-Actions (reusable with the real logic). They + share the `name:` field so the UI treats them as one. + +2. **"How many jobs does one `CI-maketest` workflow run have, and how + many matrix cells?"** + → One job definition (`builds`), expanded to 6 matrix cells, so 6 + parallel job-runs. + +3. **"How many check runs does one `CI-maketest` workflow run create?"** + → At minimum 6 (one per matrix cell, created by + `LouisBrunner/checks-action`); in practice often 12 because GitHub + auto-generates matching check runs for the same cells. + +4. **"If `CI-maketest / builds (testgalera)` fails, which file on which + branch do I read to figure out why?"** + → `ci-maketest.yml` on `GH-Actions`, specifically the `builds` job's + steps. The v3.0 caller is never where a real failure lives. + +5. **"Where does the literal string `testgalera` come from?"** + → It is one value in the `strategy.matrix.target` array inside + `ci-maketest.yml@GH-Actions`. It is *also* a Makefile target name + in the root `Makefile@v3.0`. The workflow picks the matrix value and + invokes the Makefile target in docker-compose. + +If those five answers feel comfortable, you can close this section. If +not, re-read the [nesting diagram](#122-the-full-nesting-visualized) and +then the [two-branch diagram](#123-the-proxysql-two-branch-split-visualized) +until they do. + +--- + +## Glossary (quick reference) | Term | Definition | |---|---| From 90c103a34558d81f3799ae3e5e6e1467a97d68bd Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Sat, 11 Apr 2026 12:41:20 +0000 Subject: [PATCH 2/3] =?UTF-8?q?doc(GH-Actions):=20add=20=C2=A712.6=20termi?= =?UTF-8?q?nal=20flow=20=E2=80=94=20how=20to=20actually=20see=20what=20ran?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to the vocabulary section added in ca4da932e. A maintainer hit GitHub's longstanding check-run UX papercut: clicking a row in the PR "Checks" tab lands on /runs/, which shows only a status card and whose "View more details on GitHub Actions" link often points back at the same page because details_url on auto-created check runs is self-referential. The same dead-end is reached via the PR checks table's "Details" button (an earlier draft of this doc claimed otherwise — the claim was wrong and is corrected here). This commit inserts §12.6 "Seeing what actually ran — the terminal flow" between §12.5 (Common confusions) and what is now §12.7 (Sanity check, formerly §12.6). The new section walks the exact four-command terminal flow needed to go from a single row of `gh pr checks` output to the log lines of the failing step, using the real row from PR 5596 as the walked example: ✓ CI-trigger/CI-legacy-g1 / tests (mysql57) → gh run list -R sysown/proxysql --workflow CI-legacy-g1 → gh run view 24281031512 -R sysown/proxysql → gh run view --log-failed --job=70902846188 -R sysown/proxysql The section covers: - A character-by-character breakdown of the check row, identifying which fields are useful (workflow name) and which are dead ends (the /runs/ URL). - Why `gh run list`'s `branch:` column lies ("v3.0" rather than the PR's actual branch) because workflow_run-triggered runs inherit the default branch's metadata, not the triggering PR's. The documented gotcha in §10.2 cross-referenced. - How the run's display-title is the ONLY place where the PR head SHA appears, and the idiom to grep / `jq .displayTitle | contains(...)` against it. - How job name and check-run name differ ("run / tests (mysql57)" vs "CI-legacy-g1 / tests (mysql57)") because the prefixes come from different namespaces (caller job key vs workflow name). - Three flavors of log retrieval (--log-failed, --log | less, full-run --log) with concrete awk / grep idioms for the tab-separated log format. - A copy-pasteable condensed cheat sheet parameterised over PR number and workflow name. - A "why the web UI cannot do this" explanation stacking the three separate GitHub design issues: check-runs vs job-runs are different objects with no explicit link, details_url is self-referential, and workflow_run runs are tagged with the default branch's SHA not the PR's. Also: - §12.7 Sanity-check renumbered from §12.6, internal cross-refs in its "if you didn't get this, re-read X" pointer updated. - §12.7 gains a sixth self-test question covering the terminal flow. - No TOC change needed: the TOC lists only top-level sections (§12 as a whole), subsections are reached via the heading anchors. Doc-only change. 1547 → 1818 lines. Code fences balanced at 100. --- doc/GH-Actions/README.md | 280 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 275 insertions(+), 5 deletions(-) diff --git a/doc/GH-Actions/README.md b/doc/GH-Actions/README.md index 3e81230944..c38007ccb5 100644 --- a/doc/GH-Actions/README.md +++ b/doc/GH-Actions/README.md @@ -1485,7 +1485,265 @@ cell of a shared workflow. Contrast with `CI-maketest`, where the 6 build flavors ARE matrix cells of one shared workflow. Both patterns exist in the repo for historical reasons. -### 12.6 Sanity-check yourself +### 12.6 Seeing what actually ran — the terminal flow + +The GitHub web UI for check runs is genuinely broken: if you click on a +row in the PR "Checks" tab, the page you land on is a **check-run page** +(`/runs/`), which shows only a status card — name, conclusion, and +a short summary — and nothing else. The "View more details on GitHub +Actions" link on that page usually points back at the same page, +because for auto-created check runs the API field `details_url` is set +to the check-run URL itself and there is no server-side redirect to the +underlying workflow run. The same is true of the "Details" button that +appears at the right edge of each row in the PR Checks table — it also +navigates to a check-run page, not to a job log page. + +This is not ProxySQL-specific; it is a long-standing GitHub UX papercut +affecting anyone whose workflows use matrix jobs + `LouisBrunner/checks-action` +or the GitHub-auto-created check runs. You will hit it every time you +try to investigate a CI failure from a PR. + +**The terminal saves you.** Given any row from `gh pr checks ` +output, four commands reach the actual log lines — no web navigation at +all. + +We will walk this on one concrete row. The row is the one from the PR +#5596 status output we used earlier in the session: + +``` +✓ CI-trigger/CI-legacy-g1 / tests (mysql57) (pull_request) 35m14s https://github.com/sysown/proxysql/runs/70903090156 +``` + +Reading the row character-by-character: + +``` +✓ CI-trigger/CI-legacy-g1 / tests (mysql57) (pull_request) 35m14s https://github.com/sysown/proxysql/runs/70903090156 +│ │ │ │ │ │ │ +│ │ │ │ │ │ └─ check-run URL (DEAD END — do NOT click) +│ │ │ │ │ └─ total wall time +│ │ │ │ └─ GitHub event that fired the cascade +│ │ │ └─ job + matrix cell inside the workflow +│ │ └─ the workflow that produced this check +│ └─ top-of-chain trigger workflow (the cascade starts at CI-trigger) +└─ status icon: ✓ success, ✗ failure, ○ queued, ● in_progress +``` + +Two things to extract: + +1. **Workflow name** = `CI-legacy-g1` (the piece after `CI-trigger/` and + before the first ` / `). +2. **The check-run URL is worthless.** You will not click it or use it + for navigation — it is the dead-end page. `gh pr checks` prints it + because the API returns it, not because it is useful. + +#### Step 1 — list recent runs of the workflow + +```bash +gh run list -R sysown/proxysql --workflow CI-legacy-g1 --limit 5 +``` + +Output (trimmed for width; full lines are tab-separated): + +``` +status concl display title workflow branch event run id duration +completed success v3.0_pgsql-copy-matcher-5568 CI-legacy-g1 09b97547fd19ad86045... CI-legacy-g1 v3.0 workflow_run 24281031512 41m21s +completed failure v3.0_pgsql-copy-matcher-5568 CI-legacy-g1 2abbc4f3135a57b819... CI-legacy-g1 v3.0 workflow_run 24279934338 1m8s +… +``` + +**The critical column is #3 — the display title.** Break it apart: + +``` +v3.0_pgsql-copy-matcher-5568 CI-legacy-g1 09b97547fd19ad86045783f63218fdcfa484a910 +│ │ │ +│ │ └─ full SHA of the PR commit you care about +│ └─ the workflow name +└─ the branch name of the PR +``` + +**Why column 6 (`branch`) is a liar.** It says `v3.0`, not +`v3.0_pgsql-copy-matcher-5568`. This is because `CI-legacy-g1` is fired +via a `workflow_run` chain, and GitHub records `workflow_run`-triggered +runs as belonging to the *default branch*, not the PR's branch. The +run's metadata `headSha` (not shown in the default column layout) is +also the v3.0 branch HEAD at cascade time, **not the PR commit**. This +is the documented gotcha in §10.2 ("workflow_run chains use the +triggering workflow's head_sha"). + +**The only place in this output where the actual PR commit SHA appears +is the display title**, because `CI-legacy-g1.yml`'s `run-name:` field +explicitly injects it: + +```yaml +run-name: '${{ github.event.workflow_run && github.event.workflow_run.head_branch || github.ref_name }} ${{ github.workflow }} ${{ github.event.workflow_run && github.event.workflow_run.head_sha || github.sha }}' +``` + +So to identify "which run belongs to my PR commit", **grep the display +title for the first 8-12 characters of the PR's head SHA**: + +```bash +gh run list -R sysown/proxysql --workflow CI-legacy-g1 --limit 20 \ + | grep 09b97547 +``` + +Or, for a scriptable extraction via `--json`: + +```bash +gh run list -R sysown/proxysql --workflow CI-legacy-g1 --limit 20 \ + --json databaseId,displayTitle,status,conclusion \ + -q '.[] | select(.displayTitle | contains("09b97547")) | "\(.databaseId)\t\(.status)/\(.conclusion)\t\(.displayTitle)"' +``` + +Either way, you get **run id 24281031512**. Note that number for the +next step. + +#### Step 2 — view the run's job tree + +```bash +gh run view 24281031512 -R sysown/proxysql +``` + +Output: + +``` +✓ v3.0 CI-legacy-g1 · 24281031512 +Triggered via workflow_run about 1 hour ago + +JOBS +✓ run / tests (mysql57) in 35m20s (ID 70902846188) + +ANNOTATIONS +! Node.js 20 actions are deprecated. … + +For more information about the job, try: gh run view --job=70902846188 +View this run on GitHub: https://github.com/sysown/proxysql/actions/runs/24281031512 +``` + +**Extract the job id:** `70902846188`. + +Notice the job name here is `run / tests (mysql57)` — **not** +`CI-legacy-g1 / tests (mysql57)` like the check-run row. The prefix +differs because check runs and jobs live in different namespaces +(see §12.1 and §12.4). Specifically: + +- **Job name** prefix `run /` comes from the caller stub on `v3.0`, + whose job is literally `jobs.run:`. +- **Check-run name** prefix `CI-legacy-g1 /` comes from the workflow's + `name:` field, used by `LouisBrunner/checks-action` as the first piece + of its `name:` template (see §12.4). + +The suffix `tests (mysql57)` comes from the reusable on `GH-Actions` +(the reusable has `jobs.tests:` with a `matrix.infradb: [mysql57]` +expansion), and both views agree on it because both read the same +reusable workflow. + +If the run has multiple jobs — e.g. a real six-cell matrix like +`CI-maketest` — each is listed here with its own id. Pick the one +whose name matches the row you started from. + +#### Step 3 — get the logs + +Three flavors, depending on what you want: + +```bash +# Only the steps that failed. This is what you reach for 95% of the time +# when investigating a red check. Useless here (job succeeded) but +# invaluable on real failures. +gh run view --log-failed --job=70902846188 -R sysown/proxysql + +# Full log of the whole job, every step. Pipe through less/grep/awk. +gh run view --log --job=70902846188 -R sysown/proxysql | less + +# Full log of the whole run (every job, every step). Use when you don't +# yet know which job has the answer. +gh run view 24281031512 -R sysown/proxysql --log +``` + +The log format is **tab-separated**: + +``` +\t\t +``` + +which means `awk -F'\t'` works naturally. A few idioms worth memorizing: + +```bash +# Only lines from the step you care about +gh run view --log --job=70902846188 -R sysown/proxysql \ + | awk -F'\t' '$2 == "Run legacy-g1 tests"' + +# TAP result markers only +gh run view --log --job=70902846188 -R sysown/proxysql \ + | grep -E '(^|\t)(ok|not ok|# ) ' + +# Just the tail +gh run view --log --job=70902846188 -R sysown/proxysql | tail -100 +``` + +#### The condensed cheat sheet + +From any row of `gh pr checks` to the actual log lines is this pattern. +Memorize it; the web UI is not going to help you. + +```bash +PR=5596 +REPO=sysown/proxysql +HEAD=$(gh pr view $PR -R $REPO --json headRefOid -q .headRefOid) + +# 1. Extract workflow name from the check row you care about. +# Example row from `gh pr checks`: +# "CI-trigger/CI-legacy-g1 / tests (mysql57)" → CI-legacy-g1 +WF=CI-legacy-g1 + +# 2. Find the run whose display title contains the PR head SHA. +RUN_ID=$(gh run list -R $REPO --workflow "$WF" --limit 20 \ + --json databaseId,displayTitle \ + -q ".[] | select(.displayTitle | contains(\"${HEAD:0:12}\")) | .databaseId" \ + | head -1) +echo "run id: $RUN_ID" + +# 3. Find the job id inside that run. +gh run view "$RUN_ID" -R $REPO +# → note the job id(s) printed under JOBS + +# 4. Get logs for the job. +JOB_ID=… # copy from step 3 output +gh run view --log-failed --job="$JOB_ID" -R $REPO +``` + +Four commands. Everything else (the `/runs/` URL, the +"Details" button, the "View more details on GitHub Actions" link, the +PR checks panel navigation) is noise you can ignore. + +#### Why the web UI cannot do this (short version) + +Three problems stacked on top of each other: + +1. **Check runs and workflow runs are different objects** in GitHub's + data model, attached to different endpoints, with different URL + shapes (`/runs/` for check runs, `/actions/runs//job/` + for job logs). There is no explicit `job_id` link on a check run — + you have to reconstruct the mapping by joining on `head_sha` + + `started_at` + `name`, which is what `gh` is implicitly doing under + the hood in step 2 above. +2. **`details_url` is self-referential** on auto-created check runs: + the field points at the check-run page itself rather than at the + underlying job log page, and there is no redirect. Clicking "View + more details on GitHub Actions" often just reloads the same page. +3. **For `workflow_run`-triggered cascades**, the workflow run's + top-level `headSha` is the default branch's HEAD, not the PR's + commit. So even tools that try to find "the workflow run for this + commit" by querying `gh run list --commit ` return nothing, + because no workflow run is tagged with that SHA as its metadata + `headSha`. The actual PR commit lives only in the `run-name` + string, which is why step 1 above searches `displayTitle`. + +All three issues together mean: **do not try to navigate from a check +row to a job log through the web UI**. Use the four-step terminal flow +every time. It is faster, more reliable, and leaves a command history +you can paste into PR reviews. + +### 12.7 Sanity-check yourself If you understand the vocabulary, you should be able to answer each of these in one sentence. Answers after each question. @@ -1516,10 +1774,22 @@ these in one sentence. Answers after each question. in the root `Makefile@v3.0`. The workflow picks the matrix value and invokes the Makefile target in docker-compose. -If those five answers feel comfortable, you can close this section. If -not, re-read the [nesting diagram](#122-the-full-nesting-visualized) and -then the [two-branch diagram](#123-the-proxysql-two-branch-split-visualized) -until they do. +6. **"I see the row `CI-trigger/CI-legacy-g1 / tests (mysql57)` in my + PR checks and it failed. What commands do I run in my terminal to + see the logs of the failing step?"** + → (a) `gh run list -R sysown/proxysql --workflow CI-legacy-g1 --limit 20` + and find the run whose display title contains the first 8-12 chars + of my PR's head SHA → record `RUN_ID`. (b) `gh run view $RUN_ID -R sysown/proxysql` + and note the job id under `JOBS`. (c) `gh run view --log-failed --job=$JOB_ID -R sysown/proxysql` + for the failed-step output. I do **not** touch the `/runs/` + URL from `gh pr checks`, nor the web UI "Details" button — both are + dead ends. + +If those six answers feel comfortable, you can close this section. If +not, re-read the [nesting diagram](#122-the-full-nesting-visualized) +and then the [two-branch diagram](#123-the-proxysql-two-branch-split-visualized) +until they do; if the last question stumped you, re-read +[§12.6 Seeing what actually ran](#126-seeing-what-actually-ran--the-terminal-flow). --- From 81b406a428610a20f03b550ebcb0ac5128c69b48 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Sat, 11 Apr 2026 13:15:27 +0000 Subject: [PATCH 3/3] =?UTF-8?q?doc(GH-Actions):=20address=20gemini=20revie?= =?UTF-8?q?w=20nits=20on=20=C2=A712=20vocabulary=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four minor corrections from the PR #5607 review: 1. §12 intro: "from issue" → "from the issue" (missing article) 2. §12.1.1: comma splice "(... — ProxySQL does exactly this, see #7 below)" → semicolon for grammatical correctness 3. §12.1.1 YAML example: replaced the `← ← ←` arrow annotations with `# <- ...` comments so the snippet is valid YAML if copy-pasted 4. §12.1.1: "has runs on 10 commits" → "has run on 10 commits" (past participle) No change to meaning or structure. The `←` arrows that remain in the ASCII box diagrams at §12.2 / §12.3 / §12.4 are untouched - those diagrams are illustrative text inside un-typed fenced blocks, not copy-pasteable code, and the gemini review only flagged the yaml-typed block. Coderabbit's "Critical" finding about anchor links using `--` instead of `-` is a false alarm: the em-dash in the §12 heading is stripped by GitHub's slugger, leaving two adjacent spaces which become two adjacent hyphens. I verified this by asking GitHub's own `/markdown` API to render the heading and inspecting the generated ``, which contains exactly `...vocabulary--read-this-first-if-confused` (double hyphen). No anchor fix is needed. --- doc/GH-Actions/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/GH-Actions/README.md b/doc/GH-Actions/README.md index c38007ccb5..9a105fc6c8 100644 --- a/doc/GH-Actions/README.md +++ b/doc/GH-Actions/README.md @@ -1005,9 +1005,9 @@ at the end. If you look at a PR "Checks" tab and can't answer *"what file on disk corresponds to this row, and why can't I find it by grepping?"*, read this section. -We will use **one concrete check label** throughout — the one from issue -that prompted this section — and walk it all the way down from "string on -the PR" to "YAML line on disk": +We will use **one concrete check label** throughout — the one from the +issue that prompted this section — and walk it all the way down from +"string on the PR" to "YAML line on disk": ``` CI-maketest / builds (testgalera) @@ -1030,13 +1030,13 @@ block listing its jobs. The workflow's **identity in the GitHub UI is the `name:` field**, not the filename. Two different files with the same `name:` will look like "the -same workflow" in the UI (this is important — ProxySQL does exactly this, +same workflow" in the UI (this is important — ProxySQL does exactly this; see #7 below). Concrete example — `.github/workflows/ci-maketest.yml` on branch `GH-Actions`: ```yaml -name: CI-maketest ← ← ← this is the workflow name +name: CI-maketest # <- this is the workflow name on: workflow_dispatch: workflow_call: @@ -1046,7 +1046,7 @@ on: target: type: string jobs: - builds: ← there is exactly one job: "builds" + builds: # <- there is exactly one job: "builds" runs-on: ubuntu-22.04 strategy: matrix: @@ -1057,7 +1057,7 @@ jobs: ``` This file *is* a workflow. It will stay a workflow whether it ever runs or -not, whether it has runs on 10 commits or zero commits. It is an +not, whether it has run on 10 commits or zero commits. It is an **immutable object at rest on disk**. #### 2. Workflow run — one execution of a workflow