Skip to content

Commit c1a1f77

Browse files
authored
Merge pull request #44 from pennlabs/james/linting-setup
set up pre-commit hook for linting
2 parents 598110c + 769cca9 commit c1a1f77

84 files changed

Lines changed: 1629 additions & 1654 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.pre-commit-config.yaml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Pre-commit hooks configuration for Penn Marketplace
2+
# See https://pre-commit.com for more information
3+
#
4+
# Setup: pip install pre-commit && pre-commit install
5+
# Or: cd backend && uv run pre-commit install
6+
#
7+
# Run manually: pre-commit run --all-files
8+
# Run same checks as CI: ./scripts/check.sh
9+
10+
repos:
11+
# =============================================================================
12+
# General file checks (fast, always run)
13+
# =============================================================================
14+
- repo: https://github.com/pre-commit/pre-commit-hooks
15+
rev: v4.6.0
16+
hooks:
17+
- id: trailing-whitespace
18+
exclude: ^(.*\.lock|.*\.min\.js|.*\.min\.css)
19+
- id: end-of-file-fixer
20+
exclude: ^(.*\.lock|.*\.min\.js|.*\.min\.css)
21+
- id: check-yaml
22+
- id: check-json
23+
- id: check-toml
24+
- id: check-added-large-files
25+
args: ['--maxkb=1000']
26+
27+
# =============================================================================
28+
# Backend: Python formatting and linting
29+
# =============================================================================
30+
# Note: CI uses ruff format (not Black), so we match that in pre-commit
31+
- repo: https://github.com/astral-sh/ruff-pre-commit
32+
rev: v0.8.4
33+
hooks:
34+
- id: ruff
35+
name: ruff check (Python linter)
36+
files: ^backend/.*\.py$
37+
args: ['--fix'] # Auto-fix what can be fixed
38+
- id: ruff-format
39+
name: ruff format (Python formatter)
40+
files: ^backend/.*\.py$
41+
# Auto-formats (standard pre-commit behavior)
42+
43+
# =============================================================================
44+
# Frontend: Formatting and linting via local commands
45+
# (Uses your installed pnpm/node for better compatibility)
46+
# =============================================================================
47+
- repo: local
48+
hooks:
49+
- id: frontend-prettier
50+
name: prettier (frontend)
51+
entry: bash -c 'cd frontend && pnpm format'
52+
language: system
53+
files: ^frontend/.*\.(ts|tsx|js|jsx|json|css|md)$
54+
pass_filenames: false
55+
# Auto-formats (standard pre-commit behavior)
56+
57+
- id: frontend-eslint
58+
name: eslint (frontend)
59+
entry: bash -c 'cd frontend && pnpm lint:fix'
60+
language: system
61+
files: ^frontend/.*\.(ts|tsx|js|jsx)$
62+
pass_filenames: false
63+
# Auto-fixes what can be fixed
64+
65+
- id: frontend-typecheck
66+
name: TypeScript type check (frontend)
67+
entry: bash -c 'cd frontend && pnpm typecheck'
68+
language: system
69+
files: ^frontend/.*\.(ts|tsx)$
70+
pass_filenames: false
71+
# Type checking (whole project, but runs on commit)
72+
73+
# =============================================================================
74+
# Notes:
75+
# - Pre-commit hooks AUTO-FIX issues (convenient for developers)
76+
# - check.sh only CHECKS (use --fix flag to auto-fix)
77+
# - TypeScript type checking runs in both pre-commit and check.sh
78+
# - CI doesn't run TypeScript explicitly (Next.js build catches type errors)
79+
# - CI uses ruff format (not Black), so pre-commit matches that
80+
# - Frontend: CI and pre-commit both use pnpm
81+
# =============================================================================

README.md

Lines changed: 88 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@ A secure platform where Penn students can buy/sell items and browse/post sublet
44

55
## 1. Requirements
66

7-
This project uses **Docker** for the entire development environment.
7+
**App runtime is Docker-first.**
88

9-
Install:
9+
You do not need Python, Node, Postgres, or Redis installed locally to run the app.
1010

11-
- Docker Desktop
12-
- Git
11+
### Required for Development
1312

14-
You **do not** need Python, Node, Postgres, or Redis installed locally. It is also **not** a requirement that you have `pnpm` and `uv` (our dependency managers for frontend and backend, respectively) installed locally. All of these are not required *as long as* you are running all commands inside Docker containers using `docker compose exec <service> <cmd>` (more explained below).
13+
- **Docker Desktop** - For running the app
14+
- **Git** - Version control
15+
16+
### Recommended for Local Development
17+
18+
We use pre-commit hooks to automatically run formatters, linters, and type checks before every commit.
19+
To use them, you must install these tools locally:
20+
21+
- [uv](https://docs.astral.sh/uv/getting-started/installation/) - Python package manager
22+
- [pnpm](https://pnpm.io/installation) - Node.js package manager
1523

1624
### Environment Variables
1725

@@ -20,8 +28,7 @@ You will need environment variable files for both the backend and frontend:
2028
- `backend/.env`
2129
- `frontend/.env`
2230

23-
Make sure these files are configured before running the application. If you are a member of PennLabs, you can
24-
reach out to one of them for the credentials.
31+
Make sure these files are configured before running the application. If you are a member of PennLabs, you can reach out to one of them for the credentials.
2532

2633
## 2. Clone the Repository
2734

@@ -30,21 +37,36 @@ git clone https://github.com/pennlabs/penn-marketplace.git
3037
cd penn-marketplace
3138
```
3239

40+
## 3. Setup (One Time)
41+
42+
**Run this on your local machine (not in Docker):**
43+
44+
```bash
45+
./scripts/setup.sh
46+
```
47+
48+
**What this does:**
49+
1. Checks if you have `uv` and `pnpm` installed locally
50+
2. Installs backend Python dependencies locally (creates `backend/.venv/`)
51+
3. Installs frontend Node dependencies locally (creates `frontend/node_modules/`)
52+
4. Installs pre-commit hooks in your local `.git/hooks/` directory
53+
54+
**Note:** If you don't have `uv` or `pnpm` installed locally, the script will tell you how to install them.
3355

34-
## 3. Start the Development Environment
56+
## 4. Start the Development Environment
3557

3658
```bash
3759
docker compose up --build
3860
```
3961

4062
This will:
4163

42-
- Build backend & frontend Docker images
43-
- Start Postgres + Redis
44-
- Run Django migrations
64+
- Build backend & frontend Docker images
65+
- Start Postgres + Redis
66+
- Run Django migrations
4567
- Launch:
46-
- Frontend → http://localhost:3000
47-
- Backend → http://localhost:8000
68+
- Frontend → http://localhost:3000
69+
- Backend → http://localhost:8000
4870

4971
Stop:
5072

@@ -59,8 +81,45 @@ Remove DB/storage volumes:
5981
docker compose down -v
6082
```
6183

84+
## 5. Code Quality
85+
86+
### Running Checks
87+
88+
You can run the full check script by:
89+
90+
```bash
91+
./scripts/check.sh
92+
```
93+
94+
To auto-fix formatting issues:
95+
96+
```bash
97+
./scripts/check.sh --fix
98+
```
99+
100+
### What Gets Checked
101+
102+
| Area | Checks |
103+
|------|--------|
104+
| **Frontend** | Lint (pnpm), TypeScript typecheck |
105+
| **Backend** | ruff check, ruff format |
106+
107+
### Pre-Commit Hooks
108+
109+
If you ran `./scripts/setup.sh`, pre-commit hooks are installed. They automatically format and lint your code when you run `git commit`.
110+
111+
**What hooks do:**
112+
- Auto-fix Python code formatting (ruff format)
113+
- Auto-fix Python code linting (ruff check --fix)
114+
- Auto-fix TypeScript/JavaScript code formatting (Prettier)
115+
- Auto-fix TypeScript/JavaScript code linting (ESLint --fix)
116+
- Check TypeScript types (pnpm typecheck)
117+
- Auto-fix trailing whitespace, file endings
118+
119+
**Note:** Hooks auto-fix issues when possible. TypeScript type checking can't be auto-fixed, so the commit is blocked if there are type errors.
120+
121+
## 6. Generating Test Data (optional)
62122

63-
## 4. Generating Test Data (optional)
64123
To populate the database with random sample listings for testing:
65124
```bash
66125
docker compose exec backend python manage.py generate_listings
@@ -75,21 +134,20 @@ Use this to quickly test the marketplace UI and features with realistic data.
75134

76135
**Note:** Make sure `docker compose up` is running before executing this command, as you need the backend container and database to be active.
77136

78-
79-
## 5. Hot Reload
137+
## 7. Hot Reload
80138

81139
### Frontend (Next.js)
82140

83-
- Edit files in `frontend/`
84-
- Next.js refreshes automatically
141+
- Edit files in `frontend/`
142+
- Next.js refreshes automatically
85143

86144
### Backend (Django)
87145

88-
- Edit files in `backend/`
89-
- Django dev server auto-reloads
146+
- Edit files in `backend/`
147+
- Django dev server auto-reloads
90148

91149

92-
## 6. Running Migrations
150+
## 8. Running Migrations
93151

94152
### When YOU change models in `models.py`:
95153

@@ -112,12 +170,12 @@ docker compose up
112170

113171
Migrations are applied automatically on startup.
114172

115-
> ⚠️ **You must run BOTH commands when changing models.**
173+
> ⚠️ **You must run BOTH commands when changing models.**
116174
> `makemigrations` creates the migration file, `migrate` applies it to the database.
117175
118176

119177

120-
## 7. Installing New Packages
178+
## 9. Installing New Packages
121179

122180
### Backend (Python • uv)
123181

@@ -148,21 +206,15 @@ docker compose up
148206
```
149207

150208
**Option 3: Use uv CLI (if you have uv installed locally)**
151-
152-
1. Install package:
153209
```bash
154-
cd backend
155-
uv add <package>
156-
cd ..
157-
```
158-
159-
2. Rebuild container:
160-
```bash
161-
docker compose build backend
162-
docker compose up
210+
cd backend
211+
uv add <package>
212+
cd ..
213+
docker compose build backend
214+
docker compose up
163215
```
164216

165-
> ⚠️ **Always rebuild after changing dependencies.**
217+
> ⚠️ **Always rebuild after changing dependencies.**
166218
> The `uv.lock` file must be synchronized with your Docker image.
167219
168220
### Frontend (Node • pnpm)
@@ -191,4 +243,4 @@ pnpm add <package>
191243
cd ..
192244
docker compose build frontend
193245
docker compose up
194-
```
246+
```

backend/config/asgi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from django.core.asgi import get_asgi_application
1313

14+
1415
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
1516

1617
application = get_asgi_application()

backend/config/settings/base.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"""
22
Base settings shared across all environments
33
"""
4+
45
import os
56
from pathlib import Path
67

8+
79
# Build paths inside the project like this: BASE_DIR / 'subdir'.
810
BASE_DIR = Path(__file__).resolve().parent.parent.parent
911

@@ -26,9 +28,8 @@
2628
"django.contrib.staticfiles",
2729
"rest_framework",
2830
"market",
29-
3031
# DLA for authentication management
31-
'accounts.apps.AccountsConfig',
32+
"accounts.apps.AccountsConfig",
3233
]
3334

3435
MIDDLEWARE = [
@@ -67,7 +68,9 @@
6768

6869
AUTH_PASSWORD_VALIDATORS = [
6970
{
70-
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
71+
"NAME": (
72+
"django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
73+
),
7174
},
7275
{
7376
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
@@ -120,4 +123,4 @@
120123
TWILIO_ACCOUNT_SID = os.environ.get("TWILIO_ACCOUNT_SID", "")
121124
TWILIO_AUTH_TOKEN = os.environ.get("TWILIO_AUTH_TOKEN", "")
122125
TWILIO_PHONE_NUMBER = os.environ.get("TWILIO_PHONE_NUMBER", "")
123-
PHONE_VERIFICATION_CODE_EXPIRY_MINUTES=10
126+
PHONE_VERIFICATION_CODE_EXPIRY_MINUTES = 10

backend/config/settings/development.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
"""
22
Dev settings - for local development with docker-compose
33
"""
4-
from .base import *
4+
55
import dj_database_url
66

7+
from .base import *
8+
9+
710
DEBUG = True
811

9-
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'backend']
12+
ALLOWED_HOSTS = ["localhost", "127.0.0.1", "backend"]
1013

1114
# Database
1215
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
1316

14-
DATABASES = {
15-
"default": dj_database_url.config()
16-
}
17+
DATABASES = {"default": dj_database_url.config()}
1718

1819
# Redis - from docker-compose
1920
REDIS_URL = os.environ.get("REDIS_URL", "redis://redis:6379/0")
@@ -37,4 +38,4 @@
3738
CORS_ALLOWED_ORIGINS = [
3839
"http://localhost:3000",
3940
"http://127.0.0.1:3000",
40-
]
41+
]

backend/config/settings/production.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""
22
Production settings
33
"""
4-
from .base import *
4+
55
import dj_database_url
66

7+
from .base import *
8+
9+
710
DEBUG = False
811

912
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
@@ -44,5 +47,5 @@
4447
CSRF_COOKIE_SECURE = True
4548
SECURE_BROWSER_XSS_FILTER = True
4649
SECURE_CONTENT_TYPE_NOSNIFF = True
47-
X_FRAME_OPTIONS = 'DENY'
48-
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
50+
X_FRAME_OPTIONS = "DENY"
51+
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

0 commit comments

Comments
 (0)