@@ -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 , curWorkflowID := prepareWorkflowTemplate (ctx , commit )
82+ if ctx .Written () {
83+ return
84+ }
85+ prepareWorkflowDispatchTemplate (ctx , workflows , curWorkflowID )
8186 if ctx .Written () {
8287 return
8388 }
@@ -112,55 +117,41 @@ func WorkflowDispatchInputs(ctx *context.Context) {
112117 ctx .ServerError ("GetTagCommit/GetBranchCommit" , err )
113118 return
114119 }
115- prepareWorkflowDispatchTemplate (ctx , commit )
120+ workflows , curWorkflowID := prepareWorkflowTemplate (ctx , commit )
121+ if ctx .Written () {
122+ return
123+ }
124+ prepareWorkflowDispatchTemplate (ctx , workflows , curWorkflowID )
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 ) {
123- workflowID := ctx .FormString ("workflow" )
124- ctx .Data ["CurWorkflow" ] = workflowID
125- ctx .Data ["CurWorkflowExists" ] = false
126-
127- var curWorkflow * model.Workflow
131+ func prepareWorkflowTemplate (ctx * context.Context , commit * git.Commit ) (workflows []WorkflowInfo , curWorkflowID string ) {
132+ curWorkflowID = ctx .FormString ("workflow" )
128133
129134 _ , entries , err := actions .ListWorkflows (commit )
130135 if err != nil {
131136 ctx .ServerError ("ListWorkflows" , err )
132- return nil
137+ return nil , ""
133138 }
134139
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 ))
140+ workflows = make ([]WorkflowInfo , 0 , len (entries ))
151141 for _ , entry := range entries {
152- workflow := Workflow {Entry : * entry }
142+ workflow := WorkflowInfo {Entry : * entry }
153143 content , err := actions .GetContentFromEntry (entry )
154144 if err != nil {
155145 ctx .ServerError ("GetContentFromEntry" , err )
156- return nil
146+ return nil , ""
157147 }
158- wf , err := model .ReadWorkflow (bytes .NewReader (content ))
148+ wf , err := act_model .ReadWorkflow (bytes .NewReader (content ))
159149 if err != nil {
160150 workflow .ErrMsg = ctx .Locale .TrString ("actions.runs.invalid_workflow_helper" , err .Error ())
161151 workflows = append (workflows , workflow )
162152 continue
163153 }
154+ workflow .Workflow = wf
164155 // The workflow must contain at least one job without "needs". Otherwise, a deadlock will occur and no jobs will be able to run.
165156 hasJobWithoutNeeds := false
166157 // Check whether you have matching runner and a job without "needs"
@@ -173,22 +164,6 @@ func prepareWorkflowDispatchTemplate(ctx *context.Context, commit *git.Commit) (
173164 if ! hasJobWithoutNeeds && len (j .Needs ()) == 0 {
174165 hasJobWithoutNeeds = true
175166 }
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- }
192167 }
193168 if ! hasJobWithoutNeeds {
194169 workflow .ErrMsg = ctx .Locale .TrString ("actions.runs.no_job_without_needs" )
@@ -197,61 +172,75 @@ func prepareWorkflowDispatchTemplate(ctx *context.Context, commit *git.Commit) (
197172 workflow .ErrMsg = ctx .Locale .TrString ("actions.runs.no_job" )
198173 }
199174 workflows = append (workflows , workflow )
200-
201- if workflow .Entry .Name () == workflowID {
202- curWorkflow = wf
203- ctx .Data ["CurWorkflowExists" ] = true
204- }
205175 }
206176
207177 ctx .Data ["workflows" ] = workflows
208178 ctx .Data ["RepoLink" ] = ctx .Repo .Repository .Link ()
209-
179+ ctx . Data [ "AllowDisableOrEnableWorkflow" ] = ctx . Repo . IsAdmin ()
210180 actionsConfig := ctx .Repo .Repository .MustGetUnit (ctx , unit .TypeActions ).ActionsConfig ()
211181 ctx .Data ["ActionsConfig" ] = actionsConfig
182+ ctx .Data ["CurWorkflow" ] = curWorkflowID
183+ ctx .Data ["CurWorkflowDisabled" ] = actionsConfig .IsWorkflowDisabled (curWorkflowID )
212184
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
185+ return workflows , curWorkflowID
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+ func prepareWorkflowDispatchTemplate (ctx * context.Context , workflowInfos []WorkflowInfo , curWorkflowID string ) {
189+ actionsConfig := ctx .Repo .Repository .MustGetUnit (ctx , unit .TypeActions ).ActionsConfig ()
190+ if curWorkflowID == "" || ! ctx .Repo .CanWrite (unit .TypeActions ) || actionsConfig .IsWorkflowDisabled (curWorkflowID ) {
191+ return
192+ }
193+
194+ var curWorkflow * act_model.Workflow
195+ for _ , workflowInfo := range workflowInfos {
196+ if workflowInfo .Entry .Name () == curWorkflowID {
197+ if workflowInfo .Workflow == nil {
198+ log .Debug ("CurWorkflowID %s is found but its workflowInfo.Workflow is nil" , curWorkflowID )
199+ return
248200 }
201+ curWorkflow = workflowInfo .Workflow
202+ break
249203 }
250204 }
251- return workflows
205+
206+ if curWorkflow == nil {
207+ return
208+ }
209+
210+ ctx .Data ["CurWorkflowExists" ] = true
211+ curWfDispatchCfg := workflowDispatchConfig (curWorkflow )
212+ if curWfDispatchCfg == nil {
213+ return
214+ }
215+
216+ ctx .Data ["WorkflowDispatchConfig" ] = curWfDispatchCfg
217+
218+ branchOpts := git_model.FindBranchOptions {
219+ RepoID : ctx .Repo .Repository .ID ,
220+ IsDeletedBranch : optional .Some (false ),
221+ ListOptions : db.ListOptions {
222+ ListAll : true ,
223+ },
224+ }
225+ branches , err := git_model .FindBranchNames (ctx , branchOpts )
226+ if err != nil {
227+ ctx .ServerError ("FindBranchNames" , err )
228+ return
229+ }
230+ // always put default branch on the top
231+ branches = util .SliceRemoveAll (branches , ctx .Repo .Repository .DefaultBranch )
232+ branches = append ([]string {ctx .Repo .Repository .DefaultBranch }, branches ... )
233+ ctx .Data ["Branches" ] = branches
234+
235+ tags , err := repo_model .GetTagNamesByRepoID (ctx , ctx .Repo .Repository .ID )
236+ if err != nil {
237+ ctx .ServerError ("GetTagNamesByRepoID" , err )
238+ return
239+ }
240+ ctx .Data ["Tags" ] = tags
252241}
253242
254- func prepareWorkflowList (ctx * context.Context , workflows []Workflow ) {
243+ func prepareWorkflowList (ctx * context.Context , workflows []WorkflowInfo ) {
255244 actorID := ctx .FormInt64 ("actor" )
256245 status := ctx .FormInt ("status" )
257246 workflowID := ctx .FormString ("workflow" )
@@ -302,6 +291,45 @@ func prepareWorkflowList(ctx *context.Context, workflows []Workflow) {
302291 log .Error ("LoadIsRefDeleted" , err )
303292 }
304293
294+ // Check for each run if there is at least one online runner that can run its jobs
295+ runErrors := make (map [int64 ]string )
296+ runners , err := db .Find [actions_model.ActionRunner ](ctx , actions_model.FindRunnerOptions {
297+ RepoID : ctx .Repo .Repository .ID ,
298+ IsOnline : optional .Some (true ),
299+ WithAvailable : true ,
300+ })
301+ if err != nil {
302+ ctx .ServerError ("FindRunners" , err )
303+ return
304+ }
305+ for _ , run := range runs {
306+ if ! run .Status .In (actions_model .StatusWaiting , actions_model .StatusRunning ) {
307+ continue
308+ }
309+ jobs , err := actions_model .GetRunJobsByRunID (ctx , run .ID )
310+ if err != nil {
311+ ctx .ServerError ("GetRunJobsByRunID" , err )
312+ return
313+ }
314+ for _ , job := range jobs {
315+ if ! job .Status .IsWaiting () {
316+ continue
317+ }
318+ hasOnlineRunner := false
319+ for _ , runner := range runners {
320+ if runner .CanMatchLabels (job .RunsOn ) {
321+ hasOnlineRunner = true
322+ break
323+ }
324+ }
325+ if ! hasOnlineRunner {
326+ runErrors [run .ID ] = ctx .Locale .TrString ("actions.runs.no_matching_online_runner_helper" , strings .Join (job .RunsOn , "," ))
327+ break
328+ }
329+ }
330+ }
331+ ctx .Data ["RunErrors" ] = runErrors
332+
305333 ctx .Data ["Runs" ] = runs
306334
307335 actors , err := actions_model .GetActors (ctx , ctx .Repo .Repository .ID )
@@ -362,7 +390,7 @@ type WorkflowDispatch struct {
362390 Inputs []WorkflowDispatchInput
363391}
364392
365- func workflowDispatchConfig (w * model .Workflow ) * WorkflowDispatch {
393+ func workflowDispatchConfig (w * act_model .Workflow ) * WorkflowDispatch {
366394 switch w .RawOn .Kind {
367395 case yaml .ScalarNode :
368396 var val string
0 commit comments