diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 16af8be755..f82e92b8b3 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -5,6 +5,7 @@ ### Notable Changes ### CLI +* Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively ([#5464](https://github.com/databricks/cli/pull/5464)). ### Bundles * Set the default `data_security_mode` to `DATA_SECURITY_MODE_AUTO` in bundle templates ([#5452](https://github.com/databricks/cli/pull/5452)). diff --git a/acceptance/help/output.txt b/acceptance/help/output.txt index b847152cc8..dd1063bc39 100644 --- a/acceptance/help/output.txt +++ b/acceptance/help/output.txt @@ -177,6 +177,7 @@ Additional Commands: configure Configure authentication help Help about any command labs Manage Databricks Labs installations + quickstart Print an introduction to the Databricks CLI version Retrieve information about the current version of this CLI Flags: diff --git a/acceptance/quickstart/out.test.toml b/acceptance/quickstart/out.test.toml new file mode 100644 index 0000000000..f784a18325 --- /dev/null +++ b/acceptance/quickstart/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/quickstart/output.txt b/acceptance/quickstart/output.txt new file mode 100644 index 0000000000..8d9dd3ab43 --- /dev/null +++ b/acceptance/quickstart/output.txt @@ -0,0 +1,88 @@ +# Databricks Quickstart + +The `databricks` CLI wraps the public Databricks REST API — there's a command for essentially every API endpoint, so almost any Databricks task can be driven from here. If something looks unsupported, it's almost always a command you haven't found yet, not a real gap. The headline workflow: build durable resources as code with **Databricks Asset Bundles (DABs)** and ship them with `databricks bundle deploy` (see Build and deploy below). + +## Golden rules + +- **Reason, don't refuse.** Before telling the user something can't be done, run `databricks --help` and install the matching skill (below). Almost everything is reachable through the CLI. +- **Build with bundles.** For anything durable — jobs, pipelines, dashboards, apps — define it as code in a Databricks Asset Bundle (DABs) and ship with `databricks bundle deploy`, not one-off API calls. +- **Pick the profile deliberately.** Run `databricks auth profiles`. If only one profile exists, use it. If one is already set as the default (via `databricks auth switch`), assume that one — you can confirm if unsure. Otherwise, show the user the profiles with their workspace URLs and let them choose. Don't invent profile names. +- **Always pass `--profile `.** Each Bash command runs in its own shell, so a separate `export DATABRICKS_CONFIG_PROFILE=...` line does NOT persist. Use the flag, or chain with `&&`. +- **OAuth, never PAT.** Authenticate with `databricks auth login`, not personal access tokens. + +## Step 1 — Authenticate + +```bash +databricks auth profiles # already set up? lists profiles + validity +databricks auth login --profile # if not — opens login.databricks.com to pick a workspace +``` + +No host needed: without `--host`, login opens login.databricks.com and the user picks a workspace in the browser. Only pass `--host ` if the user already gave you a specific workspace URL. Always pass a descriptive `--profile ` (e.g. `dev-aws`, `prod-azure`) so you can target it reliably afterward — ask the user for the name rather than inventing one. + +## Step 2 — Verify + +```bash +databricks current-user me --profile +``` + +## Build and deploy with Asset Bundles (DABs) + +**DABs are the standard, recommended way to build on Databricks.** A bundle is a project with a `databricks.yml` that declares your resources (jobs, pipelines, dashboards, apps) and its targets (e.g. dev, prod) — one project, one deploy, every resource type: + +```bash +databricks bundle init # scaffold a project from a template +databricks bundle validate # check the config +databricks bundle deploy -t dev # deploy everything to a target (dev, prod, ...) +databricks bundle run -t dev # run a job or pipeline +``` + +Read the `databricks-dabs` skill for bundle structure, resource schemas, and multi-target setup. + +**Databricks Apps** (full-stack TypeScript + React via AppKit) build on bundles too, with a dedicated scaffolder — see `databricks-apps`: + +```bash +databricks apps init # scaffold an AppKit app (generates the bundle for you) +databricks apps deploy # deploy it to the workspace +databricks apps run-local # develop locally (or `dev-remote` against the workspace) +``` + +## Common commands + +```bash +databricks jobs list --profile +databricks pipelines list --profile +databricks apps list --profile +databricks warehouses list --profile + +# Unity Catalog data uses POSITIONAL args, NOT flags: +databricks catalogs list --profile +databricks schemas list --profile +databricks tables list --profile +``` + +Unsure of a command's shape? Run `databricks --help`. + +## Install skills for the task + +Skills give you Databricks-specific patterns so you build resources correctly instead of guessing. They install into your coding agent (auto-detected): + +```bash +databricks aitools install # stable skills +databricks aitools install --experimental # broader coverage: more areas, lower quality bar +databricks aitools list # available + installed skills — check this for the latest +``` + +The set evolves, so run `databricks aitools list` rather than relying on a fixed list. Common ones: `databricks-core` (CLI/auth), `databricks-jobs`, `databricks-pipelines`, `databricks-dabs` (deploy as code), `databricks-apps`. Experimental skills reach further (Unity Catalog, vector search, dashboards, AI functions, and more) — worth a look depending on the prompt. + +## Explore data + +Use the built-in tools instead of guessing SQL or navigating by hand: + +```bash +databricks experimental aitools tools discover-schema .. --profile +databricks experimental aitools tools query "SELECT * FROM
LIMIT 10" --profile +``` + +## When you get stuck + +Re-read `databricks --help`, install the matching skill, and check https://docs.databricks.com. If you truly can't do something yourself, tell the user how they can — don't tell them Databricks can't. diff --git a/acceptance/quickstart/script b/acceptance/quickstart/script new file mode 100644 index 0000000000..ffe8b16364 --- /dev/null +++ b/acceptance/quickstart/script @@ -0,0 +1 @@ +$CLI quickstart diff --git a/cmd/cmd.go b/cmd/cmd.go index 2c1a32caa5..6f2848e871 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -19,6 +19,7 @@ import ( "github.com/databricks/cli/cmd/fs" "github.com/databricks/cli/cmd/labs" "github.com/databricks/cli/cmd/pipelines" + "github.com/databricks/cli/cmd/quickstart" "github.com/databricks/cli/cmd/root" "github.com/databricks/cli/cmd/selftest" "github.com/databricks/cli/cmd/sync" @@ -123,6 +124,7 @@ func New(ctx context.Context) *cobra.Command { cli.AddCommand(labs.New(ctx)) cli.AddCommand(sync.New()) cli.AddCommand(version.New()) + cli.AddCommand(quickstart.New()) cli.AddCommand(selftest.New()) cli.AddCommand(ssh.New()) diff --git a/cmd/quickstart/.gitattributes b/cmd/quickstart/.gitattributes new file mode 100644 index 0000000000..c2c839a7c6 --- /dev/null +++ b/cmd/quickstart/.gitattributes @@ -0,0 +1,6 @@ +# These markdown files are embedded into the binary with go:embed and their +# newlines are semantically important: stripFrontmatter matches an LF fence +# ("---\n"), so an extra \r on Windows would leave the frontmatter unstripped. +# Always check them out with \n so the embedded content is identical on every +# platform. +*.md text eol=lf diff --git a/cmd/quickstart/quickstart-agent.md b/cmd/quickstart/quickstart-agent.md new file mode 100644 index 0000000000..04a8d187e0 --- /dev/null +++ b/cmd/quickstart/quickstart-agent.md @@ -0,0 +1,93 @@ +--- +name: databricks-quickstart +description: First-contact orientation for the Databricks CLI when no Databricks skill is loaded. Covers OAuth auth, profile selection, command discovery, and installing the right skill for the task. Read this before attempting any Databricks work. +--- + +# Databricks Quickstart + +The `databricks` CLI wraps the public Databricks REST API — there's a command for essentially every API endpoint, so almost any Databricks task can be driven from here. If something looks unsupported, it's almost always a command you haven't found yet, not a real gap. The headline workflow: build durable resources as code with **Databricks Asset Bundles (DABs)** and ship them with `databricks bundle deploy` (see Build and deploy below). + +## Golden rules + +- **Reason, don't refuse.** Before telling the user something can't be done, run `databricks --help` and install the matching skill (below). Almost everything is reachable through the CLI. +- **Build with bundles.** For anything durable — jobs, pipelines, dashboards, apps — define it as code in a Databricks Asset Bundle (DABs) and ship with `databricks bundle deploy`, not one-off API calls. +- **Pick the profile deliberately.** Run `databricks auth profiles`. If only one profile exists, use it. If one is already set as the default (via `databricks auth switch`), assume that one — you can confirm if unsure. Otherwise, show the user the profiles with their workspace URLs and let them choose. Don't invent profile names. +- **Always pass `--profile `.** Each Bash command runs in its own shell, so a separate `export DATABRICKS_CONFIG_PROFILE=...` line does NOT persist. Use the flag, or chain with `&&`. +- **OAuth, never PAT.** Authenticate with `databricks auth login`, not personal access tokens. + +## Step 1 — Authenticate + +```bash +databricks auth profiles # already set up? lists profiles + validity +databricks auth login --profile # if not — opens login.databricks.com to pick a workspace +``` + +No host needed: without `--host`, login opens login.databricks.com and the user picks a workspace in the browser. Only pass `--host ` if the user already gave you a specific workspace URL. Always pass a descriptive `--profile ` (e.g. `dev-aws`, `prod-azure`) so you can target it reliably afterward — ask the user for the name rather than inventing one. + +## Step 2 — Verify + +```bash +databricks current-user me --profile +``` + +## Build and deploy with Asset Bundles (DABs) + +**DABs are the standard, recommended way to build on Databricks.** A bundle is a project with a `databricks.yml` that declares your resources (jobs, pipelines, dashboards, apps) and its targets (e.g. dev, prod) — one project, one deploy, every resource type: + +```bash +databricks bundle init # scaffold a project from a template +databricks bundle validate # check the config +databricks bundle deploy -t dev # deploy everything to a target (dev, prod, ...) +databricks bundle run -t dev # run a job or pipeline +``` + +Read the `databricks-dabs` skill for bundle structure, resource schemas, and multi-target setup. + +**Databricks Apps** (full-stack TypeScript + React via AppKit) build on bundles too, with a dedicated scaffolder — see `databricks-apps`: + +```bash +databricks apps init # scaffold an AppKit app (generates the bundle for you) +databricks apps deploy # deploy it to the workspace +databricks apps run-local # develop locally (or `dev-remote` against the workspace) +``` + +## Common commands + +```bash +databricks jobs list --profile +databricks pipelines list --profile +databricks apps list --profile +databricks warehouses list --profile + +# Unity Catalog data uses POSITIONAL args, NOT flags: +databricks catalogs list --profile +databricks schemas list --profile +databricks tables list --profile +``` + +Unsure of a command's shape? Run `databricks --help`. + +## Install skills for the task + +Skills give you Databricks-specific patterns so you build resources correctly instead of guessing. They install into your coding agent (auto-detected): + +```bash +databricks aitools install # stable skills +databricks aitools install --experimental # broader coverage: more areas, lower quality bar +databricks aitools list # available + installed skills — check this for the latest +``` + +The set evolves, so run `databricks aitools list` rather than relying on a fixed list. Common ones: `databricks-core` (CLI/auth), `databricks-jobs`, `databricks-pipelines`, `databricks-dabs` (deploy as code), `databricks-apps`. Experimental skills reach further (Unity Catalog, vector search, dashboards, AI functions, and more) — worth a look depending on the prompt. + +## Explore data + +Use the built-in tools instead of guessing SQL or navigating by hand: + +```bash +databricks experimental aitools tools discover-schema ..
--profile +databricks experimental aitools tools query "SELECT * FROM
LIMIT 10" --profile +``` + +## When you get stuck + +Re-read `databricks --help`, install the matching skill, and check https://docs.databricks.com. If you truly can't do something yourself, tell the user how they can — don't tell them Databricks can't. diff --git a/cmd/quickstart/quickstart-human.md b/cmd/quickstart/quickstart-human.md new file mode 100644 index 0000000000..bdd8481938 --- /dev/null +++ b/cmd/quickstart/quickstart-human.md @@ -0,0 +1,67 @@ +# Welcome to Databricks + +Databricks is one place for all your data and AI work: store and govern data, run SQL and notebooks, build pipelines and dashboards, train and serve models, and ship apps. No stitching together separate tools. + +This guide takes you from zero to your first command. + +## What you need + +A **workspace** — your Databricks home, at a URL like `https://your-company.cloud.databricks.com`. No access yet? Sign up for a free trial at https://www.databricks.com (Databricks Free Edition is great for learning). You've already got the CLI — it's how you're reading this. + +## A few concepts (the 30-second version) + +- **Workspace** — the environment you log into. Notebooks, jobs, dashboards, and data all live here. +- **Unity Catalog** — how Databricks governs your data. Tables are named in three parts: `catalog.schema.table` (think folder → subfolder → table). +- **Compute** — where your code runs. *SQL warehouses* run SQL; *clusters* and *serverless* run notebooks and jobs. +- **Profile** — a saved connection to a workspace on your machine, so you don't re-enter credentials each time. + +## Step 1 — Connect to your workspace + +```bash +databricks auth login +``` +This opens **login.databricks.com** in your browser. Sign in, pick the workspace you want, and you're connected — no URL to look up. The CLI saves the connection as a *profile*; if it's your only workspace, press Enter to accept the suggested name and every command will use it automatically. Run `databricks auth login` again any time to add another workspace. + +Already know your workspace URL? Go straight to it: `databricks auth login --host https://your-company.cloud.databricks.com --profile my-workspace`. + +## Step 2 — Try it out + +```bash +databricks current-user me # who am I? +databricks catalogs list # what data can I see? +databricks jobs list # my jobs +``` +To see everything a command can do, add `--help` — for example, `databricks jobs --help`. + +Got more than one workspace? Name each at login (`databricks auth login --profile prod`), then target it with `--profile`, e.g. `databricks jobs list --profile prod`. + +💡 **Tip:** turn on tab-completion so you can `Tab` through commands and flags: `databricks completion install`. + +## Step 3 — Build something + +The standard way to build on Databricks is **Databricks Asset Bundles (DABs)** — your jobs, pipelines, dashboards, and apps defined as code in one project, shipped with one command: + +```bash +databricks bundle init # start from a template +databricks bundle validate # check it +databricks bundle deploy -t dev # ship it to your workspace +databricks bundle run -t dev # run a job or pipeline +``` + +Want a **full-stack app**? AppKit scaffolds one in TypeScript + React: + +```bash +databricks apps init # scaffold the app +databricks apps deploy # deploy it to your workspace +databricks apps run-local # develop locally (or dev-remote) +``` + +## Where to go next + +- **Explore your data** — browse catalogs, schemas, and tables, or query them from the workspace UI. +- **More to build** — Lakeflow Jobs (orchestration), Lakeflow Pipelines (ETL), AI/BI Dashboards, and Model Serving. +- **Using an AI coding assistant?** Install the Databricks skills so it knows these patterns: `databricks aitools install`. + +📚 Full docs: https://docs.databricks.com • CLI reference: https://docs.databricks.com/dev-tools/cli + +Welcome aboard. diff --git a/cmd/quickstart/quickstart.go b/cmd/quickstart/quickstart.go new file mode 100644 index 0000000000..6628ee990b --- /dev/null +++ b/cmd/quickstart/quickstart.go @@ -0,0 +1,73 @@ +package quickstart + +import ( + _ "embed" + "fmt" + "strings" + + "github.com/databricks/cli/cmd/root" + "github.com/databricks/cli/libs/cmdio" + "github.com/spf13/cobra" +) + +// humanQuickstart is the friendly, default introduction shown to people. +// +//go:embed quickstart-human.md +var humanQuickstart string + +// agentQuickstart is the denser, agent-oriented version. It is also the +// `databricks-quickstart` skill, so it carries skill frontmatter that +// stripFrontmatter removes before printing. +// +//go:embed quickstart-agent.md +var agentQuickstart string + +func New() *cobra.Command { + cmd := &cobra.Command{ + Use: "quickstart", + Args: root.NoArgs, + Short: "Print an introduction to the Databricks CLI", + Long: `Print a short introduction to the Databricks CLI: authentication, profiles, +building with Databricks Asset Bundles, and where to go next. + +Prints a human-friendly guide by default. When stdout is not an interactive +terminal (for example, when a coding agent runs the command), it prints a +denser, agent-oriented version instead.`, + } + + cmd.RunE = func(cmd *cobra.Command, args []string) error { + content := quickstartFor(cmdio.IsPromptSupported(cmd.Context())) + _, err := fmt.Fprintln(cmd.OutOrStdout(), content) + return err + } + + return cmd +} + +// quickstartFor returns the quickstart text for the caller. Interactive +// terminals (people) get the friendly guide; non-interactive callers (coding +// agents, scripts, CI) get the agent-oriented version. The detection is +// intentionally simple for now and can grow more precise later. +func quickstartFor(interactive bool) string { + if interactive { + return strings.TrimRight(humanQuickstart, "\n") + } + return stripFrontmatter(agentQuickstart) +} + +// stripFrontmatter removes a leading YAML frontmatter block ("---\n...\n---\n") +// so the printed output starts at the document heading rather than the skill +// metadata. Input without frontmatter is returned unchanged (trailing newlines +// trimmed). Fprintln re-adds a single trailing newline. +func stripFrontmatter(s string) string { + const fence = "---\n" + if !strings.HasPrefix(s, fence) { + return strings.TrimRight(s, "\n") + } + rest := s[len(fence):] + _, body, found := strings.Cut(rest, "\n"+fence) + if !found { + return strings.TrimRight(s, "\n") + } + return strings.TrimRight(strings.TrimLeft(body, "\n"), "\n") +} diff --git a/cmd/quickstart/quickstart_test.go b/cmd/quickstart/quickstart_test.go new file mode 100644 index 0000000000..a2b8b83f43 --- /dev/null +++ b/cmd/quickstart/quickstart_test.go @@ -0,0 +1,58 @@ +package quickstart + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestQuickstartForInteractiveReturnsHumanGuide(t *testing.T) { + out := quickstartFor(true) + assert.Contains(t, out, "# Welcome to Databricks") + assert.NotContains(t, out, "## Golden rules") + assert.False(t, strings.HasSuffix(out, "\n"), "trailing newline should be trimmed; Fprintln re-adds one") +} + +func TestQuickstartForNonInteractiveReturnsAgentGuide(t *testing.T) { + out := quickstartFor(false) + assert.Contains(t, out, "# Databricks Quickstart") + assert.Contains(t, out, "## Golden rules") + // Frontmatter must be stripped so the output starts at the heading. + assert.True(t, strings.HasPrefix(out, "# Databricks Quickstart")) + assert.NotContains(t, out, "name: databricks-quickstart") +} + +func TestStripFrontmatter(t *testing.T) { + tests := []struct { + name string + in string + want string + }{ + { + name: "with frontmatter", + in: "---\nname: x\ndescription: y\n---\n\n# Title\n\nbody\n", + want: "# Title\n\nbody", + }, + { + name: "without frontmatter", + in: "# Title\n\nbody\n", + want: "# Title\n\nbody", + }, + { + name: "unterminated frontmatter is left intact", + in: "---\nname: x\n# Title", + want: "---\nname: x\n# Title", + }, + { + name: "empty", + in: "", + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, stripFrontmatter(tt.in)) + }) + } +}