From 8cfa074ea67ad6ef3ec03c86e6d9d58e53a13230 Mon Sep 17 00:00:00 2001 From: Julian Tabel Date: Tue, 17 Feb 2026 18:17:23 +0100 Subject: [PATCH] Migrate pre-commit hooks from pre-commit to prek Replace the Python-based pre-commit framework with prek (Rust) for faster hook execution. Convert .pre-commit-config.yaml to prek.toml, remove pre-commit from dev dependencies, and apply ruff auto-fixes (UP037: remove unnecessary string quotes in type annotations). Co-Authored-By: Claude Opus 4.6 --- ...ition-badges-for-boss-pokemon-mechanics.md | 4 +- ...-implement-pre-commit-hooks-for-linting.md | 13 +++-- .pre-commit-config.yaml | 34 -------------- CLAUDE.md | 4 +- backend/pyproject.toml | 2 +- backend/src/app/models/boss_battle.py | 8 ++-- backend/src/app/models/boss_pokemon.py | 4 +- backend/src/app/models/boss_result.py | 4 +- backend/src/app/models/encounter.py | 8 ++-- backend/src/app/models/evolution.py | 4 +- backend/src/app/models/game.py | 4 +- backend/src/app/models/genlocke.py | 8 ++-- backend/src/app/models/nuzlocke_run.py | 6 +-- backend/src/app/models/pokemon.py | 4 +- backend/src/app/models/route.py | 10 ++-- backend/src/app/models/route_encounter.py | 6 +-- backend/src/app/models/version_group.py | 6 +-- prek.toml | 47 +++++++++++++++++++ 18 files changed, 94 insertions(+), 82 deletions(-) delete mode 100644 .pre-commit-config.yaml create mode 100644 prek.toml diff --git a/.beans/nuzlocke-tracker-l12w--add-condition-badges-for-boss-pokemon-mechanics.md b/.beans/nuzlocke-tracker-l12w--add-condition-badges-for-boss-pokemon-mechanics.md index 8f9b04f..6e42e46 100644 --- a/.beans/nuzlocke-tracker-l12w--add-condition-badges-for-boss-pokemon-mechanics.md +++ b/.beans/nuzlocke-tracker-l12w--add-condition-badges-for-boss-pokemon-mechanics.md @@ -1,11 +1,11 @@ --- # nuzlocke-tracker-l12w title: Add condition badges for boss Pokemon mechanics -status: in-progress +status: completed type: feature priority: normal created_at: 2026-02-16T20:11:02Z -updated_at: 2026-02-16T20:11:52Z +updated_at: 2026-02-16T20:17:40Z --- Add visible badges on boss Pokemon that have mechanic-related conditions (Mega Evolution, Gigantamax, Dynamax, Terastallize). Create a ConditionBadge component following the EncounterMethodBadge pattern and integrate it into BossDefeatModal and BossTeamPreview. diff --git a/.beans/nuzlocke-tracker-rb0p--implement-pre-commit-hooks-for-linting.md b/.beans/nuzlocke-tracker-rb0p--implement-pre-commit-hooks-for-linting.md index 82bace0..632c70a 100644 --- a/.beans/nuzlocke-tracker-rb0p--implement-pre-commit-hooks-for-linting.md +++ b/.beans/nuzlocke-tracker-rb0p--implement-pre-commit-hooks-for-linting.md @@ -1,19 +1,18 @@ --- # nuzlocke-tracker-rb0p title: Implement pre-commit hooks for linting -status: todo +status: in-progress type: task priority: high created_at: 2026-02-10T12:05:39Z -updated_at: 2026-02-10T12:05:39Z +updated_at: 2026-02-17T17:15:05Z --- Set up pre-commit hooks to automatically run linting before every commit, catching issues before they reach the pipeline. ## Checklist -- [ ] Install and configure a pre-commit framework (e.g. `pre-commit` for Python, `husky` + `lint-staged` for the frontend, or a unified approach) -- [ ] Add backend hook: `ruff check` + `ruff format --check` on staged Python files -- [ ] Add frontend hook: `eslint` + `tsc` on staged TS/TSX files -- [ ] Update CI workflow to replace lint checks with test runs once the test suite is in place -- [ ] Document the pre-commit setup in CLAUDE.md or DEPLOYMENT.md \ No newline at end of file +- [x] Install and configure a pre-commit framework — migrated from `pre-commit` to `prek` (Rust) +- [x] Add backend hook: `ruff check --fix` + `ruff format` on staged Python files +- [x] Add frontend hook: `oxlint`, `oxfmt --check`, and `tsc -b` on staged TS/TSX files +- [x] Document the pre-commit setup in CLAUDE.md \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 372260e..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,34 +0,0 @@ -repos: - # Backend (Python) — ruff linting + formatting - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.0 - hooks: - - id: ruff - args: [--fix] - files: ^backend/ - - id: ruff-format - files: ^backend/ - - # Frontend (TypeScript/React) — local hooks using project node_modules - - repo: local - hooks: - - id: oxlint - name: oxlint - entry: npx oxlint -c frontend/.oxlintrc.json - language: system - files: ^frontend/src/.*\.(ts|tsx)$ - pass_filenames: true - - - id: oxfmt - name: oxfmt - entry: npx oxfmt --check --config frontend/.oxfmtrc.json - language: system - files: ^frontend/src/.*\.(ts|tsx)$ - pass_filenames: true - - - id: tsc - name: tsc - entry: bash -c 'cd frontend && npx tsc -b' - language: system - files: ^frontend/src/.*\.(ts|tsx)$ - pass_filenames: false diff --git a/CLAUDE.md b/CLAUDE.md index 30d3390..ce1272b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,9 +10,9 @@ # Pre-commit Hooks -This project uses [pre-commit](https://pre-commit.com/) to run linting and formatting checks before each commit. +This project uses [prek](https://prek.j178.dev/) (Rust-based pre-commit framework) to run linting and formatting checks before each commit. -**Setup:** `pip install pre-commit && pre-commit install` +**Setup:** `prek install` **Hooks configured:** - **Backend:** `ruff check --fix` and `ruff format` on Python files under `backend/` diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 10d7d9a..3dc9d7f 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -19,7 +19,7 @@ dependencies = [ dev = [ "ruff==0.15.0", "ty==0.0.17", - "pre-commit==4.5.1", + "pytest==9.0.2", "pytest-asyncio==1.3.0", "httpx==0.28.1", diff --git a/backend/src/app/models/boss_battle.py b/backend/src/app/models/boss_battle.py index 4049079..5a7c00d 100644 --- a/backend/src/app/models/boss_battle.py +++ b/backend/src/app/models/boss_battle.py @@ -37,10 +37,10 @@ class BossBattle(Base): ForeignKey("games.id"), index=True, default=None ) - version_group: Mapped["VersionGroup"] = relationship(back_populates="boss_battles") - after_route: Mapped["Route | None"] = relationship() - game: Mapped["Game | None"] = relationship() - pokemon: Mapped[list["BossPokemon"]] = relationship( + version_group: Mapped[VersionGroup] = relationship(back_populates="boss_battles") + after_route: Mapped[Route | None] = relationship() + game: Mapped[Game | None] = relationship() + pokemon: Mapped[list[BossPokemon]] = relationship( back_populates="boss_battle", cascade="all, delete-orphan" ) diff --git a/backend/src/app/models/boss_pokemon.py b/backend/src/app/models/boss_pokemon.py index 56aa8cb..43f18ce 100644 --- a/backend/src/app/models/boss_pokemon.py +++ b/backend/src/app/models/boss_pokemon.py @@ -16,8 +16,8 @@ class BossPokemon(Base): order: Mapped[int] = mapped_column(SmallInteger) condition_label: Mapped[str | None] = mapped_column(String(100)) - boss_battle: Mapped["BossBattle"] = relationship(back_populates="pokemon") - pokemon: Mapped["Pokemon"] = relationship() + boss_battle: Mapped[BossBattle] = relationship(back_populates="pokemon") + pokemon: Mapped[Pokemon] = relationship() def __repr__(self) -> str: return f"" diff --git a/backend/src/app/models/boss_result.py b/backend/src/app/models/boss_result.py index 4cd4ca7..84b2293 100644 --- a/backend/src/app/models/boss_result.py +++ b/backend/src/app/models/boss_result.py @@ -23,8 +23,8 @@ class BossResult(Base): attempts: Mapped[int] = mapped_column(SmallInteger, default=1) completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) - run: Mapped["NuzlockeRun"] = relationship(back_populates="boss_results") - boss_battle: Mapped["BossBattle"] = relationship() + run: Mapped[NuzlockeRun] = relationship(back_populates="boss_results") + boss_battle: Mapped[BossBattle] = relationship() def __repr__(self) -> str: return f"" diff --git a/backend/src/app/models/encounter.py b/backend/src/app/models/encounter.py index 5bf1418..241e243 100644 --- a/backend/src/app/models/encounter.py +++ b/backend/src/app/models/encounter.py @@ -28,12 +28,12 @@ class Encounter(Base): DateTime(timezone=True), server_default=func.now() ) - run: Mapped["NuzlockeRun"] = relationship(back_populates="encounters") - route: Mapped["Route"] = relationship(back_populates="encounters") - pokemon: Mapped["Pokemon"] = relationship( + run: Mapped[NuzlockeRun] = relationship(back_populates="encounters") + route: Mapped[Route] = relationship(back_populates="encounters") + pokemon: Mapped[Pokemon] = relationship( foreign_keys=[pokemon_id], back_populates="encounters" ) - current_pokemon: Mapped["Pokemon | None"] = relationship( + current_pokemon: Mapped[Pokemon | None] = relationship( foreign_keys=[current_pokemon_id] ) diff --git a/backend/src/app/models/evolution.py b/backend/src/app/models/evolution.py index 80a2b83..8cce554 100644 --- a/backend/src/app/models/evolution.py +++ b/backend/src/app/models/evolution.py @@ -19,8 +19,8 @@ class Evolution(Base): ) # catch-all for other conditions region: Mapped[str | None] = mapped_column(String(30)) - from_pokemon: Mapped["Pokemon"] = relationship(foreign_keys=[from_pokemon_id]) - to_pokemon: Mapped["Pokemon"] = relationship(foreign_keys=[to_pokemon_id]) + from_pokemon: Mapped[Pokemon] = relationship(foreign_keys=[from_pokemon_id]) + to_pokemon: Mapped[Pokemon] = relationship(foreign_keys=[to_pokemon_id]) def __repr__(self) -> str: return f"" diff --git a/backend/src/app/models/game.py b/backend/src/app/models/game.py index bd07b87..6558118 100644 --- a/backend/src/app/models/game.py +++ b/backend/src/app/models/game.py @@ -22,8 +22,8 @@ class Game(Base): ForeignKey("version_groups.id"), index=True ) - version_group: Mapped["VersionGroup | None"] = relationship(back_populates="games") - runs: Mapped[list["NuzlockeRun"]] = relationship(back_populates="game") + version_group: Mapped[VersionGroup | None] = relationship(back_populates="games") + runs: Mapped[list[NuzlockeRun]] = relationship(back_populates="game") def __repr__(self) -> str: return f"" diff --git a/backend/src/app/models/genlocke.py b/backend/src/app/models/genlocke.py index e6a6f54..32243ca 100644 --- a/backend/src/app/models/genlocke.py +++ b/backend/src/app/models/genlocke.py @@ -23,7 +23,7 @@ class Genlocke(Base): DateTime(timezone=True), server_default=func.now() ) - legs: Mapped[list["GenlockeLeg"]] = relationship( + legs: Mapped[list[GenlockeLeg]] = relationship( back_populates="genlocke", order_by="GenlockeLeg.leg_order" ) @@ -45,6 +45,6 @@ class GenlockeLeg(Base): leg_order: Mapped[int] = mapped_column(SmallInteger) retired_pokemon_ids: Mapped[list[int] | None] = mapped_column(JSONB, default=None) - genlocke: Mapped["Genlocke"] = relationship(back_populates="legs") - game: Mapped["Game"] = relationship() - run: Mapped["NuzlockeRun | None"] = relationship() + genlocke: Mapped[Genlocke] = relationship(back_populates="legs") + game: Mapped[Game] = relationship() + run: Mapped[NuzlockeRun | None] = relationship() diff --git a/backend/src/app/models/nuzlocke_run.py b/backend/src/app/models/nuzlocke_run.py index 795eff4..abd978c 100644 --- a/backend/src/app/models/nuzlocke_run.py +++ b/backend/src/app/models/nuzlocke_run.py @@ -24,9 +24,9 @@ class NuzlockeRun(Base): hof_encounter_ids: Mapped[list[int] | None] = mapped_column(JSONB, default=None) naming_scheme: Mapped[str | None] = mapped_column(String(50), nullable=True) - game: Mapped["Game"] = relationship(back_populates="runs") - encounters: Mapped[list["Encounter"]] = relationship(back_populates="run") - boss_results: Mapped[list["BossResult"]] = relationship(back_populates="run") + game: Mapped[Game] = relationship(back_populates="runs") + encounters: Mapped[list[Encounter]] = relationship(back_populates="run") + boss_results: Mapped[list[BossResult]] = relationship(back_populates="run") def __repr__(self) -> str: return ( diff --git a/backend/src/app/models/pokemon.py b/backend/src/app/models/pokemon.py index 23c0544..3724944 100644 --- a/backend/src/app/models/pokemon.py +++ b/backend/src/app/models/pokemon.py @@ -15,10 +15,10 @@ class Pokemon(Base): types: Mapped[list[str]] = mapped_column(ARRAY(String(20))) sprite_url: Mapped[str | None] = mapped_column(String(500)) - route_encounters: Mapped[list["RouteEncounter"]] = relationship( + route_encounters: Mapped[list[RouteEncounter]] = relationship( back_populates="pokemon" ) - encounters: Mapped[list["Encounter"]] = relationship( + encounters: Mapped[list[Encounter]] = relationship( foreign_keys="[Encounter.pokemon_id]", back_populates="pokemon" ) diff --git a/backend/src/app/models/route.py b/backend/src/app/models/route.py index 9f1bb6b..0126489 100644 --- a/backend/src/app/models/route.py +++ b/backend/src/app/models/route.py @@ -23,17 +23,17 @@ class Route(Base): ) pinwheel_zone: Mapped[int | None] = mapped_column(SmallInteger, default=None) - version_group: Mapped["VersionGroup"] = relationship(back_populates="routes") - route_encounters: Mapped[list["RouteEncounter"]] = relationship( + version_group: Mapped[VersionGroup] = relationship(back_populates="routes") + route_encounters: Mapped[list[RouteEncounter]] = relationship( back_populates="route", cascade="all, delete-orphan" ) - encounters: Mapped[list["Encounter"]] = relationship(back_populates="route") + encounters: Mapped[list[Encounter]] = relationship(back_populates="route") # Self-referential relationships for route grouping - parent: Mapped["Route | None"] = relationship( + parent: Mapped[Route | None] = relationship( back_populates="children", remote_side=[id] ) - children: Mapped[list["Route"]] = relationship( + children: Mapped[list[Route]] = relationship( back_populates="parent", cascade="all, delete-orphan" ) diff --git a/backend/src/app/models/route_encounter.py b/backend/src/app/models/route_encounter.py index 5b32caf..cafe722 100644 --- a/backend/src/app/models/route_encounter.py +++ b/backend/src/app/models/route_encounter.py @@ -25,9 +25,9 @@ class RouteEncounter(Base): min_level: Mapped[int] = mapped_column(SmallInteger) max_level: Mapped[int] = mapped_column(SmallInteger) - route: Mapped["Route"] = relationship(back_populates="route_encounters") - pokemon: Mapped["Pokemon"] = relationship(back_populates="route_encounters") - game: Mapped["Game"] = relationship() + route: Mapped[Route] = relationship(back_populates="route_encounters") + pokemon: Mapped[Pokemon] = relationship(back_populates="route_encounters") + game: Mapped[Game] = relationship() def __repr__(self) -> str: return f"" diff --git a/backend/src/app/models/version_group.py b/backend/src/app/models/version_group.py index e0f0ccc..c1fe64e 100644 --- a/backend/src/app/models/version_group.py +++ b/backend/src/app/models/version_group.py @@ -11,9 +11,9 @@ class VersionGroup(Base): name: Mapped[str] = mapped_column(String(100)) slug: Mapped[str] = mapped_column(String(100), unique=True) - games: Mapped[list["Game"]] = relationship(back_populates="version_group") - routes: Mapped[list["Route"]] = relationship(back_populates="version_group") - boss_battles: Mapped[list["BossBattle"]] = relationship( + games: Mapped[list[Game]] = relationship(back_populates="version_group") + routes: Mapped[list[Route]] = relationship(back_populates="version_group") + boss_battles: Mapped[list[BossBattle]] = relationship( back_populates="version_group" ) diff --git a/prek.toml b/prek.toml new file mode 100644 index 0000000..62e8b0f --- /dev/null +++ b/prek.toml @@ -0,0 +1,47 @@ +# Configuration file for `prek`, a git hook framework written in Rust. +# See https://prek.j178.dev for more information. +#:schema https://www.schemastore.org/prek.json + +[[repos]] +repo = "https://github.com/astral-sh/ruff-pre-commit" +rev = "v0.15.0" +hooks = [ + { + id = "ruff", + args = ["--fix"], + files = "^backend/" + }, + { + id = "ruff-format", + files = "^backend/" + } +] + +[[repos]] +repo = "local" +hooks = [ + { + id = "oxlint", + name = "oxlint", + entry = "npx oxlint -c frontend/.oxlintrc.json", + language = "system", + files = '^frontend/src/.*\.(ts|tsx)$', + pass_filenames = true + }, + { + id = "oxfmt", + name = "oxfmt", + entry = "npx oxfmt --check --config frontend/.oxfmtrc.json", + language = "system", + files = '^frontend/src/.*\.(ts|tsx)$', + pass_filenames = true + }, + { + id = "tsc", + name = "tsc", + entry = "bash -c 'cd frontend && npx tsc -b'", + language = "system", + files = '^frontend/src/.*\.(ts|tsx)$', + pass_filenames = false + } +]