Skip to content

Commit 4aa26fa

Browse files
bundle: surface read-only DMS commands under DAB sub-groups (#5313)
Stacked on #5311 (the SDK v0.136 bump). Retarget to `main` once that lands. ## Why SDK v0.135 added a workspace-level `bundle` service (DMS). Its auto-generated CLI commands sit at the root `databricks bundle <verb>` and collide with the DAB `bundle` command tree, so PR #5311 filters them out of top-level registration. This PR brings the **read-side** commands back, grouped under the existing DAB `bundle` namespace. ## Layout | Group | Commands | |---|---|---| | `bundle deployment` | `get`, `list` -- additive next to existing `bind`, `unbind`, `migrate` | | `bundle version` | `get`, `list` | | `bundle resource` | `get`, `list` | | `bundle operation` | `get`, `list` | **Mutating verbs are intentionally out of scope** (create / delete / complete / heartbeat). They have no user-facing workflow yet; we'll add them when the DMS write-path becomes a documented feature. Until then they remain in the filtered-out `cmd/workspace/bundle` tree. ## Wiring The DAB `deployment` group is additive -- the new `get`/`list` verbs join the existing `bind`/`unbind`/`migrate` under one parent. The other three groups are brand new. Implementation lives in `cmd/bundle/metadata_service.go`: - `metadataServiceCommands()` calls `workspacebundle.New()` once, detaches every subcommand from the discarded workspace root, and returns them in a map keyed by their original cobra `Name` (e.g. `\"get-deployment\"`). - `renameTo(c, newName)` rewrites the first whitespace-separated token of cobra's `Use` field while preserving the trailing positional-arg syntax. So `\"get-deployment NAME\"` becomes `\"get NAME\"` and cobra still renders the usage string correctly. `cmd/bundle/bundle.go` pulls only the four read-side entries (`get-deployment`, `list-deployments`, `get-version`, `list-versions`, `get-resource`, `list-resources`, `get-operation`, `list-operations`) out of the map and attaches them to the right parent. The workspace `bundle` filter in `cmd/cmd.go` stays in place, so the mutating verbs do not leak to the root. ## Test plan - [x] `go build ./...` - [x] `go test ./cmd/... ./bundle/...` (all green) - [x] `go vet ./...` clean - [x] Manual: `databricks bundle {deployment,version,resource,operation} --help` show the expected commands + alias pair - [x] `databricks bundle deployments get --help` (plural alias) routes correctly - [x] `databricks bundle debug refschema --help` unaffected - [ ] CI on this PR
1 parent 00f5edc commit 4aa26fa

6 files changed

Lines changed: 303 additions & 1 deletion

File tree

acceptance/cmd/bundle/dms-read-only/out.test.toml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
>>> [CLI] bundle deployment list
3+
[
4+
{
5+
"display_name": "first deployment",
6+
"name": "deployments/abc",
7+
"status": "DEPLOYMENT_STATUS_ACTIVE",
8+
"target_name": "dev"
9+
},
10+
{
11+
"display_name": "second deployment",
12+
"name": "deployments/def",
13+
"status": "DEPLOYMENT_STATUS_ACTIVE",
14+
"target_name": "prod"
15+
}
16+
]
17+
18+
>>> [CLI] bundle deployment get deployments/abc
19+
{
20+
"display_name": "first deployment",
21+
"last_version_id": "v1",
22+
"name": "deployments/abc",
23+
"status": "DEPLOYMENT_STATUS_ACTIVE",
24+
"target_name": "dev"
25+
}
26+
27+
>>> [CLI] bundle version list deployments/abc
28+
[
29+
{
30+
"cli_version": "[DEV_VERSION]",
31+
"name": "deployments/abc/versions/v1",
32+
"status": "VERSION_STATUS_COMPLETED",
33+
"version_type": ""
34+
}
35+
]
36+
37+
>>> [CLI] bundle version get deployments/abc/versions/v1
38+
{
39+
"cli_version": "[DEV_VERSION]",
40+
"name": "deployments/abc/versions/v1",
41+
"status": "VERSION_STATUS_COMPLETED",
42+
"version_type": ""
43+
}
44+
45+
>>> [CLI] bundle resource list deployments/abc
46+
[
47+
{
48+
"last_action_type": "OPERATION_ACTION_TYPE_CREATE",
49+
"last_version_id": "v1",
50+
"name": "deployments/abc/resources/my_job",
51+
"resource_id": "12345",
52+
"resource_type": "DEPLOYMENT_RESOURCE_TYPE_JOB"
53+
}
54+
]
55+
56+
>>> [CLI] bundle resource get deployments/abc/resources/my_job
57+
{
58+
"last_action_type": "OPERATION_ACTION_TYPE_CREATE",
59+
"last_version_id": "v1",
60+
"name": "deployments/abc/resources/my_job",
61+
"resource_id": "12345",
62+
"resource_type": "DEPLOYMENT_RESOURCE_TYPE_JOB"
63+
}
64+
65+
>>> [CLI] bundle operation list deployments/abc/versions/v1
66+
[
67+
{
68+
"action_type": "OPERATION_ACTION_TYPE_CREATE",
69+
"name": "deployments/abc/versions/v1/operations/my_job",
70+
"resource_id": "12345",
71+
"status": "OPERATION_STATUS_SUCCEEDED"
72+
}
73+
]
74+
75+
>>> [CLI] bundle operation get deployments/abc/versions/v1/operations/my_job
76+
{
77+
"action_type": "OPERATION_ACTION_TYPE_CREATE",
78+
"name": "deployments/abc/versions/v1/operations/my_job",
79+
"resource_id": "12345",
80+
"status": "OPERATION_STATUS_SUCCEEDED"
81+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trace $CLI bundle deployment list
2+
trace $CLI bundle deployment get deployments/abc
3+
trace $CLI bundle version list deployments/abc
4+
trace $CLI bundle version get deployments/abc/versions/v1
5+
trace $CLI bundle resource list deployments/abc
6+
trace $CLI bundle resource get deployments/abc/resources/my_job
7+
trace $CLI bundle operation list deployments/abc/versions/v1
8+
trace $CLI bundle operation get deployments/abc/versions/v1/operations/my_job
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Local-only acceptance test for the read-only DMS commands under
2+
# `databricks bundle {deployment,version,resource,operation}`. The DMS APIs
3+
# aren't on test workspaces yet, so we stub the eight read endpoints with
4+
# fixed response bodies and assert the CLI renders them as expected.
5+
Local = true
6+
Cloud = false
7+
8+
[[Server]]
9+
Pattern = "GET /api/2.0/bundle/deployments"
10+
Response.Body = '''
11+
{
12+
"deployments": [
13+
{
14+
"name": "deployments/abc",
15+
"display_name": "first deployment",
16+
"target_name": "dev",
17+
"status": "DEPLOYMENT_STATUS_ACTIVE"
18+
},
19+
{
20+
"name": "deployments/def",
21+
"display_name": "second deployment",
22+
"target_name": "prod",
23+
"status": "DEPLOYMENT_STATUS_ACTIVE"
24+
}
25+
]
26+
}
27+
'''
28+
29+
[[Server]]
30+
Pattern = "GET /api/2.0/bundle/deployments/abc"
31+
Response.Body = '''
32+
{
33+
"name": "deployments/abc",
34+
"display_name": "first deployment",
35+
"target_name": "dev",
36+
"status": "DEPLOYMENT_STATUS_ACTIVE",
37+
"last_version_id": "v1"
38+
}
39+
'''
40+
41+
[[Server]]
42+
Pattern = "GET /api/2.0/bundle/deployments/abc/versions"
43+
Response.Body = '''
44+
{
45+
"versions": [
46+
{
47+
"name": "deployments/abc/versions/v1",
48+
"cli_version": "0.0.0-dev",
49+
"status": "VERSION_STATUS_COMPLETED"
50+
}
51+
]
52+
}
53+
'''
54+
55+
[[Server]]
56+
Pattern = "GET /api/2.0/bundle/deployments/abc/versions/v1"
57+
Response.Body = '''
58+
{
59+
"name": "deployments/abc/versions/v1",
60+
"cli_version": "0.0.0-dev",
61+
"status": "VERSION_STATUS_COMPLETED"
62+
}
63+
'''
64+
65+
[[Server]]
66+
Pattern = "GET /api/2.0/bundle/deployments/abc/resources"
67+
Response.Body = '''
68+
{
69+
"resources": [
70+
{
71+
"name": "deployments/abc/resources/my_job",
72+
"resource_id": "12345",
73+
"resource_type": "DEPLOYMENT_RESOURCE_TYPE_JOB",
74+
"last_version_id": "v1",
75+
"last_action_type": "OPERATION_ACTION_TYPE_CREATE"
76+
}
77+
]
78+
}
79+
'''
80+
81+
[[Server]]
82+
Pattern = "GET /api/2.0/bundle/deployments/abc/resources/my_job"
83+
Response.Body = '''
84+
{
85+
"name": "deployments/abc/resources/my_job",
86+
"resource_id": "12345",
87+
"resource_type": "DEPLOYMENT_RESOURCE_TYPE_JOB",
88+
"last_version_id": "v1",
89+
"last_action_type": "OPERATION_ACTION_TYPE_CREATE"
90+
}
91+
'''
92+
93+
[[Server]]
94+
Pattern = "GET /api/2.0/bundle/deployments/abc/versions/v1/operations"
95+
Response.Body = '''
96+
{
97+
"operations": [
98+
{
99+
"name": "deployments/abc/versions/v1/operations/my_job",
100+
"action_type": "OPERATION_ACTION_TYPE_CREATE",
101+
"resource_id": "12345",
102+
"status": "OPERATION_STATUS_SUCCEEDED"
103+
}
104+
]
105+
}
106+
'''
107+
108+
[[Server]]
109+
Pattern = "GET /api/2.0/bundle/deployments/abc/versions/v1/operations/my_job"
110+
Response.Body = '''
111+
{
112+
"name": "deployments/abc/versions/v1/operations/my_job",
113+
"action_type": "OPERATION_ACTION_TYPE_CREATE",
114+
"resource_id": "12345",
115+
"status": "OPERATION_STATUS_SUCCEEDED"
116+
}
117+
'''

cmd/bundle/bundle.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,62 @@ Online documentation: https://docs.databricks.com/en/dev-tools/bundles/index.htm
3636
cmd.AddCommand(newSummaryCommand())
3737
cmd.AddCommand(newGenerateCommand())
3838
cmd.AddCommand(newDebugCommand())
39-
cmd.AddCommand(deployment.NewDeploymentCommand())
4039
cmd.AddCommand(newOpenCommand())
4140
cmd.AddCommand(newPlanCommand())
4241
cmd.AddCommand(newConfigRemoteSyncCommand())
42+
43+
// Bundle Metadata Service (DMS) read-only command groups. Only `get`
44+
// and `list` are surfaced here; mutating verbs (create/delete/heartbeat/
45+
// complete) are not user-facing yet and stay in the auto-generated
46+
// `cmd/workspace/bundle` tree (which is filtered out of top-level
47+
// registration in cmd/cmd.go).
48+
//
49+
// Hide everything from help output for now: the DMS API surface isn't
50+
// documented as a user-facing CLI feature yet. Commands still route
51+
// through cobra so callers who know about them can invoke them; they
52+
// just don't show up in `bundle --help` / `bundle <group> --help`.
53+
dms := metadataServiceCommands()
54+
for _, c := range dms {
55+
c.Hidden = true
56+
}
57+
58+
// The DAB `deployment` group already exists for bind/unbind/migrate.
59+
// Augment it additively with the (hidden) DMS read-side verbs.
60+
deploymentCmd := deployment.NewDeploymentCommand()
61+
deploymentCmd.AddCommand(renameTo(dms["get-deployment"], "get"))
62+
deploymentCmd.AddCommand(renameTo(dms["list-deployments"], "list"))
63+
cmd.AddCommand(deploymentCmd)
64+
65+
// The three new groups are hidden too; cobra hides a parent when all
66+
// of its children are hidden, but we set the flag explicitly so the
67+
// group disappears from `bundle --help` even if a future child is
68+
// added without the hide flag.
69+
versionCmd := &cobra.Command{
70+
Use: "version",
71+
Short: "Read version records in the bundle metadata service.",
72+
Hidden: true,
73+
}
74+
versionCmd.AddCommand(renameTo(dms["get-version"], "get"))
75+
versionCmd.AddCommand(renameTo(dms["list-versions"], "list"))
76+
cmd.AddCommand(versionCmd)
77+
78+
resourceCmd := &cobra.Command{
79+
Use: "resource",
80+
Short: "Read resource records from the bundle metadata service.",
81+
Hidden: true,
82+
}
83+
resourceCmd.AddCommand(renameTo(dms["get-resource"], "get"))
84+
resourceCmd.AddCommand(renameTo(dms["list-resources"], "list"))
85+
cmd.AddCommand(resourceCmd)
86+
87+
operationCmd := &cobra.Command{
88+
Use: "operation",
89+
Short: "Read operation records in the bundle metadata service.",
90+
Hidden: true,
91+
}
92+
operationCmd.AddCommand(renameTo(dms["get-operation"], "get"))
93+
operationCmd.AddCommand(renameTo(dms["list-operations"], "list"))
94+
cmd.AddCommand(operationCmd)
95+
4396
return cmd
4497
}

cmd/bundle/metadata_service.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package bundle
2+
3+
import (
4+
"strings"
5+
6+
workspacebundle "github.com/databricks/cli/cmd/workspace/bundle"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
// metadataServiceCommands returns the auto-generated workspace bundle service
11+
// commands keyed by their original cobra Name (e.g. "get-deployment").
12+
//
13+
// The auto-generated `databricks bundle <verb>` namespace collides with the
14+
// DAB `bundle` command tree; cmd/cmd.go filters the workspace bundle root out
15+
// of top-level registration. Here we call into the workspace package once,
16+
// detach each subcommand from its (discarded) parent, and let the DAB bundle
17+
// re-attach them under proper sub-groups with shorter names.
18+
func metadataServiceCommands() map[string]*cobra.Command {
19+
ws := workspacebundle.New()
20+
subs := ws.Commands()
21+
out := make(map[string]*cobra.Command, len(subs))
22+
for _, sub := range subs {
23+
ws.RemoveCommand(sub)
24+
out[sub.Name()] = sub
25+
}
26+
return out
27+
}
28+
29+
// renameTo replaces the first whitespace-separated token of cobra's Use field
30+
// with newName, preserving the trailing positional-arg syntax that cobra renders
31+
// in usage strings (e.g. "get-deployment NAME" -> "get NAME"). Returns the
32+
// command for inline chaining.
33+
func renameTo(c *cobra.Command, newName string) *cobra.Command {
34+
rest := ""
35+
if i := strings.IndexByte(c.Use, ' '); i >= 0 {
36+
rest = c.Use[i:]
37+
}
38+
c.Use = newName + rest
39+
return c
40+
}

0 commit comments

Comments
 (0)