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
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
bundle:
name: test-bundle

workspace:
host: https://custom.test
workspace_id: "5678"

targets:
inherited:
default: true
target_query_id:
workspace:
host: https://custom.test/?o=1234
target_workspace_id:
workspace:
workspace_id: "9012"
null_target:
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cloud = false
EnvMatrix.DMS = ["", "true"]
33 changes: 33 additions & 0 deletions acceptance/bundle/debug/list-targets-root-workspace/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

>>> [CLI] bundle debug list-targets
inherited (default) https://custom.test workspace_id:5678
null_target https://custom.test workspace_id:5678
target_query_id https://custom.test workspace_id:5678
target_workspace_id https://custom.test workspace_id:9012

>>> [CLI] bundle debug list-targets --output json
{
"targets": [
{
"name": "inherited",
"default": true,
"host": "https://custom.test",
"workspace_id": "5678"
},
{
"name": "null_target",
"host": "https://custom.test",
"workspace_id": "5678"
},
{
"name": "target_query_id",
"host": "https://custom.test",
"workspace_id": "5678"
},
{
"name": "target_workspace_id",
"host": "https://custom.test",
"workspace_id": "9012"
}
]
}
2 changes: 2 additions & 0 deletions acceptance/bundle/debug/list-targets-root-workspace/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
trace $CLI bundle debug list-targets
trace $CLI bundle debug list-targets --output json
11 changes: 11 additions & 0 deletions acceptance/bundle/debug/list-targets/databricks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ targets:
mode: production
workspace:
host: https://prod.example.com
custom_host_query_id:
workspace:
host: https://custom.test/?o=1234
custom_host_explicit_id:
workspace:
host: https://custom.test
workspace_id: 5678
custom_host_explicit_id_over_query:
workspace:
host: https://custom.test/?o=1234
workspace_id: "5678"
uses_terraform:
bundle:
engine: terraform
Expand Down
18 changes: 18 additions & 0 deletions acceptance/bundle/debug/list-targets/output.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@

>>> [CLI] bundle debug list-targets
custom_host_explicit_id https://custom.test workspace_id:5678
custom_host_explicit_id_over_query https://custom.test workspace_id:5678
custom_host_query_id https://custom.test workspace_id:1234
dev (default) development https://dev.example.com
prod production https://prod.example.com
staging
Expand All @@ -10,6 +13,21 @@ with_vars ${var.target_mode} ${var.target_host}
>>> [CLI] bundle debug list-targets --output json
{
"targets": [
{
"name": "custom_host_explicit_id",
"host": "https://custom.test",
"workspace_id": "5678"
},
{
"name": "custom_host_explicit_id_over_query",
"host": "https://custom.test",
"workspace_id": "5678"
},
{
"name": "custom_host_query_id",
"host": "https://custom.test",
"workspace_id": "1234"
},
{
"name": "dev",
"default": true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
bundle:
name: strict-profile-match

include:
- scripts.yml

workspace:
workspace_id: "$WORKSPACE_ID"

targets:
inherited_workspace_id:
default: true
workspace:
host: $CUSTOM_HOST/?o=2222222222
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cloud = false
EnvMatrix.DMS = ["", "true"]
16 changes: 16 additions & 0 deletions acceptance/bundle/strict_profile_match/list_targets/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

=== list-targets reports the inherited workspace ID
>>> [CLI] bundle debug list-targets -o json
{
"targets": [
{
"name": "inherited_workspace_id",
"default": true,
"host": "[CUSTOM_HOST]",
"workspace_id": "[WORKSPACE_ID]"
}
]
}
=== Authentication uses the same workspace ID
>>> errcode [CLI] bundle run -t inherited_workspace_id show_auth
profile=workspace_custom_host host=[CUSTOM_HOST] workspace_id=[WORKSPACE_ID]
7 changes: 7 additions & 0 deletions acceptance/bundle/strict_profile_match/list_targets/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# The top-level workspace_id takes precedence over ?o= in the target's host, so
# list-targets must report the workspace ID that authentication uses.
title "list-targets reports the inherited workspace ID"
trace $CLI bundle debug list-targets -o json

title "Authentication uses the same workspace ID"
trace errcode $CLI bundle run -t inherited_workspace_id show_auth
22 changes: 22 additions & 0 deletions bundle/config/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,28 @@ func mergeField(rv, ov dyn.Value, name string) (dyn.Value, error) {
return dyn.SetByPath(rv, path, out)
}

// TargetWorkspace returns the workspace settings of the named target as
// [Root.MergeTargetOverrides] merges them, without modifying the root.
func (r *Root) TargetWorkspace(name string) (Workspace, error) {
target, err := dyn.GetByPath(r.value, dyn.NewPath(dyn.Key("targets"), dyn.Key(name)))
if err != nil {
return Workspace{}, err
}
merged, err := mergeField(r.value, target, "workspace")
if err != nil {
return Workspace{}, fmt.Errorf("failed to merge target=%s field=workspace: %w", name, err)
}

var w Workspace
// Neither the root nor the target sets a workspace section.
v := merged.Get("workspace")
if !v.IsValid() {
return w, nil
}
err = convert.ToTyped(&w, v)
return w, err
}

func (r *Root) MergeTargetOverrides(name string) error {
root := r.value
target, err := dyn.GetByPath(root, dyn.NewPath(dyn.Key("targets"), dyn.Key(name)))
Expand Down
53 changes: 35 additions & 18 deletions cmd/bundle/debug/list_targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ import (
)

type targetInfo struct {
Name string `json:"name"`
Default bool `json:"default,omitempty"`
Mode config.Mode `json:"mode,omitempty"`
Host string `json:"host,omitempty"`
Name string `json:"name"`
Default bool `json:"default,omitempty"`
Mode config.Mode `json:"mode,omitempty"`
Host string `json:"host,omitempty"`
WorkspaceID string `json:"workspace_id,omitempty"`

// Engine is only reported for targets that use the removed Terraform engine.
Engine engine.EngineType `json:"engine,omitempty"`
Expand All @@ -34,35 +35,45 @@ type listTargetsOutput struct {
}

// collectTargets returns the targets sorted by name. The engine of a target is
// its own bundle.engine if set, otherwise the top-level bundle.engine.
func collectTargets(targets map[string]*config.Target, rootEngine engine.EngineType) []targetInfo {
// its own bundle.engine if set, otherwise the top-level bundle.engine. The host
// and workspace ID come from the target's workspace merged over the top-level
// one, normalized the same way authentication normalizes them.
func collectTargets(cfg *config.Root) ([]targetInfo, error) {
targets := cfg.Targets
rootEngine := cfg.Bundle.Engine
names := slices.Sorted(maps.Keys(targets))

result := make([]targetInfo, 0, len(names))
for _, name := range names {
w, err := cfg.TargetWorkspace(name)
if err != nil {
return nil, err
}
w.NormalizeHostURL()
info := targetInfo{
Name: name,
Host: w.Host,
WorkspaceID: w.WorkspaceID,
}

t := targets[name]
// YAML decoding can leave a nil entry in the map when a target is
// declared with a null value. Skip rather than dereference and panic.
if t == nil {
result = append(result, targetInfo{Name: name, Engine: terraformOnly(rootEngine)})
info.Engine = terraformOnly(rootEngine)
result = append(result, info)
continue
}
info := targetInfo{
Name: name,
Default: t.Default,
Mode: t.Mode,
}
if t.Workspace != nil {
info.Host = t.Workspace.Host
}
info.Default = t.Default
info.Mode = t.Mode
targetEngine := rootEngine
if t.Bundle != nil && t.Bundle.Engine != engine.EngineNotSet {
targetEngine = t.Bundle.Engine
}
info.Engine = terraformOnly(targetEngine)
result = append(result, info)
}
return result
return result, nil
}

func terraformOnly(e engine.EngineType) engine.EngineType {
Expand All @@ -73,7 +84,7 @@ func terraformOnly(e engine.EngineType) engine.EngineType {
}

// NewListTargetsCommand returns a command that lists all bundle targets
// with their name, default, mode, workspace host, and (if terraform) engine fields.
// with their name, default, mode, workspace host and ID, and (if terraform) engine fields.
func NewListTargetsCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "list-targets",
Expand All @@ -97,7 +108,10 @@ func NewListTargetsCommand() *cobra.Command {
return root.ErrAlreadyPrinted
}

targets := collectTargets(b.Config.Targets, b.Config.Bundle.Engine)
targets, err := collectTargets(&b.Config)
if err != nil {
return err
}

switch root.OutputType(cmd) {
case flags.OutputText:
Expand All @@ -112,6 +126,9 @@ func NewListTargetsCommand() *cobra.Command {
if t.Host != "" {
parts = append(parts, t.Host)
}
if t.WorkspaceID != "" {
parts = append(parts, "workspace_id:"+t.WorkspaceID)
}
if t.Engine != "" {
parts = append(parts, "engine:"+string(t.Engine))
}
Expand Down
Loading