buildConclusionJob creates a job that handles workflow completion tasks This job is generated when safe-outputs are configured and handles: - Updating status comments (if status-comment: true) - Processing noop messages - Handling agent failures - Recording missing tools This job runs when: 1. alway
(data *WorkflowData, mainJobName string, safeOutputJobNames []string)
| 22 | // 3. NO add_comment output was produced by the agent (avoids duplicate updates) |
| 23 | // This job depends on all safe output jobs to ensure it runs last |
| 24 | func (c *Compiler) buildConclusionJob(data *WorkflowData, mainJobName string, safeOutputJobNames []string) (*Job, error) { |
| 25 | notifyCommentLog.Printf("Building conclusion job: main_job=%s, safe_output_jobs_count=%d", mainJobName, len(safeOutputJobNames)) |
| 26 | // Always create this job when safe-outputs exist (because noop is always enabled) |
| 27 | // This ensures noop messages can be handled even without reactions |
| 28 | if data.SafeOutputs == nil { |
| 29 | notifyCommentLog.Printf("Skipping job: no safe-outputs configured") |
| 30 | return nil, nil // No safe-outputs configured, no need for conclusion job |
| 31 | } |
| 32 | steps := c.buildConclusionSetupSteps(data) |
| 33 | steps = append(steps, c.buildConclusionNoOpStep(data, mainJobName)...) |
| 34 | steps = append(steps, c.buildConclusionDetectionRunsStep(data, mainJobName)...) |
| 35 | steps = append(steps, c.buildConclusionMissingToolStep(data, mainJobName)...) |
| 36 | steps = append(steps, c.buildConclusionReportIncompleteStep(data, mainJobName)...) |
| 37 | messagesJSON := serializeConclusionMessagesJSON(data) |
| 38 | agentFailureSteps, err := c.buildAgentFailureStep(data, mainJobName, messagesJSON) |
| 39 | if err != nil { |
| 40 | return nil, err |
| 41 | } |
| 42 | steps = append(steps, agentFailureSteps...) |
| 43 | customEnvVars := c.buildConclusionScriptEnvVars(data, mainJobName, safeOutputJobNames, messagesJSON) |
| 44 | var token string |
| 45 | if data.SafeOutputs != nil && data.SafeOutputs.AddComments != nil { |
| 46 | token = data.SafeOutputs.AddComments.GitHubToken |
| 47 | } |
| 48 | // Only add the conclusion update step if status comments are explicitly enabled |
| 49 | if data.StatusComment != nil && *data.StatusComment { |
| 50 | steps = append(steps, c.buildGitHubScriptStepWithoutDownload(data, GitHubScriptStepConfig{ |
| 51 | StepName: "Update reaction comment with completion status", |
| 52 | StepID: "conclusion", |
| 53 | MainJobName: mainJobName, |
| 54 | CustomEnvVars: customEnvVars, |
| 55 | Script: getNotifyCommentErrorScript(), |
| 56 | ScriptFile: "notify_comment_error.cjs", |
| 57 | CustomToken: token, |
| 58 | })...) |
| 59 | } |
| 60 | if c.actionMode.IsScript() { |
| 61 | steps = append(steps, c.generateScriptModeCleanupStep()) |
| 62 | } |
| 63 | needs := buildConclusionJobNeeds(data, mainJobName, safeOutputJobNames) |
| 64 | notifyCommentLog.Printf("Job built successfully: dependencies_count=%d", len(needs)) |
| 65 | return &Job{ |
| 66 | Name: "conclusion", |
| 67 | If: RenderCondition(buildConclusionJobCondition(data, mainJobName, safeOutputJobNames)), |
| 68 | RunsOn: c.formatFrameworkJobRunsOn(data), |
| 69 | Environment: c.indentYAMLLines(resolveSafeOutputsEnvironment(data), " "), |
| 70 | Permissions: ComputePermissionsForSafeOutputs(data.SafeOutputs).RenderToYAML(), |
| 71 | Concurrency: c.buildConclusionJobConcurrency(data), |
| 72 | Steps: steps, |
| 73 | Needs: needs, |
| 74 | Outputs: buildConclusionJobOutputs(data), |
| 75 | }, nil |
| 76 | } |
| 77 | |
| 78 | // buildUsageArtifactUploadSteps creates steps that collect and upload a compact usage artifact. |
| 79 | // The artifact includes aw_info.json, aw-info.jsonl, agent_usage.json, agent_usage.jsonl, detection_usage.jsonl, and agent/detection token usage JSONL files (when present). |