0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-08 10:13:39 +02:00

fix(actions): report individual step status in workflow job API response (#37592)

When a workflow job failed, the API response reported all steps as
failed — even steps that had completed successfully before the failing
step. `ToActionWorkflowJob` was calling `ToActionsStatus(job.Status)`
for every step instead of `ToActionsStatus(step.Status)`, so the job's
overall conclusion was propagated to each step.

Each `ActionTaskStep` has its own `Status` field that tracks the actual
outcome of that step independently of the job result.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Nicolas 2026-05-07 20:30:34 +02:00 committed by GitHub
parent e9f82b0ee3
commit 601c6eb1a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 14 deletions

View File

@ -9,6 +9,7 @@ import (
"testing"
actions_model "code.gitea.io/gitea/models/actions"
db "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
@ -124,3 +125,55 @@ func TestToActionWorkflowRun_UsesTriggerEvent(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "schedule", apiRun.Event)
}
func TestToActionWorkflowJob_StepStatusIsIndependentOfJobStatus(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
ctx := t.Context()
run := &actions_model.ActionRun{
ID: 9001,
RepoID: 2,
TriggerUserID: 1,
WorkflowID: "test.yaml",
Index: 12345,
Ref: "refs/heads/main",
Status: actions_model.StatusFailure,
}
require.NoError(t, db.Insert(ctx, run))
task := &actions_model.ActionTask{
ID: 900102,
JobID: 9001,
RepoID: 2,
Status: actions_model.StatusFailure,
}
require.NoError(t, db.Insert(ctx, task))
job := &actions_model.ActionRunJob{
ID: 90010203,
RunID: 9001,
TaskID: 900102,
RepoID: 2,
Name: "test-job-name",
Attempt: 1,
JobID: "test-job-id",
Status: actions_model.StatusFailure,
}
require.NoError(t, db.Insert(ctx, job))
require.NoError(t, db.Insert(ctx,
&actions_model.ActionTaskStep{TaskID: task.ID, RepoID: 2, Index: 0, Name: "step-success", Status: actions_model.StatusSuccess},
&actions_model.ActionTaskStep{TaskID: task.ID, RepoID: 2, Index: 1, Name: "step-failure", Status: actions_model.StatusFailure},
))
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
apiJob, err := ToActionWorkflowJob(ctx, repo, task, job)
require.NoError(t, err)
require.Len(t, apiJob.Steps, 2)
assert.Equal(t, "completed", apiJob.Steps[0].Status, "step 0 status")
assert.Equal(t, "success", apiJob.Steps[0].Conclusion, "step 0 conclusion (succeeded before the failure)")
assert.Equal(t, "completed", apiJob.Steps[1].Status, "step 1 status")
assert.Equal(t, "failure", apiJob.Steps[1].Conclusion, "step 1 conclusion")
}

View File

@ -314,33 +314,31 @@ func ToActionWorkflowRun(ctx context.Context, run *actions_model.ActionRun, atte
}, nil
}
func ToWorkflowRunAction(status actions_model.Status) string {
var action string
func ToWorkflowRunAction(status actions_model.Status) (action string) {
switch status {
case actions_model.StatusWaiting, actions_model.StatusBlocked:
action = "requested"
case actions_model.StatusRunning:
action = "in_progress"
}
if status.IsDone() {
action = "completed"
default:
if status.IsDone() {
action = "completed"
} else {
setting.PanicInDevOrTesting("unknown action status: %v", status)
}
}
return action
}
func ToActionsStatus(status actions_model.Status) (string, string) {
var action string
var conclusion string
func ToActionsStatus(status actions_model.Status) (action, conclusion string) {
switch status {
// This is a naming conflict of the webhook between Gitea and GitHub Actions
case actions_model.StatusWaiting:
action = "queued"
action = "queued" // "waiting" is a naming conflict of the webhook between Gitea and GitHub Actions
case actions_model.StatusBlocked:
action = "waiting"
action = "waiting" // naming conflict (as above)
case actions_model.StatusRunning:
action = "in_progress"
}
if status.IsDone() {
default:
action = "completed"
switch status {
case actions_model.StatusSuccess:
@ -351,6 +349,8 @@ func ToActionsStatus(status actions_model.Status) (string, string) {
conclusion = "failure"
case actions_model.StatusSkipped:
conclusion = "skipped"
default:
setting.PanicInDevOrTesting("unknown action status: %v", status)
}
}
return action, conclusion
@ -390,7 +390,7 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task
runnerName = runner.Name
}
for i, step := range task.Steps {
stepStatus, stepConclusion := ToActionsStatus(job.Status)
stepStatus, stepConclusion := ToActionsStatus(step.Status)
steps = append(steps, &api.ActionWorkflowStep{
Name: step.Name,
Number: int64(i),