diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml index a5d6a1d920f..5ed8c6d0a47 100644 --- a/.github/workflows/ai-moderator.lock.yml +++ b/.github/workflows/ai-moderator.lock.yml @@ -23,11 +23,11 @@ name: "AI Moderator" "on": issue_comment: - lock-for-agent: true + # lock-for-agent: true # Lock-for-agent processed as issue locking in activation job types: - created issues: - lock-for-agent: true + # lock-for-agent: true # Lock-for-agent processed as issue locking in activation job types: - opened workflow_dispatch: diff --git a/.github/workflows/campaign-generator.lock.yml b/.github/workflows/campaign-generator.lock.yml index 5184599317a..d46776d8145 100644 --- a/.github/workflows/campaign-generator.lock.yml +++ b/.github/workflows/campaign-generator.lock.yml @@ -24,7 +24,7 @@ name: "Campaign Generator" "on": issues: - lock-for-agent: true + # lock-for-agent: true # Lock-for-agent processed as issue locking in activation job types: - opened - labeled diff --git a/.github/workflows/workflow-generator.lock.yml b/.github/workflows/workflow-generator.lock.yml index b48087e607e..5cf086f4ded 100644 --- a/.github/workflows/workflow-generator.lock.yml +++ b/.github/workflows/workflow-generator.lock.yml @@ -24,7 +24,7 @@ name: "Workflow Generator" "on": issues: - lock-for-agent: true + # lock-for-agent: true # Lock-for-agent processed as issue locking in activation job types: - opened - labeled diff --git a/pkg/workflow/frontmatter_extraction.go b/pkg/workflow/frontmatter_extraction.go index 59754c49b98..d4b6a3390a6 100644 --- a/pkg/workflow/frontmatter_extraction.go +++ b/pkg/workflow/frontmatter_extraction.go @@ -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 { @@ -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 { @@ -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 @@ -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 @@ -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 = "" } @@ -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 } @@ -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")) { @@ -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" @@ -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 diff --git a/pkg/workflow/lock_for_agent_test.go b/pkg/workflow/lock_for_agent_test.go index 3593db74d81..3501bcf1dd0 100644 --- a/pkg/workflow/lock_for_agent_test.go +++ b/pkg/workflow/lock_for_agent_test.go @@ -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) + } + } +}