Skip to content

Commit d8ae4a0

Browse files
authored
Share experiment to Studio from experiments table (#3289)
* create prototype for sharing experiments from the experiments table to Studio * add tests * refactor code * self review * rearrange code to fit existing structure * fix package json entries * move command out of register * send correct params
1 parent a68ceba commit d8ae4a0

File tree

19 files changed

+506
-13
lines changed

19 files changed

+506
-13
lines changed

extension/package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,12 @@
514514
"category": "DVC",
515515
"icon": "$(repo-push)"
516516
},
517+
{
518+
"title": "%command.views.experiments.shareExperimentToStudio%",
519+
"command": "dvc.views.experiments.shareExperimentToStudio",
520+
"category": "DVC",
521+
"icon": "$(repo-push)"
522+
},
517523
{
518524
"title": "%command.views.experimentsTree.selectExperiments%",
519525
"command": "dvc.views.experimentsTree.selectExperiments",
@@ -893,6 +899,10 @@
893899
"command": "dvc.views.experiments.shareExperimentAsCommit",
894900
"when": "false"
895901
},
902+
{
903+
"command": "dvc.views.experiments.shareExperimentToStudio",
904+
"when": "false"
905+
},
896906
{
897907
"command": "dvc.views.experimentsFilterByTree.removeAllFilters",
898908
"when": "false"
@@ -1149,6 +1159,11 @@
11491159
"group": "inline@3",
11501160
"when": "view == dvc.views.experimentsTree && dvc.commands.available && viewItem =~ /^(experiment|queued)$/ && !dvc.experiment.running"
11511161
},
1162+
{
1163+
"command": "dvc.views.experiments.shareExperimentToStudio",
1164+
"group": "1_share@0",
1165+
"when": "view == dvc.views.experimentsTree && dvc.commands.available && viewItem == experiment && !dvc.experiment.running"
1166+
},
11521167
{
11531168
"command": "dvc.views.experiments.shareExperimentAsCommit",
11541169
"group": "1_share@1",
@@ -1591,6 +1606,7 @@
15911606
"lodash.isequal": "4.5.0",
15921607
"lodash.merge": "4.6.2",
15931608
"lodash.omit": "4.5.0",
1609+
"node-fetch": "2.6.9",
15941610
"tree-kill": "1.2.2",
15951611
"uuid": "9.0.0",
15961612
"vscode-languageclient": "8.0.2"

extension/package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
"command.views.experiments.resetAndRunCheckpointExperiment": "Modify Param(s) and Run",
7878
"command.views.experiments.shareExperimentAsBranch": "Share as Branch",
7979
"command.views.experiments.shareExperimentAsCommit": "Commit and Share",
80+
"command.views.experiments.shareExperimentToStudio": "Share to Studio",
8081
"command.views.experimentsTree.selectExperiments": "Select Experiments to Display in Plots",
8182
"command.views.plotsPathsTree.selectPlots": "Select Plots to Display",
8283
"command.views.plotsPathsTree.refreshPlots": "Refresh Plots for Selected Experiments",

extension/src/cli/git/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export enum Command {
1717
INITIALIZE = 'init',
1818
LOG = 'log',
1919
LS_FILES = 'ls-files',
20+
LS_REMOTE = 'ls-remote',
2021
PUSH = 'push',
2122
RESET = 'reset',
2223
REV_PARSE = 'rev-parse',
@@ -30,6 +31,7 @@ export enum Flag {
3031
DOT = '.',
3132
EXCLUDE_STANDARD = '--exclude-standard',
3233
FORCE = '-f',
34+
GET_URL = '--get-url',
3335
HARD = '--hard',
3436
MESSAGE = '-m',
3537
NAME_ONLY = '--name-only',

extension/src/cli/git/reader.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { isDirectory } from '../../fileSystem'
88

99
export const autoRegisteredCommands = {
1010
GIT_GET_COMMIT_MESSAGES: 'getCommitMessages',
11+
GIT_GET_REMOTE_URL: 'getRemoteUrl',
1112
GIT_GET_REPOSITORY_ROOT: 'getGitRepositoryRoot',
1213
GIT_HAS_CHANGES: 'hasChanges',
1314
GIT_LIST_UNTRACKED: 'listUntracked'
@@ -59,6 +60,15 @@ export class GitReader extends GitCli {
5960
}
6061
}
6162

63+
public async getRemoteUrl(cwd: string): Promise<string> {
64+
const options = getOptions(cwd, Command.LS_REMOTE, Flag.GET_URL)
65+
try {
66+
return await this.executeProcess(options)
67+
} catch {
68+
return ''
69+
}
70+
}
71+
6272
public async listUntracked(cwd: string) {
6373
const [files, dirs] = await Promise.all([
6474
this.getUntrackedFiles(cwd),

extension/src/commands/external.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,5 +99,6 @@ export enum RegisteredCommands {
9999

100100
CONNECT_SHOW = 'dvc.showConnect',
101101
ADD_STUDIO_ACCESS_TOKEN = 'dvc.addStudioAccessToken',
102-
REMOVE_STUDIO_ACCESS_TOKEN = 'dvc.removeStudioAccessToken'
102+
REMOVE_STUDIO_ACCESS_TOKEN = 'dvc.removeStudioAccessToken',
103+
EXPERIMENT_VIEW_SHARE_TO_STUDIO = 'dvc.views.experiments.shareExperimentToStudio'
103104
}

extension/src/commands/internal.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ import { Disposable } from '../class/dispose'
1616

1717
type Command = (...args: Args) => unknown | Promise<unknown>
1818

19-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
2019
export const AvailableCommands = Object.assign(
21-
{} as const,
20+
{ EXP_PUSH: 'expPush' } as const,
2221
CliExecutorCommands,
2322
CliReaderCommands,
2423
dvcRunnerCommands,
@@ -28,7 +27,7 @@ export const AvailableCommands = Object.assign(
2827
typeof CliReaderCommands &
2928
typeof dvcRunnerCommands &
3029
typeof GitExecutorCommands &
31-
typeof GitReaderCommands
30+
typeof GitReaderCommands & { EXP_PUSH: 'expPush' }
3231
export type CommandId =
3332
(typeof AvailableCommands)[keyof typeof AvailableCommands]
3433

extension/src/connect/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ export class Connect extends BaseRepository<undefined> {
6161
return this.storeSecret(STUDIO_ACCESS_TOKEN_KEY, token)
6262
}
6363

64+
public getStudioAccessToken() {
65+
return this.getSecret(STUDIO_ACCESS_TOKEN_KEY)
66+
}
67+
6468
private handleMessageFromWebview(message: MessageFromWebview) {
6569
switch (message.type) {
6670
case MessageFromWebviewType.OPEN_STUDIO:
@@ -89,7 +93,7 @@ export class Connect extends BaseRepository<undefined> {
8993
}
9094

9195
private async setContext() {
92-
const storedToken = await this.getSecret(STUDIO_ACCESS_TOKEN_KEY)
96+
const storedToken = await this.getStudioAccessToken()
9397
if (isStudioAccessToken(storedToken)) {
9498
if (this.deferred.state === 'resolved') {
9599
void showInformation(

extension/src/experiments/commands/index.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import { Progress } from 'vscode'
1+
import { Progress, commands } from 'vscode'
22
import { AvailableCommands, InternalCommands } from '../../commands/internal'
33
import { Toast } from '../../vscode/toast'
44
import { WorkspaceExperiments } from '../workspace'
5+
import { Connect } from '../../connect'
6+
import { RegisteredCommands } from '../../commands/external'
57

68
export const getBranchExperimentCommand =
79
(experiments: WorkspaceExperiments) =>
@@ -104,3 +106,19 @@ export const getShareExperimentAsCommitCommand =
104106
return Toast.delayProgressClosing()
105107
})
106108
}
109+
110+
export const getShareExperimentToStudioCommand =
111+
(internalCommands: InternalCommands, connect: Connect) =>
112+
async ({ dvcRoot, id }: { dvcRoot: string; id: string }) => {
113+
const studioAccessToken = await connect.getStudioAccessToken()
114+
if (!studioAccessToken) {
115+
return commands.executeCommand(RegisteredCommands.CONNECT_SHOW)
116+
}
117+
118+
return internalCommands.executeCommand(
119+
AvailableCommands.EXP_PUSH,
120+
studioAccessToken,
121+
dvcRoot,
122+
id
123+
)
124+
}

extension/src/experiments/commands/register.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import {
22
getBranchExperimentCommand,
33
getShareExperimentAsBranchCommand,
4-
getShareExperimentAsCommitCommand
4+
getShareExperimentAsCommitCommand,
5+
getShareExperimentToStudioCommand
56
} from '.'
67
import { pickGarbageCollectionFlags } from '../quickPick'
78
import { WorkspaceExperiments } from '../workspace'
@@ -14,6 +15,7 @@ import { Title } from '../../vscode/title'
1415
import { Context, getDvcRootFromContext } from '../../vscode/context'
1516
import { Setup } from '../../setup'
1617
import { showSetupOrExecuteCommand } from '../../commands/util'
18+
import { Connect } from '../../connect'
1719

1820
type ExperimentDetails = { dvcRoot: string; id: string }
1921

@@ -329,7 +331,8 @@ const registerExperimentRunCommands = (
329331
export const registerExperimentCommands = (
330332
experiments: WorkspaceExperiments,
331333
internalCommands: InternalCommands,
332-
setup: Setup
334+
setup: Setup,
335+
connect: Connect
333336
) => {
334337
registerExperimentCwdCommands(experiments, internalCommands)
335338
registerExperimentNameCommands(experiments, internalCommands)
@@ -354,4 +357,9 @@ export const registerExperimentCommands = (
354357
({ dvcRoot, id }: ExperimentDetails) =>
355358
experiments.getRepository(dvcRoot).toggleExperimentStatus(id)
356359
)
360+
361+
internalCommands.registerExternalCommand(
362+
RegisteredCommands.EXPERIMENT_VIEW_SHARE_TO_STUDIO,
363+
getShareExperimentToStudioCommand(internalCommands, connect)
364+
)
357365
}

extension/src/experiments/webview/messages.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ export class WebviewMessages {
184184
case MessageFromWebviewType.ADD_CONFIGURATION: {
185185
return this.addConfiguration()
186186
}
187+
case MessageFromWebviewType.SHARE_EXPERIMENT_TO_STUDIO:
188+
return commands.executeCommand(
189+
RegisteredCommands.EXPERIMENT_VIEW_SHARE_TO_STUDIO,
190+
{ dvcRoot: this.dvcRoot, id: message.payload }
191+
)
187192

188193
default:
189194
Logger.error(`Unexpected message: ${JSON.stringify(message)}`)

0 commit comments

Comments
 (0)