From aa154ac91e7f8982ca414a035dbece36d34b71cd Mon Sep 17 00:00:00 2001 From: chrisdias Date: Sun, 3 Dec 2017 19:24:07 +0100 Subject: [PATCH 1/2] initial work --- dockerExtension.ts | 7 +++++- explorer/models/azureRegistryNodes.ts | 8 +++++-- explorer/models/azureUtils.ts | 34 +++++++++++++++++++++++++++ explorer/models/registryRootNode.ts | 3 ++- package.json | 10 ++++++++ 5 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 explorer/models/azureUtils.ts diff --git a/dockerExtension.ts b/dockerExtension.ts index bc759dfc1b..64c4d4cce4 100644 --- a/dockerExtension.ts +++ b/dockerExtension.ts @@ -28,7 +28,7 @@ import { DockerExplorerProvider } from './explorer/dockerExplorer'; import { removeContainer } from './commands/remove-container'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Middleware, Proposed, ProposedFeatures, DidChangeConfigurationNotification } from 'vscode-languageclient'; import { WebAppCreator } from './explorer/deploy/webAppCreator'; -import { AzureImageNode } from './explorer/models/azureRegistryNodes'; +import { AzureImageNode, AzureRegistryNode, AzureRepositoryNode } from './explorer/models/azureRegistryNodes'; import { DockerHubImageNode, DockerHubRepositoryNode, DockerHubOrgNode } from './explorer/models/dockerHubNodes'; import { AzureAccountWrapper } from './explorer/deploy/azureAccountWrapper'; import * as util from "./explorer/deploy/util"; @@ -36,6 +36,7 @@ import { dockerHubLogout, browseDockerHub } from './explorer/models/dockerHubUti import { AzureAccount } from './typings/azure-account.api'; import * as opn from 'opn'; import { DockerDebugConfigProvider } from './configureWorkspace/configDebugProvider'; +import { browseAzurePortal } from './explorer/models/azureUtils'; export const FROM_DIRECTIVE_PATTERN = /^\s*FROM\s*([\w-\/:]*)(\s*AS\s*[a-z][a-z0-9-_\\.]*)?$/i; @@ -130,6 +131,10 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { ctx.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('docker', new DockerDebugConfigProvider())); + ctx.subscriptions.push(vscode.commands.registerCommand('vscode-docker.browseAzurePortal', async (context?: AzureRegistryNode /* | AzureRepositoryNode | AzureImageNode */) => { + browseAzurePortal(context); + })); + activateLanguageClient(ctx); } diff --git a/explorer/models/azureRegistryNodes.ts b/explorer/models/azureRegistryNodes.ts index c4847edd84..90d763f45a 100644 --- a/explorer/models/azureRegistryNodes.ts +++ b/explorer/models/azureRegistryNodes.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import * as moment from 'moment'; import * as request from 'request-promise'; - +import * as ContainerModels from '../../node_modules/azure-arm-containerregistry/lib/models'; import { NodeBase } from './nodeBase'; import { SubscriptionClient, ResourceManagementClient, SubscriptionModels } from 'azure-arm-resource'; import { AzureAccount, AzureSession } from '../../typings/azure-account.api'; @@ -25,6 +25,7 @@ export class AzureRegistryNode extends NodeBase { public subscription: SubscriptionModels.Subscription; public userName: string; public password: string; + public registry: ContainerModels.Registry; getTreeItem(): vscode.TreeItem { return { @@ -107,6 +108,8 @@ export class AzureRegistryNode extends NodeBase { } } + + export class AzureRepositoryNode extends NodeBase { constructor( @@ -121,7 +124,7 @@ export class AzureRepositoryNode extends NodeBase { } public repository: string; - public subscription: any; + public subscription: SubscriptionModels.Subscription; public accessTokenARC: string; public refreshTokenARC: string; public userName: string; @@ -219,6 +222,7 @@ export class AzureImageNode extends NodeBase { super(label); } + public subscription: SubscriptionModels.Subscription; public serverUrl: string; public userName: string; public password: string; diff --git a/explorer/models/azureUtils.ts b/explorer/models/azureUtils.ts new file mode 100644 index 0000000000..5407950d50 --- /dev/null +++ b/explorer/models/azureUtils.ts @@ -0,0 +1,34 @@ +import * as opn from 'opn'; +import { AzureRepositoryNode, AzureImageNode, AzureRegistryNode } from './azureRegistryNodes'; +import { AzureSession } from '../../typings/azure-account.api'; + +// export function browseAzurePortal(context?: DockerHubImageNode | DockerHubRepositoryNode | DockerHubOrgNode) { + +// if (context) { +// let url: string = 'https://hub.docker.com/'; +// const repo: RepositoryInfo = context.repository; +// switch (context.contextValue) { +// case 'dockerHubNamespace': +// url = `${url}u/${context.userName}`; +// break; +// case 'dockerHubRepository': +// url = `${url}r/${context.repository.namespace}/${context.repository.name}`; +// break; +// case 'dockerHubImageTag': +// url = `${url}r/${context.repository.namespace}/${context.repository.name}/tags`; +// break; +// } +// opn(url); +// } +// } + +export function browseAzurePortal(context?: AzureRegistryNode /* | AzureRepositoryNode | AzureImageNode */): void { + + if (context) { + const tenantId: string = context.subscription.tenantId; + const session: AzureSession = context.azureAccount.sessions.find((s, i, array) => s.tenantId.toLowerCase() === tenantId.toLowerCase()); + const url: string = `${session.environment.portalUrl}/${tenantId}/#resource${context.registry.id}`; + opn(url); + } + +} diff --git a/explorer/models/registryRootNode.ts b/explorer/models/registryRootNode.ts index 607b1f44f7..139a167970 100644 --- a/explorer/models/registryRootNode.ts +++ b/explorer/models/registryRootNode.ts @@ -146,11 +146,12 @@ export class RegistryRootNode extends NodeBase { light: path.join(__filename, '..', '..', '..', '..', 'images', 'light', 'Registry_16x.svg'), dark: path.join(__filename, '..', '..', '..', '..', 'images', 'dark', 'Registry_16x.svg') }; - let node = new AzureRegistryNode(registries[j].loginServer, 'registry', iconPath, this._azureAccount); + let node = new AzureRegistryNode(registries[j].loginServer, 'azureRegistryNode', iconPath, this._azureAccount); node.type = RegistryType.Azure; node.password = creds.passwords[0].value; node.userName = creds.username; node.subscription = subs[i]; + node.registry = registries[j]; azureRegistryNodes.push(node); } } diff --git a/package.json b/package.json index f6433624c5..c99978f5aa 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "onCommand:vscode-docker.system.prune", "onCommand:vscode-docker.dockerHubLogout", "onCommand:vscode-docker.browseDockerHub", + "onCommand:vscode-docker.browseAzurePortal", "onView:dockerExplorer", "onDebug" ], @@ -214,6 +215,10 @@ { "command": "vscode-docker.browseDockerHub", "when": "view == dockerExplorer && viewItem == dockerHubNamespace" + }, + { + "command": "vscode-docker.browseAzurePortal", + "when": "view == dockerExplorer && viewItem == azureRegistryNode" } ] }, @@ -514,6 +519,11 @@ "command": "vscode-docker.browseDockerHub", "title": "Browse in DockerHub", "category": "Docker" + }, + { + "command": "vscode-docker.browseAzurePortal", + "title": "Browse in the Azure Portal", + "category": "Docker" } ], "views": { From 8a5173db64fc203fa20edeb464f67153ac47ae6a Mon Sep 17 00:00:00 2001 From: chrisdias Date: Mon, 4 Dec 2017 11:00:14 +0100 Subject: [PATCH 2/2] fixes #151 --- dockerExtension.ts | 10 ++--- explorer/models/azureRegistryNodes.ts | 41 +++++++++++++------- explorer/models/azureUtils.ts | 34 ---------------- explorer/models/containerNode.ts | 2 +- explorer/models/imageNode.ts | 2 +- explorer/utils/azureUtils.ts | 17 ++++++++ explorer/{models => utils}/dockerHubUtils.ts | 2 +- explorer/{models => utils}/utils.ts | 0 package.json | 10 ++++- 9 files changed, 60 insertions(+), 58 deletions(-) delete mode 100644 explorer/models/azureUtils.ts create mode 100644 explorer/utils/azureUtils.ts rename explorer/{models => utils}/dockerHubUtils.ts (99%) rename explorer/{models => utils}/utils.ts (100%) diff --git a/dockerExtension.ts b/dockerExtension.ts index 64c4d4cce4..c3523ad1a6 100644 --- a/dockerExtension.ts +++ b/dockerExtension.ts @@ -32,11 +32,11 @@ import { AzureImageNode, AzureRegistryNode, AzureRepositoryNode } from './explor import { DockerHubImageNode, DockerHubRepositoryNode, DockerHubOrgNode } from './explorer/models/dockerHubNodes'; import { AzureAccountWrapper } from './explorer/deploy/azureAccountWrapper'; import * as util from "./explorer/deploy/util"; -import { dockerHubLogout, browseDockerHub } from './explorer/models/dockerHubUtils'; +import { dockerHubLogout, browseDockerHub } from './explorer/utils/dockerHubUtils'; import { AzureAccount } from './typings/azure-account.api'; import * as opn from 'opn'; import { DockerDebugConfigProvider } from './configureWorkspace/configDebugProvider'; -import { browseAzurePortal } from './explorer/models/azureUtils'; +import { browseAzurePortal } from './explorer/utils/azureUtils'; export const FROM_DIRECTIVE_PATTERN = /^\s*FROM\s*([\w-\/:]*)(\s*AS\s*[a-z][a-z0-9-_\\.]*)?$/i; @@ -128,12 +128,12 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { ctx.subscriptions.push(vscode.commands.registerCommand('vscode-docker.browseDockerHub', async (context?: DockerHubImageNode | DockerHubRepositoryNode | DockerHubOrgNode) => { browseDockerHub(context); })); + ctx.subscriptions.push(vscode.commands.registerCommand('vscode-docker.browseAzurePortal', async (context?: AzureRegistryNode | AzureRepositoryNode | AzureImageNode ) => { + browseAzurePortal(context); + })); ctx.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('docker', new DockerDebugConfigProvider())); - ctx.subscriptions.push(vscode.commands.registerCommand('vscode-docker.browseAzurePortal', async (context?: AzureRegistryNode /* | AzureRepositoryNode | AzureImageNode */) => { - browseAzurePortal(context); - })); activateLanguageClient(ctx); } diff --git a/explorer/models/azureRegistryNodes.ts b/explorer/models/azureRegistryNodes.ts index 90d763f45a..bd9721c6e7 100644 --- a/explorer/models/azureRegistryNodes.ts +++ b/explorer/models/azureRegistryNodes.ts @@ -21,11 +21,11 @@ export class AzureRegistryNode extends NodeBase { this._azureAccount = azureAccount; } - public type: RegistryType; - public subscription: SubscriptionModels.Subscription; - public userName: string; public password: string; public registry: ContainerModels.Registry; + public subscription: SubscriptionModels.Subscription; + public type: RegistryType; + public userName: string; getTreeItem(): vscode.TreeItem { return { @@ -91,13 +91,15 @@ export class AzureRegistryNode extends NodeBase { if (body.length > 0) { const repositories = JSON.parse(body).repositories; for (let i = 0; i < repositories.length; i++) { - node = new AzureRepositoryNode(repositories[i], "azureRepository"); - node.repository = element.label; - node.subscription = element.subscription; + node = new AzureRepositoryNode(repositories[i], "azureRepositoryNode"); node.accessTokenARC = accessTokenARC; + node.azureAccount = element.azureAccount; + node.password = element.password; node.refreshTokenARC = refreshTokenARC; + node.registry = element.registry; + node.repository = element.label; + node.subscription = element.subscription; node.userName = element.userName; - node.password = element.password; repoNodes.push(node); } } @@ -123,12 +125,14 @@ export class AzureRepositoryNode extends NodeBase { super(label); } - public repository: string; - public subscription: SubscriptionModels.Subscription; public accessTokenARC: string; + public azureAccount: AzureAccount + public password: string; public refreshTokenARC: string; + public registry: ContainerModels.Registry; + public repository: string; + public subscription: SubscriptionModels.Subscription; public userName: string; - public password: string; getTreeItem(): vscode.TreeItem { return { @@ -147,7 +151,9 @@ export class AzureRepositoryNode extends NodeBase { let accessTokenARC; let tags; - const { accessToken, refreshToken } = await acquireToken(element.subscription.session); + const tenantId: string = element.subscription.tenantId; + const session: AzureSession = element.azureAccount.sessions.find((s, i, array) => s.tenantId.toLowerCase() === tenantId.toLowerCase()); + const { accessToken, refreshToken } = await acquireToken(session); if (accessToken && refreshToken) { const tenantId = element.subscription.tenantId; @@ -201,10 +207,13 @@ export class AzureRepositoryNode extends NodeBase { })); created = moment(new Date(JSON.parse(manifest.history[0].v1Compatibility).created)).fromNow(); - node = new AzureImageNode(`${element.label}:${tags[i]} (${created})`, 'azureImageTag'); + node = new AzureImageNode(`${element.label}:${tags[i]} (${created})`, 'azureImageNode'); + node.azureAccount = element.azureAccount; + node.password = element.password; + node.registry = element.registry; node.serverUrl = element.repository; + node.subscription = element.subscription; node.userName = element.userName; - node.password = element.password; imageNodes.push(node); } @@ -222,10 +231,12 @@ export class AzureImageNode extends NodeBase { super(label); } - public subscription: SubscriptionModels.Subscription; + public azureAccount: AzureAccount + public password: string; + public registry: ContainerModels.Registry; public serverUrl: string; + public subscription: SubscriptionModels.Subscription; public userName: string; - public password: string; getTreeItem(): vscode.TreeItem { return { diff --git a/explorer/models/azureUtils.ts b/explorer/models/azureUtils.ts deleted file mode 100644 index 5407950d50..0000000000 --- a/explorer/models/azureUtils.ts +++ /dev/null @@ -1,34 +0,0 @@ -import * as opn from 'opn'; -import { AzureRepositoryNode, AzureImageNode, AzureRegistryNode } from './azureRegistryNodes'; -import { AzureSession } from '../../typings/azure-account.api'; - -// export function browseAzurePortal(context?: DockerHubImageNode | DockerHubRepositoryNode | DockerHubOrgNode) { - -// if (context) { -// let url: string = 'https://hub.docker.com/'; -// const repo: RepositoryInfo = context.repository; -// switch (context.contextValue) { -// case 'dockerHubNamespace': -// url = `${url}u/${context.userName}`; -// break; -// case 'dockerHubRepository': -// url = `${url}r/${context.repository.namespace}/${context.repository.name}`; -// break; -// case 'dockerHubImageTag': -// url = `${url}r/${context.repository.namespace}/${context.repository.name}/tags`; -// break; -// } -// opn(url); -// } -// } - -export function browseAzurePortal(context?: AzureRegistryNode /* | AzureRepositoryNode | AzureImageNode */): void { - - if (context) { - const tenantId: string = context.subscription.tenantId; - const session: AzureSession = context.azureAccount.sessions.find((s, i, array) => s.tenantId.toLowerCase() === tenantId.toLowerCase()); - const url: string = `${session.environment.portalUrl}/${tenantId}/#resource${context.registry.id}`; - opn(url); - } - -} diff --git a/explorer/models/containerNode.ts b/explorer/models/containerNode.ts index c25f3c8f3f..cd64727a9e 100644 --- a/explorer/models/containerNode.ts +++ b/explorer/models/containerNode.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode'; import { NodeBase } from './nodeBase'; -import { trimWithElipsis } from './utils'; +import { trimWithElipsis } from '../utils/utils'; export class ContainerNode extends NodeBase { diff --git a/explorer/models/imageNode.ts b/explorer/models/imageNode.ts index ee3e95e2a3..723ec29f2a 100644 --- a/explorer/models/imageNode.ts +++ b/explorer/models/imageNode.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import * as moment from 'moment'; import { NodeBase } from './nodeBase'; -import { trimWithElipsis } from './utils'; +import { trimWithElipsis } from '../utils/utils'; export class ImageNode extends NodeBase { diff --git a/explorer/utils/azureUtils.ts b/explorer/utils/azureUtils.ts new file mode 100644 index 0000000000..f6ae59e2ea --- /dev/null +++ b/explorer/utils/azureUtils.ts @@ -0,0 +1,17 @@ +import * as opn from 'opn'; +import { AzureRepositoryNode, AzureImageNode, AzureRegistryNode } from '../models/azureRegistryNodes'; +import { AzureSession } from '../../typings/azure-account.api'; + +export function browseAzurePortal(context?: AzureRegistryNode | AzureRepositoryNode | AzureImageNode ): void { + + if (context) { + const tenantId: string = context.subscription.tenantId; + const session: AzureSession = context.azureAccount.sessions.find((s, i, array) => s.tenantId.toLowerCase() === tenantId.toLowerCase()); + let url: string = `${session.environment.portalUrl}/${tenantId}/#resource${context.registry.id}`; + if (context.contextValue === 'azureImageNode' || context.contextValue === 'azureRepositoryNode') { + url = `${url}/repository`; + } + opn(url); + } + +} diff --git a/explorer/models/dockerHubUtils.ts b/explorer/utils/dockerHubUtils.ts similarity index 99% rename from explorer/models/dockerHubUtils.ts rename to explorer/utils/dockerHubUtils.ts index f964da1cbf..4428692e9a 100644 --- a/explorer/models/dockerHubUtils.ts +++ b/explorer/utils/dockerHubUtils.ts @@ -2,7 +2,7 @@ import * as vscode from 'vscode'; import * as keytarType from 'keytar'; import * as opn from 'opn'; import request = require('request-promise'); -import { DockerHubRepositoryNode, DockerHubImageNode, DockerHubOrgNode } from './dockerHubNodes'; +import { DockerHubRepositoryNode, DockerHubImageNode, DockerHubOrgNode } from '../models/dockerHubNodes'; let _token: Token; diff --git a/explorer/models/utils.ts b/explorer/utils/utils.ts similarity index 100% rename from explorer/models/utils.ts rename to explorer/utils/utils.ts diff --git a/package.json b/package.json index c99978f5aa..3c94781831 100644 --- a/package.json +++ b/package.json @@ -194,7 +194,7 @@ }, { "command": "vscode-docker.createWebApp", - "when": "view == dockerExplorer && viewItem == azureImageTag" + "when": "view == dockerExplorer && viewItem == azureImageNode" }, { "command": "vscode-docker.createWebApp", @@ -219,6 +219,14 @@ { "command": "vscode-docker.browseAzurePortal", "when": "view == dockerExplorer && viewItem == azureRegistryNode" + }, + { + "command": "vscode-docker.browseAzurePortal", + "when": "view == dockerExplorer && viewItem == azureRepositoryNode" + }, + { + "command": "vscode-docker.browseAzurePortal", + "when": "view == dockerExplorer && viewItem == azureImageNode" } ] },