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 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
# nuzlocke-tracker-l12w
|
# nuzlocke-tracker-l12w
|
||||||
title: Add condition badges for boss Pokemon mechanics
|
title: Add condition badges for boss Pokemon mechanics
|
||||||
status: in-progress
|
status: completed
|
||||||
type: feature
|
type: feature
|
||||||
priority: normal
|
priority: normal
|
||||||
created_at: 2026-02-16T20:11:02Z
|
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.
|
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.
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
---
|
---
|
||||||
# nuzlocke-tracker-rb0p
|
# nuzlocke-tracker-rb0p
|
||||||
title: Implement pre-commit hooks for linting
|
title: Implement pre-commit hooks for linting
|
||||||
status: todo
|
status: in-progress
|
||||||
type: task
|
type: task
|
||||||
priority: high
|
priority: high
|
||||||
created_at: 2026-02-10T12:05:39Z
|
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.
|
Set up pre-commit hooks to automatically run linting before every commit, catching issues before they reach the pipeline.
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
- [ ] Install and configure a pre-commit framework (e.g. `pre-commit` for Python, `husky` + `lint-staged` for the frontend, or a unified approach)
|
- [x] Install and configure a pre-commit framework — migrated from `pre-commit` to `prek` (Rust)
|
||||||
- [ ] Add backend hook: `ruff check` + `ruff format --check` on staged Python files
|
- [x] Add backend hook: `ruff check --fix` + `ruff format` on staged Python files
|
||||||
- [ ] Add frontend hook: `eslint` + `tsc` on staged TS/TSX files
|
- [x] Add frontend hook: `oxlint`, `oxfmt --check`, and `tsc -b` on staged TS/TSX files
|
||||||
- [ ] Update CI workflow to replace lint checks with test runs once the test suite is in place
|
- [x] Document the pre-commit setup in CLAUDE.md
|
||||||
- [ ] Document the pre-commit setup in CLAUDE.md or DEPLOYMENT.md
|
|
||||||
@@ -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
|
|
||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
# Pre-commit Hooks
|
# 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:**
|
**Hooks configured:**
|
||||||
- **Backend:** `ruff check --fix` and `ruff format` on Python files under `backend/`
|
- **Backend:** `ruff check --fix` and `ruff format` on Python files under `backend/`
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ dependencies = [
|
|||||||
dev = [
|
dev = [
|
||||||
"ruff==0.15.0",
|
"ruff==0.15.0",
|
||||||
"ty==0.0.17",
|
"ty==0.0.17",
|
||||||
"pre-commit==4.5.1",
|
|
||||||
"pytest==9.0.2",
|
"pytest==9.0.2",
|
||||||
"pytest-asyncio==1.3.0",
|
"pytest-asyncio==1.3.0",
|
||||||
"httpx==0.28.1",
|
"httpx==0.28.1",
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ class BossBattle(Base):
|
|||||||
ForeignKey("games.id"), index=True, default=None
|
ForeignKey("games.id"), index=True, default=None
|
||||||
)
|
)
|
||||||
|
|
||||||
version_group: Mapped["VersionGroup"] = relationship(back_populates="boss_battles")
|
version_group: Mapped[VersionGroup] = relationship(back_populates="boss_battles")
|
||||||
after_route: Mapped["Route | None"] = relationship()
|
after_route: Mapped[Route | None] = relationship()
|
||||||
game: Mapped["Game | None"] = relationship()
|
game: Mapped[Game | None] = relationship()
|
||||||
pokemon: Mapped[list["BossPokemon"]] = relationship(
|
pokemon: Mapped[list[BossPokemon]] = relationship(
|
||||||
back_populates="boss_battle", cascade="all, delete-orphan"
|
back_populates="boss_battle", cascade="all, delete-orphan"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ class BossPokemon(Base):
|
|||||||
order: Mapped[int] = mapped_column(SmallInteger)
|
order: Mapped[int] = mapped_column(SmallInteger)
|
||||||
condition_label: Mapped[str | None] = mapped_column(String(100))
|
condition_label: Mapped[str | None] = mapped_column(String(100))
|
||||||
|
|
||||||
boss_battle: Mapped["BossBattle"] = relationship(back_populates="pokemon")
|
boss_battle: Mapped[BossBattle] = relationship(back_populates="pokemon")
|
||||||
pokemon: Mapped["Pokemon"] = relationship()
|
pokemon: Mapped[Pokemon] = relationship()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<BossPokemon(id={self.id}, boss_battle_id={self.boss_battle_id}, pokemon_id={self.pokemon_id})>"
|
return f"<BossPokemon(id={self.id}, boss_battle_id={self.boss_battle_id}, pokemon_id={self.pokemon_id})>"
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ class BossResult(Base):
|
|||||||
attempts: Mapped[int] = mapped_column(SmallInteger, default=1)
|
attempts: Mapped[int] = mapped_column(SmallInteger, default=1)
|
||||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||||
|
|
||||||
run: Mapped["NuzlockeRun"] = relationship(back_populates="boss_results")
|
run: Mapped[NuzlockeRun] = relationship(back_populates="boss_results")
|
||||||
boss_battle: Mapped["BossBattle"] = relationship()
|
boss_battle: Mapped[BossBattle] = relationship()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<BossResult(id={self.id}, run_id={self.run_id}, boss_battle_id={self.boss_battle_id}, result='{self.result}')>"
|
return f"<BossResult(id={self.id}, run_id={self.run_id}, boss_battle_id={self.boss_battle_id}, result='{self.result}')>"
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ class Encounter(Base):
|
|||||||
DateTime(timezone=True), server_default=func.now()
|
DateTime(timezone=True), server_default=func.now()
|
||||||
)
|
)
|
||||||
|
|
||||||
run: Mapped["NuzlockeRun"] = relationship(back_populates="encounters")
|
run: Mapped[NuzlockeRun] = relationship(back_populates="encounters")
|
||||||
route: Mapped["Route"] = relationship(back_populates="encounters")
|
route: Mapped[Route] = relationship(back_populates="encounters")
|
||||||
pokemon: Mapped["Pokemon"] = relationship(
|
pokemon: Mapped[Pokemon] = relationship(
|
||||||
foreign_keys=[pokemon_id], back_populates="encounters"
|
foreign_keys=[pokemon_id], back_populates="encounters"
|
||||||
)
|
)
|
||||||
current_pokemon: Mapped["Pokemon | None"] = relationship(
|
current_pokemon: Mapped[Pokemon | None] = relationship(
|
||||||
foreign_keys=[current_pokemon_id]
|
foreign_keys=[current_pokemon_id]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ class Evolution(Base):
|
|||||||
) # catch-all for other conditions
|
) # catch-all for other conditions
|
||||||
region: Mapped[str | None] = mapped_column(String(30))
|
region: Mapped[str | None] = mapped_column(String(30))
|
||||||
|
|
||||||
from_pokemon: Mapped["Pokemon"] = relationship(foreign_keys=[from_pokemon_id])
|
from_pokemon: Mapped[Pokemon] = relationship(foreign_keys=[from_pokemon_id])
|
||||||
to_pokemon: Mapped["Pokemon"] = relationship(foreign_keys=[to_pokemon_id])
|
to_pokemon: Mapped[Pokemon] = relationship(foreign_keys=[to_pokemon_id])
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Evolution(id={self.id}, from={self.from_pokemon_id}, to={self.to_pokemon_id}, trigger='{self.trigger}')>"
|
return f"<Evolution(id={self.id}, from={self.from_pokemon_id}, to={self.to_pokemon_id}, trigger='{self.trigger}')>"
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class Game(Base):
|
|||||||
ForeignKey("version_groups.id"), index=True
|
ForeignKey("version_groups.id"), index=True
|
||||||
)
|
)
|
||||||
|
|
||||||
version_group: Mapped["VersionGroup | None"] = relationship(back_populates="games")
|
version_group: Mapped[VersionGroup | None] = relationship(back_populates="games")
|
||||||
runs: Mapped[list["NuzlockeRun"]] = relationship(back_populates="game")
|
runs: Mapped[list[NuzlockeRun]] = relationship(back_populates="game")
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Game(id={self.id}, name='{self.name}')>"
|
return f"<Game(id={self.id}, name='{self.name}')>"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Genlocke(Base):
|
|||||||
DateTime(timezone=True), server_default=func.now()
|
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"
|
back_populates="genlocke", order_by="GenlockeLeg.leg_order"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,6 +45,6 @@ class GenlockeLeg(Base):
|
|||||||
leg_order: Mapped[int] = mapped_column(SmallInteger)
|
leg_order: Mapped[int] = mapped_column(SmallInteger)
|
||||||
retired_pokemon_ids: Mapped[list[int] | None] = mapped_column(JSONB, default=None)
|
retired_pokemon_ids: Mapped[list[int] | None] = mapped_column(JSONB, default=None)
|
||||||
|
|
||||||
genlocke: Mapped["Genlocke"] = relationship(back_populates="legs")
|
genlocke: Mapped[Genlocke] = relationship(back_populates="legs")
|
||||||
game: Mapped["Game"] = relationship()
|
game: Mapped[Game] = relationship()
|
||||||
run: Mapped["NuzlockeRun | None"] = relationship()
|
run: Mapped[NuzlockeRun | None] = relationship()
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ class NuzlockeRun(Base):
|
|||||||
hof_encounter_ids: Mapped[list[int] | None] = mapped_column(JSONB, default=None)
|
hof_encounter_ids: Mapped[list[int] | None] = mapped_column(JSONB, default=None)
|
||||||
naming_scheme: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
naming_scheme: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
||||||
|
|
||||||
game: Mapped["Game"] = relationship(back_populates="runs")
|
game: Mapped[Game] = relationship(back_populates="runs")
|
||||||
encounters: Mapped[list["Encounter"]] = relationship(back_populates="run")
|
encounters: Mapped[list[Encounter]] = relationship(back_populates="run")
|
||||||
boss_results: Mapped[list["BossResult"]] = relationship(back_populates="run")
|
boss_results: Mapped[list[BossResult]] = relationship(back_populates="run")
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ class Pokemon(Base):
|
|||||||
types: Mapped[list[str]] = mapped_column(ARRAY(String(20)))
|
types: Mapped[list[str]] = mapped_column(ARRAY(String(20)))
|
||||||
sprite_url: Mapped[str | None] = mapped_column(String(500))
|
sprite_url: Mapped[str | None] = mapped_column(String(500))
|
||||||
|
|
||||||
route_encounters: Mapped[list["RouteEncounter"]] = relationship(
|
route_encounters: Mapped[list[RouteEncounter]] = relationship(
|
||||||
back_populates="pokemon"
|
back_populates="pokemon"
|
||||||
)
|
)
|
||||||
encounters: Mapped[list["Encounter"]] = relationship(
|
encounters: Mapped[list[Encounter]] = relationship(
|
||||||
foreign_keys="[Encounter.pokemon_id]", back_populates="pokemon"
|
foreign_keys="[Encounter.pokemon_id]", back_populates="pokemon"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -23,17 +23,17 @@ class Route(Base):
|
|||||||
)
|
)
|
||||||
pinwheel_zone: Mapped[int | None] = mapped_column(SmallInteger, default=None)
|
pinwheel_zone: Mapped[int | None] = mapped_column(SmallInteger, default=None)
|
||||||
|
|
||||||
version_group: Mapped["VersionGroup"] = relationship(back_populates="routes")
|
version_group: Mapped[VersionGroup] = relationship(back_populates="routes")
|
||||||
route_encounters: Mapped[list["RouteEncounter"]] = relationship(
|
route_encounters: Mapped[list[RouteEncounter]] = relationship(
|
||||||
back_populates="route", cascade="all, delete-orphan"
|
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
|
# Self-referential relationships for route grouping
|
||||||
parent: Mapped["Route | None"] = relationship(
|
parent: Mapped[Route | None] = relationship(
|
||||||
back_populates="children", remote_side=[id]
|
back_populates="children", remote_side=[id]
|
||||||
)
|
)
|
||||||
children: Mapped[list["Route"]] = relationship(
|
children: Mapped[list[Route]] = relationship(
|
||||||
back_populates="parent", cascade="all, delete-orphan"
|
back_populates="parent", cascade="all, delete-orphan"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ class RouteEncounter(Base):
|
|||||||
min_level: Mapped[int] = mapped_column(SmallInteger)
|
min_level: Mapped[int] = mapped_column(SmallInteger)
|
||||||
max_level: Mapped[int] = mapped_column(SmallInteger)
|
max_level: Mapped[int] = mapped_column(SmallInteger)
|
||||||
|
|
||||||
route: Mapped["Route"] = relationship(back_populates="route_encounters")
|
route: Mapped[Route] = relationship(back_populates="route_encounters")
|
||||||
pokemon: Mapped["Pokemon"] = relationship(back_populates="route_encounters")
|
pokemon: Mapped[Pokemon] = relationship(back_populates="route_encounters")
|
||||||
game: Mapped["Game"] = relationship()
|
game: Mapped[Game] = relationship()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<RouteEncounter(route_id={self.route_id}, pokemon_id={self.pokemon_id}, method='{self.encounter_method}')>"
|
return f"<RouteEncounter(route_id={self.route_id}, pokemon_id={self.pokemon_id}, method='{self.encounter_method}')>"
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ class VersionGroup(Base):
|
|||||||
name: Mapped[str] = mapped_column(String(100))
|
name: Mapped[str] = mapped_column(String(100))
|
||||||
slug: Mapped[str] = mapped_column(String(100), unique=True)
|
slug: Mapped[str] = mapped_column(String(100), unique=True)
|
||||||
|
|
||||||
games: Mapped[list["Game"]] = relationship(back_populates="version_group")
|
games: Mapped[list[Game]] = relationship(back_populates="version_group")
|
||||||
routes: Mapped[list["Route"]] = relationship(back_populates="version_group")
|
routes: Mapped[list[Route]] = relationship(back_populates="version_group")
|
||||||
boss_battles: Mapped[list["BossBattle"]] = relationship(
|
boss_battles: Mapped[list[BossBattle]] = relationship(
|
||||||
back_populates="version_group"
|
back_populates="version_group"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
47
prek.toml
Normal file
47
prek.toml
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user