| @@ -244,7 +244,13 @@ func runBuildShow(c *Ctx, args []string) int { |
| 244 | } |
244 | } |
| 245 | d := buildToOut(b) |
245 | d := buildToOut(b) |
| 246 | json.Unmarshal([]byte(b.Steps), &d.Steps) |
246 | json.Unmarshal([]byte(b.Steps), &d.Steps) |
| 247 | return c.emit(d, func(w io.Writer) { |
247 | var mr *store.MR |
| |
248 | if c.Term.Cols > 0 && !c.JSON { |
| |
249 | if m, ok, err := c.Store.OpenMRBySource(repo.ID, d.Ref); err == nil && ok { |
| |
250 | mr = &m |
| |
251 | } |
| |
252 | } |
| |
253 | return c.emitView(d, func(w io.Writer) { |
| 248 | failedStep, failed := "", "" |
254 | failedStep, failed := "", "" |
| 249 | if d.FailedStep > 0 && d.FailedStep <= len(d.Steps) { |
255 | if d.FailedStep > 0 && d.FailedStep <= len(d.Steps) { |
| 250 | step, _, _ := strings.Cut(d.Steps[d.FailedStep-1], "\n") |
256 | step, _, _ := strings.Cut(d.Steps[d.FailedStep-1], "\n") |
| @@ -259,15 +265,6 @@ func runBuildShow(c *Ctx, args []string) int { |
| 259 | if d.DurationS > 0 { |
265 | if d.DurationS > 0 { |
| 260 | duration = (time.Duration(d.DurationS) * time.Second).String() |
266 | duration = (time.Duration(d.DurationS) * time.Second).String() |
| 261 | } |
267 | } |
| 262 | // At a terminal: the open merge request the build ran for, and |
| |
| 263 | // the command that prints its log. |
| |
| 264 | mr, logCmd := "", "" |
| |
| 265 | if c.Term.Cols > 0 { |
| |
| 266 | if m, ok, err := c.Store.OpenMRBySource(repo.ID, d.Ref); err == nil && ok { |
| |
| 267 | mr = fmt.Sprintf("!%d %s", m.Number, m.Title) |
| |
| 268 | } |
| |
| 269 | logCmd = fmt.Sprintf("gitbay build log %s %d", repo.Path(), d.Number) |
| |
| 270 | } |
| |
| 271 | v := c.view(w) |
268 | v := c.view(w) |
| 272 | v.title(fmt.Sprintf("#%d", d.Number), d.Job, d.Status) |
269 | v.title(fmt.Sprintf("#%d", d.Number), d.Job, d.Status) |
| 273 | v.fields( |
270 | v.fields( |
| @@ -278,20 +275,44 @@ func runBuildShow(c *Ctx, args []string) int { |
| 278 | "duration", duration, |
275 | "duration", duration, |
| 279 | "failed step", failedStep, |
276 | "failed step", failedStep, |
| 280 | "failed", failed, |
277 | "failed", failed, |
| 281 | "mr", mr, |
| |
| 282 | "log", logCmd, |
| |
| 283 | "url", c.siteURL(repo.Path(), "builds", strconv.FormatInt(d.Number, 10)), |
278 | "url", c.siteURL(repo.Path(), "builds", strconv.FormatInt(d.Number, 10)), |
| 284 | ) |
279 | ) |
| 285 | if c.Term.Cols > 0 && len(d.Steps) > 0 { |
280 | }, func() screen { return buildShowScreen(c, repo, d, mr) }) |
| 286 | v.section("steps") |
281 | } |
| 287 | tb := c.table(w, "#", "STEP", "STATE") |
282 | |
| 288 | for i, step := range d.Steps { |
283 | // buildShowScreen is build show at a terminal: the build's outcome, what |
| 289 | line, _, _ := strings.Cut(step, "\n") |
284 | // it ran on, each step's outcome, and the command for its log. |
| 290 | tb.row(cNum(int64(i+1)), cFlex(line), cState(stepState(d.Status, d.FailedStep, i+1))) |
285 | func buildShowScreen(c *Ctx, repo store.Repo, d BuildOut, mr *store.MR) screen { |
| 291 | } |
286 | n := strconv.FormatInt(d.Number, 10) |
| 292 | tb.flush() |
287 | path := repo.Path() |
| |
288 | var s screen |
| |
289 | s.fields = append(s.fields, |
| |
290 | field{"Build", []cell{cLink(n, c.siteURL(path, "builds", n)), cText(d.Job)}}, |
| |
291 | field{"State", []cell{cGlyph(d.Status), cState(d.Status)}}, |
| |
292 | field{"Commit", []cell{cRef(fmt.Sprintf("%.10s", d.SHA)), cText(d.Subject)}}, |
| |
293 | field{"Ref", []cell{cText(d.Ref)}}, |
| |
294 | ) |
| |
295 | if mr != nil { |
| |
296 | s.fields = append(s.fields, field{"MR", []cell{cRef(fmt.Sprintf("!%d", mr.Number)), cText(mr.Title)}}) |
| |
297 | } |
| |
298 | if d.DurationS > 0 { |
| |
299 | s.fields = append(s.fields, field{"Duration", []cell{cText(c.Term.dur(d.DurationS))}}) |
| |
300 | } |
| |
301 | if !c.Term.Links { |
| |
302 | s.fields = append(s.fields, field{"URL", []cell{cText(c.siteURL(path, "builds", n))}}) |
| |
303 | } |
| |
304 | steps := section{title: "Steps", n: len(d.Steps)} |
| |
305 | for i, step := range d.Steps { |
| |
306 | line, _, _ := strings.Cut(step, "\n") |
| |
307 | meta := "" |
| |
308 | if i+1 == d.FailedStep { |
| |
309 | meta = d.FailedReason |
| 293 | } |
310 | } |
| 294 | }) |
311 | steps.rows = append(steps.rows, rowOf(cGlyph(stepState(d.Status, d.FailedStep, i+1)), cFlex(line), cMeta(meta))) |
| |
312 | } |
| |
313 | s.sections = []section{steps} |
| |
314 | s.actions = []action{{"Read", []string{"build", "log", path, n}}} |
| |
315 | return s |
| 295 | } |
316 | } |
| 296 | |
317 | |
| 297 | // stepState is what a finished build says about one of its steps: those |
318 | // stepState is what a finished build says about one of its steps: those |