diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000..b5d741a --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,69 @@ +name: pre-commit (PR only on changed files) + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +jobs: + detect_changes: + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.changed_files.outputs.changed }} + + steps: + - name: Checkout full history + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Detect changed files + id: changed_files + env: + BASE_REF: ${{ github.base_ref }} + run: | + git fetch origin "$BASE_REF" + CHANGED_FILES=$(git diff --name-only --diff-filter=d "origin/$BASE_REF...HEAD") + + delimiter="changed_$(openssl rand -hex 16)" + { + echo "changed<<$delimiter" + echo "$CHANGED_FILES" + echo "$delimiter" + } >> "$GITHUB_OUTPUT" + + - name: Show changed files + env: + CHANGED_FILES: ${{ steps.changed_files.outputs.changed }} + run: | + echo "Changed files:" + echo "$CHANGED_FILES" + + precommit: + needs: detect_changes + runs-on: ubuntu-latest + if: ${{ needs.detect_changes.outputs.changed != '' }} + + steps: + - name: Checkout PR branch + uses: actions/checkout@v6 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.sha }} + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Install pre-commit + run: pip install pre-commit + + - name: Run pre-commit (CI check-only stage) on changed files + env: + CHANGED_FILES: ${{ needs.detect_changes.outputs.changed }} + run: | + mapfile -t files <<< "$CHANGED_FILES" + pre-commit run --hook-stage manual --files "${files[@]}" --show-diff-on-failure diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..533b2bb --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,55 @@ +default_stages: [pre-commit] + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: check-added-large-files + stages: [pre-commit, manual] + - id: check-yaml + stages: [pre-commit, manual] + - id: check-toml + stages: [pre-commit, manual] + - id: check-merge-conflict + stages: [pre-commit, manual] + - id: name-tests-test + args: [--pytest-test-first] + stages: [pre-commit, manual] + - id: check-json + stages: [pre-commit, manual] + # In CI a fixer fails by modifying the file; --show-diff-on-failure prints the change + - id: end-of-file-fixer + stages: [pre-commit, manual] + - id: trailing-whitespace + stages: [pre-commit, manual] + + - repo: https://github.com/tox-dev/pyproject-fmt + rev: v2.19.0 + hooks: + - id: pyproject-fmt + stages: [pre-commit, manual] + + - repo: https://github.com/abravalheri/validate-pyproject + rev: v0.25 + hooks: + - id: validate-pyproject + stages: [pre-commit, manual] + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.15.6 + hooks: + - id: ruff-check + name: ruff-check (fix) + args: [--fix] + stages: [pre-commit] + - id: ruff-format + name: ruff-format (write) + stages: [pre-commit] + - id: ruff-check + name: ruff-check (ci) + args: [--no-fix, --output-format=github] + stages: [manual] + - id: ruff-format + name: ruff-format (ci) + args: [--check, --diff] + stages: [manual] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..eeee3c8 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,40 @@ +[tool.ruff] +# TODO: @C-Achard "py310" once requires-python is ">=3.10" (CI update PR); main still tests 3.9 +target-version = "py39" +line-length = 120 +format.docstring-code-format = true +lint.select = [ + "ANN", + "ARG", + "B", + "C4", + "D", + "DTZ", + "E", + "ERA", + "F", + "I", + "N", + "PIE", + "RET", + "RUF", + "SIM", + "UP", +] +lint.ignore = [ + "ANN401", + "B007", + "D100", + "D101", + "D102", + "D104", + "D106", + "D107", + "D202", + "E741", + "N803", + "N806", +] +lint.per-file-ignores."__init__.py" = [ "E402", "F401" ] +lint.per-file-ignores."tests/**" = [ "D" ] +lint.pydocstyle.convention = "google"