mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-24 16:34:58 +02:00
fix(actions): evaluate job-level if: before concurrency check (#39437)
Gitea doesn't evaluate a job's `if:` before checking the job's concurrency group, which causes a job that should have been skipped to incorrectly cancel other jobs in the same concurrency group. This PR makes Gitea decide `if:` for every job before it becomes waiting, including jobs without `needs` at insertion, on approval and on rerun. A skipped job therefore no longer takes part in job concurrency or holds a max-parallel slot, and a reusable caller whose `if:` is false is no longer expanded on approval or rerun. An invalid `if:` skips the job with an error summary. After this PR, Gitea decides all jobs' `if:` expressions and sends `if: always()` to the runner, so the runner no longer needs to evaluate a job's `if:` again ([gitea/runner `run_context.go`](https://gitea.com/gitea/runner/src/commit/81add274599355ec1838b6ebe45804890d40bab9/act/runner/run_context.go#L1195)). --------- Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
1 parent
f0f53a76ee
commit
a15f032026
12 files changed
+263
-83
No files matched your search
@@ -5,6 +5,7 @@ package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
actions_model "gitea.dev/models/actions"
|
||||
@@ -92,11 +93,35 @@ func pullRequestTargetBaseSHA(run *actions_model.ActionRun) (string, bool) {
|
||||
return payload.PullRequest.Base.Sha, true
|
||||
}
|
||||
|
||||
// evaluateJobIf evaluates a job's `if:`
|
||||
// evaluateJobIf evaluates a job's `if:`. An invalid `if:` skips the job and is reported in its summary.
|
||||
func evaluateJobIf(ctx context.Context, run *actions_model.ActionRun, attempt *actions_model.ActionRunAttempt, job *actions_model.ActionRunJob, vars map[string]string, allNeedsSucceed bool) (bool, error) {
|
||||
shouldStart, err := resolveJobIf(ctx, run, attempt, job, vars, allNeedsSucceed)
|
||||
if errors.Is(err, util.ErrInvalidArgument) {
|
||||
return false, upsertJobErrorSummary(ctx, job, "if", err)
|
||||
}
|
||||
return shouldStart, err
|
||||
}
|
||||
|
||||
// decideJobIf skips a waiting job whose `if:` is false before its insertion, an invalid `if:` is returned for the job's summary.
|
||||
func decideJobIf(ctx context.Context, run *actions_model.ActionRun, attempt *actions_model.ActionRunAttempt, job *actions_model.ActionRunJob, vars map[string]string) (invalidIf, err error) {
|
||||
if job.Status != actions_model.StatusWaiting {
|
||||
return nil, nil
|
||||
}
|
||||
shouldStart, err := resolveJobIf(ctx, run, attempt, job, vars, true)
|
||||
if errors.Is(err, util.ErrInvalidArgument) {
|
||||
invalidIf, err = err, nil
|
||||
}
|
||||
if !shouldStart {
|
||||
job.Status = actions_model.StatusSkipped
|
||||
}
|
||||
return invalidIf, err
|
||||
}
|
||||
|
||||
// resolveJobIf evaluates a job's `if:` and returns an invalid `if:` as util.ErrInvalidArgument.
|
||||
func resolveJobIf(ctx context.Context, run *actions_model.ActionRun, attempt *actions_model.ActionRunAttempt, job *actions_model.ActionRunJob, vars map[string]string, allNeedsSucceed bool) (bool, error) {
|
||||
parsedJob, err := job.ParseJob()
|
||||
if err != nil {
|
||||
return false, upsertJobErrorSummary(ctx, job, "if", err)
|
||||
return false, util.NewInvalidArgumentErrorf("%v", err)
|
||||
}
|
||||
// Empty `if:` reduces to implicit `success()` - true iff every need finished as Success.
|
||||
if len(parsedJob.If.Value) == 0 {
|
||||
@@ -122,7 +147,7 @@ func evaluateJobIf(ctx context.Context, run *actions_model.ActionRun, attempt *a
|
||||
gitCtx["job"] = "" // github.com decides a job's `if:` before the job exists
|
||||
shouldStart, err := jobparser.EvaluateJobIfExpression(job.JobID, parsedJob, gitCtx, jobResults, vars, inputs)
|
||||
if err != nil {
|
||||
return false, upsertJobErrorSummary(ctx, job, "if", err)
|
||||
return false, util.NewInvalidArgumentErrorf("%v", err)
|
||||
}
|
||||
return shouldStart, nil
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user