Skip to content

Add compact inventory for spec-loop prompts (#702) #1606

Add compact inventory for spec-loop prompts (#702)

Add compact inventory for spec-loop prompts (#702) #1606

Workflow file for this run

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
---
name: tests
on: # yamllint disable-line rule:truthy
pull_request:
push:
branches: [main]
permissions: {}
jobs:
# Discover workspace members from the root pyproject.toml so the
# pytest matrix below is data-driven — adding a new tool is a
# one-line edit to `[tool.uv.workspace] members` and the matrix
# picks it up automatically.
members:
name: list-workspace-members
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
members: ${{ steps.list.outputs.members }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- id: list
# Emit the workspace members as a JSON array of {name,path}
# objects so the matrix below can both label jobs by name
# AND pass the path to `uv run --directory`. The `pytest`
# filter mirrors the auto-discovery rule in
# `tools/dev/run-workspace-check.sh`: only members with a
# `[tool.pytest.ini_options]` section get pytest jobs, and
# an explicit `[tool.magpie.checks] skip = [..., "pytest"]`
# opts out.
run: |
members=$(python3 <<'PY'
import json
import sys
import tomllib
with open("pyproject.toml", "rb") as f:
root = tomllib.load(f)
paths = root["tool"]["uv"]["workspace"]["members"]
out = []
for path in paths:
with open(f"{path}/pyproject.toml", "rb") as f:
data = tomllib.load(f)
tool = data.get("tool", {})
if "ini_options" not in tool.get("pytest", {}):
continue
skip = tool.get("magpie", {}).get("checks", {}).get("skip", [])
if "pytest" in skip:
continue
out.append({"name": path.split("/")[-1], "path": path})
# Sort for deterministic CI ordering.
out.sort(key=lambda x: x["name"])
print(json.dumps(out))
PY
)
echo "members=${members}" >> "$GITHUB_OUTPUT"
echo "Discovered workspace members for pytest matrix:"
echo "${members}" | python3 -m json.tool
# Per-member pytest matrix. Each Python project under tools/ that
# is a uv-workspace member with a `[tool.pytest.ini_options]`
# section gets its own job. Running them as separate matrix jobs
# surfaces per-project pass/fail in the CI checks list, which is
# easier to triage than the bundled `workspace-pytest` line inside
# the `prek` workflow's output. The `prek` workflow still
# exercises pytest as a hook, so this workflow is the visible
# signal — not the gate.
pytest:
name: "pytest (${{ matrix.project.name }})"
runs-on: ubuntu-latest
needs: members
permissions:
contents: read
strategy:
fail-fast: false
matrix:
project: ${{ fromJSON(needs.members.outputs.members) }}
# GitHub Actions log viewer renders ANSI colour escapes; without
# an attached TTY most tools default to monochrome. `FORCE_COLOR`
# is the de-facto signal honoured by uv, ruff, mypy, and pytest's
# own auto-detection. Belt-and-braces — the explicit
# `--color=yes` on the pytest invocation below covers tools that
# don't read `FORCE_COLOR`.
env:
FORCE_COLOR: "1"
PY_COLORS: "1"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
# uv brings its own Python and reads each project's
# `pyproject.toml` + the workspace `uv.lock`. Minimum uv
# version is enforced by the root `pyproject.toml`'s
# `[tool.uv] required-version`.
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
- name: Sync workspace (installs ruff / mypy / pytest from root dev group)
# Dev-group deps live in the root pyproject (`[dependency-groups]
# dev`) and only land in the shared workspace `.venv` when an
# explicit `--group dev` sync runs. `--all-packages` ensures
# every workspace member is installed too (the root has
# `package = false`, so without it members and their
# `[project.scripts]` entry points would be skipped).
run: uv sync --all-packages --group dev
- name: Run pytest
# `--directory` (not `--project`) — both move uv's project
# context, but `--directory` also changes cwd, which pytest
# needs because each project's `pyproject.toml` declares
# `testpaths = ["tests"]` relative to its own root. No
# `--group` flag here because the sync above already
# installed the dev tools into the shared workspace venv.
run: uv run --directory ${{ matrix.project.path }} pytest --color=yes
# Umbrella status check. `.asf.yaml`'s `required_status_checks`
# cannot use patterns or wildcards (GitHub's branch-protection and
# rulesets APIs both require exact context names), so a matrix job
# with N entries would otherwise force N `.asf.yaml` lines that
# must be kept in lock-step with the matrix. This single
# `tests-ok` job is the only pytest-related context required by
# branch protection — it passes iff every entry in the `pytest`
# matrix above passed. Adding, renaming, or removing matrix
# entries no longer touches `.asf.yaml`.
tests-ok:
name: tests-ok
runs-on: ubuntu-latest
needs: pytest
# `always()` — without it, this job would be skipped (not
# failed) when an upstream matrix entry fails, and a skipped
# required-check is treated as missing by branch protection,
# which leaves the PR mergeable. Run unconditionally and assert
# on the result instead.
if: always()
steps:
- name: Assert all pytest matrix entries succeeded
run: |
if [ "${{ needs.pytest.result }}" != "success" ]; then
echo "pytest matrix result: ${{ needs.pytest.result }}"
exit 1
fi
echo "all pytest matrix entries passed"