diff --git a/models/bots/run_job.go b/models/bots/run_job.go index 91e32aaf04..01b190de83 100644 --- a/models/bots/run_job.go +++ b/models/bots/run_job.go @@ -80,3 +80,11 @@ func GetRunJobByID(ctx context.Context, id int64) (*RunJob, error) { return &job, nil } + +func GetRunJobsByRunID(ctx context.Context, runID int64) ([]*RunJob, error) { + var jobs []*RunJob + if err := db.GetEngine(ctx).Where("run_id=?", runID).Find(&jobs); err != nil { + return nil, err + } + return jobs, nil +} diff --git a/models/bots/task.go b/models/bots/task.go index 3420c8a811..144381f99c 100644 --- a/models/bots/task.go +++ b/models/bots/task.go @@ -69,6 +69,29 @@ func (task *Task) LoadAttributes(ctx context.Context) error { return nil } +// ErrTaskNotExist represents an error for bot task not exist +type ErrTaskNotExist struct { + ID int64 +} + +func (err ErrTaskNotExist) Error() string { + return fmt.Sprintf("task [%d] is not exist", err.ID) +} + +func GetTaskByID(ctx context.Context, id int64) (*Task, error) { + var task Task + has, err := db.GetEngine(ctx).Where("id=?", id).Get(&task) + if err != nil { + return nil, err + } else if !has { + return nil, ErrTaskNotExist{ + ID: id, + } + } + + return &task, nil +} + func CreateTaskForRunner(runner *Runner) (*Task, bool, error) { ctx, commiter, err := db.TxContext() if err != nil { diff --git a/routers/web/repo/builds/builds.go b/routers/web/repo/builds/builds.go index 7058661dba..55507fe9af 100644 --- a/routers/web/repo/builds/builds.go +++ b/routers/web/repo/builds/builds.go @@ -8,6 +8,7 @@ import ( "fmt" "net/http" + "code.gitea.io/gitea/core" bots_model "code.gitea.io/gitea/models/bots" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unit" @@ -147,3 +148,102 @@ LOOP_WORKFLOWS: ctx.JSON(http.StatusOK, logs) } + +type RunState struct { + Title string `json:"title"` + Jobs []*RunStateJob `json:"jobs"` + CurrentJobInfo *RunStateJobInfo `json:"current_job_info"` + CurrentJobSteps []*RunStateJobSteps `json:"current_job_steps"` +} + +type RunStateJob struct { + ID int64 `json:"id"` + Name string `json:"name"` + Status core.BuildStatus `json:"status"` +} + +type RunStateJobInfo struct { + Title string `json:"title"` + Detail string `json:"detail"` +} + +type RunStateJobSteps struct { + Summary string `json:"summary"` + Status core.BuildStatus `json:"status"` + Duration int64 `json:"duration"` // seconds +} + +func GetRunState(ctx *context.Context) { + runID := ctx.ParamsInt64("index") + currentJobID := ctx.ParamsInt64("jobid") + + run, err := bots_model.GetRunByID(ctx, runID) + if err != nil { + if _, ok := err.(bots_model.ErrRunNotExist); ok { + ctx.Error(http.StatusNotFound, err.Error()) + return + } + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + jobs, err := bots_model.GetRunJobsByRunID(ctx, run.ID) + if err != nil { + if _, ok := err.(bots_model.ErrRunJobNotExist); ok { + ctx.Error(http.StatusNotFound, err.Error()) + return + } + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + + state := &RunState{ + Title: run.Name, + Jobs: make([]*RunStateJob, len(jobs)), + } + for i, v := range jobs { + state.Jobs[i] = &RunStateJob{ + ID: v.ID, + Name: v.Name, + Status: v.Status, + } + } + if currentJobID != 0 { + for _, job := range jobs { + if job.ID == currentJobID { + state.CurrentJobInfo = &RunStateJobInfo{ + Title: job.Name, + } + if job.TaskID == 0 { + state.CurrentJobInfo.Detail = "wait to be pick up by a runner" + } + state.CurrentJobInfo.Detail = "TODO: more detail info" // TODO: more detail info, need to be internationalized + + 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 + } + state.CurrentJobSteps = make([]*RunStateJobSteps, 0, len(task.Steps)+2) + // TODO: add steps "Set up job" and "Complete job" + for _, step := range task.Steps { + state.CurrentJobSteps = append(state.CurrentJobSteps, &RunStateJobSteps{ + Summary: step.Name, + Status: core.StatusRunning, // TODO: add status to step + Duration: int64(step.Stopped - step.Started), + }) + } + } + } + } + + ctx.JSON(http.StatusOK, state) +} + +func GetRunLog(ctx *context.Context) { + // TODO +} diff --git a/routers/web/web.go b/routers/web/web.go index 08252e3c15..dc0194b668 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1185,8 +1185,10 @@ func RegisterRoutes(m *web.Route) { m.Group("/builds", func() { m.Get("", builds.List) m.Group("/{index}", func() { - m.Get("", builds.ViewBuild) - m.Get("/{workflow}/job/{jobname}/logs", builds.GetBuildJobLogs) + //m.Get("", builds.ViewBuild) + //m.Get("/{workflow}/job/{jobname}/logs", builds.GetBuildJobLogs) + m.Get("", builds.GetRunState) + m.Get("/job/{jobid}", builds.GetRunState) }) }, reqRepoBuildsReader, builds.MustEnableBuilds)