pytest-selective 0.2.0__tar.gz → 0.3.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.
Files changed (172) hide show
  1. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/test-lanes.json +5 -6
  2. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/workflows/ci.yml +58 -15
  3. pytest_selective-0.3.0/.github/workflows/docs.yml +30 -0
  4. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/workflows/observe-ci.yml +2 -1
  5. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/workflows/public-actions.yml +23 -1
  6. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/workflows/release.yml +2 -1
  7. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.gitignore +4 -0
  8. pytest_selective-0.3.0/.readthedocs.yaml +11 -0
  9. pytest_selective-0.3.0/.release-please-manifest.json +3 -0
  10. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/AGENTS.md +13 -2
  11. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/CHANGELOG.md +23 -0
  12. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/CONTRIBUTING.md +35 -6
  13. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/PKG-INFO +17 -13
  14. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/README.md +15 -11
  15. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/RELEASING.md +11 -4
  16. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/action.yml +2 -2
  17. pytest_selective-0.3.0/actions/README.md +13 -0
  18. {pytest_selective-0.2.0/.github → pytest_selective-0.3.0}/actions/plan-lanes/action.yml +2 -2
  19. {pytest_selective-0.2.0/.github → pytest_selective-0.3.0}/actions/pytest-expansion/action.yml +1 -1
  20. {pytest_selective-0.2.0/.github → pytest_selective-0.3.0}/actions/test-impact/action.yml +2 -2
  21. pytest_selective-0.3.0/docs/actions.md +45 -0
  22. pytest_selective-0.3.0/docs/assets/banner.png +0 -0
  23. pytest_selective-0.3.0/docs/assets/banner.svg +28 -0
  24. pytest_selective-0.3.0/docs/assets/brand.json +13 -0
  25. pytest_selective-0.3.0/docs/assets/icon.png +0 -0
  26. pytest_selective-0.3.0/docs/assets/logo.svg +10 -0
  27. pytest_selective-0.3.0/docs/assets/raster-sources.json +9 -0
  28. pytest_selective-0.3.0/docs/assets/social-preview.png +0 -0
  29. pytest_selective-0.3.0/docs/assets/social-preview.svg +30 -0
  30. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22.md +1 -1
  31. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/ci-toolkit.md +4 -2
  32. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/ci.md +37 -8
  33. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/comparison-pytest-impacted.md +4 -4
  34. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/configuration.md +5 -3
  35. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/evidence.md +3 -1
  36. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/tutorial.md +37 -1
  37. pytest_selective-0.3.0/docs/tutorials/skip-unrelated-ci.md +140 -0
  38. pytest_selective-0.3.0/docs/work-in-progress/tickets/actions-directory-test-plan.md +10 -0
  39. pytest_selective-0.3.0/docs/work-in-progress/tickets/move-action-implementations-test-plan.md +10 -0
  40. pytest_selective-0.3.0/documentation/assets/routing-comparison.svg +1 -0
  41. pytest_selective-0.3.0/documentation/check_site.py +77 -0
  42. pytest_selective-0.3.0/documentation/ecosystem.md +31 -0
  43. pytest_selective-0.3.0/documentation/hooks.py +76 -0
  44. pytest_selective-0.3.0/documentation/index.md +72 -0
  45. pytest_selective-0.3.0/documentation/overrides/main.html +14 -0
  46. pytest_selective-0.3.0/documentation/publishing.md +107 -0
  47. pytest_selective-0.3.0/documentation/requirements.in +2 -0
  48. pytest_selective-0.3.0/documentation/requirements.txt +562 -0
  49. pytest_selective-0.3.0/mkdocs.yml +106 -0
  50. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/pyproject.toml +2 -2
  51. pytest_selective-0.3.0/scripts/ci_file_config.py +20 -0
  52. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/public_actions.py +4 -6
  53. pytest_selective-0.3.0/scripts/render_brand.py +140 -0
  54. pytest_selective-0.3.0/scripts/run_ci_tests.py +40 -0
  55. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/tutorial.py +3 -0
  56. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/skills/pytest-selective/SKILL.md +11 -5
  57. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/skills/pytest-selective/references/adoption.md +4 -3
  58. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/ci.py +14 -3
  59. pytest_selective-0.3.0/tests/test_ci_admission.py +64 -0
  60. pytest_selective-0.3.0/tests/test_ci_test_execution.py +71 -0
  61. pytest_selective-0.3.0/tests/test_public_actions.py +34 -0
  62. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/test_pytest_expansion.py +4 -1
  63. pytest_selective-0.3.0/tests/test_repository_ci.py +147 -0
  64. pytest_selective-0.3.0/tests/test_repository_hygiene.py.gv-dependency.yaml +4 -0
  65. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/test_tutorial.py +2 -0
  66. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_ci.py +86 -1
  67. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_impact_explanation.py +2 -2
  68. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_impact_graph.py +9 -9
  69. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_pytest_plugin.py +3 -0
  70. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_working_tree.py +3 -0
  71. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/uv.lock +1 -1
  72. pytest_selective-0.2.0/.release-please-manifest.json +0 -3
  73. pytest_selective-0.2.0/docs/actions.md +0 -42
  74. pytest_selective-0.2.0/docs/pytest-impacted.md +0 -69
  75. pytest_selective-0.2.0/plan-lanes/action.yml +0 -33
  76. pytest_selective-0.2.0/pytest-expansion/action.yml +0 -35
  77. pytest_selective-0.2.0/test-impact/action.yml +0 -106
  78. pytest_selective-0.2.0/tests/test_public_actions.py +0 -30
  79. pytest_selective-0.2.0/tests/test_repository_ci.py +0 -48
  80. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.gitattributes +0 -0
  81. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  82. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  83. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/dependabot.yml +0 -0
  84. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/workflows/pr-title.yml +0 -0
  85. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/workflows/release-please.yml +0 -0
  86. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.github/workflows/windows-performance.yml +0 -0
  87. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/.pre-commit-config.yaml +0 -0
  88. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/CLAUDE.md +0 -0
  89. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/LICENSE +0 -0
  90. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/PROVENANCE.md +0 -0
  91. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/agentsync.toml +0 -0
  92. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/README.md +0 -0
  93. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/agents.md +0 -0
  94. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-due-ci.json +0 -0
  95. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-due-docs-ci.json +0 -0
  96. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-due-docs-widget.json +0 -0
  97. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-due-widget.json +0 -0
  98. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-input-replays.json +0 -0
  99. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-obligation-docs.json +0 -0
  100. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-obligation.json +0 -0
  101. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-routing.md +0 -0
  102. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-22-selective-docs.json +0 -0
  103. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor/obligation-baseline.json +0 -0
  104. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after-3.11.xml +0 -0
  105. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after-3.14.xml +0 -0
  106. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-after.json +0 -0
  107. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control-3.11.xml +0 -0
  108. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control-3.14.xml +0 -0
  109. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-control.json +0 -0
  110. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor/selective-earlier.json +0 -0
  111. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/2026-10-23-windows-saleor.md +0 -0
  112. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/benchmarks/windows-runtime.md +0 -0
  113. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/local-development.md +0 -0
  114. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/pytest-hygiene.md +0 -0
  115. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/selection-health.md +0 -0
  116. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/work-in-progress/tickets/codex-selector-correctness-performance-test-plan.md +0 -0
  117. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/work-in-progress/tickets/codex-windows-git-performance-test-plan.md +0 -0
  118. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/work-in-progress/tickets/impacted-improvements-test-plan.md +0 -0
  119. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/docs/work-in-progress/tickets/public-action-onboarding-test-plan.md +0 -0
  120. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/release-please-config.json +0 -0
  121. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/benchmark_graph.py +0 -0
  122. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/benchmark_parsing.py +0 -0
  123. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/benchmark_rust.py +0 -0
  124. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/check_docs.py +0 -0
  125. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/check_metadata.py +0 -0
  126. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/compare_impacted.py +0 -0
  127. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/measure_ci_runs.py +0 -0
  128. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/scripts/smoke_distribution.py +0 -0
  129. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/skills/pytest-selective/agents/openai.yaml +0 -0
  130. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/__init__.py +0 -0
  131. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/__main__.py +0 -0
  132. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/ast_imports.py +0 -0
  133. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/hygiene.py +0 -0
  134. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_audit.py +0 -0
  135. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_audit_plugin.py +0 -0
  136. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_cli.py +0 -0
  137. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_declarations.py +0 -0
  138. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_explanation.py +0 -0
  139. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_first_party.py +0 -0
  140. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_graph.py +0 -0
  141. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_models.py +0 -0
  142. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_name_scope.py +0 -0
  143. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/impact_selection.py +0 -0
  144. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/input_policy.py +0 -0
  145. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/local.py +0 -0
  146. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/parse_batch.py +0 -0
  147. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/plugin.py +0 -0
  148. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/py.typed +0 -0
  149. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/pytest_expansion.py +0 -0
  150. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/pytest_plugins.py +0 -0
  151. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/pytest_sharding.py +0 -0
  152. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/test_inventory.py +0 -0
  153. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/typecheck_scope.py +0 -0
  154. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/src/pytest_selective/working_tree.py +0 -0
  155. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/__init__.py +0 -0
  156. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/test_ci_measurements.py +0 -0
  157. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/test_distribution_metadata.py +0 -0
  158. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/test_hygiene.py +0 -0
  159. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/test_repository_hygiene.py +0 -0
  160. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/__init__.py +0 -0
  161. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/git_repo.py +0 -0
  162. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_ast_imports.py +0 -0
  163. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_git_repo.py +0 -0
  164. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_global_inputs.py +0 -0
  165. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_impact_audit.py +0 -0
  166. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_impact_first_party.py +0 -0
  167. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_impact_name_scope.py +0 -0
  168. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_parse_batch.py +0 -0
  169. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_portability.py +0 -0
  170. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_pytest_plugins.py +0 -0
  171. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_pytest_sharding.py +0 -0
  172. {pytest_selective-0.2.0 → pytest_selective-0.3.0}/tests/testing/test_typecheck_scope.py +0 -0
@@ -18,14 +18,14 @@
18
18
  ],
19
19
  "inputs": [
20
20
  "src/**",
21
- "scripts/**",
22
- "tests/**",
23
- ".pre-commit-config.yaml",
24
- ".python-version"
21
+ "tests/**"
25
22
  ]
26
23
  }
27
24
  },
28
25
  "global_inputs": [
26
+ "scripts/**",
27
+ ".pre-commit-config.yaml",
28
+ ".python-version",
29
29
  "**/pyproject.toml",
30
30
  "pyproject.toml",
31
31
  "**/uv.lock",
@@ -33,9 +33,8 @@
33
33
  ".github/test-lanes.json",
34
34
  ".github/workflows/ci.yml",
35
35
  ".github/workflows/release.yml",
36
- ".github/actions/**",
36
+ "actions/**",
37
37
  "action.yml",
38
- "*/action.yml",
39
38
  "examples/**",
40
39
  ".github/workflows/public-actions.yml"
41
40
  ]
@@ -17,31 +17,56 @@ jobs:
17
17
  runs-on: ubuntu-latest
18
18
  outputs:
19
19
  lanes: ${{ steps.plan.outputs.lanes }}
20
+ mode: ${{ steps.files.outputs.mode }}
21
+ files: ${{ steps.paths.outputs.files }}
20
22
  steps:
21
23
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
24
  with:
23
25
  fetch-depth: 0
24
26
  - id: plan
25
- uses: ./plan-lanes
27
+ uses: ./actions/plan-lanes
26
28
  with:
27
29
  config: .github/test-lanes.json
28
30
  base: ${{ github.event.pull_request.base.sha || github.event.before }}
29
- full: ${{ github.run_attempt > 1 || github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'test:full') }}
31
+ full: ${{ github.run_attempt > 1 || contains(fromJSON('["workflow_dispatch","workflow_call","schedule","release"]'), github.event_name) || contains(github.event.pull_request.labels.*.name, 'test:full') }}
32
+ - name: Share the repository graph and execution inputs with file selection
33
+ env:
34
+ PYTHONPATH: src
35
+ run: |
36
+ uv run --no-project --python 3.14 --with pydantic==2.13.4 --with pyyaml==6.0.3 \
37
+ python scripts/ci_file_config.py "$RUNNER_TEMP/test-impact.json"
38
+ - id: files
39
+ uses: ./
40
+ with:
41
+ config: ${{ runner.temp }}/test-impact.json
42
+ base: ${{ github.event.pull_request.base.sha || github.event.before }}
43
+ full-roots: tests
44
+ full: ${{ github.run_attempt > 1 || contains(fromJSON('["workflow_dispatch","workflow_call","schedule","release"]'), github.event_name) || contains(github.event.pull_request.labels.*.name, 'test:full') }}
45
+ - id: paths
46
+ name: Forward exact selected paths without shell splitting
47
+ env:
48
+ MODE: ${{ steps.files.outputs.mode }}
49
+ run: |
50
+ python - <<'PY'
51
+ import json, os
52
+ from pathlib import Path
53
+ files = json.loads(Path('test-impact-report.json').read_text())['selected'] if os.environ['MODE'] == 'scoped' else []
54
+ with open(os.environ['GITHUB_OUTPUT'], 'a') as output:
55
+ output.write('files=' + json.dumps(files) + '\n')
56
+ PY
30
57
  quality:
31
58
  runs-on: ubuntu-latest
32
59
  steps:
33
60
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
34
- - uses: gigaverse-app/ci-esta/.github/actions/setup-cached-uv@v0.1
61
+ - uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
35
62
  with:
36
63
  python-version: '3.14'
37
64
  - run: uv run --locked pre-commit run --all-files
38
65
  - name: Check aggregate gate against the execution lanes
39
66
  run: >-
40
67
  uv run --no-project --python 3.14
41
- --with "ci-esta>=0.1.0,<0.2.0"
68
+ --with "ci-esta>=1.1.0,<2.0.0"
42
69
  ci-esta check-workflow --workflow .github/workflows/ci.yml --lanes .github/test-lanes.json
43
- - name: Validate routing even when the platform matrix is skipped
44
- run: uv run --locked pytest -q tests/test_repository_ci.py
45
70
  - name: Validate GitHub Actions
46
71
  run: docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:1.7.7 -color
47
72
  tests:
@@ -57,20 +82,26 @@ jobs:
57
82
  runs-on: ${{ matrix.os }}
58
83
  steps:
59
84
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
60
- - uses: gigaverse-app/ci-esta/.github/actions/setup-cached-uv@v0.1
85
+ - uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
61
86
  with:
62
87
  python-version: ${{ matrix.python }}
63
88
  - name: Use native Git for Windows
64
- uses: gigaverse-app/ci-esta/.github/actions/native-windows-git@v0.1
89
+ uses: gigaverse-app/ci-esta/actions/native-windows-git@v1
65
90
  - name: Record coverage runtime
66
91
  run: uv run --locked python -m coverage --version
67
- - run: uv run --locked pytest -q -n 4 --durations=20 --junitxml=test-timings.xml --cov --cov-report=term-missing --cov-report=xml
92
+ - name: Execute the shared affected-file plan
93
+ run: uv run --locked python scripts/run_ci_tests.py -q -n 4 --durations=20 --junitxml=test-timings.xml
68
94
  env:
95
+ CI_PLANNER_RESULT: ${{ needs.select-tests.result }}
96
+ CI_TEST_MODE: ${{ needs.select-tests.outputs.mode }}
97
+ CI_TEST_FILES: ${{ needs.select-tests.outputs.files }}
98
+ CI_COVERAGE: 'true'
69
99
  # Keep temporary Git repositories beside the checkout on the work disk.
70
100
  TMP: ${{ runner.temp }}
71
101
  TEMP: ${{ runner.temp }}
72
102
  TMPDIR: ${{ runner.temp }}
73
- - uses: gigaverse-app/ci-esta/.github/actions/learn-test-timings@v0.1
103
+ - uses: gigaverse-app/ci-esta/actions/learn-test-timings@v1
104
+ if: ${{ hashFiles('test-timings.xml') != '' }}
74
105
  with:
75
106
  junit-pattern: test-timings.xml
76
107
  artifact-name: test-timings-${{ matrix.python }}-${{ matrix.os }}
@@ -89,22 +120,34 @@ jobs:
89
120
  runs-on: ubuntu-latest
90
121
  steps:
91
122
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
92
- - uses: gigaverse-app/ci-esta/.github/actions/setup-cached-uv@v0.1
123
+ - uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
93
124
  with:
94
125
  python-version: '3.11'
95
126
  - run: uv pip install 'pytest==8.0.0'
96
- - run: uv run --no-sync pytest -q -n 4 --durations=20
127
+ - name: Execute the same file plan on minimum pytest
128
+ run: uv run --no-sync python scripts/run_ci_tests.py -q -n 4 --durations=20
129
+ env:
130
+ CI_PLANNER_RESULT: ${{ needs.select-tests.result }}
131
+ CI_TEST_MODE: ${{ needs.select-tests.outputs.mode }}
132
+ CI_TEST_FILES: ${{ needs.select-tests.outputs.files }}
97
133
  distributions:
134
+ needs: select-tests
135
+ # README changes still need build/metadata checks; planner failure must not skip them.
136
+ if: ${{ !cancelled() }}
98
137
  runs-on: ubuntu-latest
99
138
  steps:
100
139
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
101
- - uses: gigaverse-app/ci-esta/.github/actions/setup-cached-uv@v0.1
140
+ - uses: gigaverse-app/ci-esta/actions/setup-cached-uv@v1
102
141
  with:
103
142
  python-version: '3.14'
104
143
  - run: uv build
105
144
  - run: uv run --locked twine check --strict dist/*
106
145
  - run: uv run --locked python scripts/check_metadata.py
107
- - run: uv run --locked python scripts/smoke_distribution.py
146
+ - name: Smoke installed distributions when runtime inputs change
147
+ if: >-
148
+ ${{ needs.select-tests.result != 'success' ||
149
+ fromJSON(needs.select-tests.outputs.lanes).tests }}
150
+ run: uv run --locked python scripts/smoke_distribution.py
108
151
  - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
109
152
  with:
110
153
  name: distributions
@@ -117,7 +160,7 @@ jobs:
117
160
  if: ${{ !cancelled() }}
118
161
  runs-on: ubuntu-latest
119
162
  steps:
120
- - uses: gigaverse-app/ci-esta/.github/actions/validation-gate@v0.1
163
+ - uses: gigaverse-app/ci-esta/actions/validation-gate@v1
121
164
  with:
122
165
  needs: ${{ toJSON(needs) }}
123
166
  lanes: ${{ needs.select-tests.outputs.lanes || '{}' }}
@@ -0,0 +1,30 @@
1
+ name: Documentation
2
+ on:
3
+ pull_request:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+ permissions:
8
+ contents: read
9
+ concurrency:
10
+ group: docs-${{ github.event.pull_request.number || github.ref }}
11
+ cancel-in-progress: true
12
+ jobs:
13
+ docs:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
17
+ - uses: actions/setup-python@v6
18
+ with:
19
+ python-version: '3.13'
20
+ cache: pip
21
+ cache-dependency-path: documentation/requirements.txt
22
+ - run: python -m pip install -r documentation/requirements.txt
23
+ - run: python scripts/render_brand.py --check
24
+ - run: python -m mkdocs build --strict
25
+ - run: python documentation/check_site.py
26
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
27
+ with:
28
+ name: documentation-site
29
+ path: site/
30
+ if-no-files-found: error
@@ -13,7 +13,7 @@ permissions:
13
13
 
14
14
  jobs:
15
15
  report:
16
- uses: gigaverse-app/ci-esta/.github/workflows/report.yml@v0.3.0
16
+ uses: gigaverse-app/ci-esta/.github/workflows/report.yml@v1
17
17
  with:
18
18
  run-id: ${{ github.event.workflow_run.id }}
19
19
  run-attempt: ${{ github.event.workflow_run.run_attempt }}
@@ -22,3 +22,4 @@ jobs:
22
22
  post-sticky: true
23
23
  required-gates-json: '[{"kind":"actions_job","job_name":"Validation gate"}]'
24
24
  analyze-critical-path: true
25
+ test-selection-artifact: test-impact-explanation
@@ -7,7 +7,26 @@ on:
7
7
  permissions:
8
8
  contents: read
9
9
  jobs:
10
+ select-tests:
11
+ runs-on: ubuntu-latest
12
+ outputs:
13
+ lanes: ${{ steps.select.outputs.lanes }}
14
+ steps:
15
+ - uses: actions/checkout@v7
16
+ with:
17
+ fetch-depth: 0
18
+ - id: select
19
+ uses: ./actions/plan-lanes
20
+ with:
21
+ config: .github/test-lanes.json
22
+ base: ${{ github.event.pull_request.base.sha || github.event.before }}
23
+ full: ${{ github.run_attempt > 1 || contains(fromJSON('["workflow_dispatch","workflow_call","schedule","release"]'), github.event_name) || contains(github.event.pull_request.labels.*.name, 'test:full') }}
24
+ artifact-name: public-action-selection
10
25
  public-actions:
26
+ needs: select-tests
27
+ if: >-
28
+ ${{ !cancelled() && (needs.select-tests.result != 'success' ||
29
+ fromJSON(needs.select-tests.outputs.lanes).tests) }}
11
30
  runs-on: ubuntu-latest
12
31
  steps:
13
32
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
@@ -37,7 +56,7 @@ jobs:
37
56
  run: |
38
57
  test "$MODE" = full
39
58
  test -n "$ROOTS"
40
- - uses: ./plan-lanes
59
+ - uses: ./actions/plan-lanes
41
60
  id: lanes
42
61
  with:
43
62
  config: .github/test-lanes.json
@@ -52,3 +71,6 @@ jobs:
52
71
  import json, os
53
72
  assert json.loads(os.environ['LANES']) == {'tests': True}
54
73
  PY
74
+ - name: Require successful planning after fallback execution
75
+ if: ${{ !cancelled() && needs.select-tests.result != 'success' }}
76
+ run: exit 1
@@ -54,7 +54,8 @@ jobs:
54
54
  if [[ ! "$RELEASE_TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
55
55
  exit 0
56
56
  fi
57
- alias="v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
57
+ # The Actions API has its own major, independent of the Python package.
58
+ alias="v1"
58
59
  if gh api "repos/$GH_REPO/git/ref/tags/$alias" --silent; then
59
60
  gh api --method PATCH "repos/$GH_REPO/git/refs/tags/$alias" \
60
61
  -f sha="$RELEASE_SHA" -F force=true --silent
@@ -11,3 +11,7 @@ dist/
11
11
  coverage.xml
12
12
  htmlcov/
13
13
  tutorial-report.json
14
+
15
+ # Built documentation
16
+ /site/
17
+ /.venv-docs/
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ build:
3
+ os: ubuntu-24.04
4
+ tools:
5
+ python: "3.13"
6
+ python:
7
+ install:
8
+ - requirements: documentation/requirements.txt
9
+ mkdocs:
10
+ configuration: mkdocs.yml
11
+ fail_on_warning: true
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.3.0"
3
+ }
@@ -14,8 +14,8 @@ on pytest-selective itself.
14
14
  - Planning supports committed revisions and explicit working-tree snapshots. Preserve full execution on
15
15
  operational uncertainty and diagnostics for invalid declarations. An empty
16
16
  selection is not an empty pytest argument list.
17
- - Keep consumer routing regressions in the always-running quality job. Update
18
- `.github/test-lanes.json` when adding execution inputs; preserve full main/manual
17
+ - Select consumer routing regressions by their declared execution/configuration inputs. Update
18
+ `.github/test-lanes.json` when adding execution inputs; preserve explicit full/manual
19
19
  checkpoints and the `test:full` override.
20
20
  - The README's performance numbers are scenario-specific observations. Keep
21
21
  claims linked to [raw evidence](docs/benchmarks/2026-10-22-routing.md); distinguish
@@ -56,3 +56,14 @@ npx --yes @dallay/agentsync@1.52.3 status
56
56
  ```
57
57
 
58
58
  Keep the symlink tracked in Git. See CONTRIBUTING.md for platform setup.
59
+
60
+ ## Documentation-only CI
61
+
62
+ Documentation-only PRs execute zero tests unless a test or lane explicitly
63
+ declares that documentation as an input. This includes CI contract tests,
64
+ installed-wheel smoke and public-action smoke. Metadata/link/build checks may
65
+ still validate documentation without running runtime tests. Declare execution
66
+ workflows, selector configuration, helpers, locks and non-import inputs; missing
67
+ history or failed planning must execute the full affected lanes and fail the
68
+ required planning gate. Ordinary PRs and pushes use selection; manual/release/scheduled/full overrides
69
+ remain complete checkpoints.
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.0](https://github.com/gigaverse-app/pytest-selective/compare/v0.2.0...v0.3.0) (2026-10-23)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * **actions:** named action callers upgrading from older layouts must replace `.github/actions/NAME` or `NAME` with `actions/NAME` and select a revision containing that path.
9
+
10
+ ### Features
11
+
12
+ * **actions:** group public entry points under actions directory ([#44](https://github.com/gigaverse-app/pytest-selective/issues/44)) ([236aefc](https://github.com/gigaverse-app/pytest-selective/commit/236aefc83d9f0ee1696a5ffa29fc83cbcc4a53dc))
13
+
14
+
15
+ ### Bug fixes
16
+
17
+ * **ci:** dogfood dependency-based test selection ([#57](https://github.com/gigaverse-app/pytest-selective/issues/57)) ([76afb69](https://github.com/gigaverse-app/pytest-selective/commit/76afb69cea84681bd661ec2bfff7be857b434129))
18
+ * **ci:** select all runtime tests by declared dependencies ([9673e50](https://github.com/gigaverse-app/pytest-selective/commit/9673e50dd8a709db9347d2e325da242aca96cece))
19
+ * **docs:** refresh cached artwork when branding changes ([5726530](https://github.com/gigaverse-app/pytest-selective/commit/5726530a445099e7cf24a1a7a89016fed0270308))
20
+
21
+
22
+ ### Refactoring
23
+
24
+ * **actions:** move implementations into the public actions directory ([#46](https://github.com/gigaverse-app/pytest-selective/issues/46)) ([bd5aae3](https://github.com/gigaverse-app/pytest-selective/commit/bd5aae32176ae83b121d2353f40b562642184cd8))
25
+
3
26
  ## [0.2.0](https://github.com/gigaverse-app/pytest-selective/compare/v0.1.1...v0.2.0) (2026-10-23)
4
27
 
5
28
 
@@ -54,14 +54,32 @@ limitations. The pull request template provides a short checklist. See
54
54
  ## CI lane selection
55
55
 
56
56
  This repository uses its own `plan-lanes` action. Documentation-only PRs keep
57
- quality checks (including Markdown links) and distribution build/install checks,
58
- while skipping the six-platform pytest matrix and minimum-pytest lane. Source,
59
- tests, scripts, dependency/pytest policy and workflow changes run the complete
60
- matrix. Main, manual/called runs and the `test:full` label run it in full; a
61
- failed planner also runs all tests. Repository routing controls exercise the
62
- committed config against real Git trees, including full and missing-history
57
+ quality checks (including Markdown links) and distribution build/metadata checks,
58
+ while skipping the six-platform pytest matrix and minimum-pytest lane. Within an
59
+ admitted lane, the repository's public file-selection action selects affected
60
+ test files once; the platform matrix and minimum-pytest job execute that same
61
+ plan. CI-esta receives both lane and file explanations, learns JUnit timings,
62
+ and validates the aggregate gate. Source and test edits follow dependencies;
63
+ scripts, dependency/pytest policy and execution workflow changes retain full
64
+ validation. Manual/called/release runs and the `test:full` label run it in full; a
65
+ failed planner also runs all tests. Installed-distribution smoke checks use the
66
+ same runtime-input decision; README-only changes skip those checks while still
67
+ verifying the README embedded in both release archives. Repository routing
68
+ controls exercise the committed config against real Git trees, including full and missing-history
63
69
  controls. Add new non-import execution inputs to `.github/test-lanes.json`.
64
70
 
71
+ File planning derives its graph from that same lane config and merges its declared
72
+ global execution inputs with the graph's environment inputs. Declare subprocess
73
+ and non-import dependencies at their readers. Full plans collect whole-suite
74
+ coverage; scoped plans produce JUnit timing evidence without presenting partial
75
+ coverage as a whole-suite result. The small execution wrapper only consumes the
76
+ public action's JSON file list: it does not implement another selector.
77
+ The outer pytest process disables the selective plugin to avoid a second planner
78
+ and a hidden dependency of every test on plugin startup. Plugin integration tests
79
+ still load it normally in subprocesses and declare that dependency explicitly.
80
+ Missing or failed planning runs complete roots, and an empty successful plan never starts
81
+ pytest. The aggregate gate still fails when planning fails.
82
+
65
83
  ## Conventional Commits
66
84
 
67
85
  Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
@@ -123,3 +141,14 @@ the Linux filesystem. See the
123
141
  [Windows setup guide](https://dallay.github.io/agentsync/guides/windows-symlink-setup/).
124
142
  If AgentSync backs up an existing `CLAUDE.md`, review and preserve any unique
125
143
  guidance in `AGENTS.md`; do not commit the backup as another instruction source.
144
+
145
+ ## Documentation-only CI
146
+
147
+ Documentation-only PRs execute zero tests unless a test or lane explicitly
148
+ declares that documentation as an input. This includes CI contract tests,
149
+ installed-wheel smoke and public-action smoke. Metadata/link/build checks may
150
+ still validate documentation without running runtime tests. Declare execution
151
+ workflows, selector configuration, helpers, locks and non-import inputs; missing
152
+ history or failed planning must execute the full affected lanes and fail the
153
+ required planning gate. Ordinary PRs and pushes use selection; manual/release/scheduled/full overrides
154
+ remain complete checkpoints.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pytest-selective
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Explainable Python test impact analysis: select affected pytest files from Git changes
5
5
  Project-URL: Homepage, https://github.com/gigaverse-app/pytest-selective
6
- Project-URL: Documentation, https://github.com/gigaverse-app/pytest-selective/blob/main/docs/README.md
6
+ Project-URL: Documentation, https://pytest-selective.readthedocs.io/en/latest/
7
7
  Project-URL: Repository, https://github.com/gigaverse-app/pytest-selective
8
8
  Project-URL: Issues, https://github.com/gigaverse-app/pytest-selective/issues
9
9
  Project-URL: Changelog, https://github.com/gigaverse-app/pytest-selective/blob/main/CHANGELOG.md
@@ -29,10 +29,9 @@ Provides-Extra: audit
29
29
  Requires-Dist: pytest>=8; extra == 'audit'
30
30
  Description-Content-Type: text/markdown
31
31
 
32
- # pytest-selective
33
-
34
- **Run affected Python tests. See why they matter.**
32
+ ![pytest-selective: Run affected Python tests. See why they matter.](https://raw.githubusercontent.com/gigaverse-app/pytest-selective/main/docs/assets/banner.png?v=17de2a0b7412)
35
33
 
34
+ # pytest-selective
36
35
  [![CI](https://github.com/gigaverse-app/pytest-selective/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/gigaverse-app/pytest-selective/actions/workflows/ci.yml)
37
36
  [![PyPI](https://img.shields.io/pypi/v/pytest-selective)](https://pypi.org/project/pytest-selective/)
38
37
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB?logo=python&logoColor=white)](https://github.com/gigaverse-app/pytest-selective/blob/main/pyproject.toml)
@@ -40,6 +39,11 @@ Description-Content-Type: text/markdown
40
39
  [![Ruff](https://img.shields.io/badge/code%20style-Ruff-D7FF64?logo=ruff&logoColor=black)](https://github.com/gigaverse-app/pytest-selective/blob/main/.pre-commit-config.yaml)
41
40
  [![Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/gigaverse-app/pytest-selective/blob/main/LICENSE)
42
41
  [![Agent skill](https://img.shields.io/badge/Agent_Skill-ready-2563EB)](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/agents.md)
42
+ [![Documentation](https://readthedocs.org/projects/pytest-selective/badge/?version=latest)](https://pytest-selective.readthedocs.io/en/latest/)
43
+
44
+ **Run affected Python tests. See why they matter.**
45
+
46
+ [Read the documentation](https://pytest-selective.readthedocs.io/en/latest/) · [Related tools](https://pytest-selective.readthedocs.io/en/latest/ecosystem/)
43
47
 
44
48
  pytest-selective is a **Python test impact analysis** tool for incremental testing
45
49
  with pytest. It follows dependencies through both sides of a Git change, selects
@@ -47,7 +51,8 @@ the affected test files, and explains the result. Use it directly as a pytest
47
51
  plugin, or plan before collection and service startup with the CLI and CI actions.
48
52
 
49
53
  Built from the selector used in Gigaverse's backend, AI, and shared Python
50
- infrastructure. The API may change before 1.0.
54
+ infrastructure. Use the moving `@v1` Actions tag. The Python package has its own
55
+ version and compatible dependency range.
51
56
  [Provenance and extraction scope](https://github.com/gigaverse-app/pytest-selective/blob/main/PROVENANCE.md).
52
57
 
53
58
  [Quick tutorial](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/tutorial.md) ·
@@ -70,8 +75,8 @@ and slack. [See the source runs and method](https://github.com/gigaverse-app/ci-
70
75
  | --- | --- | --- |
71
76
  | Test local edits with your existing pytest command | `uv add --dev pytest-selective`, then `uv run pytest --selective` | Unaffected test execution; staged, unstaged and untracked changes are included |
72
77
  | Avoid expensive collection and application imports | `pytest-selective run --config .github/test-impact.json -- -q` | Collection/imports for unaffected files as well as execution |
73
- | Plan affected files in GitHub Actions | `gigaverse-app/pytest-selective@main` | Plans before installing your application |
74
- | Keep whole-suite coverage or conformance checks | `gigaverse-app/pytest-selective/plan-lanes@main` | Entire unaffected jobs, including their services and setup |
78
+ | Plan affected files in GitHub Actions | `gigaverse-app/pytest-selective@v1` | Plans before installing your application |
79
+ | Keep whole-suite coverage or conformance checks | `gigaverse-app/pytest-selective/actions/plan-lanes@v1` | Entire unaffected jobs, including their services and setup |
75
80
  | Check assumptions about JSON, templates and other runtime inputs | Optional file-read recorder and dependency audit | Exposes observed reads missing from the declared graph |
76
81
  | Keep selection narrow as the project grows | Explanations, startup-floor budgets, expansion and isolation guards | Makes broad new fixture/import dependencies visible |
77
82
 
@@ -81,10 +86,9 @@ collects normally; the pre-collection runner and CI planner can avoid that cost.
81
86
  Keep full checkpoints and use complete lanes when partial suites cannot satisfy
82
87
  your coverage contract.
83
88
 
84
- **Public-path availability:** root and short action paths are new on `main`;
85
- existing `v0.1` releases predate them. Evaluate with `@main`, or pin a reviewed
86
- commit containing the public `action.yml`. Adopt a compatible release tag after
87
- it includes these paths. Existing `.github/actions/...` paths remain supported.
89
+ **Public-path availability:** version 1 provides the root action and
90
+ `actions/NAME` paths. Use the moving `@v1` tag for compatible updates.
91
+ Older immutable releases retain their original layouts.
88
92
  [Public action API](docs/actions.md).
89
93
 
90
94
  ## Have your agent set it up
@@ -262,7 +266,7 @@ and evidence checks.
262
266
  inspectable JSON plans, runtime dependency audits, and planning before application
263
267
  startup. Both use static dependency analysis; choose
264
268
  based on your workflow, and validate selection against your own suite.
265
- See the [lessons from pytest-impacted](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/pytest-impacted.md)
269
+ See the [comparison with pytest-impacted](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/comparison-pytest-impacted.md)
266
270
  for portability and Git-resolution improvements adopted from that comparison.
267
271
 
268
272
  ## Contribute
@@ -1,7 +1,6 @@
1
- # pytest-selective
2
-
3
- **Run affected Python tests. See why they matter.**
1
+ ![pytest-selective: Run affected Python tests. See why they matter.](https://raw.githubusercontent.com/gigaverse-app/pytest-selective/main/docs/assets/banner.png?v=17de2a0b7412)
4
2
 
3
+ # pytest-selective
5
4
  [![CI](https://github.com/gigaverse-app/pytest-selective/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/gigaverse-app/pytest-selective/actions/workflows/ci.yml)
6
5
  [![PyPI](https://img.shields.io/pypi/v/pytest-selective)](https://pypi.org/project/pytest-selective/)
7
6
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB?logo=python&logoColor=white)](https://github.com/gigaverse-app/pytest-selective/blob/main/pyproject.toml)
@@ -9,6 +8,11 @@
9
8
  [![Ruff](https://img.shields.io/badge/code%20style-Ruff-D7FF64?logo=ruff&logoColor=black)](https://github.com/gigaverse-app/pytest-selective/blob/main/.pre-commit-config.yaml)
10
9
  [![Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/gigaverse-app/pytest-selective/blob/main/LICENSE)
11
10
  [![Agent skill](https://img.shields.io/badge/Agent_Skill-ready-2563EB)](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/agents.md)
11
+ [![Documentation](https://readthedocs.org/projects/pytest-selective/badge/?version=latest)](https://pytest-selective.readthedocs.io/en/latest/)
12
+
13
+ **Run affected Python tests. See why they matter.**
14
+
15
+ [Read the documentation](https://pytest-selective.readthedocs.io/en/latest/) · [Related tools](https://pytest-selective.readthedocs.io/en/latest/ecosystem/)
12
16
 
13
17
  pytest-selective is a **Python test impact analysis** tool for incremental testing
14
18
  with pytest. It follows dependencies through both sides of a Git change, selects
@@ -16,7 +20,8 @@ the affected test files, and explains the result. Use it directly as a pytest
16
20
  plugin, or plan before collection and service startup with the CLI and CI actions.
17
21
 
18
22
  Built from the selector used in Gigaverse's backend, AI, and shared Python
19
- infrastructure. The API may change before 1.0.
23
+ infrastructure. Use the moving `@v1` Actions tag. The Python package has its own
24
+ version and compatible dependency range.
20
25
  [Provenance and extraction scope](https://github.com/gigaverse-app/pytest-selective/blob/main/PROVENANCE.md).
21
26
 
22
27
  [Quick tutorial](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/tutorial.md) ·
@@ -39,8 +44,8 @@ and slack. [See the source runs and method](https://github.com/gigaverse-app/ci-
39
44
  | --- | --- | --- |
40
45
  | Test local edits with your existing pytest command | `uv add --dev pytest-selective`, then `uv run pytest --selective` | Unaffected test execution; staged, unstaged and untracked changes are included |
41
46
  | Avoid expensive collection and application imports | `pytest-selective run --config .github/test-impact.json -- -q` | Collection/imports for unaffected files as well as execution |
42
- | Plan affected files in GitHub Actions | `gigaverse-app/pytest-selective@main` | Plans before installing your application |
43
- | Keep whole-suite coverage or conformance checks | `gigaverse-app/pytest-selective/plan-lanes@main` | Entire unaffected jobs, including their services and setup |
47
+ | Plan affected files in GitHub Actions | `gigaverse-app/pytest-selective@v1` | Plans before installing your application |
48
+ | Keep whole-suite coverage or conformance checks | `gigaverse-app/pytest-selective/actions/plan-lanes@v1` | Entire unaffected jobs, including their services and setup |
44
49
  | Check assumptions about JSON, templates and other runtime inputs | Optional file-read recorder and dependency audit | Exposes observed reads missing from the declared graph |
45
50
  | Keep selection narrow as the project grows | Explanations, startup-floor budgets, expansion and isolation guards | Makes broad new fixture/import dependencies visible |
46
51
 
@@ -50,10 +55,9 @@ collects normally; the pre-collection runner and CI planner can avoid that cost.
50
55
  Keep full checkpoints and use complete lanes when partial suites cannot satisfy
51
56
  your coverage contract.
52
57
 
53
- **Public-path availability:** root and short action paths are new on `main`;
54
- existing `v0.1` releases predate them. Evaluate with `@main`, or pin a reviewed
55
- commit containing the public `action.yml`. Adopt a compatible release tag after
56
- it includes these paths. Existing `.github/actions/...` paths remain supported.
58
+ **Public-path availability:** version 1 provides the root action and
59
+ `actions/NAME` paths. Use the moving `@v1` tag for compatible updates.
60
+ Older immutable releases retain their original layouts.
57
61
  [Public action API](docs/actions.md).
58
62
 
59
63
  ## Have your agent set it up
@@ -231,7 +235,7 @@ and evidence checks.
231
235
  inspectable JSON plans, runtime dependency audits, and planning before application
232
236
  startup. Both use static dependency analysis; choose
233
237
  based on your workflow, and validate selection against your own suite.
234
- See the [lessons from pytest-impacted](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/pytest-impacted.md)
238
+ See the [comparison with pytest-impacted](https://github.com/gigaverse-app/pytest-selective/blob/main/docs/comparison-pytest-impacted.md)
235
239
  for portability and Git-resolution improvements adopted from that comparison.
236
240
 
237
241
  ## Contribute
@@ -43,10 +43,17 @@ check out or build source with that permission.
43
43
  `pytest-selective --help` and run the tutorial using that installation.
44
44
 
45
45
  After a normal release publishes successfully, the workflow advances the
46
- compatible Actions tag (for example, `v0.1` for `v0.1.0`). Consumers can use
47
- `@v0.1` to receive patch releases. Package requirements use compatible ranges
48
- such as `pytest-selective>=0.1.0,<0.2.0`; lockfiles retain resolved versions and
49
- artifact hashes. Prereleases do not advance the Actions tag.
46
+ Actions tag `v1`. The Actions API version is independent of the Python package
47
+ version: publishing Python `0.x.y` does not prevent updating Actions `v1`.
48
+ Consumers deliberately use `actions/NAME@v1` as a moving target. Change the
49
+ Actions major only when deliberately establishing a new Actions API line.
50
+ Package requirements use their own compatible ranges, such as
51
+ `pytest-selective>=0.2,<0.3`; lockfiles retain resolved versions and artifact
52
+ hashes. Prereleases do not advance the Actions tag.
53
+
54
+ For an Actions-only publication, advance `v1` to the exact reviewed main commit
55
+ after its complete CI passes. This updates the Git tag without creating a GitHub
56
+ release or invoking PyPI publication. Do not move immutable package release tags.
50
57
 
51
58
  Manual dispatch is available for a version-matching **tag**, not a branch. The
52
59
  workflow intentionally does not skip existing uploads: investigate a partial
@@ -1,4 +1,4 @@
1
- # Generated by scripts/public_actions.py; edit the canonical .github/actions metadata.
1
+ # Generated by scripts/public_actions.py; edit the canonical actions metadata.
2
2
  name: Cached test impact selection
3
3
  description: Select affected Python test files from both Git trees, falling back to all configured roots.
4
4
  inputs:
@@ -86,7 +86,7 @@ runs:
86
86
  using: composite
87
87
  steps:
88
88
  - id: action
89
- uses: $/.github/actions/test-impact
89
+ uses: $/actions/test-impact
90
90
  with:
91
91
  warm-only: ${{ inputs.warm-only }}
92
92
  config: ${{ inputs.config }}
@@ -0,0 +1,13 @@
1
+ # pytest-selective actions
2
+
3
+ Use `gigaverse-app/pytest-selective/actions/NAME@REF` for individual actions, such as
4
+ `gigaverse-app/pytest-selective/actions/plan-lanes@main`.
5
+ The root `gigaverse-app/pytest-selective@REF` action plans affected test files.
6
+
7
+ See the [action reference and version availability](../docs/actions.md) for
8
+ inputs, outputs and compatible pins, or start with the
9
+ [complete CI recipe](../docs/ci.md).
10
+
11
+ Each directory contains the actual implementation and its helpers. Only the
12
+ root default action is generated; refresh it with
13
+ `uv run python scripts/public_actions.py` after changing test-impact's metadata.
@@ -8,7 +8,7 @@ inputs:
8
8
  description: Base commit containing the complete change set.
9
9
  required: true
10
10
  full:
11
- description: Run every lane for main, schedules, or an explicit full-test request.
11
+ description: Run every lane for an explicit full-test checkpoint; ordinary PRs and pushes use selection.
12
12
  default: 'false'
13
13
  artifact-name:
14
14
  description: >
@@ -39,7 +39,7 @@ runs:
39
39
  SELECTIVE_BASE: ${{ inputs.base }}
40
40
  SELECTIVE_FULL: ${{ inputs.full }}
41
41
  run: |
42
- export PYTHONPATH="$SELECTIVE_ACTION/../../../src${PYTHONPATH:+:$PYTHONPATH}"
42
+ export PYTHONPATH="$SELECTIVE_ACTION/../../src${PYTHONPATH:+:$PYTHONPATH}"
43
43
  args=(--config "$SELECTIVE_CONFIG" --base "$SELECTIVE_BASE" --github-output "$GITHUB_OUTPUT")
44
44
  if [ "$SELECTIVE_FULL" = true ]; then args+=(--full); fi
45
45
  uv run --no-project --python 3.14 --with pydantic==2.13.4 --with pyyaml==6.0.3 \