From 5261938c5bc804d03698825e33c50f1e2d3502d9 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Wed, 20 Mar 2024 21:35:15 +0800 Subject: [PATCH 1/8] fix order of rerun --- routers/web/repo/actions/view.go | 45 ++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 3f8030e40d7b..6a878dae0945 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/timeutil" @@ -303,12 +304,43 @@ func Rerun(ctx *context_module.Context) { return } - if jobIndexStr != "" { - jobs = []*actions_model.ActionRunJob{job} + if jobIndexStr == "" { // rerun all jobs + for _, j := range jobs { + if err := rerunJob(ctx, j, len(j.Needs) > 0); err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + } + return + } + + rerunJobs := []*actions_model.ActionRunJob{job} + rerunJobsIDSet := make(container.Set[string]) + rerunJobsIDSet.Add(job.JobID) + + for { + found := false + for _, j := range jobs { + if rerunJobsIDSet.Contains(j.JobID) { + continue + } + for _, need := range j.Needs { + if rerunJobsIDSet.Contains(need) && !rerunJobsIDSet.Contains(j.JobID) { + found = true + rerunJobs = append(rerunJobs, j) + rerunJobsIDSet.Add(j.JobID) + continue + } + } + } + if !found { + break + } } - for _, j := range jobs { - if err := rerunJob(ctx, j); err != nil { + for _, j := range rerunJobs { + shouldlock := j.JobID != job.JobID && len(j.Needs) > 0 + if err := rerunJob(ctx, j, shouldlock); err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return } @@ -317,7 +349,7 @@ func Rerun(ctx *context_module.Context) { ctx.JSON(http.StatusOK, struct{}{}) } -func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob) error { +func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob, shouldBlock bool) error { status := job.Status if !status.IsDone() { return nil @@ -325,6 +357,9 @@ func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob) erro job.TaskID = 0 job.Status = actions_model.StatusWaiting + if shouldBlock { + job.Status = actions_model.StatusBlocked + } job.Started = 0 job.Stopped = 0 From 0fb3243273dd8b33d2fdc530a2ee7f52daa014c5 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Wed, 20 Mar 2024 21:53:01 +0800 Subject: [PATCH 2/8] fix incorrect check --- routers/web/repo/actions/view.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 6a878dae0945..da249f022f03 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -306,7 +306,8 @@ func Rerun(ctx *context_module.Context) { if jobIndexStr == "" { // rerun all jobs for _, j := range jobs { - if err := rerunJob(ctx, j, len(j.Needs) > 0); err != nil { + shouldBlock := len(j.Needs) > 0 + if err := rerunJob(ctx, j, shouldBlock); err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return } @@ -325,11 +326,11 @@ func Rerun(ctx *context_module.Context) { continue } for _, need := range j.Needs { - if rerunJobsIDSet.Contains(need) && !rerunJobsIDSet.Contains(j.JobID) { + if rerunJobsIDSet.Contains(need) { found = true rerunJobs = append(rerunJobs, j) rerunJobsIDSet.Add(j.JobID) - continue + break } } } @@ -339,8 +340,8 @@ func Rerun(ctx *context_module.Context) { } for _, j := range rerunJobs { - shouldlock := j.JobID != job.JobID && len(j.Needs) > 0 - if err := rerunJob(ctx, j, shouldlock); err != nil { + shouldBlock := j.JobID != job.JobID && len(j.Needs) > 0 + if err := rerunJob(ctx, j, shouldBlock); err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return } From 666451201a1c3fb750c1bb568d3adf4ad6647abb Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Wed, 20 Mar 2024 22:59:20 +0800 Subject: [PATCH 3/8] move code to services --- routers/web/repo/actions/view.go | 29 ++++-------------------- services/actions/rerun.go | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 services/actions/rerun.go diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index da249f022f03..00de3222f6f9 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -22,7 +22,6 @@ import ( "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/timeutil" @@ -306,6 +305,7 @@ func Rerun(ctx *context_module.Context) { if jobIndexStr == "" { // rerun all jobs for _, j := range jobs { + // if the job has needs, it should be set to "blocked" status to wait for other jobs shouldBlock := len(j.Needs) > 0 if err := rerunJob(ctx, j, shouldBlock); err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) @@ -315,32 +315,11 @@ func Rerun(ctx *context_module.Context) { return } - rerunJobs := []*actions_model.ActionRunJob{job} - rerunJobsIDSet := make(container.Set[string]) - rerunJobsIDSet.Add(job.JobID) - - for { - found := false - for _, j := range jobs { - if rerunJobsIDSet.Contains(j.JobID) { - continue - } - for _, need := range j.Needs { - if rerunJobsIDSet.Contains(need) { - found = true - rerunJobs = append(rerunJobs, j) - rerunJobsIDSet.Add(j.JobID) - break - } - } - } - if !found { - break - } - } + rerunJobs := actions_service.GetAllRerunJobs(job, jobs) for _, j := range rerunJobs { - shouldBlock := j.JobID != job.JobID && len(j.Needs) > 0 + // jobs other than the specified one should be set to "blocked" status + shouldBlock := j.JobID != job.JobID if err := rerunJob(ctx, j, shouldBlock); err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return diff --git a/services/actions/rerun.go b/services/actions/rerun.go new file mode 100644 index 000000000000..60f66509058f --- /dev/null +++ b/services/actions/rerun.go @@ -0,0 +1,38 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/modules/container" +) + +// GetAllRerunJobs get all jobs that need to be rerun when job should be rerun +func GetAllRerunJobs(job *actions_model.ActionRunJob, allJobs []*actions_model.ActionRunJob) []*actions_model.ActionRunJob { + rerunJobs := []*actions_model.ActionRunJob{job} + rerunJobsIDSet := make(container.Set[string]) + rerunJobsIDSet.Add(job.JobID) + + for { + found := false + for _, j := range allJobs { + if rerunJobsIDSet.Contains(j.JobID) { + continue + } + for _, need := range j.Needs { + if rerunJobsIDSet.Contains(need) { + found = true + rerunJobs = append(rerunJobs, j) + rerunJobsIDSet.Add(j.JobID) + break + } + } + } + if !found { + break + } + } + + return rerunJobs +} From 0cf180c954e51f1f7faf493b0ffb9f3d16cb6986 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Thu, 21 Mar 2024 01:01:03 +0800 Subject: [PATCH 4/8] add TestGetAllRerunJobs --- services/actions/rerun_test.go | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 services/actions/rerun_test.go diff --git a/services/actions/rerun_test.go b/services/actions/rerun_test.go new file mode 100644 index 000000000000..cd91ad8d3a8a --- /dev/null +++ b/services/actions/rerun_test.go @@ -0,0 +1,47 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "testing" + + actions_model "code.gitea.io/gitea/models/actions" + "github.com/stretchr/testify/assert" +) + +func TestGetAllRerunJobs(t *testing.T) { + job1 := &actions_model.ActionRunJob{JobID: "job1"} + job2 := &actions_model.ActionRunJob{JobID: "job2", Needs: []string{"job1"}} + job3 := &actions_model.ActionRunJob{JobID: "job3", Needs: []string{"job2"}} + job4 := &actions_model.ActionRunJob{JobID: "job4", Needs: []string{"job2", "job3"}} + + jobs := []*actions_model.ActionRunJob{job1, job2, job3, job4} + + testCases := []struct { + job *actions_model.ActionRunJob + rerunJobs []*actions_model.ActionRunJob + }{ + { + job1, + []*actions_model.ActionRunJob{job1, job2, job3, job4}, + }, + { + job2, + []*actions_model.ActionRunJob{job2, job3, job4}, + }, + { + job3, + []*actions_model.ActionRunJob{job3, job4}, + }, + { + job4, + []*actions_model.ActionRunJob{job4}, + }, + } + + for _, tc := range testCases { + rerunJobs := GetAllRerunJobs(tc.job, jobs) + assert.ElementsMatch(t, tc.rerunJobs, rerunJobs) + } +} From 4ebd2274df6e3d3ba722b7a64a5f554a5b3f7b5f Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Thu, 21 Mar 2024 02:03:44 +0800 Subject: [PATCH 5/8] fmt --- services/actions/rerun_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/services/actions/rerun_test.go b/services/actions/rerun_test.go index cd91ad8d3a8a..a98de7b78826 100644 --- a/services/actions/rerun_test.go +++ b/services/actions/rerun_test.go @@ -7,6 +7,7 @@ import ( "testing" actions_model "code.gitea.io/gitea/models/actions" + "github.com/stretchr/testify/assert" ) From ea4f58c5f5807ee6587f74a6348d3ce27553157f Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Thu, 21 Mar 2024 02:10:32 +0800 Subject: [PATCH 6/8] add a warning --- options/locale/locale_en-US.ini | 1 + routers/web/repo/actions/actions.go | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 6622a25efd3b..dc8bc0d5eae3 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3627,6 +3627,7 @@ runs.scheduled = Scheduled runs.pushed_by = pushed by runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s runs.no_matching_online_runner_helper = No matching online runner with label: %s +runs.no_job_without_needs = The workflow must contain at least one job with no dependencies. runs.actor = Actor runs.status = Status runs.actors_no_select = All actors diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index f27329aa0f02..6059ad1414b7 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -104,8 +104,13 @@ func List(ctx *context.Context) { workflows = append(workflows, workflow) continue } - // Check whether have matching runner + // The workflow must contain at least one job without "needs". Otherwise, a deadlock will occur and no jobs will be able to run. + hasJobWithoutNeeds := false + // Check whether have matching runner and a job without "needs" for _, j := range wf.Jobs { + if !hasJobWithoutNeeds && len(j.Needs()) == 0 { + hasJobWithoutNeeds = true + } runsOnList := j.RunsOn() for _, ro := range runsOnList { if strings.Contains(ro, "${{") { @@ -123,6 +128,9 @@ func List(ctx *context.Context) { break } } + if !hasJobWithoutNeeds { + workflow.ErrMsg = ctx.Locale.TrString("actions.runs.no_job_without_needs") + } workflows = append(workflows, workflow) } } From be1e1c753e4c9d569b70318320b14b81d639534c Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Thu, 21 Mar 2024 03:06:30 +0800 Subject: [PATCH 7/8] update translation --- options/locale/locale_en-US.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index dc8bc0d5eae3..91e6e50ab9d4 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3627,7 +3627,7 @@ runs.scheduled = Scheduled runs.pushed_by = pushed by runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s runs.no_matching_online_runner_helper = No matching online runner with label: %s -runs.no_job_without_needs = The workflow must contain at least one job with no dependencies. +runs.no_job_without_needs = The workflow must contain at least one job without dependencies. runs.actor = Actor runs.status = Status runs.actors_no_select = All actors From 5021f55b1663e63ce0fda2247f15ddf72f52e220 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Thu, 21 Mar 2024 05:57:49 +0800 Subject: [PATCH 8/8] fix resp error --- routers/web/repo/actions/view.go | 1 + 1 file changed, 1 insertion(+) diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 00de3222f6f9..41989589bebc 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -312,6 +312,7 @@ func Rerun(ctx *context_module.Context) { return } } + ctx.JSON(http.StatusOK, struct{}{}) return }