Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@
"command": "dvc.setupWorkspace",
"category": "DVC"
},
{
"title": "%command.shareExperimentAsBranch%",
"command": "dvc.shareExperimentAsBranch",
"category": "DVC",
"icon": "$(repo-push)"
},
{
"title": "%command.showCommands",
"command": "dvc.showCommands",
Expand Down Expand Up @@ -741,6 +747,10 @@
"command": "dvc.showCommands",
"when": "false"
},
{
"command": "dvc.shareExperimentAsBranch",
"when": "dvc.commands.available && dvc.project.available && !dvc.experiment.running"
},
{
"command": "dvc.showExperiments",
"when": "dvc.commands.available && dvc.project.available"
Expand Down
1 change: 1 addition & 0 deletions extension/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"command.resetAndRunCheckpointExperiment": "Reset and Run Experiment",
"command.selectForCompare": "Select for Compare",
"command.setupWorkspace": "Setup The Workspace",
"command.shareExperimentAsBranch": "Share Experiment as Branch",
"command.showCommands": "Show Commands",
"command.showExperiments": "Show Experiments",
"command.showOutput": "Show DVC Output",
Expand Down
1 change: 1 addition & 0 deletions extension/src/commands/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum RegisteredCliCommands {
EXPERIMENT_RUN = 'dvc.runExperiment',
EXPERIMENT_RUN_QUEUED = 'dvc.startExperimentsQueue',
EXPERIMENT_RESET_AND_RUN = 'dvc.resetAndRunCheckpointExperiment',
EXPERIMENT_SHARE_AS_BRANCH = 'dvc.shareExperimentAsBranch',
QUEUE_EXPERIMENT = 'dvc.queueExperiment',

EXPERIMENT_VIEW_APPLY = 'dvc.views.experiments.applyExperiment',
Expand Down
27 changes: 27 additions & 0 deletions extension/src/experiments/commands/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AvailableCommands } from '../../commands/internal'
import { gitPushBranch } from '../../git'
import { Toast } from '../../vscode/toast'
import { WorkspaceExperiments } from '../workspace'

export const getBranchExperimentCommand =
(experiments: WorkspaceExperiments) =>
(cwd: string, name: string, input: string) =>
experiments.runCommand(
AvailableCommands.EXPERIMENT_BRANCH,
cwd,
name,
input
)

export const getShareExperimentAsBranchCommand =
(experiments: WorkspaceExperiments) =>
async (cwd: string, name: string, input: string) => {
const branchCommand = getBranchExperimentCommand(experiments)
await branchCommand(cwd, name, input)

await experiments.runCommand(AvailableCommands.EXPERIMENT_APPLY, cwd, name)

await experiments.runCommand(AvailableCommands.PUSH, cwd)

return Toast.showOutput(gitPushBranch(cwd, input))
}
47 changes: 16 additions & 31 deletions extension/src/experiments/commands/register.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
getBranchExperimentCommand,
getShareExperimentAsBranchCommand
} from '.'
import { pickGarbageCollectionFlags } from '../quickPick'
import { WorkspaceExperiments } from '../workspace'
import { AvailableCommands, InternalCommands } from '../../commands/internal'
Expand All @@ -6,9 +10,6 @@ import {
RegisteredCommands
} from '../../commands/external'
import { Title } from '../../vscode/title'
import { gitPushBranch } from '../../git'
import { Toast } from '../../vscode/toast'
import { Args } from '../../cli/constants'

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

Expand Down Expand Up @@ -156,12 +157,7 @@ const registerExperimentInputCommands = (
RegisteredCliCommands.EXPERIMENT_BRANCH,
() =>
experiments.getCwdExpNameAndInputThenRun(
(cwd, ...args: Args) =>
experiments.runCommand(
AvailableCommands.EXPERIMENT_BRANCH,
cwd,
...args
),
getBranchExperimentCommand(experiments),
Title.ENTER_BRANCH_NAME
)
)
Expand All @@ -170,38 +166,27 @@ const registerExperimentInputCommands = (
RegisteredCliCommands.EXPERIMENT_VIEW_BRANCH,
({ dvcRoot, id }: ExperimentDetails) =>
experiments.getExpNameAndInputThenRun(
(name: string, input: string) =>
experiments.runCommand(
AvailableCommands.EXPERIMENT_BRANCH,
dvcRoot,
name,
input
),
getBranchExperimentCommand(experiments),
Title.ENTER_BRANCH_NAME,
dvcRoot,
id
)
)

internalCommands.registerExternalCliCommand(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar blocks of code found in 2 locations. Consider refactoring.

RegisteredCliCommands.EXPERIMENT_SHARE_AS_BRANCH,
() =>
experiments.getCwdExpNameAndInputThenRun(
getShareExperimentAsBranchCommand(experiments),
Title.ENTER_BRANCH_NAME
)
)

internalCommands.registerExternalCliCommand(
RegisteredCliCommands.EXPERIMENT_VIEW_SHARE_AS_BRANCH,
({ dvcRoot, id }: ExperimentDetails) =>
experiments.getExpNameAndInputThenRun(
async (name: string, input: string) => {
await experiments.runCommand(
AvailableCommands.EXPERIMENT_BRANCH,
dvcRoot,
name,
input
)
await experiments.runCommand(
AvailableCommands.EXPERIMENT_APPLY,
dvcRoot,
name
)
await experiments.runCommand(AvailableCommands.PUSH, dvcRoot)
return Toast.showOutput(gitPushBranch(dvcRoot, input))
},
getShareExperimentAsBranchCommand(experiments),
Title.ENTER_BRANCH_NAME,
dvcRoot,
id
Expand Down
2 changes: 1 addition & 1 deletion extension/src/experiments/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export class WorkspaceExperiments extends BaseWorkspaceWebviews<
return
}

return this.getInputAndRun(runCommand, title, name)
return this.getInputAndRun(runCommand, title, cwd, name)
}

public getExpNameThenRun(commandId: CommandId, cwd: string, id: string) {
Expand Down
1 change: 1 addition & 0 deletions extension/src/telemetry/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export interface IEventNamePropertyMapping {
[EventName.EXPERIMENT_RUN_QUEUED]: undefined
[EventName.EXPERIMENT_RESET_AND_RUN]: undefined
[EventName.EXPERIMENT_SELECT]: undefined
[EventName.EXPERIMENT_SHARE_AS_BRANCH]: undefined
[EventName.EXPERIMENT_SHOW]: undefined
[EventName.EXPERIMENT_SORT_ADD]: undefined
[EventName.EXPERIMENT_SORT_ADD_STARRED]: undefined
Expand Down
110 changes: 109 additions & 1 deletion extension/src/test/suite/experiments/workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { WorkspaceExperiments } from '../../../experiments/workspace'
import { Experiments } from '../../../experiments'
import * as QuickPick from '../../../vscode/quickPick'
import { CliExecutor } from '../../../cli/executor'
import { closeAllEditors, mockDuration } from '../util'
import { closeAllEditors, getInputBoxEvent, mockDuration } from '../util'
import { dvcDemoPath } from '../../util'
import { RegisteredCliCommands } from '../../../commands/external'
import * as Telemetry from '../../../telemetry'
Expand All @@ -26,6 +26,7 @@ import { WEBVIEW_TEST_TIMEOUT } from '../timeouts'
import { Title } from '../../../vscode/title'
import { join } from '../../util/path'
import { AvailableCommands } from '../../../commands/internal'
import * as Git from '../../../git'

suite('Workspace Experiments Test Suite', () => {
const disposable = Disposable.fn()
Expand Down Expand Up @@ -564,6 +565,113 @@ suite('Workspace Experiments Test Suite', () => {
})
})

describe('dvc.branchExperiment', () => {
it('should be able to create a branch from an experiment', async () => {
const { experiments } = buildExperiments(disposable)
await experiments.isReady()

const testExperiment = 'exp-83425'
const mockBranch = 'brunch'
const inputEvent = getInputBoxEvent(mockBranch)

stub(window, 'showQuickPick').resolves({
value: { id: testExperiment, name: testExperiment }
} as QuickPickItemWithValue<{ id: string; name: string }>)

const mockExperimentBranch = stub(
CliExecutor.prototype,
'experimentBranch'
).resolves(
`Git branch '${mockBranch}' has been created from experiment '${testExperiment}'.
To switch to the new branch run:
git checkout ${mockBranch}`
)

stub(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(WorkspaceExperiments as any).prototype,
'getOnlyOrPickProject'
).returns(dvcDemoPath)

stub(WorkspaceExperiments.prototype, 'getRepository').returns(experiments)

await commands.executeCommand(RegisteredCliCommands.EXPERIMENT_BRANCH)

await inputEvent
expect(mockExperimentBranch).to.be.calledWithExactly(
dvcDemoPath,
testExperiment,
mockBranch
)
})
})

describe('dvc.shareExperimentAsBranch', () => {
it('should be able to share an experiment as a branch', async () => {
const { experiments } = buildExperiments(disposable)
await experiments.isReady()

const testExperiment = 'exp-83425'
const mockBranch = 'more-brunch'
const inputEvent = getInputBoxEvent(mockBranch)

stub(window, 'showQuickPick').resolves({
value: { id: testExperiment, name: testExperiment }
} as QuickPickItemWithValue<{ id: string; name: string }>)

const mockExperimentBranch = stub(
CliExecutor.prototype,
'experimentBranch'
).resolves(
`Git branch '${mockBranch}' has been created from experiment '${testExperiment}'.
To switch to the new branch run:
git checkout ${mockBranch}`
)
const mockExperimentApply = stub(
CliExecutor.prototype,
'experimentApply'
).resolves(
`Changes for experiment '${testExperiment}' have been applied to your current workspace.`
)
const mockPush = stub(CliExecutor.prototype, 'push').resolves(
'10 files updated.'
)
const mockGitPush = stub(Git, 'gitPushBranch')
const branchPushedToRemote = new Promise(resolve =>
mockGitPush.callsFake(() => {
resolve(undefined)
return Promise.resolve(`${mockBranch} pushed to remote`)
})
)

stub(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(WorkspaceExperiments as any).prototype,
'getOnlyOrPickProject'
).returns(dvcDemoPath)

stub(WorkspaceExperiments.prototype, 'getRepository').returns(experiments)

await commands.executeCommand(
RegisteredCliCommands.EXPERIMENT_SHARE_AS_BRANCH
)

await inputEvent
await branchPushedToRemote
expect(mockExperimentBranch).to.be.calledWithExactly(
dvcDemoPath,
testExperiment,
mockBranch
)
expect(mockExperimentApply).to.be.calledWithExactly(
dvcDemoPath,
testExperiment
)
expect(mockPush).to.be.calledWithExactly(dvcDemoPath)
expect(mockGitPush).to.be.calledWithExactly(dvcDemoPath, mockBranch)
})
})

describe('dvc.removeExperiment', () => {
it('should ask the user to pick an experiment and then remove that experiment from the workspace', async () => {
const mockExperiment = 'exp-to-remove'
Expand Down