Enforce drizzle-kit generated migrations with a custom lint check#2430
Conversation
WalkthroughA new lint script validates Drizzle SQL migration files against naming conventions and template markers, then integrates the check into the build orchestrator and custom lint script chain. Drizzle Migration File Validation
🎯 1 (Trivial) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Coverage Report for API Unit Tests Coverage (./packages/api)
File CoverageNo changed files found. |
Coverage Report for Expo Unit Tests Coverage (./apps/expo)
File CoverageNo changed files found. |
|
Nice guardrail. Two follow-ups worth considering before merge: (1) When the check fails, print the literal regeneration command ( |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/lint/check-drizzle-migrations.ts`:
- Around line 53-56: Update the failure logging to include a per-package
regeneration command alongside the violation details: when iterating the
violations array (violations, violation.packageName, violation.message), print a
suggested shell command that uses violation.packageName to regenerate migrations
(for example: cd packages/${violation.packageName} && npm run
generate-migrations or npm run db:migrate:generate
--workspace=${violation.packageName}) so maintainers can copy-paste the recovery
step directly; ensure the command string is clearly labeled and uses the
packageName variable.
- Around line 8-11: MIGRATION_TARGETS is hard-coded so new packages with a
drizzle folder are missed; replace the static MIGRATION_TARGETS constant with
code that auto-discovers packages/*/drizzle (e.g., using fs.readdir or glob) and
builds the array of targets (each with name and allowManual Set), preserving
existing allowManual entries for known packages (0010_great_colleen_wing.sql and
0000_extensions.sql) and defaulting to an empty Set for others so the lint check
covers all current and future drizzle folders.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 865e0bbe-698a-403e-bade-6ccfe9137b3a
📒 Files selected for processing (3)
package.jsonscripts/check-all.tsscripts/lint/check-drizzle-migrations.ts
| const MIGRATION_TARGETS = [ | ||
| { name: 'packages/api', allowManual: new Set(['0010_great_colleen_wing.sql']) }, | ||
| { name: 'packages/osm-db', allowManual: new Set(['0000_extensions.sql']) }, | ||
| ]; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
Auto-discover drizzle targets to avoid silent policy gaps.
Line 8 hard-codes MIGRATION_TARGETS, so new packages/*/drizzle folders can bypass this check until someone updates this file.
Proposed refactor
import { existsSync, readdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
const ROOT = join(import.meta.dir, '..', '..');
-const MIGRATION_TARGETS = [
- { name: 'packages/api', allowManual: new Set(['0010_great_colleen_wing.sql']) },
- { name: 'packages/osm-db', allowManual: new Set(['0000_extensions.sql']) },
-];
+const ALLOW_MANUAL_BY_PACKAGE = new Map<string, Set<string>>([
+ ['packages/api', new Set(['0010_great_colleen_wing.sql'])],
+ ['packages/osm-db', new Set(['0000_extensions.sql'])],
+]);
+
+const MIGRATION_TARGETS = readdirSync(join(ROOT, 'packages'), { withFileTypes: true })
+ .filter((d) => d.isDirectory())
+ .map((d) => `packages/${d.name}`)
+ .filter((name) => existsSync(join(ROOT, name, 'drizzle')))
+ .map((name) => ({
+ name,
+ allowManual: ALLOW_MANUAL_BY_PACKAGE.get(name) ?? new Set<string>(),
+ }));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/lint/check-drizzle-migrations.ts` around lines 8 - 11,
MIGRATION_TARGETS is hard-coded so new packages with a drizzle folder are
missed; replace the static MIGRATION_TARGETS constant with code that
auto-discovers packages/*/drizzle (e.g., using fs.readdir or glob) and builds
the array of targets (each with name and allowManual Set), preserving existing
allowManual entries for known packages (0010_great_colleen_wing.sql and
0000_extensions.sql) and defaulting to an empty Set for others so the lint check
covers all current and future drizzle folders.
| console.log(`Drizzle migration checks failed (${violations.length}):\n`); | ||
| for (const violation of violations) { | ||
| console.log(`${violation.packageName}: ${violation.message}`); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Print per-package regeneration commands in failures.
Current output reports the violation but not the exact recovery command, which slows remediation.
Proposed improvement
if (violations.length > 0) {
console.log(`Drizzle migration checks failed (${violations.length}):\n`);
for (const violation of violations) {
console.log(`${violation.packageName}: ${violation.message}`);
}
+ console.log('\nSuggested fix commands:');
+ for (const pkg of new Set(violations.map((v) => v.packageName))) {
+ console.log(` bun --cwd ${pkg} drizzle-kit generate`);
+ }
process.exit(1);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| console.log(`Drizzle migration checks failed (${violations.length}):\n`); | |
| for (const violation of violations) { | |
| console.log(`${violation.packageName}: ${violation.message}`); | |
| } | |
| console.log(`Drizzle migration checks failed (${violations.length}):\n`); | |
| for (const violation of violations) { | |
| console.log(`${violation.packageName}: ${violation.message}`); | |
| } | |
| console.log('\nSuggested fix commands:'); | |
| for (const pkg of new Set(violations.map((v) => v.packageName))) { | |
| console.log(` bun --cwd ${pkg} drizzle-kit generate`); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/lint/check-drizzle-migrations.ts` around lines 53 - 56, Update the
failure logging to include a per-package regeneration command alongside the
violation details: when iterating the violations array (violations,
violation.packageName, violation.message), print a suggested shell command that
uses violation.packageName to regenerate migrations (for example: cd
packages/${violation.packageName} && npm run generate-migrations or npm run
db:migrate:generate --workspace=${violation.packageName}) so maintainers can
copy-paste the recovery step directly; ensure the command string is clearly
labeled and uses the packageName variable.
There was a problem hiding this comment.
Pull request overview
This PR adds a new custom lint check to enforce that new SQL migrations in the Drizzle migration directories are generated via drizzle-kit (and not hand-written), while allowing a small set of known legacy/manual migrations to remain.
Changes:
- Added
scripts/lint/check-drizzle-migrations.tsto validate migration filenames and detect the Drizzle “custom SQL migration template” marker. - Wired the new check into the master custom check runner (
scripts/check-all.ts). - Added the new check to the root
lint:customscript inpackage.json.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| scripts/lint/check-drizzle-migrations.ts | Implements migration enforcement (filename format + template marker detection) with legacy allowlist support. |
| scripts/check-all.ts | Adds check-drizzle-migrations to the unified custom-check runner. |
| package.json | Runs the new migration check as part of lint:custom. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Motivation
drizzle-kitrather than hand-edited.Description
scripts/lint/check-drizzle-migrations.tsthat scanspackages/api/drizzleandpackages/osm-db/drizzlemigration folders and reports violations.^\d{4}_[a-z0-9]+(?:_[a-z0-9]+)+\.sql$and flags files that contain the drizzle template marker-- Custom SQL migration file, put your code below! --.packages/api/drizzle/0010_great_colleen_wing.sqlandpackages/osm-db/drizzle/0000_extensions.sql.scripts/check-all.tsascheck-drizzle-migrationsand into rootlint:custominpackage.json.Testing
bun scripts/lint/check-drizzle-migrations.ts, which passed (no violations after adding the intentional allowlist).bun scripts/check-all.ts, which included the new check and reported the new check as passing while an unrelated existingcheck-react-doctorfailed due to external npm registry 403 responses in this environment.biome checklint step executed as part of the commit and passed for the modified files.Codex Task
Summary by CodeRabbit