Skip to content

Conversation

@pietern
Copy link
Contributor

@pietern pietern commented Jan 29, 2026

Summary

  • Add support for the new Lakebase Autoscaling API (projects/branches/endpoints) alongside existing Lakebase Provisioned instances
  • Introduce --provisioned and --autoscaling flags to filter by product type during interactive selection
  • Add --project, --branch, and --endpoint flags for direct autoscaling resource targeting
  • Auto-select branch/endpoint when only one exists for streamlined UX
  • Skip retries for non-retryable connection errors (authentication failures, missing roles/databases)

Backward Compatibility

The existing interface remains fully compatible:

  • databricks psql my-instance continues to work for Lakebase Provisioned
  • databricks psql (no args) still shows interactive selection, now including both products
  • All existing flags and behaviors are preserved

Test plan

  • New acceptance tests
  • Manually tested with both provisioned and autoscaling instances

pietern and others added 22 commits January 29, 2026 18:22
- Add lakebasev2 package for new Postgres API (projects/branches/endpoints)
- Move existing lakebase code to lakebasev1 package
- Update psql command to support both APIs:
  - Old API: databricks psql <database-instance>
  - New API: databricks psql --project <id> or projects/<id>/...
- Add interactive selection with display names
- Auto-select when only one branch/endpoint exists

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactor lakebase v1 and v2 packages to contain only library logic
(fetching instances, connecting) while the interactive selection and
prompting logic now lives in cmd/psql. This improves separation of
concerns - libraries handle data and connections, commands handle UI.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move the psql command building, retry logic, and connection handling
into libs/lakebase/psql. Both v1 (Database API) and v2 (Postgres API)
now use the shared RetryConfig and ConnectOptions structs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The first connection attempt now shows the same message as when retries
are disabled. Attempt numbers are only shown on the 2nd and subsequent
attempts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of retrieving the workspace client from context inside the
Connect functions, require it as a parameter. This makes the dependency
explicit.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rename "Old Database API" to "Lakebase Provisioned" and "New Postgres API"
to "Lakebase Autoscaling" throughout the codebase to align with official
Databricks documentation.

Also fix the auto-selection acceptance test by configuring the mock server
to return a single branch and endpoint, and add test coverage for:
- All three flags specified (--project --branch --endpoint)
- Extra arguments with --project flag

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reduce verbosity by showing concise connection status (e.g., "Instance: my-database
(provisioned)" instead of multiple status lines). Add FormatEndpointType and
FormatEndpointState helpers for cleaner display. Consolidate connection functions
and simplify control flow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tection

Positional argument now takes precedence over flags. Flags can supplement
missing components in partial paths but conflict with existing components
in the path. Also validates resource path structure and rejects malformed
paths with clear error messages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ection

Extract listAllDatabases function to fetch instances and projects in
parallel, used by both autocompletion and interactive selection.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tput

Move the project log line from connectAutoscaling to resolveEndpoint and
fetch the project to display its human-readable name.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Return the branch ID string directly instead of the full branch object,
matching the pattern used by selectEndpointID.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Follows the same pattern as selectBranchID and selectEndpointID.
Displays project display names but returns the project ID.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update resolveEndpoint to:
- Call selectProjectID when projectID is not provided
- Perform GET calls on branch and endpoint to validate they exist
- Use the fetched objects to build resource names consistently

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The endpoint is now fetched directly in resolveEndpoint using the SDK.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- psql.go: Main command setup, argument parsing, interactive selection
- psql_provisioned.go: connectProvisioned function
- psql_autoscaling.go: connectAutoscaling, resolveEndpoint, and select* functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…selection

These flags limit the interactive selection to a single product segment:
- --provisioned: Only show/select from provisioned database instances
- --autoscaling: Only show/select from autoscaling projects

The flags are mutually exclusive with each other and have appropriate
conflict detection with other flags and positional arguments.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add error classification to distinguish between transient and permanent
psql connection failures. Errors like "role does not exist" and
"authentication failed" are not retried since they require user action.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Standardize error messages across all selection functions:
- Combined: "no Lakebase databases found in workspace"
- Provisioned: "no Lakebase Provisioned instances found in workspace"
- Autoscaling: "no Lakebase Autoscaling projects found in workspace"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Simplify help text with grouped examples instead of numbered list
- Add link to Lakebase documentation
- Group flags into "Product Selection" and "Autoscaling" sections
- Fix usage string to show flags before -- separator

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Show instance name for provisioned and project name for autoscaling
in the selection ID, instead of numeric indices.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@pietern pietern temporarily deployed to test-trigger-is January 29, 2026 22:27 — with GitHub Actions Inactive
@eng-dev-ecosystem-bot
Copy link
Collaborator

eng-dev-ecosystem-bot commented Jan 29, 2026

Commit: 9b9e19b

Run: 21496999517

Env 🟨​KNOWN 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🟨​ aws linux 3 5 7 442 710 21:51
🟨​ aws windows 3 5 7 414 718 18:50
🟨​ aws-ucws linux 5 8 5 641 580 75:55
🟨​ aws-ucws windows 5 8 5 610 589 68:49
💚​ azure linux 2 9 442 709 21:47
💚​ azure windows 2 9 414 717 19:56
🟨​ azure-ucws linux 3 4 7 637 579 73:28
🟨​ azure-ucws windows 3 4 7 606 588 64:55
💚​ gcp linux 2 9 431 715 22:24
💚​ gcp windows 2 9 403 723 19:36
18 interesting tests: 8 RECOVERED, 5 KNOWN, 5 SKIP
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🟨​ TestAccept 🟨​K 🟨​K 🟨​K 🟨​K 💚​R 💚​R 🟨​K 🟨​K 💚​R 💚​R
🙈​ TestAccept/bundle/deployment/bind/alert 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/generate/alert 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🟨​K 🟨​K 🙈​S 🙈​S 🟨​K 🟨​K 🙈​S 🙈​S
🟨​ TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=alert.yml.tmpl 🟨​K 🟨​K 🟨​K 🟨​K
🙈​ TestAccept/bundle/resources/alerts/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/alerts/with_file 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 🟨​K 🟨​K 🟨​K 🟨​K 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 🟨​K 🟨​K
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 💚​R 💚​R 🙈​S 🙈​S 💚​R 💚​R 🙈​S 🙈​S
💚​ TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/ssh/connection 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
Top 50 slowest tests (at least 2 minutes):
duration env testname
8:19 aws-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl
8:03 gcp linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
7:03 aws-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl
6:51 aws-ucws windows TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
6:38 aws-ucws linux TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
6:36 aws-ucws windows TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
6:34 aws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
6:15 aws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
6:08 aws-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl
6:08 aws-ucws linux TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
6:06 gcp windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:52 aws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:43 aws-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_instance.yml.tmpl
5:40 aws-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl
5:38 gcp windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:35 aws-ucws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:23 aws-ucws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:16 aws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:10 aws-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_instance.yml.tmpl
5:08 azure-ucws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
4:51 gcp linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
4:42 azure-ucws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
4:29 azure windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
4:24 azure linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
4:22 azure-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl
4:15 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:13 azure-ucws windows TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
4:00 azure windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
3:59 azure-ucws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
3:57 azure-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_instance.yml.tmpl
3:56 azure-ucws linux TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
3:47 azure linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
3:46 azure-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl
3:38 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:34 azure-ucws windows TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
3:32 azure-ucws linux TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
3:29 azure-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl
3:27 aws-ucws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
3:23 azure-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl
3:20 azure-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_instance.yml.tmpl
3:08 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:06 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:47 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:45 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:44 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:43 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:43 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:43 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:43 aws-ucws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
2:42 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform

@pietern pietern requested a review from simonfaltum January 30, 2026 09:59
func FormatEndpointState(state postgres.EndpointStatusState) string {
switch state {
case postgres.EndpointStatusStateActive:
return ""
Copy link
Contributor

Choose a reason for hiding this comment

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

why is this empty string and not "active"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't need to inform the user that the endpoint is in the nominal good state.

I'll refactor this to provide a "suffix" with parens to make the logger below simpler.

endpointType := FormatEndpointType(endpoint.Status.EndpointType)
stateDesc := FormatEndpointState(state)
if stateDesc != "" {
cmdio.LogString(ctx, fmt.Sprintf("Connecting to %s endpoint (%s)...", endpointType, stateDesc))
Copy link
Contributor

Choose a reason for hiding this comment

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

This branch only executes for state == Idle, intentional?

cmdio.LogString(ctx, fmt.Sprintf("Connecting to %s endpoint...", endpointType))
}

if endpoint.Status.Hosts == nil || endpoint.Status.Hosts.Host == "" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why some errors are returned before Connecting message and some after? What's the difference?

@@ -0,0 +1,100 @@
package lakebasev2
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this package in libs/, it seems tightly coupled to psql command, so it can live somewhere in cmd/?

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.

5 participants