Skip to content
Open
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 .nextchanges/bundles/app-appkit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Add `app-appkit` to bundle templates to simplify starting a Databricks Apps project. ([#7004](https://github.com/databricks/cli/pull/7004), [#7007](https://github.com/databricks/cli/pull/7007))
9 changes: 4 additions & 5 deletions acceptance/bundle/help/bundle-init/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ TEMPLATE_PATH optionally specifies which template to use. It can be one of the f
- dbt-sql: The dbt SQL template (databricks.com/blog/delivering-cost-effective-data-real-time-dbt-and-databricks)
- mlops-stacks: The Databricks MLOps Stacks template (github.com/databricks/mlops-stacks)
- pydabs: A variant of the 'default-python' template that defines resources in Python instead of YAML
- app-appkit: Databricks App with AppKit (TypeScript)
- a local file system path with a template directory
- a Git repository URL, e.g. https://github.com/my/repository

Examples:
databricks bundle init # Choose from built-in templates
databricks bundle init default-python # Python jobs and notebooks
databricks bundle init dbt-sql # dbt + SQL warehouse project
databricks bundle init --output-dir ./my-project
databricks bundle init default-python
databricks bundle init app-appkit --config-file input.json # {"project_name":"my-app"}

After initialization:
databricks bundle deploy --target dev
databricks bundle deploy

See https://docs.databricks.com/en/dev-tools/bundles/templates.html for more information on templates.

Expand Down
4 changes: 4 additions & 0 deletions acceptance/bundle/templates/app-appkit/input-version.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"project_name": "appkit-bundle-test",
"version": "0.76.1"
}
5 changes: 5 additions & 0 deletions acceptance/bundle/templates/app-appkit/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"project_name": "appkit-bundle-test",
"app_description": "AppKit bundle initialization test",
"skip_install": true
}
3 changes: 3 additions & 0 deletions acceptance/bundle/templates/app-appkit/out.test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Cloud = false
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"]
EnvMatrix.DMS = [""]
63 changes: 63 additions & 0 deletions acceptance/bundle/templates/app-appkit/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

=== Missing project name fails without a terminal
>>> musterr [CLI] bundle init app-appkit
Error: app-appkit requires project_name in --config-file in non-interactive mode

=== Unsupported template directory fails before initialization
>>> musterr [CLI] bundle init app-appkit --template-dir template
Error: --template-dir is not supported for app-appkit; use databricks apps init --template for a custom AppKit template

=== Version and branch cannot be combined
>>> musterr [CLI] bundle init app-appkit --config-file input-version.json --branch main
Error: version in --config-file cannot be combined with --tag or --branch

=== JSON output is unsupported
>>> musterr [CLI] bundle init app-appkit --config-file input.json -o json
Error: -o json is not supported for app-appkit; use text output

=== Initialize AppKit from a config file without a terminal
>>> [CLI] bundle init app-appkit --config-file input.json --output-dir output
✔ Creating project

✔ Project created successfully!

Location: [TEST_TMP_DIR]/output/appkit-bundle-test
Files: 5

Next steps:

cd appkit-bundle-test
pnpm install --frozen-lockfile && pnpm run dev


>>> [CLI] bundle validate
Name: appkit-bundle-test
Target: default
Workspace:
Host: [DATABRICKS_URL]
User: [USERNAME]
Path: /Workspace/Users/[USERNAME]/.bundle/appkit-bundle-test/default

Validation OK!

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/appkit-bundle-test/default/files...
✓ Deployment succeeded
Created apps.app
Files: 5 uploaded, 0 deleted
Resources: 1 created, 0 changed, 0 deleted, 0 unchanged

>>> [CLI] apps get appkit-bundle-test -o json
{
"name": "appkit-bundle-test",
"compute_state": "ACTIVE",
"deployment_state": "SUCCEEDED"
}

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete resources.apps.app

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/appkit-bundle-test/default

Destroy: 1 deleted
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
command: ["npm", "run", "start"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"version": "2.0",
"plugins": {
"server": {
"name": "server",
"displayName": "Server",
"description": "HTTP server",
"package": "@databricks/appkit",
"requiredByTemplate": true,
"resources": {
"required": [],
"optional": []
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
bundle:
name: appkit-bundle-test

resources:
apps:
app:
name: appkit-bundle-test
description: AppKit bundle initialization test
source_code_path: ./
lifecycle:
started: true

targets:
default:
default: true
workspace:
host: [DATABRICKS_URL]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "appkit-bundle-test",
"version": "1.0.0",
"type": "module",
"description": "AppKit bundle initialization test",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"@databricks/appkit": "0.57.0"
},
"packageManager": "pnpm@11.0.8"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createApp, server } from '@databricks/appkit';

createApp({
plugins: [server(),],
}).catch(console.error);
25 changes: 25 additions & 0 deletions acceptance/bundle/templates/app-appkit/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export DATABRICKS_APPKIT_TEMPLATE_PATH="$TESTDIR/template"

title "Missing project name fails without a terminal"
trace musterr $CLI bundle init app-appkit < /dev/null

title "Unsupported template directory fails before initialization"
trace musterr $CLI bundle init app-appkit --template-dir template < /dev/null

title "Version and branch cannot be combined"
trace musterr $CLI bundle init app-appkit --config-file input-version.json --branch main < /dev/null

title "JSON output is unsupported"
trace musterr $CLI bundle init app-appkit --config-file input.json -o json < /dev/null

title "Initialize AppKit from a config file without a terminal"
trace $CLI bundle init app-appkit --config-file input.json --output-dir output < /dev/null
test ! -d output/appkit-bundle-test/node_modules

cd output/appkit-bundle-test

trace $CLI bundle validate < /dev/null
trace $CLI bundle deploy < /dev/null
trace $CLI apps get appkit-bundle-test -o json | jq '{name, compute_state: .compute_status.state, deployment_state: .active_deployment.status.state}'
trace $CLI bundle destroy --auto-approve < /dev/null
rm -r .databricks
1 change: 1 addition & 0 deletions acceptance/bundle/templates/app-appkit/template/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
command: ["npm", "run", "start"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"version": "2.0",
"plugins": {
"server": {
"name": "server",
"displayName": "Server",
"description": "HTTP server",
"package": "@databricks/appkit",
"requiredByTemplate": true,
"resources": {
"required": [],
"optional": []
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
bundle:
name: {{.projectName}}

resources:
apps:
app:
name: {{.projectName}}
description: {{.appDescription}}
source_code_path: ./
lifecycle:
started: true

targets:
default:
default: true
workspace:
host: {{.workspaceHost}}
12 changes: 12 additions & 0 deletions acceptance/bundle/templates/app-appkit/template/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "{{.projectName}}",
"version": "1.0.0",
"type": "module",
"description": "{{.appDescription}}",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"@databricks/appkit": "0.57.0"
}
}
5 changes: 5 additions & 0 deletions acceptance/bundle/templates/app-appkit/template/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createApp{{range $name, $_ := .plugins}}, {{$name}}{{end}} } from '@databricks/appkit';

createApp({
plugins: [{{range $name, $_ := .plugins}}{{$name}}(),{{end}}],
}).catch(console.error);
1 change: 1 addition & 0 deletions acceptance/bundle/templates/app-appkit/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"]
4 changes: 2 additions & 2 deletions cmd/apps/delete_bundle.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package apps

import (
"github.com/databricks/cli/cmd/bundle"
"github.com/databricks/cli/cmd/bundle/utils"
"github.com/databricks/databricks-sdk-go/service/apps"
"github.com/spf13/cobra"
)
Expand All @@ -23,7 +23,7 @@ func BundleDeleteOverrideWithWrapper(wrapError ErrorWrapper) func(*cobra.Command
originalRunE := deleteCmd.RunE
deleteCmd.RunE = func(cmd *cobra.Command, args []string) error {
if len(args) == 0 && hasBundleConfig() {
return bundle.CommandBundleDestroy(cmd, args, autoApprove, forceDestroy)
return utils.CommandBundleDestroy(cmd, args, autoApprove, forceDestroy)
}

err := originalRunE(cmd, args)
Expand Down
5 changes: 5 additions & 0 deletions cmd/apps/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ Environment variables:
return cmd
}

// NewInitCommand creates the AppKit initializer for use by other CLI commands.
func NewInitCommand() *cobra.Command {
return newInitCmd()
}

type createOptions struct {
templatePath string
branch string
Expand Down
55 changes: 1 addition & 54 deletions cmd/bundle/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,8 @@
package bundle

import (
"context"
"errors"

"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/phases"
"github.com/databricks/cli/bundle/statemgmt"
"github.com/databricks/cli/cmd/bundle/utils"
"github.com/databricks/cli/cmd/root"
"github.com/databricks/cli/libs/agent"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/logdiag"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -44,52 +35,8 @@ Typical use cases:
cmd.Flags().CountVarP(&quiet, "quiet", "q", "Reduce output: -qq prints only warnings and errors.")

cmd.RunE = func(cmd *cobra.Command, args []string) error {
return CommandBundleDestroy(cmd, args, autoApprove, forceDestroy)
return utils.CommandBundleDestroy(cmd, args, autoApprove, forceDestroy)
}

return cmd
}

func CommandBundleDestroy(cmd *cobra.Command, args []string, autoApprove, forceDestroy bool) error {
// We require auto-approve for non-interactive terminals since prompts are not possible.
if !cmdio.IsPromptSupported(cmd.Context()) && !autoApprove {
return errors.New("this command will destroy all resources deployed by this bundle, " +
"including workspace files in the deployment directory.\n" +
phases.DataLossWarning + "\n" +
"To proceed, use --auto-approve." + agent.AgentNotice())
}

// Check if context is already initialized (e.g., when called from apps delete override)
skipInitContext := logdiag.IsSetup(cmd.Context())

opts := utils.ProcessOptions{
InitFunc: func(b *bundle.Bundle) {
// If `--force-lock` is specified, force acquisition of the deployment lock.
utils.SetForceLock(cmd, b, forceDestroy)

// If `--auto-approve`` is specified, we skip confirmation checks
b.AutoApprove = autoApprove

// Read --quiet off the command rather than taking it as a parameter, since
// other commands reuse this function ("apps delete") without defining it.
if cmd.Flags().Lookup("quiet") != nil {
n, _ := cmd.Flags().GetCount("quiet")
b.Quiet = bundle.QuietLevel(n)
}
},
// Skip context initialization if already initialized by parent command
SkipInitContext: skipInitContext,
AlwaysPull: true,
SkipEnforcingDeploymentHistorySetting: true,
PostStateFunc: func(ctx context.Context, b *bundle.Bundle, stateDesc *statemgmt.StateDesc) error {
phases.Destroy(ctx, b)
if logdiag.HasError(ctx) {
return root.ErrAlreadyPrinted
}
return nil
},
}

_, _, err := utils.ProcessBundleRet(cmd, opts)
return err
}
Loading
Loading