From 1cba52376aa7ec7e4f0c01f1db845f162816d698 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Fri, 14 Oct 2022 18:30:00 +0800 Subject: [PATCH] feat: use run id and job id in page view --- models/bots/task.go | 34 +++++ routers/web/dev/buildview.go | 158 +++++++++++------------- routers/web/web.go | 11 +- templates/dev/buildview.tmpl | 2 +- web_src/js/components/RepoBuildView.vue | 17 ++- 5 files changed, 126 insertions(+), 96 deletions(-) diff --git a/models/bots/task.go b/models/bots/task.go index 144381f99c..58849d4086 100644 --- a/models/bots/task.go +++ b/models/bots/task.go @@ -69,6 +69,40 @@ func (task *Task) LoadAttributes(ctx context.Context) error { return nil } +// FullSteps returns steps with "Set up job" and "Complete job" +func (task *Task) FullSteps() []*TaskStep { + var firstStep, lastStep *TaskStep + if l := len(task.Steps); l > 0 { + firstStep = task.Steps[0] + lastStep = task.Steps[l-1] + } + headStep := &TaskStep{ + Name: "Set up job", + LogIndex: 0, + LogLength: -1, // no limit + Started: task.Started, + } + if firstStep != nil { + headStep.LogLength = firstStep.LogIndex + headStep.Stopped = firstStep.Started + } + tailStep := &TaskStep{ + Name: "Complete job", + Stopped: task.Stopped, + } + if lastStep != nil { + tailStep.LogIndex = lastStep.LogIndex + lastStep.LogLength + tailStep.LogLength = -1 // no limit + tailStep.Started = lastStep.Stopped + } + steps := make([]*TaskStep, 0, len(task.Steps)+2) + steps = append(steps, headStep) + steps = append(steps, task.Steps...) + steps = append(steps, tailStep) + + return steps +} + // ErrTaskNotExist represents an error for bot task not exist type ErrTaskNotExist struct { ID int64 diff --git a/routers/web/dev/buildview.go b/routers/web/dev/buildview.go index cf1fbbfd87..4c31724a27 100644 --- a/routers/web/dev/buildview.go +++ b/routers/web/dev/buildview.go @@ -1,16 +1,19 @@ package dev import ( + "fmt" + "net/http" + "code.gitea.io/gitea/core" bots_model "code.gitea.io/gitea/models/bots" - "code.gitea.io/gitea/modules/web" - "net/http" - "strconv" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/web" ) func BuildView(ctx *context.Context) { + ctx.Data["RunID"] = ctx.Params("runid") + ctx.Data["JobID"] = ctx.Params("jobid") + ctx.HTML(http.StatusOK, "dev/buildview") } @@ -70,38 +73,34 @@ type BuildViewStepLogLine struct { func BuildViewPost(ctx *context.Context) { req := web.GetForm(ctx).(*BuildViewRequest) - currentJobID, _ := strconv.ParseInt(ctx.Req.URL.Query().Get("job_id"), 10, 64) + runID := ctx.ParamsInt64("runid") + jobID := ctx.ParamsInt64("jobid") - job, err := bots_model.GetRunJobByID(ctx, currentJobID) + run, err := bots_model.GetRunByID(ctx, runID) if err != nil { - if _, ok := err.(bots_model.ErrRunJobNotExist); ok { + if _, ok := err.(bots_model.ErrRunNotExist); ok { ctx.Error(http.StatusNotFound, err.Error()) return } ctx.Error(http.StatusInternalServerError, err.Error()) return } - if err := job.LoadAttributes(ctx); err != nil { - ctx.Error(http.StatusInternalServerError, err.Error()) - return - } - - run := job.Run jobs, err := bots_model.GetRunJobsByRunID(ctx, run.ID) if err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return } - var task *bots_model.Task - if job.TaskID > 0 { - task, err = bots_model.GetTaskByID(ctx, job.TaskID) - if err != nil { - ctx.Error(http.StatusInternalServerError, err.Error()) - return + + var job *bots_model.RunJob + if jobID != 0 { + for _, v := range jobs { + if v.ID == jobID { + job = v + break + } } - task.Job = job - if err := task.LoadAttributes(ctx); err != nil { - ctx.Error(http.StatusInternalServerError, err.Error()) + if job == nil { + ctx.Error(http.StatusNotFound, fmt.Sprintf("run %v has no job %v", runID, jobID)) return } } @@ -125,75 +124,64 @@ func BuildViewPost(ctx *context.Context) { }, } - resp.StateData.CurrentJobInfo.Title = job.Name - resp.LogsData.StreamingLogs = make([]BuildViewStepLog, 0, len(req.StepLogCursors)) - if job.TaskID == 0 { - resp.StateData.CurrentJobInfo.Detail = "wait to be pick up by a runner" - } else { - resp.StateData.CurrentJobInfo.Detail = "TODO: more detail info" // TODO: more detail info - - var firstStep, lastStep *bots_model.TaskStep - if l := len(task.Steps); l > 0 { - firstStep = task.Steps[0] - lastStep = task.Steps[l-1] - } - headStep := &bots_model.TaskStep{ - Name: "Set up job", - LogIndex: 0, - LogLength: -1, // no limit - Started: task.Started, - } - if firstStep != nil { - headStep.LogLength = firstStep.LogIndex - headStep.Stopped = firstStep.Started - } - tailStep := &bots_model.TaskStep{ - Name: "Complete job", - Stopped: task.Stopped, - } - if lastStep != nil { - tailStep.LogIndex = lastStep.LogIndex + lastStep.LogLength - tailStep.LogLength = -1 // no limit - tailStep.Started = lastStep.Stopped - } - steps := make([]*bots_model.TaskStep, 0, len(task.Steps)+2) - steps = append(steps, headStep) - steps = append(steps, task.Steps...) - steps = append(steps, tailStep) - - resp.StateData.CurrentJobSteps = make([]BuildViewJobStep, len(steps)) - for i, v := range steps { - resp.StateData.CurrentJobSteps[i] = BuildViewJobStep{ - Summary: v.Name, - Duration: float64(v.Stopped - v.Started), - Status: core.StatusRunning, // TODO: add status to step, + if job != nil { + var task *bots_model.Task + if job.TaskID > 0 { + task, err = bots_model.GetTaskByID(ctx, job.TaskID) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + task.Job = job + if err := task.LoadAttributes(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return } } - for _, cursor := range req.StepLogCursors { - if cursor.Expanded { - step := steps[cursor.StepIndex] - var logRows []*bots_model.TaskLog - if cursor.Cursor < step.LogLength || step.LogLength < 0 { - logRows, err = bots_model.GetTaskLogs(task.ID, step.LogIndex+cursor.Cursor, step.LogLength-cursor.Cursor) - if err != nil { - ctx.Error(http.StatusInternalServerError, err.Error()) - return - } + resp.StateData.CurrentJobInfo.Title = job.Name + resp.LogsData.StreamingLogs = make([]BuildViewStepLog, 0, len(req.StepLogCursors)) + if job.TaskID == 0 { + resp.StateData.CurrentJobInfo.Detail = "wait to be pick up by a runner" + } else { + resp.StateData.CurrentJobInfo.Detail = "TODO: more detail info" // TODO: more detail info + + steps := task.FullSteps() + + resp.StateData.CurrentJobSteps = make([]BuildViewJobStep, len(steps)) + for i, v := range steps { + resp.StateData.CurrentJobSteps[i] = BuildViewJobStep{ + Summary: v.Name, + Duration: float64(v.Stopped - v.Started), + Status: core.StatusRunning, // TODO: add status to step, } - logLines := make([]BuildViewStepLogLine, len(logRows)) - for i, row := range logRows { - logLines[i] = BuildViewStepLogLine{ - Ln: i, - M: row.Content, - T: float64(row.Timestamp), + } + + for _, cursor := range req.StepLogCursors { + if cursor.Expanded { + step := steps[cursor.StepIndex] + var logRows []*bots_model.TaskLog + if cursor.Cursor < step.LogLength || step.LogLength < 0 { + logRows, err = bots_model.GetTaskLogs(task.ID, step.LogIndex+cursor.Cursor, step.LogLength-cursor.Cursor) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } } + logLines := make([]BuildViewStepLogLine, len(logRows)) + for i, row := range logRows { + logLines[i] = BuildViewStepLogLine{ + Ln: i, + M: row.Content, + T: float64(row.Timestamp), + } + } + resp.LogsData.StreamingLogs = append(resp.LogsData.StreamingLogs, BuildViewStepLog{ + StepIndex: cursor.StepIndex, + Cursor: cursor.Cursor + int64(len(logLines)), + Lines: logLines, + }) } - resp.LogsData.StreamingLogs = append(resp.LogsData.StreamingLogs, BuildViewStepLog{ - StepIndex: cursor.StepIndex, - Cursor: cursor.Cursor + int64(len(logLines)), - Lines: logLines, - }) } } } diff --git a/routers/web/web.go b/routers/web/web.go index 1c284f9df0..9ed94099e2 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/metrics" "code.gitea.io/gitea/modules/public" + _ "code.gitea.io/gitea/modules/session" // to registers all internal adapters "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/structs" @@ -45,8 +46,6 @@ import ( "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/lfs" - _ "code.gitea.io/gitea/modules/session" // to registers all internal adapters - "gitea.com/go-chi/captcha" "gitea.com/go-chi/session" "github.com/NYTimes/gziphandler" @@ -661,8 +660,12 @@ func RegisterRoutes(m *web.Route) { if !setting.IsProd { m.Any("/dev/termdemo", dev.TermDemo) - m.Get("/dev/buildview", dev.BuildView) - m.Post("/dev/buildview", bindIgnErr(dev.BuildViewRequest{}), dev.BuildViewPost) + m.Combo("/dev/buildview/runs/{runid}"). + Get(dev.BuildView). + Post(bindIgnErr(dev.BuildViewRequest{}), dev.BuildViewPost) + m.Combo("/dev/buildview/runs/{runid}/jobs/{jobid}"). + Get(dev.BuildView). + Post(bindIgnErr(dev.BuildViewRequest{}), dev.BuildViewPost) } reqRepoAdmin := context.RequireRepoAdmin() diff --git a/templates/dev/buildview.tmpl b/templates/dev/buildview.tmpl index bd5ef151ba..044adff7c0 100644 --- a/templates/dev/buildview.tmpl +++ b/templates/dev/buildview.tmpl @@ -1,6 +1,6 @@ {{template "base/head" .}} -
+
diff --git a/web_src/js/components/RepoBuildView.vue b/web_src/js/components/RepoBuildView.vue index 90737790dd..f2b963eba3 100644 --- a/web_src/js/components/RepoBuildView.vue +++ b/web_src/js/components/RepoBuildView.vue @@ -10,7 +10,7 @@ {{ jobGroup.summary }}
- + @@ -77,11 +77,13 @@ const sfc = { components: { SvgIcon, }, + props: { + runId: Number, + jobId: Number, + }, data() { return { - jobId: 120, // TODO: read job id - // internal state loading: false, currentJobStepsStates: [], @@ -138,7 +140,7 @@ const sfc = { toggleStepLogs(idx) { this.currentJobStepsStates[idx].expanded = !this.currentJobStepsStates[idx].expanded; if (this.currentJobStepsStates[idx].expanded) { - this.loadJobData(); + // this.loadJobData(); // FIXME: cannot call loadJobData more than once } }, @@ -250,7 +252,7 @@ const sfc = { }, async fetchJobData(reqData) { - const resp = await fetch(`?job_id=${this.jobId}`, { + const resp = await fetch(`/dev/buildview/runs/${this.runId}/jobs/${this.jobId}`, { // FIXME: hard code path method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(reqData), @@ -307,7 +309,10 @@ export function initRepositoryBuildView() { const el = document.getElementById('repo-build-view'); if (!el) return; - const view = createApp(sfc); + const view = createApp(sfc, { + jobId: el.getAttribute("job-id"), + runId: el.getAttribute("run-id"), + }); view.mount(el); }