Skip to content
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

Updated download task to support package names #10984

Merged
merged 8 commits into from
Jul 31, 2019
24 changes: 24 additions & 0 deletions Tasks/DownloadPackageV1/Tests/L0.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,30 @@ describe("Download single file package suite", function() {
done();
});

it("resolves package id, then downloads and extracts nuget package.", (done: MochaDone) => {
this.timeout(1000);

let tp: string = path.join(__dirname, "L0DownloadNugetPackageNameResolves.js");

let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);

tr.run();

assert.equal(tl.ls(null, [tempDir]).length, 1, "should have only 1 file.");
const zipPath = path.join(tempDir, "singlePackageName.nupkg");
const zipStats = tl.stats(zipPath);
assert(zipStats && zipStats.isFile(), "nupkg file should be downloaded");

var extractedFilePath = path.join(destinationDir, "nugetFile");
const fileStats = tl.stats(extractedFilePath);
assert(fileStats && fileStats.isFile(), "nupkg file should be extracted");

assert(tr.stderr.length === 0, "should not have written to stderr");
assert(tr.succeeded, "task should have succeeded");

done();
});

it("downloads nuget file from project scoped feed as nupkg and extracts it", (done: MochaDone) => {
this.timeout(1000);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
tr.setInput("packageType", "maven");
tr.setInput("feed", "feedId");
tr.setInput("view", "viewId");
tr.setInput("definition", "packageId");
tr.setInput("definition", "6f598cbe-a5e2-4f75-aa78-e0fd08301a15");
tr.setInput("version", "versionId");
tr.setInput("downloadPath", outputPath);
tr.setInput("files", "*.jar; *.pom");
Expand Down
2 changes: 1 addition & 1 deletion Tasks/DownloadPackageV1/Tests/L0DownloadNpmPackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
tr.setInput("packageType", "npm");
tr.setInput("feed", "feedId");
tr.setInput("view", "viewId");
tr.setInput("definition", "packageId");
tr.setInput("definition", "6f598cbe-a5e2-4f75-aa78-e0fd08301a15");
tr.setInput("version", "versionId");
tr.setInput("downloadPath", outputPath);
tr.setInput("extract", "true");
Expand Down
2 changes: 1 addition & 1 deletion Tasks/DownloadPackageV1/Tests/L0DownloadNugetPackage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
tr.setInput("packageType", "nuget");
tr.setInput("feed", "/feedId");
tr.setInput("view", "viewId");
tr.setInput("definition", "packageId");
tr.setInput("definition", "6f598cbe-a5e2-4f75-aa78-e0fd08301a15");
tr.setInput("version", "versionId");
tr.setInput("downloadPath", outputPath);
tr.setInput("extract", "true");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import tmrm = require("azure-pipelines-task-lib/mock-run");
import path = require("path");
import { WebApiMock } from "./helpers/webapimock";

let taskPath = path.join(__dirname, "..", "main.js");
let outputPath: string = path.join(__dirname, "out", "packageOutput");
let tempPath: string = path.join(__dirname, "temp");
let zipLocation: string = path.join(tempPath, "singlePackageName.nupkg");
let tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);

// Set inputs
tr.setInput("packageType", "nuget");
tr.setInput("feed", "/feedId");
tr.setInput("view", "viewId");
tr.setInput("definition", "packageName");
tr.setInput("version", "versionId");
tr.setInput("downloadPath", outputPath);
tr.setInput("extract", "true");
tr.setInput("verbosity", "verbose");

// Set variables.
process.env["AGENT_TEMPDIRECTORY"] = tempPath;
process.env["SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"] = "https://abc.visualstudio.com/";
process.env["AGENT_VERSION"] = "2.116.0";
process.env["HOME"] = "/users/test";
process.env["ENDPOINT_AUTH_SYSTEMVSSCONNECTION"] =
'{"scheme":"OAuth","parameters":{"AccessToken":"YWFtYWxsYWQ6ZXd0emE1bmN3MzN6c3lyM2NoN2prazUzejczamN6MnluNGtiNzd0ZXc0NnlhZzV2d3ZlcQ=="}}';

// provide answers for task mock
tr.setAnswers({
exist: {
[outputPath]: true,
[tempPath]: true
},
rmRF: {
[zipLocation]: {
success: true
}
}
});

// Register connections mock
tr.registerMock("./connections", {
getConnection: function(): Promise<any> {
return Promise.resolve(new WebApiMock());
}
});

tr.registerMock("./universal", {
downloadUniversalPackage: function(
downloadPath: string,
feedId: string,
packageId: string,
version: string
): Promise<void> {
return;
}
});

tr.run();
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
tr.setInput("packageType", "nuget");
tr.setInput("feed", "feedId");
tr.setInput("view", "viewId");
tr.setInput("definition", "packageId");
tr.setInput("definition", "6f598cbe-a5e2-4f75-aa78-e0fd08301a15");
tr.setInput("version", "versionId");
tr.setInput("downloadPath", outputPath);
tr.setInput("extract", "false");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let tr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
tr.setInput("packageType", "nuget");
tr.setInput("feed", "projectId/feedId");
tr.setInput("view", "viewId");
tr.setInput("definition", "packageId");
tr.setInput("definition", "6f598cbe-a5e2-4f75-aa78-e0fd08301a15");
tr.setInput("version", "versionId");
tr.setInput("downloadPath", outputPath);
tr.setInput("extract", "true");
Expand Down
15 changes: 15 additions & 0 deletions Tasks/DownloadPackageV1/Tests/helpers/webapimock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,27 @@ class VsoClientMock {
routeValues: any,
queryParams?: any
): Promise<any> {
if(queryParams && "packageNameQuery" in queryParams) {
return Promise.resolve({ requestUrl: "packageNameResolverUrl" })
}
return Promise.resolve({ requestUrl: this.packageUrlMap[locationId] });
}
}

class RestMock {
private metadataMap = {
packageNameResolverUrl: {
"count":2,
"value": [
{
"name": "unknown"
},
{
"name": "packageName",
"id": "6f598cbe-a5e2-4f75-aa78-e0fd08301a15"
}
]
},
singlePackageMetadataUrl: {
name: "singlePackageName"
},
Expand Down
8 changes: 8 additions & 0 deletions Tasks/DownloadPackageV1/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ async function main(): Promise<void> {
.matchingPattern(files)
.withRetries(Retry(retryLimit))
.build();

const regexGuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;

if(!regexGuid.test(packageId)){
tl.debug("Trying to resolve package name " + packageId + " to id.");
packageId = await p.resolvePackageId(feed.feedId, feed.projectId, packageId);
tl.debug("Resolved package id: " + packageId);
}

const packageFiles: PackageFile[] = await p.download(feed.feedId, feed.projectId, packageId, version, downloadPath, extractPackage);

Expand Down
36 changes: 34 additions & 2 deletions Tasks/DownloadPackageV1/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export abstract class Package {

private executeWithRetries: <T>(operation: () => Promise<T>) => Promise<T>;
private packagingAreaName: string = "Packaging";
private getPackagesAreaId: string = "7a20d846-c929-4acc-9ea2-0d5a7df1b197";
private packagingMetadataAreaId: string;

constructor(builder: PackageUrlsBuilder) {
Expand Down Expand Up @@ -78,11 +79,11 @@ export abstract class Package {
});
}

protected async getPackageMetadata(connection: WebApi, routeValues: any, queryParams?: any): Promise<any> {
protected async getPackageMetadata(connection: WebApi, routeValues: any, queryParams?: any, areaId?: string): Promise<any> {
var metadataUrl = await this.getUrl(
connection.vsoClient,
this.packagingAreaName,
this.packagingMetadataAreaId,
areaId || this.packagingMetadataAreaId,
routeValues,
queryParams
);
Expand All @@ -105,6 +106,37 @@ export abstract class Package {
});
}

public async resolvePackageId(
feedId: string,
project: string,
packageName: string
): Promise<string> {
const routeValues = {
feedId: feedId,
project: project
};
const queryParams = {
packageNameQuery: packageName,
protocolType: this.packageProtocolAreaName
};

return new Promise<string>(async (resolve, reject) => {
this.getPackageMetadata(this.feedConnection, routeValues, queryParams, this.getPackagesAreaId)
.then(packages => {
tl.debug("Found " + packages["count"] + " packages matching search pattern " + packageName);
for (let i = 0; i < packages["count"]; i++) {
if (packages["value"][i]["name"] == packageName) {
return resolve(packages["value"][i]["id"]);
}
}
return reject("Package with name " + packageName + " not found.");
}).catch(error => {
tl.debug("Package with name " + packageName + " not found: " + error);
return reject(error);
})
});
}

public async download(
feedId: string,
project: string,
Expand Down
7 changes: 5 additions & 2 deletions Tasks/DownloadPackageV1/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,12 @@
"view": "$(view)",
"packageType": "$(packageType)"
},
"endpointUrl": "{{endpoint.url}}/{{ #regex ([a-fA-F0-9\\-]+/)[a-fA-F0-9\\-]+ feed }}_apis/Packaging/Feeds/{{ #regex [a-fA-F0-9\\-]*/([a-fA-F0-9\\-]+) feed }}{{#if view}}@{{{view}}}{{/if}}/Packages?includeUrls=false&isListed=true&includeDeleted=false&protocolType={{{packageType}}}",
"endpointUrl": "{{endpoint.url}}/{{ #regex ([a-fA-F0-9\\-]+/)[a-fA-F0-9\\-]+ feed }}_apis/Packaging/Feeds/{{ #regex [a-fA-F0-9\\-]*/([a-fA-F0-9\\-]+) feed }}{{#if view}}@{{{view}}}{{/if}}/Packages?includeUrls=false&isListed=true&includeDeleted=false&protocolType={{{packageType}}}&$skip={{skip}}&$top=1000",
"resultSelector": "jsonpath:$.value[*]",
"resultTemplate": "{ \"Value\" : \"{{{id}}}\", \"DisplayValue\" : \"{{{name}}}\" }"
"resultTemplate": "{ \"Value\" : \"{{{id}}}\", \"DisplayValue\" : \"{{{name}}}\" }",
"callbackContextTemplate": "{\"skip\": \"{{add skip 1000}}\"}",
"callbackRequiredTemplate": "{{isEqualNumber result.count 1000}}",
"initialContextTemplate": "{\"skip\": \"0\"}"
},
{
"target": "version",
Expand Down
7 changes: 5 additions & 2 deletions Tasks/DownloadPackageV1/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,12 @@
"view": "$(view)",
"packageType": "$(packageType)"
},
"endpointUrl": "{{endpoint.url}}/{{ #regex ([a-fA-F0-9\\-]+/)[a-fA-F0-9\\-]+ feed }}_apis/Packaging/Feeds/{{ #regex [a-fA-F0-9\\-]*/([a-fA-F0-9\\-]+) feed }}{{#if view}}@{{{view}}}{{/if}}/Packages?includeUrls=false&isListed=true&includeDeleted=false&protocolType={{{packageType}}}",
"endpointUrl": "{{endpoint.url}}/{{ #regex ([a-fA-F0-9\\-]+/)[a-fA-F0-9\\-]+ feed }}_apis/Packaging/Feeds/{{ #regex [a-fA-F0-9\\-]*/([a-fA-F0-9\\-]+) feed }}{{#if view}}@{{{view}}}{{/if}}/Packages?includeUrls=false&isListed=true&includeDeleted=false&protocolType={{{packageType}}}&$skip={{skip}}&$top=1000",
"resultSelector": "jsonpath:$.value[*]",
"resultTemplate": "{ \"Value\" : \"{{{id}}}\", \"DisplayValue\" : \"{{{name}}}\" }"
"resultTemplate": "{ \"Value\" : \"{{{id}}}\", \"DisplayValue\" : \"{{{name}}}\" }",
"callbackContextTemplate": "{\"skip\": \"{{add skip 1000}}\"}",
"callbackRequiredTemplate": "{{isEqualNumber result.count 1000}}",
"initialContextTemplate": "{\"skip\": \"0\"}"
},
{
"target": "version",
Expand Down