diff --git a/package.json b/package.json index 9a19d7c2b9..3f96389ca1 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,6 @@ "onCommand:vscode-docker.registries.pullRepository", "onCommand:vscode-docker.registries.reconnectRegistry", "onCommand:vscode-docker.registries.refresh", - "onCommand:vscode-docker.registries.setAsDefault", "onCommand:vscode-docker.volumes.configureExplorer", "onCommand:vscode-docker.volumes.inspect", "onCommand:vscode-docker.volumes.prune", @@ -370,7 +369,7 @@ }, { "command": "vscode-docker.registries.azure.selectSubscriptions", - "when": "view == dockerRegistries && viewItem == azureextensionui.azureSubscription", + "when": "view == dockerRegistries && viewItem == azure;DockerV2;RegistryProvider;", "group": "inline" }, { @@ -393,11 +392,6 @@ "when": "view == dockerRegistries && viewItem == azureextensionui.azureSubscription", "group": "regs_1_general@1" }, - { - "command": "vscode-docker.registries.setAsDefault", - "when": "view == dockerRegistries && viewItem =~ /Registry;/", - "group": "regs_reg_1_general@1" - }, { "command": "vscode-docker.registries.azure.deleteRegistry", "when": "view == dockerRegistries && viewItem == azure;DockerV2;Registry;", @@ -1325,10 +1319,10 @@ "configuration": { "title": "Docker", "properties": { - "docker.defaultRegistryPath": { - "type": "string", - "default": "", - "description": "%vscode-docker.config.docker.defaultRegistryPath%" + "docker.promptForRegistryWhenPushingImages": { + "type": "boolean", + "default": true, + "description": "%vscode-docker.config.docker.promptForRegistryWhenPushingImages%" }, "docker.explorerRefreshInterval": { "type": "number", @@ -2326,11 +2320,6 @@ "dark": "resources/dark/refresh.svg" } }, - { - "command": "vscode-docker.registries.setAsDefault", - "title": "%vscode-docker.commands.registries.setAsDefault%", - "category": "%vscode-docker.commands.category.dockerRegistries%" - }, { "command": "vscode-docker.volumes.configureExplorer", "title": "%vscode-docker.commands.volumes.configureExplorer%", diff --git a/package.nls.json b/package.nls.json index 5f0bb3c24a..fe6f01e876 100644 --- a/package.nls.json +++ b/package.nls.json @@ -94,6 +94,7 @@ "vscode-docker.tasks.docker-run.python.args": "Arguments passed to the Python app.", "vscode-docker.tasks.docker-run.python.wait": "Whether to wait for debugger to attach.", "vscode-docker.tasks.docker-run.python.debugPort": "The port that the debugger will listen on.", + "vscode-docker.config.docker.promptForRegistryWhenPushingImages": "Whether to prompt for the registry to push to if the image is not explicitly tagged.", "vscode-docker.config.template.build.template": "The command template.", "vscode-docker.config.template.build.label": "The label displayed to the user.", "vscode-docker.config.template.build.match": "The regular expression for choosing the right template. Checked against container name, container's image name, etc.", @@ -122,7 +123,6 @@ "vscode-docker.config.template.composeDown.label": "The label displayed to the user.", "vscode-docker.config.template.composeDown.match": "The regular expression for choosing the right template. Checked against docker-compose YAML files, folder name, etc.", "vscode-docker.config.template.composeDown.description": "Command templates for `docker-compose down` commands.", - "vscode-docker.config.docker.defaultRegistryPath": "Default registry and path when tagging an image", "vscode-docker.config.docker.explorerRefreshInterval": "Docker view refresh interval (milliseconds)", "vscode-docker.config.docker.containers.groupBy": "The property to use to group containers in Docker view: ContainerId, ContainerName, CreatedTime, FullTag, ImageId, Networks, Ports, Registry, Repository, RepositoryName, RepositoryNameAndTag, State, Status, Tag, or None", "vscode-docker.config.docker.containers.description": "Any secondary properties to display for a container (an array). Possible elements include: ContainerId, ContainerName, CreatedTime, FullTag, ImageId, Networks, Ports, Registry, Repository, RepositoryName, RepositoryNameAndTag, State, Status, and Tag", @@ -223,7 +223,6 @@ "vscode-docker.commands.registries.pullImage": "Pull Image", "vscode-docker.commands.registries.pullRepository": "Pull Repository", "vscode-docker.commands.registries.refresh": "Refresh", - "vscode-docker.commands.registries.setAsDefault": "Set as Default", "vscode-docker.commands.volumes.configureExplorer": "Configure Explorer...", "vscode-docker.commands.volumes.inspect": "Inspect", "vscode-docker.commands.volumes.prune": "Prune...", diff --git a/src/commands/images/buildImage.ts b/src/commands/images/buildImage.ts index d1c1b77770..62b3572a8c 100644 --- a/src/commands/images/buildImage.ts +++ b/src/commands/images/buildImage.ts @@ -57,7 +57,7 @@ export async function buildImage(context: IActionContext, dockerFileUri: vscode. await delay(500); addImageTaggingTelemetry(context, suggestedImageName, '.before'); - const imageName: string = await getTagFromUserInput(suggestedImageName, !prevImageName); + const imageName: string = await getTagFromUserInput(suggestedImageName); addImageTaggingTelemetry(context, imageName, '.after'); await ext.context.globalState.update(dockerFileKey, imageName); diff --git a/src/commands/images/pushImage.ts b/src/commands/images/pushImage.ts index e8b8d7609e..718dbaafb8 100644 --- a/src/commands/images/pushImage.ts +++ b/src/commands/images/pushImage.ts @@ -4,49 +4,77 @@ *--------------------------------------------------------------------------------------------*/ import vscode = require('vscode'); -import { IActionContext } from 'vscode-azureextensionui'; -import { configurationKeys } from '../../constants'; +import { IActionContext, UserCancelledError } from 'vscode-azureextensionui'; import { ext } from '../../extensionVariables'; import { localize } from '../../localize'; import { ImageTreeItem } from '../../tree/images/ImageTreeItem'; -import { askToSaveRegistryPath } from '../registries/registrySettings'; +import { registryExpectedContextValues } from '../../tree/registries/registryContextValues'; +import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase'; import { addImageTaggingTelemetry, tagImage } from './tagImage'; export async function pushImage(context: IActionContext, node: ImageTreeItem | undefined): Promise { if (!node) { node = await ext.imagesTree.showTreeItemPicker(ImageTreeItem.contextValue, { ...context, - noItemFoundErrorMessage: localize('vscode-docker.commands.images.push.noImages', 'No images are available to push') + noItemFoundErrorMessage: localize('vscode-docker.commands.images.push.noImages', 'No images are available to push'), }); } - const defaultRegistryPath = vscode.workspace.getConfiguration('docker').get(configurationKeys.defaultRegistryPath); + let connectedRegistry: RegistryTreeItemBase | undefined; - let fullTag: string = node.fullTag; - if (fullTag.includes('/')) { - if (!defaultRegistryPath) { - await askToSaveRegistryPath(fullTag); - } - } else { - let askToPushPrefix: boolean = true; - if (askToPushPrefix && defaultRegistryPath) { - context.telemetry.properties.pushWithoutRepositoryAnswer = 'Cancel'; - - let tagFirst: vscode.MessageItem = { title: localize('vscode-docker.commands.images.push.tagFirst', 'Tag first') }; - let pushAnyway: vscode.MessageItem = { title: localize('vscode-docker.commands.images.push.pushAnyway', 'Push anyway') } - let options: vscode.MessageItem[] = [tagFirst, pushAnyway]; - let response: vscode.MessageItem = await ext.ui.showWarningMessage(localize('vscode-docker.commands.images.push.pushDockerHub', 'This will attempt to push to the official public Docker Hub library (docker.io/library), which you may not have permissions for. To push to your own repository, you must tag the image like /'), ...options); - context.telemetry.properties.pushWithoutRepositoryAnswer = response.title; - - if (response === tagFirst) { - fullTag = await tagImage(context, node); + if (!node.fullTag.includes('/')) { + // The registry to push to is indeterminate--could be Docker Hub, or could need tagging. + const prompt: boolean = vscode.workspace.getConfiguration('docker').get('promptForRegistryWhenPushingImages', true); + + // If the prompt setting is true, we'll ask; if not we'll assume Docker Hub. + if (prompt) { + try { + connectedRegistry = await ext.registriesTree.showTreeItemPicker(registryExpectedContextValues.all.registry, context); + } catch (error) { + if (error instanceof UserCancelledError) { + // Rethrow UserCancelledError, otherwise, move on without a selected registry + throw error; + } } + } else { + // Try to find a connected Docker Hub registry (primarily for login credentials) + connectedRegistry = await tryGetDockerHubRegistry(context); } + } else { + // The registry to push to is determinate. If there's a connected registry in the tree view, we'll try to find it, to perform login ahead of time. + // Registry path is everything up to the last slash. + const baseImagePath = node.fullTag.substring(0, node.fullTag.lastIndexOf('/')); + + const progressOptions: vscode.ProgressOptions = { + location: vscode.ProgressLocation.Notification, + title: localize('vscode-docker.commands.images.push.fetchingCreds', 'Fetching login credentials...'), + }; + + connectedRegistry = await vscode.window.withProgress(progressOptions, async () => await tryGetConnectedRegistryForPath(context, baseImagePath)); } - addImageTaggingTelemetry(context, fullTag, ''); + // Give the user a chance to modify the tag however they want + const finalTag = await tagImage(context, node, connectedRegistry); - const terminal = ext.terminalProvider.createTerminal(fullTag); - terminal.sendText(`docker push ${fullTag}`); + if (connectedRegistry && finalTag.startsWith(connectedRegistry.baseImagePath)) { + // If a registry was found/chosen and is still the same as the final tag's registry, try logging in + await vscode.commands.executeCommand('vscode-docker.registries.logInToDockerCli', connectedRegistry); + } + + addImageTaggingTelemetry(context, finalTag, ''); + + // Finally push the image + const terminal = ext.terminalProvider.createTerminal(finalTag); + terminal.sendText(`docker push ${finalTag}`); terminal.show(); } + +async function tryGetConnectedRegistryForPath(context: IActionContext, baseImagePath: string): Promise { + const allRegistries = await ext.registriesRoot.getAllConnectedRegistries(context); + return allRegistries.find(r => r.baseImagePath === baseImagePath); +} + +async function tryGetDockerHubRegistry(context: IActionContext): Promise { + const allRegistries = await ext.registriesRoot.getAllConnectedRegistries(context); + return allRegistries.find(r => r.contextValue.match(registryExpectedContextValues.dockerHub.registry)); +} diff --git a/src/commands/images/tagImage.ts b/src/commands/images/tagImage.ts index 7c2c2e0b83..2119d6ca15 100644 --- a/src/commands/images/tagImage.ts +++ b/src/commands/images/tagImage.ts @@ -6,14 +6,14 @@ import { Image } from 'dockerode'; import * as vscode from 'vscode'; import { IActionContext, TelemetryProperties } from 'vscode-azureextensionui'; -import { configurationKeys } from '../../constants'; import { ext } from '../../extensionVariables'; import { localize } from '../../localize'; import { ImageTreeItem } from '../../tree/images/ImageTreeItem'; +import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase'; import { callDockerodeWithErrorHandling } from '../../utils/callDockerodeWithErrorHandling'; import { extractRegExGroups } from '../../utils/extractRegExGroups'; -export async function tagImage(context: IActionContext, node: ImageTreeItem | undefined): Promise { +export async function tagImage(context: IActionContext, node?: ImageTreeItem, registry?: RegistryTreeItemBase): Promise { if (!node) { node = await ext.imagesTree.showTreeItemPicker(ImageTreeItem.contextValue, { ...context, @@ -22,7 +22,7 @@ export async function tagImage(context: IActionContext, node: ImageTreeItem | un } addImageTaggingTelemetry(context, node.fullTag, '.before'); - let newTaggedName: string = await getTagFromUserInput(node.fullTag, true); + let newTaggedName: string = await getTagFromUserInput(node.fullTag, registry?.baseImagePath); addImageTaggingTelemetry(context, newTaggedName, '.after'); let repo: string = newTaggedName; @@ -39,27 +39,22 @@ export async function tagImage(context: IActionContext, node: ImageTreeItem | un return newTaggedName; } -export async function getTagFromUserInput(fullTag: string, addDefaultRegistry: boolean): Promise { - const configOptions: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('docker'); - const defaultRegistryPath = configOptions.get(configurationKeys.defaultRegistryPath, ''); - +export async function getTagFromUserInput(fullTag: string, baseImagePath?: string): Promise { let opt: vscode.InputBoxOptions = { ignoreFocusOut: true, prompt: localize('vscode-docker.commands.images.tag.tagAs', 'Tag image as...'), }; - if (addDefaultRegistry) { - let registryLength: number = fullTag.indexOf('/'); - if (defaultRegistryPath.length > 0 && registryLength < 0) { - fullTag = defaultRegistryPath + '/' + fullTag; - registryLength = defaultRegistryPath.length; - } - opt.valueSelection = registryLength < 0 ? undefined : [0, registryLength + 1]; // include the '/' + + if (fullTag.includes('/')) { + opt.valueSelection = [0, fullTag.lastIndexOf('/')]; + } else if (baseImagePath) { + fullTag = `${baseImagePath}/${fullTag}`; + opt.valueSelection = [0, fullTag.lastIndexOf('/')]; } opt.value = fullTag; - const nameWithTag: string = await ext.ui.showInputBox(opt); - return nameWithTag; + return await ext.ui.showInputBox(opt); } const KnownRegistries: { type: string, regex: RegExp }[] = [ diff --git a/src/commands/registerCommands.ts b/src/commands/registerCommands.ts index 38b27aa4c3..a34cfc735d 100644 --- a/src/commands/registerCommands.ts +++ b/src/commands/registerCommands.ts @@ -57,7 +57,6 @@ import { logInToDockerCli } from "./registries/logInToDockerCli"; import { logOutOfDockerCli } from "./registries/logOutOfDockerCli"; import { pullImage, pullRepository } from "./registries/pullImages"; import { reconnectRegistry } from "./registries/reconnectRegistry"; -import { setRegistryAsDefault } from "./registries/registrySettings"; import { configureVolumesExplorer } from "./volumes/configureVolumesExplorer"; import { inspectVolume } from "./volumes/inspectVolume"; import { pruneVolumes } from "./volumes/pruneVolumes"; @@ -112,7 +111,6 @@ export function registerCommands(): void { registerWorkspaceCommand('vscode-docker.registries.pullImage', pullImage); registerWorkspaceCommand('vscode-docker.registries.pullRepository', pullRepository); registerCommand('vscode-docker.registries.reconnectRegistry', reconnectRegistry); - registerCommand('vscode-docker.registries.setAsDefault', setRegistryAsDefault); registerCommand('vscode-docker.registries.dockerHub.openInBrowser', openDockerHubInBrowser); diff --git a/src/commands/registries/azure/tasks/scheduleRunRequest.ts b/src/commands/registries/azure/tasks/scheduleRunRequest.ts index eaaf35350d..d29c84d6f2 100644 --- a/src/commands/registries/azure/tasks/scheduleRunRequest.ts +++ b/src/commands/registries/azure/tasks/scheduleRunRequest.ts @@ -104,7 +104,7 @@ async function quickPickImageName(context: IActionContext, rootFolder: vscode.Wo await delay(500); addImageTaggingTelemetry(context, suggestedImageName, '.before'); - const imageName: string = await getTagFromUserInput(suggestedImageName, false); + const imageName: string = await getTagFromUserInput(suggestedImageName); addImageTaggingTelemetry(context, imageName, '.after'); await ext.context.globalState.update(dockerFileKey, imageName); diff --git a/src/commands/registries/logInToDockerCli.ts b/src/commands/registries/logInToDockerCli.ts index b8653d6b4b..a7f39c5194 100644 --- a/src/commands/registries/logInToDockerCli.ts +++ b/src/commands/registries/logInToDockerCli.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { exec } from 'child_process'; +import * as vscode from 'vscode'; import { IActionContext } from 'vscode-azureextensionui'; import { NULL_GUID } from '../../constants'; import { ext } from '../../extensionVariables'; @@ -31,29 +32,36 @@ export async function logInToDockerCli(context: IActionContext, node?: RegistryT if (!username || !password) { ext.outputChannel.appendLine(localize('vscode-docker.commands.registries.logIn.skipping', 'WARNING: Skipping login for "{0}" because it does not require authentication.', creds.registryPath)) } else { - await new Promise((resolve, reject) => { - const dockerLoginCmd = `docker login ${creds.registryPath} --username ${username} --password-stdin`; - let childProcess = exec(dockerLoginCmd, (err, stdout, stderr) => { - ext.outputChannel.appendLine(dockerLoginCmd); - ext.outputChannel.append(stdout); - ext.outputChannel.append(stderr); - if (err && err.message.match(/error storing credentials.*The stub received bad data/)) { - // Temporary work-around for this error- same as Azure CLI - // See https://github.com/Azure/azure-cli/issues/4843 - reject(new Error(localize('vscode-docker.commands.registries.logIn.dockerCliTokens', 'In order to log in to the Docker CLI using tokens, you currently need to go to \nOpen your Docker config file and remove "credsStore": "wincred" from the config.json file, then try again. \nDoing this will disable wincred and cause Docker to store credentials directly in the .docker/config.json file. All registries that are currently logged in will be effectly logged out.'))); - } else if (err) { - reject(err); - } else { - // Docker emits some non-error warning messages to stderr, so we cannot reject on all stderr without failing unnecessarily - // Consequently, as long as exit code is 0, we will resolve - // Note that both stdout and stderr are logged unconditionally above - resolve(); - } - }); + const progressOptions: vscode.ProgressOptions = { + location: vscode.ProgressLocation.Notification, + title: localize('vscode-docker.commands.registries.logIn.loggingIn', 'Logging in...'), + }; - childProcess.stdin.write(password); // Prevents insecure password error - childProcess.stdin.end(); - }); + await vscode.window.withProgress(progressOptions, async () => + await new Promise((resolve, reject) => { + const dockerLoginCmd = `docker login ${creds.registryPath} --username ${username} --password-stdin`; + let childProcess = exec(dockerLoginCmd, (err, stdout, stderr) => { + ext.outputChannel.appendLine(dockerLoginCmd); + ext.outputChannel.append(stdout); + ext.outputChannel.append(stderr); + if (err && err.message.match(/error storing credentials.*The stub received bad data/)) { + // Temporary work-around for this error- same as Azure CLI + // See https://github.com/Azure/azure-cli/issues/4843 + reject(new Error(localize('vscode-docker.commands.registries.logIn.dockerCliTokens', 'In order to log in to the Docker CLI using tokens, you currently need to go to \nOpen your Docker config file and remove "credsStore": "wincred" from the config.json file, then try again. \nDoing this will disable wincred and cause Docker to store credentials directly in the .docker/config.json file. All registries that are currently logged in will be effectly logged out.'))); + } else if (err) { + reject(err); + } else { + // Docker emits some non-error warning messages to stderr, so we cannot reject on all stderr without failing unnecessarily + // Consequently, as long as exit code is 0, we will resolve + // Note that both stdout and stderr are logged unconditionally above + resolve(); + } + }); + + childProcess.stdin.write(password); // Prevents insecure password error + childProcess.stdin.end(); + }) + ); } ext.outputChannel.show(); diff --git a/src/commands/registries/registrySettings.ts b/src/commands/registries/registrySettings.ts deleted file mode 100644 index 81cfd9265e..0000000000 --- a/src/commands/registries/registrySettings.ts +++ /dev/null @@ -1,68 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See LICENSE.md in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from 'vscode'; -import { DialogResponses, IActionContext } from 'vscode-azureextensionui'; -import { configurationKeys } from '../../constants'; -import { ext } from '../../extensionVariables'; -import { localize } from "../../localize"; -import { registryExpectedContextValues } from '../../tree/registries/registryContextValues'; -import { RegistryTreeItemBase } from '../../tree/registries/RegistryTreeItemBase'; - -const defaultRegistryKey = "defaultRegistry"; -const hasCheckedRegistryPaths = "hasCheckedRegistryPaths" - -export async function setRegistryAsDefault(context: IActionContext, node?: RegistryTreeItemBase): Promise { - if (!node) { - node = await ext.registriesTree.showTreeItemPicker(registryExpectedContextValues.all.registry, context); - } - - const configOptions: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('docker'); - await configOptions.update(configurationKeys.defaultRegistryPath, node.baseImagePath, vscode.ConfigurationTarget.Global); - /* eslint-disable-next-line @typescript-eslint/no-floating-promises */ - vscode.window.showInformationMessage(localize('vscode-docker.commands.registries.settings.updated', 'Updated setting "docker.defaultRegistryPath" to "{0}".', node.baseImagePath)); -} - -export async function consolidateDefaultRegistrySettings(): Promise { - const configOptions: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('docker'); - const combineRegistryPaths: boolean = !(ext.context.workspaceState.get(hasCheckedRegistryPaths)); - let defaultRegistryPath: string = configOptions.get(configurationKeys.defaultRegistryPath, ''); - let defaultRegistry: string = configOptions.get(defaultRegistryKey, ''); - - if (defaultRegistry && combineRegistryPaths) { - let updatedPath = defaultRegistryPath ? `${defaultRegistry}/${defaultRegistryPath}` : `${defaultRegistry}`; - await ext.context.workspaceState.update(hasCheckedRegistryPaths, true); - await configOptions.update(configurationKeys.defaultRegistryPath, updatedPath, vscode.ConfigurationTarget.Global); - /* eslint-disable-next-line @typescript-eslint/no-floating-promises */ - vscode.window.showInformationMessage(localize('vscode-docker.commands.registries.settings.defaultRegistryObsolete', 'The \'docker.defaultRegistry\' setting is now obsolete, please use the \'docker.{0}\' setting by itself. Your settings have been updated to reflect this change.', configurationKeys.defaultRegistryPath)) - } -} - -export async function askToSaveRegistryPath(imagePath: string, promptForSave?: boolean): Promise { - let askToSaveKey: string = 'docker.askToSaveRegistryPath'; - let askToSavePath: boolean = promptForSave || ext.context.globalState.get(askToSaveKey, true); - const configOptions: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('docker'); - - if (!vscode.workspace.workspaceFolders || !vscode.workspace.workspaceFolders.length) { - // Can't save to workspace settings if no workspace - return; - } - - let prefix = ""; - if (imagePath.includes('/')) { - prefix = imagePath.substring(0, imagePath.lastIndexOf('/')); - } - if (prefix && askToSavePath) { - let userPrefixPreference: vscode.MessageItem = await ext.ui.showWarningMessage(localize('vscode-docker.commands.registries.settings.confirm', 'Would you like to save \'{0}\' as your default registry path?', prefix), DialogResponses.yes, DialogResponses.no, DialogResponses.skipForNow); - if (userPrefixPreference === DialogResponses.yes || userPrefixPreference === DialogResponses.no) { - await ext.context.globalState.update(askToSaveKey, false); - } - if (userPrefixPreference === DialogResponses.yes) { - await configOptions.update(configurationKeys.defaultRegistryPath, prefix, vscode.ConfigurationTarget.Workspace); - /* eslint-disable-next-line @typescript-eslint/no-floating-promises */ - vscode.window.showInformationMessage(localize('vscode-docker.commands.registries.settings.defaultRegistrySaved', 'Default registry path saved to the \'docker.{0}\' setting.', configurationKeys.defaultRegistryPath)); - } - } -} diff --git a/src/constants.ts b/src/constants.ts index 9d31daa5ba..d7e1fa3d33 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -17,7 +17,6 @@ export namespace keytarConstants { } export namespace configurationKeys { - export const defaultRegistryPath = "defaultRegistryPath"; export const groupImagesBy = 'groupImagesBy'; } diff --git a/src/extension.ts b/src/extension.ts index ec968b4edf..66dfcc9d9c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -11,7 +11,6 @@ import { registerAppServiceExtensionVariables } from 'vscode-azureappservice'; import { AzureUserInput, callWithTelemetryAndErrorHandling, createAzExtOutputChannel, createTelemetryReporter, IActionContext, registerUIExtensionVariables, UserCancelledError } from 'vscode-azureextensionui'; import { ConfigurationParams, DidChangeConfigurationNotification, DocumentSelector, LanguageClient, LanguageClientOptions, Middleware, ServerOptions, TransportKind } from 'vscode-languageclient/lib/main'; import { registerCommands } from './commands/registerCommands'; -import { consolidateDefaultRegistrySettings } from './commands/registries/registrySettings'; import { LegacyDockerDebugConfigProvider } from './configureWorkspace/LegacyDockerDebugConfigProvider'; import { COMPOSE_FILE_GLOB_PATTERN } from './constants'; import { registerDebugConfigurationProvider } from './debugging/coreclr/registerDebugConfigurationProvider'; @@ -130,7 +129,6 @@ export async function activateInternal(ctx: vscode.ExtensionContext, perfStats: registerDebugProvider(ctx); registerTaskProviders(ctx); - await consolidateDefaultRegistrySettings(); activateLanguageClient(ctx); registerListeners(ctx); diff --git a/src/tree/registries/RegistriesTreeItem.ts b/src/tree/registries/RegistriesTreeItem.ts index e65849481d..c97369bc1a 100644 --- a/src/tree/registries/RegistriesTreeItem.ts +++ b/src/tree/registries/RegistriesTreeItem.ts @@ -18,6 +18,7 @@ import { ICachedRegistryProvider } from "./ICachedRegistryProvider"; import { IRegistryProvider } from "./IRegistryProvider"; import { IRegistryProviderTreeItem } from "./IRegistryProviderTreeItem"; import { anyContextValuePart, contextValueSeparator } from "./registryContextValues"; +import { RegistryTreeItemBase } from "./RegistryTreeItemBase"; const providersKey = 'docker.registryProviders'; @@ -191,6 +192,10 @@ export class RegistriesTreeItem extends AzExtParentTreeItem { return this._cachedProviders.filter(c => c.id === cachedProvider.id).length > 1; } + public async getAllConnectedRegistries(context: IActionContext): Promise { + return await recursiveGetAllConnectedRegistries(context, ext.registriesRoot); + } + private async saveCachedProviders(): Promise { await ext.context.globalState.update(providersKey, this._cachedProviders); await this.refresh(); @@ -221,3 +226,17 @@ export class RegistriesTreeItem extends AzExtParentTreeItem { return node } } + +async function recursiveGetAllConnectedRegistries(context: IActionContext, node: AzExtParentTreeItem): Promise { + let results: RegistryTreeItemBase[] = []; + + for (const child of await node.getCachedChildren(context)) { + if (child instanceof RegistryTreeItemBase) { + results.push(child); + } else if (child instanceof AzExtParentTreeItem) { + results = results.concat(await recursiveGetAllConnectedRegistries(context, child)); + } + } + + return results; +} diff --git a/src/tree/registries/dockerHub/DockerHubAccountTreeItem.ts b/src/tree/registries/dockerHub/DockerHubAccountTreeItem.ts index ef7d18a7eb..c6ba40f2d6 100644 --- a/src/tree/registries/dockerHub/DockerHubAccountTreeItem.ts +++ b/src/tree/registries/dockerHub/DockerHubAccountTreeItem.ts @@ -73,7 +73,7 @@ export class DockerHubAccountTreeItem extends AzExtParentTreeItem implements IRe return this.createTreeItemsWithErrorHandling( response.body.namespaces, 'invalidDockerHubNamespace', - n => new DockerHubNamespaceTreeItem(this, n), + n => new DockerHubNamespaceTreeItem(this, n.toLowerCase()), n => n ); } diff --git a/src/tree/registries/dockerV2/DockerV2RegistryTreeItemBase.ts b/src/tree/registries/dockerV2/DockerV2RegistryTreeItemBase.ts index e126546fff..7a5f2287f2 100644 --- a/src/tree/registries/dockerV2/DockerV2RegistryTreeItemBase.ts +++ b/src/tree/registries/dockerV2/DockerV2RegistryTreeItemBase.ts @@ -24,7 +24,7 @@ export abstract class DockerV2RegistryTreeItemBase extends RegistryTreeItemBase } public get baseImagePath(): string { - return this.host; + return this.host.toLowerCase(); } public get host(): string { diff --git a/src/tree/registries/gitLab/GitLabAccountTreeItem.ts b/src/tree/registries/gitLab/GitLabAccountTreeItem.ts index 0a10af3db6..012ec6f91c 100644 --- a/src/tree/registries/gitLab/GitLabAccountTreeItem.ts +++ b/src/tree/registries/gitLab/GitLabAccountTreeItem.ts @@ -73,7 +73,7 @@ export class GitLabAccountTreeItem extends AzExtParentTreeItem implements IRegis return this.createTreeItemsWithErrorHandling( response.body, 'invalidGitLabProject', - n => new GitLabProjectTreeItem(this, n.id.toString(), n.path_with_namespace), + n => new GitLabProjectTreeItem(this, n.id.toString(), n.path_with_namespace.toLowerCase()), n => n.path_with_namespace ); }