mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Add rerun workflow button and refactor to use SVG octicons (#24350)
Changes: - Add rerun workflow button. Then users can rerun the whole workflow by only one-click. - Refactor to use SVG octicons in RepoActionView.vue    --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		@@ -55,6 +55,7 @@ type ViewResponse struct {
 | 
				
			|||||||
			Status     string     `json:"status"`
 | 
								Status     string     `json:"status"`
 | 
				
			||||||
			CanCancel  bool       `json:"canCancel"`
 | 
								CanCancel  bool       `json:"canCancel"`
 | 
				
			||||||
			CanApprove bool       `json:"canApprove"` // the run needs an approval and the doer has permission to approve
 | 
								CanApprove bool       `json:"canApprove"` // the run needs an approval and the doer has permission to approve
 | 
				
			||||||
 | 
								CanRerun   bool       `json:"canRerun"`
 | 
				
			||||||
			Done       bool       `json:"done"`
 | 
								Done       bool       `json:"done"`
 | 
				
			||||||
			Jobs       []*ViewJob `json:"jobs"`
 | 
								Jobs       []*ViewJob `json:"jobs"`
 | 
				
			||||||
			Commit     ViewCommit `json:"commit"`
 | 
								Commit     ViewCommit `json:"commit"`
 | 
				
			||||||
@@ -136,6 +137,7 @@ func ViewPost(ctx *context_module.Context) {
 | 
				
			|||||||
	resp.State.Run.Link = run.Link()
 | 
						resp.State.Run.Link = run.Link()
 | 
				
			||||||
	resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
 | 
						resp.State.Run.CanCancel = !run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
 | 
				
			||||||
	resp.State.Run.CanApprove = run.NeedApproval && ctx.Repo.CanWrite(unit.TypeActions)
 | 
						resp.State.Run.CanApprove = run.NeedApproval && ctx.Repo.CanWrite(unit.TypeActions)
 | 
				
			||||||
 | 
						resp.State.Run.CanRerun = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions)
 | 
				
			||||||
	resp.State.Run.Done = run.Status.IsDone()
 | 
						resp.State.Run.Done = run.Status.IsDone()
 | 
				
			||||||
	resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json
 | 
						resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json
 | 
				
			||||||
	resp.State.Run.Status = run.Status.String()
 | 
						resp.State.Run.Status = run.Status.String()
 | 
				
			||||||
@@ -238,7 +240,7 @@ func ViewPost(ctx *context_module.Context) {
 | 
				
			|||||||
	ctx.JSON(http.StatusOK, resp)
 | 
						ctx.JSON(http.StatusOK, resp)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Rerun(ctx *context_module.Context) {
 | 
					func RerunOne(ctx *context_module.Context) {
 | 
				
			||||||
	runIndex := ctx.ParamsInt64("run")
 | 
						runIndex := ctx.ParamsInt64("run")
 | 
				
			||||||
	jobIndex := ctx.ParamsInt64("job")
 | 
						jobIndex := ctx.ParamsInt64("job")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -246,10 +248,37 @@ func Rerun(ctx *context_module.Context) {
 | 
				
			|||||||
	if ctx.Written() {
 | 
						if ctx.Written() {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := rerunJob(ctx, job); err != nil {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusInternalServerError, err.Error())
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.JSON(http.StatusOK, struct{}{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func RerunAll(ctx *context_module.Context) {
 | 
				
			||||||
 | 
						runIndex := ctx.ParamsInt64("run")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, jobs := getRunJobs(ctx, runIndex, 0)
 | 
				
			||||||
 | 
						if ctx.Written() {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, j := range jobs {
 | 
				
			||||||
 | 
							if err := rerunJob(ctx, j); err != nil {
 | 
				
			||||||
 | 
								ctx.Error(http.StatusInternalServerError, err.Error())
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.JSON(http.StatusOK, struct{}{})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob) error {
 | 
				
			||||||
	status := job.Status
 | 
						status := job.Status
 | 
				
			||||||
	if !status.IsDone() {
 | 
						if !status.IsDone() {
 | 
				
			||||||
		ctx.JSON(http.StatusOK, struct{}{})
 | 
							return nil
 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	job.TaskID = 0
 | 
						job.TaskID = 0
 | 
				
			||||||
@@ -261,13 +290,11 @@ func Rerun(ctx *context_module.Context) {
 | 
				
			|||||||
		_, err := actions_model.UpdateRunJob(ctx, job, builder.Eq{"status": status}, "task_id", "status", "started", "stopped")
 | 
							_, err := actions_model.UpdateRunJob(ctx, job, builder.Eq{"status": status}, "task_id", "status", "started", "stopped")
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}); err != nil {
 | 
						}); err != nil {
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, err.Error())
 | 
							return err
 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	actions_service.CreateCommitStatus(ctx, job)
 | 
						actions_service.CreateCommitStatus(ctx, job)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
	ctx.JSON(http.StatusOK, struct{}{})
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Cancel(ctx *context_module.Context) {
 | 
					func Cancel(ctx *context_module.Context) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1186,10 +1186,11 @@ func registerRoutes(m *web.Route) {
 | 
				
			|||||||
					m.Combo("").
 | 
										m.Combo("").
 | 
				
			||||||
						Get(actions.View).
 | 
											Get(actions.View).
 | 
				
			||||||
						Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
 | 
											Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
 | 
				
			||||||
					m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
 | 
										m.Post("/rerun", reqRepoActionsWriter, actions.RerunOne)
 | 
				
			||||||
				})
 | 
									})
 | 
				
			||||||
				m.Post("/cancel", reqRepoActionsWriter, actions.Cancel)
 | 
									m.Post("/cancel", reqRepoActionsWriter, actions.Cancel)
 | 
				
			||||||
				m.Post("/approve", reqRepoActionsWriter, actions.Approve)
 | 
									m.Post("/approve", reqRepoActionsWriter, actions.Approve)
 | 
				
			||||||
 | 
									m.Post("/rerun", reqRepoActionsWriter, actions.RerunAll)
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		}, reqRepoActionsReader, actions.MustEnableActions)
 | 
							}, reqRepoActionsReader, actions.MustEnableActions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,11 +6,14 @@
 | 
				
			|||||||
        <div class="action-title">
 | 
					        <div class="action-title">
 | 
				
			||||||
          {{ run.title }}
 | 
					          {{ run.title }}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <button class="run_approve" @click="approveRun()" v-if="run.canApprove">
 | 
					        <button class="action-control-button text green" @click="approveRun()" v-if="run.canApprove">
 | 
				
			||||||
          <i class="play circle outline icon"/>
 | 
					          <SvgIcon name="octicon-play" :size="20"/>
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
        <button class="run_cancel" @click="cancelRun()" v-else-if="run.canCancel">
 | 
					        <button class="action-control-button text red" @click="cancelRun()" v-else-if="run.canCancel">
 | 
				
			||||||
          <i class="stop circle outline icon"/>
 | 
					          <SvgIcon name="octicon-x-circle-fill" :size="20"/>
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					        <button class="action-control-button text green" @click="rerun()" v-else-if="run.canRerun">
 | 
				
			||||||
 | 
					          <SvgIcon name="octicon-sync" :size="20"/>
 | 
				
			||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="action-commit-summary">
 | 
					      <div class="action-commit-summary">
 | 
				
			||||||
@@ -106,6 +109,7 @@ const sfc = {
 | 
				
			|||||||
        status: '',
 | 
					        status: '',
 | 
				
			||||||
        canCancel: false,
 | 
					        canCancel: false,
 | 
				
			||||||
        canApprove: false,
 | 
					        canApprove: false,
 | 
				
			||||||
 | 
					        canRerun: false,
 | 
				
			||||||
        done: false,
 | 
					        done: false,
 | 
				
			||||||
        jobs: [
 | 
					        jobs: [
 | 
				
			||||||
          // {
 | 
					          // {
 | 
				
			||||||
@@ -193,6 +197,11 @@ const sfc = {
 | 
				
			|||||||
      await this.fetchPost(`${jobLink}/rerun`);
 | 
					      await this.fetchPost(`${jobLink}/rerun`);
 | 
				
			||||||
      window.location.href = jobLink;
 | 
					      window.location.href = jobLink;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    // rerun workflow
 | 
				
			||||||
 | 
					    async rerun() {
 | 
				
			||||||
 | 
					      await this.fetchPost(`${this.run.link}/rerun`);
 | 
				
			||||||
 | 
					      window.location.href = this.run.link;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    // cancel a run
 | 
					    // cancel a run
 | 
				
			||||||
    cancelRun() {
 | 
					    cancelRun() {
 | 
				
			||||||
      this.fetchPost(`${this.run.link}/cancel`);
 | 
					      this.fetchPost(`${this.run.link}/cancel`);
 | 
				
			||||||
@@ -366,26 +375,16 @@ export function ansiLogToHTML(line) {
 | 
				
			|||||||
  margin: 0 20px 20px 20px;
 | 
					  margin: 0 20px 20px 20px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.action-view-header .run_cancel {
 | 
					.action-view-header .action-control-button {
 | 
				
			||||||
  border: none;
 | 
					  border: none;
 | 
				
			||||||
  color: var(--color-red);
 | 
					 | 
				
			||||||
  background-color: transparent;
 | 
					  background-color: transparent;
 | 
				
			||||||
  outline: none;
 | 
					  outline: none;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
  transition: transform 0.2s;
 | 
					  transition: transform 0.2s;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.action-view-header .run_approve {
 | 
					.action-view-header .action-control-button:hover {
 | 
				
			||||||
  border: none;
 | 
					 | 
				
			||||||
  color: var(--color-green);
 | 
					 | 
				
			||||||
  background-color: transparent;
 | 
					 | 
				
			||||||
  outline: none;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  transition: transform 0.2s;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.action-view-header .run_cancel:hover,
 | 
					 | 
				
			||||||
.action-view-header .run_approve:hover {
 | 
					 | 
				
			||||||
  transform: scale(130%);
 | 
					  transform: scale(130%);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,7 @@ import octiconLink from '../../public/img/svg/octicon-link.svg';
 | 
				
			|||||||
import octiconLock from '../../public/img/svg/octicon-lock.svg';
 | 
					import octiconLock from '../../public/img/svg/octicon-lock.svg';
 | 
				
			||||||
import octiconMilestone from '../../public/img/svg/octicon-milestone.svg';
 | 
					import octiconMilestone from '../../public/img/svg/octicon-milestone.svg';
 | 
				
			||||||
import octiconMirror from '../../public/img/svg/octicon-mirror.svg';
 | 
					import octiconMirror from '../../public/img/svg/octicon-mirror.svg';
 | 
				
			||||||
 | 
					import octiconPlay from '../../public/img/svg/octicon-play.svg';
 | 
				
			||||||
import octiconProject from '../../public/img/svg/octicon-project.svg';
 | 
					import octiconProject from '../../public/img/svg/octicon-project.svg';
 | 
				
			||||||
import octiconRepo from '../../public/img/svg/octicon-repo.svg';
 | 
					import octiconRepo from '../../public/img/svg/octicon-repo.svg';
 | 
				
			||||||
import octiconRepoForked from '../../public/img/svg/octicon-repo-forked.svg';
 | 
					import octiconRepoForked from '../../public/img/svg/octicon-repo-forked.svg';
 | 
				
			||||||
@@ -79,6 +80,7 @@ const svgs = {
 | 
				
			|||||||
  'octicon-milestone': octiconMilestone,
 | 
					  'octicon-milestone': octiconMilestone,
 | 
				
			||||||
  'octicon-mirror': octiconMirror,
 | 
					  'octicon-mirror': octiconMirror,
 | 
				
			||||||
  'octicon-organization': octiconOrganization,
 | 
					  'octicon-organization': octiconOrganization,
 | 
				
			||||||
 | 
					  'octicon-play': octiconPlay,
 | 
				
			||||||
  'octicon-plus': octiconPlus,
 | 
					  'octicon-plus': octiconPlus,
 | 
				
			||||||
  'octicon-project': octiconProject,
 | 
					  'octicon-project': octiconProject,
 | 
				
			||||||
  'octicon-repo': octiconRepo,
 | 
					  'octicon-repo': octiconRepo,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user