-
Notifications
You must be signed in to change notification settings - Fork 2
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
Rutusamai/list build tasks for each registry #37
Changes from all commits
6175beb
04a670e
4389efa
a92fb72
84f0bf2
1b2b2fa
d584a0b
522b17f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import { AsyncPool } from '../../utils/asyncpool'; | |
import { MAX_CONCURRENT_REQUESTS } from '../../utils/constants' | ||
import { NodeBase } from './nodeBase'; | ||
import { RegistryType } from './registryType'; | ||
import { TaskRootNode } from './taskNode'; | ||
|
||
export class AzureRegistryNode extends NodeBase { | ||
private _azureAccount: AzureAccount; | ||
|
@@ -38,9 +39,17 @@ export class AzureRegistryNode extends NodeBase { | |
} | ||
} | ||
|
||
public async getChildren(element: AzureRegistryNode): Promise<AzureRepositoryNode[]> { | ||
const repoNodes: AzureRepositoryNode[] = []; | ||
let node: AzureRepositoryNode; | ||
public async getChildren(element: AzureRegistryNode): Promise<NodeBase[]> { | ||
const registryChildNodes: NodeBase[] = []; | ||
|
||
let iconPath = { | ||
light: path.join(__filename, '..', '..', '..', '..', 'images', 'light', 'buildTasks_light.svg'), | ||
dark: path.join(__filename, '..', '..', '..', '..', 'images', 'dark', 'buildTasks_dark.svg') | ||
}; | ||
|
||
//Pushing single TaskRootNode under the current registry. All the following nodes added to registryNodes are type AzureRepositoryNode | ||
let taskNode = new TaskRootNode("Build Tasks", "taskRootNode", element.subscription, element.azureAccount, element.registry, iconPath); | ||
registryChildNodes.push(taskNode); | ||
|
||
const tenantId: string = element.subscription.tenantId; | ||
if (!this._azureAccount) { | ||
|
@@ -50,6 +59,8 @@ export class AzureRegistryNode extends NodeBase { | |
const session: AzureSession = this._azureAccount.sessions.find((s, i, array) => s.tenantId.toLowerCase() === tenantId.toLowerCase()); | ||
const { accessToken, refreshToken } = await acquireToken(session); | ||
|
||
let node: AzureRepositoryNode; | ||
|
||
if (accessToken && refreshToken) { | ||
let refreshTokenARC; | ||
let accessTokenARC; | ||
|
@@ -91,9 +102,8 @@ export class AzureRegistryNode extends NodeBase { | |
}, (err, httpResponse, body) => { | ||
if (body.length > 0) { | ||
const repositories = JSON.parse(body).repositories; | ||
// tslint:disable-next-line:prefer-for-of // Grandfathered in | ||
for (let i = 0; i < repositories.length; i++) { | ||
node = new AzureRepositoryNode(repositories[i], "azureRepositoryNode"); | ||
for (let repo of repositories) { | ||
node = new AzureRepositoryNode(repo, "azureRepositoryNode"); | ||
node.accessTokenARC = accessTokenARC; | ||
node.azureAccount = element.azureAccount; | ||
node.password = element.password; | ||
|
@@ -102,13 +112,13 @@ export class AzureRegistryNode extends NodeBase { | |
node.repository = element.label; | ||
node.subscription = element.subscription; | ||
node.userName = element.userName; | ||
repoNodes.push(node); | ||
registryChildNodes.push(node); | ||
} | ||
} | ||
}); | ||
} | ||
//Note these are ordered by default in alphabetical order | ||
return repoNodes; | ||
return registryChildNodes; | ||
} | ||
} | ||
|
||
|
@@ -117,7 +127,7 @@ export class AzureRepositoryNode extends NodeBase { | |
constructor( | ||
public readonly label: string, | ||
public readonly contextValue: string, | ||
public readonly iconPath: { light: string | vscode.Uri; dark: string | vscode.Uri } = { | ||
public readonly iconPath: AzureRegistryNode["iconPath"] = { | ||
light: path.join(__filename, '..', '..', '..', '..', 'images', 'light', 'Repository_16x.svg'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like both are the same icon? Make sure that this changes when we get the real one |
||
dark: path.join(__filename, '..', '..', '..', '..', 'images', 'dark', 'Repository_16x.svg') | ||
} | ||
|
@@ -199,18 +209,17 @@ export class AzureRepositoryNode extends NodeBase { | |
}); | ||
|
||
const pool = new AsyncPool(MAX_CONCURRENT_REQUESTS); | ||
// tslint:disable-next-line:prefer-for-of // Grandfathered in | ||
for (let i = 0; i < tags.length; i++) { | ||
for (let tag of tags) { | ||
pool.addTask(async () => { | ||
let data = await request.get('https://' + element.repository + '/v2/' + element.label + `/manifests/${tags[i]}`, { | ||
let data = await request.get('https://' + element.repository + '/v2/' + element.label + `/manifests/${tag}`, { | ||
auth: { | ||
bearer: accessTokenARC | ||
} | ||
}); | ||
|
||
//Acquires each image's manifest to acquire build time. | ||
let manifest = JSON.parse(data); | ||
node = new AzureImageNode(`${element.label}:${tags[i]}`, 'azureImageNode'); | ||
node = new AzureImageNode(`${element.label}:${tag}`, 'azureImageNode'); | ||
node.azureAccount = element.azureAccount; | ||
node.password = element.password; | ||
node.registry = element.registry; | ||
|
@@ -296,7 +305,7 @@ async function acquireToken(session: AzureSession): Promise<{ accessToken: strin | |
const credentials: any = session.credentials; | ||
const environment: any = session.environment; | ||
// tslint:disable-next-line:no-function-expression // Grandfathered in | ||
credentials.context.acquireToken(environment.activeDirectoryResourceId, credentials.username, credentials.clientId, function (err: any, result: { accessToken: string; refreshToken: string; }): void { | ||
credentials.context.acquireToken(environment.activeDirectoryResourceId, credentials.username, credentials.clientId, function (err: any, result: any): any { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { ResourceManagementClient, SubscriptionClient, SubscriptionModels } from 'azure-arm-resource'; | ||
import * as opn from 'opn'; | ||
import * as vscode from 'vscode'; | ||
import * as ContainerModels from '../../node_modules/azure-arm-containerregistry/lib/models'; | ||
import { AzureAccount, AzureSession } from '../../typings/azure-account.api'; | ||
import * as acrTools from '../../utils/Azure/acrTools'; | ||
import { AzureCredentialsManager } from '../../utils/azureCredentialsManager'; | ||
import { NodeBase } from './nodeBase'; | ||
|
||
/* Single TaskRootNode under each Repository. Labeled "Build Tasks" */ | ||
export class TaskRootNode extends NodeBase { | ||
constructor( | ||
public readonly label: string, | ||
public readonly contextValue: string, | ||
public subscription: SubscriptionModels.Subscription, | ||
public readonly azureAccount: AzureAccount, | ||
public registry: ContainerModels.Registry, | ||
public readonly iconPath: any = {} | ||
) { | ||
super(label); | ||
} | ||
|
||
public name: string; | ||
|
||
public getTreeItem(): vscode.TreeItem { | ||
return { | ||
label: this.label, | ||
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed, | ||
contextValue: this.contextValue, | ||
iconPath: this.iconPath | ||
} | ||
} | ||
|
||
/* Making a list view of BuildTaskNodes, or the Build Tasks of the current registry */ | ||
public async getChildren(element: TaskRootNode): Promise<BuildTaskNode[]> { | ||
const buildTaskNodes: BuildTaskNode[] = []; | ||
let buildTasks: ContainerModels.BuildTask[] = []; | ||
|
||
const client = AzureCredentialsManager.getInstance().getContainerRegistryManagementClient(element.subscription); | ||
const resourceGroup: string = acrTools.getResourceGroup(element.registry); | ||
|
||
buildTasks = await client.buildTasks.list(resourceGroup, element.registry.name); | ||
if (buildTasks.length === 0) { | ||
vscode.window.showInformationMessage(`You do not have any Build Tasks in the registry, '${element.registry.name}'. You can create one with ACR Build. `, "Learn More").then(val => { | ||
if (val === "Learn More") { | ||
opn('https://aka.ms/acr/buildtask'); | ||
} | ||
}) | ||
} | ||
|
||
for (let buildTask of buildTasks) { | ||
let node = new BuildTaskNode(buildTask.name, "buildTaskNode"); | ||
buildTaskNodes.push(node); | ||
} | ||
return buildTaskNodes; | ||
} | ||
} | ||
|
||
export class BuildTaskNode extends NodeBase { | ||
|
||
constructor( | ||
public readonly label: string, | ||
public readonly contextValue: string, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. where do you use the contextValue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nowhere yet, but later we will link the BuildTaskNode to open the corresponding log |
||
) { | ||
super(label); | ||
} | ||
} |
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.
We should probably standardize the icon names/ paths, there is a file under utils called constants which would be helpful for 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.
Not sure we need that since for each image, iconPath (light and dark) is only called once in the codebase
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 is true but it is easier to refactor/change images from a single location, this is better practice and makes for a more unified experience, moving them all out would make the codebase neater. This isn't however pressing and should be done on further refactorings and doesn't really fit in this scope.