From 8ec529293f7a761073a44aa4dc74ea2118e1c728 Mon Sep 17 00:00:00 2001 From: Gareth Emslie Date: Tue, 28 Sep 2021 15:28:09 +0200 Subject: [PATCH] lint fixes --- libs/nexus-v2/IhttpHelper.ts | 19 ++- libs/nexus-v2/httpHelper.ts | 316 ++++++++++++++++++---------------- libs/nexus-v2/nexus.ts | 305 +++++++++++++++++++-------------- libs/nexus-v3/IhttpHelper.ts | 19 ++- libs/nexus-v3/httpHelper.ts | 321 +++++++++++++++++++---------------- libs/nexus-v3/nexus.ts | 156 +++++++++-------- 6 files changed, 637 insertions(+), 499 deletions(-) diff --git a/libs/nexus-v2/IhttpHelper.ts b/libs/nexus-v2/IhttpHelper.ts index c4d0da8..51ccf26 100644 --- a/libs/nexus-v2/IhttpHelper.ts +++ b/libs/nexus-v2/IhttpHelper.ts @@ -1,6 +1,15 @@ 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 + 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; +} diff --git a/libs/nexus-v2/httpHelper.ts b/libs/nexus-v2/httpHelper.ts index e9417da..a2b0ad5 100644 --- a/libs/nexus-v2/httpHelper.ts +++ b/libs/nexus-v2/httpHelper.ts @@ -1,157 +1,187 @@ import tl = require('azure-pipelines-task-lib/task'); -import path = require("path"); +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/xml' - } - }; - - 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 - return await this.execute_request(http, options); + public async execute_http(searchUri: URL): Promise; + public async execute_http( + searchUri: URL, + username?: string, + password?: string + ): Promise { + tl.debug('execute_http.'); + + const options: http.RequestOptions = { + host: searchUri.hostname, + path: `${searchUri.pathname}?${searchUri.searchParams}`, + method: 'GET', + headers: { + Accept: 'application/xml', + }, + }; + + 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; } - 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/xml' - } - }; - - 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 - return await this.execute_request(https, options); + // Setup new agent dont use the global one + options.agent = new http.Agent(); + options.port = searchUri.port || options.defaultPort; + + // execute the http request + return 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.'); + + const 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/xml', + }, + }; + + 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; } - 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 == 301 || res.statusCode == 307) { - 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 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); - inner_res.on('data', function(chunk : any){ - file.write(chunk); - }).on('end', function(){ - file.end(); - - // Maintain a list of files that have been downloaded and set a pipeline variable containing the list - let MAVEN_REPOSITORY_ASSET_FILENAMES : string = tl.getVariable("MAVEN_REPOSITORY_ASSET_FILENAMES"); - if(MAVEN_REPOSITORY_ASSET_FILENAMES) - { - if(!MAVEN_REPOSITORY_ASSET_FILENAMES.includes(filename)) - { - tl.setVariable("MAVEN_REPOSITORY_ASSET_FILENAMES", `${MAVEN_REPOSITORY_ASSET_FILENAMES},${filename}`, false); - } - } - else - { - tl.setVariable("MAVEN_REPOSITORY_ASSET_FILENAMES", filename, false); - } - - console.log(`Successfully downloaded asset '${filename}' using '${downloadUri}'.`); - resolve(); - }); - } else - { - console.log(`Asset download was not successful!`); - reject(`Asset download was not successful!`); + // Setup new agent dont use the global one + options.agent = new https.Agent(); + options.port = searchUri.port || options.defaultPort; + + // execute the https request + return 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) => { + const 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 == 301 || res.statusCode == 307) { + 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 file using '${downloadUri}'.`); + const filename: string = path.basename(downloadUri.pathname); + console.log(`Download filename '${filename}'`); + + const 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(); + + // Maintain a list of files that have been downloaded and set a pipeline variable containing the list + const MAVEN_REPOSITORY_ASSET_FILENAMES: string = + tl.getVariable('MAVEN_REPOSITORY_ASSET_FILENAMES'); + if (MAVEN_REPOSITORY_ASSET_FILENAMES) { + if ( + !MAVEN_REPOSITORY_ASSET_FILENAMES.includes(filename) + ) { + tl.setVariable( + 'MAVEN_REPOSITORY_ASSET_FILENAMES', + `${MAVEN_REPOSITORY_ASSET_FILENAMES},${filename}`, + false + ); } + } else { + tl.setVariable( + 'MAVEN_REPOSITORY_ASSET_FILENAMES', + filename, + false + ); + } + + console.log( + `Successfully downloaded asset '${filename}' using '${downloadUri}'.` + ); + resolve(); }); - inner_req.end(); - }else if(res.statusCode == 200) - { - tl.debug(`Http Get request was successful!`); - // get response body - const body = []; - res.on('data', (chunk) => body.push(chunk)); - // we are done, resolve promise with those joined chunks - res.on('end', () => resolve(body.join(''))); - }else - { - tl.debug(`Asset search was not successful!`); - let message : string = `Asset search was not successful!`; - 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); + } else { + console.log('Asset download was not successful!'); + reject('Asset download was not successful!'); } - }); - req.end(); - }); - } -} \ No newline at end of file + } + ); + inner_req.end(); + } else if (res.statusCode == 200) { + tl.debug('Http Get request was successful!'); + // get response body + const body = []; + res.on('data', (chunk) => body.push(chunk)); + // we are done, resolve promise with those joined chunks + res.on('end', () => resolve(body.join(''))); + } else { + tl.debug('Asset search was not successful!'); + let message = 'Asset search was not successful!'; + 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(); + }); + } +} diff --git a/libs/nexus-v2/nexus.ts b/libs/nexus-v2/nexus.ts index 71cf9da..b33651e 100644 --- a/libs/nexus-v2/nexus.ts +++ b/libs/nexus-v2/nexus.ts @@ -1,143 +1,184 @@ import tl = require('azure-pipelines-task-lib/task'); -import path = require("path"); +import path = require('path'); import * as xml2js from 'xml2js'; -import * as xpath from "xml2js-xpath"; +import * as xpath from 'xml2js-xpath'; import { IhttpHelper } from './IhttpHelper'; import { httpHelper } from './httpHelper'; -const helper : IhttpHelper = new 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, version : 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", version); - 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 downloadAsset( + nexusUrl: string, + auth: tl.EndpointAuthorization, + acceptUntrustedCerts: boolean, + repository: string, + group: string, + artifact: string, + version: 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 + const hostUri = new URL(nexusUrl); + let requestPath = '/service/local/artifact/maven/redirect'; + + // Handle root path + if (hostUri.pathname !== '/') { + requestPath = path.join(hostUri.pathname, requestPath); } - - public async downloadAssets(nexusUrl: string, auth: tl.EndpointAuthorization, acceptUntrustedCerts: boolean, repository : string, group : string, artifact : string, version : 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", version); - 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, version, extensions[extension], packaging, classifier); - } - - console.log(`Completed search for asset using '${hostUri}'.`); + hostUri.pathname = requestPath; + + // Query Parameters + hostUri.searchParams.append('r', repository); + hostUri.searchParams.append('g', group); + hostUri.searchParams.append('a', artifact); + hostUri.searchParams.append('v', version); + 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, + version: 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 + const hostUri = new URL(nexusUrl); + let lucenePath = '/service/local/lucene/search'; + + // Handle root path + if (hostUri.pathname !== '/') { + lucenePath = path.join(hostUri.pathname, lucenePath); } - - 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); - } - } - }); - }); + hostUri.pathname = lucenePath; + // Query Parameters + hostUri.searchParams.append('repositoryId', repository); + hostUri.searchParams.append('g', group); + hostUri.searchParams.append('a', artifact); + hostUri.searchParams.append('v', version); + 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 + const responseContent = await this.executeRequest( + hostUri, + auth, + acceptUntrustedCerts + ); + tl.debug(`Response Content '${responseContent}'.`); + const extensions: string[] = await this.parseExtensions(responseContent); + + // Download each asset + for (const extension in extensions) { + await this.downloadAsset( + nexusUrl, + auth, + acceptUntrustedCerts, + repository, + group, + artifact, + version, + extensions[extension], + packaging, + classifier + ); } - - 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; + + 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 { + const message = 'Search result XML contains multiple artifactHits.'; + console.log(message); + reject(message); + } + } + }); + }); + } + + private async executeRequest( + hostUri: URL, + auth: tl.EndpointAuthorization, + acceptUntrustedCerts: boolean + ): Promise { + let 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); } - return responseContent; + } + } catch (inner_err) { + console.log(`Failed to execute request '${hostUri}'.`); + throw inner_err; } -} \ No newline at end of file + return responseContent; + } +} diff --git a/libs/nexus-v3/IhttpHelper.ts b/libs/nexus-v3/IhttpHelper.ts index c4d0da8..51ccf26 100644 --- a/libs/nexus-v3/IhttpHelper.ts +++ b/libs/nexus-v3/IhttpHelper.ts @@ -1,6 +1,15 @@ 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 + 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; +} diff --git a/libs/nexus-v3/httpHelper.ts b/libs/nexus-v3/httpHelper.ts index 606ccc7..04d294f 100644 --- a/libs/nexus-v3/httpHelper.ts +++ b/libs/nexus-v3/httpHelper.ts @@ -1,159 +1,190 @@ import tl = require('azure-pipelines-task-lib/task'); -import path = require("path"); +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 - return await this.execute_request(http, options); + public async execute_http(searchUri: URL): Promise; + public async execute_http( + searchUri: URL, + username?: string, + password?: string + ): Promise { + tl.debug('execute_http.'); + + const 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; } - 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 - return await this.execute_request(https, options); + // Setup new agent dont use the global one + options.agent = new http.Agent(); + options.port = searchUri.port || options.defaultPort; + + // execute the http request + return 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.'); + + const 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; } - 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 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); - inner_res.on('data', function(chunk : any){ - file.write(chunk); - }).on('end', function(){ - file.end(); - - // Maintain a list of files that have been downloaded and set a pipeline variable containing the list - let MAVEN_REPOSITORY_ASSET_FILENAMES : string = tl.getVariable("MAVEN_REPOSITORY_ASSET_FILENAMES"); - if(MAVEN_REPOSITORY_ASSET_FILENAMES) - { - if(!MAVEN_REPOSITORY_ASSET_FILENAMES.includes(filename)) - { - tl.setVariable("MAVEN_REPOSITORY_ASSET_FILENAMES", `${MAVEN_REPOSITORY_ASSET_FILENAMES},${filename}`, false); - } - } - else - { - tl.setVariable("MAVEN_REPOSITORY_ASSET_FILENAMES", filename, false); - } - - console.log(`Successfully downloaded asset '${filename}' using '${downloadUri}'.`); - resolve(); - }); - } else - { - console.log(`Asset download was not successful!`); - reject(`Asset download was not successful!`); + // Setup new agent dont use the global one + options.agent = new https.Agent(); + options.port = searchUri.port || options.defaultPort; + + // execute the https request + return 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) => { + const 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 file using '${downloadUri}'.`); + const filename: string = path.basename(downloadUri.pathname); + console.log(`Download filename '${filename}'`); + + const 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(); + + // Maintain a list of files that have been downloaded and set a pipeline variable containing the list + const MAVEN_REPOSITORY_ASSET_FILENAMES: string = + tl.getVariable('MAVEN_REPOSITORY_ASSET_FILENAMES'); + if (MAVEN_REPOSITORY_ASSET_FILENAMES) { + if ( + !MAVEN_REPOSITORY_ASSET_FILENAMES.includes(filename) + ) { + tl.setVariable( + 'MAVEN_REPOSITORY_ASSET_FILENAMES', + `${MAVEN_REPOSITORY_ASSET_FILENAMES},${filename}`, + false + ); } + } else { + tl.setVariable( + 'MAVEN_REPOSITORY_ASSET_FILENAMES', + filename, + false + ); + } + + console.log( + `Successfully downloaded asset '${filename}' using '${downloadUri}'.` + ); + resolve(); }); - inner_req.end(); - }else if(res.statusCode == 200) - { - tl.debug(`Http Get request was successful!`); - // get response body - const body = []; - res.on('data', (chunk) => body.push(chunk)); - // we are done, resolve promise with those joined chunks - res.on('end', () => resolve(body.join(''))); - }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); + } else { + console.log('Asset download was not successful!'); + reject('Asset download was not successful!'); } - }); - req.end(); - }); - } -} \ No newline at end of file + } + ); + inner_req.end(); + } else if (res.statusCode == 200) { + tl.debug('Http Get request was successful!'); + // get response body + const body = []; + res.on('data', (chunk) => body.push(chunk)); + // we are done, resolve promise with those joined chunks + res.on('end', () => resolve(body.join(''))); + } else { + tl.debug('Asset search was not successful!'); + let message = '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(); + }); + } +} diff --git a/libs/nexus-v3/nexus.ts b/libs/nexus-v3/nexus.ts index af0f1b9..6e98df2 100644 --- a/libs/nexus-v3/nexus.ts +++ b/libs/nexus-v3/nexus.ts @@ -1,81 +1,99 @@ import tl = require('azure-pipelines-task-lib/task'); -import path = require("path"); +import path = require('path'); import * as xml2js from 'xml2js'; -import * as xpath from "xml2js-xpath"; +import * as xpath from 'xml2js-xpath'; import { IhttpHelper } from './IhttpHelper'; import { httpHelper } from './httpHelper'; -const helper : IhttpHelper = new 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, version : 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`; + public async downloadAsset( + nexusUrl: string, + auth: tl.EndpointAuthorization, + acceptUntrustedCerts: boolean, + repository: string, + group: string, + artifact: string, + version: string, + extension: string, + packaging: string, + classifier?: string + ): Promise { + // Build the final download uri + const hostUri = new URL(nexusUrl); + // https://help.sonatype.com/repomanager3/rest-and-integration-api/search-api + // Build the final search uri + let requestPath = '/service/rest/v1/search/assets/download'; - // Handle root path - if(hostUri.pathname !== "/") - { - requestPath = path.join(hostUri.pathname, requestPath); - } - hostUri.pathname = requestPath; + // 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.extension', extension); + hostUri.searchParams.append('maven.classifier', ''); + // Do we have a classifier + if (classifier) { + hostUri.searchParams.set('maven.classifier', classifier); + } + // switch to the "version" criteria, should work in the case of release and snapshot versions + // hostUri.searchParams.append("maven.baseVersion", baseVersion); + hostUri.searchParams.append('version', version); - // 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+ *** + console.log(`Download asset using '${hostUri}'.`); + // Execute the request + await this.executeRequest(hostUri, auth, acceptUntrustedCerts); + console.log(`Completed download asset using '${hostUri}'.`); + } - hostUri.searchParams.append("repository", repository); - hostUri.searchParams.append("maven.groupId", group); - hostUri.searchParams.append("maven.artifactId", artifact); - hostUri.searchParams.append("maven.extension", extension); - hostUri.searchParams.append("maven.classifier", ""); - // Do we have a classifier - if (classifier) { - hostUri.searchParams.set("maven.classifier",classifier); + private async executeRequest( + hostUri: URL, + auth: tl.EndpointAuthorization, + acceptUntrustedCerts: boolean + ): Promise { + let 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 + ); } - // switch to the "version" criteria, should work in the case of release and snapshot versions - // hostUri.searchParams.append("maven.baseVersion", baseVersion); - hostUri.searchParams.append("version", version); - - 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; + } else { + if (auth.scheme === 'UsernamePassword') { + responseContent = await helper.execute_http( + hostUri, + auth.parameters['username'], + auth.parameters['password'] + ); + } else { + responseContent = await helper.execute_http(hostUri); } - return responseContent; + } + } catch (inner_err) { + console.log(`Failed to execute request '${hostUri}'.`); + throw inner_err; } -} \ No newline at end of file + return responseContent; + } +}