diff --git a/acceptance/bundle/help/bundle-deployment/output.txt b/acceptance/bundle/help/bundle-deployment/output.txt index a135735cd44..558d10850e4 100644 --- a/acceptance/bundle/help/bundle-deployment/output.txt +++ b/acceptance/bundle/help/bundle-deployment/output.txt @@ -21,6 +21,8 @@ Usage: Available Commands: bind Bind bundle-defined resources to existing resources + get Get a deployment. + list List deployments. migrate Migrate from Terraform to Direct deployment engine unbind Unbind bundle-defined resources from its managed remote resource diff --git a/acceptance/bundle/help/bundle/output.txt b/acceptance/bundle/help/bundle/output.txt index 624e18db9ca..715c7a6045e 100644 --- a/acceptance/bundle/help/bundle/output.txt +++ b/acceptance/bundle/help/bundle/output.txt @@ -24,12 +24,15 @@ Available Commands: generate Generate bundle configuration init Initialize using a bundle template open Open a resource in the browser + operation Read operation records in the bundle metadata service. plan Show deployment plan + resource Read resource records from the bundle metadata service. run Run a job, pipeline update or app schema Generate JSON Schema for bundle configuration summary Summarize resources deployed by this bundle sync Synchronize bundle tree to the workspace validate Validate configuration + version Read version records in the bundle metadata service. Flags: -h, --help help for bundle diff --git a/acceptance/cmd/bundle/dms-read-only/out.test.toml b/acceptance/cmd/bundle/dms-read-only/out.test.toml new file mode 100644 index 00000000000..f784a183258 --- /dev/null +++ b/acceptance/cmd/bundle/dms-read-only/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/cmd/bundle/dms-read-only/output.txt b/acceptance/cmd/bundle/dms-read-only/output.txt new file mode 100644 index 00000000000..6b702e746e3 --- /dev/null +++ b/acceptance/cmd/bundle/dms-read-only/output.txt @@ -0,0 +1,81 @@ + +>>> [CLI] bundle deployment list +[ + { + "display_name": "first deployment", + "name": "deployments/abc", + "status": "DEPLOYMENT_STATUS_ACTIVE", + "target_name": "dev" + }, + { + "display_name": "second deployment", + "name": "deployments/def", + "status": "DEPLOYMENT_STATUS_ACTIVE", + "target_name": "prod" + } +] + +>>> [CLI] bundle deployment get deployments/abc +{ + "display_name": "first deployment", + "last_version_id": "v1", + "name": "deployments/abc", + "status": "DEPLOYMENT_STATUS_ACTIVE", + "target_name": "dev" +} + +>>> [CLI] bundle version list deployments/abc +[ + { + "cli_version": "[DEV_VERSION]", + "name": "deployments/abc/versions/v1", + "status": "VERSION_STATUS_COMPLETED", + "version_type": "" + } +] + +>>> [CLI] bundle version get deployments/abc/versions/v1 +{ + "cli_version": "[DEV_VERSION]", + "name": "deployments/abc/versions/v1", + "status": "VERSION_STATUS_COMPLETED", + "version_type": "" +} + +>>> [CLI] bundle resource list deployments/abc +[ + { + "last_action_type": "OPERATION_ACTION_TYPE_CREATE", + "last_version_id": "v1", + "name": "deployments/abc/resources/my_job", + "resource_id": "12345", + "resource_type": "DEPLOYMENT_RESOURCE_TYPE_JOB" + } +] + +>>> [CLI] bundle resource get deployments/abc/resources/my_job +{ + "last_action_type": "OPERATION_ACTION_TYPE_CREATE", + "last_version_id": "v1", + "name": "deployments/abc/resources/my_job", + "resource_id": "12345", + "resource_type": "DEPLOYMENT_RESOURCE_TYPE_JOB" +} + +>>> [CLI] bundle operation list deployments/abc/versions/v1 +[ + { + "action_type": "OPERATION_ACTION_TYPE_CREATE", + "name": "deployments/abc/versions/v1/operations/my_job", + "resource_id": "12345", + "status": "OPERATION_STATUS_SUCCEEDED" + } +] + +>>> [CLI] bundle operation get deployments/abc/versions/v1/operations/my_job +{ + "action_type": "OPERATION_ACTION_TYPE_CREATE", + "name": "deployments/abc/versions/v1/operations/my_job", + "resource_id": "12345", + "status": "OPERATION_STATUS_SUCCEEDED" +} diff --git a/acceptance/cmd/bundle/dms-read-only/script b/acceptance/cmd/bundle/dms-read-only/script new file mode 100644 index 00000000000..1a39de6a77d --- /dev/null +++ b/acceptance/cmd/bundle/dms-read-only/script @@ -0,0 +1,8 @@ +trace $CLI bundle deployment list +trace $CLI bundle deployment get deployments/abc +trace $CLI bundle version list deployments/abc +trace $CLI bundle version get deployments/abc/versions/v1 +trace $CLI bundle resource list deployments/abc +trace $CLI bundle resource get deployments/abc/resources/my_job +trace $CLI bundle operation list deployments/abc/versions/v1 +trace $CLI bundle operation get deployments/abc/versions/v1/operations/my_job diff --git a/acceptance/cmd/bundle/dms-read-only/test.toml b/acceptance/cmd/bundle/dms-read-only/test.toml new file mode 100644 index 00000000000..b7a8cbd5901 --- /dev/null +++ b/acceptance/cmd/bundle/dms-read-only/test.toml @@ -0,0 +1,117 @@ +# Local-only acceptance test for the read-only DMS commands under +# `databricks bundle {deployment,version,resource,operation}`. The DMS APIs +# aren't on test workspaces yet, so we stub the eight read endpoints with +# fixed response bodies and assert the CLI renders them as expected. +Local = true +Cloud = false + +[[Server]] +Pattern = "GET /api/2.0/bundle/deployments" +Response.Body = ''' +{ + "deployments": [ + { + "name": "deployments/abc", + "display_name": "first deployment", + "target_name": "dev", + "status": "DEPLOYMENT_STATUS_ACTIVE" + }, + { + "name": "deployments/def", + "display_name": "second deployment", + "target_name": "prod", + "status": "DEPLOYMENT_STATUS_ACTIVE" + } + ] +} +''' + +[[Server]] +Pattern = "GET /api/2.0/bundle/deployments/abc" +Response.Body = ''' +{ + "name": "deployments/abc", + "display_name": "first deployment", + "target_name": "dev", + "status": "DEPLOYMENT_STATUS_ACTIVE", + "last_version_id": "v1" +} +''' + +[[Server]] +Pattern = "GET /api/2.0/bundle/deployments/abc/versions" +Response.Body = ''' +{ + "versions": [ + { + "name": "deployments/abc/versions/v1", + "cli_version": "0.0.0-dev", + "status": "VERSION_STATUS_COMPLETED" + } + ] +} +''' + +[[Server]] +Pattern = "GET /api/2.0/bundle/deployments/abc/versions/v1" +Response.Body = ''' +{ + "name": "deployments/abc/versions/v1", + "cli_version": "0.0.0-dev", + "status": "VERSION_STATUS_COMPLETED" +} +''' + +[[Server]] +Pattern = "GET /api/2.0/bundle/deployments/abc/resources" +Response.Body = ''' +{ + "resources": [ + { + "name": "deployments/abc/resources/my_job", + "resource_id": "12345", + "resource_type": "DEPLOYMENT_RESOURCE_TYPE_JOB", + "last_version_id": "v1", + "last_action_type": "OPERATION_ACTION_TYPE_CREATE" + } + ] +} +''' + +[[Server]] +Pattern = "GET /api/2.0/bundle/deployments/abc/resources/my_job" +Response.Body = ''' +{ + "name": "deployments/abc/resources/my_job", + "resource_id": "12345", + "resource_type": "DEPLOYMENT_RESOURCE_TYPE_JOB", + "last_version_id": "v1", + "last_action_type": "OPERATION_ACTION_TYPE_CREATE" +} +''' + +[[Server]] +Pattern = "GET /api/2.0/bundle/deployments/abc/versions/v1/operations" +Response.Body = ''' +{ + "operations": [ + { + "name": "deployments/abc/versions/v1/operations/my_job", + "action_type": "OPERATION_ACTION_TYPE_CREATE", + "resource_id": "12345", + "status": "OPERATION_STATUS_SUCCEEDED" + } + ] +} +''' + +[[Server]] +Pattern = "GET /api/2.0/bundle/deployments/abc/versions/v1/operations/my_job" +Response.Body = ''' +{ + "name": "deployments/abc/versions/v1/operations/my_job", + "action_type": "OPERATION_ACTION_TYPE_CREATE", + "resource_id": "12345", + "status": "OPERATION_STATUS_SUCCEEDED" +} +''' diff --git a/cmd/bundle/bundle.go b/cmd/bundle/bundle.go index 3f4985c2480..5ed4e6dc8e1 100644 --- a/cmd/bundle/bundle.go +++ b/cmd/bundle/bundle.go @@ -36,9 +36,47 @@ Online documentation: https://docs.databricks.com/en/dev-tools/bundles/index.htm cmd.AddCommand(newSummaryCommand()) cmd.AddCommand(newGenerateCommand()) cmd.AddCommand(newDebugCommand()) - cmd.AddCommand(deployment.NewDeploymentCommand()) cmd.AddCommand(newOpenCommand()) cmd.AddCommand(newPlanCommand()) cmd.AddCommand(newConfigRemoteSyncCommand()) + + // Bundle Metadata Service (DMS) read-only command groups. Only `get` + // and `list` are surfaced here; mutating verbs (create/delete/heartbeat/ + // complete) are not user-facing yet and stay in the auto-generated + // `cmd/workspace/bundle` tree (which is filtered out of top-level + // registration in cmd/cmd.go). + dms := metadataServiceCommands() + + // The DAB `deployment` group already exists for bind/unbind/migrate. + // Augment it additively with the DMS read-side verbs. + deploymentCmd := deployment.NewDeploymentCommand() + deploymentCmd.AddCommand(renameTo(dms["get-deployment"], "get")) + deploymentCmd.AddCommand(renameTo(dms["list-deployments"], "list")) + cmd.AddCommand(deploymentCmd) + + versionCmd := &cobra.Command{ + Use: "version", + Short: "Read version records in the bundle metadata service.", + } + versionCmd.AddCommand(renameTo(dms["get-version"], "get")) + versionCmd.AddCommand(renameTo(dms["list-versions"], "list")) + cmd.AddCommand(versionCmd) + + resourceCmd := &cobra.Command{ + Use: "resource", + Short: "Read resource records from the bundle metadata service.", + } + resourceCmd.AddCommand(renameTo(dms["get-resource"], "get")) + resourceCmd.AddCommand(renameTo(dms["list-resources"], "list")) + cmd.AddCommand(resourceCmd) + + operationCmd := &cobra.Command{ + Use: "operation", + Short: "Read operation records in the bundle metadata service.", + } + operationCmd.AddCommand(renameTo(dms["get-operation"], "get")) + operationCmd.AddCommand(renameTo(dms["list-operations"], "list")) + cmd.AddCommand(operationCmd) + return cmd } diff --git a/cmd/bundle/metadata_service.go b/cmd/bundle/metadata_service.go new file mode 100644 index 00000000000..80836e7cf3c --- /dev/null +++ b/cmd/bundle/metadata_service.go @@ -0,0 +1,42 @@ +package bundle + +import ( + "strings" + + workspacebundle "github.com/databricks/cli/cmd/workspace/bundle" + "github.com/spf13/cobra" +) + +// metadataServiceCommands returns the auto-generated workspace bundle service +// commands keyed by their original cobra Name (e.g. "get-deployment"). +// +// The auto-generated `databricks bundle ` namespace collides with the +// DAB `bundle` command tree; cmd/cmd.go filters the workspace bundle root out +// of top-level registration. Here we call into the workspace package once, +// detach each subcommand from its (discarded) parent, and let the DAB bundle +// re-attach them under proper sub-groups with shorter names. +func metadataServiceCommands() map[string]*cobra.Command { + ws := workspacebundle.New() + subs := ws.Commands() + out := make(map[string]*cobra.Command, len(subs)) + for _, sub := range subs { + ws.RemoveCommand(sub) + // These ride under the DAB bundle now, which is visible. + sub.Hidden = false + out[sub.Name()] = sub + } + return out +} + +// renameTo replaces the first whitespace-separated token of cobra's Use field +// with newName, preserving the trailing positional-arg syntax that cobra renders +// in usage strings (e.g. "get-deployment NAME" -> "get NAME"). Returns the +// command for inline chaining. +func renameTo(c *cobra.Command, newName string) *cobra.Command { + rest := "" + if i := strings.IndexByte(c.Use, ' '); i >= 0 { + rest = c.Use[i:] + } + c.Use = newName + rest + return c +}