Skip to content

Commit cad154d

Browse files
authored
Add push experiment(s) to the command palette (#3793)
1 parent 651c2f6 commit cad154d

File tree

8 files changed

+155
-4
lines changed

8 files changed

+155
-4
lines changed

extension/package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,11 @@
296296
"light": "resources/light/queue-experiment.svg"
297297
}
298298
},
299+
{
300+
"title": "Push Experiment(s)",
301+
"command": "dvc.pushExperiments",
302+
"category": "DVC"
303+
},
299304
{
300305
"title": "Remove Experiment(s)",
301306
"command": "dvc.removeExperiments",
@@ -761,6 +766,10 @@
761766
"command": "dvc.modifyExperimentParamsResetAndRun",
762767
"when": "dvc.commands.available && dvc.project.available && !dvc.experiment.running && dvc.experiment.checkpoints"
763768
},
769+
{
770+
"command": "dvc.pushExperiments",
771+
"when": "dvc.commands.available && dvc.project.available && !dvc.experiment.running"
772+
},
764773
{
765774
"command": "dvc.queueExperiment",
766775
"when": "dvc.commands.available && dvc.project.available && !dvc.experiment.running"

extension/src/commands/external.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export enum RegisteredCliCommands {
22
EXPERIMENT_APPLY = 'dvc.applyExperiment',
33
EXPERIMENT_BRANCH = 'dvc.branchExperiment',
44
EXPERIMENT_GARBAGE_COLLECT = 'dvc.experimentGarbageCollect',
5+
EXPERIMENT_PUSH = 'dvc.pushExperiments',
56
EXPERIMENT_REMOVE = 'dvc.removeExperiments',
67
EXPERIMENT_REMOVE_QUEUE = 'dvc.removeExperimentQueue',
78
EXPERIMENT_RESET_AND_RUN = 'dvc.resetAndRunCheckpointExperiment',

extension/src/experiments/commands/register.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ const registerExperimentInputCommands = (
160160

161161
const registerExperimentQuickPickCommands = (
162162
experiments: WorkspaceExperiments,
163-
internalCommands: InternalCommands
163+
internalCommands: InternalCommands,
164+
setup: Setup
164165
): void => {
165166
internalCommands.registerExternalCliCommand(
166167
RegisteredCliCommands.EXPERIMENT_GARBAGE_COLLECT,
@@ -220,6 +221,11 @@ const registerExperimentQuickPickCommands = (
220221
() => experiments.selectQueueTasksToKill()
221222
)
222223

224+
internalCommands.registerExternalCliCommand(
225+
RegisteredCliCommands.EXPERIMENT_PUSH,
226+
() => experiments.selectExperimentsToPush(setup)
227+
)
228+
223229
internalCommands.registerExternalCliCommand(
224230
RegisteredCliCommands.EXPERIMENT_REMOVE,
225231
() => experiments.selectExperimentsToRemove()
@@ -280,7 +286,7 @@ export const registerExperimentCommands = (
280286
registerExperimentCwdCommands(experiments, internalCommands)
281287
registerExperimentNameCommands(experiments, internalCommands)
282288
registerExperimentInputCommands(experiments, internalCommands)
283-
registerExperimentQuickPickCommands(experiments, internalCommands)
289+
registerExperimentQuickPickCommands(experiments, internalCommands, setup)
284290
registerExperimentRunCommands(experiments, internalCommands, setup)
285291

286292
internalCommands.registerExternalCommand(

extension/src/experiments/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,14 @@ export class Experiments extends BaseRepository<TableData> {
401401
)
402402
}
403403

404+
public pickExperimentsToPush() {
405+
return pickExperiments(
406+
this.experiments.getExperiments(),
407+
this.getFirstThreeColumnOrder(),
408+
Title.SELECT_EXPERIMENTS_PUSH
409+
)
410+
}
411+
404412
public async pickAndModifyParams(overrideId?: string) {
405413
const id = await this.getExperimentId(overrideId)
406414
if (!id) {

extension/src/experiments/workspace.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { EventEmitter, Memento } from 'vscode'
22
import isEmpty from 'lodash.isempty'
33
import { Experiments, ModifiedExperimentAndRunCommandId } from '.'
4+
import { getPushExperimentCommand } from './commands'
45
import { TableData } from './webview/contract'
56
import { Args } from '../cli/dvc/constants'
67
import {
@@ -9,6 +10,7 @@ import {
910
InternalCommands
1011
} from '../commands/internal'
1112
import { ResourceLocator } from '../resourceLocator'
13+
import { Setup } from '../setup'
1214
import { Toast } from '../vscode/toast'
1315
import {
1416
getInput,
@@ -172,6 +174,22 @@ export class WorkspaceExperiments extends BaseWorkspaceWebviews<
172174
return this.runCommand(AvailableCommands.QUEUE_KILL, cwd, ...taskIds)
173175
}
174176

177+
public async selectExperimentsToPush(setup: Setup) {
178+
const dvcRoot = await this.getFocusedOrOnlyOrPickProject()
179+
if (!dvcRoot) {
180+
return
181+
}
182+
183+
const ids = await this.getRepository(dvcRoot).pickExperimentsToPush()
184+
if (!ids || isEmpty(ids)) {
185+
return
186+
}
187+
188+
const pushCommand = getPushExperimentCommand(this.internalCommands, setup)
189+
190+
return pushCommand({ dvcRoot, ids })
191+
}
192+
175193
public async selectExperimentsToRemove() {
176194
const cwd = await this.getFocusedOrOnlyOrPickProject()
177195
if (!cwd) {

extension/src/telemetry/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export interface IEventNamePropertyMapping {
127127
[EventName.EXPERIMENT_FILTERS_REMOVE_ALL]: undefined
128128
[EventName.EXPERIMENT_GARBAGE_COLLECT]: undefined
129129
[EventName.EXPERIMENT_METRICS_AND_PARAMS_TOGGLE]: undefined
130+
[EventName.EXPERIMENT_PUSH]: undefined
130131
[EventName.EXPERIMENT_REMOVE]: undefined
131132
[EventName.EXPERIMENT_REMOVE_QUEUE]: undefined
132133
[EventName.EXPERIMENT_RESUME]: undefined

extension/src/test/suite/experiments/workspace.test.ts

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { Experiments } from '../../../experiments'
1313
import * as QuickPick from '../../../vscode/quickPick'
1414
import { DvcExecutor } from '../../../cli/dvc/executor'
1515
import {
16+
bypassProgressCloseDelay,
1617
closeAllEditors,
1718
getInputBoxEvent,
1819
getTimeSafeDisposer,
@@ -657,6 +658,112 @@ suite('Workspace Experiments Test Suite', () => {
657658
})
658659
})
659660

661+
describe('dvc.pushExperiments', () => {
662+
it('should ask the user to pick experiment(s) and then push selected ones to the remote', async () => {
663+
bypassProgressCloseDelay()
664+
const mockExperimentId = 'exp-e7a67'
665+
const secondMockExperimentId = 'exp-83425'
666+
type QuickPickReturnValue = QuickPickItemWithValue<string>[]
667+
stub(Setup.prototype, 'getStudioAccessToken').returns('isat_token')
668+
669+
const { experiments } = buildExperiments(disposable)
670+
671+
await experiments.isReady()
672+
673+
stubWorkspaceExperimentsGetters(dvcDemoPath, experiments)
674+
675+
const mockShowQuickPick = stub(window, 'showQuickPick') as SinonStub<
676+
[items: readonly QuickPickItem[], options: QuickPickOptionsWithTitle],
677+
Thenable<QuickPickReturnValue | undefined>
678+
>
679+
680+
mockShowQuickPick
681+
.onFirstCall()
682+
.resolves([
683+
{
684+
value: mockExperimentId
685+
}
686+
] as QuickPickReturnValue)
687+
.onSecondCall()
688+
.resolves([
689+
{
690+
value: mockExperimentId
691+
},
692+
{
693+
value: secondMockExperimentId
694+
}
695+
] as QuickPickReturnValue)
696+
const mockExpPush = stub(DvcExecutor.prototype, 'expPush')
697+
698+
await commands.executeCommand(RegisteredCliCommands.EXPERIMENT_PUSH)
699+
expect(mockShowQuickPick).calledWithExactly(
700+
[
701+
{
702+
description: '[exp-e7a67]',
703+
detail: `Created:${formatDate(
704+
'2020-12-29T15:31:52'
705+
)}, loss:2.0205045, accuracy:0.37241668`,
706+
label: '4fb124a',
707+
value: 'exp-e7a67'
708+
},
709+
{
710+
description: '[test-branch]',
711+
detail: `Created:${formatDate(
712+
'2020-12-29T15:28:59'
713+
)}, loss:1.9293040, accuracy:0.46680000`,
714+
label: '42b8736',
715+
value: 'test-branch'
716+
},
717+
{
718+
description: '[exp-83425]',
719+
detail: `Created:${formatDate(
720+
'2020-12-29T15:27:02'
721+
)}, loss:1.7750162, accuracy:0.59265000`,
722+
label: EXPERIMENT_WORKSPACE_ID,
723+
value: 'exp-83425'
724+
},
725+
{
726+
description: undefined,
727+
detail: 'Created:-, loss:-, accuracy:-',
728+
label: '489fd8b',
729+
value: '489fd8b'
730+
},
731+
{
732+
description: '[exp-f13bca]',
733+
detail: `Created:${formatDate(
734+
'2020-12-29T15:26:36'
735+
)}, loss:-, accuracy:-`,
736+
label: 'f0f9186',
737+
value: 'exp-f13bca'
738+
},
739+
{
740+
description: undefined,
741+
detail: `Created:${formatDate(
742+
'2020-12-29T15:25:27'
743+
)}, loss:-, accuracy:-`,
744+
label: '55d492c',
745+
value: '55d492c'
746+
}
747+
],
748+
{
749+
canPickMany: true,
750+
matchOnDescription: true,
751+
matchOnDetail: true,
752+
title: 'Select Experiment(s) to Push'
753+
}
754+
)
755+
expect(mockExpPush).to.be.calledWith(dvcDemoPath, mockExperimentId)
756+
757+
await commands.executeCommand(RegisteredCliCommands.EXPERIMENT_PUSH)
758+
759+
expect(mockExpPush).to.be.calledWith(
760+
dvcDemoPath,
761+
mockExperimentId,
762+
secondMockExperimentId
763+
)
764+
})
765+
})
766+
660767
describe('dvc.removeExperiments', () => {
661768
it('should ask the user to pick experiment(s) and then remove selected ones from the workspace', async () => {
662769
const mockExperimentId = 'exp-e7a67'
@@ -754,7 +861,7 @@ suite('Workspace Experiments Test Suite', () => {
754861
canPickMany: true,
755862
matchOnDescription: true,
756863
matchOnDetail: true,
757-
title: 'Select Experiments to Remove'
864+
title: 'Select Experiment(s) to Remove'
758865
}
759866
)
760867
expect(mockExperimentRemove).to.be.calledWith(

extension/src/vscode/title.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export enum Title {
1717
SELECT_COLUMNS = 'Select Columns to Display in the Experiments Table',
1818
SELECT_EXPERIMENT = 'Select an Experiment',
1919
SELECT_EXPERIMENTS = 'Select Experiments',
20-
SELECT_EXPERIMENTS_REMOVE = 'Select Experiments to Remove',
20+
SELECT_EXPERIMENTS_PUSH = 'Select Experiment(s) to Push',
21+
SELECT_EXPERIMENTS_REMOVE = 'Select Experiment(s) to Remove',
2122
SELECT_EXPERIMENTS_TO_PLOT = 'Select up to 7 Experiments to Display in Plots',
2223
SELECT_FILTERS_TO_REMOVE = 'Select Filter(s) to Remove',
2324
SELECT_FOCUSED_PROJECTS = 'Select Project(s) to Focus (set dvc.focusedProjects)',

0 commit comments

Comments
 (0)