From 987bb71a44bbe66869414378808443e2a841acf1 Mon Sep 17 00:00:00 2001 From: Zhibo Lin <147509942+LE0-Lin@users.noreply.github.com> Date: Thu, 20 Aug 2026 21:54:23 +0800 Subject: [PATCH 1/3] Add unpause action for paused containers --- extensions/vscode-containers/package.json | 12 ++++++++- extensions/vscode-containers/package.nls.json | 1 + .../src/commands/containers/startContainer.ts | 2 +- .../commands/containers/unpauseContainer.ts | 26 ++++++++++++++++++ .../src/commands/registerCommands.ts | 2 ++ .../DockerClientBase/DockerClientBase.ts | 27 +++++++++++++++++++ .../src/clients/WslcClient/WslcClient.ts | 7 +++++ .../src/contracts/ContainerClient.ts | 18 +++++++++++++ .../src/test/ContainersClientE2E.test.ts | 24 +++++++++++++++++ .../clients/DockerClient/DockerClient.test.ts | 15 +++++++++++ .../clients/WslcClient/WslcCanary.test.ts | 1 + .../clients/WslcClient/WslcClient.test.ts | 4 +++ 12 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 extensions/vscode-containers/src/commands/containers/unpauseContainer.ts diff --git a/extensions/vscode-containers/package.json b/extensions/vscode-containers/package.json index c9656f64..ce8e8084 100644 --- a/extensions/vscode-containers/package.json +++ b/extensions/vscode-containers/package.json @@ -403,7 +403,12 @@ }, { "command": "vscode-containers.containers.start", - "when": "view == vscode-containers.views.containers && viewItem =~ /^(created|dead|exited|paused|terminated)Container$/i", + "when": "view == vscode-containers.views.containers && viewItem =~ /^(created|dead|exited|terminated)Container$/i", + "group": "containers_2_active@5" + }, + { + "command": "vscode-containers.containers.unpause", + "when": "view == vscode-containers.views.containers && viewItem =~ /^pausedContainer$/i", "group": "containers_2_active@5" }, { @@ -2743,6 +2748,11 @@ "title": "%vscode-containers.commands.containers.stop%", "category": "%vscode-containers.commands.category.containers%" }, + { + "command": "vscode-containers.containers.unpause", + "title": "%vscode-containers.commands.containers.unpause%", + "category": "%vscode-containers.commands.category.containers%" + }, { "command": "vscode-containers.containers.stats", "title": "%vscode-containers.commands.containers.stats%", diff --git a/extensions/vscode-containers/package.nls.json b/extensions/vscode-containers/package.nls.json index 349b01c7..f2f03595 100644 --- a/extensions/vscode-containers/package.nls.json +++ b/extensions/vscode-containers/package.nls.json @@ -248,6 +248,7 @@ "vscode-containers.commands.containers.select": "Select container", "vscode-containers.commands.containers.start": "Start", "vscode-containers.commands.containers.stop": "Stop", + "vscode-containers.commands.containers.unpause": "Unpause", "vscode-containers.commands.containers.stats": "Stats", "vscode-containers.commands.containers.viewLogs": "View Logs", "vscode-containers.commands.containers.composeGroup.logs": "Compose Logs", diff --git a/extensions/vscode-containers/src/commands/containers/startContainer.ts b/extensions/vscode-containers/src/commands/containers/startContainer.ts index c0c12b77..f409c355 100644 --- a/extensions/vscode-containers/src/commands/containers/startContainer.ts +++ b/extensions/vscode-containers/src/commands/containers/startContainer.ts @@ -13,7 +13,7 @@ export async function startContainer(context: IActionContext, node?: ContainerTr nodes = await multiSelectNodes( { ...context, noItemFoundErrorMessage: vscode.l10n.t('No containers are available to start') }, ext.containersTree, - /^(created|dead|exited|paused|terminated)Container$/i, + /^(created|dead|exited|terminated)Container$/i, node, nodes ); diff --git a/extensions/vscode-containers/src/commands/containers/unpauseContainer.ts b/extensions/vscode-containers/src/commands/containers/unpauseContainer.ts new file mode 100644 index 00000000..c8e5940f --- /dev/null +++ b/extensions/vscode-containers/src/commands/containers/unpauseContainer.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IActionContext } from '@microsoft/vscode-azext-utils'; +import * as vscode from 'vscode'; +import { ext } from '../../extensionVariables'; +import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem'; +import { multiSelectNodes } from '../../utils/multiSelectNodes'; + +export async function unpauseContainer(context: IActionContext, node?: ContainerTreeItem, nodes?: ContainerTreeItem[]): Promise { + nodes = await multiSelectNodes( + { ...context, noItemFoundErrorMessage: vscode.l10n.t('No containers are available to unpause') }, + ext.containersTree, + /^pausedContainer$/i, + node, + nodes + ); + + await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: vscode.l10n.t('Unpausing Container(s)...') }, async () => { + await ext.runWithDefaults(client => + client.unpauseContainers({ container: nodes.map(n => n.containerId) }) + ); + }); +} diff --git a/extensions/vscode-containers/src/commands/registerCommands.ts b/extensions/vscode-containers/src/commands/registerCommands.ts index cea77c8f..54e808fb 100644 --- a/extensions/vscode-containers/src/commands/registerCommands.ts +++ b/extensions/vscode-containers/src/commands/registerCommands.ts @@ -27,6 +27,7 @@ import { selectContainer } from "./containers/selectContainer"; import { startContainer } from "./containers/startContainer"; import { stats } from "./containers/stats"; import { stopContainer } from "./containers/stopContainer"; +import { unpauseContainer } from "./containers/unpauseContainer"; import { viewContainerLogs } from "./containers/viewContainerLogs"; import { configureDockerContextsExplorer, dockerContextsHelp } from "./context/DockerContextsViewCommands"; import { inspectDockerContext } from "./context/inspectDockerContext"; @@ -141,6 +142,7 @@ export function registerCommands(): void { registerCommand('vscode-containers.containers.select', selectContainer); registerCommand('vscode-containers.containers.start', startContainer); registerCommand('vscode-containers.containers.stop', stopContainer); + registerCommand('vscode-containers.containers.unpause', unpauseContainer); registerWorkspaceCommand('vscode-containers.containers.stats', stats); registerWorkspaceCommand('vscode-containers.containers.viewLogs', viewContainerLogs); registerWorkspaceCommand('vscode-containers.containers.composeGroup.logs', composeGroupLogs); diff --git a/packages/vscode-container-client/src/clients/DockerClientBase/DockerClientBase.ts b/packages/vscode-container-client/src/clients/DockerClientBase/DockerClientBase.ts index 928732c1..1e8f1b77 100644 --- a/packages/vscode-container-client/src/clients/DockerClientBase/DockerClientBase.ts +++ b/packages/vscode-container-client/src/clients/DockerClientBase/DockerClientBase.ts @@ -80,6 +80,7 @@ import type { StatPathItem, StopContainersCommandOptions, TagImageCommandOptions, + UnpauseContainersCommandOptions, UseContextCommandOptions, VersionCommandOptions, VersionItem, @@ -862,6 +863,32 @@ export abstract class DockerClientBase extends ConfigurableClient implements ICo //#endregion + //#region UnpauseContainers Command + + protected getUnpauseContainersCommandArgs(options: UnpauseContainersCommandOptions): CommandLineArgs { + return composeArgs( + withArg('container', 'unpause'), + withArg(...toArray(options.container)), + )(); + } + + protected parseUnpauseContainersCommandOutput( + options: UnpauseContainersCommandOptions, + output: string, + strict: boolean, + ): Promise> { + return Promise.resolve(asIds(output)); + } + + unpauseContainers(options: UnpauseContainersCommandOptions): Promise>> { + return this.makeCommandResponse( + this.getUnpauseContainersCommandArgs(options), + (output, strict) => this.parseUnpauseContainersCommandOutput(options, output, strict), + ); + } + + //#endregion + //#region RestartContainers Command protected getRestartContainersCommandArgs(options: RestartContainersCommandOptions): CommandLineArgs { diff --git a/packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts b/packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts index 224d4262..488bb233 100644 --- a/packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts +++ b/packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts @@ -46,6 +46,7 @@ import type { RemoveNetworksCommandOptions, RestartContainersCommandOptions, RunContainerCommandOptions, + UnpauseContainersCommandOptions, VersionCommandOptions, VersionItem, WriteFileCommandOptions, @@ -366,6 +367,12 @@ export class WslcClient extends DockerClientBase { return Promise.reject(new CommandNotSupportedError('wslc does not support the restart command.')); } + // wslc has no `unpause` subcommand. Reject rather than silently inheriting + // a command line that wslc would reject. + public override unpauseContainers(options: UnpauseContainersCommandOptions): Promise>> { + return Promise.reject(new CommandNotSupportedError('wslc does not support the unpause command.')); + } + protected override getInspectContainersCommandArgs(options: InspectContainersCommandOptions): CommandLineArgs { return this.getWslcInspectCommandArgs('container', options.containers); } diff --git a/packages/vscode-container-client/src/contracts/ContainerClient.ts b/packages/vscode-container-client/src/contracts/ContainerClient.ts index a714e466..648da913 100644 --- a/packages/vscode-container-client/src/contracts/ContainerClient.ts +++ b/packages/vscode-container-client/src/contracts/ContainerClient.ts @@ -906,6 +906,23 @@ type StartContainersCommand = { startContainers(options: StartContainersCommandOptions): Promise>>; }; +// Unpause Containers Command Types + +export type UnpauseContainersCommandOptions = CommonCommandOptions & { + /** + * Containers to unpause + */ + container: Array; +}; + +type UnpauseContainersCommand = { + /** + * Generate a CommandResponse for unpausing container(s). + * @param options Command options + */ + unpauseContainers(options: UnpauseContainersCommandOptions): Promise>>; +}; + // Restart Containers Command Types export type RestartContainersCommandOptions = CommonCommandOptions & { @@ -1883,6 +1900,7 @@ export interface IContainersClient extends ExecContainerCommand, ListContainersCommand, StartContainersCommand, + UnpauseContainersCommand, RestartContainersCommand, StopContainersCommand, RemoveContainersCommand, diff --git a/packages/vscode-container-client/src/test/ContainersClientE2E.test.ts b/packages/vscode-container-client/src/test/ContainersClientE2E.test.ts index 9c34e2b7..f554238d 100644 --- a/packages/vscode-container-client/src/test/ContainersClientE2E.test.ts +++ b/packages/vscode-container-client/src/test/ContainersClientE2E.test.ts @@ -634,6 +634,30 @@ describe('(integration) ContainersClientE2E', function () { expect(startedContainer.state.toLowerCase()).to.equal('running'); }); + it('UnpauseContainersCommand', async function () { + if (clientTypeToTest === 'wslc') { + this.skip(); // wslc has no `pause` or `unpause` subcommands + } + + await defaultRunner.getCommandRunner()({ + command: client.commandName, + args: ['container', 'pause', testContainerId], + }); + + const pausedContainer = (await validateContainerExists(client, defaultRunner, { containerId: testContainerId }))!; + expect(pausedContainer.state.toLowerCase()).to.equal('paused'); + + const unpausedContainers = await defaultRunner.getCommandRunner()( + client.unpauseContainers({ container: [testContainerId] }) + ); + + expect(unpausedContainers).to.be.an('array'); + expect(unpausedContainers).to.include(testContainerId); + + const runningContainer = (await validateContainerExists(client, defaultRunner, { containerId: testContainerId }))!; + expect(runningContainer.state.toLowerCase()).to.equal('running'); + }); + it('RestartContainersCommand', async function () { if (clientTypeToTest === 'wslc') { this.skip(); // wslc has no `restart` subcommand diff --git a/packages/vscode-container-client/src/test/clients/DockerClient/DockerClient.test.ts b/packages/vscode-container-client/src/test/clients/DockerClient/DockerClient.test.ts index 73dec79a..5b5390a5 100644 --- a/packages/vscode-container-client/src/test/clients/DockerClient/DockerClient.test.ts +++ b/packages/vscode-container-client/src/test/clients/DockerClient/DockerClient.test.ts @@ -17,6 +17,21 @@ import type { BuildImageCommandOptions, RunContainerCommandOptions } from '../.. describe('(unit) DockerClient', () => { const client = new DockerClient(); + describe('#unpauseContainers()', () => { + it('generates the command and parses unpaused container IDs', async () => { + const commandResult = await client.unpauseContainers({ container: ['abc', 'def'] }); + + expect(commandResult).to.have.a.property('command', 'docker'); + expect(commandResult.args).to.deep.equal([ + escaped('container'), + escaped('unpause'), + escaped('abc'), + escaped('def'), + ]); + expect(await commandResult.parse('abc\ndef\n', true)).to.deep.equal(['abc', 'def']); + }); + }); + describe('#listImagesAsync()', () => { it('parses date formats', async () => { const commandResult = await client.listImages({}); diff --git a/packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts b/packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts index 1e403741..6e1350d5 100644 --- a/packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts +++ b/packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts @@ -63,6 +63,7 @@ describe('(integration) WslcCanary', function () { { description: '`events`', args: 'events --help', unrecognizedToken: 'events', workaround: 'WslcClient.getEventStream rejects with CommandNotSupportedError' }, { description: '`info`', args: 'info --help', unrecognizedToken: 'info', workaround: 'WslcClient.getInfoCommandArgs/parseInfoCommandOutput synthesize a linux InfoItem' }, { description: '`container restart`', args: 'container restart --help', unrecognizedToken: 'restart', workaround: 'WslcClient.restartContainers rejects with CommandNotSupportedError' }, + { description: '`container unpause`', args: 'container unpause --help', unrecognizedToken: 'unpause', workaround: 'WslcClient.unpauseContainers rejects with CommandNotSupportedError' }, ]; cases.forEach(({ description, args, unrecognizedToken, workaround }) => { diff --git a/packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts b/packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts index 7e2be0d0..f2ed24a2 100644 --- a/packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts +++ b/packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts @@ -499,6 +499,10 @@ describe('(unit) WslcClient', () => { it('restartContainers rejects with CommandNotSupportedError', async () => { await expectRejection(client.restartContainers({ container: ['abc'] })); }); + + it('unpauseContainers rejects with CommandNotSupportedError', async () => { + await expectRejection(client.unpauseContainers({ container: ['abc'] })); + }); }); describe('#listVolumes()', () => { From 0ff97393edc9c6028e846a35d4c85683675f3675 Mon Sep 17 00:00:00 2001 From: Zhibo Lin <147509942+LE0-Lin@users.noreply.github.com> Date: Fri, 21 Aug 2026 13:38:54 +0800 Subject: [PATCH 2/3] Fix unpause command license reference --- .../src/commands/containers/unpauseContainer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/vscode-containers/src/commands/containers/unpauseContainer.ts b/extensions/vscode-containers/src/commands/containers/unpauseContainer.ts index c8e5940f..986ab982 100644 --- a/extensions/vscode-containers/src/commands/containers/unpauseContainer.ts +++ b/extensions/vscode-containers/src/commands/containers/unpauseContainer.ts @@ -1,6 +1,6 @@ /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE in the project root for license information. + * Licensed under the MIT License. See LICENSE.md in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { IActionContext } from '@microsoft/vscode-azext-utils'; From 5d2ee63a51099b38a947581bfdc7e7d80e294609 Mon Sep 17 00:00:00 2001 From: Zhibo Lin <147509942+LE0-Lin@users.noreply.github.com> Date: Mon, 24 Aug 2026 22:25:46 +0800 Subject: [PATCH 3/3] Add pause command for running containers --- extensions/vscode-containers/package.json | 10 +++++++ extensions/vscode-containers/package.nls.json | 1 + .../src/commands/containers/pauseContainer.ts | 26 ++++++++++++++++++ .../src/commands/registerCommands.ts | 2 ++ .../DockerClientBase/DockerClientBase.ts | 27 +++++++++++++++++++ .../src/clients/WslcClient/WslcClient.ts | 7 +++++ .../src/contracts/ContainerClient.ts | 18 +++++++++++++ .../src/test/ContainersClientE2E.test.ts | 12 +++++---- .../clients/DockerClient/DockerClient.test.ts | 15 +++++++++++ .../clients/WslcClient/WslcCanary.test.ts | 1 + .../clients/WslcClient/WslcClient.test.ts | 4 +++ 11 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 extensions/vscode-containers/src/commands/containers/pauseContainer.ts diff --git a/extensions/vscode-containers/package.json b/extensions/vscode-containers/package.json index ce8e8084..947d55de 100644 --- a/extensions/vscode-containers/package.json +++ b/extensions/vscode-containers/package.json @@ -411,6 +411,11 @@ "when": "view == vscode-containers.views.containers && viewItem =~ /^pausedContainer$/i", "group": "containers_2_active@5" }, + { + "command": "vscode-containers.containers.pause", + "when": "view == vscode-containers.views.containers && viewItem =~ /^runningContainer$/i", + "group": "containers_2_active@5" + }, { "command": "vscode-containers.containers.downloadFile", "when": "view == vscode-containers.views.containers && viewItem == containerFile", @@ -2728,6 +2733,11 @@ "title": "%vscode-containers.commands.containers.group.remove%", "category": "%vscode-containers.commands.category.containers%" }, + { + "command": "vscode-containers.containers.pause", + "title": "%vscode-containers.commands.containers.pause%", + "category": "%vscode-containers.commands.category.containers%" + }, { "command": "vscode-containers.containers.restart", "title": "%vscode-containers.commands.containers.restart%", diff --git a/extensions/vscode-containers/package.nls.json b/extensions/vscode-containers/package.nls.json index f2f03595..a11c2439 100644 --- a/extensions/vscode-containers/package.nls.json +++ b/extensions/vscode-containers/package.nls.json @@ -240,6 +240,7 @@ "vscode-containers.commands.containers.downloadFile": "Download...", "vscode-containers.commands.containers.inspect": "Inspect", "vscode-containers.commands.containers.openFile": "Open", + "vscode-containers.commands.containers.pause": "Pause", "vscode-containers.commands.containers.prune": "Prune...", "vscode-containers.commands.containers.refresh": "Refresh", "vscode-containers.commands.containers.remove": "Remove...", diff --git a/extensions/vscode-containers/src/commands/containers/pauseContainer.ts b/extensions/vscode-containers/src/commands/containers/pauseContainer.ts new file mode 100644 index 00000000..4b37ee23 --- /dev/null +++ b/extensions/vscode-containers/src/commands/containers/pauseContainer.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See LICENSE.md in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IActionContext } from '@microsoft/vscode-azext-utils'; +import * as vscode from 'vscode'; +import { ext } from '../../extensionVariables'; +import { ContainerTreeItem } from '../../tree/containers/ContainerTreeItem'; +import { multiSelectNodes } from '../../utils/multiSelectNodes'; + +export async function pauseContainer(context: IActionContext, node?: ContainerTreeItem, nodes?: ContainerTreeItem[]): Promise { + nodes = await multiSelectNodes( + { ...context, noItemFoundErrorMessage: vscode.l10n.t('No containers are available to pause') }, + ext.containersTree, + /^runningContainer$/i, + node, + nodes + ); + + await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: vscode.l10n.t('Pausing Container(s)...') }, async () => { + await ext.runWithDefaults(client => + client.pauseContainers({ container: nodes.map(n => n.containerId) }) + ); + }); +} diff --git a/extensions/vscode-containers/src/commands/registerCommands.ts b/extensions/vscode-containers/src/commands/registerCommands.ts index 54e808fb..aab69066 100644 --- a/extensions/vscode-containers/src/commands/registerCommands.ts +++ b/extensions/vscode-containers/src/commands/registerCommands.ts @@ -19,6 +19,7 @@ import { configureContainersExplorer } from "./containers/configureContainersExp import { downloadContainerFile } from "./containers/files/downloadContainerFile"; import { openContainerFile } from "./containers/files/openContainerFile"; import { inspectContainer } from "./containers/inspectContainer"; +import { pauseContainer } from "./containers/pauseContainer"; import { pruneContainers } from "./containers/pruneContainers"; import { removeContainer } from "./containers/removeContainer"; import { removeContainerGroup } from "./containers/removeContainerGroup"; @@ -135,6 +136,7 @@ export function registerCommands(): void { registerCommand('vscode-containers.containers.filter', filterContainersTree); registerCommand('vscode-containers.containers.clearFilter', clearContainersFilter); registerCommand('vscode-containers.containers.openFile', openContainerFile); + registerCommand('vscode-containers.containers.pause', pauseContainer); registerCommand('vscode-containers.containers.prune', pruneContainers); registerCommand('vscode-containers.containers.remove', removeContainer); registerCommand('vscode-containers.containers.group.remove', removeContainerGroup); diff --git a/packages/vscode-container-client/src/clients/DockerClientBase/DockerClientBase.ts b/packages/vscode-container-client/src/clients/DockerClientBase/DockerClientBase.ts index 1e8f1b77..fb566b68 100644 --- a/packages/vscode-container-client/src/clients/DockerClientBase/DockerClientBase.ts +++ b/packages/vscode-container-client/src/clients/DockerClientBase/DockerClientBase.ts @@ -57,6 +57,7 @@ import type { LoginCommandOptions, LogoutCommandOptions, LogsForContainerCommandOptions, + PauseContainersCommandOptions, PruneContainersCommandOptions, PruneContainersItem, PruneImagesCommandOptions, @@ -863,6 +864,32 @@ export abstract class DockerClientBase extends ConfigurableClient implements ICo //#endregion + //#region PauseContainers Command + + protected getPauseContainersCommandArgs(options: PauseContainersCommandOptions): CommandLineArgs { + return composeArgs( + withArg('container', 'pause'), + withArg(...toArray(options.container)), + )(); + } + + protected parsePauseContainersCommandOutput( + options: PauseContainersCommandOptions, + output: string, + strict: boolean, + ): Promise> { + return Promise.resolve(asIds(output)); + } + + pauseContainers(options: PauseContainersCommandOptions): Promise>> { + return this.makeCommandResponse( + this.getPauseContainersCommandArgs(options), + (output, strict) => this.parsePauseContainersCommandOutput(options, output, strict), + ); + } + + //#endregion + //#region UnpauseContainers Command protected getUnpauseContainersCommandArgs(options: UnpauseContainersCommandOptions): CommandLineArgs { diff --git a/packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts b/packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts index 488bb233..618959f1 100644 --- a/packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts +++ b/packages/vscode-container-client/src/clients/WslcClient/WslcClient.ts @@ -34,6 +34,7 @@ import type { ListNetworksCommandOptions, ListVolumeItem, ListVolumesCommandOptions, + PauseContainersCommandOptions, PruneContainersCommandOptions, PruneImagesCommandOptions, PruneNetworksCommandOptions, @@ -367,6 +368,12 @@ export class WslcClient extends DockerClientBase { return Promise.reject(new CommandNotSupportedError('wslc does not support the restart command.')); } + // wslc has no `pause` subcommand. Reject rather than silently inheriting + // a command line that wslc would reject. + public override pauseContainers(options: PauseContainersCommandOptions): Promise>> { + return Promise.reject(new CommandNotSupportedError('wslc does not support the pause command.')); + } + // wslc has no `unpause` subcommand. Reject rather than silently inheriting // a command line that wslc would reject. public override unpauseContainers(options: UnpauseContainersCommandOptions): Promise>> { diff --git a/packages/vscode-container-client/src/contracts/ContainerClient.ts b/packages/vscode-container-client/src/contracts/ContainerClient.ts index 648da913..23e0b642 100644 --- a/packages/vscode-container-client/src/contracts/ContainerClient.ts +++ b/packages/vscode-container-client/src/contracts/ContainerClient.ts @@ -906,6 +906,23 @@ type StartContainersCommand = { startContainers(options: StartContainersCommandOptions): Promise>>; }; +// Pause Containers Command Types + +export type PauseContainersCommandOptions = CommonCommandOptions & { + /** + * Containers to pause + */ + container: Array; +}; + +type PauseContainersCommand = { + /** + * Generate a CommandResponse for pausing container(s). + * @param options Command options + */ + pauseContainers(options: PauseContainersCommandOptions): Promise>>; +}; + // Unpause Containers Command Types export type UnpauseContainersCommandOptions = CommonCommandOptions & { @@ -1900,6 +1917,7 @@ export interface IContainersClient extends ExecContainerCommand, ListContainersCommand, StartContainersCommand, + PauseContainersCommand, UnpauseContainersCommand, RestartContainersCommand, StopContainersCommand, diff --git a/packages/vscode-container-client/src/test/ContainersClientE2E.test.ts b/packages/vscode-container-client/src/test/ContainersClientE2E.test.ts index f554238d..741eba0e 100644 --- a/packages/vscode-container-client/src/test/ContainersClientE2E.test.ts +++ b/packages/vscode-container-client/src/test/ContainersClientE2E.test.ts @@ -634,15 +634,17 @@ describe('(integration) ContainersClientE2E', function () { expect(startedContainer.state.toLowerCase()).to.equal('running'); }); - it('UnpauseContainersCommand', async function () { + it('PauseAndUnpauseContainersCommands', async function () { if (clientTypeToTest === 'wslc') { this.skip(); // wslc has no `pause` or `unpause` subcommands } - await defaultRunner.getCommandRunner()({ - command: client.commandName, - args: ['container', 'pause', testContainerId], - }); + const pausedContainers = await defaultRunner.getCommandRunner()( + client.pauseContainers({ container: [testContainerId] }) + ); + + expect(pausedContainers).to.be.an('array'); + expect(pausedContainers).to.include(testContainerId); const pausedContainer = (await validateContainerExists(client, defaultRunner, { containerId: testContainerId }))!; expect(pausedContainer.state.toLowerCase()).to.equal('paused'); diff --git a/packages/vscode-container-client/src/test/clients/DockerClient/DockerClient.test.ts b/packages/vscode-container-client/src/test/clients/DockerClient/DockerClient.test.ts index 5b5390a5..e2b30c93 100644 --- a/packages/vscode-container-client/src/test/clients/DockerClient/DockerClient.test.ts +++ b/packages/vscode-container-client/src/test/clients/DockerClient/DockerClient.test.ts @@ -17,6 +17,21 @@ import type { BuildImageCommandOptions, RunContainerCommandOptions } from '../.. describe('(unit) DockerClient', () => { const client = new DockerClient(); + describe('#pauseContainers()', () => { + it('generates the command and parses paused container IDs', async () => { + const commandResult = await client.pauseContainers({ container: ['abc', 'def'] }); + + expect(commandResult).to.have.a.property('command', 'docker'); + expect(commandResult.args).to.deep.equal([ + escaped('container'), + escaped('pause'), + escaped('abc'), + escaped('def'), + ]); + expect(await commandResult.parse('abc\ndef\n', true)).to.deep.equal(['abc', 'def']); + }); + }); + describe('#unpauseContainers()', () => { it('generates the command and parses unpaused container IDs', async () => { const commandResult = await client.unpauseContainers({ container: ['abc', 'def'] }); diff --git a/packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts b/packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts index 6e1350d5..6843a092 100644 --- a/packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts +++ b/packages/vscode-container-client/src/test/clients/WslcClient/WslcCanary.test.ts @@ -63,6 +63,7 @@ describe('(integration) WslcCanary', function () { { description: '`events`', args: 'events --help', unrecognizedToken: 'events', workaround: 'WslcClient.getEventStream rejects with CommandNotSupportedError' }, { description: '`info`', args: 'info --help', unrecognizedToken: 'info', workaround: 'WslcClient.getInfoCommandArgs/parseInfoCommandOutput synthesize a linux InfoItem' }, { description: '`container restart`', args: 'container restart --help', unrecognizedToken: 'restart', workaround: 'WslcClient.restartContainers rejects with CommandNotSupportedError' }, + { description: '`container pause`', args: 'container pause --help', unrecognizedToken: 'pause', workaround: 'WslcClient.pauseContainers rejects with CommandNotSupportedError' }, { description: '`container unpause`', args: 'container unpause --help', unrecognizedToken: 'unpause', workaround: 'WslcClient.unpauseContainers rejects with CommandNotSupportedError' }, ]; diff --git a/packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts b/packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts index f2ed24a2..fbf9df5f 100644 --- a/packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts +++ b/packages/vscode-container-client/src/test/clients/WslcClient/WslcClient.test.ts @@ -500,6 +500,10 @@ describe('(unit) WslcClient', () => { await expectRejection(client.restartContainers({ container: ['abc'] })); }); + it('pauseContainers rejects with CommandNotSupportedError', async () => { + await expectRejection(client.pauseContainers({ container: ['abc'] })); + }); + it('unpauseContainers rejects with CommandNotSupportedError', async () => { await expectRejection(client.unpauseContainers({ container: ['abc'] })); });