@@ -28,7 +28,7 @@ import (
2828 "code.gitea.io/gitea/services/context"
2929 "code.gitea.io/gitea/services/convert"
3030
31- "github.com/nektos/act/pkg/model"
31+ act_model "github.com/nektos/act/pkg/model"
3232 "gopkg.in/yaml.v3"
3333)
3434
@@ -38,9 +38,10 @@ const (
3838 tplViewActions templates.TplName = "repo/actions/view"
3939)
4040
41- type Workflow struct {
42- Entry git.TreeEntry
43- ErrMsg string
41+ type WorkflowInfo struct {
42+ Entry git.TreeEntry
43+ ErrMsg string
44+ Workflow * act_model.Workflow
4445}
4546
4647// MustEnableActions check if actions are enabled in settings
@@ -77,7 +78,11 @@ func List(ctx *context.Context) {
7778 return
7879 }
7980
80- workflows := prepareWorkflowDispatchTemplate (ctx , commit )
81+ workflows := prepareWorkflowTemplate (ctx , commit )
82+ if ctx .Written () {
83+ return
84+ }
85+ prepareWorkflowDispatchTemplate (ctx , workflows )
8186 if ctx .Written () {
8287 return
8388 }
@@ -112,55 +117,42 @@ func WorkflowDispatchInputs(ctx *context.Context) {
112117 ctx .ServerError ("GetTagCommit/GetBranchCommit" , err )
113118 return
114119 }
115- prepareWorkflowDispatchTemplate (ctx , commit )
120+ workflows := prepareWorkflowTemplate (ctx , commit )
121+ if ctx .Written () {
122+ return
123+ }
124+ prepareWorkflowDispatchTemplate (ctx , workflows )
116125 if ctx .Written () {
117126 return
118127 }
119128 ctx .HTML (http .StatusOK , tplDispatchInputsActions )
120129}
121130
122- func prepareWorkflowDispatchTemplate (ctx * context.Context , commit * git.Commit ) (workflows []Workflow ) {
131+ func prepareWorkflowTemplate (ctx * context.Context , commit * git.Commit ) (workflows []WorkflowInfo ) {
123132 workflowID := ctx .FormString ("workflow" )
124133 ctx .Data ["CurWorkflow" ] = workflowID
125- ctx .Data ["CurWorkflowExists" ] = false
126-
127- var curWorkflow * model.Workflow
128134
129135 _ , entries , err := actions .ListWorkflows (commit )
130136 if err != nil {
131137 ctx .ServerError ("ListWorkflows" , err )
132138 return nil
133139 }
134140
135- // Get all runner labels
136- runners , err := db .Find [actions_model.ActionRunner ](ctx , actions_model.FindRunnerOptions {
137- RepoID : ctx .Repo .Repository .ID ,
138- IsOnline : optional .Some (true ),
139- WithAvailable : true ,
140- })
141- if err != nil {
142- ctx .ServerError ("FindRunners" , err )
143- return nil
144- }
145- allRunnerLabels := make (container.Set [string ])
146- for _ , r := range runners {
147- allRunnerLabels .AddMultiple (r .AgentLabels ... )
148- }
149-
150- workflows = make ([]Workflow , 0 , len (entries ))
141+ workflows = make ([]WorkflowInfo , 0 , len (entries ))
151142 for _ , entry := range entries {
152- workflow := Workflow {Entry : * entry }
143+ workflow := WorkflowInfo {Entry : * entry }
153144 content , err := actions .GetContentFromEntry (entry )
154145 if err != nil {
155146 ctx .ServerError ("GetContentFromEntry" , err )
156147 return nil
157148 }
158- wf , err := model .ReadWorkflow (bytes .NewReader (content ))
149+ wf , err := act_model .ReadWorkflow (bytes .NewReader (content ))
159150 if err != nil {
160151 workflow .ErrMsg = ctx .Locale .TrString ("actions.runs.invalid_workflow_helper" , err .Error ())
161152 workflows = append (workflows , workflow )
162153 continue
163154 }
155+ workflow .Workflow = wf
164156 // The workflow must contain at least one job without "needs". Otherwise, a deadlock will occur and no jobs will be able to run.
165157 hasJobWithoutNeeds := false
166158 // Check whether you have matching runner and a job without "needs"
@@ -173,22 +165,6 @@ func prepareWorkflowDispatchTemplate(ctx *context.Context, commit *git.Commit) (
173165 if ! hasJobWithoutNeeds && len (j .Needs ()) == 0 {
174166 hasJobWithoutNeeds = true
175167 }
176- runsOnList := j .RunsOn ()
177- for _ , ro := range runsOnList {
178- if strings .Contains (ro , "${{" ) {
179- // Skip if it contains expressions.
180- // The expressions could be very complex and could not be evaluated here,
181- // so just skip it, it's OK since it's just a tooltip message.
182- continue
183- }
184- if ! allRunnerLabels .Contains (ro ) {
185- workflow .ErrMsg = ctx .Locale .TrString ("actions.runs.no_matching_online_runner_helper" , ro )
186- break
187- }
188- }
189- if workflow .ErrMsg != "" {
190- break
191- }
192168 }
193169 if ! hasJobWithoutNeeds {
194170 workflow .ErrMsg = ctx .Locale .TrString ("actions.runs.no_job_without_needs" )
@@ -197,61 +173,81 @@ func prepareWorkflowDispatchTemplate(ctx *context.Context, commit *git.Commit) (
197173 workflow .ErrMsg = ctx .Locale .TrString ("actions.runs.no_job" )
198174 }
199175 workflows = append (workflows , workflow )
200-
201- if workflow .Entry .Name () == workflowID {
202- curWorkflow = wf
203- ctx .Data ["CurWorkflowExists" ] = true
204- }
205176 }
206177
207178 ctx .Data ["workflows" ] = workflows
208179 ctx .Data ["RepoLink" ] = ctx .Repo .Repository .Link ()
209-
180+ ctx . Data [ "AllowDisableOrEnableWorkflow" ] = ctx . Repo . IsAdmin ()
210181 actionsConfig := ctx .Repo .Repository .MustGetUnit (ctx , unit .TypeActions ).ActionsConfig ()
211182 ctx .Data ["ActionsConfig" ] = actionsConfig
212183
213- if len (workflowID ) > 0 && ctx .Repo .CanWrite (unit .TypeActions ) {
214- ctx .Data ["AllowDisableOrEnableWorkflow" ] = ctx .Repo .IsAdmin ()
215- isWorkflowDisabled := actionsConfig .IsWorkflowDisabled (workflowID )
216- ctx .Data ["CurWorkflowDisabled" ] = isWorkflowDisabled
217-
218- if ! isWorkflowDisabled && curWorkflow != nil {
219- workflowDispatchConfig := workflowDispatchConfig (curWorkflow )
220- if workflowDispatchConfig != nil {
221- ctx .Data ["WorkflowDispatchConfig" ] = workflowDispatchConfig
222-
223- branchOpts := git_model.FindBranchOptions {
224- RepoID : ctx .Repo .Repository .ID ,
225- IsDeletedBranch : optional .Some (false ),
226- ListOptions : db.ListOptions {
227- ListAll : true ,
228- },
229- }
230- branches , err := git_model .FindBranchNames (ctx , branchOpts )
231- if err != nil {
232- ctx .ServerError ("FindBranchNames" , err )
233- return nil
234- }
235- // always put default branch on the top if it exists
236- if slices .Contains (branches , ctx .Repo .Repository .DefaultBranch ) {
237- branches = util .SliceRemoveAll (branches , ctx .Repo .Repository .DefaultBranch )
238- branches = append ([]string {ctx .Repo .Repository .DefaultBranch }, branches ... )
239- }
240- ctx .Data ["Branches" ] = branches
184+ if len (workflowID ) > 0 {
185+ ctx .Data ["CurWorkflowDisabled" ] = actionsConfig .IsWorkflowDisabled (workflowID )
186+ }
241187
242- tags , err := repo_model .GetTagNamesByRepoID (ctx , ctx .Repo .Repository .ID )
243- if err != nil {
244- ctx .ServerError ("GetTagNamesByRepoID" , err )
245- return nil
246- }
247- ctx .Data ["Tags" ] = tags
188+ return workflows
189+ }
190+
191+ func prepareWorkflowDispatchTemplate (ctx * context.Context , workflowInfos []WorkflowInfo ) {
192+ workflowID := ctx .FormString ("workflow" )
193+ actionsConfig := ctx .Repo .Repository .MustGetUnit (ctx , unit .TypeActions ).ActionsConfig ()
194+ if len (workflowID ) == 0 || ! ctx .Repo .CanWrite (unit .TypeActions ) || actionsConfig .IsWorkflowDisabled (workflowID ) {
195+ return
196+ }
197+
198+ ctx .Data ["CurWorkflowExists" ] = false
199+ var curWorkflow * act_model.Workflow
200+ for _ , workflowInfo := range workflowInfos {
201+ if workflowInfo .Entry .Name () == workflowID {
202+ if workflowInfo .Workflow == nil {
203+ log .Error ("%s workflowInfo.Workflow is nil" , workflowID )
204+ return
248205 }
206+ curWorkflow = workflowInfo .Workflow
207+ ctx .Data ["CurWorkflowExists" ] = true
208+ break
249209 }
250210 }
251- return workflows
211+
212+ if curWorkflow == nil {
213+ return
214+ }
215+
216+ workflowDispatchConfig := workflowDispatchConfig (curWorkflow )
217+ if workflowDispatchConfig == nil {
218+ return
219+ }
220+
221+ ctx .Data ["WorkflowDispatchConfig" ] = workflowDispatchConfig
222+
223+ branchOpts := git_model.FindBranchOptions {
224+ RepoID : ctx .Repo .Repository .ID ,
225+ IsDeletedBranch : optional .Some (false ),
226+ ListOptions : db.ListOptions {
227+ ListAll : true ,
228+ },
229+ }
230+ branches , err := git_model .FindBranchNames (ctx , branchOpts )
231+ if err != nil {
232+ ctx .ServerError ("FindBranchNames" , err )
233+ return
234+ }
235+ // always put default branch on the top if it exists
236+ if slices .Contains (branches , ctx .Repo .Repository .DefaultBranch ) {
237+ branches = util .SliceRemoveAll (branches , ctx .Repo .Repository .DefaultBranch )
238+ branches = append ([]string {ctx .Repo .Repository .DefaultBranch }, branches ... )
239+ }
240+ ctx .Data ["Branches" ] = branches
241+
242+ tags , err := repo_model .GetTagNamesByRepoID (ctx , ctx .Repo .Repository .ID )
243+ if err != nil {
244+ ctx .ServerError ("GetTagNamesByRepoID" , err )
245+ return
246+ }
247+ ctx .Data ["Tags" ] = tags
252248}
253249
254- func prepareWorkflowList (ctx * context.Context , workflows []Workflow ) {
250+ func prepareWorkflowList (ctx * context.Context , workflows []WorkflowInfo ) {
255251 actorID := ctx .FormInt64 ("actor" )
256252 status := ctx .FormInt ("status" )
257253 workflowID := ctx .FormString ("workflow" )
@@ -302,6 +298,45 @@ func prepareWorkflowList(ctx *context.Context, workflows []Workflow) {
302298 log .Error ("LoadIsRefDeleted" , err )
303299 }
304300
301+ // Check for each run if there is at least one online runner that can run its jobs
302+ runErrors := make (map [int64 ]string )
303+ runners , err := db .Find [actions_model.ActionRunner ](ctx , actions_model.FindRunnerOptions {
304+ RepoID : ctx .Repo .Repository .ID ,
305+ IsOnline : optional .Some (true ),
306+ WithAvailable : true ,
307+ })
308+ if err != nil {
309+ ctx .ServerError ("FindRunners" , err )
310+ return
311+ }
312+ for _ , run := range runs {
313+ if ! run .Status .In (actions_model .StatusWaiting , actions_model .StatusRunning ) {
314+ continue
315+ }
316+ jobs , err := actions_model .GetRunJobsByRunID (ctx , run .ID )
317+ if err != nil {
318+ ctx .ServerError ("GetRunJobsByRunID" , err )
319+ return
320+ }
321+ for _ , job := range jobs {
322+ if ! job .Status .IsWaiting () {
323+ continue
324+ }
325+ hasOnlineRunner := false
326+ for _ , runner := range runners {
327+ if runner .CanMatchLabels (job .RunsOn ) {
328+ hasOnlineRunner = true
329+ break
330+ }
331+ }
332+ if ! hasOnlineRunner {
333+ runErrors [run .ID ] = ctx .Locale .TrString ("actions.runs.no_matching_online_runner_helper" , strings .Join (job .RunsOn , "," ))
334+ break
335+ }
336+ }
337+ }
338+ ctx .Data ["RunErrors" ] = runErrors
339+
305340 ctx .Data ["Runs" ] = runs
306341
307342 actors , err := actions_model .GetActors (ctx , ctx .Repo .Repository .ID )
@@ -362,7 +397,7 @@ type WorkflowDispatch struct {
362397 Inputs []WorkflowDispatchInput
363398}
364399
365- func workflowDispatchConfig (w * model .Workflow ) * WorkflowDispatch {
400+ func workflowDispatchConfig (w * act_model .Workflow ) * WorkflowDispatch {
366401 switch w .RawOn .Kind {
367402 case yaml .ScalarNode :
368403 var val string
0 commit comments