Merge pull request #947 from elemated/fix-igdb-game-key-art-type #820
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Lint | |
| on: | |
| pull_request: | |
| paths-ignore: | |
| - ".github/workflows/**" | |
| push: | |
| branches: | |
| - latest | |
| - release | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| lint: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 | |
| with: | |
| version: "0.12.3" | |
| - name: Check dependency lock | |
| run: uv lock --check | |
| - name: Install lint dependencies | |
| run: uv sync --locked --only-group lint | |
| - name: Ruff | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| IS_PR: ${{ github.event_name == 'pull_request' }} | |
| run: | | |
| if [ "$IS_PR" != "true" ]; then | |
| echo "Not a pull request - running full check." | |
| uv run --no-sync ruff check src | |
| exit $? | |
| fi | |
| uv run --no-sync python - <<'PY' | |
| import json, os, re, subprocess, sys | |
| base, head = os.environ["BASE_SHA"], os.environ["HEAD_SHA"] | |
| # Lines added/modified by this PR, per file. | |
| diff = subprocess.run( | |
| ["git", "diff", "--unified=0", f"{base}...{head}", "--", "src"], | |
| capture_output=True, text=True, check=True, | |
| ).stdout | |
| changed: dict[str, set[int]] = {} | |
| path = None | |
| hunk = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@") | |
| for line in diff.splitlines(): | |
| if line.startswith("+++ b/"): | |
| path = line[6:] | |
| elif line.startswith("@@") and path: | |
| m = hunk.match(line) | |
| if m: | |
| start = int(m.group(1)) | |
| count = int(m.group(2) or 1) | |
| changed.setdefault(path, set()).update( | |
| range(start, start + count) | |
| ) | |
| changed = {p: lines for p, lines in changed.items() if p.endswith(".py")} | |
| if not changed: | |
| print("No changed Python lines under src/ - nothing to lint.") | |
| sys.exit(0) | |
| proc = subprocess.run( | |
| ["ruff", "check", "src", "--output-format=json", "--no-cache"], | |
| capture_output=True, text=True, | |
| ) | |
| if proc.returncode not in (0, 1): | |
| sys.stderr.write(proc.stderr) | |
| sys.exit(proc.returncode) | |
| diagnostics = json.loads(proc.stdout or "[]") | |
| repo = os.getcwd() | |
| offending = [] | |
| for d in diagnostics: | |
| rel = os.path.relpath(d["filename"], repo) | |
| row = (d.get("location") or {}).get("row") | |
| if row is not None and row in changed.get(rel, ()): | |
| offending.append((rel, row, d["code"], d["message"])) | |
| total = len(diagnostics) | |
| print(f"{total} violations exist in src/; gating on changed lines only.") | |
| if offending: | |
| print(f"\n{len(offending)} violation(s) on lines this PR changed:\n") | |
| for rel, row, code, msg in sorted(offending): | |
| print(f" {rel}:{row}: {code} {msg}") | |
| sys.exit(1) | |
| print("No violations on changed lines.") | |
| PY |