diff --git a/Makefile b/Makefile index f888826..3e00fb6 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ TAILWIND_VERSION := v4.1.18 TAILWIND := web/bin/tailwindcss SOPS_DOTENV := sops --input-type dotenv --output-type dotenv -.PHONY: help dev css-build css-watch \ +.PHONY: help dev css-build css-watch install-hooks \ secrets-decrypt-dev secrets-decrypt-prod \ secrets-edit-dev secrets-edit-prod \ secrets-encrypt-dev secrets-encrypt-prod \ @@ -13,6 +13,7 @@ help: @echo " dev Start full dev environment (migrate, seed, app + worker + CSS watcher)" @echo " css-build Build + minify Tailwind CSS" @echo " css-watch Watch + rebuild Tailwind CSS" + @echo " install-hooks Install git pre-commit hook (run once after cloning)" @echo " secrets-decrypt-dev Decrypt .env.dev.sops → .env" @echo " secrets-decrypt-prod Decrypt .env.prod.sops → .env" @echo " secrets-edit-dev Edit .env.dev.sops in \$$EDITOR" @@ -23,6 +24,11 @@ help: # ── Dev environment ─────────────────────────────────────────────────────────── +install-hooks: + cp scripts/hooks/pre-commit .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit + @echo "✓ pre-commit hook installed" + dev: @./web/scripts/dev_run.sh diff --git a/pyproject.toml b/pyproject.toml index db45dc5..0951e4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,6 +88,7 @@ exclude = [ "site-packages", "venv", "notebooks", + "web", ] indent-width = 4 diff --git a/scripts/hooks/pre-commit b/scripts/hooks/pre-commit new file mode 100644 index 0000000..2e4caa3 --- /dev/null +++ b/scripts/hooks/pre-commit @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# Pre-commit hook: ruff lint + auto-fix. +# Install: make install-hooks +set -euo pipefail + +REPO_ROOT="$(git rev-parse --show-toplevel)" +RUFF="$REPO_ROOT/.venv/bin/ruff" + +if [[ ! -x "$RUFF" ]]; then + echo "pre-commit: ruff not found at $RUFF — run 'uv sync' first" >&2 + exit 1 +fi + +echo "→ ruff check (root)" +"$RUFF" check --fix "$REPO_ROOT" + +echo "→ ruff check (web/src web/tests)" +"$RUFF" check --fix "$REPO_ROOT/web/src" "$REPO_ROOT/web/tests" \ + --config "$REPO_ROOT/web/pyproject.toml" + +# Re-stage any files ruff fixed so they land in the commit. +git diff --name-only | xargs -r git add diff --git a/web/tests/conftest.py b/web/tests/conftest.py index 49b1cfb..70d45ee 100644 --- a/web/tests/conftest.py +++ b/web/tests/conftest.py @@ -7,7 +7,6 @@ from unittest.mock import AsyncMock, patch import aiosqlite import pytest - from beanflows import core from beanflows.app import create_app diff --git a/web/tests/test_billing_helpers.py b/web/tests/test_billing_helpers.py index 36e0081..5f89501 100644 --- a/web/tests/test_billing_helpers.py +++ b/web/tests/test_billing_helpers.py @@ -2,10 +2,6 @@ Unit tests for billing SQL helpers, feature/limit access, and plan determination. """ import pytest -from hypothesis import HealthCheck, given -from hypothesis import settings as h_settings -from hypothesis import strategies as st - from beanflows.billing.routes import ( can_access_feature, get_billing_customer, @@ -18,6 +14,9 @@ from beanflows.billing.routes import ( upsert_subscription, ) from beanflows.core import config +from hypothesis import HealthCheck, given +from hypothesis import settings as h_settings +from hypothesis import strategies as st # ════════════════════════════════════════════════════════════ # get_subscription diff --git a/web/tests/test_billing_hooks.py b/web/tests/test_billing_hooks.py index 863cd16..e89874b 100644 --- a/web/tests/test_billing_hooks.py +++ b/web/tests/test_billing_hooks.py @@ -2,7 +2,6 @@ Tests for the billing event hook system. """ import pytest - from beanflows.billing.routes import _billing_hooks, _fire_hooks, on_billing_event diff --git a/web/tests/test_billing_routes.py b/web/tests/test_billing_routes.py index b57be63..6531ed8 100644 --- a/web/tests/test_billing_routes.py +++ b/web/tests/test_billing_routes.py @@ -144,9 +144,8 @@ class TestCancelRoute: # subscription_required decorator # ════════════════════════════════════════════════════════════ -from quart import Blueprint # noqa: E402 - from beanflows.auth.routes import subscription_required # noqa: E402 +from quart import Blueprint # noqa: E402 test_bp = Blueprint("test", __name__) diff --git a/web/tests/test_billing_webhooks.py b/web/tests/test_billing_webhooks.py index 295cb87..bfef5ce 100644 --- a/web/tests/test_billing_webhooks.py +++ b/web/tests/test_billing_webhooks.py @@ -5,13 +5,12 @@ Covers signature verification, event parsing, subscription lifecycle transitions import json import pytest +from beanflows.billing.routes import get_billing_customer, get_subscription from conftest import make_webhook_payload, sign_payload from hypothesis import HealthCheck, given from hypothesis import settings as h_settings from hypothesis import strategies as st -from beanflows.billing.routes import get_billing_customer, get_subscription - WEBHOOK_PATH = "/billing/webhook/paddle" SIG_HEADER = "Paddle-Signature" diff --git a/web/tests/test_roles.py b/web/tests/test_roles.py index ba46746..f5a970c 100644 --- a/web/tests/test_roles.py +++ b/web/tests/test_roles.py @@ -3,8 +3,6 @@ Tests for role-based access control: role_required decorator, grant/revoke/ensur and admin route protection. """ import pytest -from quart import Blueprint - from beanflows import core from beanflows.auth.routes import ( ensure_admin_role, @@ -12,6 +10,7 @@ from beanflows.auth.routes import ( revoke_role, role_required, ) +from quart import Blueprint # ════════════════════════════════════════════════════════════ # grant_role / revoke_role