Skip to content

Commit 360b53a

Browse files
authored
fix: convert duplicate YAML merge key panic to diagnostic error (#5188)
Better error for #5182
1 parent 38eb06e commit 360b53a

6 files changed

Lines changed: 77 additions & 1 deletion

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
bundle:
2+
name: test-bundle
3+
4+
definitions:
5+
cluster1: &cluster1
6+
num_workers: 1
7+
cluster2: &cluster2
8+
spark_version: "13.3.x-scala2.12"
9+
10+
resources:
11+
jobs:
12+
my_job:
13+
name: "test job"
14+
tasks:
15+
- task_key: "main"
16+
new_cluster:
17+
<<: *cluster1
18+
<<: *cluster2
19+
notebook_task:
20+
notebook_path: "/notebook"

acceptance/bundle/validate/duplicate_yaml_merge_key/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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
>>> [CLI] bundle validate
3+
Error: duplicate YAML merge key ('<<') is not allowed; to merge multiple maps, use a sequence: '<<: [*anchor1, *anchor2]'
4+
in databricks.yml:18:13
5+
6+
7+
Found 1 error
8+
9+
>>> [CLI] bundle validate
10+
Name: test-bundle
11+
Target: default
12+
Workspace:
13+
User: [USERNAME]
14+
Path: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default
15+
16+
Validation OK!
17+
{
18+
"num_workers": 1,
19+
"spark_version": "13.3.x-scala2.12"
20+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
musterr trace $CLI bundle validate
2+
3+
update_file.py databricks.yml " <<: *cluster1
4+
<<: *cluster2" " <<: [*cluster1, *cluster2]"
5+
6+
trace $CLI bundle validate
7+
8+
$CLI bundle validate -o json | jq '.resources.jobs.my_job.tasks[0].new_cluster'

bundle/config/root.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package config
33
import (
44
"bytes"
55
"context"
6+
"errors"
67
"fmt"
78
"os"
89
"reflect"
@@ -106,6 +107,14 @@ func LoadFromBytes(path string, raw []byte) (*Root, diag.Diagnostics) {
106107
// Load configuration tree from YAML.
107108
v, err := yamlloader.LoadYAML(path, bytes.NewBuffer(raw))
108109
if err != nil {
110+
var le *yamlloader.LocationError
111+
if errors.As(err, &le) {
112+
return nil, diag.Diagnostics{{
113+
Severity: diag.Error,
114+
Summary: le.Summary,
115+
Locations: []dyn.Location{le.Loc},
116+
}}
117+
}
109118
return nil, diag.Errorf("failed to load %s: %v", path, err)
110119
}
111120

libs/dyn/yamlloader/loader.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ import (
1010
"go.yaml.in/yaml/v3"
1111
)
1212

13+
// LocationError is an error with a YAML source location that can be displayed
14+
// to the user with a file path, line, and column number.
15+
type LocationError struct {
16+
Loc dyn.Location
17+
Summary string
18+
}
19+
20+
func (e *LocationError) Error() string {
21+
return fmt.Sprintf("yaml (%s): %s", e.Loc, e.Summary)
22+
}
23+
1324
type loader struct {
1425
path string
1526
}
@@ -110,7 +121,12 @@ func (d *loader) loadMapping(node *yaml.Node, loc dyn.Location) (dyn.Value, erro
110121
// However, when used as a key, it is treated as the string "null".
111122
case "!!merge":
112123
if merge != nil {
113-
panic("merge node already set")
124+
// The YAML merge key spec allows a single '<<' key per mapping.
125+
// To merge multiple maps, use a sequence: '<<: [*anchor1, *anchor2]'.
126+
return dyn.InvalidValue, &LocationError{
127+
Loc: d.location(key),
128+
Summary: "duplicate YAML merge key ('<<') is not allowed; to merge multiple maps, use a sequence: '<<: [*anchor1, *anchor2]'",
129+
}
114130
}
115131
merge = val
116132
continue

0 commit comments

Comments
 (0)