mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-01 20:59:45 +09: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:
@@ -17,6 +17,7 @@ import (
|
||||
actions_module "gitea.dev/modules/actions"
|
||||
"gitea.dev/modules/json"
|
||||
api "gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/test"
|
||||
webhook_module "gitea.dev/modules/webhook"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -97,6 +98,47 @@ jobs:
|
||||
assert.NotEmpty(t, persisted.RawConcurrency)
|
||||
}
|
||||
|
||||
func TestPrepareRunAndInsert_JobIf(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
defer test.MockVariableValue(&EmitJobsIfReadyByRun, func(int64) error { return nil })()
|
||||
|
||||
run := insertMaxParallelRun(t, `on: push
|
||||
jobs:
|
||||
start:
|
||||
if: github.event_name == 'push'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo
|
||||
skip:
|
||||
if: github.event_name != 'push'
|
||||
runs-on: ubuntu-latest
|
||||
concurrency: skip
|
||||
steps:
|
||||
- run: echo
|
||||
skip-caller:
|
||||
if: false
|
||||
uses: ./.gitea/workflows/callee.yml
|
||||
invalid:
|
||||
if: fromJSON('{')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo
|
||||
`, false)
|
||||
|
||||
jobs := map[string]*actions_model.ActionRunJob{}
|
||||
for _, job := range runJobs(t, run.ID, run.LatestAttemptID) {
|
||||
jobs[job.JobID] = job
|
||||
}
|
||||
assert.Equal(t, actions_model.StatusWaiting, jobs["start"].Status)
|
||||
assert.Equal(t, actions_model.StatusSkipped, jobs["skip"].Status)
|
||||
assert.False(t, jobs["skip"].IsConcurrencyEvaluated)
|
||||
assert.Equal(t, actions_model.StatusSkipped, jobs["skip-caller"].Status)
|
||||
assert.Equal(t, actions_model.StatusSkipped, jobs["invalid"].Status)
|
||||
summary, err := actions_model.GetActionRunJobSummary(t.Context(), run.RepoID, run.ID, run.LatestAttemptID, jobs["invalid"].ID, 0)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, summary.Content, "Error when evaluating `if` for job `invalid`")
|
||||
}
|
||||
|
||||
func TestComputeReusableCallerOutputs(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
ctx := t.Context()
|
||||
|
||||
Reference in New Issue
Block a user