Skip to content
Merged
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
34 changes: 34 additions & 0 deletions pkg/cli/codemod_pull_request_target_checkout_false.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ func getPullRequestTargetCheckoutFalseCodemod() Codemod {
return content, false, nil
}

if isCheckoutMapping(frontmatter) {
pullRequestTargetCheckoutFalseCodemodLog.Print("Skipping pull_request_target checkout codemod: checkout is already a mapping with sub-keys")
return content, false, nil
}

if hasExplicitCheckoutCommands(content) {
pullRequestTargetCheckoutFalseCodemodLog.Print("Skipping pull_request_target checkout codemod: explicit checkout command detected")
return content, false, nil
Expand Down Expand Up @@ -81,6 +86,19 @@ func isPullRequestTargetCheckoutDisabled(frontmatter map[string]any) bool {
return ok && !checkoutDisabled
}

// isCheckoutMapping returns true when the frontmatter "checkout" key is a YAML
// mapping (e.g. sparse-checkout:, fetch-depth:) rather than a scalar or absent.
// Overwriting a mapping with a scalar would orphan the child keys and produce
// invalid YAML, so callers should skip the codemod in this case.
func isCheckoutMapping(frontmatter map[string]any) bool {
checkoutAny, hasCheckout := frontmatter["checkout"]
if !hasCheckout {
return false
}
_, isMap := checkoutAny.(map[string]any)
return isMap
}

func hasExplicitCheckoutCommands(content string) bool {
lowerContent := strings.ToLower(content)

Expand Down Expand Up @@ -113,6 +131,22 @@ func ensureCheckoutFalseForPullRequestTarget(lines []string) ([]string, bool) {
}

if strings.HasPrefix(trimmed, "checkout:") {
// If the checkout line has no inline value, the next indented line
// would make this a YAML mapping block. Replacing it with a scalar
// would orphan those child keys and produce invalid YAML.
inlineValue := strings.TrimSpace(strings.TrimPrefix(trimmed, "checkout:"))
if inlineValue == "" {
for j := i + 1; j < len(lines); j++ {
next := lines[j]
if strings.TrimSpace(next) == "" {
continue
}
if len(next) > 0 && (next[0] == ' ' || next[0] == '\t') {
return lines, false
}
break
}
}
checkoutLine, modified := normalizeCheckoutFalseLine(line)
if !modified {
return lines, false
Expand Down
26 changes: 26 additions & 0 deletions pkg/cli/codemod_pull_request_target_checkout_false_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,30 @@ strict: false
assert.False(t, applied, "codemod should not apply when strict is false")
assert.Equal(t, content, result, "content should remain unchanged")
})

t.Run("does not modify when checkout is a mapping with sub-keys", func(t *testing.T) {
content := `---
description: "Review Azure SDK management-plane PRs"
on:
pull_request_target:
checkout:
sparse-checkout: |
.github
inlined-imports: true
---
`
frontmatter := map[string]any{
"on": map[string]any{
"pull_request_target": map[string]any{},
},
"checkout": map[string]any{
"sparse-checkout": ".github\n",
},
}

result, applied, err := codemod.Apply(content, frontmatter)
require.NoError(t, err, "codemod should not return an error")
assert.False(t, applied, "codemod should not apply when checkout is a mapping")
assert.Equal(t, content, result, "content should remain unchanged and not corrupt the mapping")
})
}
Loading