Skip to content

feat: add db status command#8173

Merged
eduardoboucas merged 1 commit intomainfrom
feat/db-status
Apr 20, 2026
Merged

feat: add db status command#8173
eduardoboucas merged 1 commit intomainfrom
feat/db-status

Conversation

@eduardoboucas
Copy link
Copy Markdown
Member

Screenshot 2026-04-20 at 17 27 57

@eduardoboucas eduardoboucas requested a review from a team as a code owner April 20, 2026 16:29
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Summary by CodeRabbit

New Features

  • Added db status subcommand to check database migration status for local and remote Netlify Databases
  • Introduced --branch option to inspect migration status for specific database branches
  • Introduced --show-credentials option to display database connection credentials
  • Introduced --json flag for JSON-formatted migration status output
  • New migration status reporting classifies migrations as applied, pending, missing on disk, or out of order

Tests

  • Added comprehensive test coverage for database migration status functionality

Walkthrough

This pull request introduces database migration status monitoring functionality for Netlify databases. It adds a new module defining shared migration file types and two AppliedMigrationsFetcher implementations—one fetching applied migrations from a Netlify API endpoint scoped by site and branch, the other querying local database records and constructing file paths. The PR extends the database connection API to accept an optional URL override parameter and adds local connection string detection capabilities. A new statusDb command is introduced that computes migration status (categorizing migrations as applied, pending, missing on disk, or out of order) and renders either JSON or human-readable reports with command hints and issue sections. The command is integrated into the existing database CLI with conditional routing based on an experimental feature flag. New database schema and table constants are defined. Comprehensive test coverage with 636 lines verifies the command behavior across enabled/disabled detection, local and remote modes, credential handling, and error scenarios.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add db status command' directly and specifically describes the main change in the pull request—introducing a new db status command with supporting infrastructure.
Description check ✅ Passed The description contains a screenshot demonstrating the new db status command in action, which is directly related to the changeset and shows the feature's output and functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/db-status

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

📊 Benchmark results

Comparing with 289933d

  • Dependency count: 1,061 (no change)
  • Package size: 355 MB ⬆️ 0.00% increase vs. 289933d
  • Number of ts-expect-error directives: 356 (no change)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/commands/database/db-connection.ts (1)

72-89: ⚠️ Potential issue | 🟠 Major

Stop NetlifyDev when the pg client fails to connect.

After await netlifyDev.start() on line 72, a rejection from client.connect() on line 81 exits this function before the cleanup handler is ever registered, leaving the spawned dev process running. Additionally, if client.end() throws within cleanup, netlifyDev.stop() is never called.

Wrap client.connect() in a try-catch to stop NetlifyDev on failure, and wrap the cleanup operations in try-finally to ensure NetlifyDev is always stopped:

Suggested fix
   const client = new Client({ connectionString })
-  await client.connect()
+  try {
+    await client.connect()
+  } catch (error) {
+    await netlifyDev.stop()
+    throw error
+  }

   return {
     client,
     connectionString,
     cleanup: async () => {
-      await client.end()
-      await netlifyDev.stop()
+      try {
+        await client.end()
+      } finally {
+        await netlifyDev.stop()
+      }
     },
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/database/db-connection.ts` around lines 72 - 89, After starting
NetlifyDev with netlifyDev.start(), ensure netlifyDev.stop() is always called if
client.connect() fails by wrapping the connection in a try/catch that calls
await netlifyDev.stop() before rethrowing; locate the Client instantiation and
the await client.connect() call and add the try/catch around it. Also make the
returned cleanup ensure netlifyDev.stop() runs even if client.end() throws by
changing cleanup to use try/finally: attempt await client.end() in the try and
always await netlifyDev.stop() in the finally block so the dev process is always
stopped.
🧹 Nitpick comments (1)
src/commands/database/status-db.ts (1)

52-59: Share the migration version parser.

This parser is duplicated verbatim in src/commands/database/applied-migrations.ts. If the naming rules change in one place, disk parsing and applied-migration parsing will drift and computeStatus() will start classifying the same migration differently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/database/status-db.ts` around lines 52 - 59, The parseVersion
logic is duplicated (function parseVersion) and must be centralized: extract the
parser into a single shared utility (e.g., export a parseMigrationVersion
function from a new or existing util module) and replace the inline parseVersion
definitions in both src/commands/database/status-db.ts and
src/commands/database/applied-migrations.ts with imports of that shared
function; ensure the exported name matches usages and keep the same behavior and
return type (number | null) so computeStatus() and applied-migration parsing
stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/database/status-db.ts`:
- Around line 323-335: The message shown when status.outOfOrder has entries is
incorrect: replace the current remediation text that suggests running
formatCommand('db migrations reset') with guidance to remove or renumber the
local migration files and re-generate them with a higher prefix (e.g.
delete/rename the local migration directories listed in status.outOfOrder and
run the migration generation command again). Also gate any suggestion to run
formatCommand('db reset') so it’s only displayed for local-only flows (detect
via the existing status metadata that indicates a remote baseline or local-only
state) rather than as a general fix. Ensure you update the strings produced
where status.outOfOrder is formatted and keep references to the offending
migrations (status.outOfOrder.map(...)) so users can identify which local files
to delete/regenerate.
- Around line 270-284: The output mistakenly suggests running `db connect`/`db
connect --query` for branch status even though connect.ts
(connectRawClient/buildDir) connects to the local DB; wrap the call to
logConnectCommands and the follow-up secondary messages in a guard that only
shows those connect instructions when the status is for the local DB (not when
invoked in branch/--branch mode or when the connectionString clearly refers to a
remote branch). Update the logic around connectionString, showCredentials,
logConnectCommands, connectionStringHasCredentials, primary and secondary so
that when a branch flag (or a predicate like isBranchTarget(connectionString))
is true you omit logConnectCommands and instead keep only the safe informational
message about the branch connection string. Ensure the new predicate is used
where connectionString is checked so suggestions don't point to the wrong
target.

---

Outside diff comments:
In `@src/commands/database/db-connection.ts`:
- Around line 72-89: After starting NetlifyDev with netlifyDev.start(), ensure
netlifyDev.stop() is always called if client.connect() fails by wrapping the
connection in a try/catch that calls await netlifyDev.stop() before rethrowing;
locate the Client instantiation and the await client.connect() call and add the
try/catch around it. Also make the returned cleanup ensure netlifyDev.stop()
runs even if client.end() throws by changing cleanup to use try/finally: attempt
await client.end() in the try and always await netlifyDev.stop() in the finally
block so the dev process is always stopped.

---

Nitpick comments:
In `@src/commands/database/status-db.ts`:
- Around line 52-59: The parseVersion logic is duplicated (function
parseVersion) and must be centralized: extract the parser into a single shared
utility (e.g., export a parseMigrationVersion function from a new or existing
util module) and replace the inline parseVersion definitions in both
src/commands/database/status-db.ts and
src/commands/database/applied-migrations.ts with imports of that shared
function; ensure the exported name matches usages and keep the same behavior and
return type (number | null) so computeStatus() and applied-migration parsing
stay consistent.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7fd9b746-877b-488b-8db0-be9172a64116

📥 Commits

Reviewing files that changed from the base of the PR and between 289933d and 2144ef5.

📒 Files selected for processing (6)
  • src/commands/database/applied-migrations.ts
  • src/commands/database/constants.ts
  • src/commands/database/database.ts
  • src/commands/database/db-connection.ts
  • src/commands/database/status-db.ts
  • tests/unit/commands/database/status-db.test.ts

Comment on lines +270 to +284
if (connectionString) {
const displayed = showCredentials ? connectionString : redactConnectionString(connectionString)

primary(STATUS_GOOD, `Connected to database branch: ${displayed}`)
logConnectCommands()

if (!showCredentials && connectionStringHasCredentials(connectionString)) {
secondary(
`To reveal the full connection string (including credentials), run ${formatCommand(
'db status --show-credentials',
)}`,
)
} else {
secondary(`To connect to the database directly, use the connection string: ${displayed}`)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't suggest db connect for branch status output.

This block always prints db connect/db connect --query when a connectionString exists, but src/commands/database/connect.ts still calls connectRawClient(buildDir) with no branch override, so those commands connect to the local database, not the branch being reported here. In --branch mode that's misleading and can send follow-up queries to the wrong target.

Suggested fix
   if (connectionString) {
     const displayed = showCredentials ? connectionString : redactConnectionString(connectionString)

     primary(STATUS_GOOD, `Connected to database branch: ${displayed}`)
-    logConnectCommands()
+    if (isLocal) {
+      logConnectCommands()
+    }

     if (!showCredentials && connectionStringHasCredentials(connectionString)) {
       secondary(
         `To reveal the full connection string (including credentials), run ${formatCommand(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/database/status-db.ts` around lines 270 - 284, The output
mistakenly suggests running `db connect`/`db connect --query` for branch status
even though connect.ts (connectRawClient/buildDir) connects to the local DB;
wrap the call to logConnectCommands and the follow-up secondary messages in a
guard that only shows those connect instructions when the status is for the
local DB (not when invoked in branch/--branch mode or when the connectionString
clearly refers to a remote branch). Update the logic around connectionString,
showCredentials, logConnectCommands, connectionStringHasCredentials, primary and
secondary so that when a branch flag (or a predicate like
isBranchTarget(connectionString)) is true you omit logConnectCommands and
instead keep only the safe informational message about the branch connection
string. Ensure the new predicate is used where connectionString is checked so
suggestions don't point to the wrong target.

Comment on lines +323 to +335
if (status.outOfOrder.length > 0) {
log(
` Out of order: ${status.outOfOrder
.map((m) => chalk.red(`${m.name} (version ${String(m.version)} <= max applied ${String(m.maxApplied)})`))
.join(', ')}`,
)
log('')
log(
chalk.gray(
`Run ${formatCommand(
'db migrations reset',
)} to delete these local-only migrations, then generate them again with a higher prefix.`,
),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The out-of-order remediation points to the wrong fix.

db migrations reset is not a registered command, and even db reset only rebuilds the local dev database—it does not delete or renumber the migration directories that make this status out of order, especially in --branch mode where the comparison baseline is remote. The guidance here should focus on deleting/regenerating the local migration files, with any reset hint gated to local-only flows.

Suggested fix
     if (status.outOfOrder.length > 0) {
       log(
         `  Out of order: ${status.outOfOrder
           .map((m) => chalk.red(`${m.name} (version ${String(m.version)} <= max applied ${String(m.maxApplied)})`))
           .join(', ')}`,
       )
       log('')
       log(
         chalk.gray(
-          `Run ${formatCommand(
-            'db migrations reset',
-          )} to delete these local-only migrations, then generate them again with a higher prefix.`,
+          'Delete or rename these local migration directories, then generate them again with a higher prefix.',
         ),
       )
+      if (isLocal) {
+        log(chalk.gray(`If you need to rebuild the local dev database from scratch, run ${formatCommand('db reset')}.`))
+      }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/database/status-db.ts` around lines 323 - 335, The message shown
when status.outOfOrder has entries is incorrect: replace the current remediation
text that suggests running formatCommand('db migrations reset') with guidance to
remove or renumber the local migration files and re-generate them with a higher
prefix (e.g. delete/rename the local migration directories listed in
status.outOfOrder and run the migration generation command again). Also gate any
suggestion to run formatCommand('db reset') so it’s only displayed for
local-only flows (detect via the existing status metadata that indicates a
remote baseline or local-only state) rather than as a general fix. Ensure you
update the strings produced where status.outOfOrder is formatted and keep
references to the offending migrations (status.outOfOrder.map(...)) so users can
identify which local files to delete/regenerate.

@eduardoboucas eduardoboucas merged commit 9bccaf9 into main Apr 20, 2026
103 of 105 checks passed
@eduardoboucas eduardoboucas deleted the feat/db-status branch April 20, 2026 17:06
eduardoboucas added a commit that referenced this pull request Apr 20, 2026
eduardoboucas pushed a commit that referenced this pull request Apr 21, 2026
🤖 I have created a release *beep* *boop*
---


## [25.1.0](v25.0.1...v25.1.0)
(2026-04-21)


### Features

* add `db migrations reset` command
([#8177](#8177))
([3dd0f38](3dd0f38))
* add `db status` command
([#8173](#8173))
([9bccaf9](9bccaf9))
* Add deploy_source to CLI deploy requests (EX-2032)
([#8155](#8155))
([289933d](289933d))
* restructure db command files
([#8175](#8175))
([794c2e0](794c2e0))
* support `NETLIFY_DB_BRANCH` env var in `db status` command
([#8174](#8174))
([5647420](5647420))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: token-generator-app[bot] <82042599+token-generator-app[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants