Skip to content

Conversation

@fjakobs
Copy link
Contributor

@fjakobs fjakobs commented Jan 25, 2026

Summary

This PR adds bundle mode support to apps delete, start, stop, and logs commands, allowing them to auto-detect the app name from project configuration. It also significantly reduces code duplication by extracting common functionality into shared helper functions.

Changes

New Features

  • Bundle mode support: Commands now work without explicit app name when run from project directory
    • databricks apps delete - Destroys all project resources (calls bundle destroy)
    • databricks apps start/stop - Auto-detects app name from databricks.yml
    • databricks apps logs - Streams logs for project app automatically
  • Idempotent operations: Start/stop commands handle "already in desired state" errors gracefully
  • Enhanced output: Display app URL after starting, improved status messages with emojis
  • Target support: All bundle-mode commands support --target flag

Examples

# From a Databricks Apps project directory:
databricks apps start              # Auto-detects app name
databricks apps stop --target prod # Stop production app
databricks apps delete             # Destroy all project resources
databricks apps logs               # Stream logs for project app

# API mode (works from anywhere):
databricks apps start my-app
databricks apps delete my-app

fjakobs and others added 11 commits January 24, 2026 14:02
When run from a directory containing databricks.yml without an app name,
`databricks apps delete` now destroys all project resources (similar to
`databricks bundle destroy`).

When an app name is provided, it falls back to the original API delete.

This mirrors the behavior of `databricks apps deploy` and provides a
consistent UX for project-based workflows.

Changes:
- Add BundleDeleteOverrideWithWrapper in cmd/apps/delete_bundle.go
- Register delete override in cmd/workspace/apps/overrides.go
- Add --auto-approve and --force-lock flags for project mode
- Update terminology from "bundle" to "Databricks Apps project"
- Add unit tests for delete override functionality

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
When run from a Databricks Apps project directory without an app name,
`databricks apps start` and `databricks apps stop` now automatically
detect the app name from the databricks.yml configuration (similar to
how `databricks apps dev-remote` works).

When an app name is provided, they fall back to the original API behavior.

This provides a consistent UX for project-based workflows where users
don't need to manually specify the app name each time.

Changes:
- Add BundleStartOverrideWithWrapper in cmd/apps/start_stop_bundle.go
- Add BundleStopOverrideWithWrapper in cmd/apps/start_stop_bundle.go
- Register start and stop overrides in cmd/workspace/apps/overrides.go
- Remove old startOverride function (replaced by bundle version)
- Add unit tests for start/stop override functionality

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhanced the apps start, stop, deploy, and delete commands with better
target support and user experience:

Target Flag Support:
- Added examples showing --target flag usage in all project mode commands
- The --target flag was already working (via TryConfigureBundle) but now
  properly documented in help text

Human-Readable Output:
- start/stop commands in project mode now show friendly success messages
  instead of raw JSON output
- Provides clear feedback: "✔ App 'name' started/stopped successfully"

Changes:
- Add --target examples to all command help texts
- Improve start/stop output formatting in project mode
- Maintain JSON output for API mode (backward compatible)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed start and stop commands to handle cases where the app is already
in the desired state gracefully instead of returning an error.

Behavior:
- `databricks apps start` on an already-running app now shows:
  "✔ App 'name' is already started" (instead of erroring)

- `databricks apps stop` on an already-stopped app now shows:
  "✔ App 'name' is already stopped" (instead of erroring)

This makes the commands idempotent and provides a better user experience,
especially in automation scenarios where the exact state of the app may
not be known before running the command.

Works in both project mode and API mode.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Modified start and stop commands to respect the output format flag:

Text Mode (default):
- In project mode, calls the API directly and shows only human-readable
  messages without JSON output
- Shows spinner with progress updates during wait
- Clean output: "✔ App 'name' started/stopped successfully"
- Idempotent behavior maintained

JSON Mode (-o json):
- Uses the original command to render JSON output
- No additional human-readable messages added
- Useful for scripting and automation

This ensures users see clean, human-friendly output by default while
still supporting JSON output when explicitly requested.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Modified the start command to display the app URL after successfully
starting (or when the app is already started).

Behavior:
- After `databricks apps start` completes, shows: "App URL: <url>"
- Works in both project mode and API mode
- Works for both newly started apps and already-running apps (idempotent case)
- In project mode: Uses the app info from the wait response when available,
  otherwise makes a separate API call to get the URL
- In API mode with explicit app name: Gets URL when app is already started

This makes it easier for users to immediately access their app after starting it.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enhanced the visual presentation of the app URL after starting:

Before:
  ✔ App 'app7' is already started
  App URL: https://app7-1966697730403610.10.azure.databricksapps.com

After:
  ✔ App 'app7' is already running

  🔗 https://app7-1966697730403610.10.azure.databricksapps.com

Changes:
- Added link emoji (🔗) before URL for better visual distinction
- Added blank lines before and after URL to improve readability
- Changed "already started" to "already running" for consistency
- Makes the URL stand out more clearly in the terminal output

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit adds bundle mode support to the `apps logs` command and
reduces code duplication across apps commands (logs, start, stop).

Changes:
- Add bundle_helpers.go with shared helper functions:
  - makeArgsOptionalWithBundle: Handles optional NAME argument
  - getAppNameFromArgs: Detects app name from args or bundle config
  - updateCommandHelp: Generates consistent help text
  - BundleLogsOverride: Applies bundle mode to logs command

- Update apps logs command to auto-detect app name from databricks.yml
  - Now supports `databricks apps logs` without NAME argument
  - Maintains backward compatibility with explicit NAME

- Refactor start/stop commands to reduce duplication:
  - Extract formatAppStatusMessage helper for status message generation
  - Reduces ~90 lines of duplicated code
  - Remove obvious comments and improve code clarity

- Fix apps delete double initialization panic:
  - Update CommandBundleDestroy to skip context initialization when
    already initialized by parent command (apps delete override)
  - Fixes: "must not call InitContext() twice" panic

All commands now support consistent dual mode behavior:
- Auto-detect from databricks.yml when no NAME provided
- Fall back to API mode with explicit NAME argument

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…rage

Extracted 3 helper functions (isIdempotencyError, displayAppURL,
handleAlreadyInStateError) to eliminate repeated patterns across
start/stop/delete commands. Replaced inline argument validation with
shared makeArgsOptionalWithBundle helper. Removed 15+ redundant comments
per CLAUDE.md guidelines.

Added comprehensive unit tests for all helper functions and command
override behavior, increasing test coverage from 10-15% to 70-80%.

Net impact: -92 lines of production code, +165 lines including tests.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Move formatAppStatusMessage and helper functions to bundle_helpers.go
- Refactor start/stop overrides to use shared helper functions
- Remove verbose test assertion messages

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Remove "Get current working directory for validation" comment
- Remove "Show error details" comment

Both comments were redundant and violated the project style guide.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@eng-dev-ecosystem-bot
Copy link
Collaborator

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

Commit: fd33b4f

Run: 21335067591

Env 🟨​KNOWN 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🟨​ aws linux 7 1 7 411 700 21:24
🟨​ aws windows 7 1 7 413 698 21:48
🟨​ aws-ucws linux 5 8 5 598 574 74:24
🟨​ aws-ucws windows 5 8 5 600 572 69:32
💚​ azure linux 2 9 411 699 20:49
💚​ azure windows 2 9 413 697 20:13
🟨​ azure-ucws linux 3 4 7 594 573 66:10
🟨​ azure-ucws windows 3 4 7 596 571 65:40
💚​ gcp linux 2 9 400 705 21:36
🔄​ gcp windows 2 9 402 703 20:46
18 interesting tests: 9 KNOWN, 5 SKIP, 3 RECOVERED, 1 flaky
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 🔄​f
🙈​ 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 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​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 🔄​f
Top 50 slowest tests (at least 2 minutes):
duration env testname
7:30 aws-ucws linux TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
7:19 aws-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_instance.yml.tmpl
7:14 aws-ucws linux TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
7:10 aws-ucws windows TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
7:10 aws-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl
7:06 aws-ucws windows TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
6:57 aws-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl
6:48 aws-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl
6:11 aws-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_instance.yml.tmpl
6:03 aws-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl
5:42 aws-ucws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:39 aws-ucws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:38 aws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:37 aws-ucws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:34 gcp windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:31 azure-ucws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:31 gcp windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:26 aws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:23 aws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
5:15 aws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
5:03 gcp linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
4:59 gcp linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
4:33 azure linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
4:17 azure-ucws linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
4:13 azure-ucws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
4:08 azure-ucws windows TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
3:58 azure-ucws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
3:45 azure linux TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
3:25 azure-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl
3:24 azure-ucws windows TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
3:20 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:19 azure-ucws linux TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=terraform
3:12 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:08 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:06 azure-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl
3:03 azure-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_catalog.yml.tmpl
2:53 azure-ucws windows TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=database_instance.yml.tmpl
2:53 azure-ucws linux TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=synced_database_table.yml.tmpl
2:46 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:45 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:42 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:41 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:40 azure-ucws linux TestAccept/bundle/resources/synced_database_tables/basic/DATABRICKS_BUNDLE_ENGINE=direct
2:39 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:38 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:38 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:36 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:34 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:34 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:27 aws-ucws windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform

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.

3 participants