-
Notifications
You must be signed in to change notification settings - Fork 517
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
Azurecr/registry management #383
Azurecr/registry management #383
Conversation
Update dev to match Microsoft/vscode-docker/master
* Added Azure Credentials Manager Singleton * Added getResourceManagementClient
Added try catch loop and awaited for resource group list again to check for duplicates with ResourceManagementClient
* Added Azure Credentials Manager Singleton * Small Style Fixes * Further Style fixes, added getResourceManagementClient * Lazy Initialization Patches
-Changed order of questions asked to user for better UX (location of new res group & location of new registry) -Placeholder of location is display name view
Master update
Create Registry
* first fully functional version of delete through input bar AND right click * refactored code to make it prettier! * comments * comments, added subscription function * fixed to style guide * style fixes, refactoring * delete image after reviews put my functions from azureCredentialsManager into two new files: utils/azure/acrTools.ts, and commands/utils/quick-pick-azure.ts Edited code based on Esteban's and Bin's reviews * One last little change to delete image * moved repository, azureimage, and getsubscriptions to the correct places within deleteImage * changes from PR reviews on delete image * fixed authentication issue, got rid of azureAccount property for repository and image **on constructor for repository, azurecredentialsmanager was being recreated and thus couldn't find the azureAccount. For this reason, I got rid of the azureAccount property of the classes Repository and AzureImage. This bug may lead to future problems (Esteban and I couldn't see why it was happening) * minor fixes deleteImage * delete a parentheses
Master merge maintain fork updated
* Merge fixes to acquire latest telemetry items * Updated to master AzureUtilityManager
* tslint updates, transfered from old branch * updated icon * Addressed PR comments- mostly styling/code efficiency * Changed url to aka.ms link * changed Error window to Info message for no build tasks in your registry * Changed default sku and unified parsing resource group into a new method, getResourceGroup in acrTools.ts * Changed build task icon
* deleteRepo moved over to branch off dev * Got rid of unnecessary code, fully functioning! * deleteRepo moved over to branch off dev * Got rid of unnecessary code, fully functioning! * spacing * final commit * Cleaned code * Added Telemetry
Delete azure registry functionality added Delete azure registry moved to branch off dev Reorganized stye
Master dev merge
package.json
Outdated
@@ -491,6 +511,21 @@ | |||
"description": "Restarts a composition of containers", | |||
"category": "Docker" | |||
}, | |||
{ | |||
"command": "vscode-docker.create-ACR-Registry", | |||
"title": "Create Registry", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"title": "Create Azure Registry..."
The "Azure" part is important because from the command palette the context would otherwise be unclear. The "..." lets the user know we will be asking for more information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing my team suggested was should we maybe instead change the category to ACR ? And do the same for the rest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say it should probably match the registry node name, which is currently 'Azure'. You thinking that should change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, our pm suggested that we could just leave it so the commands would show up as ACR : Create Registry, ACR : Delete Repository, etc …
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fiveisprime Matt, what are your thoughts on having the ACR commands use a different category than the rest? Personally I'd rather they all start with "Docker: ".
(Esteban - I misspoke earlier about the category matching the node - I was referring to the command title, not the category).
I.e., I'd suggest:
Docker: Create ACR Registry
Docker: Delete ACR Repository
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather than start with "Docker:" as well; I like the suggestion of "Docker: Create ACR Registry" and so on. Is that clear enough?
Should we still abbreviate in this case? For example, would it make more sense to say "Docker: Create Azure Container Registry"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think either would be fine, I'll try to message my team's PM to see what his opinion is.
commands/utils/quick-pick-azure.ts
Outdated
resourceGroupNames.push(resGroupName.name); | ||
} | ||
|
||
let resourceGroupName = await vscode.window.showQuickPick(resourceGroupNames, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ext.ui.showQuickPick().
With your current code, the user can press cancel on this step, but the code keeps going and eventually ends up with "Error: Cannot read property 'name' of undefined"
commands/utils/quick-pick-azure.ts
Outdated
let resourceGroupNames: string[] = []; | ||
|
||
if (canCreateNew) { resourceGroupNames.push('+ Create new resource group'); } | ||
for (let resGroupName of resourceGroups) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resGroupName -> resGroup (it's a ResourceGroup, not a string)
commands/utils/quick-pick-azure.ts
Outdated
} else { | ||
resourceGroup = resourceGroups.find(resGroup => { return resGroup.name === resourceGroupName; }); | ||
} | ||
return resourceGroup; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method has some possible bug points that result from that fact that:
- You're treating the first item as special and indexing resourceGroupNames[0] directly
- You're assuming you will find the resourceGroup by name
These are fine as currently written, but they're fragile. E.g., what would you theoretically do you do if the find returns undefined? You can avoid these issues completely by rewriting this way:
export async function quickPickResourceGroup(canCreateNew?: boolean, subscription?: Subscription): Promise<ResourceGroup> {
let resourceGroups = await AzureUtilityManager.getInstance().getResourceGroups(subscription);
let resourceGroupItems: QuickPickItemWithData<ResourceGroup | undefined>[] = [];
let createNewItem: QuickPickItemWithData<ResourceGroup | undefined> = { label: '+ Create new resource group', data: undefined };
if (canCreateNew) { resourceGroupItems.push(createNewItem); }
for (let resGroup of resourceGroups) {
resourceGroupItems.push({ label: resGroup.name, data: resGroup });
}
let selectedItem = await vscode.window.showQuickPick(resourceGroupItems, {
'canPickMany': false,
'placeHolder': 'Choose a resource group to use'
});
let resourceGroup: ResourceGroup;
if (selectedItem === createNewItem) {
if (!subscription) {
subscription = await quickPickSubscription();
}
const loc = await quickPickLocation(subscription);
resourceGroup = await createNewResourceGroup(loc, subscription);
} else {
resourceGroup = selectedItem.data;
}
return resourceGroup;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! that looks a lot better and is more stable, I also implemented it for the optional can create part of quickPickACRRegistry. As a note I used IAzureQuickPickItem instead of QuickPickWithData as the IAzure one keeps track of recently used items.
utils/Azure/acrTools.ts
Outdated
}); | ||
}); | ||
} | ||
/** Obtains refresh tokens for Azure Container Registry. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: It's easier to read if you separate each function with a blank line
|
||
//Credential management | ||
/** Obtains registry username and password compatible with docker login */ | ||
export async function loginCredentials(registry: Registry): Promise<{ password: string, username: string }> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be unused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is as of this PR but I included it given that all the other token management items are included in this one. It is used in an upcoming feature we will PR after this one to enable pull.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay.
@@ -0,0 +1,163 @@ | |||
/*--------------------------------------------------------------------------------------------- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be largely a duplicate of code in azureRegistryNodes.ts. Duplicate code is bad - what if a bug is fixed in one copy but left unfixed in another? If you want to pull out the code from azureRegistryNodes.ts into shared functions and call it from multiple places, that's fine, as long the actual logic exists only in one place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable, Ill get to that too.
commands/utils/quick-pick-azure.ts
Outdated
|
||
export async function quickPickACRRegistry(canCreateNew: boolean = false, prompt?: string): Promise<Registry> { | ||
const placeHolder = prompt ? prompt : 'Choose registry to use'; | ||
let registries = await AzureUtilityManager.getInstance().getRegistries(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're not passing in a sort function, there's the list is not sorted. Really this is a problem with AzureUtilityManager.getRegistries - it should either:
- require a sort function (not optional)
- have a default sort if none is provided
- or don't ask for a sort function, just always do a sort by name
The current implementation makes bugs like these likely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think option 2 is best. It provides the functionality without limiting options that will avoid double sorting if an alternate sort is necessary. Ill use a default alphabetical sort.
vscode.window.showInformationMessage(`Successfully deleted image ${tag}`); | ||
if (context) { | ||
dockerExplorerProvider.refreshNode(context.parent); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else refreshRegistries()
vscode.window.showInformationMessage(`Successfully deleted repository ${Repository.name}`); | ||
if (context) { | ||
dockerExplorerProvider.refreshNode(context.parent); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else refreshRegistries()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See additional comments
commands/utils/quick-pick-azure.ts
Outdated
export async function confirmUserIntent(yesOrNoPrompt: string): Promise<boolean> { | ||
let opt: vscode.InputBoxOptions = { | ||
ignoreFocusOut: true, | ||
placeHolder: 'No', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
placeHolder: 'Yes'
(Value is the default value - they'll see that at first - so 'No' is correct for that. placeHolder is a watermark which they'll see if they delete the 'No' default value - it guides them or gives them examples of what to enter.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh that makes sense
I've updated to match the review items, let me know if there is anything else that looks like it could use some improvement. The only thing that may need a bit of further discussion is if we should change the naming for the acr features to show up as ACR : Create Registry, ACR : Delete Repository, etc …changing the category. For now I just normalized create Registry to Create Azure Registry. |
let createNewItem: IAzureQuickPickItem<Registry | undefined> = { label: '+ Create new registry', data: undefined }; | ||
if (canCreateNew) { quickPickRegList.unshift(createNewItem); } | ||
|
||
let desiredReg: IAzureQuickPickItem<Registry | undefined> = await ext.ui.showQuickPick(quickPickRegList, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ext.ui.showQuickPick will never return undefined (it will throw UserCancelledError instead)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's for the type of data within IAzureQuickPickItem however. That's only so I can potentially create a new registry if desired, it should have not have an effect on error checking neither is it used towards that effect.
commands/utils/quick-pick-azure.ts
Outdated
@@ -128,36 +130,30 @@ export async function quickPickResourceGroup(canCreateNew?: boolean, subscriptio | |||
export async function confirmUserIntent(yesOrNoPrompt: string): Promise<boolean> { | |||
let opt: vscode.InputBoxOptions = { | |||
ignoreFocusOut: true, | |||
placeHolder: 'No', | |||
placeHolder: 'Yes', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After playing with it, I'm suggesting a change:
placeHolder: 'Enter "Yes"',
Without that, it looks too much like a default value.
|
||
const subPool = new AsyncPool(MAX_CONCURRENT_SUBSCRIPTON_REQUESTS); | ||
let subsAndRegistries: { 'subscription': SubscriptionModels.Subscription, 'registries': ContainerModels.RegistryListResult }[] = []; | ||
//Acquire each subscription's data simultaneously | ||
// tslint:disable-next-line:prefer-for-of // Grandfathered in | ||
for (let i = 0; i < subs.length; i++) { | ||
for (let sub of subscriptions) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
np :)
@@ -33,8 +35,8 @@ export async function deleteAzureImage(context?: AzureImageNode): Promise<void> | |||
tag = wholeName[1]; | |||
} | |||
|
|||
const shouldDelete = await quickPicks.confirmUserIntent(`Are you sure you want to delete ${repoName}:${tag}? Enter yes to continue: `); | |||
if (shouldDelete) { | |||
const shouldDelete = await ext.ui.showWarningMessage(`Are you sure you want to delete ${repoName}:${tag}? Enter yes to continue: `, { modal: true }, DialogResponses.deleteResponse, DialogResponses.cancel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove "Enter yes to continue:"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you fixed that later...
} else { | ||
registry = await quickPickACRRegistry(false, 'Select the registry you want to delete'); | ||
} | ||
const shouldDelete = await confirmUserIntent(`Are you sure you want to delete ${registry.name} and its associated images? Enter yes to continue: `); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: You should let confirmUserIntent() append the 'Enter Yes to continue' portion to the prompt, since it's the one that's expecting that answer from the user anyway.
dockerExtension.ts
Outdated
@@ -160,6 +165,10 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> { | |||
ctx.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('docker', new DockerDebugConfigProvider())); | |||
|
|||
if (azureAccount) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because these commands are specified in the package.json, they will show up in the command palette. If you don't register them and the user tries to use them, you'll get an error from vscode saying it couldn't find the command. You could either:
- set it up so they don't show up in the command palette (minor pain)
- have them show a message to the user that they require the Azure Account extension to be installed
I'd prefer #2 for better discoverability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll update accordingly then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a wrapper for registerCommand called registerAzureCommand that handles the case that the azure account extension is not installed by letting the user know in the same manner as the deploy to appservices prompt does before. I suspect we may want to gather telemetry on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few more minor changes, otherwise looking good!
Adds ACR management capabilities to the extension, including:
Internally provides additional functionality for further development including:
Quick picks for azure related items
Additional functionality for ACR
Other changes: