@@ -49,11 +49,12 @@ type ViewRequest struct {
4949type ViewResponse struct {
5050 State struct {
5151 Run struct {
52- Link string `json:"link"`
53- Title string `json:"title"`
54- CanCancel bool `json:"canCancel"`
55- Done bool `json:"done"`
56- Jobs []* ViewJob `json:"jobs"`
52+ Link string `json:"link"`
53+ Title string `json:"title"`
54+ CanCancel bool `json:"canCancel"`
55+ CanApprove bool `json:"canApprove"` // the run needs an approval and the doer has permission to approve
56+ Done bool `json:"done"`
57+ Jobs []* ViewJob `json:"jobs"`
5758 } `json:"run"`
5859 CurrentJob struct {
5960 Title string `json:"title"`
@@ -107,6 +108,7 @@ func ViewPost(ctx *context_module.Context) {
107108 resp .State .Run .Title = run .Title
108109 resp .State .Run .Link = run .Link ()
109110 resp .State .Run .CanCancel = ! run .Status .IsDone () && ctx .Repo .CanWrite (unit .TypeActions )
111+ resp .State .Run .CanApprove = run .NeedApproval && ctx .Repo .CanWrite (unit .TypeActions )
110112 resp .State .Run .Done = run .Status .IsDone ()
111113 resp .State .Run .Jobs = make ([]* ViewJob , 0 , len (jobs )) // marshal to '[]' instead fo 'null' in json
112114 for _ , v := range jobs {
@@ -135,6 +137,9 @@ func ViewPost(ctx *context_module.Context) {
135137
136138 resp .State .CurrentJob .Title = current .Name
137139 resp .State .CurrentJob .Detail = current .Status .LocaleString (ctx .Locale )
140+ if run .NeedApproval {
141+ resp .State .CurrentJob .Detail = ctx .Locale .Tr ("actions.need_approval_desc" )
142+ }
138143 resp .State .CurrentJob .Steps = make ([]* ViewJobStep , 0 ) // marshal to '[]' instead fo 'null' in json
139144 resp .Logs .StepsLog = make ([]* ViewStepLog , 0 ) // marshal to '[]' instead fo 'null' in json
140145 if task != nil {
@@ -261,6 +266,40 @@ func Cancel(ctx *context_module.Context) {
261266 ctx .JSON (http .StatusOK , struct {}{})
262267}
263268
269+ func Approve (ctx * context_module.Context ) {
270+ runIndex := ctx .ParamsInt64 ("run" )
271+
272+ current , jobs := getRunJobs (ctx , runIndex , - 1 )
273+ if ctx .Written () {
274+ return
275+ }
276+ run := current .Run
277+ doer := ctx .Doer
278+
279+ if err := db .WithTx (ctx , func (ctx context.Context ) error {
280+ run .NeedApproval = false
281+ run .ApprovedBy = doer .ID
282+ if err := actions_model .UpdateRun (ctx , run , "need_approval" , "approved_by" ); err != nil {
283+ return err
284+ }
285+ for _ , job := range jobs {
286+ if len (job .Needs ) == 0 && job .Status .IsBlocked () {
287+ job .Status = actions_model .StatusWaiting
288+ _ , err := actions_model .UpdateRunJob (ctx , job , nil , "status" )
289+ if err != nil {
290+ return err
291+ }
292+ }
293+ }
294+ return nil
295+ }); err != nil {
296+ ctx .Error (http .StatusInternalServerError , err .Error ())
297+ return
298+ }
299+
300+ ctx .JSON (http .StatusOK , struct {}{})
301+ }
302+
264303// getRunJobs gets the jobs of runIndex, and returns jobs[jobIndex], jobs.
265304// Any error will be written to the ctx.
266305// It never returns a nil job of an empty jobs, if the jobIndex is out of range, it will be treated as 0.
0 commit comments