Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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'
}}
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]"

- 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