Skip to content

Commit 729e9a1

Browse files
authored
Show failed tasks as errors in statusbars (#355)
* Show failed tasks as errors in statusbars * Change formatting of status bar error * Add changelog
1 parent c237a7a commit 729e9a1

File tree

8 files changed

+72
-3
lines changed

8 files changed

+72
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ All notable changes to `src-cli` are documented in this file.
1515

1616
### Changed
1717

18+
- The progress bar in `src campaign [preview|apply]` now shows when executing a step failed in a repository by styling the line red and displaying standard error output. [#355](https://github.com/sourcegraph/src-cli/pull/355)
19+
1820
### Fixed
1921

2022
## 3.21.2

cmd/src/campaign_progress_printer.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,11 @@ func (p *campaignProgressPrinter) PrintStatuses(statuses []*campaigns.TaskStatus
134134
// Log that this task completed, but only if there is no
135135
// currently executing one in this bar, to avoid flicker.
136136
if _, ok := p.statusBarRepo[idx]; !ok {
137-
p.progress.StatusBarCompletef(idx, statusText)
137+
if ts.Err != nil {
138+
p.progress.StatusBarFailf(idx, statusText)
139+
} else {
140+
p.progress.StatusBarCompletef(idx, statusText)
141+
}
138142
}
139143
delete(p.repoStatusBar, ts.RepoName)
140144
}
@@ -161,12 +165,24 @@ func (p *campaignProgressPrinter) PrintStatuses(statuses []*campaigns.TaskStatus
161165
}
162166
}
163167

168+
type statusTexter interface {
169+
StatusText() string
170+
}
171+
164172
func taskStatusText(ts *campaigns.TaskStatus) (string, error) {
165173
var statusText string
166174

167175
if ts.IsCompleted() {
168176
if ts.ChangesetSpec == nil {
169-
statusText = "No changes"
177+
if ts.Err != nil {
178+
if texter, ok := ts.Err.(statusTexter); ok {
179+
statusText = texter.StatusText()
180+
} else {
181+
statusText = ts.Err.Error()
182+
}
183+
} else {
184+
statusText = "No changes"
185+
}
170186
} else {
171187
fileDiffs, err := diff.ParseMultiFileDiff([]byte(ts.ChangesetSpec.Commits[0].Diff))
172188
if err != nil {

internal/campaigns/executor.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ func (e TaskExecutionErr) Error() string {
3232
)
3333
}
3434

35+
func (e TaskExecutionErr) StatusText() string {
36+
if stepErr, ok := e.Err.(stepFailedErr); ok {
37+
return stepErr.SingleLineError()
38+
}
39+
return e.Err.Error()
40+
}
41+
3542
type Executor interface {
3643
AddTask(repo *graphql.Repository, steps []Step, template *ChangesetTemplate) *TaskStatus
3744
LogFiles() []string

internal/campaigns/run_steps.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,12 @@ func (e stepFailedErr) Error() string {
262262

263263
return out.String()
264264
}
265+
266+
func (e stepFailedErr) SingleLineError() string {
267+
out := e.Err.Error()
268+
if len(e.Stderr) > 0 {
269+
out = e.Stderr
270+
}
271+
272+
return strings.Split(out, "\n")[0]
273+
}

internal/output/progress_with_status_bars.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ type ProgressWithStatusBars interface {
55

66
StatusBarUpdatef(i int, format string, args ...interface{})
77
StatusBarCompletef(i int, format string, args ...interface{})
8+
StatusBarFailf(i int, format string, args ...interface{})
89
StatusBarResetf(i int, label, format string, args ...interface{})
910
}
1011

internal/output/progress_with_status_bars_simple.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ func (p *progressWithStatusBarsSimple) StatusBarCompletef(i int, format string,
3232
}
3333
}
3434

35+
func (p *progressWithStatusBarsSimple) StatusBarFailf(i int, format string, args ...interface{}) {
36+
if p.statusBars[i] != nil {
37+
wasCompleted := p.statusBars[i].completed
38+
p.statusBars[i].Failf(format, args...)
39+
if !wasCompleted {
40+
writeStatusBar(p.Output, p.statusBars[i])
41+
}
42+
}
43+
}
44+
3545
func (p *progressWithStatusBarsSimple) StatusBarResetf(i int, label, format string, args ...interface{}) {
3646
if p.statusBars[i] != nil {
3747
p.statusBars[i].Resetf(label, format, args...)

internal/output/progress_with_status_bars_tty.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,17 @@ func (p *progressWithStatusBarsTTY) StatusBarCompletef(i int, format string, arg
153153
p.drawInSitu()
154154
}
155155

156+
func (p *progressWithStatusBarsTTY) StatusBarFailf(i int, format string, args ...interface{}) {
157+
p.o.lock.Lock()
158+
defer p.o.lock.Unlock()
159+
160+
if p.statusBars[i] != nil {
161+
p.statusBars[i].Failf(format, args...)
162+
}
163+
164+
p.drawInSitu()
165+
}
166+
156167
func (p *progressWithStatusBarsTTY) draw() {
157168
for _, bar := range p.bars {
158169
p.writeBar(bar)
@@ -205,8 +216,13 @@ func (p *progressWithStatusBarsTTY) determineStatusBarLabelWidth() {
205216
func (p *progressWithStatusBarsTTY) writeStatusBar(last bool, statusBar *StatusBar) {
206217
style := StylePending
207218
if statusBar.completed {
208-
style = StyleSuccess
219+
if statusBar.failed {
220+
style = StyleWarning
221+
} else {
222+
style = StyleSuccess
223+
}
209224
}
225+
210226
box := "├── "
211227
if last {
212228
box = "└── "

internal/output/status_bar.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import "time"
66
// of a process.
77
type StatusBar struct {
88
completed bool
9+
failed bool
910

1011
label string
1112
format string
@@ -24,10 +25,17 @@ func (sb *StatusBar) Completef(format string, args ...interface{}) {
2425
sb.finishedAt = time.Now()
2526
}
2627

28+
// Failf sets the StatusBar to completed and failed and updates its text.
29+
func (sb *StatusBar) Failf(format string, args ...interface{}) {
30+
sb.Completef(format, args...)
31+
sb.failed = true
32+
}
33+
2734
// Resetf sets the status of the StatusBar to incomplete and updates its label and text.
2835
func (sb *StatusBar) Resetf(label, format string, args ...interface{}) {
2936
sb.initialized = true
3037
sb.completed = false
38+
sb.failed = false
3139
sb.label = label
3240
sb.format = format
3341
sb.args = args

0 commit comments

Comments
 (0)