From 32f35a3ad783198d555fc66139cd58083735ea7f Mon Sep 17 00:00:00 2001 From: Gareth Emslie Date: Thu, 13 Aug 2020 09:36:38 +0200 Subject: [PATCH] refactor shared code --- .../DownloadArtifactsNexusV0_2/index.ts | 164 +---- .../package-lock.json | 32 - .../DownloadArtifactsNexusV0_2/package.json | 4 +- .../DownloadArtifactsNexusV0_3/IhttpHelper.ts | 6 - .../DownloadArtifactsNexusV0_3/httpHelper.ts | 138 ---- .../DownloadArtifactsNexusV0_3/index.ts | 81 +-- .../DownloadArtifactsNexusV2/index.ts | 149 +--- .../package-lock.json | 13 + .../DownloadArtifactsNexusV3/IhttpHelper.ts | 6 - .../DownloadArtifactsNexusV3/httpHelper.ts | 138 ---- .../DownloadArtifactsNexusV3/index.ts | 81 +-- .../nexus-v2}/IhttpHelper.ts | 2 +- .../nexus-v2}/httpHelper.ts | 0 libs/nexus-v2/nexus.ts | 143 ++++ libs/nexus-v2/package-lock.json | 641 ++++++++++++++++++ libs/nexus-v2/package.json | 24 + libs/nexus-v2/tsconfig.json | 22 + .../nexus-v3}/IhttpHelper.ts | 2 +- .../nexus-v3}/httpHelper.ts | 18 +- libs/nexus-v3/nexus.ts | 80 +++ libs/nexus-v3/package-lock.json | 641 ++++++++++++++++++ libs/nexus-v3/package.json | 24 + libs/nexus-v3/tsconfig.json | 22 + package.json | 10 +- tsconfig.json | 2 +- 25 files changed, 1686 insertions(+), 757 deletions(-) delete mode 100644 Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/IhttpHelper.ts delete mode 100644 Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/httpHelper.ts delete mode 100644 Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/IhttpHelper.ts delete mode 100644 Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/httpHelper.ts rename {Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2 => libs/nexus-v2}/IhttpHelper.ts (83%) rename {Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2 => libs/nexus-v2}/httpHelper.ts (100%) create mode 100644 libs/nexus-v2/nexus.ts create mode 100644 libs/nexus-v2/package-lock.json create mode 100644 libs/nexus-v2/package.json create mode 100644 libs/nexus-v2/tsconfig.json rename {Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2 => libs/nexus-v3}/IhttpHelper.ts (83%) rename {Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2 => libs/nexus-v3}/httpHelper.ts (94%) create mode 100644 libs/nexus-v3/nexus.ts create mode 100644 libs/nexus-v3/package-lock.json create mode 100644 libs/nexus-v3/package.json create mode 100644 libs/nexus-v3/tsconfig.json diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/index.ts b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/index.ts index d9cda67..aed2a30 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/index.ts +++ b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/index.ts @@ -2,11 +2,8 @@ import tl = require('azure-pipelines-task-lib/task'); import shell = require("shelljs"); import path = require("path"); import fs = require('fs'); -import * as xml2js from 'xml2js'; -import * as xpath from "xml2js-xpath"; -import { IhttpHelper } from './IhttpHelper'; -import { httpHelper } from './httpHelper'; -const nexus : IhttpHelper = new httpHelper(); +import n = require('nexus-v2'); +const nexus = new n.nexus(); async function run() { console.log(`Downloading artifact.`); @@ -47,7 +44,7 @@ async function run() { const group: string | undefined = tl.getInput("group", true); const artifact: string | undefined = tl.getInput("artifact", true); const baseVersion: string | undefined = tl.getInput("version", true); - const packaging: string | undefined = tl.getInput("packaging", false); + const packaging: string | undefined = tl.getInput("packaging", true); const classifier: string | undefined = tl.getInput("classifier", false); const extension: string | undefined = tl.getInput("extension", false); const downloadPath: string | undefined = tl.getInput("downloadPath", false); @@ -89,15 +86,7 @@ async function run() { } tl.debug(`HostUri set to '${hostUri}'`); - - if(packaging) - { - console.log(`Using Packaging ${packaging}.`); - } - else - { - console.log('Packaging has not been supplied.'); - } + console.log(`Using Packaging ${packaging}.`); if(extension) { @@ -120,12 +109,12 @@ async function run() { // Do we have packaging and extension? if not lets download all files. // https://help.sonatype.com/repomanager3/repository-manager-concepts/components%2C-repositories%2C-and-repository-formats if(!extension) - { - await downloadAssets(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, classifier, packaging); + { + await nexus.downloadAssets(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, packaging, classifier); } else { - await downloadAsset(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extension, classifier, packaging); + await nexus.downloadAsset(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extension, packaging, classifier); } } catch (err) { @@ -134,144 +123,5 @@ async function run() { console.log(`Downloading artifact completed.`); } -async function downloadAsset(nexusUrl: string, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean, repository : string, group : string, artifact : string, baseVersion : string, extension : string, classifier? : string, packaging? : string) : Promise { - // Build the final download uri - // https://support.sonatype.com/hc/en-us/articles/213465488 - // https://repository.sonatype.org/nexus-restlet1x-plugin/default/docs/path__artifact_maven_redirect.html - let hostUri = new URL(nexusUrl); - let requestPath : string = `/service/local/artifact/maven/redirect`; - - // Handle root path - if(hostUri.pathname !== "/") - { - requestPath = path.join(hostUri.pathname, requestPath); - } - hostUri.pathname = requestPath; - - // Query Parameters - hostUri.searchParams.append("r", repository); - hostUri.searchParams.append("g", group); - hostUri.searchParams.append("a", artifact); - hostUri.searchParams.append("v", baseVersion); - - if(packaging) - { - hostUri.searchParams.append("p", packaging); - } - - // Do we have a extension - if (extension) { - hostUri.searchParams.append("e", extension); - } - - // Do we have a classifier - if (classifier) { - hostUri.searchParams.append("c", classifier); - } - - console.log(`Download asset using '${hostUri}'.`); - // Execute the request - await executeRequest(hostUri, auth, acceptUntrustedCerts); - console.log(`Completed download asset using '${hostUri}'.`); -} - -async function downloadAssets(nexusUrl: string, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean, repository : string, group : string, artifact : string, baseVersion : string, classifier? : string, packaging? : string) : Promise { - // Build the final search uri - // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/path__lucene_search.html - // https://nexusrepov2vm1.azure-zone.net:8443/nexus/service/local/lucene/search?repositoryId=releases&g=org.apache.maven&a=maven-artifact&v=3.6.3 - // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/el_ns0_searchNGResponse.html - // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/ns0.xsd - let hostUri = new URL(nexusUrl); - let lucenePath : string = `/service/local/lucene/search`; - - // Handle root path - if(hostUri.pathname !== "/") - { - lucenePath = path.join(hostUri.pathname, lucenePath); - } - hostUri.pathname = lucenePath; - // Query Parameters - hostUri.searchParams.append("repositoryId", repository); - hostUri.searchParams.append("g", group); - hostUri.searchParams.append("a", artifact); - hostUri.searchParams.append("v", baseVersion); - // Do we have a classifier - if (classifier) { - hostUri.searchParams.append("c", classifier); - } - if(packaging) - { - hostUri.searchParams.append("p", packaging); - } - console.log(`Search for asset using '${hostUri}'.`); - - // perform lucene Search - var responseContent = await executeRequest(hostUri, auth, acceptUntrustedCerts); - tl.debug(`Response Content '${responseContent}'.`); - var extensions : string[] = await parseExtensions(responseContent); - - // Download each asset - for(var extension in extensions){ - await downloadAsset(nexusUrl, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extensions[extension], classifier); - } - - console.log(`Completed search for asset using '${hostUri}'.`); -} - -async function parseExtensions(xml: string) : Promise { - return new Promise((resolve, reject) => { - xml2js.parseString(xml, { explicitArray : false }, function (err, result) { - if(err) - { - console.log(`Failed to parse response XML.`); - reject(err); - } - else - { - if(result.searchNGResponse.totalCount == 1) - { - resolve(xpath.find(result.searchNGResponse.data.artifact.artifactHits, "//extension")); - } - else - { - let message = `Search result XML contains multiple artifactHits.`; - console.log(message); - reject(message); - } - } - }); - }); -} - -async function executeRequest(hostUri: URL, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean) : Promise { - var responseContent: string; - try { - if (hostUri.protocol === "https:") { - if (auth.scheme === "UsernamePassword") { - responseContent = await nexus.execute_https(hostUri, acceptUntrustedCerts, auth.parameters["username"], auth.parameters["password"]); - } - - else { - responseContent = await nexus.execute_https(hostUri, acceptUntrustedCerts); - } - } - - else { - if (auth.scheme === "UsernamePassword") { - responseContent = await nexus.execute_http(hostUri, auth.parameters["username"], auth.parameters["password"]); - } - - else { - responseContent = await nexus.execute_http(hostUri); - } - } - } catch (inner_err) { - console.log(`Failed to execute request '${hostUri}'.`); - throw inner_err; - } - return responseContent; -} - - run(); diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/package-lock.json b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/package-lock.json index b7139ef..eb91cfe 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/package-lock.json +++ b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/package-lock.json @@ -252,11 +252,6 @@ "esprima": "^4.0.0" } }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -363,11 +358,6 @@ "path-parse": "^1.0.6" } }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -513,28 +503,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xml2js-xpath": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/xml2js-xpath/-/xml2js-xpath-0.11.0.tgz", - "integrity": "sha512-LJJWN9VcZUItBb3R3NmaWuE7+mZzhwGfo9vqekDki02ZnnO7M5QHeqpT49XBfWxZlBuuYVXw3t8rjvekZY43Yg==", - "requires": { - "lodash": "^4.17.15" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" } } } diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/package.json b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/package.json index 44543ee..5a10088 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/package.json +++ b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/package.json @@ -9,9 +9,7 @@ "azure-pipelines-task-lib": "^2.9.3", "fs": "0.0.1-security", "path": "^0.12.7", - "shelljs": "^0.8.3", - "xml2js": "^0.4.23", - "xml2js-xpath": "^0.11.0" + "shelljs": "^0.8.3" }, "devDependencies": { "@types/node": "^12.12.15", diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/IhttpHelper.ts b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/IhttpHelper.ts deleted file mode 100644 index 9885bd2..0000000 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/IhttpHelper.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface IhttpHelper { - execute_http(searchUri : URL) : Promise; - execute_http(searchUri : URL, username? : string, password? : string) : Promise; - execute_https(searchUri : URL, acceptUntrustedCerts : boolean) : Promise; - execute_https(searchUri : URL, acceptUntrustedCerts : boolean, username? : string, password? : string) : Promise -}; \ No newline at end of file diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/httpHelper.ts b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/httpHelper.ts deleted file mode 100644 index 5efbfe2..0000000 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/httpHelper.ts +++ /dev/null @@ -1,138 +0,0 @@ -import tl = require('azure-pipelines-task-lib/task'); -import path = require("path"); -import fs = require('fs'); -import http = require('http'); -import https = require('https'); -import { IhttpHelper } from './IhttpHelper'; - -export class httpHelper implements IhttpHelper { - - public async execute_http(searchUri : URL) : Promise; - public async execute_http(searchUri : URL, username? : string, password? : string) : Promise - { - tl.debug(`execute_http.`); - - let options : http.RequestOptions = { - host: searchUri.hostname, - path: `${searchUri.pathname}?${searchUri.searchParams}`, - method: 'GET', - headers: { - 'Accept': 'application/json' - } - }; - - if(username && - password) - { - const authBase64 : string = Buffer.from(username + ':' + password).toString('base64'); - - // Make sure the secret is correctly scrubbed from any logs - tl.setSecret(authBase64); - options.headers['Authorization'] = 'Basic ' + authBase64; - } - - // Setup new agent dont use the global one - options.agent = new http.Agent(); - options.port = searchUri.port || options.defaultPort; - - // execute the http request - await this.execute_request(http, options); - } - - public async execute_https(searchUri : URL, acceptUntrustedCerts : boolean) : Promise; - public async execute_https(searchUri : URL, acceptUntrustedCerts : boolean, username? : string, password? : string) : Promise - { - tl.debug(`execute_https.`); - - let options : https.RequestOptions = { - host: searchUri.hostname, - path: `${searchUri.pathname}?${searchUri.searchParams}`, - method: 'GET', - rejectUnauthorized: !acceptUntrustedCerts, // By default ensure we validate SSL certificates - headers: { - 'Accept': 'application/json' - } - }; - - if(username && - password) - { - const authBase64 : string = Buffer.from(username + ':' + password).toString('base64'); - - // Make sure the secret is correctly scrubbed from any logs - tl.setSecret(authBase64); - options.headers['Authorization'] = 'Basic ' + authBase64; - } - - // Setup new agent dont use the global one - options.agent = new https.Agent(); - options.port = searchUri.port || options.defaultPort; - - // execute the https request - await this.execute_request(https, options); - } - - private async execute_request(client : any, options : http.RequestOptions | https.RequestOptions) : Promise - { - tl.debug(`HTTP Request Options: ${JSON.stringify(options)}.`); - - return new Promise((resolve, reject) => { - let req : http.ClientRequest = client.request(options, function(res : http.IncomingMessage) { - tl.debug(`HTTP Response Status Code: ${res.statusCode}.`); - tl.debug(`HTTP Response Status Message: ${res.statusMessage}.`); - tl.debug(`HTTP Response Headers: ${JSON.stringify(res.headers)}.`); - - if (res.statusCode == 302) { - const downloadUri : URL = new URL(res.headers.location); - - // Set correct options for the new request to download our file - options.host = downloadUri.hostname; - options.path = downloadUri.pathname; - options.port = downloadUri.port || options.defaultPort; - - console.log(`Download asset using '${downloadUri}'.`); - let filename : string = path.basename(downloadUri.pathname); - console.log(`Download filename '${filename}'`); - - let inner_req : http.ClientRequest = client.request(options, function(inner_res : http.IncomingMessage) { - tl.debug(`HTTP Response Status Code: ${inner_res.statusCode}.`); - tl.debug(`HTTP Response Status Message: ${inner_res.statusMessage}.`); - tl.debug(`HTTP Response Headers: ${JSON.stringify(inner_res.headers)}.`); - - if(inner_res.statusCode == 200) - { - const file : fs.WriteStream = fs.createWriteStream(filename); - inner_res.on('data', function(chunk : any){ - file.write(chunk); - }).on('end', function(){ - file.end(); - }); - console.log(`##vso[task.setvariable variable=MAVEN_REPOSITORY_ASSET_FILENAME;isSecret=false;isOutput=true;]${filename}`) - console.log(`Successfully downloaded asset '${filename}' using '${downloadUri}'.`); - resolve(); - } else - { - console.log(`Asset download was not successful!`); - reject(`Asset download was not successful!`); - } - }); - inner_req.end(); - }else - { - tl.debug(`Asset search was not successful!`); - let message : string = `Asset search was not successful!`; - if (res.statusCode == 400) { - message = `Search returned multiple assets, please refine search criteria to find a single asset!`; - } else if (res.statusCode == 401) { - message = `Invalid Nexus Repo Manager credentials!`; - } else if (res.statusCode == 404) { - message = `Asset does not exist for search, or invalid Nexus Repo Manager Url!`; - } - console.log(message); - reject(message); - } - }); - req.end(); - }); - } -} \ No newline at end of file diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/index.ts b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/index.ts index 464fb1a..91c5077 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/index.ts +++ b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3/index.ts @@ -2,9 +2,8 @@ import tl = require('azure-pipelines-task-lib/task'); import shell = require("shelljs"); import path = require("path"); import fs = require('fs'); -import { IhttpHelper } from './IhttpHelper'; -import { httpHelper } from './httpHelper'; -const nexus : IhttpHelper = new httpHelper(); +import n = require('nexus-v3'); +const nexus = new n.nexus(); async function run() { console.log(`Downloading artifact.`); @@ -93,71 +92,37 @@ async function run() { } tl.debug(`HostUri set to '${hostUri}'`); - // https://help.sonatype.com/repomanager3/rest-and-integration-api/search-api - // Build the final search uri - let requestPath : string = `/service/rest/v1/search/assets/download`; - // Handle root path - if(hostUri.pathname !== "/") + console.log(`Using Packaging ${packaging}.`); + + if(extension) { - requestPath = path.join(hostUri.pathname, requestPath); + console.log(`Using extension ${extension}.`); + } + else + { + console.log('Extension has not been supplied.'); } - hostUri.pathname = requestPath; - // Query Parameters - - // *** ONLY Works in Nexus 3.16+ *** - // https://help.sonatype.com/repomanager3/rest-and-integration-api/search-api#SearchAPI-DownloadingtheLatestVersionofanAsset - // We could use /service/rest/v1/status and look at the response header "server: Nexus/3.21.1-01 (OSS)" - // hostUri.searchParams.append("sort", "version"); - // *** ONLY Works in Nexus 3.16+ *** - - hostUri.searchParams.append("repository", repository); - hostUri.searchParams.append("maven.groupId", group); - hostUri.searchParams.append("maven.artifactId", artifact); - hostUri.searchParams.append("maven.baseVersion", baseVersion); - hostUri.searchParams.append("maven.extension", extension); - hostUri.searchParams.append("maven.classifier", ""); - - // Do we have a classifier - if (classifier) { + if (classifier) + { console.log(`Using classifier ${classifier}.`); - hostUri.searchParams.set("maven.classifier",classifier); } else { console.log('Classifier has not been supplied.'); } - - console.log(`Search for asset using '${hostUri}'.`); - try { - // need to refactor this logic to reduce duplication of code - if (hostUri.protocol === "https:") { - if(auth.scheme === "UsernamePassword") - { - await nexus.execute_https(hostUri, acceptUntrustedCerts, auth.parameters["username"], auth.parameters["password"]); - } - else - { - await nexus.execute_https(hostUri, acceptUntrustedCerts); - } - } - else - { - if(auth.scheme === "UsernamePassword") - { - await nexus.execute_http(hostUri, auth.parameters["username"], auth.parameters["password"]); - } - else - { - await nexus.execute_http(hostUri); - } - } - console.log(`Completed search for asset using '${hostUri}'.`); - } catch (inner_err) { - console.log(`Could not complete search for asset using '${hostUri}'.`); - throw inner_err; - } + + // Do we have packaging and extension? if not lets download all files. + // https://help.sonatype.com/repomanager3/repository-manager-concepts/components%2C-repositories%2C-and-repository-formats + // if(!extension) + // { + // await nexus.downloadAssets(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, packaging, classifier); + // } + // else + // { + await nexus.downloadAsset(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extension, packaging, classifier); + // } } catch (err) { diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/index.ts b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/index.ts index f82b3ef..b236698 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/index.ts +++ b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/index.ts @@ -2,11 +2,8 @@ import tl = require('azure-pipelines-task-lib/task'); import shell = require("shelljs"); import path = require("path"); import fs = require('fs'); -import * as xml2js from 'xml2js'; -import * as xpath from "xml2js-xpath"; -import { IhttpHelper } from './IhttpHelper'; -import { httpHelper } from './httpHelper'; -const nexus : IhttpHelper = new httpHelper(); +import n = require('nexus-v2'); +const nexus = new n.nexus(); async function run() { console.log(`Downloading artifact.`); @@ -121,11 +118,11 @@ async function run() { // https://help.sonatype.com/repomanager3/repository-manager-concepts/components%2C-repositories%2C-and-repository-formats if(!extension) { - await downloadAssets(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, classifier, packaging); + await nexus.downloadAssets(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, classifier, packaging); } else { - await downloadAsset(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extension, classifier, packaging); + await nexus.downloadAsset(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extension, classifier, packaging); } } catch (err) { @@ -134,142 +131,4 @@ async function run() { console.log(`Downloading artifact completed.`); } -async function downloadAsset(nexusUrl: string, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean, repository : string, group : string, artifact : string, baseVersion : string, extension : string, classifier? : string, packaging? : string) : Promise { - // Build the final download uri - // https://support.sonatype.com/hc/en-us/articles/213465488 - // https://repository.sonatype.org/nexus-restlet1x-plugin/default/docs/path__artifact_maven_redirect.html - let hostUri = new URL(nexusUrl); - let requestPath : string = `/service/local/artifact/maven/redirect`; - - // Handle root path - if(hostUri.pathname !== "/") - { - requestPath = path.join(hostUri.pathname, requestPath); - } - hostUri.pathname = requestPath; - - // Query Parameters - hostUri.searchParams.append("r", repository); - hostUri.searchParams.append("g", group); - hostUri.searchParams.append("a", artifact); - hostUri.searchParams.append("v", baseVersion); - - if(packaging) - { - hostUri.searchParams.append("p", packaging); - } - - // Do we have a extension - if (extension) { - hostUri.searchParams.append("e", extension); - } - - // Do we have a classifier - if (classifier) { - hostUri.searchParams.append("c", classifier); - } - - console.log(`Download asset using '${hostUri}'.`); - // Execute the request - await executeRequest(hostUri, auth, acceptUntrustedCerts); - console.log(`Completed download asset using '${hostUri}'.`); -} - -async function downloadAssets(nexusUrl: string, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean, repository : string, group : string, artifact : string, baseVersion : string, classifier? : string, packaging? : string) : Promise { - // Build the final search uri - // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/path__lucene_search.html - // https://nexusrepov2vm1.azure-zone.net:8443/nexus/service/local/lucene/search?repositoryId=releases&g=org.apache.maven&a=maven-artifact&v=3.6.3 - // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/el_ns0_searchNGResponse.html - // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/ns0.xsd - let hostUri = new URL(nexusUrl); - let lucenePath : string = `/service/local/lucene/search`; - - // Handle root path - if(hostUri.pathname !== "/") - { - lucenePath = path.join(hostUri.pathname, lucenePath); - } - hostUri.pathname = lucenePath; - // Query Parameters - hostUri.searchParams.append("repositoryId", repository); - hostUri.searchParams.append("g", group); - hostUri.searchParams.append("a", artifact); - hostUri.searchParams.append("v", baseVersion); - // Do we have a classifier - if (classifier) { - hostUri.searchParams.append("c", classifier); - } - if(packaging) - { - hostUri.searchParams.append("p", packaging); - } - console.log(`Search for asset using '${hostUri}'.`); - - // perform lucene Search - var responseContent = await executeRequest(hostUri, auth, acceptUntrustedCerts); - tl.debug(`Response Content '${responseContent}'.`); - var extensions : string[] = await parseExtensions(responseContent); - - // Download each asset - for(var extension in extensions){ - await downloadAsset(nexusUrl, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extensions[extension], classifier); - } - - console.log(`Completed search for asset using '${hostUri}'.`); -} - -async function parseExtensions(xml: string) : Promise { - return new Promise((resolve, reject) => { - xml2js.parseString(xml, { explicitArray : false }, function (err, result) { - if(err) - { - console.log(`Failed to parse response XML.`); - reject(err); - } - else - { - if(result.searchNGResponse.totalCount == 1) - { - resolve(xpath.find(result.searchNGResponse.data.artifact.artifactHits, "//extension")); - } - else - { - let message = `Search result XML contains multiple artifactHits.`; - console.log(message); - reject(message); - } - } - }); - }); -} - -async function executeRequest(hostUri: URL, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean) : Promise { - var responseContent: string; - try { - if (hostUri.protocol === "https:") { - if (auth.scheme === "UsernamePassword") { - responseContent = await nexus.execute_https(hostUri, acceptUntrustedCerts, auth.parameters["username"], auth.parameters["password"]); - } - - else { - responseContent = await nexus.execute_https(hostUri, acceptUntrustedCerts); - } - } - - else { - if (auth.scheme === "UsernamePassword") { - responseContent = await nexus.execute_http(hostUri, auth.parameters["username"], auth.parameters["password"]); - } - - else { - responseContent = await nexus.execute_http(hostUri); - } - } - } catch (inner_err) { - console.log(`Failed to execute request '${hostUri}'.`); - throw inner_err; - } - return responseContent; -} - run(); diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/package-lock.json b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/package-lock.json index f19b26e..b7139ef 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/package-lock.json +++ b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/package-lock.json @@ -252,6 +252,11 @@ "esprima": "^4.0.0" } }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -518,6 +523,14 @@ "xmlbuilder": "~11.0.0" } }, + "xml2js-xpath": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/xml2js-xpath/-/xml2js-xpath-0.11.0.tgz", + "integrity": "sha512-LJJWN9VcZUItBb3R3NmaWuE7+mZzhwGfo9vqekDki02ZnnO7M5QHeqpT49XBfWxZlBuuYVXw3t8rjvekZY43Yg==", + "requires": { + "lodash": "^4.17.15" + } + }, "xmlbuilder": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/IhttpHelper.ts b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/IhttpHelper.ts deleted file mode 100644 index 9885bd2..0000000 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/IhttpHelper.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface IhttpHelper { - execute_http(searchUri : URL) : Promise; - execute_http(searchUri : URL, username? : string, password? : string) : Promise; - execute_https(searchUri : URL, acceptUntrustedCerts : boolean) : Promise; - execute_https(searchUri : URL, acceptUntrustedCerts : boolean, username? : string, password? : string) : Promise -}; \ No newline at end of file diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/httpHelper.ts b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/httpHelper.ts deleted file mode 100644 index 5efbfe2..0000000 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/httpHelper.ts +++ /dev/null @@ -1,138 +0,0 @@ -import tl = require('azure-pipelines-task-lib/task'); -import path = require("path"); -import fs = require('fs'); -import http = require('http'); -import https = require('https'); -import { IhttpHelper } from './IhttpHelper'; - -export class httpHelper implements IhttpHelper { - - public async execute_http(searchUri : URL) : Promise; - public async execute_http(searchUri : URL, username? : string, password? : string) : Promise - { - tl.debug(`execute_http.`); - - let options : http.RequestOptions = { - host: searchUri.hostname, - path: `${searchUri.pathname}?${searchUri.searchParams}`, - method: 'GET', - headers: { - 'Accept': 'application/json' - } - }; - - if(username && - password) - { - const authBase64 : string = Buffer.from(username + ':' + password).toString('base64'); - - // Make sure the secret is correctly scrubbed from any logs - tl.setSecret(authBase64); - options.headers['Authorization'] = 'Basic ' + authBase64; - } - - // Setup new agent dont use the global one - options.agent = new http.Agent(); - options.port = searchUri.port || options.defaultPort; - - // execute the http request - await this.execute_request(http, options); - } - - public async execute_https(searchUri : URL, acceptUntrustedCerts : boolean) : Promise; - public async execute_https(searchUri : URL, acceptUntrustedCerts : boolean, username? : string, password? : string) : Promise - { - tl.debug(`execute_https.`); - - let options : https.RequestOptions = { - host: searchUri.hostname, - path: `${searchUri.pathname}?${searchUri.searchParams}`, - method: 'GET', - rejectUnauthorized: !acceptUntrustedCerts, // By default ensure we validate SSL certificates - headers: { - 'Accept': 'application/json' - } - }; - - if(username && - password) - { - const authBase64 : string = Buffer.from(username + ':' + password).toString('base64'); - - // Make sure the secret is correctly scrubbed from any logs - tl.setSecret(authBase64); - options.headers['Authorization'] = 'Basic ' + authBase64; - } - - // Setup new agent dont use the global one - options.agent = new https.Agent(); - options.port = searchUri.port || options.defaultPort; - - // execute the https request - await this.execute_request(https, options); - } - - private async execute_request(client : any, options : http.RequestOptions | https.RequestOptions) : Promise - { - tl.debug(`HTTP Request Options: ${JSON.stringify(options)}.`); - - return new Promise((resolve, reject) => { - let req : http.ClientRequest = client.request(options, function(res : http.IncomingMessage) { - tl.debug(`HTTP Response Status Code: ${res.statusCode}.`); - tl.debug(`HTTP Response Status Message: ${res.statusMessage}.`); - tl.debug(`HTTP Response Headers: ${JSON.stringify(res.headers)}.`); - - if (res.statusCode == 302) { - const downloadUri : URL = new URL(res.headers.location); - - // Set correct options for the new request to download our file - options.host = downloadUri.hostname; - options.path = downloadUri.pathname; - options.port = downloadUri.port || options.defaultPort; - - console.log(`Download asset using '${downloadUri}'.`); - let filename : string = path.basename(downloadUri.pathname); - console.log(`Download filename '${filename}'`); - - let inner_req : http.ClientRequest = client.request(options, function(inner_res : http.IncomingMessage) { - tl.debug(`HTTP Response Status Code: ${inner_res.statusCode}.`); - tl.debug(`HTTP Response Status Message: ${inner_res.statusMessage}.`); - tl.debug(`HTTP Response Headers: ${JSON.stringify(inner_res.headers)}.`); - - if(inner_res.statusCode == 200) - { - const file : fs.WriteStream = fs.createWriteStream(filename); - inner_res.on('data', function(chunk : any){ - file.write(chunk); - }).on('end', function(){ - file.end(); - }); - console.log(`##vso[task.setvariable variable=MAVEN_REPOSITORY_ASSET_FILENAME;isSecret=false;isOutput=true;]${filename}`) - console.log(`Successfully downloaded asset '${filename}' using '${downloadUri}'.`); - resolve(); - } else - { - console.log(`Asset download was not successful!`); - reject(`Asset download was not successful!`); - } - }); - inner_req.end(); - }else - { - tl.debug(`Asset search was not successful!`); - let message : string = `Asset search was not successful!`; - if (res.statusCode == 400) { - message = `Search returned multiple assets, please refine search criteria to find a single asset!`; - } else if (res.statusCode == 401) { - message = `Invalid Nexus Repo Manager credentials!`; - } else if (res.statusCode == 404) { - message = `Asset does not exist for search, or invalid Nexus Repo Manager Url!`; - } - console.log(message); - reject(message); - } - }); - req.end(); - }); - } -} \ No newline at end of file diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/index.ts b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/index.ts index e9b38af..24dd64e 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/index.ts +++ b/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3/index.ts @@ -2,9 +2,8 @@ import tl = require('azure-pipelines-task-lib/task'); import shell = require("shelljs"); import path = require("path"); import fs = require('fs'); -import { IhttpHelper } from './IhttpHelper'; -import { httpHelper } from './httpHelper'; -const nexus : IhttpHelper = new httpHelper(); +import n = require('nexus-v3'); +const nexus = new n.nexus(); async function run() { console.log(`Downloading artifact.`); @@ -93,71 +92,37 @@ async function run() { } tl.debug(`HostUri set to '${hostUri}'`); - // https://help.sonatype.com/repomanager3/rest-and-integration-api/search-api - // Build the final search uri - let requestPath : string = `/service/rest/v1/search/assets/download`; - // Handle root path - if(hostUri.pathname !== "/") + console.log(`Using Packaging ${packaging}.`); + + if(extension) { - requestPath = path.join(hostUri.pathname, requestPath); + console.log(`Using extension ${extension}.`); + } + else + { + console.log('Extension has not been supplied.'); } - hostUri.pathname = requestPath; - // Query Parameters - - // *** ONLY Works in Nexus 3.16+ *** - // https://help.sonatype.com/repomanager3/rest-and-integration-api/search-api#SearchAPI-DownloadingtheLatestVersionofanAsset - // We could use /service/rest/v1/status and look at the response header "server: Nexus/3.21.1-01 (OSS)" - // hostUri.searchParams.append("sort", "version"); - // *** ONLY Works in Nexus 3.16+ *** - - hostUri.searchParams.append("repository", repository); - hostUri.searchParams.append("maven.groupId", group); - hostUri.searchParams.append("maven.artifactId", artifact); - hostUri.searchParams.append("maven.baseVersion", baseVersion); - hostUri.searchParams.append("maven.extension", extension); - hostUri.searchParams.append("maven.classifier", ""); - - // Do we have a classifier - if (classifier) { + if (classifier) + { console.log(`Using classifier ${classifier}.`); - hostUri.searchParams.set("maven.classifier",classifier); } else { console.log('Classifier has not been supplied.'); } - - console.log(`Search for asset using '${hostUri}'.`); - try { - // need to refactor this logic to reduce duplication of code - if (hostUri.protocol === "https:") { - if(auth.scheme === "UsernamePassword") - { - await nexus.execute_https(hostUri, acceptUntrustedCerts, auth.parameters["username"], auth.parameters["password"]); - } - else - { - await nexus.execute_https(hostUri, acceptUntrustedCerts); - } - } - else - { - if(auth.scheme === "UsernamePassword") - { - await nexus.execute_http(hostUri, auth.parameters["username"], auth.parameters["password"]); - } - else - { - await nexus.execute_http(hostUri); - } - } - console.log(`Completed search for asset using '${hostUri}'.`); - } catch (inner_err) { - console.log(`Could not complete search for asset using '${hostUri}'.`); - throw inner_err; - } + + // Do we have packaging and extension? if not lets download all files. + // https://help.sonatype.com/repomanager3/repository-manager-concepts/components%2C-repositories%2C-and-repository-formats + // if(!extension) + // { + // await nexus.downloadAssets(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, packaging, classifier); + // } + // else + // { + await nexus.downloadAsset(hostUri.href, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extension, packaging, classifier); + // } } catch (err) { diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/IhttpHelper.ts b/libs/nexus-v2/IhttpHelper.ts similarity index 83% rename from Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/IhttpHelper.ts rename to libs/nexus-v2/IhttpHelper.ts index a0f2bc4..c4d0da8 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/IhttpHelper.ts +++ b/libs/nexus-v2/IhttpHelper.ts @@ -2,5 +2,5 @@ export interface IhttpHelper { execute_http(searchUri : URL) : Promise; execute_http(searchUri : URL, username? : string, password? : string) : Promise; execute_https(searchUri : URL, acceptUntrustedCerts : boolean) : Promise; - execute_https(searchUri : URL, acceptUntrustedCerts : boolean, username? : string, password? : string) : Promise + execute_https(searchUri : URL, acceptUntrustedCerts : boolean, username? : string, password? : string) : Promise; }; \ No newline at end of file diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/httpHelper.ts b/libs/nexus-v2/httpHelper.ts similarity index 100% rename from Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2/httpHelper.ts rename to libs/nexus-v2/httpHelper.ts diff --git a/libs/nexus-v2/nexus.ts b/libs/nexus-v2/nexus.ts new file mode 100644 index 0000000..c528161 --- /dev/null +++ b/libs/nexus-v2/nexus.ts @@ -0,0 +1,143 @@ +import tl = require('azure-pipelines-task-lib/task'); +import path = require("path"); +import * as xml2js from 'xml2js'; +import * as xpath from "xml2js-xpath"; +import { IhttpHelper } from './IhttpHelper'; +import { httpHelper } from './httpHelper'; +const helper : IhttpHelper = new httpHelper(); + + +export class nexus { + + public async downloadAsset(nexusUrl: string, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean, repository : string, group : string, artifact : string, baseVersion : string, extension : string, packaging : string, classifier? : string) : Promise { + // Build the final download uri + // https://support.sonatype.com/hc/en-us/articles/213465488 + // https://repository.sonatype.org/nexus-restlet1x-plugin/default/docs/path__artifact_maven_redirect.html + let hostUri = new URL(nexusUrl); + let requestPath : string = `/service/local/artifact/maven/redirect`; + + // Handle root path + if(hostUri.pathname !== "/") + { + requestPath = path.join(hostUri.pathname, requestPath); + } + hostUri.pathname = requestPath; + + // Query Parameters + hostUri.searchParams.append("r", repository); + hostUri.searchParams.append("g", group); + hostUri.searchParams.append("a", artifact); + hostUri.searchParams.append("v", baseVersion); + hostUri.searchParams.append("p", packaging); + + // Do we have a extension + if (extension) { + hostUri.searchParams.append("e", extension); + } + + // Do we have a classifier + if (classifier) { + hostUri.searchParams.append("c", classifier); + } + + console.log(`Download asset using '${hostUri}'.`); + // Execute the request + await this.executeRequest(hostUri, auth, acceptUntrustedCerts); + console.log(`Completed download asset using '${hostUri}'.`); + } + + public async downloadAssets(nexusUrl: string, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean, repository : string, group : string, artifact : string, baseVersion : string, packaging : string, classifier? : string) : Promise { + // Build the final search uri + // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/path__lucene_search.html + // https://nexusrepov2vm1.azure-zone.net:8443/nexus/service/local/lucene/search?repositoryId=releases&g=org.apache.maven&a=maven-artifact&v=3.6.3 + // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/el_ns0_searchNGResponse.html + // https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/ns0.xsd + let hostUri = new URL(nexusUrl); + let lucenePath : string = `/service/local/lucene/search`; + + // Handle root path + if(hostUri.pathname !== "/") + { + lucenePath = path.join(hostUri.pathname, lucenePath); + } + hostUri.pathname = lucenePath; + // Query Parameters + hostUri.searchParams.append("repositoryId", repository); + hostUri.searchParams.append("g", group); + hostUri.searchParams.append("a", artifact); + hostUri.searchParams.append("v", baseVersion); + hostUri.searchParams.append("p", packaging); + + // Do we have a classifier + if (classifier) { + hostUri.searchParams.append("c", classifier); + } + console.log(`Search for asset using '${hostUri}'.`); + + // perform lucene Search + var responseContent = await this.executeRequest(hostUri, auth, acceptUntrustedCerts); + tl.debug(`Response Content '${responseContent}'.`); + var extensions : string[] = await this.parseExtensions(responseContent); + + // Download each asset + for(var extension in extensions){ + await this.downloadAsset(nexusUrl, auth, acceptUntrustedCerts, repository, group, artifact, baseVersion, extensions[extension], classifier); + } + + console.log(`Completed search for asset using '${hostUri}'.`); + } + + private async parseExtensions(xml: string) : Promise { + return new Promise((resolve, reject) => { + xml2js.parseString(xml, { explicitArray : false }, function (err, result) { + if(err) + { + console.log(`Failed to parse response XML.`); + reject(err); + } + else + { + if(result.searchNGResponse.totalCount == 1) + { + resolve(xpath.find(result.searchNGResponse.data.artifact.artifactHits, "//extension")); + } + else + { + let message = `Search result XML contains multiple artifactHits.`; + console.log(message); + reject(message); + } + } + }); + }); + } + + private async executeRequest(hostUri: URL, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean) : Promise { + var responseContent: string; + try { + if (hostUri.protocol === "https:") { + if (auth.scheme === "UsernamePassword") { + responseContent = await helper.execute_https(hostUri, acceptUntrustedCerts, auth.parameters["username"], auth.parameters["password"]); + } + + else { + responseContent = await helper.execute_https(hostUri, acceptUntrustedCerts); + } + } + + else { + if (auth.scheme === "UsernamePassword") { + responseContent = await helper.execute_http(hostUri, auth.parameters["username"], auth.parameters["password"]); + } + + else { + responseContent = await helper.execute_http(hostUri); + } + } + } catch (inner_err) { + console.log(`Failed to execute request '${hostUri}'.`); + throw inner_err; + } + return responseContent; + } +} \ No newline at end of file diff --git a/libs/nexus-v2/package-lock.json b/libs/nexus-v2/package-lock.json new file mode 100644 index 0000000..4b1c354 --- /dev/null +++ b/libs/nexus-v2/package-lock.json @@ -0,0 +1,641 @@ +{ + "name": "nexus-v2", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "12.12.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", + "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", + "dev": true + }, + "@types/shelljs": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.8.tgz", + "integrity": "sha512-lD3LWdg6j8r0VRBFahJVaxoW0SIcswxKaFUrmKl33RJVeeoNYQAz4uqCJ5Z6v4oIBOsC5GozX+I5SorIKiTcQA==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "azure-pipelines-task-lib": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.10.0.tgz", + "integrity": "sha512-nmwf4ReXGfaBDMRO08/KSDOqbieJFljQSXd6bSFl28QsOKiGy5qz1O7pMnb9UqYfH5Fbro0zU4Q88hpO0XkFHg==", + "requires": { + "minimatch": "3.0.4", + "mockery": "^1.7.0", + "q": "^1.1.2", + "semver": "^5.1.0", + "shelljs": "^0.3.0", + "sync-request": "3.0.1", + "uuid": "^3.0.1" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "http-basic": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz", + "integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=", + "requires": { + "caseless": "~0.11.0", + "concat-stream": "^1.4.6", + "http-response-object": "^1.0.0" + } + }, + "http-response-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz", + "integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mock-require": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz", + "integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==", + "dev": true, + "requires": { + "get-caller-file": "^1.0.2", + "normalize-path": "^2.1.1" + } + }, + "mockery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz", + "integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8=" + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "sync-request": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz", + "integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=", + "requires": { + "concat-stream": "^1.4.7", + "http-response-object": "^1.0.1", + "then-request": "^2.0.1" + } + }, + "then-request": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz", + "integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=", + "requires": { + "caseless": "~0.11.0", + "concat-stream": "^1.4.7", + "http-basic": "^2.5.1", + "http-response-object": "^1.1.0", + "promise": "^7.1.1", + "qs": "^6.1.0" + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "typescript-tslint-plugin": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/typescript-tslint-plugin/-/typescript-tslint-plugin-0.5.5.tgz", + "integrity": "sha512-tR5igNQP+6FhxaPJYRlUBVsEl0n5cSuXRbg7L1y80mL4B1jUHb8uiIcbQBJ9zWyypJEdFYFUccpXxvMwZR8+AA==", + "dev": true, + "requires": { + "minimatch": "^3.0.4", + "mock-require": "^3.0.3", + "vscode-languageserver": "^5.2.1" + } + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "vscode-jsonrpc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", + "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==", + "dev": true + }, + "vscode-languageserver": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.2.1.tgz", + "integrity": "sha512-GuayqdKZqAwwaCUjDvMTAVRPJOp/SLON3mJ07eGsx/Iq9HjRymhKWztX41rISqDKhHVVyFM+IywICyZDla6U3A==", + "dev": true, + "requires": { + "vscode-languageserver-protocol": "3.14.1", + "vscode-uri": "^1.0.6" + } + }, + "vscode-languageserver-protocol": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz", + "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==", + "dev": true, + "requires": { + "vscode-jsonrpc": "^4.0.0", + "vscode-languageserver-types": "3.14.0" + } + }, + "vscode-languageserver-types": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", + "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==", + "dev": true + }, + "vscode-uri": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz", + "integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xml2js-xpath": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/xml2js-xpath/-/xml2js-xpath-0.11.0.tgz", + "integrity": "sha512-LJJWN9VcZUItBb3R3NmaWuE7+mZzhwGfo9vqekDki02ZnnO7M5QHeqpT49XBfWxZlBuuYVXw3t8rjvekZY43Yg==", + "requires": { + "lodash": "^4.17.15" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + } + } +} diff --git a/libs/nexus-v2/package.json b/libs/nexus-v2/package.json new file mode 100644 index 0000000..c9324c9 --- /dev/null +++ b/libs/nexus-v2/package.json @@ -0,0 +1,24 @@ +{ + "name": "nexus-v2", + "version": "1.0.0", + "description": "", + "main": "dist/nexus.js", + "author": "Gareth Emslie", + "license": "MIT", + "dependencies": { + "azure-pipelines-task-lib": "^2.9.3", + "path": "^0.12.7", + "xml2js": "^0.4.23", + "xml2js-xpath": "^0.11.0" + }, + "devDependencies": { + "@types/node": "^12.12.15", + "@types/shelljs": "^0.8.6", + "tslint": "^6.1.0", + "typescript": "^3.8.3", + "typescript-tslint-plugin": "^0.5.5" + }, + "scripts": { + "build": "tsc" + } +} diff --git a/libs/nexus-v2/tsconfig.json b/libs/nexus-v2/tsconfig.json new file mode 100644 index 0000000..2a49675 --- /dev/null +++ b/libs/nexus-v2/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "dist", + "rootDir": ".", + "sourceMap": true, + "strict": false, + "declaration": false, + "plugins": [ + { + "name": "typescript-tslint-plugin" + } + ] + }, + "include": [ + "**/*" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/IhttpHelper.ts b/libs/nexus-v3/IhttpHelper.ts similarity index 83% rename from Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/IhttpHelper.ts rename to libs/nexus-v3/IhttpHelper.ts index a0f2bc4..c4d0da8 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/IhttpHelper.ts +++ b/libs/nexus-v3/IhttpHelper.ts @@ -2,5 +2,5 @@ export interface IhttpHelper { execute_http(searchUri : URL) : Promise; execute_http(searchUri : URL, username? : string, password? : string) : Promise; execute_https(searchUri : URL, acceptUntrustedCerts : boolean) : Promise; - execute_https(searchUri : URL, acceptUntrustedCerts : boolean, username? : string, password? : string) : Promise + execute_https(searchUri : URL, acceptUntrustedCerts : boolean, username? : string, password? : string) : Promise; }; \ No newline at end of file diff --git a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/httpHelper.ts b/libs/nexus-v3/httpHelper.ts similarity index 94% rename from Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/httpHelper.ts rename to libs/nexus-v3/httpHelper.ts index 503584f..5092702 100644 --- a/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2/httpHelper.ts +++ b/libs/nexus-v3/httpHelper.ts @@ -16,7 +16,7 @@ export class httpHelper implements IhttpHelper { path: `${searchUri.pathname}?${searchUri.searchParams}`, method: 'GET', headers: { - 'Accept': 'application/xml' + 'Accept': 'application/json' } }; @@ -49,7 +49,7 @@ export class httpHelper implements IhttpHelper { method: 'GET', rejectUnauthorized: !acceptUntrustedCerts, // By default ensure we validate SSL certificates headers: { - 'Accept': 'application/xml' + 'Accept': 'application/json' } }; @@ -80,10 +80,10 @@ export class httpHelper implements IhttpHelper { tl.debug(`HTTP Response Status Code: ${res.statusCode}.`); tl.debug(`HTTP Response Status Message: ${res.statusMessage}.`); tl.debug(`HTTP Response Headers: ${JSON.stringify(res.headers)}.`); - - if (res.statusCode == 301 || res.statusCode == 307) { + + if (res.statusCode == 302) { const downloadUri : URL = new URL(res.headers.location); - + // Set correct options for the new request to download our file options.host = downloadUri.hostname; options.path = downloadUri.pathname; @@ -92,12 +92,12 @@ export class httpHelper implements IhttpHelper { console.log(`Download file using '${downloadUri}'.`); let filename : string = path.basename(downloadUri.pathname); console.log(`Download filename '${filename}'`); - + let inner_req : http.ClientRequest = client.request(options, function(inner_res : http.IncomingMessage) { tl.debug(`HTTP Response Status Code: ${inner_res.statusCode}.`); tl.debug(`HTTP Response Status Message: ${inner_res.statusMessage}.`); tl.debug(`HTTP Response Headers: ${JSON.stringify(inner_res.headers)}.`); - + if(inner_res.statusCode == 200) { const file : fs.WriteStream = fs.createWriteStream(filename); @@ -128,7 +128,9 @@ export class httpHelper implements IhttpHelper { { tl.debug(`Asset search was not successful!`); let message : string = `Asset search was not successful!`; - if (res.statusCode == 401) { + if (res.statusCode == 400) { + message = `Search returned multiple assets, please refine search criteria to find a single asset!`; + } else if (res.statusCode == 401) { message = `Invalid Nexus Repo Manager credentials!`; } else if (res.statusCode == 404) { message = `Asset does not exist for search, or invalid Nexus Repo Manager Url!`; diff --git a/libs/nexus-v3/nexus.ts b/libs/nexus-v3/nexus.ts new file mode 100644 index 0000000..bebfebb --- /dev/null +++ b/libs/nexus-v3/nexus.ts @@ -0,0 +1,80 @@ +import tl = require('azure-pipelines-task-lib/task'); +import path = require("path"); +import * as xml2js from 'xml2js'; +import * as xpath from "xml2js-xpath"; +import { IhttpHelper } from './IhttpHelper'; +import { httpHelper } from './httpHelper'; +const helper : IhttpHelper = new httpHelper(); + + +export class nexus { + + public async downloadAsset(nexusUrl: string, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean, repository : string, group : string, artifact : string, baseVersion : string, extension : string, packaging : string, classifier? : string) : Promise { + // Build the final download uri + let hostUri = new URL(nexusUrl); + // https://help.sonatype.com/repomanager3/rest-and-integration-api/search-api + // Build the final search uri + let requestPath : string = `/service/rest/v1/search/assets/download`; + + // Handle root path + if(hostUri.pathname !== "/") + { + requestPath = path.join(hostUri.pathname, requestPath); + } + hostUri.pathname = requestPath; + + // Query Parameters + + // *** ONLY Works in Nexus 3.16+ *** + // https://help.sonatype.com/repomanager3/rest-and-integration-api/search-api#SearchAPI-DownloadingtheLatestVersionofanAsset + // We could use /service/rest/v1/status and look at the response header "server: Nexus/3.21.1-01 (OSS)" + // hostUri.searchParams.append("sort", "version"); + // *** ONLY Works in Nexus 3.16+ *** + + hostUri.searchParams.append("repository", repository); + hostUri.searchParams.append("maven.groupId", group); + hostUri.searchParams.append("maven.artifactId", artifact); + hostUri.searchParams.append("maven.baseVersion", baseVersion); + hostUri.searchParams.append("maven.extension", extension); + hostUri.searchParams.append("maven.classifier", ""); + + // Do we have a classifier + if (classifier) { + hostUri.searchParams.set("maven.classifier",classifier); + } + + console.log(`Download asset using '${hostUri}'.`); + // Execute the request + await this.executeRequest(hostUri, auth, acceptUntrustedCerts); + console.log(`Completed download asset using '${hostUri}'.`); + } + + private async executeRequest(hostUri: URL, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean) : Promise { + var responseContent: string; + try { + if (hostUri.protocol === "https:") { + if (auth.scheme === "UsernamePassword") { + responseContent = await helper.execute_https(hostUri, acceptUntrustedCerts, auth.parameters["username"], auth.parameters["password"]); + } + + else { + responseContent = await helper.execute_https(hostUri, acceptUntrustedCerts); + } + } + + else { + if (auth.scheme === "UsernamePassword") { + responseContent = await helper.execute_http(hostUri, auth.parameters["username"], auth.parameters["password"]); + } + + else { + responseContent = await helper.execute_http(hostUri); + } + } + } catch (inner_err) { + console.log(`Failed to execute request '${hostUri}'.`); + throw inner_err; + } + return responseContent; + } +} \ No newline at end of file diff --git a/libs/nexus-v3/package-lock.json b/libs/nexus-v3/package-lock.json new file mode 100644 index 0000000..6b1430a --- /dev/null +++ b/libs/nexus-v3/package-lock.json @@ -0,0 +1,641 @@ +{ + "name": "nexus-v3", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "12.12.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", + "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", + "dev": true + }, + "@types/shelljs": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.8.tgz", + "integrity": "sha512-lD3LWdg6j8r0VRBFahJVaxoW0SIcswxKaFUrmKl33RJVeeoNYQAz4uqCJ5Z6v4oIBOsC5GozX+I5SorIKiTcQA==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "azure-pipelines-task-lib": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.10.0.tgz", + "integrity": "sha512-nmwf4ReXGfaBDMRO08/KSDOqbieJFljQSXd6bSFl28QsOKiGy5qz1O7pMnb9UqYfH5Fbro0zU4Q88hpO0XkFHg==", + "requires": { + "minimatch": "3.0.4", + "mockery": "^1.7.0", + "q": "^1.1.2", + "semver": "^5.1.0", + "shelljs": "^0.3.0", + "sync-request": "3.0.1", + "uuid": "^3.0.1" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "http-basic": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz", + "integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=", + "requires": { + "caseless": "~0.11.0", + "concat-stream": "^1.4.6", + "http-response-object": "^1.0.0" + } + }, + "http-response-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz", + "integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mock-require": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz", + "integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==", + "dev": true, + "requires": { + "get-caller-file": "^1.0.2", + "normalize-path": "^2.1.1" + } + }, + "mockery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz", + "integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8=" + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "sync-request": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz", + "integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=", + "requires": { + "concat-stream": "^1.4.7", + "http-response-object": "^1.0.1", + "then-request": "^2.0.1" + } + }, + "then-request": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz", + "integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=", + "requires": { + "caseless": "~0.11.0", + "concat-stream": "^1.4.7", + "http-basic": "^2.5.1", + "http-response-object": "^1.1.0", + "promise": "^7.1.1", + "qs": "^6.1.0" + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "typescript-tslint-plugin": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/typescript-tslint-plugin/-/typescript-tslint-plugin-0.5.5.tgz", + "integrity": "sha512-tR5igNQP+6FhxaPJYRlUBVsEl0n5cSuXRbg7L1y80mL4B1jUHb8uiIcbQBJ9zWyypJEdFYFUccpXxvMwZR8+AA==", + "dev": true, + "requires": { + "minimatch": "^3.0.4", + "mock-require": "^3.0.3", + "vscode-languageserver": "^5.2.1" + } + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "vscode-jsonrpc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", + "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==", + "dev": true + }, + "vscode-languageserver": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.2.1.tgz", + "integrity": "sha512-GuayqdKZqAwwaCUjDvMTAVRPJOp/SLON3mJ07eGsx/Iq9HjRymhKWztX41rISqDKhHVVyFM+IywICyZDla6U3A==", + "dev": true, + "requires": { + "vscode-languageserver-protocol": "3.14.1", + "vscode-uri": "^1.0.6" + } + }, + "vscode-languageserver-protocol": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz", + "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==", + "dev": true, + "requires": { + "vscode-jsonrpc": "^4.0.0", + "vscode-languageserver-types": "3.14.0" + } + }, + "vscode-languageserver-types": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", + "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==", + "dev": true + }, + "vscode-uri": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.8.tgz", + "integrity": "sha512-obtSWTlbJ+a+TFRYGaUumtVwb+InIUVI0Lu0VBUAPmj2cU5JutEXg3xUE0c2J5Tcy7h2DEKVJBFi+Y9ZSFzzPQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xml2js-xpath": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/xml2js-xpath/-/xml2js-xpath-0.11.0.tgz", + "integrity": "sha512-LJJWN9VcZUItBb3R3NmaWuE7+mZzhwGfo9vqekDki02ZnnO7M5QHeqpT49XBfWxZlBuuYVXw3t8rjvekZY43Yg==", + "requires": { + "lodash": "^4.17.15" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + } + } +} diff --git a/libs/nexus-v3/package.json b/libs/nexus-v3/package.json new file mode 100644 index 0000000..435dada --- /dev/null +++ b/libs/nexus-v3/package.json @@ -0,0 +1,24 @@ +{ + "name": "nexus-v3", + "version": "1.0.0", + "description": "", + "main": "dist/nexus.js", + "author": "Gareth Emslie", + "license": "MIT", + "dependencies": { + "azure-pipelines-task-lib": "^2.9.3", + "path": "^0.12.7", + "xml2js": "^0.4.23", + "xml2js-xpath": "^0.11.0" + }, + "devDependencies": { + "@types/node": "^12.12.15", + "@types/shelljs": "^0.8.6", + "tslint": "^6.1.0", + "typescript": "^3.8.3", + "typescript-tslint-plugin": "^0.5.5" + }, + "scripts": { + "build": "tsc" + } +} diff --git a/libs/nexus-v3/tsconfig.json b/libs/nexus-v3/tsconfig.json new file mode 100644 index 0000000..2a49675 --- /dev/null +++ b/libs/nexus-v3/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "dist", + "rootDir": ".", + "sourceMap": true, + "strict": false, + "declaration": false, + "plugins": [ + { + "name": "typescript-tslint-plugin" + } + ] + }, + "include": [ + "**/*" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/package.json b/package.json index fd673df..6c970ba 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "scripts": { - "postinstall": "cd ./Tasks/DownloadArtifactsNexus && cd ./DownloadArtifactsNexusV2 && npm install && cd ../DownloadArtifactsNexusV3 && npm install && cd ../DownloadArtifactsNexusV0_2 && npm install && cd ../DownloadArtifactsNexusV0_3 && npm install", + "postinstall": "cd ./libs/nexus-v2 && npm link && cd ../nexus-v3 && npm link && cd ../../Tasks/DownloadArtifactsNexus && cd ./DownloadArtifactsNexusV2 && npm install && npm link nexus-v2 && cd ../DownloadArtifactsNexusV3 && npm install && npm link nexus-v3 && cd ../DownloadArtifactsNexusV0_2 && npm install && npm link nexus-v2 && cd ../DownloadArtifactsNexusV0_3 && npm install && npm link nexus-v3", "build": "tsc", - "package:DownloadArtifactsNexusV0_2": "(for %f in (task.json,package.json,icon.png) do xcopy /y /i .\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV0_2\\%f .\\dist\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV0_2\\) && cd ./dist/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2 && npm install --only=production", - "package:DownloadArtifactsNexusV0_3": "(for %f in (task.json,package.json,icon.png) do xcopy /y /i .\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV0_3\\%f .\\dist\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV0_3\\) && cd ./dist/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3 && npm install --only=production", - "package:DownloadArtifactsNexusV2": "(for %f in (task.json,package.json,icon.png) do xcopy /y /i .\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV2\\%f .\\dist\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV2\\) && cd ./dist/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2 && npm install --only=production", - "package:DownloadArtifactsNexusV3": "(for %f in (task.json,package.json,icon.png) do xcopy /y /i .\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV3\\%f .\\dist\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV3\\) && cd ./dist/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3 && npm install --only=production", + "package:DownloadArtifactsNexusV0_2": "(for %f in (task.json,package.json,icon.png) do xcopy /y /i .\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV0_2\\%f .\\dist\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV0_2\\) && cd ./dist/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_2 && npm install --only=production --force", + "package:DownloadArtifactsNexusV0_3": "(for %f in (task.json,package.json,icon.png) do xcopy /y /i .\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV0_3\\%f .\\dist\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV0_3\\) && cd ./dist/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV0_3 && npm install --only=production --force", + "package:DownloadArtifactsNexusV2": "(for %f in (task.json,package.json,icon.png) do xcopy /y /i .\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV2\\%f .\\dist\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV2\\) && cd ./dist/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV2 && npm install --only=production --force", + "package:DownloadArtifactsNexusV3": "(for %f in (task.json,package.json,icon.png) do xcopy /y /i .\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV3\\%f .\\dist\\Tasks\\DownloadArtifactsNexus\\DownloadArtifactsNexusV3\\) && cd ./dist/Tasks/DownloadArtifactsNexus/DownloadArtifactsNexusV3 && npm install --only=production --force", "package:Server2018VSIX": "npm run build && npm run package:DownloadArtifactsNexusV0_2 && npm run package:DownloadArtifactsNexusV0_3 && tfx extension create --manifests vss-extension-server-2018.json --output-path ./dist/", "package:ServiceVSIX": "npm run build && npm run package:DownloadArtifactsNexusV2 && npm run package:DownloadArtifactsNexusV3 && tfx extension create --manifests vss-extension.json --output-path ./dist/", "package": "npm run package:Server2018VSIX && npm run package:ServiceVSIX" diff --git a/tsconfig.json b/tsconfig.json index 1d09ceb..c0ee984 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ ] }, "include": [ - "./Tasks/**/*" + "./Tasks/**/*" ], "exclude": [ "node_modules"