From c1c5e3152e5472f2e407c23a56958ec926b1f28a Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 7 Feb 2023 14:34:59 +0800 Subject: [PATCH 01/11] feat: need approval for fork pr --- models/actions/run.go | 7 +--- models/actions/status.go | 4 ++ options/locale/locale_en-US.ini | 2 + routers/web/repo/actions/view.go | 47 +++++++++++++++++++++--- routers/web/web.go | 1 + services/actions/notifier_helper.go | 3 ++ web_src/js/components/RepoActionView.vue | 20 +++++++++- 7 files changed, 72 insertions(+), 12 deletions(-) diff --git a/models/actions/run.go b/models/actions/run.go index 14d191c814e34..4163598b30538 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -37,6 +37,7 @@ type ActionRun struct { Ref string CommitSHA string IsForkPullRequest bool + NeedApproval bool // NeedApproval could be true if IsForkPullRequest is true Event webhook_module.HookEventType EventPayload string `xorm:"LONGTEXT"` Status Status `xorm:"index"` @@ -164,10 +165,6 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork } run.Index = index - if run.Status.IsUnknown() { - run.Status = StatusWaiting - } - if err := db.Insert(ctx, run); err != nil { return err } @@ -191,7 +188,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork job.EraseNeeds() payload, _ := v.Marshal() status := StatusWaiting - if len(needs) > 0 { + if len(needs) > 0 || run.NeedApproval { status = StatusBlocked } runJobs = append(runJobs, &ActionRunJob{ diff --git a/models/actions/status.go b/models/actions/status.go index 059cf9bc09515..c97578f2acf4e 100644 --- a/models/actions/status.go +++ b/models/actions/status.go @@ -82,6 +82,10 @@ func (s Status) IsRunning() bool { return s == StatusRunning } +func (s Status) IsBlocked() bool { + return s == StatusBlocked +} + // In returns whether s is one of the given statuses func (s Status) In(statuses ...Status) bool { for _, v := range statuses { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a7506986f6966..be73cce03812d 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3338,3 +3338,5 @@ runs.open_tab = %d Open runs.closed_tab = %d Closed runs.commit = Commit runs.pushed_by = Pushed by + +need_approval_desc = Fork pull request need approval to run workflows. diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 5370310e8d9dc..0f0c340f26800 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -49,11 +49,12 @@ type ViewRequest struct { type ViewResponse struct { State struct { Run struct { - Link string `json:"link"` - Title string `json:"title"` - CanCancel bool `json:"canCancel"` - Done bool `json:"done"` - Jobs []*ViewJob `json:"jobs"` + Link string `json:"link"` + Title string `json:"title"` + CanCancel bool `json:"canCancel"` + CanApproval bool `json:"canApproval"` // the run needs an approval and the doer has permission to approve + Done bool `json:"done"` + Jobs []*ViewJob `json:"jobs"` } `json:"run"` CurrentJob struct { Title string `json:"title"` @@ -107,6 +108,7 @@ func ViewPost(ctx *context_module.Context) { resp.State.Run.Title = run.Title resp.State.Run.Link = run.Link() resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) + resp.State.Run.CanApproval = run.NeedApproval && !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) resp.State.Run.Done = run.Status.IsDone() resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json for _, v := range jobs { @@ -135,6 +137,9 @@ func ViewPost(ctx *context_module.Context) { resp.State.CurrentJob.Title = current.Name resp.State.CurrentJob.Detail = current.Status.LocaleString(ctx.Locale) + if run.NeedApproval { + resp.State.CurrentJob.Detail += ". " + ctx.Locale.Tr("actions.need_approval_desc") + } resp.State.CurrentJob.Steps = make([]*ViewJobStep, 0) // marshal to '[]' instead fo 'null' in json resp.Logs.StepsLog = make([]*ViewStepLog, 0) // marshal to '[]' instead fo 'null' in json if task != nil { @@ -261,6 +266,38 @@ func Cancel(ctx *context_module.Context) { ctx.JSON(http.StatusOK, struct{}{}) } +func Approve(ctx *context_module.Context) { + runIndex := ctx.ParamsInt64("run") + + current, jobs := getRunJobs(ctx, runIndex, -1) + if ctx.Written() { + return + } + run := current.Run + + if err := db.WithTx(ctx, func(ctx context.Context) error { + run.NeedApproval = false + if err := actions_model.UpdateRun(ctx, run, "need_approval"); err != nil { + return err + } + for _, job := range jobs { + if len(job.Needs) == 0 && job.Status.IsBlocked() { + job.Status = actions_model.StatusWaiting + _, err := actions_model.UpdateRunJob(ctx, job, nil, "status") + if err != nil { + return err + } + } + } + return nil + }); err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + + ctx.JSON(http.StatusOK, struct{}{}) +} + // getRunJobs gets the jobs of runIndex, and returns jobs[jobIndex], jobs. // Any error will be written to the ctx. // It never returns a nil job of an empty jobs, if the jobIndex is out of range, it will be treated as 0. diff --git a/routers/web/web.go b/routers/web/web.go index 6898956053521..397135600e7e7 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1286,6 +1286,7 @@ func RegisterRoutes(m *web.Route) { m.Post("/rerun", reqRepoActionsWriter, actions.Rerun) }) m.Post("/cancel", reqRepoActionsWriter, actions.Cancel) + m.Post("/approve", reqRepoActionsWriter, actions.Approve) }) }, reqRepoActionsReader, actions.MustEnableActions) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 5b8f6bfdf6ef4..7ead8b84dedf2 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -166,6 +166,9 @@ func notify(ctx context.Context, input *notifyInput) error { EventPayload: string(p), Status: actions_model.StatusWaiting, } + if run.IsForkPullRequest { + run.NeedApproval = true + } jobs, err := jobparser.Parse(content) if err != nil { log.Error("jobparser.Parse: %v", err) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 4c7408d1b3c2a..1c337c9d8666d 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -3,7 +3,10 @@
{{ run.title }} - +
@@ -95,6 +98,7 @@ const sfc = { link: '', title: '', canCancel: false, + canApproval: false, done: false, jobs: [ // { @@ -169,6 +173,10 @@ const sfc = { cancelRun() { this.fetch(`${this.run.link}/cancel`); }, + // approve a run + approveRun() { + this.fetch(`${this.run.link}/approve`); + }, createLogLine(line) { const div = document.createElement('div'); @@ -296,7 +304,15 @@ export function initRepositoryActionView() { cursor: pointer; transition:transform 0.2s; }; - button.run_cancel:hover{ + button.run_approve { + border: none; + color: var(--color-green); + background-color: transparent; + outline: none; + cursor: pointer; + transition:transform 0.2s; + }; + button.run_cancel:hover, button.run_approve:hover { transform:scale(130%); }; } From 73a68a0472ffffda30ff87632179e20fc128fee0 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 7 Feb 2023 14:41:01 +0800 Subject: [PATCH 02/11] fix: canApprove --- routers/web/repo/actions/view.go | 14 +++++++------- web_src/js/components/RepoActionView.vue | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 0f0c340f26800..d66cc904056d9 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -49,12 +49,12 @@ type ViewRequest struct { type ViewResponse struct { State struct { Run struct { - Link string `json:"link"` - Title string `json:"title"` - CanCancel bool `json:"canCancel"` - CanApproval bool `json:"canApproval"` // the run needs an approval and the doer has permission to approve - Done bool `json:"done"` - Jobs []*ViewJob `json:"jobs"` + Link string `json:"link"` + Title string `json:"title"` + CanCancel bool `json:"canCancel"` + CanApprove bool `json:"canApprove"` // the run needs an approval and the doer has permission to approve + Done bool `json:"done"` + Jobs []*ViewJob `json:"jobs"` } `json:"run"` CurrentJob struct { Title string `json:"title"` @@ -108,7 +108,7 @@ func ViewPost(ctx *context_module.Context) { resp.State.Run.Title = run.Title resp.State.Run.Link = run.Link() resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) - resp.State.Run.CanApproval = run.NeedApproval && !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) + resp.State.Run.CanApprove = run.NeedApproval && ctx.Repo.CanWrite(unit.TypeActions) resp.State.Run.Done = run.Status.IsDone() resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json for _, v := range jobs { diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 1c337c9d8666d..5e30a9e6a7183 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -3,7 +3,7 @@
{{ run.title }} -