Skip to content

Commit 405bfc7

Browse files
committed
Show CLI errors generated by exp show
1 parent 0db0877 commit 405bfc7

File tree

31 files changed

+362
-74
lines changed

31 files changed

+362
-74
lines changed

extension/src/experiments/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,10 @@ export class Experiments extends BaseRepository<TableData> {
407407
}
408408

409409
public getWorkspaceAndCommits() {
410-
if (!this.columns.hasNonDefaultColumns()) {
410+
if (
411+
!this.experiments.getCliError() &&
412+
!this.columns.hasNonDefaultColumns()
413+
) {
411414
return []
412415
}
413416

@@ -499,6 +502,10 @@ export class Experiments extends BaseRepository<TableData> {
499502
return this.experiments.hasRunningWorkspaceExperiment()
500503
}
501504

505+
public getCliError() {
506+
return this.experiments.getCliError()
507+
}
508+
502509
public getFirstThreeColumnOrder() {
503510
return this.columns.getFirstThreeColumnOrder()
504511
}

extension/src/experiments/model/collect.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export type ExperimentItem = {
4747
}
4848

4949
type ExperimentsAccumulator = {
50+
cliError: string | undefined
5051
commits: Experiment[]
5152
experimentsByCommit: Map<string, Experiment[]>
5253
hasCheckpoints: boolean
@@ -330,12 +331,22 @@ const hasCheckpoints = (data: ExpShowOutput) => {
330331
return !!workspace.data.meta.has_checkpoints
331332
}
332333

334+
const collectCliError = (
335+
acc: ExperimentsAccumulator,
336+
expShow: ExpShowOutput
337+
) => {
338+
if (expShow.length === 1 && acc.workspace.error) {
339+
acc.cliError = acc.workspace.error
340+
}
341+
}
342+
333343
export const collectExperiments = (
334344
expShow: ExpShowOutput,
335345
gitLog: string,
336346
dvcLiveOnly: boolean
337347
): ExperimentsAccumulator => {
338348
const acc: ExperimentsAccumulator = {
349+
cliError: undefined,
339350
commits: [],
340351
experimentsByCommit: new Map(),
341352
hasCheckpoints: hasCheckpoints(expShow),
@@ -363,6 +374,8 @@ export const collectExperiments = (
363374

364375
setWorkspaceAsRunning(acc, dvcLiveOnly)
365376

377+
collectCliError(acc, expShow)
378+
366379
return acc
367380
}
368381

extension/src/experiments/model/index.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,4 +522,32 @@ describe('ExperimentsModel', () => {
522522
expect(getSelectedRevisions(model)).toStrictEqual([])
523523
expect(model.hasRunningExperiment()).toBe(false)
524524
})
525+
526+
it('should capture a Cli error when exp show fails', () => {
527+
const model = new ExperimentsModel('', buildMockMemento())
528+
529+
const errorMsg = 'a very unexpected error - (╯°□°)╯︵ ┻━┻'
530+
531+
const data = [
532+
{
533+
rev: EXPERIMENT_WORKSPACE_ID,
534+
error: { msg: errorMsg, type: 'caught error' }
535+
}
536+
]
537+
model.transformAndSet(data, gitLogFixture, false, [], {
538+
main: 6
539+
})
540+
541+
expect(model.getCliError()).toStrictEqual(errorMsg)
542+
543+
model.transformAndSet(
544+
outputFixture,
545+
gitLogFixture,
546+
false,
547+
rowOrderFixture,
548+
{ main: 6 }
549+
)
550+
551+
expect(model.getCliError()).toBe(undefined)
552+
})
525553
})

extension/src/experiments/model/index.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export enum ExperimentType {
5353

5454
export class ExperimentsModel extends ModelWithPersistence {
5555
private workspace = {} as Experiment
56+
private cliError: undefined | string
5657
private commits: Experiment[] = []
5758
private experimentsByCommit: Map<string, Experiment[]> = new Map()
5859
private rowOrder: { branch: string; sha: string }[] = []
@@ -122,11 +123,12 @@ export class ExperimentsModel extends ModelWithPersistence {
122123
availableNbCommits: { [branch: string]: number }
123124
) {
124125
const {
125-
workspace,
126+
cliError,
126127
commits,
127128
experimentsByCommit,
129+
hasCheckpoints,
128130
runningExperiments,
129-
hasCheckpoints
131+
workspace
130132
} = collectExperiments(expShow, gitLog, dvcLiveOnly)
131133

132134
const { hasMoreCommits, isShowingMoreCommits } =
@@ -141,6 +143,7 @@ export class ExperimentsModel extends ModelWithPersistence {
141143

142144
this.rowOrder = rowOrder
143145
this.workspace = workspace
146+
this.cliError = cliError
144147
this.commits = commits
145148
this.experimentsByCommit = experimentsByCommit
146149
this.checkpoints = hasCheckpoints
@@ -192,6 +195,10 @@ export class ExperimentsModel extends ModelWithPersistence {
192195
return this.checkpoints
193196
}
194197

198+
public getCliError() {
199+
return this.cliError
200+
}
201+
195202
public canSelect() {
196203
return canSelect(this.coloredStatus)
197204
}
@@ -323,11 +330,18 @@ export class ExperimentsModel extends ModelWithPersistence {
323330
}
324331

325332
public getErrors() {
326-
return new Set(
327-
this.getCombinedList()
328-
.filter(({ error }) => error)
329-
.map(({ label }) => label)
330-
)
333+
const errors = new Set<string>()
334+
for (const { error, label } of this.getCombinedList()) {
335+
if (!error) {
336+
continue
337+
}
338+
errors.add(label)
339+
}
340+
if (this.cliError) {
341+
errors.add(this.cliError)
342+
}
343+
344+
return errors
331345
}
332346

333347
public getExperimentParams(id: string) {

extension/src/experiments/model/tree.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const mockedGetMarkdownString = jest.mocked(getMarkdownString)
3434
const {
3535
mockedExperiments,
3636
mockedGetCommitExperiments,
37+
mockedGetCliError,
3738
mockedGetDvcRoots,
3839
mockedGetFirstThreeColumnOrder,
3940
mockedGetWorkspaceAndCommits
@@ -450,6 +451,37 @@ describe('ExperimentsTree', () => {
450451
}
451452
])
452453
})
454+
455+
it('should return an error item if the repository has a CLI error', async () => {
456+
const errorMsg = 'the CLI is broken :('
457+
mockedGetCliError.mockReturnValueOnce(errorMsg)
458+
const experiments = [
459+
{
460+
displayColor: undefined,
461+
error: errorMsg,
462+
hasChildren: false,
463+
id: EXPERIMENT_WORKSPACE_ID,
464+
label: EXPERIMENT_WORKSPACE_ID,
465+
selected: false,
466+
type: ExperimentType.WORKSPACE
467+
}
468+
]
469+
470+
mockedGetWorkspaceAndCommits
471+
.mockReturnValueOnce(experiments)
472+
.mockReturnValueOnce(experiments)
473+
mockedGetDvcRoots.mockReturnValueOnce(['repo'])
474+
mockedGetFirstThreeColumnOrder.mockReturnValue([])
475+
476+
const experimentsTree = new ExperimentsTree(
477+
mockedExperiments,
478+
mockedResourceLocator
479+
)
480+
481+
const children = await experimentsTree.getChildren()
482+
483+
expect(children).toStrictEqual([{ error: errorMsg }])
484+
})
453485
})
454486

455487
describe('getTreeItem', () => {

extension/src/experiments/model/tree.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ import { definedAndNonEmpty, sortCollectedArray } from '../../util/array'
1919
import {
2020
createTreeView,
2121
DecoratableTreeItemScheme,
22+
ErrorItem,
23+
getCliErrorTreeItem,
2224
getDecoratableTreeItem,
2325
getErrorTooltip,
2426
getRootItem,
27+
isErrorItem,
2528
isRoot
2629
} from '../../tree'
2730
import { IconName, Resource, ResourceLocator } from '../../resourceLocator'
@@ -44,14 +47,14 @@ type ExperimentAugmented = Experiment & {
4447

4548
export class ExperimentsTree
4649
extends Disposable
47-
implements TreeDataProvider<string | ExperimentItem>
50+
implements TreeDataProvider<string | ExperimentItem | ErrorItem>
4851
{
4952
public readonly onDidChangeTreeData: Event<string | void>
5053

5154
private readonly experiments: WorkspaceExperiments
5255
private readonly resourceLocator: ResourceLocator
5356

54-
private readonly view: TreeView<string | ExperimentItem>
57+
private readonly view: TreeView<string | ExperimentItem | ErrorItem>
5558
private viewed = false
5659

5760
constructor(
@@ -63,7 +66,11 @@ export class ExperimentsTree
6366
this.onDidChangeTreeData = experiments.experimentsChanged.event
6467

6568
this.view = this.dispose.track(
66-
createTreeView<ExperimentItem>('dvc.views.experimentsTree', this, true)
69+
createTreeView<ExperimentItem | ErrorItem>(
70+
'dvc.views.experimentsTree',
71+
this,
72+
true
73+
)
6774
)
6875

6976
this.experiments = experiments
@@ -79,6 +86,15 @@ export class ExperimentsTree
7986
return getRootItem(element)
8087
}
8188

89+
if (isErrorItem(element)) {
90+
const { error } = element
91+
return getCliErrorTreeItem(
92+
error,
93+
error,
94+
DecoratableTreeItemScheme.EXPERIMENTS
95+
)
96+
}
97+
8298
const {
8399
label,
84100
collapsibleState,
@@ -109,7 +125,7 @@ export class ExperimentsTree
109125

110126
public getChildren(
111127
element?: string | ExperimentItem
112-
): Promise<string[] | ExperimentItem[]> {
128+
): Promise<string[] | ExperimentItem[] | ErrorItem[]> {
113129
if (!element) {
114130
return this.getRootElements()
115131
}
@@ -226,9 +242,17 @@ export class ExperimentsTree
226242
}
227243
}
228244

229-
private getWorkspaceAndCommits(dvcRoot: string): ExperimentItem[] {
230-
return this.experiments
231-
.getRepository(dvcRoot)
245+
private getWorkspaceAndCommits(
246+
dvcRoot: string
247+
): ExperimentItem[] | ErrorItem[] {
248+
const repository = this.experiments.getRepository(dvcRoot)
249+
250+
const cliError = repository.getCliError()
251+
if (cliError) {
252+
return [{ error: cliError }]
253+
}
254+
255+
return repository
232256
.getWorkspaceAndCommits()
233257
.map(experiment => this.formatExperiment(experiment, dvcRoot))
234258
}

extension/src/experiments/webview/contract.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export interface Column extends ColumnAggregateData {
9393

9494
export type TableData = {
9595
changes: string[]
96+
cliError: string | undefined
9697
columnOrder: string[]
9798
columns: Column[]
9899
columnWidths: Record<string, number>

extension/src/experiments/webview/messages.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ export class WebviewMessages {
205205
case MessageFromWebviewType.SELECT_BRANCHES:
206206
return this.addAndRemoveBranches()
207207

208+
case MessageFromWebviewType.REFRESH_EXP_DATA:
209+
return this.refreshData()
210+
208211
default:
209212
Logger.error(`Unexpected message: ${JSON.stringify(message)}`)
210213
}
@@ -242,9 +245,20 @@ export class WebviewMessages {
242245
await this.update()
243246
}
244247

248+
private refreshData() {
249+
sendTelemetryEvent(
250+
EventName.VIEWS_EXPERIMENTS_TABLE_REFRESH,
251+
undefined,
252+
undefined
253+
)
254+
255+
return this.update()
256+
}
257+
245258
private getWebviewData() {
246259
return {
247260
changes: this.columns.getChanges(),
261+
cliError: this.experiments.getCliError(),
248262
columnOrder: this.columns.getColumnOrder(),
249263
columnWidths: this.columns.getColumnWidths(),
250264
columns: this.columns.getSelected(),

extension/src/experiments/workspace.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,19 @@ export class WorkspaceExperiments extends BaseWorkspaceWebviews<
386386
return allLoading
387387
}
388388

389+
public getCliError() {
390+
const repositories = Object.values(this.repositories)
391+
const errors = []
392+
for (const repository of repositories) {
393+
const cliError = repository.getCliError()
394+
if (!cliError) {
395+
continue
396+
}
397+
errors.push(cliError)
398+
}
399+
return errors.length > 0 ? errors.join('\n') : undefined
400+
}
401+
389402
public hasRunningExperiment() {
390403
return Object.values(this.repositories).some(experiments =>
391404
experiments.hasRunningExperiment()

extension/src/setup/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export class Setup
7474

7575
private readonly webviewMessages: WebviewMessages
7676
private readonly getHasData: () => boolean | undefined
77+
private readonly getExpShowError: () => string | undefined
7778
private readonly collectWorkspaceScale: () => Promise<WorkspaceScale>
7879

7980
private readonly workspaceChanged: EventEmitter<void> = this.dispose.track(
@@ -129,6 +130,7 @@ export class Setup
129130
}
130131

131132
this.getHasData = () => experiments.getHasData()
133+
this.getExpShowError = () => experiments.getCliError()
132134
const onDidChangeHasData = experiments.columnsChanged.event
133135
this.dispose.track(
134136
onDidChangeHasData(() =>
@@ -232,7 +234,7 @@ export class Setup
232234
public shouldBeShown(): { dvc: boolean; experiments: boolean } {
233235
return {
234236
dvc: !!this.getCliCompatible() && this.hasRoots(),
235-
experiments: !!this.getHasData()
237+
experiments: !!(this.getExpShowError() || this.getHasData())
236238
}
237239
}
238240

0 commit comments

Comments
 (0)