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
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@
},
{
"command": "vscode-docker.registries.copyImageDigest",
"when": "view == dockerRegistries && viewItem =~ /registryV2Tag/",
"when": "view == dockerRegistries && viewItem =~ /(dockerHubTag|registryV2Tag|azureContainerTag|githubRegistryTag)/",
"group": "regs_tag_1_general@3"
},
{
Expand All @@ -531,7 +531,7 @@
},
{
"command": "vscode-docker.registries.deleteImage",
"when": "view == dockerRegistries && viewItem =~ /DockerV2;Tag;/",
"when": "view == dockerRegistries && viewItem =~ /(genericRegistryV2Tag|azureContainerTag|githubRegistryTag)/i",
"group": "regs_tag_2_destructive@2"
},
{
Expand Down
4 changes: 2 additions & 2 deletions src/commands/images/pushImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ export async function pushImage(context: IActionContext, node: ImageTreeItem | u

// Give the user a chance to modify the tag however they want
const finalTag = await tagImage(context, node, connectedRegistry);

if (connectedRegistry && finalTag.startsWith(getBaseImagePathFromRegistryItem(connectedRegistry.wrappedItem))) {
const baseImagePath = getBaseImagePathFromRegistryItem(connectedRegistry.wrappedItem);
if (connectedRegistry && finalTag.startsWith(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);
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/images/tagImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ImageTreeItem } from '../../tree/images/ImageTreeItem';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getBaseImagePathFromRegistryItem } from '../../tree/registries/registryTreeUtils';

export async function tagImage(context: IActionContext, node?: ImageTreeItem, registry?: UnifiedRegistryItem<unknown>): Promise<string> {
export async function tagImage(context: IActionContext, node?: ImageTreeItem, registry?: UnifiedRegistryItem<CommonRegistry>): Promise<string> {
if (!node) {
await ext.imagesTree.refresh(context);
node = await ext.imagesTree.showTreeItemPicker<ImageTreeItem>(ImageTreeItem.contextValue, {
Expand All @@ -21,7 +21,7 @@ export async function tagImage(context: IActionContext, node?: ImageTreeItem, re
}

addImageTaggingTelemetry(context, node.fullTag, '.before');
const baseImagePath = isRegistry(registry) ? getBaseImagePathFromRegistryItem(registry.wrappedItem as CommonRegistry) : undefined;
const baseImagePath = isRegistry(registry.wrappedItem) ? getBaseImagePathFromRegistryItem(registry.wrappedItem) : undefined;
const newTaggedName: string = await getTagFromUserInput(context, node.fullTag, baseImagePath);
addImageTaggingTelemetry(context, newTaggedName, '.after');

Expand Down
3 changes: 2 additions & 1 deletion src/commands/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import { viewAzureProperties } from "./registries/azure/viewAzureProperties";
import { connectRegistry } from "./registries/connectRegistry";
import { copyRemoteFullTag } from "./registries/copyRemoteFullTag";
import { copyRemoteImageDigest } from "./registries/copyRemoteImageDigest";
import { deleteRemoteImage } from "./registries/deleteRemoteImage";
import { disconnectRegistry } from "./registries/disconnectRegistry";
import { openDockerHubInBrowser } from "./registries/dockerHub/openDockerHubInBrowser";
import { logInToDockerCli } from "./registries/logInToDockerCli";
Expand Down Expand Up @@ -165,7 +166,7 @@ export function registerCommands(): void {
registerCommand('vscode-docker.registries.connectRegistry', connectRegistry);
registerCommand('vscode-docker.registries.copyImageDigest', copyRemoteImageDigest);
registerCommand('vscode-docker.registries.copyRemoteFullTag', copyRemoteFullTag);
// registerCommand('vscode-docker.registries.deleteImage', deleteRemoteImage);
registerCommand('vscode-docker.registries.deleteImage', deleteRemoteImage);
registerCommand('vscode-docker.registries.deployImageToAzure', deployImageToAzure);
registerCommand('vscode-docker.registries.deployImageToAca', deployImageToAca);
registerCommand('vscode-docker.registries.disconnectRegistry', disconnectRegistry);
Expand Down
6 changes: 3 additions & 3 deletions src/commands/registries/copyRemoteImageDigest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { IActionContext, contextValueExperience } from "@microsoft/vscode-azext-utils";
import { CommonTag, RegistryV2DataProvider, V2Tag } from "@microsoft/vscode-docker-registries";
import { CommonRegistryDataProvider, CommonTag } from "@microsoft/vscode-docker-registries";
import * as vscode from "vscode";
import { ext } from "../../extensionVariables";
import { UnifiedRegistryItem } from "../../tree/registries/UnifiedRegistryTreeDataProvider";
Expand All @@ -14,8 +14,8 @@ export async function copyRemoteImageDigest(context: IActionContext, node?: Unif
node = await contextValueExperience(context, ext.registriesTree, { include: ['registryV2Tag'] });
}

const v2DataProvider = node.provider as unknown as RegistryV2DataProvider;
const digest = await v2DataProvider.getImageDigest(node.wrappedItem as V2Tag);
const v2DataProvider = node.provider as unknown as CommonRegistryDataProvider;
const digest = await v2DataProvider.getImageDigest?.(node.wrappedItem as CommonTag);

/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
vscode.env.clipboard.writeText(digest);
Expand Down
77 changes: 45 additions & 32 deletions src/commands/registries/deleteRemoteImage.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,50 @@
// /*---------------------------------------------------------------------------------------------
// * Copyright (c) Microsoft Corporation. All rights reserved.
// * Licensed under the MIT License. See LICENSE.md in the project root for license information.
// *--------------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// import { DialogResponses, IActionContext } from '@microsoft/vscode-azext-utils';
// import { l10n, ProgressLocation, window } from 'vscode';
// import { ext } from '../../extensionVariables';
// import { DockerV2TagTreeItem } from '../../tree/registries/dockerV2/DockerV2TagTreeItem';
// import { registryExpectedContextValues } from '../../tree/registries/registryContextValues';
import { DialogResponses, IActionContext, UserCancelledError, parseError } from '@microsoft/vscode-azext-utils';
import { CommonTag, GenericRegistryV2DataProvider } from '@microsoft/vscode-docker-registries';
import { ProgressLocation, l10n, window } from 'vscode';
import { ext } from '../../extensionVariables';
import { UnifiedRegistryItem } from '../../tree/registries/UnifiedRegistryTreeDataProvider';
import { getImageNameFromRegistryTagItem } from '../../tree/registries/registryTreeUtils';
import { registryExperience } from '../../utils/registryExperience';

// export async function deleteRemoteImage(context: IActionContext, node?: DockerV2TagTreeItem): Promise<void> {
// if (!node) {
// node = await ext.registriesTree.showTreeItemPicker<DockerV2TagTreeItem>(registryExpectedContextValues.dockerV2.tag, {
// ...context,
// suppressCreatePick: true,
// noItemFoundErrorMessage: l10n.t('No remote images are available to delete')
// });
// }
export async function deleteRemoteImage(context: IActionContext, node?: UnifiedRegistryItem<CommonTag>): Promise<void> {
if (!node) {
node = await registryExperience(context, ext.registriesTree, { include: ['genericRegistryV2Tag', 'azureContainerTag', 'githubRegistryTag'] }, false);
}

// const confirmDelete = l10n.t('Are you sure you want to delete image "{0}"? This will delete all images that have the same digest.', node.repoNameAndTag);
// // no need to check result - cancel will throw a UserCancelledError
// await context.ui.showWarningMessage(confirmDelete, { modal: true }, DialogResponses.deleteResponse);
const tagName = getImageNameFromRegistryTagItem(node.wrappedItem);
const confirmDelete = l10n.t('Are you sure you want to delete image "{0}"? This will delete all images that have the same digest.', tagName);
// no need to check result - cancel will throw a UserCancelledError
await context.ui.showWarningMessage(confirmDelete, { modal: true }, DialogResponses.deleteResponse);

// const repoTI = node.parent;
// const deleting = l10n.t('Deleting image "{0}"...', node.repoNameAndTag);
// await window.withProgress({ location: ProgressLocation.Notification, title: deleting }, async () => {
// await node.deleteTreeItem(context);
// });
const deleting = l10n.t('Deleting image "{0}"...', tagName);
await window.withProgress({ location: ProgressLocation.Notification, title: deleting }, async () => {
const provider = node.provider as unknown as GenericRegistryV2DataProvider;

// // Other tags that also matched the image may have been deleted, so refresh the whole repository
// await repoTI.refresh(context);
// const message = l10n.t('Successfully deleted image "{0}".', node.repoNameAndTag);
// // don't wait
// /* eslint-disable-next-line @typescript-eslint/no-floating-promises */
// window.showInformationMessage(message);
// }
try {
await provider.deleteTag(node.wrappedItem);
} catch (error) {
const errorType: string = parseError(error).errorType.toLowerCase();
if (errorType === '405' || errorType === 'unsupported') {
// Don't wait
// eslint-disable-next-line @typescript-eslint/no-floating-promises
context.ui.showWarningMessage('Deleting remote images is not supported on this registry. It may need to be enabled.', { learnMoreLink: 'https://aka.ms/AA7jsql' });
throw new UserCancelledError();
} else {
throw error;
}
}
});

// TODO: investigate if we can do this for GitHub

// Other tags that also matched the image may have been deleted, so refresh the whole repository
// don't wait
void ext.registriesTree.refresh();
/* eslint-disable-next-line @typescript-eslint/no-floating-promises */
window.showInformationMessage(l10n.t('Successfully deleted image "{0}".', tagName));
}
3 changes: 1 addition & 2 deletions src/tree/registries/Azure/AzureRegistryDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export class AzureRegistryDataProvider extends RegistryV2DataProvider implements
await client.registries.beginDeleteAndWait(resourceGroup, item.label);
}

public async deleteTag(item: AzureTag): Promise<void> {
public override async deleteTag(item: AzureTag): Promise<void> {
const authenticationProvider = this.getAuthenticationProvider(item.parent.parent as unknown as AzureRegistryItem);

const reponse = await registryV2Request({
Expand All @@ -194,7 +194,6 @@ export class AzureRegistryDataProvider extends RegistryV2DataProvider implements

if (!reponse.succeeded) {
throw new Error(`Failed to delete tag: ${reponse.statusText}`);

}
}

Expand Down
5 changes: 4 additions & 1 deletion src/tree/registries/registryTreeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ export function getBaseImagePathFromRegistryItem(registry: CommonRegistry): stri

switch (registry.additionalContextValues?.[0] ?? '') {
case 'azureContainerRegistry':
case 'genericRegistryV2': {
case 'genericRegistryV2Registry': {
return registry.baseUrl.authority.toLowerCase();
}
case 'githubRegistry': {
return `${registry.baseUrl.authority.toLowerCase()}/${registry.label}`;
}
case 'dockerHubRegistry':
default:
return `${registry.label}`;
Expand Down
4 changes: 2 additions & 2 deletions src/utils/registryExperience.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import { AzureWizardPromptStep, ContextValueFilter, IActionContext, QuickPickWizardContext, RecursiveQuickPickStep, runQuickPickWizard } from '@microsoft/vscode-azext-utils';
import * as vscode from 'vscode';

export async function registryExperience<TPick>(context: IActionContext, tdp: vscode.TreeDataProvider<unknown>, contextValueFilter: ContextValueFilter): Promise<TPick> {
export async function registryExperience<TPick>(context: IActionContext, tdp: vscode.TreeDataProvider<unknown>, contextValueFilter: ContextValueFilter, skipIfOne: boolean = true): Promise<TPick> {
const promptSteps: AzureWizardPromptStep<QuickPickWizardContext>[] = [
new RecursiveQuickPickStep(
tdp,
{
contextValueFilter: contextValueFilter,
skipIfOne: true
skipIfOne: skipIfOne
}
)
];
Expand Down