Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ user_data/
.DS_Store
.tmp
.pi
node_modules/
1 change: 1 addition & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx --no-install commitlint --edit "$1"
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx lint-staged
21 changes: 21 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Prettier is scoped to the frontend; everything else is ignored.
# (lint-staged already restricts which files Prettier sees, but this keeps
# manual `prettier .` runs from touching the wrong places.)

# Python backend — handled by ruff, not Prettier
backend/

# Dependencies & build output
node_modules/
frontend/node_modules/
frontend/.next/
frontend/out/
frontend/next-env.d.ts
**/*.tsbuildinfo
package-lock.json
frontend/package-lock.json

# Generated / data dirs
user_data/
.pgdata/
.tmp/
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": true,
"singleQuote": false,
"printWidth": 100,
"tabWidth": 2,
"trailingComma": "all"
}
67 changes: 67 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ python scripts/seed_problems.py # load problems from YAML
python app.py
```

One-time, from the repo root, install the Git hook tooling (requires Node 18+):

```bash
npm install # sets up Husky pre-commit + commit-msg hooks
```

This activates auto-formatting and commit-message validation on every commit
(see [Git hooks](#git-hooks) and [Commit messages](#commit-messages) below).

### Running tests

Tests run against PostgreSQL (a dedicated `o1prep_test` database is created
Expand Down Expand Up @@ -116,6 +125,64 @@ CI (GitHub Actions) spins up a PostgreSQL service and runs `ruff check .` and
`pytest` on every push and pull request across Python 3.11 and 3.12. Please make
sure both pass locally first.

### Git hooks

After `npm install` (repo root), [Husky](https://typicode.github.io/husky/)
installs two hooks that run automatically:

- **`pre-commit`** — runs [lint-staged](https://github.com/lint-staged/lint-staged)
on your **staged files only**, formatting them in place and re-staging the
result:
- Frontend (`frontend/**/*.{ts,tsx,js,jsx,mjs,cjs,css,json,md}`) → `prettier --write`
- Backend (`backend/**/*.py`) → `ruff check --fix` then `ruff format`
- **`commit-msg`** — validates your commit message with
[commitlint](https://commitlint.js.org/) (see below).

Formatting config lives in `.prettierrc` / `.prettierignore` (frontend) and the
`[tool.ruff]` sections of `backend/pyproject.toml` (backend). Backend formatting
relies on `ruff`, which you already have from `requirements-dev.txt`.

If a hook ever blocks you mid-rebase or in an automated context, you can bypass
it with `git commit --no-verify` — but please don't make a habit of it.

### Commit messages

We follow [Conventional Commits](https://www.conventionalcommits.org/) with a
**required scope**, enforced by the `commit-msg` hook. The format is:

```
type(scope): subject
```

Examples:

```
feat(frontend): persist study chat width across reloads
fix(backend): correct expected output for Two Sum 'adjacent' case
docs(repo): document commit conventions and contributor setup
refactor(frontend,backend): split into a monorepo layout
```

**Allowed types**: `feat`, `fix`, `refactor`, `chore`, `docs`, `ci`, `perf`,
`test`, `build`, `style`, `revert`, `polish`

**Allowed scopes**:

| Scope | Use for |
| ---------- | -------------------------------------------- |
| `frontend` | the Next.js app |
| `backend` | Flask app, API, services |
| `problems` | problem content, variants, generators |
| `db` | migrations, schema, Postgres |
| `ci` | GitHub Actions / pipelines |
| `docs` | README, `docs/`, markdown |
| `deps` | dependency bumps |
| `repo` | root tooling / monorepo-wide changes |

Rules of thumb: the subject is required, written in lowercase, and has no
trailing period. Commits spanning two areas may list both scopes
(`feat(frontend,backend): ...`). The full ruleset is in `commitlint.config.js`.

---

## Adding Your Own Problems
Expand Down
5 changes: 5 additions & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@ select = ["E", "F", "W", "I"]
ignore = [
"E501", # line length is enforced loosely; long prompt/SQL strings are fine
]

[tool.ruff.format]
# Black-compatible defaults, applied to staged .py files via the pre-commit hook.
quote-style = "double"
indent-style = "space"
53 changes: 53 additions & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Commit message standard: Conventional Commits with a required, validated scope.
* Enforced on every commit via the .husky/commit-msg hook.
*
* type(scope): subject
* e.g. feat(frontend): persist study chat width
*
* Multi-area commits may list several scopes: refactor(frontend,backend): ...
*/
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
// Allowed types — config-conventional defaults plus the repo's own "polish".
"type-enum": [
2,
"always",
[
"feat",
"fix",
"refactor",
"chore",
"docs",
"ci",
"perf",
"test",
"build",
"style",
"revert",
"polish",
],
],
// Scope is required and must come from this list.
"scope-empty": [2, "never"],
"scope-enum": [
2,
"always",
[
"frontend", // Next.js app
"backend", // Flask app / API / services
"problems", // problem content, variants, generators
"db", // migrations, schema, Postgres
"ci", // GitHub Actions / pipelines
"docs", // README, docs/, markdown
"deps", // dependency bumps
"repo", // root tooling, monorepo-wide changes
],
],
// Practical subject rules: required, no trailing period, no hard length cap.
"subject-empty": [2, "never"],
"subject-full-stop": [2, "never", "."],
"header-max-length": [0],
},
};
Loading
Loading