Skip to content

Commit 1d7221a

Browse files
committed
release: add defensive error messages for YAML structure validation
1 parent 43be0d6 commit 1d7221a

File tree

1 file changed

+44
-34
lines changed

1 file changed

+44
-34
lines changed

pkg/cmd/release/update_workflow.go

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,20 @@ func addBranchToWorkflow(branch string) error {
188188
}
189189

190190
// findBranchNode navigates the YAML tree to find the branch array node.
191+
//
192+
// IMPORTANT: This function expects the workflow YAML to have the following structure:
193+
//
194+
// jobs:
195+
// update-crdb-releases-yaml:
196+
// strategy:
197+
// matrix:
198+
// branch:
199+
// - "master"
200+
// - "release-X.Y"
201+
//
202+
// If the workflow structure changes (job name, nesting, etc.), this function will
203+
// return an error. Update the expectedPath below if the structure needs to change.
191204
func findBranchNode(root *yaml.Node) (*yaml.Node, error) {
192-
// Navigate: root -> jobs (map key) -> jobs (map value) ->
193-
// update-crdb-releases-yaml (key) -> update-crdb-releases-yaml (value) ->
194-
// strategy (key) -> strategy (value) -> matrix (key) -> matrix (value) ->
195-
// branch (key) -> branch (value - sequence)
196-
197205
if root.Kind != yaml.DocumentNode || len(root.Content) == 0 {
198206
return nil, fmt.Errorf("invalid YAML structure: expected document node")
199207
}
@@ -203,43 +211,45 @@ func findBranchNode(root *yaml.Node) (*yaml.Node, error) {
203211
return nil, fmt.Errorf("invalid YAML structure: expected mapping at top level")
204212
}
205213

206-
// Find "jobs" key
207-
jobsNode := findMapValue(topMap, "jobs")
208-
if jobsNode == nil {
209-
return nil, fmt.Errorf("'jobs' key not found in workflow")
210-
}
211-
212-
// Find "update-crdb-releases-yaml" key
213-
jobNode := findMapValue(jobsNode, "update-crdb-releases-yaml")
214-
if jobNode == nil {
215-
return nil, fmt.Errorf("'update-crdb-releases-yaml' job not found")
216-
}
217-
218-
// Find "strategy" key
219-
strategyNode := findMapValue(jobNode, "strategy")
220-
if strategyNode == nil {
221-
return nil, fmt.Errorf("'strategy' key not found in job")
222-
}
223-
224-
// Find "matrix" key
225-
matrixNode := findMapValue(strategyNode, "matrix")
226-
if matrixNode == nil {
227-
return nil, fmt.Errorf("'matrix' key not found in strategy")
228-
}
229-
230-
// Find "branch" key
231-
branchNode := findMapValue(matrixNode, "branch")
232-
if branchNode == nil {
233-
return nil, fmt.Errorf("'branch' key not found in matrix")
214+
// Navigate to jobs.update-crdb-releases-yaml.strategy.matrix.branch
215+
// If this path changes in the workflow file, update it here and in the comment above.
216+
expectedPath := []string{"jobs", "update-crdb-releases-yaml", "strategy", "matrix", "branch"}
217+
branchNode, err := navigateYAMLPath(topMap, expectedPath)
218+
if err != nil {
219+
return nil, fmt.Errorf("workflow structure does not match expected format.\n"+
220+
"Expected path: %s\n"+
221+
"Error: %w\n\n"+
222+
"If the workflow file structure has changed, update the expectedPath in findBranchNode()",
223+
strings.Join(expectedPath, " -> "), err)
234224
}
235225

236226
if branchNode.Kind != yaml.SequenceNode {
237-
return nil, fmt.Errorf("'branch' value is not a sequence")
227+
return nil, fmt.Errorf("expected 'branch' to be a sequence (array), but found %v.\n"+
228+
"The workflow file structure may have changed. Update the code in findBranchNode() if needed",
229+
branchNode.Kind)
238230
}
239231

240232
return branchNode, nil
241233
}
242234

235+
// navigateYAMLPath navigates through a sequence of keys in a YAML mapping structure.
236+
func navigateYAMLPath(start *yaml.Node, path []string) (*yaml.Node, error) {
237+
current := start
238+
for i, key := range path {
239+
next := findMapValue(current, key)
240+
if next == nil {
241+
// Provide context about where in the path we failed
242+
completedPath := strings.Join(path[:i], " -> ")
243+
if completedPath != "" {
244+
completedPath += " -> "
245+
}
246+
return nil, fmt.Errorf("key '%s' not found after navigating: %s", key, completedPath+"[HERE]")
247+
}
248+
current = next
249+
}
250+
return current, nil
251+
}
252+
243253
// findMapValue finds a value in a mapping node by key.
244254
func findMapValue(mapNode *yaml.Node, key string) *yaml.Node {
245255
if mapNode.Kind != yaml.MappingNode {

0 commit comments

Comments
 (0)