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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@
- [ ] `PYTHONPATH=. pytest -q`

## Merge checklist
- [ ] All required checks are **green** (static analysis, tests, compiler smoke, BLAS/LAPACK, and parser reference).
- [ ] If parser Fortran data or goldens changed, the PR explains why.
- [ ] If using `ignore-parser-reference-guard`, the PR explains why it is safe.
- [ ] All required checks are **green**.
- [ ] Parser fixture or golden changes are explained.
139 changes: 2 additions & 137 deletions .github/workflows/merge-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,141 +61,9 @@ jobs:
continue-on-error: true
run: python -m radon mi prik -s

parser-reference-guard:
name: Parser reference guard · Ubuntu 24.04
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Verify parser references were updated when needed
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }}
run: |
set -euo pipefail
CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA")

echo "Changed files:"
echo "$CHANGED_FILES"
echo "PR labels: ${PR_LABELS:-<none>}"

FORCE_LABEL="require-parser-reference-update"
IGNORE_LABEL="ignore-parser-reference-guard"

if [[ ",${PR_LABELS}," == *",${FORCE_LABEL},"* && \
",${PR_LABELS}," == *",${IGNORE_LABEL},"* ]]; then
echo "Conflicting labels: ${FORCE_LABEL} and ${IGNORE_LABEL}. Remove one."
exit 1
fi

if [[ ",${PR_LABELS}," == *",${IGNORE_LABEL},"* ]]; then
echo "${IGNORE_LABEL} label present; skipping guard."
exit 0
fi

C_DOC="docs/developer/c-parser-reference.md"
FORTRAN_DOC="docs/developer/fortran-parser-reference.md"
PYI_DOC="docs/user/reference/semantic-pyi-format.md"

C_DOC_CHANGED=false
FORTRAN_DOC_CHANGED=false
PYI_DOC_CHANGED=false
C_PARSER_CHANGED=false
FORTRAN_PARSER_CHANGED=false
PYI_PARSER_CHANGED=false
SHARED_PARSER_CHANGED=false

if grep -Fxq "$C_DOC" <<< "$CHANGED_FILES"; then
C_DOC_CHANGED=true
fi
if grep -Fxq "$FORTRAN_DOC" <<< "$CHANGED_FILES"; then
FORTRAN_DOC_CHANGED=true
fi
if grep -Fxq "$PYI_DOC" <<< "$CHANGED_FILES"; then
PYI_DOC_CHANGED=true
fi

while IFS= read -r changed_file; do
case "$changed_file" in
prik/parsers/c/*|tests/c/parsing/*|tests/c/fixtures/*|tests/c/probes/test_c_types.py)
C_PARSER_CHANGED=true
;;
prik/parsers/fortran/*|tests/fortran/source_parsing/parsing/*|tests/fortran/data_types/probes/test_fortran_type_probes.py)
FORTRAN_PARSER_CHANGED=true
;;
prik/parsers/pyi/*|tests/fortran/semantic_pyi_format/*)
PYI_PARSER_CHANGED=true
;;
tests/fortran/command_line_interface/pipeline/*|\
tests/fortran/source_preprocessing/preprocessing/*|\
prik/parsers/__init__.py|\
prik/preprocessing.py)
SHARED_PARSER_CHANGED=true
;;
esac
done <<< "$CHANGED_FILES"

if [[ ",${PR_LABELS}," == *",${FORCE_LABEL},"* ]]; then
if [ "$C_DOC_CHANGED" = true ] || [ "$FORTRAN_DOC_CHANGED" = true ] || [ "$PYI_DOC_CHANGED" = true ]; then
echo "${FORCE_LABEL} label present and at least one parser reference changed."
else
echo "${FORCE_LABEL} label present, but no parser reference changed."
echo "Update ${C_DOC}, ${FORTRAN_DOC}, or ${PYI_DOC}, or remove ${FORCE_LABEL}."
exit 1
fi
fi

FAILED=false

if [ "$C_PARSER_CHANGED" = true ] && [ "$C_DOC_CHANGED" != true ]; then
echo "C parser-related files changed without updating ${C_DOC}."
FAILED=true
fi

if [ "$FORTRAN_PARSER_CHANGED" = true ] && [ "$FORTRAN_DOC_CHANGED" != true ]; then
echo "Fortran parser-related files changed without updating ${FORTRAN_DOC}."
FAILED=true
fi

if [ "$PYI_PARSER_CHANGED" = true ] && [ "$PYI_DOC_CHANGED" != true ]; then
echo "Semantic .pyi parser-related files changed without updating ${PYI_DOC}."
FAILED=true
fi

if [ "$SHARED_PARSER_CHANGED" = true ] && \
[ "$C_DOC_CHANGED" != true ] && \
[ "$FORTRAN_DOC_CHANGED" != true ] && \
[ "$PYI_DOC_CHANGED" != true ]; then
echo "Shared parser workflow files changed without updating a parser reference."
echo "Update ${C_DOC}, ${FORTRAN_DOC}, or ${PYI_DOC}, whichever behavior changed."
FAILED=true
fi

if [ "$FAILED" = true ]; then
echo "Use ${IGNORE_LABEL} only when the parser reference is already accurate."
exit 1
fi

if [ "$C_DOC_CHANGED" = true ]; then
echo "${C_DOC} changed."
fi
if [ "$FORTRAN_DOC_CHANGED" = true ]; then
echo "${FORTRAN_DOC} changed."
fi
if [ "$PYI_DOC_CHANGED" = true ]; then
echo "${PYI_DOC} changed."
fi

echo "Parser reference guard passed."

compiler-smoke:
name: Compiler smoke · ${{ matrix.display_name }}
needs: [static-analysis, parser-reference-guard]
needs: static-analysis
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
Expand Down Expand Up @@ -294,7 +162,7 @@ jobs:

compiler-smoke-macos:
name: Compiler smoke · macOS 15 ARM64 · LLVM Flang · Python 3.12
needs: [static-analysis, parser-reference-guard]
needs: static-analysis
runs-on: macos-15
timeout-minutes: 60
permissions:
Expand Down Expand Up @@ -769,7 +637,6 @@ jobs:
if: ${{ always() }}
needs:
- static-analysis
- parser-reference-guard
- compiler-smoke
- compiler-smoke-macos
- unit-tests
Expand All @@ -781,7 +648,6 @@ jobs:
permissions: {}
env:
STATIC_ANALYSIS_RESULT: ${{ needs.static-analysis.result }}
PARSER_REFERENCE_RESULT: ${{ needs.parser-reference-guard.result }}
COMPILER_SMOKE_RESULT: ${{ needs.compiler-smoke.result }}
COMPILER_SMOKE_MACOS_RESULT: ${{ needs.compiler-smoke-macos.result }}
UNIT_TESTS_RESULT: ${{ needs.unit-tests.result }}
Expand All @@ -797,7 +663,6 @@ jobs:
failed=0
for staged_result in \
"static-analysis=$STATIC_ANALYSIS_RESULT" \
"parser-reference=$PARSER_REFERENCE_RESULT" \
"compiler-smoke=$COMPILER_SMOKE_RESULT" \
"compiler-smoke-macos=$COMPILER_SMOKE_MACOS_RESULT" \
"unit-tests=$UNIT_TESTS_RESULT" \
Expand Down
78 changes: 43 additions & 35 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
## Contributing

### Contribution license

prik is distributed under the MIT License. By submitting a contribution, you
agree that your contribution is licensed under the same MIT terms and represent
that you have the right to submit it. If an employer or another organization
owns the work, obtain its authorization before contributing.

### Pull requests

- **CI must be green before merging**: do not merge a PR unless all checks pass (including `test` and `parser-reference-guard`).
- **Explain fixture/golden updates**: if you update a parser source or JSON model under `tests/fortran/source_parsing/parsing/fixtures/`, include a short note in the PR describing why the expected output changed.
- **Run the QA stack for parser/compiler changes**: install `python -m pip install -e ".[qa]"` and use the workflows in `docs/developer/quality-assurance.md`.

### Parser reference guard

This repo includes a CI guard that may require updating parser reference docs
when parser-related files change.

- **C parser changes**: if you change `prik/parsers/c/`, `tests/c/fixtures/parser/`, or
`tests/c/fixtures/native/`, update `docs/c_parser.md` when the change affects the
documented feature inventory, public API, diagnostics, fixtures, semantic
handoff, or maintenance workflow. The guard also treats
`tests/c/probes/test_c_types.py` as C parser related.
- **Fortran parser changes**: if you change `prik/parsers/fortran/` or
`tests/fortran/source_parsing/parsing/`, update
`docs/developer/fortran-parser-reference.md` when the change affects the documented feature
inventory, public API, diagnostics, fixtures, semantic handoff, or
maintenance workflow. The guard also tracks focused Fortran parser tests
under `tests/fortran/source_parsing/parsing/`.
- **Shared parser workflow changes**: if you change shared parser CLI or
preprocessing behavior, update `docs/c_parser.md` or
`docs/fortran_parser.md`, whichever parser behavior changed.
- **Bypass (use sparingly)**: add the PR label `ignore-parser-reference-guard` to skip that guard for changes that do not meaningfully affect the reference.
# Contributing to PRIK

Thanks for helping make native Python interfaces easier to build.

## Get started

Create a focused branch and install PRIK with its development tools:

```bash
python3 -m pip install -e ".[qa]"
```

Run the smallest relevant test while you work:

```bash
PYTHONPATH=. python3 -m pytest -q path/to/tests
```

## Before opening a pull request

- Add or update tests for changed behavior.
- Update the user guide when the public API, CLI, or supported behavior changes.
- Add user-visible changes to **Unreleased** in `CHANGELOG.md`.
- Run Ruff and the relevant tests:

```bash
python3 -m ruff check .
python3 -m ruff format --check .
PYTHONPATH=. python3 -m pytest -q path/to/tests
```

Keep the pull request easy to review: explain the problem, the solution, and
how you verified it. All required GitHub checks must pass before merge.

For the complete workflow, see the
[development guide](docs/developer/development-workflow.md) and
[quality-assurance guide](docs/developer/quality-assurance.md).

## License

Contributions are accepted under the [MIT License](LICENSE). By submitting a
contribution, you confirm that you have the right to license it under those
terms.
6 changes: 1 addition & 5 deletions docs/developer/c-parser-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@ PRIK_C_DOCS_END &#45;&#45;>
<!&#45;&#45; PRIK_C_DOCS_START
Parser-related pull requests should update this file when the documented
feature inventory, public API, diagnostics, project behavior, semantic handoff,
or maintenance workflow changes. The parser-reference guard checks C, Fortran,
and semantic `.pyi` references independently. It watches `prik/parsers/c/`, `tests/c/fixtures/parser/`,
`tests/c/fixtures/native/`, and C standard-type probe tests and expects
`docs/developer/c-parser-reference.md` to change unless the PR is explicitly labeled to skip the
guard.
or maintenance workflow changes.
PRIK_C_DOCS_END &#45;&#45;>

<!&#45;&#45; PRIK_C_DOCS_START
Expand Down
6 changes: 1 addition & 5 deletions docs/developer/fortran-parser-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,7 @@ The implementation inventory is maintained across these surfaces:
<!-- PRIK_C_DOCS_START
Parser-related pull requests should update this file when the documented
feature inventory, public API, diagnostics, project behavior, semantic handoff,
or maintenance workflow changes. The parser-reference guard watches C,
Fortran, and semantic `.pyi` references independently. For Fortran, it watches
`prik/parsers/fortran/` and `tests/fortran/source_parsing/parsing/`. It expects
`docs/developer/fortran-parser-reference.md` to change unless the PR is explicitly labeled to skip
the guard.
or maintenance workflow changes.
PRIK_C_DOCS_END -->

`parse_file` is the central orchestration path. It first slices the source into
Expand Down
5 changes: 2 additions & 3 deletions docs/developer/quality-assurance.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ testing and pre-commit are not part of the active stack.
Active GitHub Actions checks use stable, self-contained job names. Pull requests
are coordinated by `Pull Request` in five stages:

1. Static analysis and the parser-reference contract run in parallel.
2. Alternate-compiler smoke testing starts only after both fast policy checks
succeed.
1. Static analysis runs first.
2. Alternate-compiler smoke testing starts after static analysis succeeds.
3. The unit-test matrix starts after compiler smoke testing succeeds; its
Ubuntu Python 3.12 entry owns the project-coverage gate instead of repeating
that suite in a separate job.
Expand Down
6 changes: 1 addition & 5 deletions docs/old_docs/c_parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ changes documented here.

Parser-related pull requests should update this file when the documented
feature inventory, public API, diagnostics, project behavior, semantic handoff,
or maintenance workflow changes. The parser-reference guard checks C and
Fortran references independently. It watches `prik/c_parser/`, `tests/parser/c/`,
`tests/data/c/`, and C standard-type probe tests and expects
`docs/c_parser.md` to change unless the PR is explicitly labeled to skip the
guard.
or maintenance workflow changes.

## Purpose

Expand Down
9 changes: 2 additions & 7 deletions docs/old_docs/fortran_parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ or `prik.fortran_parser` package imports.

This file is the single maintained Fortran parser reference. It replaces the
older standalone implementation-reference document; parser feature inventory,
testing workflow, and maintenance guard policy live here.
testing workflow, and maintenance guidance live here.

The implementation inventory is maintained across these surfaces:

Expand All @@ -141,12 +141,7 @@ The implementation inventory is maintained across these surfaces:

Parser-related pull requests should update this file when the documented
feature inventory, public API, diagnostics, project behavior, semantic handoff,
or maintenance workflow changes. The parser-reference guard watches
Fortran and C references independently. For Fortran, it watches
`prik/fortran_parser/`, `tests/parser/fortran/`, `tests/data/fortran/`, and focused
Fortran parser tests directly under `tests/parser/`. It expects
`docs/fortran_parser.md` to change unless the PR is explicitly labeled to skip
the guard.
or maintenance workflow changes.

`parse_file` is the central orchestration path. It first slices the source into
direct file-level units, then each unit visitor parses only its own substring
Expand Down
4 changes: 2 additions & 2 deletions docs/user/reference/semantic-pyi-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ Status terms used below:
- **Roadmap**: design direction, not implemented wrapper behavior.

Parser-related pull requests that change `prik/parsers/pyi/` or its focused
loading tests must update this reference. The parser-reference guard checks
that contract independently from the language parser references.
loading tests should update this reference when the documented behavior
changes.

## Contract Imports

Expand Down
11 changes: 4 additions & 7 deletions tests/shared/architecture/test_test_suite_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,6 @@ def test_active_github_action_checks_use_distinct_workflow_scopes_and_job_names(
},
MERGE_VALIDATION_WORKFLOW: {
"static-analysis": "Static analysis · Ubuntu 24.04 · Python 3.12",
"parser-reference-guard": "Parser reference guard · Ubuntu 24.04",
"compiler-smoke": "Compiler smoke · ${{ matrix.display_name }}",
"compiler-smoke-macos": "Compiler smoke · macOS 15 ARM64 · LLVM Flang · Python 3.12",
"unit-tests": "${{ matrix.display_name }}",
Expand Down Expand Up @@ -420,14 +419,13 @@ def test_pull_request_declares_direct_staged_jobs_and_always_reports_the_gate()
assert "cancel-in-progress: true" in workflow
assert "uses: ./.github/workflows/" not in workflow

for job_id in ("static-analysis", "parser-reference-guard"):
block = _github_action_job_block(MERGE_VALIDATION_WORKFLOW, job_id)
assert "needs:" not in block
assert "runs-on:" in block
static_analysis = _github_action_job_block(MERGE_VALIDATION_WORKFLOW, "static-analysis")
assert "needs:" not in static_analysis
assert "runs-on:" in static_analysis

for job_id in ("compiler-smoke", "compiler-smoke-macos"):
block = _github_action_job_block(MERGE_VALIDATION_WORKFLOW, job_id)
assert "needs: [static-analysis, parser-reference-guard]" in block
assert "needs: static-analysis" in block
assert "runs-on:" in block

for job_id in ("unit-tests", "unit-tests-macos"):
Expand Down Expand Up @@ -466,7 +464,6 @@ def test_pull_request_declares_direct_staged_jobs_and_always_reports_the_gate()
assert "if: ${{ always() }}" in gate
for dependency in (
"static-analysis",
"parser-reference-guard",
"compiler-smoke",
"compiler-smoke-macos",
"unit-tests",
Expand Down
Loading