Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add remove queued experiment command #1454

Merged
merged 2 commits into from
Mar 17, 2022
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
9 changes: 9 additions & 0 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@
"category": "DVC",
"icon": "$(close-all)"
},
{
"title": "%command.removeQueuedExperiment%",
"command": "dvc.removeQueuedExperiment",
"category": "DVC"
},
{
"title": "%command.removeTarget%",
"command": "dvc.removeTarget",
Expand Down Expand Up @@ -513,6 +518,10 @@
"command": "dvc.removeExperimentsTableSorts",
"when": "dvc.commands.available && dvc.project.available"
},
{
"command": "dvc.removeQueuedExperiment",
"when": "dvc.commands.available && dvc.project.available"
},
{
"command": "dvc.removeTarget",
"when": "false"
Expand Down
1 change: 1 addition & 0 deletions extension/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"command.removeExperimentQueue": "Remove All Queued Experiments",
"command.removeExperimentsTableFilters": "Remove Filter(s) From Experiments Table",
"command.removeExperimentsTableSorts": "Remove Sort(s) From Experiments Table",
"command.removeQueuedExperiment": "Remove Queued Experiment",
"command.removeTarget": "Remove",
"command.renameTarget": "Rename",
"command.resetWorkspace": "Reset the Workspace",
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 @@ -4,6 +4,7 @@ export enum RegisteredCliCommands {
EXPERIMENT_GARBAGE_COLLECT = 'dvc.experimentGarbageCollect',
EXPERIMENT_REMOVE = 'dvc.removeExperiment',
EXPERIMENT_REMOVE_QUEUE = 'dvc.removeExperimentQueue',
EXPERIMENT_REMOVE_QUEUED = 'dvc.removeQueuedExperiment',
EXPERIMENT_RUN = 'dvc.runExperiment',
EXPERIMENT_RUN_QUEUED = 'dvc.runQueuedExperiments',
EXPERIMENT_RUN_RESET = 'dvc.runResetExperiment',
Expand Down
5 changes: 5 additions & 0 deletions extension/src/experiments/commands/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ const registerExperimentNameCommands = (
RegisteredCliCommands.EXPERIMENT_REMOVE,
() => experiments.getExpNameThenRun(AvailableCommands.EXPERIMENT_REMOVE)
)

internalCommands.registerExternalCliCommand(
RegisteredCliCommands.EXPERIMENT_REMOVE_QUEUED,
() => experiments.getQueuedExpThenRun(AvailableCommands.EXPERIMENT_REMOVE)
)
}

const registerExperimentInputCommands = (
Expand Down
3 changes: 2 additions & 1 deletion extension/src/experiments/data/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { join } from 'path'
import { GIT_REFS } from '../../git'
import { GIT_LOGS_REFS, GIT_REFS } from '../../git'

export const EXPERIMENTS_GIT_REFS = join(GIT_REFS, 'exps')
export const EXPERIMENTS_GIT_LOGS_REFS = join(GIT_LOGS_REFS, 'exps')
9 changes: 7 additions & 2 deletions extension/src/experiments/data/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { join } from 'path'
import { EventEmitter } from 'vscode'
import { collectFiles } from './collect'
import { EXPERIMENTS_GIT_REFS } from './constants'
import { EXPERIMENTS_GIT_LOGS_REFS, EXPERIMENTS_GIT_REFS } from './constants'
import {
createFileSystemWatcher,
getRelativePattern
Expand Down Expand Up @@ -55,7 +55,12 @@ export class ExperimentsData extends BaseData<ExperimentsOutput> {

private async watchExpGitRefs(): Promise<void> {
const gitRoot = await getGitRepositoryRoot(this.dvcRoot)
const watchedRelPaths = [DOT_GIT_HEAD, EXPERIMENTS_GIT_REFS, HEADS_GIT_REFS]
const watchedRelPaths = [
DOT_GIT_HEAD,
EXPERIMENTS_GIT_REFS,
EXPERIMENTS_GIT_LOGS_REFS,
HEADS_GIT_REFS
]

this.dispose.track(
createFileSystemWatcher(
Expand Down
4 changes: 4 additions & 0 deletions extension/src/experiments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ export class Experiments extends BaseRepository<TableData> {
return pickExperiment(this.experiments.getCurrentExperiments())
}

public pickQueuedExperiment() {
return pickExperiment(this.experiments.getQueuedExperiments())
}

public async pickParamsToQueue() {
const base = await pickExperiment(this.experiments.getExperiments())

Expand Down
15 changes: 14 additions & 1 deletion extension/src/experiments/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,11 @@ export class ExperimentsModel {
}

public getCurrentExperiments() {
return this.flattenExperiments().filter(({ queued }) => !queued)
return this.splitExperimentsByQueued()
}

public getQueuedExperiments() {
return this.splitExperimentsByQueued(true)
}

public getCheckpoints(id: string): Experiment[] | undefined {
Expand Down Expand Up @@ -381,6 +385,15 @@ export class ExperimentsModel {
return flattenMapValues(this.experimentsByBranch)
}

private splitExperimentsByQueued(getQueued = false) {
return this.flattenExperiments().filter(({ queued }) => {
if (getQueued) {
return queued
}
return !queued
})
}

private flattenCheckpoints() {
return flattenMapValues(this.checkpointsByTip)
}
Expand Down
41 changes: 29 additions & 12 deletions extension/src/experiments/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,19 +150,15 @@ export class WorkspaceExperiments extends BaseWorkspaceWebviews<
return Toast.showOutput(stdout)
}

public getExpNameThenRun = async (commandId: CommandId) => {
const cwd = await this.getFocusedOrOnlyOrPickProject()
if (!cwd) {
return
}

const experiment = await this.pickCurrentExperiment(cwd)
public getExpNameThenRun(commandId: CommandId) {
return this.pickExpThenRun(commandId, cwd =>
this.pickCurrentExperiment(cwd)
)
}

if (!experiment) {
return
}
return Toast.showOutput(
this.internalCommands.executeCommand(commandId, cwd, experiment.name)
public getQueuedExpThenRun(commandId: CommandId) {
return this.pickExpThenRun(commandId, cwd =>
this.getRepository(cwd).pickQueuedExperiment()
)
}

Expand Down Expand Up @@ -247,6 +243,27 @@ export class WorkspaceExperiments extends BaseWorkspaceWebviews<
return experiments
}

private async pickExpThenRun(
commandId: CommandId,
pickFunc: (
cwd: string
) => Thenable<{ id: string; name: string } | undefined> | undefined
) {
const cwd = await this.getFocusedOrOnlyOrPickProject()
if (!cwd) {
return
}

const experiment = await pickFunc(cwd)

if (!experiment) {
return
}
return Toast.showOutput(
this.internalCommands.executeCommand(commandId, cwd, experiment.name)
)
}

private async getDvcRoot(overrideRoot?: string) {
return overrideRoot || (await this.getFocusedOrOnlyOrPickProject())
}
Expand Down
1 change: 1 addition & 0 deletions extension/src/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const DOT_GIT = '.git'
export const DOT_GIT_HEAD = join(DOT_GIT, 'HEAD')
export const DOT_GIT_INDEX = join(DOT_GIT, 'index')
export const GIT_REFS = join(DOT_GIT, 'refs')
export const GIT_LOGS_REFS = join(DOT_GIT, 'logs', 'refs')
export const HEADS_GIT_REFS = join(GIT_REFS, 'heads')

const getUris = (repositoryRoot: string, relativePaths: string[]) =>
Expand Down
6 changes: 5 additions & 1 deletion extension/src/repository/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import {
getRelativePattern
} from '../../fileSystem/watcher'
import { join } from '../../test/util/path'
import { EXPERIMENTS_GIT_REFS } from '../../experiments/data/constants'
import {
EXPERIMENTS_GIT_LOGS_REFS,
EXPERIMENTS_GIT_REFS
} from '../../experiments/data/constants'

export type Data = {
diffFromHead: DiffOutput
Expand All @@ -28,6 +31,7 @@ export const isExcluded = (dvcRoot: string, path: string) =>
(path.includes('.git') && (path.includes('HEAD') || path.includes('index')))
) ||
path.includes(EXPERIMENTS_GIT_REFS) ||
path.includes(EXPERIMENTS_GIT_LOGS_REFS) ||
ignoredDotDirectories.test(path)

export class RepositoryData {
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 @@ -82,6 +82,7 @@ export interface IEventNamePropertyMapping {
[EventName.EXPERIMENT_METRICS_AND_PARAMS_TOGGLE]: undefined
[EventName.EXPERIMENT_REMOVE]: undefined
[EventName.EXPERIMENT_REMOVE_QUEUE]: undefined
[EventName.EXPERIMENT_REMOVE_QUEUED]: undefined
[EventName.EXPERIMENT_RUN]: undefined
[EventName.EXPERIMENT_RUN_QUEUED]: undefined
[EventName.EXPERIMENT_RUN_RESET]: undefined
Expand Down
35 changes: 35 additions & 0 deletions extension/src/test/suite/experiments/workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,4 +417,39 @@ suite('Workspace Experiments Test Suite', () => {
expect(mockExperimentRemove).to.be.calledWith(dvcDemoPath, '--queue')
})
})

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

const { experiments } = buildExperiments(disposable)

await experiments.isReady()

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

stub(window, 'showQuickPick').resolves({
value: { id: mockExperiment, name: mockExperiment }
} as QuickPickItemWithValue<{ id: string; name: string }>)
const mockExperimentRemove = stub(
CliExecutor.prototype,
'experimentRemove'
)

await commands.executeCommand(
RegisteredCliCommands.EXPERIMENT_REMOVE_QUEUED
)

expect(mockExperimentRemove).to.be.calledWith(dvcDemoPath, mockExperiment)
})
})
})