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
4 changes: 2 additions & 2 deletions .github/workflows/ai-moderator.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .github/workflows/campaign-generator.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .github/workflows/workflow-generator.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 29 additions & 12 deletions pkg/workflow/frontmatter_extraction.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (c *Compiler) extractTopLevelYAMLSection(frontmatter map[string]any, key st
return yamlStr
}

// commentOutProcessedFieldsInOnSection comments out draft, fork, forks, names, manual-approval, stop-after, skip-if-match, and reaction fields in the on section
// commentOutProcessedFieldsInOnSection comments out draft, fork, forks, names, manual-approval, stop-after, skip-if-match, reaction, and lock-for-agent fields in the on section
// These fields are processed separately and should be commented for documentation
// Exception: names fields in sections with __gh_aw_native_label_filter__ marker in frontmatter are NOT commented out
func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmatter map[string]any) string {
Expand All @@ -135,7 +135,7 @@ func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmat
nativeLabelFilterSections := make(map[string]bool)
if onValue, exists := frontmatter["on"]; exists {
if onMap, ok := onValue.(map[string]any); ok {
for _, sectionKey := range []string{"issues", "pull_request", "discussion"} {
for _, sectionKey := range []string{"issues", "pull_request", "discussion", "issue_comment"} {
if sectionValue, hasSec := onMap[sectionKey]; hasSec {
if sectionMap, ok := sectionValue.(map[string]any); ok {
if marker, hasMarker := sectionMap["__gh_aw_native_label_filter__"]; hasMarker {
Expand All @@ -155,16 +155,18 @@ func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmat
inPullRequest := false
inIssues := false
inDiscussion := false
inIssueComment := false
inForksArray := false
inSkipIfMatch := false
currentSection := "" // Track which section we're in ("issues", "pull_request", or "discussion")
currentSection := "" // Track which section we're in ("issues", "pull_request", "discussion", or "issue_comment")

for _, line := range lines {
// Check if we're entering a pull_request, issues, or discussion section
// Check if we're entering a pull_request, issues, discussion, or issue_comment section
if strings.Contains(line, "pull_request:") {
inPullRequest = true
inIssues = false
inDiscussion = false
inIssueComment = false
currentSection = "pull_request"
result = append(result, line)
continue
Expand All @@ -173,6 +175,7 @@ func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmat
inIssues = true
inPullRequest = false
inDiscussion = false
inIssueComment = false
currentSection = "issues"
result = append(result, line)
continue
Expand All @@ -181,18 +184,29 @@ func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmat
inDiscussion = true
inPullRequest = false
inIssues = false
inIssueComment = false
currentSection = "discussion"
result = append(result, line)
continue
}
if strings.Contains(line, "issue_comment:") {
inIssueComment = true
inPullRequest = false
inIssues = false
inDiscussion = false
currentSection = "issue_comment"
result = append(result, line)
continue
}

// Check if we're leaving the pull_request, issues, or discussion section (new top-level key or end of indent)
if inPullRequest || inIssues || inDiscussion {
// Check if we're leaving the pull_request, issues, discussion, or issue_comment section (new top-level key or end of indent)
if inPullRequest || inIssues || inDiscussion || inIssueComment {
// If line is not indented or is a new top-level key, we're out of the section
if strings.TrimSpace(line) != "" && !strings.HasPrefix(line, " ") && !strings.HasPrefix(line, "\t") {
inPullRequest = false
inIssues = false
inDiscussion = false
inIssueComment = false
inForksArray = false
currentSection = ""
}
Expand All @@ -201,7 +215,7 @@ func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmat
trimmedLine := strings.TrimSpace(line)

// Skip marker lines in the YAML output
if (inPullRequest || inIssues || inDiscussion) && strings.Contains(trimmedLine, "__gh_aw_native_label_filter__:") {
if (inPullRequest || inIssues || inDiscussion || inIssueComment) && strings.Contains(trimmedLine, "__gh_aw_native_label_filter__:") {
// Don't include the marker line in the output
continue
}
Expand All @@ -212,7 +226,7 @@ func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmat
}

// Check if we're entering skip-if-match object
if !inPullRequest && !inIssues && !inSkipIfMatch {
if !inPullRequest && !inIssues && !inDiscussion && !inIssueComment && !inSkipIfMatch {
// Check both uncommented and commented forms
if (strings.HasPrefix(trimmedLine, "skip-if-match:") && trimmedLine == "skip-if-match:") ||
(strings.HasPrefix(trimmedLine, "# skip-if-match:") && strings.Contains(trimmedLine, "pre-activation job")) {
Expand Down Expand Up @@ -248,8 +262,8 @@ func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmat
shouldComment := false
var commentReason string

// Check for top-level fields that should be commented out (not inside pull_request or issues)
if !inPullRequest && !inIssues {
// Check for top-level fields that should be commented out (not inside pull_request, issues, discussion, or issue_comment)
if !inPullRequest && !inIssues && !inDiscussion && !inIssueComment {
if strings.HasPrefix(trimmedLine, "manual-approval:") {
shouldComment = true
commentReason = " # Manual approval processed as environment field in activation job"
Expand Down Expand Up @@ -278,13 +292,16 @@ func (c *Compiler) commentOutProcessedFieldsInOnSection(yamlStr string, frontmat
} else if inForksArray && strings.HasPrefix(trimmedLine, "-") {
shouldComment = true
commentReason = " # Fork filtering applied via job conditions"
} else if (inPullRequest || inIssues || inDiscussion) && strings.HasPrefix(trimmedLine, "names:") {
} else if (inPullRequest || inIssues || inDiscussion || inIssueComment) && strings.HasPrefix(trimmedLine, "lock-for-agent:") {
shouldComment = true
commentReason = " # Lock-for-agent processed as issue locking in activation job"
} else if (inPullRequest || inIssues || inDiscussion || inIssueComment) && strings.HasPrefix(trimmedLine, "names:") {
// Only comment out names if NOT using native label filtering for this section
if !nativeLabelFilterSections[currentSection] {
shouldComment = true
commentReason = " # Label filtering applied via job conditions"
}
} else if (inPullRequest || inIssues || inDiscussion) && line != "" {
} else if (inPullRequest || inIssues || inDiscussion || inIssueComment) && line != "" {
// Check if we're in a names array (after "names:" line)
// Look back to see if the previous uncommented line was "names:"
// Only do this if NOT using native label filtering for this section
Expand Down
70 changes: 70 additions & 0 deletions pkg/workflow/lock_for_agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,73 @@ Test workflow with lock-for-agent enabled for issue_comment events.
t.Error("Conclusion job should have issues: write permission when lock-for-agent is enabled")
}
}

func TestLockForAgentCommentedInYAML(t *testing.T) {
// Create temporary directory for test files
tmpDir := testutil.TempDir(t, "lock-for-agent-commented-test")

// Create a test markdown file with lock-for-agent enabled
testContent := `---
on:
issues:
types: [opened]
lock-for-agent: true
issue_comment:
types: [created]
lock-for-agent: true
engine: copilot
safe-outputs:
add-comment: {}
---

# Lock For Agent Commented Test

Test that lock-for-agent is commented out in generated YAML.
`

testFile := filepath.Join(tmpDir, "test-lock-for-agent-commented.md")
if err := os.WriteFile(testFile, []byte(testContent), 0644); err != nil {
t.Fatal(err)
}

compiler := NewCompiler(false, "", "test")

// Parse the workflow
workflowData, err := compiler.ParseWorkflowFile(testFile)
if err != nil {
t.Fatalf("Failed to parse workflow: %v", err)
}

// Verify lock-for-agent field is parsed correctly
if !workflowData.LockForAgent {
t.Error("Expected LockForAgent to be true")
}

// Generate YAML
yamlContent, err := compiler.generateYAML(workflowData, testFile)
if err != nil {
t.Fatalf("Failed to generate YAML: %v", err)
}

// Verify lock-for-agent is commented out in the on section
expectedComments := []string{
"# lock-for-agent: true # Lock-for-agent processed as issue locking in activation job",
}

for _, comment := range expectedComments {
if !strings.Contains(yamlContent, comment) {
t.Errorf("Generated YAML should contain commented lock-for-agent: %s", comment)
}
}

// Verify lock-for-agent does not appear uncommented
// Look for lines that have "lock-for-agent:" but not starting with "#"
lines := strings.Split(yamlContent, "\n")
for i, line := range lines {
trimmed := strings.TrimSpace(line)
// Check if line contains "lock-for-agent:" but is not a comment
if strings.Contains(trimmed, "lock-for-agent:") && !strings.HasPrefix(trimmed, "#") {
t.Errorf("Line %d contains uncommented lock-for-agent: %s", i+1, line)
}
}
}