pytest-selective 0.4.1__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytest_selective-1.0.0/.dry-lint/baseline.json +80 -0
- pytest_selective-1.0.0/.dry-lint/progress.json +7 -0
- pytest_selective-1.0.0/.dry-lint.toml +6 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/test-lanes.json +28 -2
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/workflows/ci.yml +55 -15
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/workflows/docs.yml +3 -3
- pytest_selective-1.0.0/.github/workflows/dry-lint-audit.yml +91 -0
- pytest_selective-1.0.0/.github/workflows/dry-lint-judge.yml +30 -0
- pytest_selective-1.0.0/.github/workflows/dry-lint.yml +41 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/workflows/pr-title.yml +1 -1
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/workflows/public-actions.yml +6 -2
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/workflows/release-please.yml +2 -2
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/workflows/release.yml +8 -4
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/workflows/windows-performance.yml +11 -7
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.gitignore +6 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.pre-commit-config.yaml +12 -0
- pytest_selective-1.0.0/.release-please-manifest.json +3 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/AGENTS.md +10 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/CHANGELOG.md +22 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/CONTRIBUTING.md +103 -3
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/PKG-INFO +47 -2
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/README.md +46 -1
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/RELEASING.md +23 -1
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/actions/plan-lanes/action.yml +2 -2
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/actions/test-impact/action.yml +4 -4
- pytest_selective-1.0.0/contracts/selection/README.md +33 -0
- pytest_selective-1.0.0/contracts/selection/conftest.py +297 -0
- pytest_selective-1.0.0/contracts/selection/quint-connect.json +107 -0
- pytest_selective-1.0.0/contracts/selection/quint.ini +8 -0
- pytest_selective-1.0.0/contracts/selection/selection.qnt +336 -0
- pytest_selective-1.0.0/contracts/selection/selection_driver.py +112 -0
- pytest_selective-1.0.0/contracts/selection/test_selection_contract.py +4 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/ci-toolkit.md +5 -1
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/ci.md +12 -1
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/configuration.md +12 -1
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/local-development.md +5 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/tutorials/adoption-checklist.md +5 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/tutorials/skip-unrelated-ci.md +33 -0
- pytest_selective-1.0.0/docs/work-in-progress/tickets/graph-based-inputs-plan.md +58 -0
- pytest_selective-1.0.0/docs/work-in-progress/tickets/ratchet-duplicates-zero-test-plan.md +18 -0
- pytest_selective-1.0.0/documentation/requirements.in +2 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/documentation/requirements.txt +5 -5
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/pyproject.toml +3 -1
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/skills/pytest-selective/SKILL.md +8 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/skills/pytest-selective/references/adoption.md +3 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/ast_imports.py +26 -2
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/ci.py +9 -4
- pytest_selective-1.0.0/src/pytest_selective/git_operations.py +49 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/hygiene.py +3 -10
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_audit_plugin.py +1 -6
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_first_party.py +4 -11
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_graph.py +134 -46
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_models.py +3 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_name_scope.py +1 -5
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/pytest_expansion.py +21 -70
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/typecheck_scope.py +4 -7
- pytest_selective-1.0.0/src/pytest_selective/working_tree.py +41 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_hygiene.py +8 -0
- pytest_selective-1.0.0/tests/test_release_workflow.py +36 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_repository_ci.py +90 -29
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_ci.py +53 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_impact_graph.py +69 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_portability.py +3 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_typecheck_scope.py +20 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_working_tree.py +78 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/uv.lock +170 -150
- pytest_selective-0.4.1/.release-please-manifest.json +0 -3
- pytest_selective-0.4.1/documentation/requirements.in +0 -2
- pytest_selective-0.4.1/src/pytest_selective/working_tree.py +0 -43
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.gitattributes +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/dependabot.yml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.github/workflows/observe-ci.yml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/.readthedocs.yaml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/CLAUDE.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/LICENSE +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/PROVENANCE.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/action.yml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/actions/README.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/actions/pytest-expansion/action.yml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/agentsync.toml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/README.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/actions.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/agents.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/assets/banner.png +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/assets/banner.svg +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/assets/brand.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/assets/icon.png +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/assets/logo.svg +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/assets/raster-sources.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/assets/social-preview.png +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/assets/social-preview.svg +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-due-ci.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-due-docs-ci.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-due-docs-widget.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-due-widget.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-input-replays.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-obligation-docs.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-obligation.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-routing.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22-selective-docs.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-22.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor/obligation-baseline.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after-3.11.xml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after-3.14.xml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control-3.11.xml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control-3.14.xml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-earlier.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/2026-10-23-windows-saleor.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/benchmarks/windows-runtime.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/comparison-pytest-impacted.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/evidence.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/pytest-hygiene.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/selection-health.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/tutorial.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/tutorials/sidecar-dependencies.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/work-in-progress/tickets/actions-directory-test-plan.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/work-in-progress/tickets/codex-selector-correctness-performance-test-plan.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/work-in-progress/tickets/codex-windows-git-performance-test-plan.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/work-in-progress/tickets/impacted-improvements-test-plan.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/work-in-progress/tickets/move-action-implementations-test-plan.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/work-in-progress/tickets/public-action-onboarding-test-plan.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/docs/work-in-progress/tickets/rerun-selection-test-plan.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/documentation/assets/routing-comparison.svg +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/documentation/check_site.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/documentation/ecosystem.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/documentation/hooks.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/documentation/index.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/documentation/overrides/main.html +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/documentation/publishing.md +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/mkdocs.yml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/release-please-config.json +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/benchmark_graph.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/benchmark_parsing.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/benchmark_rust.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/check_docs.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/check_metadata.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/ci_file_config.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/compare_impacted.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/measure_ci_runs.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/public_actions.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/render_brand.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/run_ci_tests.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/smoke_distribution.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/scripts/tutorial.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/skills/pytest-selective/agents/openai.yaml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/__init__.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/__main__.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/checkpoint.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_audit.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_cli.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_declarations.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_explanation.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/impact_selection.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/input_policy.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/local.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/parse_batch.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/plugin.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/py.typed +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/pytest_plugins.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/pytest_sharding.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/src/pytest_selective/test_inventory.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/__init__.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_checkpoint_policy.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_ci_admission.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_ci_measurements.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_ci_test_execution.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_distribution_metadata.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_public_actions.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_pytest_expansion.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_repository_hygiene.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_repository_hygiene.py.gv-dependency.yaml +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/test_tutorial.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/__init__.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/git_repo.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_ast_imports.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_git_repo.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_global_inputs.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_impact_audit.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_impact_explanation.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_impact_first_party.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_impact_name_scope.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_parse_batch.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_pytest_plugin.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_pytest_plugins.py +0 -0
- {pytest_selective-0.4.1 → pytest_selective-1.0.0}/tests/testing/test_pytest_sharding.py +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"contract": "fbf56a4a852e47539b956057d11e9f3ee56a986bbb3b26ac209dc491d4b45f6e",
|
|
4
|
+
"started_at": "fee809549a83ddfb432cb6599ea57ae73efbe66a",
|
|
5
|
+
"checked_at": "031cafd1748babfecff2ef2629a0320715d8fe9c",
|
|
6
|
+
"entries": [
|
|
7
|
+
{
|
|
8
|
+
"hashes": {
|
|
9
|
+
"src/pytest_selective/hygiene.py::discover_test_modules": "49e17f87bfe24aeb",
|
|
10
|
+
"src/pytest_selective/test_inventory.py::discover_test_files": "567e0cacf263d340"
|
|
11
|
+
},
|
|
12
|
+
"context_hash": "",
|
|
13
|
+
"state": "cleaned"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"hashes": {
|
|
17
|
+
"src/pytest_selective/impact_graph.py::within": "5417d89a2cedc5ea",
|
|
18
|
+
"src/pytest_selective/typecheck_scope.py::_under": "221f42a33c38887c"
|
|
19
|
+
},
|
|
20
|
+
"context_hash": "",
|
|
21
|
+
"state": "cleaned"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"hashes": {
|
|
25
|
+
"src/pytest_selective/impact_audit_plugin.py::_git": "be715e103f83b281",
|
|
26
|
+
"src/pytest_selective/impact_graph.py::git": "a53bf9a83105b354"
|
|
27
|
+
},
|
|
28
|
+
"context_hash": "",
|
|
29
|
+
"state": "cleaned"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"hashes": {
|
|
33
|
+
"src/pytest_selective/impact_audit_plugin.py::_git": "be715e103f83b281",
|
|
34
|
+
"src/pytest_selective/pytest_expansion.py::git": "42cac77499ad42b1"
|
|
35
|
+
},
|
|
36
|
+
"context_hash": "",
|
|
37
|
+
"state": "cleaned"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"hashes": {
|
|
41
|
+
"src/pytest_selective/impact_first_party.py::_module_name": "c214530cc8698c18",
|
|
42
|
+
"src/pytest_selective/pytest_expansion.py::SourceTree.module_name": "633b2e80dfaac9e6"
|
|
43
|
+
},
|
|
44
|
+
"context_hash": "",
|
|
45
|
+
"state": "cleaned"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"hashes": {
|
|
49
|
+
"src/pytest_selective/impact_graph.py::git": "a53bf9a83105b354",
|
|
50
|
+
"src/pytest_selective/pytest_expansion.py::git": "42cac77499ad42b1"
|
|
51
|
+
},
|
|
52
|
+
"context_hash": "",
|
|
53
|
+
"state": "cleaned"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"hashes": {
|
|
57
|
+
"src/pytest_selective/impact_graph.py::git_environment": "1b32a738ac740022",
|
|
58
|
+
"src/pytest_selective/pytest_expansion.py::git_environment": "df7139fadaa213a9"
|
|
59
|
+
},
|
|
60
|
+
"context_hash": "",
|
|
61
|
+
"state": "cleaned"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"hashes": {
|
|
65
|
+
"src/pytest_selective/impact_name_scope.py::_casefold": "9ecabff1de943de2",
|
|
66
|
+
"src/pytest_selective/impact_graph.py::ModuleIndex.resolve": "a1089dfe99f751cd"
|
|
67
|
+
},
|
|
68
|
+
"context_hash": "",
|
|
69
|
+
"state": "cleaned"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"hashes": {
|
|
73
|
+
"src/pytest_selective/impact_name_scope.py::_casefold": "9ecabff1de943de2",
|
|
74
|
+
"src/pytest_selective/impact_graph.py::ModuleIndex.__init__": "84c3976fe798fb7e"
|
|
75
|
+
},
|
|
76
|
+
"context_hash": "",
|
|
77
|
+
"state": "cleaned"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
"test_roots": [
|
|
8
8
|
"tests"
|
|
9
9
|
],
|
|
10
|
+
"global_inputs": [
|
|
11
|
+
"pyproject.toml",
|
|
12
|
+
"uv.lock",
|
|
13
|
+
".python-version"
|
|
14
|
+
],
|
|
10
15
|
"pytest_policy": {
|
|
11
16
|
"pyproject.toml": "7a78d68735c0e3b091962244620d3a17557951123c645970638f15d3a737d987"
|
|
12
17
|
}
|
|
@@ -20,6 +25,27 @@
|
|
|
20
25
|
"src/**",
|
|
21
26
|
"tests/**"
|
|
22
27
|
]
|
|
28
|
+
},
|
|
29
|
+
"contracts": {
|
|
30
|
+
"roots": [
|
|
31
|
+
"contracts"
|
|
32
|
+
],
|
|
33
|
+
"inputs": [
|
|
34
|
+
"src/**",
|
|
35
|
+
"contracts/**",
|
|
36
|
+
"tests/testing/git_repo.py"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"package": {
|
|
40
|
+
"inputs": [
|
|
41
|
+
"src/**",
|
|
42
|
+
"pyproject.toml",
|
|
43
|
+
"uv.lock",
|
|
44
|
+
"README.md",
|
|
45
|
+
"LICENSE",
|
|
46
|
+
"scripts/check_metadata.py",
|
|
47
|
+
"scripts/smoke_distribution.py"
|
|
48
|
+
]
|
|
23
49
|
}
|
|
24
50
|
},
|
|
25
51
|
"global_inputs": [
|
|
@@ -33,9 +59,9 @@
|
|
|
33
59
|
".github/test-lanes.json",
|
|
34
60
|
".github/workflows/ci.yml",
|
|
35
61
|
".github/workflows/release.yml",
|
|
36
|
-
"actions
|
|
62
|
+
"actions/*/*",
|
|
63
|
+
"actions/*.py",
|
|
37
64
|
"action.yml",
|
|
38
|
-
"examples/**",
|
|
39
65
|
".github/workflows/public-actions.yml"
|
|
40
66
|
]
|
|
41
67
|
}
|
|
@@ -6,6 +6,8 @@ on:
|
|
|
6
6
|
types: [opened, synchronize, reopened]
|
|
7
7
|
workflow_dispatch:
|
|
8
8
|
workflow_call:
|
|
9
|
+
schedule:
|
|
10
|
+
- cron: '13 3 * * 1'
|
|
9
11
|
permissions:
|
|
10
12
|
contents: read
|
|
11
13
|
concurrency:
|
|
@@ -20,7 +22,7 @@ jobs:
|
|
|
20
22
|
mode: ${{ steps.files.outputs.mode }}
|
|
21
23
|
files: ${{ steps.files.outputs.test_roots_json }}
|
|
22
24
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
25
|
+
- uses: actions/checkout@v7
|
|
24
26
|
with:
|
|
25
27
|
fetch-depth: 0
|
|
26
28
|
- id: plan
|
|
@@ -41,11 +43,14 @@ jobs:
|
|
|
41
43
|
quality:
|
|
42
44
|
runs-on: ubuntu-latest
|
|
43
45
|
steps:
|
|
44
|
-
- uses: actions/checkout@
|
|
46
|
+
- uses: actions/checkout@v7
|
|
45
47
|
- uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
|
|
46
48
|
with:
|
|
47
49
|
python-version: '3.14'
|
|
50
|
+
# Semantic judging owns its credentials and fork boundary in the required dry-lint job.
|
|
48
51
|
- run: uv run --locked pre-commit run --all-files
|
|
52
|
+
env:
|
|
53
|
+
SKIP: dry-lint
|
|
49
54
|
- name: Check aggregate gate against the execution lanes
|
|
50
55
|
run: >-
|
|
51
56
|
uv run --no-project --python 3.14
|
|
@@ -65,7 +70,7 @@ jobs:
|
|
|
65
70
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
66
71
|
runs-on: ${{ matrix.os }}
|
|
67
72
|
steps:
|
|
68
|
-
- uses: actions/checkout@
|
|
73
|
+
- uses: actions/checkout@v7
|
|
69
74
|
- uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
|
|
70
75
|
with:
|
|
71
76
|
python-version: ${{ matrix.python }}
|
|
@@ -89,13 +94,12 @@ jobs:
|
|
|
89
94
|
with:
|
|
90
95
|
junit-pattern: test-timings.xml
|
|
91
96
|
artifact-name: test-timings-${{ matrix.python }}-${{ matrix.os }}
|
|
92
|
-
|
|
93
|
-
- uses: actions/upload-artifact@
|
|
97
|
+
# tests/test_tutorial.py owns the end-to-end tutorial and follows the file plan.
|
|
98
|
+
- uses: actions/upload-artifact@v7
|
|
99
|
+
if: ${{ hashFiles('coverage.xml') != '' }}
|
|
94
100
|
with:
|
|
95
101
|
name: evidence-${{ matrix.os }}-${{ matrix.python }}
|
|
96
|
-
path:
|
|
97
|
-
coverage.xml
|
|
98
|
-
tutorial-report.json
|
|
102
|
+
path: coverage.xml
|
|
99
103
|
pytest-minimum:
|
|
100
104
|
needs: select-tests
|
|
101
105
|
if: >-
|
|
@@ -103,7 +107,7 @@ jobs:
|
|
|
103
107
|
fromJSON(needs.select-tests.outputs.lanes).tests) }}
|
|
104
108
|
runs-on: ubuntu-latest
|
|
105
109
|
steps:
|
|
106
|
-
- uses: actions/checkout@
|
|
110
|
+
- uses: actions/checkout@v7
|
|
107
111
|
- uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
|
|
108
112
|
with:
|
|
109
113
|
python-version: '3.11'
|
|
@@ -116,11 +120,13 @@ jobs:
|
|
|
116
120
|
CI_TEST_FILES: ${{ needs.select-tests.outputs.files }}
|
|
117
121
|
distributions:
|
|
118
122
|
needs: select-tests
|
|
119
|
-
#
|
|
120
|
-
if:
|
|
123
|
+
# The package lane includes the embedded README and LICENSE; planner failure must not skip it.
|
|
124
|
+
if: >-
|
|
125
|
+
${{ always() && !cancelled() && (needs.select-tests.result != 'success' ||
|
|
126
|
+
fromJSON(needs.select-tests.outputs.lanes).package) }}
|
|
121
127
|
runs-on: ubuntu-latest
|
|
122
128
|
steps:
|
|
123
|
-
- uses: actions/checkout@
|
|
129
|
+
- uses: actions/checkout@v7
|
|
124
130
|
- uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
|
|
125
131
|
with:
|
|
126
132
|
python-version: '3.14'
|
|
@@ -132,15 +138,49 @@ jobs:
|
|
|
132
138
|
${{ needs.select-tests.result != 'success' ||
|
|
133
139
|
fromJSON(needs.select-tests.outputs.lanes).tests }}
|
|
134
140
|
run: uv run --locked python scripts/smoke_distribution.py
|
|
135
|
-
- uses: actions/upload-artifact@
|
|
141
|
+
- uses: actions/upload-artifact@v7
|
|
136
142
|
with:
|
|
137
143
|
name: distributions
|
|
138
144
|
path: dist/*
|
|
139
145
|
if-no-files-found: error
|
|
140
146
|
|
|
147
|
+
selection-contract:
|
|
148
|
+
name: Selection contract (Quint)
|
|
149
|
+
needs: select-tests
|
|
150
|
+
permissions:
|
|
151
|
+
contents: read
|
|
152
|
+
# The contract report's pull-request comment.
|
|
153
|
+
pull-requests: write
|
|
154
|
+
if: >-
|
|
155
|
+
${{ always() && !cancelled() && (needs.select-tests.result != 'success' ||
|
|
156
|
+
fromJSON(needs.select-tests.outputs.lanes).contracts) }}
|
|
157
|
+
runs-on: ubuntu-latest
|
|
158
|
+
steps:
|
|
159
|
+
- uses: actions/checkout@v7
|
|
160
|
+
- uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
|
|
161
|
+
with:
|
|
162
|
+
python-version: '3.14'
|
|
163
|
+
# pytest-quint-connect installs its locked Quint with npm on first use.
|
|
164
|
+
- uses: actions/setup-node@v7
|
|
165
|
+
with:
|
|
166
|
+
node-version: '24'
|
|
167
|
+
- name: Check the generated driver against the model
|
|
168
|
+
run: uv run --locked --group quint pytest-quint-connect codegen --check contracts/selection/quint-connect.json
|
|
169
|
+
- name: Generate histories from the model and replay them against the planner
|
|
170
|
+
run: uv run --locked --group quint pytest -c contracts/selection/quint.ini contracts/selection --quint-require-complete -q
|
|
171
|
+
# Match the README with the same locked renderer that produced these receipts.
|
|
172
|
+
# A presentation update to the floating report action must not break an immutable release.
|
|
173
|
+
- name: Check the README against the locked contract renderer
|
|
174
|
+
run: uv run --locked --group quint pytest-quint-connect report '**/.artifacts/quint-connect/results.json' --readme README.md --check
|
|
175
|
+
# The current action owns the sticky and artifacts, independently of README formatting.
|
|
176
|
+
- uses: gigaverse-app/pytest-quint-connect/report@v1
|
|
177
|
+
if: ${{ always() }}
|
|
178
|
+
with:
|
|
179
|
+
readme-mode: 'off'
|
|
180
|
+
|
|
141
181
|
validation-gate:
|
|
142
182
|
name: Validation gate
|
|
143
|
-
needs: [select-tests, quality, tests, pytest-minimum, distributions]
|
|
183
|
+
needs: [select-tests, quality, tests, pytest-minimum, distributions, selection-contract]
|
|
144
184
|
if: ${{ !cancelled() }}
|
|
145
185
|
runs-on: ubuntu-latest
|
|
146
186
|
steps:
|
|
@@ -148,4 +188,4 @@ jobs:
|
|
|
148
188
|
with:
|
|
149
189
|
needs: ${{ toJSON(needs) }}
|
|
150
190
|
lanes: ${{ needs.select-tests.outputs.lanes || '{}' }}
|
|
151
|
-
lane-jobs: '{"tests":["tests"],"pytest-minimum":["tests"]}'
|
|
191
|
+
lane-jobs: '{"tests":["tests"],"pytest-minimum":["tests"],"distributions":["package"],"selection-contract":["contracts"]}'
|
|
@@ -13,8 +13,8 @@ jobs:
|
|
|
13
13
|
docs:
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
17
|
-
- uses: actions/setup-python@
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
- uses: actions/setup-python@v7
|
|
18
18
|
with:
|
|
19
19
|
python-version: '3.13'
|
|
20
20
|
cache: pip
|
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
- run: python scripts/render_brand.py --check
|
|
24
24
|
- run: python -m mkdocs build --strict
|
|
25
25
|
- run: python documentation/check_site.py
|
|
26
|
-
- uses: actions/upload-artifact@
|
|
26
|
+
- uses: actions/upload-artifact@v7
|
|
27
27
|
with:
|
|
28
28
|
name: documentation-site
|
|
29
29
|
path: site/
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
name: dry-lint audit
|
|
2
|
+
# Audits the whole repository against the accepted backlog, then ratchets it: pairs that were refactored away or
|
|
3
|
+
# judged separate are recorded as cleaned in .dry-lint/baseline.json, progress.json and the README block, through a
|
|
4
|
+
# pull request that runs the ordinary checks. The baseline only ever shrinks; a new blocking pair fails the audit
|
|
5
|
+
# and no ratchet pull request is opened. Run it by hand after merging a cleanup to record the progress at once.
|
|
6
|
+
on:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: '23 6 * * 1'
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
workflow_call:
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
concurrency:
|
|
14
|
+
group: dry-lint-audit
|
|
15
|
+
cancel-in-progress: false
|
|
16
|
+
jobs:
|
|
17
|
+
audit:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
|
+
with:
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
- uses: gigaverse-app/dry-lint@v1
|
|
24
|
+
with:
|
|
25
|
+
mode: sweep
|
|
26
|
+
base: HEAD
|
|
27
|
+
python-version: '3.13'
|
|
28
|
+
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
29
|
+
plugins: anthropic==2.4.0
|
|
30
|
+
baseline: .dry-lint/baseline.json
|
|
31
|
+
require-complete: 'true'
|
|
32
|
+
budget-usd: '5'
|
|
33
|
+
- name: Retain the audit for human or agent review
|
|
34
|
+
if: always()
|
|
35
|
+
uses: actions/upload-artifact@v7
|
|
36
|
+
with:
|
|
37
|
+
name: dry-lint-audit
|
|
38
|
+
path: |
|
|
39
|
+
${{ runner.temp }}/dry-lint/report.json
|
|
40
|
+
${{ runner.temp }}/dry-lint/comment.md
|
|
41
|
+
retention-days: 30
|
|
42
|
+
if-no-files-found: warn
|
|
43
|
+
- name: Require ratchet PR authentication
|
|
44
|
+
env:
|
|
45
|
+
HAS_RATCHET_TOKEN: ${{ secrets.GV_CI_CROSS_REPO_TOKEN != '' }}
|
|
46
|
+
run: |
|
|
47
|
+
if [[ "$HAS_RATCHET_TOKEN" != "true" ]]; then
|
|
48
|
+
echo "::error::Configure the adopter-owned GV_CI_CROSS_REPO_TOKEN with contents and pull-request write access."
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
# The Action's sweep mode only audits. The CLI records the ratchet, reusing the verdicts the audit just stored,
|
|
52
|
+
# and the exact CLI environment installed by the Action. No second install or judge-version drift.
|
|
53
|
+
- name: Record cleaned pairs
|
|
54
|
+
env:
|
|
55
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
56
|
+
run: |
|
|
57
|
+
dry-lint sweep --update --store "$RUNNER_TEMP/dry-lint/verdicts" --budget-usd 5 \
|
|
58
|
+
--readme README.md --repository "$GITHUB_REPOSITORY" --branch main
|
|
59
|
+
# One standing branch: a later run updates the open ratchet PR instead of stacking another. The adopter-owned
|
|
60
|
+
# credential makes the PR run ordinary CI, including the required dry-lint check that refuses any widening.
|
|
61
|
+
- uses: peter-evans/create-pull-request@v8
|
|
62
|
+
with:
|
|
63
|
+
token: ${{ secrets.GV_CI_CROSS_REPO_TOKEN }}
|
|
64
|
+
branch: dry-lint/ratchet
|
|
65
|
+
delete-branch: true
|
|
66
|
+
add-paths: |
|
|
67
|
+
.dry-lint/baseline.json
|
|
68
|
+
.dry-lint/progress.json
|
|
69
|
+
README.md
|
|
70
|
+
commit-message: 'chore(dry-lint): record cleaned duplicate pairs in the baseline'
|
|
71
|
+
title: 'chore(dry-lint): record cleaned duplicate pairs in the baseline'
|
|
72
|
+
body: |
|
|
73
|
+
## TLDR
|
|
74
|
+
|
|
75
|
+
The weekly dry-lint audit found accepted duplicate pairs that no longer exist or were judged separate,
|
|
76
|
+
and shrinks `.dry-lint/baseline.json`, the progress badge and the README block to match.
|
|
77
|
+
|
|
78
|
+
The baseline can only shrink: the required `dry-lint` check rejects any pull request that widens it.
|
|
79
|
+
The full audit is in the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
BEFORE: merged cleanup -> accepted baseline and README still show old debt
|
|
83
|
+
AFTER: complete audit -> reviewed metadata PR -> baseline and README record cleanup
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
| Policy | Before | After |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| Accepted pairs | Previously recorded states | Removed/separate pairs marked cleaned; explicit exclusions dismissed |
|
|
89
|
+
| New debt | Rejected | Still rejected; no added allowances |
|
|
90
|
+
|
|
91
|
+
Pair-count changes appear in the baseline/progress diff and the linked audit. No application code changes.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: dry-lint judge
|
|
2
|
+
on:
|
|
3
|
+
workflow_run:
|
|
4
|
+
workflows: [dry-lint]
|
|
5
|
+
types: [completed]
|
|
6
|
+
permissions:
|
|
7
|
+
actions: read
|
|
8
|
+
checks: write
|
|
9
|
+
contents: read
|
|
10
|
+
pull-requests: write
|
|
11
|
+
concurrency:
|
|
12
|
+
group: dry-lint-judge-${{ github.event.workflow_run.head_branch }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
jobs:
|
|
15
|
+
judge:
|
|
16
|
+
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.head_repository.full_name != github.repository
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
# Only trusted default-branch settings and baseline; fork code is artifact data.
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
|
+
with:
|
|
22
|
+
persist-credentials: false
|
|
23
|
+
- uses: gigaverse-app/dry-lint@v1
|
|
24
|
+
with:
|
|
25
|
+
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
26
|
+
plugins: anthropic==2.4.0
|
|
27
|
+
baseline: .dry-lint/baseline.json
|
|
28
|
+
require-complete: 'true'
|
|
29
|
+
comment: 'true'
|
|
30
|
+
comment-on-clean: 'true'
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: dry-lint
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
types: [opened, synchronize, reopened]
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
pull-requests: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: dry-lint-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }}
|
|
15
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
check:
|
|
19
|
+
# A detection-only fork job must never satisfy the required judged check.
|
|
20
|
+
name: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && 'dry-lint detect' || 'dry-lint' }}
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
with:
|
|
25
|
+
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
26
|
+
fetch-depth: 1
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
- uses: gigaverse-app/dry-lint@v1
|
|
29
|
+
with:
|
|
30
|
+
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
31
|
+
plugins: anthropic==2.4.0
|
|
32
|
+
baseline: .dry-lint/baseline.json
|
|
33
|
+
require-complete: 'true'
|
|
34
|
+
comment: 'true'
|
|
35
|
+
comment-on-clean: 'true'
|
|
36
|
+
|
|
37
|
+
audit:
|
|
38
|
+
# Manual full validation also exercises the scheduled ratchet before its first merge.
|
|
39
|
+
if: github.event_name == 'workflow_dispatch'
|
|
40
|
+
uses: ./.github/workflows/dry-lint-audit.yml
|
|
41
|
+
secrets: inherit
|
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
timeout-minutes: 5
|
|
15
15
|
steps:
|
|
16
16
|
# Only reads PR metadata. Never check out or execute PR code in this workflow.
|
|
17
|
-
- uses: amannn/action-semantic-pull-request@
|
|
17
|
+
- uses: amannn/action-semantic-pull-request@v6
|
|
18
18
|
with:
|
|
19
19
|
types: |
|
|
20
20
|
feat
|
|
@@ -4,6 +4,8 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
branches: [main]
|
|
6
6
|
workflow_dispatch:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: '33 3 * * 1'
|
|
7
9
|
permissions:
|
|
8
10
|
contents: read
|
|
9
11
|
jobs:
|
|
@@ -27,7 +29,7 @@ jobs:
|
|
|
27
29
|
fromJSON(needs.select-tests.outputs.lanes).tests) }}
|
|
28
30
|
runs-on: ubuntu-latest
|
|
29
31
|
steps:
|
|
30
|
-
- uses: actions/checkout@
|
|
32
|
+
- uses: actions/checkout@v7
|
|
31
33
|
with:
|
|
32
34
|
fetch-depth: 0
|
|
33
35
|
- name: Use the reviewed repository graph
|
|
@@ -67,7 +69,9 @@ jobs:
|
|
|
67
69
|
run: |
|
|
68
70
|
python - <<'PY'
|
|
69
71
|
import json, os
|
|
70
|
-
|
|
72
|
+
# A full checkpoint admits every configured lane.
|
|
73
|
+
configured = json.load(open('.github/test-lanes.json', encoding='utf-8'))['lanes']
|
|
74
|
+
assert json.loads(os.environ['LANES']) == dict.fromkeys(configured, True)
|
|
71
75
|
PY
|
|
72
76
|
- name: Require successful planning after fallback execution
|
|
73
77
|
if: ${{ !cancelled() && needs.select-tests.result != 'success' }}
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
steps:
|
|
29
29
|
- name: Only process the tested main head
|
|
30
30
|
id: current
|
|
31
|
-
uses: actions/github-script@
|
|
31
|
+
uses: actions/github-script@v9
|
|
32
32
|
with:
|
|
33
33
|
script: |
|
|
34
34
|
const {data: branch} = await github.rest.repos.getBranch({...context.repo, branch: 'main'});
|
|
@@ -44,7 +44,7 @@ jobs:
|
|
|
44
44
|
fi
|
|
45
45
|
- name: Prepare release PR or publish its GitHub release
|
|
46
46
|
if: steps.current.outputs.matches == 'true'
|
|
47
|
-
uses: googleapis/release-please-action@
|
|
47
|
+
uses: googleapis/release-please-action@v5
|
|
48
48
|
with:
|
|
49
49
|
# This credential triggers CI on release PRs and Publish on releases.
|
|
50
50
|
# GITHUB_TOKEN would suppress those follow-up workflow events.
|
|
@@ -10,8 +10,8 @@ jobs:
|
|
|
10
10
|
validate-tag:
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
14
|
-
- uses: astral-sh/setup-uv@
|
|
13
|
+
- uses: actions/checkout@v7
|
|
14
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
15
15
|
with:
|
|
16
16
|
python-version: '3.14'
|
|
17
17
|
- name: Require a version-matching tag
|
|
@@ -21,6 +21,10 @@ jobs:
|
|
|
21
21
|
uv run --no-project python -c 'import os, pathlib, tomllib; version = tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"]; assert os.environ["RELEASE_REF"] == f"refs/tags/v{version}", "Run publishing from the version-matching v tag"'
|
|
22
22
|
checks:
|
|
23
23
|
needs: validate-tag
|
|
24
|
+
# Reusable CI's Quint report requests this grant, even on a tag with no PR.
|
|
25
|
+
permissions:
|
|
26
|
+
contents: read
|
|
27
|
+
pull-requests: write
|
|
24
28
|
uses: ./.github/workflows/ci.yml
|
|
25
29
|
publish:
|
|
26
30
|
needs: checks
|
|
@@ -31,12 +35,12 @@ jobs:
|
|
|
31
35
|
permissions:
|
|
32
36
|
id-token: write
|
|
33
37
|
steps:
|
|
34
|
-
- uses: actions/download-artifact@
|
|
38
|
+
- uses: actions/download-artifact@v8
|
|
35
39
|
with:
|
|
36
40
|
name: distributions
|
|
37
41
|
path: dist
|
|
38
42
|
- name: Publish tested distributions with attestations
|
|
39
|
-
uses: pypa/gh-action-pypi-publish@
|
|
43
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
40
44
|
|
|
41
45
|
action-version:
|
|
42
46
|
needs: publish
|
|
@@ -21,34 +21,38 @@ jobs:
|
|
|
21
21
|
matrix:
|
|
22
22
|
python: ['3.11', '3.14']
|
|
23
23
|
steps:
|
|
24
|
-
- uses: actions/checkout@
|
|
24
|
+
- uses: actions/checkout@v7
|
|
25
25
|
with:
|
|
26
26
|
ref: ${{ inputs.baseline || github.event.pull_request.base.sha }}
|
|
27
27
|
path: baseline
|
|
28
|
-
- uses: actions/checkout@
|
|
28
|
+
- uses: actions/checkout@v7
|
|
29
29
|
with:
|
|
30
30
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
31
31
|
path: candidate
|
|
32
|
-
- uses: astral-sh/setup-uv@
|
|
32
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
33
33
|
with:
|
|
34
34
|
python-version: ${{ matrix.python }}
|
|
35
35
|
cache-suffix: matched-windows-${{ matrix.python }}
|
|
36
36
|
- run: uv sync --directory baseline --locked
|
|
37
37
|
- run: uv sync --directory candidate --locked
|
|
38
|
+
- name: Preserve the baseline Git search path
|
|
39
|
+
shell: pwsh
|
|
40
|
+
run: '"BASELINE_GIT_PATH=$env:PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append'
|
|
41
|
+
- uses: gigaverse-app/ci-esta/actions/native-windows-git@v1
|
|
38
42
|
- name: Run complete suites in both orders on the same worker
|
|
39
43
|
shell: pwsh
|
|
40
44
|
run: |
|
|
41
45
|
$results = Join-Path $env:GITHUB_WORKSPACE 'measurements'
|
|
42
46
|
New-Item -ItemType Directory -Path $results | Out-Null
|
|
43
47
|
$measurements = @()
|
|
44
|
-
$originalPath = $env:
|
|
48
|
+
$originalPath = $env:BASELINE_GIT_PATH
|
|
49
|
+
$nativeGitPath = $env:PATH
|
|
45
50
|
foreach ($sample in @('baseline-1', 'candidate-1', 'candidate-2', 'baseline-2')) {
|
|
46
51
|
$arm = $sample.Split('-')[0]
|
|
47
52
|
Push-Location (Join-Path $env:GITHUB_WORKSPACE $arm)
|
|
48
53
|
try {
|
|
49
54
|
# Start every arm with the same PATH; only the candidate opts in.
|
|
50
|
-
$env:PATH = $originalPath
|
|
51
|
-
if ($arm -eq 'candidate') { ./scripts/use_native_windows_git.ps1 }
|
|
55
|
+
$env:PATH = if ($arm -eq 'candidate') { $nativeGitPath } else { $originalPath }
|
|
52
56
|
$sha = git rev-parse HEAD
|
|
53
57
|
# Keep repeated arms from timing cleanup of an earlier arm's Git fixtures.
|
|
54
58
|
$temp = Join-Path $env:RUNNER_TEMP "matched-pytest-$sample"
|
|
@@ -63,7 +67,7 @@ jobs:
|
|
|
63
67
|
if ($result -ne 0) { throw "${sample} failed: $result" }
|
|
64
68
|
} finally { Pop-Location }
|
|
65
69
|
}
|
|
66
|
-
- uses: actions/upload-artifact@
|
|
70
|
+
- uses: actions/upload-artifact@v7
|
|
67
71
|
if: always()
|
|
68
72
|
with:
|
|
69
73
|
name: matched-windows-${{ matrix.python }}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
minimum_pre_commit_version: '4.3.0'
|
|
2
|
+
default_install_hook_types: [pre-commit, prepare-commit-msg]
|
|
3
|
+
default_stages: [pre-commit]
|
|
1
4
|
repos:
|
|
2
5
|
- repo: local
|
|
3
6
|
hooks:
|
|
@@ -17,3 +20,12 @@ repos:
|
|
|
17
20
|
language: system
|
|
18
21
|
pass_filenames: false
|
|
19
22
|
types: [markdown]
|
|
23
|
+
|
|
24
|
+
- repo: https://github.com/gigaverse-app/dry-lint
|
|
25
|
+
rev: v1
|
|
26
|
+
hooks:
|
|
27
|
+
- id: dry-lint
|
|
28
|
+
args: [--preset, sonnet, --baseline, .dry-lint/baseline.json]
|
|
29
|
+
language_version: python3.13
|
|
30
|
+
- id: dry-lint-trailers
|
|
31
|
+
language_version: python3.13
|