Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ jobs:
typecheck: true
coverage: true
coverage-min: '80'
pytest_args: "-n auto --dist loadscope"
secrets: inherit
9 changes: 5 additions & 4 deletions .github/workflows/pr-00-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ jobs:
uses: stranske/Workflows/.github/workflows/reusable-10-ci-python.yml@main
with:
python-versions: '["3.11"]'
coverage-min: "80"
# PR Gate is optimized for fast feedback. Full coverage enforcement runs on main.
coverage: false
format_check: false # Using ruff for formatting
# Keep PR feedback fast by skipping heavy integration suites here.
# Full test coverage remains enforced on main branch CI.
pytest_args: "--ignore=tests/integration --ignore=tests/integrations"
pytest_markers: "not release"
pytest_args: "-n auto --dist loadscope --ignore=tests/integration --ignore=tests/integrations"
working-directory: "."
artifact-prefix: "gate-"
# Enable soft coverage gate for trend tracking and hotspot reporting
enable-soft-gate: true
enable-soft-gate: false
secrets: inherit

summary:
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/release-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Runs slow release/packaging validation outside the PR Gate critical path.
# Trigger modes:
# - Nightly schedule (main branch)
# - Manual dispatch
# - PR label "run-release" (runs against PR head SHA)

name: Release E2E

on:
schedule:
- cron: "15 3 * * *" # ~03:15 UTC nightly
workflow_dispatch:
pull_request:
types: [labeled]

concurrency:
group: release-e2e-${{ github.event.pull_request.number || github.ref_name }}
cancel-in-progress: true

jobs:
release-tests:
name: Release / Packaging Tests
if: >-
${
github.event_name != 'pull_request' ||
github.event.label.name == 'run-release'
}
Comment thread
stranske marked this conversation as resolved.
Outdated
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"

- name: Install dependencies
run: |
set -euo pipefail
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -e "[dev]"
Comment thread
stranske marked this conversation as resolved.
Outdated

- name: Run release-marked tests
run: |
set -euo pipefail
pytest -q -m release --durations=10
32 changes: 32 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,38 @@ Never silently drop exposures. If a new counterparty appears and there is no mat
- Do not edit `.github/workflows/**` unless explicitly operating under a high-privilege environment and the task requires it.
- If workflow changes are needed, fix them in **stranske/Workflows** then sync.

## CI test situation (what runs when)

This repo is tuned so PR Gate stays reasonably fast by skipping the most expensive suites.

### PR Gate

PR Gate uses `.github/workflows/pr-00-gate.yml`:

- Runs pytest **in parallel** with xdist (`-n auto --dist loadscope`).
- Runs pytest **without coverage**.
- Skips `tests/integration/` and `tests/integrations/`.
- Skips `release`-marked tests (`pytest_markers: "not release"`).

### Main CI (push to `main`)

Main CI uses `.github/workflows/ci.yml`:

- Runs pytest **with coverage** and enforces `coverage-min`.
- Runs pytest **in parallel** with xdist.
- Runs the full test suite.

### Release tests (nightly or label)

The slowest release/packaging checks are isolated behind the `release` marker and can be triggered via:

- Nightly schedule (`.github/workflows/release-e2e.yml`)
- PR label: `run-release`

### Agent guidance

When a PR touches release/packaging mechanics (e.g., `release.spec`, `pyinstaller_runtime_hook.py`, templates/config bundling), make sure `release` tests run by applying the `run-release` label.

## Agent guardrails (must follow)

- Also read: `.github/codex/AGENT_INSTRUCTIONS.md`
Expand Down
47 changes: 47 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,53 @@ When an issue is labeled `agent:codex`:

## Common Issues

## CI Test Policy (PR Gate vs CI vs Release E2E)

This repo intentionally does **not** run the full test surface area on every PR Gate run.

### PR Gate (`.github/workflows/pr-00-gate.yml`)

Goal: fast feedback for most PRs.

- Runs pytest **in parallel** (xdist): `-n auto --dist loadscope`
- Runs pytest **without coverage** (`coverage: false`)
- Skips integration directories:
- `tests/integration/`
- `tests/integrations/`
- Skips **release/packaging** tests via marker: `pytest_markers: "not release"`

These suites will NOT run on PR Gate unless you run them manually (see below).

### Main-branch CI (`.github/workflows/ci.yml`)

Goal: enforce full quality gates on `main`.

- Runs pytest **with coverage** (`coverage: true`, `coverage-min` enforced)
- Runs pytest **in parallel** (xdist): `-n auto --dist loadscope`
- Runs the full test suite (including integration dirs and `release` tests)

### Release/Packaging E2E (`.github/workflows/release-e2e.yml`)

Goal: keep slow PyInstaller + packaged-executable checks out of PR Gate.

- Runs nightly on `main`
- Runs on PRs when the PR is labeled: `run-release`
- Executes only the tests marked `release`: `pytest -m release`

### How to run skipped suites locally

```bash
# Fast PR-gate-like run (parallel, no coverage, skip release + integration dirs)
pytest -q -n auto --dist loadscope -m "not release" \
--ignore=tests/integration --ignore=tests/integrations

# Release / packaging validation (PyInstaller + packaged executable)
pytest -q -m release

# Integration directories (if you need them on a PR)
pytest -q tests/integration tests/integrations
```

### Workflow fails with "workflow file issue"
- A reusable workflow is being called that doesn't exist
- Check Workflows repo has the required `reusable-*.yml` file
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ app = []
dev = [
"pytest==9.0.2",
"pytest-cov==7.0.0",
"pytest-xdist==3.8.0",
"pandas>=2.2,<3",
"black==24.10.0",
"ruff==0.15.1",
Expand All @@ -55,6 +56,9 @@ pythonpath = ["src"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
"release: slow release/packaging tests (PyInstaller build + packaged executable)",
]

[tool.coverage.run]
source = ["src"]
Expand Down
71 changes: 59 additions & 12 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
@@ -1,46 +1,93 @@
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml --extra dev --universal --output-file requirements-dev.lock
colorama==0.4.6 ; sys_platform == 'win32'
# via pytest
annotated-types==0.7.0
# via pydantic
black==24.10.0
# via my-project (pyproject.toml)
click==8.3.1
# via black
colorama==0.4.6 ; sys_platform == 'win32'
# via
# click
# pytest
coverage==7.13.4
# via pytest-cov
et-xmlfile==2.0.0
# via openpyxl
execnet==2.1.2
# via pytest-xdist
iniconfig==2.3.0
# via pytest
librt==0.8.0 ; platform_python_implementation != 'PyPy'
# via mypy
lxml==6.0.2
# via python-pptx
mypy==1.19.1
# via my-project (pyproject.toml)
mypy-extensions==1.1.0
# via mypy
# via
# black
# mypy
numpy==2.4.2
# via pandas
openpyxl==3.1.5
# via my-project (pyproject.toml)
packaging==25.0
# via pytest
# via
# black
# pytest
pandas==2.2.3
# via my-project (pyproject.toml)
pathspec==0.12.1
# via mypy
pydantic==2.7.4
# via my-project (pyproject.toml)
python-pptx==1.0.2
# via my-project (pyproject.toml)
pyyaml==6.0.2
# via my-project (pyproject.toml)
# via
# black
# mypy
pillow==12.1.1
# via python-pptx
platformdirs==4.9.1
# via black
pluggy==1.6.0
# via
# pytest
# pytest-cov
pydantic==2.7.4
# via my-project (pyproject.toml)
pydantic-core==2.18.4
# via pydantic
pygments==2.19.2
# via pytest
pytest==9.0.2
# via
# my-project (pyproject.toml)
# pytest-cov
# pytest-xdist
pytest-cov==7.0.0
# via my-project (pyproject.toml)
pytest-xdist==3.8.0
# via my-project (pyproject.toml)
python-dateutil==2.9.0.post0
# via pandas
python-pptx==1.0.2
# via my-project (pyproject.toml)
pytz==2025.2
# via pandas
pyyaml==6.0.2
# via my-project (pyproject.toml)
ruff==0.15.1
# via my-project (pyproject.toml)
six==1.17.0
# via python-dateutil
tomli==2.4.0 ; python_full_version <= '3.11'
# via coverage
tomlkit==0.13.3
# via my-project (pyproject.toml)
typing-extensions==4.15.0
# via mypy
# via
# mypy
# pydantic
# pydantic-core
# python-pptx
tzdata==2025.3
# via pandas
xlsxwriter==3.2.9
# via python-pptx
Loading
Loading