diff --git a/pkg/workflow/compiler.go b/pkg/workflow/compiler.go index 16792f12e3e..a20102640ce 100644 --- a/pkg/workflow/compiler.go +++ b/pkg/workflow/compiler.go @@ -1932,7 +1932,7 @@ func (c *Compiler) buildAddReactionJob(data *WorkflowData, taskJobCreated bool) Permissions: "permissions:\n issues: write\n pull-requests: write", Steps: steps, Outputs: outputs, - Depends: depends, + Needs: depends, } return job, nil @@ -1993,7 +1993,7 @@ func (c *Compiler) buildCreateOutputIssueJob(data *WorkflowData, mainJobName str TimeoutMinutes: 10, // 10-minute timeout as required Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil @@ -2052,7 +2052,7 @@ func (c *Compiler) buildCreateOutputDiscussionJob(data *WorkflowData, mainJobNam TimeoutMinutes: 10, // 10-minute timeout as required Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil @@ -2129,7 +2129,7 @@ func (c *Compiler) buildCreateOutputAddIssueCommentJob(data *WorkflowData, mainJ TimeoutMinutes: 10, // 10-minute timeout as required Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil @@ -2193,7 +2193,7 @@ func (c *Compiler) buildCreateOutputPullRequestReviewCommentJob(data *WorkflowDa TimeoutMinutes: 10, // 10-minute timeout as required Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil @@ -2281,7 +2281,7 @@ func (c *Compiler) buildCreateOutputSecurityReportJob(data *WorkflowData, mainJo TimeoutMinutes: 10, // 10-minute timeout Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil @@ -2376,7 +2376,7 @@ func (c *Compiler) buildCreateOutputPullRequestJob(data *WorkflowData, mainJobNa TimeoutMinutes: 10, // 10-minute timeout as required Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil @@ -2417,7 +2417,7 @@ func (c *Compiler) buildMainJob(data *WorkflowData, jobName string, taskJobCreat RunsOn: c.indentYAMLLines(data.RunsOn, " "), Permissions: c.indentYAMLLines(data.Permissions, " "), Steps: steps, - Depends: depends, + Needs: depends, Outputs: outputs, } @@ -3580,16 +3580,16 @@ func (c *Compiler) buildCustomJobs(data *WorkflowData) error { } // Extract job dependencies - if depends, hasDeps := configMap["depends"]; hasDeps { - if depsList, ok := depends.([]any); ok { - for _, dep := range depsList { - if depStr, ok := dep.(string); ok { - job.Depends = append(job.Depends, depStr) + if needs, hasNeeds := configMap["needs"]; hasNeeds { + if needsList, ok := needs.([]any); ok { + for _, need := range needsList { + if needStr, ok := need.(string); ok { + job.Needs = append(job.Needs, needStr) } } - } else if depStr, ok := depends.(string); ok { + } else if needStr, ok := needs.(string); ok { // Single dependency as string - job.Depends = append(job.Depends, depStr) + job.Needs = append(job.Needs, needStr) } } diff --git a/pkg/workflow/job_dependencies_test.go b/pkg/workflow/job_dependencies_test.go index 044eb434006..d9f619d2cd1 100644 --- a/pkg/workflow/job_dependencies_test.go +++ b/pkg/workflow/job_dependencies_test.go @@ -18,8 +18,8 @@ func TestJobDependenciesWithCycleDetection(t *testing.T) { name: "valid job dependencies", jobs: []*Job{ {Name: "build", RunsOn: "ubuntu-latest"}, - {Name: "test", RunsOn: "ubuntu-latest", Depends: []string{"build"}}, - {Name: "deploy", RunsOn: "ubuntu-latest", Depends: []string{"build", "test"}}, + {Name: "test", RunsOn: "ubuntu-latest", Needs: []string{"build"}}, + {Name: "deploy", RunsOn: "ubuntu-latest", Needs: []string{"build", "test"}}, }, expectError: false, description: "Valid linear job dependencies should work", @@ -27,8 +27,8 @@ func TestJobDependenciesWithCycleDetection(t *testing.T) { { name: "simple cycle detection", jobs: []*Job{ - {Name: "job1", RunsOn: "ubuntu-latest", Depends: []string{"job2"}}, - {Name: "job2", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, + {Name: "job1", RunsOn: "ubuntu-latest", Needs: []string{"job2"}}, + {Name: "job2", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, }, expectError: true, errorMsg: "cycle detected", @@ -37,9 +37,9 @@ func TestJobDependenciesWithCycleDetection(t *testing.T) { { name: "complex cycle detection", jobs: []*Job{ - {Name: "job1", RunsOn: "ubuntu-latest", Depends: []string{"job2"}}, - {Name: "job2", RunsOn: "ubuntu-latest", Depends: []string{"job3"}}, - {Name: "job3", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, + {Name: "job1", RunsOn: "ubuntu-latest", Needs: []string{"job2"}}, + {Name: "job2", RunsOn: "ubuntu-latest", Needs: []string{"job3"}}, + {Name: "job3", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, }, expectError: true, errorMsg: "cycle detected", @@ -48,7 +48,7 @@ func TestJobDependenciesWithCycleDetection(t *testing.T) { { name: "dependency on non-existent job", jobs: []*Job{ - {Name: "job1", RunsOn: "ubuntu-latest", Depends: []string{"nonexistent_job"}}, + {Name: "job1", RunsOn: "ubuntu-latest", Needs: []string{"nonexistent_job"}}, }, expectError: true, errorMsg: "depends on non-existent job", @@ -57,7 +57,7 @@ func TestJobDependenciesWithCycleDetection(t *testing.T) { { name: "self-dependency cycle", jobs: []*Job{ - {Name: "job1", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, + {Name: "job1", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, }, expectError: true, errorMsg: "cycle detected", @@ -146,9 +146,9 @@ func TestJobDependencyTopologicalOrder(t *testing.T) { // Create a complex dependency graph: build -> [unit-test, integration-test] -> deploy jobs := []*Job{ {Name: "build", RunsOn: "ubuntu-latest"}, - {Name: "unit-test", RunsOn: "ubuntu-latest", Depends: []string{"build"}}, - {Name: "integration-test", RunsOn: "ubuntu-latest", Depends: []string{"build"}}, - {Name: "deploy", RunsOn: "ubuntu-latest", Depends: []string{"unit-test", "integration-test"}}, + {Name: "unit-test", RunsOn: "ubuntu-latest", Needs: []string{"build"}}, + {Name: "integration-test", RunsOn: "ubuntu-latest", Needs: []string{"build"}}, + {Name: "deploy", RunsOn: "ubuntu-latest", Needs: []string{"unit-test", "integration-test"}}, } for _, job := range jobs { diff --git a/pkg/workflow/jobs.go b/pkg/workflow/jobs.go index a081d9bbf6b..24ac7c32685 100644 --- a/pkg/workflow/jobs.go +++ b/pkg/workflow/jobs.go @@ -14,7 +14,7 @@ type Job struct { Permissions string TimeoutMinutes int Steps []string - Depends []string // Job dependencies (needs clause) + Needs []string // Job dependencies (needs clause) Outputs map[string]string } @@ -67,7 +67,7 @@ func (jm *JobManager) GetAllJobs() map[string]*Job { func (jm *JobManager) ValidateDependencies() error { // First check that all dependencies reference existing jobs for jobName, job := range jm.jobs { - for _, dep := range job.Depends { + for _, dep := range job.Needs { if _, exists := jm.jobs[dep]; !exists { return fmt.Errorf("job '%s' depends on non-existent job '%s'", jobName, dep) } @@ -105,7 +105,7 @@ func (jm *JobManager) dfsVisit(jobName string, visitState map[string]int) error visitState[jobName] = 1 // Mark as visiting job := jm.jobs[jobName] - for _, dep := range job.Depends { + for _, dep := range job.Needs { if visitState[dep] == 1 { // Found a back edge - cycle detected return fmt.Errorf("cycle detected in job dependencies: job '%s' has circular dependency through '%s'", jobName, dep) @@ -146,12 +146,12 @@ func (jm *JobManager) renderJob(job *Job) string { yaml.WriteString(fmt.Sprintf(" %s:\n", job.Name)) // Add needs clause if there are dependencies - if len(job.Depends) > 0 { - if len(job.Depends) == 1 { - yaml.WriteString(fmt.Sprintf(" needs: %s\n", job.Depends[0])) + if len(job.Needs) > 0 { + if len(job.Needs) == 1 { + yaml.WriteString(fmt.Sprintf(" needs: %s\n", job.Needs[0])) } else { yaml.WriteString(" needs:\n") - for _, dep := range job.Depends { + for _, dep := range job.Needs { yaml.WriteString(fmt.Sprintf(" - %s\n", dep)) } } @@ -222,7 +222,7 @@ func (jm *JobManager) GetTopologicalOrder() ([]string, error) { // Calculate in-degrees: count how many dependencies each job has for _, job := range jm.jobs { - inDegree[job.Name] = len(job.Depends) + inDegree[job.Name] = len(job.Needs) } // Start with jobs that have no dependencies (in-degree = 0) @@ -247,7 +247,7 @@ func (jm *JobManager) GetTopologicalOrder() ([]string, error) { // For each job that depends on the current job, reduce its in-degree for jobName, job := range jm.jobs { - for _, dep := range job.Depends { + for _, dep := range job.Needs { if dep == currentJob { inDegree[jobName]-- if inDegree[jobName] == 0 { diff --git a/pkg/workflow/jobs_test.go b/pkg/workflow/jobs_test.go index 0ec18a4c85a..744ccd9a676 100644 --- a/pkg/workflow/jobs_test.go +++ b/pkg/workflow/jobs_test.go @@ -81,8 +81,8 @@ func TestJobManager_ValidateDependencies(t *testing.T) { name: "valid dependencies", jobs: []*Job{ {Name: "job1", RunsOn: "ubuntu-latest"}, - {Name: "job2", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, - {Name: "job3", RunsOn: "ubuntu-latest", Depends: []string{"job1", "job2"}}, + {Name: "job2", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, + {Name: "job3", RunsOn: "ubuntu-latest", Needs: []string{"job1", "job2"}}, }, wantErr: false, }, @@ -90,7 +90,7 @@ func TestJobManager_ValidateDependencies(t *testing.T) { name: "missing dependency", jobs: []*Job{ {Name: "job1", RunsOn: "ubuntu-latest"}, - {Name: "job2", RunsOn: "ubuntu-latest", Depends: []string{"nonexistent"}}, + {Name: "job2", RunsOn: "ubuntu-latest", Needs: []string{"nonexistent"}}, }, wantErr: true, errMsg: "depends on non-existent job 'nonexistent'", @@ -98,8 +98,8 @@ func TestJobManager_ValidateDependencies(t *testing.T) { { name: "simple cycle", jobs: []*Job{ - {Name: "job1", RunsOn: "ubuntu-latest", Depends: []string{"job2"}}, - {Name: "job2", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, + {Name: "job1", RunsOn: "ubuntu-latest", Needs: []string{"job2"}}, + {Name: "job2", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, }, wantErr: true, errMsg: "cycle detected", @@ -107,9 +107,9 @@ func TestJobManager_ValidateDependencies(t *testing.T) { { name: "complex cycle", jobs: []*Job{ - {Name: "job1", RunsOn: "ubuntu-latest", Depends: []string{"job2"}}, - {Name: "job2", RunsOn: "ubuntu-latest", Depends: []string{"job3"}}, - {Name: "job3", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, + {Name: "job1", RunsOn: "ubuntu-latest", Needs: []string{"job2"}}, + {Name: "job2", RunsOn: "ubuntu-latest", Needs: []string{"job3"}}, + {Name: "job3", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, }, wantErr: true, errMsg: "cycle detected", @@ -117,7 +117,7 @@ func TestJobManager_ValidateDependencies(t *testing.T) { { name: "self-dependency cycle", jobs: []*Job{ - {Name: "job1", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, + {Name: "job1", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, }, wantErr: true, errMsg: "cycle detected", @@ -172,8 +172,8 @@ func TestJobManager_GetTopologicalOrder(t *testing.T) { name: "linear dependencies", jobs: []*Job{ {Name: "job1", RunsOn: "ubuntu-latest"}, - {Name: "job2", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, - {Name: "job3", RunsOn: "ubuntu-latest", Depends: []string{"job2"}}, + {Name: "job2", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, + {Name: "job3", RunsOn: "ubuntu-latest", Needs: []string{"job2"}}, }, expected: []string{"job1", "job2", "job3"}, wantErr: false, @@ -182,9 +182,9 @@ func TestJobManager_GetTopologicalOrder(t *testing.T) { name: "complex dependencies", jobs: []*Job{ {Name: "build", RunsOn: "ubuntu-latest"}, - {Name: "test", RunsOn: "ubuntu-latest", Depends: []string{"build"}}, - {Name: "lint", RunsOn: "ubuntu-latest", Depends: []string{"build"}}, - {Name: "deploy", RunsOn: "ubuntu-latest", Depends: []string{"test", "lint"}}, + {Name: "test", RunsOn: "ubuntu-latest", Needs: []string{"build"}}, + {Name: "lint", RunsOn: "ubuntu-latest", Needs: []string{"build"}}, + {Name: "deploy", RunsOn: "ubuntu-latest", Needs: []string{"test", "lint"}}, }, expected: []string{"build", "lint", "test", "deploy"}, // build first, then lint/test (alphabetical), then deploy wantErr: false, @@ -192,8 +192,8 @@ func TestJobManager_GetTopologicalOrder(t *testing.T) { { name: "cycle should error", jobs: []*Job{ - {Name: "job1", RunsOn: "ubuntu-latest", Depends: []string{"job2"}}, - {Name: "job2", RunsOn: "ubuntu-latest", Depends: []string{"job1"}}, + {Name: "job1", RunsOn: "ubuntu-latest", Needs: []string{"job2"}}, + {Name: "job2", RunsOn: "ubuntu-latest", Needs: []string{"job1"}}, }, wantErr: true, errMsg: "cycle detected", @@ -272,10 +272,10 @@ func TestJobManager_RenderToYAML(t *testing.T) { name: "job with dependencies", jobs: []*Job{ { - Name: "job1", - RunsOn: "runs-on: ubuntu-latest", - Depends: []string{"job2"}, - Steps: []string{" - name: Step1\n run: echo step1\n"}, + Name: "job1", + RunsOn: "runs-on: ubuntu-latest", + Needs: []string{"job2"}, + Steps: []string{" - name: Step1\n run: echo step1\n"}, }, { Name: "job2", @@ -296,10 +296,10 @@ func TestJobManager_RenderToYAML(t *testing.T) { name: "job with multiple dependencies", jobs: []*Job{ { - Name: "deploy", - RunsOn: "runs-on: ubuntu-latest", - Depends: []string{"build", "test"}, - Steps: []string{" - name: Deploy\n run: echo deploy\n"}, + Name: "deploy", + RunsOn: "runs-on: ubuntu-latest", + Needs: []string{"build", "test"}, + Steps: []string{" - name: Deploy\n run: echo deploy\n"}, }, }, expected: []string{ diff --git a/pkg/workflow/output_labels.go b/pkg/workflow/output_labels.go index 5598665ae65..047f6072cd9 100644 --- a/pkg/workflow/output_labels.go +++ b/pkg/workflow/output_labels.go @@ -71,7 +71,7 @@ func (c *Compiler) buildCreateOutputLabelJob(data *WorkflowData, mainJobName str TimeoutMinutes: 10, // 10-minute timeout as required Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil diff --git a/pkg/workflow/output_missing_tool.go b/pkg/workflow/output_missing_tool.go index bb1d8c58c39..bd862a7ad5e 100644 --- a/pkg/workflow/output_missing_tool.go +++ b/pkg/workflow/output_missing_tool.go @@ -47,7 +47,7 @@ func (c *Compiler) buildCreateOutputMissingToolJob(data *WorkflowData, mainJobNa TimeoutMinutes: 5, // Short timeout since it's just processing output Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil diff --git a/pkg/workflow/output_missing_tool_test.go b/pkg/workflow/output_missing_tool_test.go index 2659ed1e71c..c78f12cd65d 100644 --- a/pkg/workflow/output_missing_tool_test.go +++ b/pkg/workflow/output_missing_tool_test.go @@ -103,8 +103,8 @@ func TestMissingToolSafeOutput(t *testing.T) { if job.Name != "missing_tool" { t.Errorf("Expected job name to be 'missing_tool', got '%s'", job.Name) } - if len(job.Depends) != 1 || job.Depends[0] != "main-job" { - t.Errorf("Expected job to depend on 'main-job', got %v", job.Depends) + if len(job.Needs) != 1 || job.Needs[0] != "main-job" { + t.Errorf("Expected job to depend on 'main-job', got %v", job.Needs) } } } diff --git a/pkg/workflow/output_push_to_branch.go b/pkg/workflow/output_push_to_branch.go index ce3f4a0d28e..c05faa8689d 100644 --- a/pkg/workflow/output_push_to_branch.go +++ b/pkg/workflow/output_push_to_branch.go @@ -101,7 +101,7 @@ func (c *Compiler) buildCreateOutputPushToBranchJob(data *WorkflowData, mainJobN TimeoutMinutes: 10, // 10-minute timeout as required Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil diff --git a/pkg/workflow/output_update_issue.go b/pkg/workflow/output_update_issue.go index 2e4ab6cb35b..aeea45f02d7 100644 --- a/pkg/workflow/output_update_issue.go +++ b/pkg/workflow/output_update_issue.go @@ -84,7 +84,7 @@ func (c *Compiler) buildCreateOutputUpdateIssueJob(data *WorkflowData, mainJobNa TimeoutMinutes: 10, // 10-minute timeout as required Steps: steps, Outputs: outputs, - Depends: []string{mainJobName}, // Depend on the main workflow job + Needs: []string{mainJobName}, // Depend on the main workflow job } return job, nil diff --git a/pkg/workflow/security_reports_test.go b/pkg/workflow/security_reports_test.go index 10ea48537a9..e1aa4f38c28 100644 --- a/pkg/workflow/security_reports_test.go +++ b/pkg/workflow/security_reports_test.go @@ -120,8 +120,8 @@ func TestBuildCreateOutputSecurityReportJob(t *testing.T) { t.Errorf("Expected timeout 10 minutes, got %d", job.TimeoutMinutes) } - if len(job.Depends) != 1 || job.Depends[0] != "main_job" { - t.Errorf("Expected dependency on 'main_job', got %v", job.Depends) + if len(job.Needs) != 1 || job.Needs[0] != "main_job" { + t.Errorf("Expected dependency on 'main_job', got %v", job.Needs) } // Check that job has necessary permissions