diff --git a/models/actions/run_job.go b/models/actions/run_job.go index 9c7c3658d77c3..f72a7040e3359 100644 --- a/models/actions/run_job.go +++ b/models/actions/run_job.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + "github.com/nektos/act/pkg/jobparser" "xorm.io/builder" ) @@ -99,6 +100,24 @@ func (job *ActionRunJob) LoadAttributes(ctx context.Context) error { return job.Run.LoadAttributes(ctx) } +// ParseJob parses the job structure from the ActionRunJob.WorkflowPayload +func (job *ActionRunJob) ParseJob() (*jobparser.Job, error) { + // job.WorkflowPayload is a SingleWorkflow created from an ActionRun's workflow, which exactly contains this job's YAML definition. + // Ideally it shouldn't be called "Workflow", it is just a job with global workflow fields + trigger + parsedWorkflows, err := jobparser.Parse(job.WorkflowPayload) + if err != nil { + return nil, fmt.Errorf("job %d single workflow: unable to parse: %w", job.ID, err) + } else if len(parsedWorkflows) != 1 { + return nil, fmt.Errorf("job %d single workflow: not single workflow", job.ID) + } + _, workflowJob := parsedWorkflows[0].Job() + if workflowJob == nil { + // it shouldn't happen, and since the callers don't check nil, so return an error instead of nil + return nil, util.ErrorWrap(util.ErrNotExist, "job %d single workflow: payload doesn't contain a job", job.ID) + } + return workflowJob, nil +} + func GetRunJobByID(ctx context.Context, id int64) (*ActionRunJob, error) { var job ActionRunJob has, err := db.GetEngine(ctx).Where("id=?", id).Get(&job) diff --git a/models/actions/task.go b/models/actions/task.go index c1306a8418248..7417af8b45186 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -21,7 +21,6 @@ import ( runnerv1 "code.gitea.io/actions-proto-go/runner/v1" lru "github.com/hashicorp/golang-lru/v2" - "github.com/nektos/act/pkg/jobparser" "google.golang.org/protobuf/types/known/timestamppb" "xorm.io/builder" ) @@ -278,13 +277,10 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask return nil, false, err } - parsedWorkflows, err := jobparser.Parse(job.WorkflowPayload) + workflowJob, err := job.ParseJob() if err != nil { - return nil, false, fmt.Errorf("parse workflow of job %d: %w", job.ID, err) - } else if len(parsedWorkflows) != 1 { - return nil, false, fmt.Errorf("workflow of job %d: not single workflow", job.ID) + return nil, false, fmt.Errorf("load job %d: %w", job.ID, err) } - _, workflowJob := parsedWorkflows[0].Job() if _, err := e.Insert(task); err != nil { return nil, false, err diff --git a/services/actions/concurrency.go b/services/actions/concurrency.go index 2910e47739557..090830270943a 100644 --- a/services/actions/concurrency.go +++ b/services/actions/concurrency.go @@ -5,7 +5,6 @@ package actions import ( "context" - "errors" "fmt" actions_model "code.gitea.io/gitea/models/actions" @@ -91,17 +90,12 @@ func EvaluateJobConcurrencyFillModel(ctx context.Context, run *actions_model.Act return fmt.Errorf("get inputs: %w", err) } - // singleWorkflows is created from an ActionJob, which always contains exactly a single job's YAML definition. - // Ideally it shouldn't be called "Workflow", it is just a job with global workflow fields + trigger - singleWorkflows, err := jobparser.Parse(actionRunJob.WorkflowPayload) + workflowJob, err := actionRunJob.ParseJob() if err != nil { - return fmt.Errorf("parse single workflow: %w", err) - } else if len(singleWorkflows) != 1 { - return errors.New("not single workflow") + return fmt.Errorf("load job %d: %w", actionRunJob.ID, err) } - _, singleWorkflowJob := singleWorkflows[0].Job() - actionRunJob.ConcurrencyGroup, actionRunJob.ConcurrencyCancel, err = jobparser.EvaluateConcurrency(&rawConcurrency, actionRunJob.JobID, singleWorkflowJob, actionsJobCtx, jobResults, vars, inputs) + actionRunJob.ConcurrencyGroup, actionRunJob.ConcurrencyCancel, err = jobparser.EvaluateConcurrency(&rawConcurrency, actionRunJob.JobID, workflowJob, actionsJobCtx, jobResults, vars, inputs) if err != nil { return fmt.Errorf("evaluate concurrency: %w", err) } diff --git a/services/actions/job_emitter.go b/services/actions/job_emitter.go index c6578eae65163..762d28e9cc238 100644 --- a/services/actions/job_emitter.go +++ b/services/actions/job_emitter.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/modules/util" notify_service "code.gitea.io/gitea/services/notify" - "github.com/nektos/act/pkg/jobparser" "xorm.io/builder" ) @@ -305,9 +304,9 @@ func (r *jobStatusResolver) resolveCheckNeeds(id int64) (allDone, allSucceed boo } func (r *jobStatusResolver) resolveJobHasIfCondition(actionRunJob *actions_model.ActionRunJob) (hasIf bool) { - if wfJobs, _ := jobparser.Parse(actionRunJob.WorkflowPayload); len(wfJobs) == 1 { - _, wfJob := wfJobs[0].Job() - hasIf = len(wfJob.If.Value) > 0 + // FIXME evaluate this on the server side + if job, err := actionRunJob.ParseJob(); err == nil { + return len(job.If.Value) > 0 } return hasIf }