From 7050f3832e3c2730f41066e5f569374552d73b2b Mon Sep 17 00:00:00 2001 From: Dani Date: Fri, 4 Sep 2026 03:42:20 -0400 Subject: [PATCH 1/2] ci: run the floor as well as the latest Python MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI has only ever run one interpreter — 3.14 — while the package declared a different one. That is how 1.0.0 and both 1.1.0 release candidates shipped a `python_requires` nobody had ever executed (in fact they shipped none at all: the constant was defined in the template and never passed to setup()). 1.1.0 fixes the metadata and sets the floor to 3.12, so run 3.12 alongside 3.14 and let the promise be tested. fail-fast is off so a break on one version still reports the other. Keep the matrix in step with templates/setup.mustache in the SDK factory. --- .github/workflows/ci.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cbdf812..35d48a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,14 @@ permissions: jobs: build: runs-on: ubuntu-latest + strategy: + fail-fast: false + # Floor + latest. The floor is the version setup.py's `python_requires` + # promises (>=3.12): a promise nothing runs is how 1.0.0 and both release + # candidates shipped a Requires-Python they had never tested. Keep this in + # step with templates/setup.mustache in the factory. + matrix: + python-version: ["3.12", "3.14"] steps: - uses: actions/checkout@v5 @@ -31,7 +39,7 @@ jobs: - uses: actions/setup-python@v6 if: steps.detect.outputs.has_pkg == 'true' with: - python-version: "3.14" + python-version: ${{ matrix.python-version }} - name: Install if: steps.detect.outputs.has_pkg == 'true' From c3e78106dc4df35a76bdb7439d94410bc93c2706 Mon Sep 17 00:00:00 2001 From: Dani Date: Fri, 4 Sep 2026 15:07:19 -0400 Subject: [PATCH 2/2] ci: keep `build` as a stable check name for branch protection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turning the job into a matrix renamed it: `build` became `build (3.12)` and `build (3.14)`. The v1 ruleset requires a check literally named `build`, so that check stopped existing and every PR blocked waiting for a report that could never arrive — this PR included. Rename the matrix job to `test` and add a one-step `build` job that gates on its aggregate result. Branch protection keeps pointing at one name, and the matrix can grow or shrink without anyone editing the ruleset. `if: always()` so the gate reports a failure rather than being skipped when a leg fails. --- .github/workflows/ci.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35d48a8..38cbe73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ permissions: contents: read jobs: - build: + test: runs-on: ubuntu-latest strategy: fail-fast: false @@ -144,3 +144,19 @@ jobs: run: | python -m pip install --upgrade build python -m build + + # Aggregate gate. Branch protection pins required checks BY NAME, and a matrix + # job reports as `test (3.12)` / `test (3.14)` — never as a single stable name. + # Without this job the required `build` check simply never arrives and the PR + # blocks forever; with it, the matrix can grow or shrink without anyone editing + # the ruleset. + build: + needs: [test] + if: always() + runs-on: ubuntu-latest + steps: + - name: Gate on the matrix result + run: | + echo "matrix result: ${{ needs.test.result }}" + [ "${{ needs.test.result }}" = "success" ] || { + echo "::error::one or more Python versions failed"; exit 1; }