From 25a3dcc12f816135bb20713e2c1b17e302569f73 Mon Sep 17 00:00:00 2001 From: Ivan Duplenskikh <115665590+ivanduplenskikh@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:24:57 +0100 Subject: [PATCH 1/3] Remove q library --- node/mock-task.ts | 1081 +++++++++++++++++++-------------------- node/mock-toolrunner.ts | 849 +++++++++++++++--------------- node/package-lock.json | 11 - node/package.json | 2 - node/task.ts | 3 +- node/toolrunner.ts | 509 +++++++++--------- 6 files changed, 1217 insertions(+), 1238 deletions(-) diff --git a/node/mock-task.ts b/node/mock-task.ts index 633a7dc44..ed5bc1fd0 100644 --- a/node/mock-task.ts +++ b/node/mock-task.ts @@ -1,542 +1,541 @@ -import Q = require('q'); -import path = require('path'); -import fs = require('fs'); -import task = require('./task'); -import tcm = require('./taskcommand'); -import trm = require('./mock-toolrunner'); -import ma = require('./mock-answer'); - -let mock: ma.MockAnswers = new ma.MockAnswers(); - -export function setAnswers(answers: ma.TaskLibAnswers) { - mock.initialize(answers); - trm.setAnswers(answers); -} - -//----------------------------------------------------- -// Enums -//----------------------------------------------------- - -module.exports.TaskResult = task.TaskResult; -module.exports.TaskState = task.TaskState; -module.exports.IssueType = task.IssueType; -module.exports.ArtifactType = task.ArtifactType; -module.exports.FieldType = task.FieldType; -module.exports.Platform = task.Platform; - -//----------------------------------------------------- -// Results and Exiting -//----------------------------------------------------- - -module.exports.setStdStream = task.setStdStream; -module.exports.setErrStream = task.setErrStream; -module.exports.setResult = task.setResult; -module.exports.setSanitizedResult = task.setSanitizedResult; - -//----------------------------------------------------- -// Loc Helpers -//----------------------------------------------------- -export function setResourcePath(path: string): void { - // nothing in mock -} - -export function loc(key: string, ...args: any[]): string { - let str: string = 'loc_mock_' + key; - if (args.length) { - str += ' ' + args.join(' '); - } - - return str; -} - -//----------------------------------------------------- -// Input Helpers -//----------------------------------------------------- -module.exports.assertAgent = task.assertAgent; -module.exports.getVariable = task.getVariable; -module.exports.getVariables = task.getVariables; -module.exports.setVariable = task.setVariable; -module.exports.setSecret = task.setSecret; -module.exports.getTaskVariable = task.getTaskVariable; -module.exports.setTaskVariable = task.setTaskVariable; -module.exports.getInput = task.getInput; -module.exports.getInputRequired = task.getInputRequired; -module.exports.getBoolInput = task.getBoolInput; -module.exports.getBoolFeatureFlag = task.getBoolFeatureFlag; -module.exports.getPipelineFeature = task.getPipelineFeature; -module.exports.getDelimitedInput = task.getDelimitedInput; -module.exports.filePathSupplied = task.filePathSupplied; - -function getPathInput(name: string, required?: boolean, check?: boolean): string { - var inval = module.exports.getInput(name, required); - if (inval) { - if (check) { - checkPath(inval, name); - } - } - return inval; -} -module.exports.getPathInput = getPathInput; - -function getPathInputRequired(name: string, check?: boolean): string { - return getPathInput(name, true, check)!; -} -module.exports.getPathInputRequired = getPathInputRequired; - -//----------------------------------------------------- -// Endpoint Helpers -//----------------------------------------------------- -module.exports.getEndpointUrl = task.getEndpointUrl; -module.exports.getEndpointUrlRequired = task.getEndpointUrlRequired; -module.exports.getEndpointDataParameter = task.getEndpointDataParameter; -module.exports.getEndpointDataParameterRequired = task.getEndpointDataParameterRequired; -module.exports.getEndpointAuthorizationScheme = task.getEndpointAuthorizationScheme; -module.exports.getEndpointAuthorizationSchemeRequired = task.getEndpointAuthorizationSchemeRequired; -module.exports.getEndpointAuthorizationParameter = task.getEndpointAuthorizationParameter; -module.exports.getEndpointAuthorizationParameterRequired = task.getEndpointAuthorizationParameterRequired; -module.exports.getEndpointAuthorization = task.getEndpointAuthorization; - -// TODO: should go away when task lib -export interface EndpointAuthorization { - parameters: { - [key: string]: string; - }; - scheme: string; -} - -//----------------------------------------------------- -// SecureFile Helpers -//----------------------------------------------------- -module.exports.getSecureFileName = task.getSecureFileName; -module.exports.getSecureFileTicket = task.getSecureFileTicket; - -//----------------------------------------------------- -// Fs Helpers -//----------------------------------------------------- - -export class FsStats implements fs.Stats { - private m_isFile: boolean = false; - private m_isDirectory: boolean = false; - private m_isBlockDevice: boolean = false; - private m_isCharacterDevice: boolean = false; - private m_isSymbolicLink: boolean = false; - private m_isFIFO: boolean = false; - private m_isSocket: boolean = false; - - dev: number = 0; - ino: number = 0; - mode: number = 0; - nlink: number = 0; - uid: number = 0; - gid: number = 0; - rdev: number = 0; - size: number = 0; - blksize: number = 0; - blocks: number = 0; - atime: Date = new Date(); - mtime: Date = new Date(); - ctime: Date = new Date(); - birthtime: Date = new Date(); - atimeMs: number; - mtimeMs: number; - ctimeMs: number; - birthtimeMs: number; - - setAnswers(mockResponses: any): void { - this.m_isFile = mockResponses['isFile'] || this.m_isFile; - this.m_isDirectory = mockResponses['isDirectory'] || this.m_isDirectory; - this.m_isBlockDevice = mockResponses['isBlockDevice'] || this.m_isBlockDevice; - this.m_isCharacterDevice = mockResponses['isCharacterDevice'] || this.m_isCharacterDevice; - this.m_isSymbolicLink = mockResponses['isSymbolicLink'] || this.m_isSymbolicLink; - this.m_isFIFO = mockResponses['isFIFO'] || this.m_isFIFO; - this.m_isSocket = mockResponses['isSocket'] || this.m_isSocket; - - this.dev = mockResponses['dev'] || this.dev; - this.ino = mockResponses['ino'] || this.ino; - this.mode = mockResponses['mode'] || this.mode; - this.nlink = mockResponses['nlink'] || this.nlink; - this.uid = mockResponses['uid'] || this.uid; - this.gid = mockResponses['gid'] || this.gid; - this.rdev = mockResponses['rdev'] || this.rdev; - this.size = mockResponses['size'] || this.size; - this.blksize = mockResponses['blksize'] || this.blksize; - this.blocks = mockResponses['blocks'] || this.blocks; - this.atime = mockResponses['atime'] || this.atime; - this.mtime = mockResponses['mtime'] || this.mtime; - this.ctime = mockResponses['ctime'] || this.ctime; - this.m_isSocket = mockResponses['isSocket'] || this.m_isSocket; - } - - isFile(): boolean { - return this.m_isFile; - } - - isDirectory(): boolean { - return this.m_isDirectory; - } - - isBlockDevice(): boolean { - return this.m_isBlockDevice; - } - - isCharacterDevice(): boolean { - return this.m_isCharacterDevice; - } - - isSymbolicLink(): boolean { - return this.m_isSymbolicLink; - } - - isFIFO(): boolean { - return this.m_isFIFO; - } - - isSocket(): boolean { - return this.m_isSocket; - } -} - -export function stats(path: string): FsStats { - var fsStats = new FsStats(); - fsStats.setAnswers(mock.getResponse('stats', path, module.exports.debug) || {}); - return fsStats; -} - -export function exist(path: string): boolean { - return mock.getResponse('exist', path, module.exports.debug) || false; -} - -export interface FsOptions { - encoding?:string; - mode?:number; - flag?:string; -} - -export function writeFile(file: string, data: string|Buffer, options?: string|FsOptions) { - //do nothing -} - -export function osType(): string { - return mock.getResponse('osType', 'osType', module.exports.debug); -} - -export function getPlatform(): task.Platform { - return mock.getResponse('getPlatform', 'getPlatform', module.exports.debug); -} - -export function getNodeMajorVersion(): Number { - return mock.getResponse('getNodeMajorVersion', 'getNodeMajorVersion', module.exports.debug); -} - -export function getAgentMode(): task.AgentHostedMode { - return mock.getResponse('getAgentMode', 'getAgentMode', module.exports.debug); -} - -export function cwd(): string { - return mock.getResponse('cwd', 'cwd', module.exports.debug); -} - -//----------------------------------------------------- -// Cmd Helpers -//----------------------------------------------------- -module.exports.command = task.command; -module.exports.warning = task.warning; -module.exports.error = task.error; -module.exports.debug = task.debug; - -export function cd(path: string): void { - // do nothing. TODO: keep stack with asserts -} - -export function pushd(path: string): void { - // do nothing. TODO: keep stack with asserts -} - -export function popd(): void { - // do nothing. TODO: keep stack with asserts -} - -//------------------------------------------------ -// Validation Helpers -//------------------------------------------------ - -export function checkPath(p: string, name: string): void { - module.exports.debug('check path : ' + p); - if (!p || !mock.getResponse('checkPath', p, module.exports.debug)) { - throw new Error('Not found ' + p); - } -} - -//----------------------------------------------------- -// Shell/File I/O Helpers -// Abstract these away so we can -// - default to good error handling -// - inject system.debug info -// - have option to switch internal impl (shelljs now) -//----------------------------------------------------- -export function mkdirP(p): void { - module.exports.debug('creating path: ' + p); -} - -export function resolve(): string { - // we can't do ...param if we target ES6 and node 5. This is what <=ES5 compiles down to. - //return the posix implementation in the mock, so paths will be consistent when L0 tests are run on Windows or Mac/Linux - var absolutePath = path.posix.resolve.apply(this, arguments); - module.exports.debug('Absolute path for pathSegments: ' + arguments + ' = ' + absolutePath); - return absolutePath; -} - -export function which(tool: string, check?: boolean): string { - var response = mock.getResponse('which', tool, module.exports.debug); - if (check) { - checkPath(response, tool); - } - return response; -} - -export function ls(options: string, paths: string[]): string[] { - var response = mock.getResponse('ls', paths[0], module.exports.debug); - if(!response){ - return []; - } - return response; -} - -export function cp(source: string, dest: string): void { - module.exports.debug('###copying###'); - module.exports.debug('copying ' + source + ' to ' + dest); -} - -export function retry(func: Function, args: any[], retryOptions: task.RetryOptions): any { - module.exports.debug(`trying to execute ${func?.name}(${args.toString()}) with ${retryOptions.retryCount} retries`); -} - -export function find(findPath: string): string[] { - return mock.getResponse('find', findPath, module.exports.debug); -} - -export function rmRF(path: string): void { - module.exports.debug('rmRF ' + path); - var response = mock.getResponse('rmRF', path, module.exports.debug); - if (!response['success']) { - module.exports.setResult(1, response['message']); - } -} - -export function mv(source: string, dest: string, force: boolean, continueOnError?: boolean): boolean { - module.exports.debug('moving ' + source + ' to ' + dest); - return true; -} - -//----------------------------------------------------- -// Exec convenience wrapper -//----------------------------------------------------- -export function exec(tool: string, args: any, options?: trm.IExecOptions): Q.Promise { - var toolPath = which(tool, true); - var tr: trm.ToolRunner = this.tool(toolPath); - if (args) { - tr.arg(args); - } - return tr.exec(options); -} - -//----------------------------------------------------- -// Exec convenience wrapper -//----------------------------------------------------- -export function execAsync(tool: string, args: any, options?: trm.IExecOptions): Promise { - var toolPath = which(tool, true); - var tr: trm.ToolRunner = this.tool(toolPath); - if (args) { - tr.arg(args); - } - return tr.execAsync(options); -} - -export function execSync(tool: string, args: any, options?: trm.IExecSyncOptions): trm.IExecSyncResult { - var toolPath = which(tool, true); - var tr: trm.ToolRunner = this.tool(toolPath); - if (args) { - tr.arg(args); - } - - return tr.execSync(options); -} - -export function tool(tool: string): trm.ToolRunner { - var tr: trm.ToolRunner = new trm.ToolRunner(tool); - tr.on('debug', (message: string) => { - module.exports.debug(message); - }) - - return tr; -} - -//----------------------------------------------------- -// Matching helpers -//----------------------------------------------------- -module.exports.filter = task.filter; -module.exports.match = task.match; - -// redefine to avoid folks having to typings install minimatch -export interface MatchOptions { - debug?: boolean; - nobrace?: boolean; - noglobstar?: boolean; - dot?: boolean; - noext?: boolean; - nocase?: boolean; - nonull?: boolean; - matchBase?: boolean; - nocomment?: boolean; - nonegate?: boolean; - flipNegate?: boolean; -} - -export function findMatch(defaultRoot: string, patterns: string[] | string) : string[] { - let responseKey: string = typeof patterns == 'object' ? (patterns as string[]).join('\n') : patterns as string; - return mock.getResponse('findMatch', responseKey, module.exports.debug); -} - -export function legacyFindFiles(rootDirectory: string, pattern: string, includeFiles?: boolean, includeDirectories?: boolean) : string[] { - return mock.getResponse('legacyFindFiles', pattern, module.exports.debug); -} - -//----------------------------------------------------- -// Test Publisher -//----------------------------------------------------- -export class TestPublisher { - constructor(public testRunner: string) { - } - - public publish(resultFiles?: string, mergeResults?: string, platform?: string, config?: string, runTitle?: string, publishRunAttachments?: string) { - - var properties = <{ [key: string]: string }>{}; - properties['type'] = this.testRunner; - - if (mergeResults) { - properties['mergeResults'] = mergeResults; - } - - if (platform) { - properties['platform'] = platform; - } - - if (config) { - properties['config'] = config; - } - - if (runTitle) { - properties['runTitle'] = runTitle; - } - - if (publishRunAttachments) { - properties['publishRunAttachments'] = publishRunAttachments; - } - - if (resultFiles) { - properties['resultFiles'] = resultFiles; - } - - module.exports.command('results.publish', properties, ''); - } -} - -//----------------------------------------------------- -// Code Coverage Publisher -//----------------------------------------------------- -export class CodeCoveragePublisher { - constructor() { - } - public publish(codeCoverageTool?: string, summaryFileLocation?: string, reportDirectory?: string, additionalCodeCoverageFiles?: string) { - - var properties = <{ [key: string]: string }>{}; - - if (codeCoverageTool) { - properties['codecoveragetool'] = codeCoverageTool; - } - - if (summaryFileLocation) { - properties['summaryfile'] = summaryFileLocation; - } - - if (reportDirectory) { - properties['reportdirectory'] = reportDirectory; - } - - if (additionalCodeCoverageFiles) { - properties['additionalcodecoveragefiles'] = additionalCodeCoverageFiles; - } - - module.exports.command('codecoverage.publish', properties, ""); - } -} - -//----------------------------------------------------- -// Code coverage Publisher -//----------------------------------------------------- -export class CodeCoverageEnabler { - private buildTool: string; - private ccTool: string; - - constructor(buildTool: string, ccTool: string) { - this.buildTool = buildTool; - this.ccTool = ccTool; - } - - public enableCodeCoverage(buildProps: { [key: string]: string }) { - buildProps['buildtool'] = this.buildTool; - buildProps['codecoveragetool'] = this.ccTool; - module.exports.command('codecoverage.enable', buildProps, ""); - } -} - -//----------------------------------------------------- -// Task Logging Commands -//----------------------------------------------------- -exports.uploadFile = task.uploadFile; -exports.prependPath = task.prependPath; -exports.uploadSummary = task.uploadSummary; -exports.addAttachment = task.addAttachment; -exports.setEndpoint = task.setEndpoint; -exports.setProgress = task.setProgress; -exports.logDetail = task.logDetail; -exports.logIssue = task.logIssue; - -//----------------------------------------------------- -// Artifact Logging Commands -//----------------------------------------------------- -exports.uploadArtifact = task.uploadArtifact; -exports.associateArtifact = task.associateArtifact; - -//----------------------------------------------------- -// Build Logging Commands -//----------------------------------------------------- -exports.uploadBuildLog = task.uploadBuildLog; -exports.updateBuildNumber = task.updateBuildNumber; -exports.addBuildTag = task.addBuildTag; - -//----------------------------------------------------- -// Release Logging Commands -//----------------------------------------------------- -exports.updateReleaseName = task.updateReleaseName; - -//----------------------------------------------------- -// Tools -//----------------------------------------------------- -exports.TaskCommand = tcm.TaskCommand; -exports.commandFromString = tcm.commandFromString; -exports.ToolRunner = trm.ToolRunner; - -//----------------------------------------------------- -// Http Proxy Helper -//----------------------------------------------------- -export function getHttpProxyConfiguration(requestUrl?: string): task.ProxyConfiguration | null { - return null; -} - -//----------------------------------------------------- -// Http Certificate Helper -//----------------------------------------------------- -export function getHttpCertConfiguration(): task.CertConfiguration | null { - return null +import path = require('path'); +import fs = require('fs'); +import task = require('./task'); +import tcm = require('./taskcommand'); +import trm = require('./mock-toolrunner'); +import ma = require('./mock-answer'); + +let mock: ma.MockAnswers = new ma.MockAnswers(); + +export function setAnswers(answers: ma.TaskLibAnswers) { + mock.initialize(answers); + trm.setAnswers(answers); +} + +//----------------------------------------------------- +// Enums +//----------------------------------------------------- + +module.exports.TaskResult = task.TaskResult; +module.exports.TaskState = task.TaskState; +module.exports.IssueType = task.IssueType; +module.exports.ArtifactType = task.ArtifactType; +module.exports.FieldType = task.FieldType; +module.exports.Platform = task.Platform; + +//----------------------------------------------------- +// Results and Exiting +//----------------------------------------------------- + +module.exports.setStdStream = task.setStdStream; +module.exports.setErrStream = task.setErrStream; +module.exports.setResult = task.setResult; +module.exports.setSanitizedResult = task.setSanitizedResult; + +//----------------------------------------------------- +// Loc Helpers +//----------------------------------------------------- +export function setResourcePath(path: string): void { + // nothing in mock +} + +export function loc(key: string, ...args: any[]): string { + let str: string = 'loc_mock_' + key; + if (args.length) { + str += ' ' + args.join(' '); + } + + return str; +} + +//----------------------------------------------------- +// Input Helpers +//----------------------------------------------------- +module.exports.assertAgent = task.assertAgent; +module.exports.getVariable = task.getVariable; +module.exports.getVariables = task.getVariables; +module.exports.setVariable = task.setVariable; +module.exports.setSecret = task.setSecret; +module.exports.getTaskVariable = task.getTaskVariable; +module.exports.setTaskVariable = task.setTaskVariable; +module.exports.getInput = task.getInput; +module.exports.getInputRequired = task.getInputRequired; +module.exports.getBoolInput = task.getBoolInput; +module.exports.getBoolFeatureFlag = task.getBoolFeatureFlag; +module.exports.getPipelineFeature = task.getPipelineFeature; +module.exports.getDelimitedInput = task.getDelimitedInput; +module.exports.filePathSupplied = task.filePathSupplied; + +function getPathInput(name: string, required?: boolean, check?: boolean): string { + var inval = module.exports.getInput(name, required); + if (inval) { + if (check) { + checkPath(inval, name); + } + } + return inval; +} +module.exports.getPathInput = getPathInput; + +function getPathInputRequired(name: string, check?: boolean): string { + return getPathInput(name, true, check)!; +} +module.exports.getPathInputRequired = getPathInputRequired; + +//----------------------------------------------------- +// Endpoint Helpers +//----------------------------------------------------- +module.exports.getEndpointUrl = task.getEndpointUrl; +module.exports.getEndpointUrlRequired = task.getEndpointUrlRequired; +module.exports.getEndpointDataParameter = task.getEndpointDataParameter; +module.exports.getEndpointDataParameterRequired = task.getEndpointDataParameterRequired; +module.exports.getEndpointAuthorizationScheme = task.getEndpointAuthorizationScheme; +module.exports.getEndpointAuthorizationSchemeRequired = task.getEndpointAuthorizationSchemeRequired; +module.exports.getEndpointAuthorizationParameter = task.getEndpointAuthorizationParameter; +module.exports.getEndpointAuthorizationParameterRequired = task.getEndpointAuthorizationParameterRequired; +module.exports.getEndpointAuthorization = task.getEndpointAuthorization; + +// TODO: should go away when task lib +export interface EndpointAuthorization { + parameters: { + [key: string]: string; + }; + scheme: string; +} + +//----------------------------------------------------- +// SecureFile Helpers +//----------------------------------------------------- +module.exports.getSecureFileName = task.getSecureFileName; +module.exports.getSecureFileTicket = task.getSecureFileTicket; + +//----------------------------------------------------- +// Fs Helpers +//----------------------------------------------------- + +export class FsStats implements fs.Stats { + private m_isFile: boolean = false; + private m_isDirectory: boolean = false; + private m_isBlockDevice: boolean = false; + private m_isCharacterDevice: boolean = false; + private m_isSymbolicLink: boolean = false; + private m_isFIFO: boolean = false; + private m_isSocket: boolean = false; + + dev: number = 0; + ino: number = 0; + mode: number = 0; + nlink: number = 0; + uid: number = 0; + gid: number = 0; + rdev: number = 0; + size: number = 0; + blksize: number = 0; + blocks: number = 0; + atime: Date = new Date(); + mtime: Date = new Date(); + ctime: Date = new Date(); + birthtime: Date = new Date(); + atimeMs: number; + mtimeMs: number; + ctimeMs: number; + birthtimeMs: number; + + setAnswers(mockResponses: any): void { + this.m_isFile = mockResponses['isFile'] || this.m_isFile; + this.m_isDirectory = mockResponses['isDirectory'] || this.m_isDirectory; + this.m_isBlockDevice = mockResponses['isBlockDevice'] || this.m_isBlockDevice; + this.m_isCharacterDevice = mockResponses['isCharacterDevice'] || this.m_isCharacterDevice; + this.m_isSymbolicLink = mockResponses['isSymbolicLink'] || this.m_isSymbolicLink; + this.m_isFIFO = mockResponses['isFIFO'] || this.m_isFIFO; + this.m_isSocket = mockResponses['isSocket'] || this.m_isSocket; + + this.dev = mockResponses['dev'] || this.dev; + this.ino = mockResponses['ino'] || this.ino; + this.mode = mockResponses['mode'] || this.mode; + this.nlink = mockResponses['nlink'] || this.nlink; + this.uid = mockResponses['uid'] || this.uid; + this.gid = mockResponses['gid'] || this.gid; + this.rdev = mockResponses['rdev'] || this.rdev; + this.size = mockResponses['size'] || this.size; + this.blksize = mockResponses['blksize'] || this.blksize; + this.blocks = mockResponses['blocks'] || this.blocks; + this.atime = mockResponses['atime'] || this.atime; + this.mtime = mockResponses['mtime'] || this.mtime; + this.ctime = mockResponses['ctime'] || this.ctime; + this.m_isSocket = mockResponses['isSocket'] || this.m_isSocket; + } + + isFile(): boolean { + return this.m_isFile; + } + + isDirectory(): boolean { + return this.m_isDirectory; + } + + isBlockDevice(): boolean { + return this.m_isBlockDevice; + } + + isCharacterDevice(): boolean { + return this.m_isCharacterDevice; + } + + isSymbolicLink(): boolean { + return this.m_isSymbolicLink; + } + + isFIFO(): boolean { + return this.m_isFIFO; + } + + isSocket(): boolean { + return this.m_isSocket; + } +} + +export function stats(path: string): FsStats { + var fsStats = new FsStats(); + fsStats.setAnswers(mock.getResponse('stats', path, module.exports.debug) || {}); + return fsStats; +} + +export function exist(path: string): boolean { + return mock.getResponse('exist', path, module.exports.debug) || false; +} + +export interface FsOptions { + encoding?:string; + mode?:number; + flag?:string; +} + +export function writeFile(file: string, data: string|Buffer, options?: string|FsOptions) { + //do nothing +} + +export function osType(): string { + return mock.getResponse('osType', 'osType', module.exports.debug); +} + +export function getPlatform(): task.Platform { + return mock.getResponse('getPlatform', 'getPlatform', module.exports.debug); +} + +export function getNodeMajorVersion(): Number { + return mock.getResponse('getNodeMajorVersion', 'getNodeMajorVersion', module.exports.debug); +} + +export function getAgentMode(): task.AgentHostedMode { + return mock.getResponse('getAgentMode', 'getAgentMode', module.exports.debug); +} + +export function cwd(): string { + return mock.getResponse('cwd', 'cwd', module.exports.debug); +} + +//----------------------------------------------------- +// Cmd Helpers +//----------------------------------------------------- +module.exports.command = task.command; +module.exports.warning = task.warning; +module.exports.error = task.error; +module.exports.debug = task.debug; + +export function cd(path: string): void { + // do nothing. TODO: keep stack with asserts +} + +export function pushd(path: string): void { + // do nothing. TODO: keep stack with asserts +} + +export function popd(): void { + // do nothing. TODO: keep stack with asserts +} + +//------------------------------------------------ +// Validation Helpers +//------------------------------------------------ + +export function checkPath(p: string, name: string): void { + module.exports.debug('check path : ' + p); + if (!p || !mock.getResponse('checkPath', p, module.exports.debug)) { + throw new Error('Not found ' + p); + } +} + +//----------------------------------------------------- +// Shell/File I/O Helpers +// Abstract these away so we can +// - default to good error handling +// - inject system.debug info +// - have option to switch internal impl (shelljs now) +//----------------------------------------------------- +export function mkdirP(p): void { + module.exports.debug('creating path: ' + p); +} + +export function resolve(): string { + // we can't do ...param if we target ES6 and node 5. This is what <=ES5 compiles down to. + //return the posix implementation in the mock, so paths will be consistent when L0 tests are run on Windows or Mac/Linux + var absolutePath = path.posix.resolve.apply(this, arguments); + module.exports.debug('Absolute path for pathSegments: ' + arguments + ' = ' + absolutePath); + return absolutePath; +} + +export function which(tool: string, check?: boolean): string { + var response = mock.getResponse('which', tool, module.exports.debug); + if (check) { + checkPath(response, tool); + } + return response; +} + +export function ls(options: string, paths: string[]): string[] { + var response = mock.getResponse('ls', paths[0], module.exports.debug); + if(!response){ + return []; + } + return response; +} + +export function cp(source: string, dest: string): void { + module.exports.debug('###copying###'); + module.exports.debug('copying ' + source + ' to ' + dest); +} + +export function retry(func: Function, args: any[], retryOptions: task.RetryOptions): any { + module.exports.debug(`trying to execute ${func?.name}(${args.toString()}) with ${retryOptions.retryCount} retries`); +} + +export function find(findPath: string): string[] { + return mock.getResponse('find', findPath, module.exports.debug); +} + +export function rmRF(path: string): void { + module.exports.debug('rmRF ' + path); + var response = mock.getResponse('rmRF', path, module.exports.debug); + if (!response['success']) { + module.exports.setResult(1, response['message']); + } +} + +export function mv(source: string, dest: string, force: boolean, continueOnError?: boolean): boolean { + module.exports.debug('moving ' + source + ' to ' + dest); + return true; +} + +//----------------------------------------------------- +// Exec convenience wrapper +//----------------------------------------------------- +export function exec(tool: string, args: any, options?: trm.IExecOptions): Promise { + var toolPath = which(tool, true); + var tr: trm.ToolRunner = this.tool(toolPath); + if (args) { + tr.arg(args); + } + return tr.exec(options); +} + +//----------------------------------------------------- +// Exec convenience wrapper +//----------------------------------------------------- +export function execAsync(tool: string, args: any, options?: trm.IExecOptions): Promise { + var toolPath = which(tool, true); + var tr: trm.ToolRunner = this.tool(toolPath); + if (args) { + tr.arg(args); + } + return tr.execAsync(options); +} + +export function execSync(tool: string, args: any, options?: trm.IExecSyncOptions): trm.IExecSyncResult { + var toolPath = which(tool, true); + var tr: trm.ToolRunner = this.tool(toolPath); + if (args) { + tr.arg(args); + } + + return tr.execSync(options); +} + +export function tool(tool: string): trm.ToolRunner { + var tr: trm.ToolRunner = new trm.ToolRunner(tool); + tr.on('debug', (message: string) => { + module.exports.debug(message); + }) + + return tr; +} + +//----------------------------------------------------- +// Matching helpers +//----------------------------------------------------- +module.exports.filter = task.filter; +module.exports.match = task.match; + +// redefine to avoid folks having to typings install minimatch +export interface MatchOptions { + debug?: boolean; + nobrace?: boolean; + noglobstar?: boolean; + dot?: boolean; + noext?: boolean; + nocase?: boolean; + nonull?: boolean; + matchBase?: boolean; + nocomment?: boolean; + nonegate?: boolean; + flipNegate?: boolean; +} + +export function findMatch(defaultRoot: string, patterns: string[] | string) : string[] { + let responseKey: string = typeof patterns == 'object' ? (patterns as string[]).join('\n') : patterns as string; + return mock.getResponse('findMatch', responseKey, module.exports.debug); +} + +export function legacyFindFiles(rootDirectory: string, pattern: string, includeFiles?: boolean, includeDirectories?: boolean) : string[] { + return mock.getResponse('legacyFindFiles', pattern, module.exports.debug); +} + +//----------------------------------------------------- +// Test Publisher +//----------------------------------------------------- +export class TestPublisher { + constructor(public testRunner: string) { + } + + public publish(resultFiles?: string, mergeResults?: string, platform?: string, config?: string, runTitle?: string, publishRunAttachments?: string) { + + var properties = <{ [key: string]: string }>{}; + properties['type'] = this.testRunner; + + if (mergeResults) { + properties['mergeResults'] = mergeResults; + } + + if (platform) { + properties['platform'] = platform; + } + + if (config) { + properties['config'] = config; + } + + if (runTitle) { + properties['runTitle'] = runTitle; + } + + if (publishRunAttachments) { + properties['publishRunAttachments'] = publishRunAttachments; + } + + if (resultFiles) { + properties['resultFiles'] = resultFiles; + } + + module.exports.command('results.publish', properties, ''); + } +} + +//----------------------------------------------------- +// Code Coverage Publisher +//----------------------------------------------------- +export class CodeCoveragePublisher { + constructor() { + } + public publish(codeCoverageTool?: string, summaryFileLocation?: string, reportDirectory?: string, additionalCodeCoverageFiles?: string) { + + var properties = <{ [key: string]: string }>{}; + + if (codeCoverageTool) { + properties['codecoveragetool'] = codeCoverageTool; + } + + if (summaryFileLocation) { + properties['summaryfile'] = summaryFileLocation; + } + + if (reportDirectory) { + properties['reportdirectory'] = reportDirectory; + } + + if (additionalCodeCoverageFiles) { + properties['additionalcodecoveragefiles'] = additionalCodeCoverageFiles; + } + + module.exports.command('codecoverage.publish', properties, ""); + } +} + +//----------------------------------------------------- +// Code coverage Publisher +//----------------------------------------------------- +export class CodeCoverageEnabler { + private buildTool: string; + private ccTool: string; + + constructor(buildTool: string, ccTool: string) { + this.buildTool = buildTool; + this.ccTool = ccTool; + } + + public enableCodeCoverage(buildProps: { [key: string]: string }) { + buildProps['buildtool'] = this.buildTool; + buildProps['codecoveragetool'] = this.ccTool; + module.exports.command('codecoverage.enable', buildProps, ""); + } +} + +//----------------------------------------------------- +// Task Logging Commands +//----------------------------------------------------- +exports.uploadFile = task.uploadFile; +exports.prependPath = task.prependPath; +exports.uploadSummary = task.uploadSummary; +exports.addAttachment = task.addAttachment; +exports.setEndpoint = task.setEndpoint; +exports.setProgress = task.setProgress; +exports.logDetail = task.logDetail; +exports.logIssue = task.logIssue; + +//----------------------------------------------------- +// Artifact Logging Commands +//----------------------------------------------------- +exports.uploadArtifact = task.uploadArtifact; +exports.associateArtifact = task.associateArtifact; + +//----------------------------------------------------- +// Build Logging Commands +//----------------------------------------------------- +exports.uploadBuildLog = task.uploadBuildLog; +exports.updateBuildNumber = task.updateBuildNumber; +exports.addBuildTag = task.addBuildTag; + +//----------------------------------------------------- +// Release Logging Commands +//----------------------------------------------------- +exports.updateReleaseName = task.updateReleaseName; + +//----------------------------------------------------- +// Tools +//----------------------------------------------------- +exports.TaskCommand = tcm.TaskCommand; +exports.commandFromString = tcm.commandFromString; +exports.ToolRunner = trm.ToolRunner; + +//----------------------------------------------------- +// Http Proxy Helper +//----------------------------------------------------- +export function getHttpProxyConfiguration(requestUrl?: string): task.ProxyConfiguration | null { + return null; +} + +//----------------------------------------------------- +// Http Certificate Helper +//----------------------------------------------------- +export function getHttpCertConfiguration(): task.CertConfiguration | null { + return null } \ No newline at end of file diff --git a/node/mock-toolrunner.ts b/node/mock-toolrunner.ts index 8f5a3380a..95c59ebf6 100644 --- a/node/mock-toolrunner.ts +++ b/node/mock-toolrunner.ts @@ -1,426 +1,423 @@ -import Q = require('q'); -import os = require('os'); -import events = require('events'); -import ma = require('./mock-answer'); - -let mock: ma.MockAnswers = new ma.MockAnswers(); - -export function setAnswers(answers: ma.TaskLibAnswers) { - mock.initialize(answers); -} - -export interface IExecOptions extends IExecSyncOptions { - failOnStdErr?: boolean; - ignoreReturnCode?: boolean; -}; - -export interface IExecSyncOptions { - cwd?: string; - env?: { [key: string]: string | undefined }; - silent?: boolean; - outStream: NodeJS.WritableStream; - errStream: NodeJS.WritableStream; - windowsVerbatimArguments?: boolean; -}; - -export interface IExecSyncResult { - stdout: string; - stderr: string; - code: number; - error: Error; -} - -export function debug(message) { - // do nothing, overridden -} - -export class ToolRunner extends events.EventEmitter { - constructor(toolPath: string) { - debug('toolRunner toolPath: ' + toolPath); - - super(); - - this.toolPath = toolPath; - this.args = []; - } - - private toolPath: string; - private args: string[]; - private pipeOutputToTool: ToolRunner | undefined; - - private _debug(message) { - debug(message); - this.emit('debug', message); - } - - private _argStringToArray(argString: string): string[] { - var args: string[] = []; - - var inQuotes = false; - var escaped =false; - var arg = ''; - - var append = function(c: string) { - // we only escape double quotes. - if (escaped && c !== '"') { - arg += '\\'; - } - - arg += c; - escaped = false; - } - - for (var i=0; i < argString.length; i++) { - var c = argString.charAt(i); - - if (c === '"') { - if (!escaped) { - inQuotes = !inQuotes; - } - else { - append(c); - } - continue; - } - - if (c === "\\" && inQuotes) { - escaped = true; - continue; - } - - if (c === ' ' && !inQuotes) { - if (arg.length > 0) { - args.push(arg); - arg = ''; - } - continue; - } - - append(c); - } - - if (arg.length > 0) { - args.push(arg.trim()); - } - - return args; - } - - public arg(val: any): ToolRunner { - if (!val) { - return this; - } - - if (val instanceof Array) { - this._debug(this.toolPath + ' arg: ' + JSON.stringify(val)); - this.args = this.args.concat(val); - } - else if (typeof(val) === 'string') { - this._debug(this.toolPath + ' arg: ' + val); - this.args = this.args.concat(val.trim()); - } - - return this; - } - - public argIf(condition: any, val: any): ToolRunner { - if (condition) { - this.arg(val); - } - - return this; - } - - public line(val: string): ToolRunner { - if (!val) { - return this; - } - - this._debug(this.toolPath + ' arg: ' + val); - this.args = this.args.concat(this._argStringToArray(val)); - return this; - } - - public pipeExecOutputToTool(tool: ToolRunner) : ToolRunner { - this.pipeOutputToTool = tool; - return this; - } - - private ignoreTempPath(cmdString: string): string { - this._debug('ignoreTempPath=' + process.env['MOCK_IGNORE_TEMP_PATH']); - this._debug('tempPath=' + process.env['MOCK_TEMP_PATH']); - if (process.env['MOCK_IGNORE_TEMP_PATH'] === 'true') { - // Using split/join to replace the temp path - cmdString = cmdString.split(process.env['MOCK_TEMP_PATH'] || "").join(''); - } - - return cmdString; - } - - // - // Exec - use for long running tools where you need to stream live output as it runs - // returns a promise with return code. - // - public execAsync(options?: IExecOptions): Promise { - this._debug('exec tool: ' + this.toolPath); - this._debug('Arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); - - var success = true; - options = options || {}; - - var ops: IExecOptions = { - cwd: options.cwd || process.cwd(), - env: options.env || process.env, - silent: options.silent || false, - outStream: options.outStream || process.stdout, - errStream: options.errStream || process.stderr, - failOnStdErr: options.failOnStdErr || false, - ignoreReturnCode: options.ignoreReturnCode || false, - windowsVerbatimArguments: options.windowsVerbatimArguments - }; - - var argString = this.args.join(' ') || ''; - var cmdString = this.toolPath; - if (argString) { - cmdString += (' ' + argString); - } - - // Using split/join to replace the temp path - cmdString = this.ignoreTempPath(cmdString); - - if (!ops.silent) { - if(this.pipeOutputToTool) { - var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; - var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); - if(pipeToolArgString) { - pipeToolCmdString += (' ' + pipeToolArgString); - } - - cmdString += ' | ' + pipeToolCmdString; - } - - ops.outStream.write('[command]' + cmdString + os.EOL); - } - - // TODO: filter process.env - var res = mock.getResponse('exec', cmdString, debug); - if (res.stdout) { - this.emit('stdout', res.stdout); - if (!ops.silent) { - ops.outStream.write(res.stdout + os.EOL); - } - const stdLineArray = res.stdout.split(os.EOL); - for (const line of stdLineArray.slice(0, -1)) { - this.emit('stdline', line); - } - if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { - this.emit('stdline', stdLineArray[stdLineArray.length - 1]); - } - } - - if (res.stderr) { - this.emit('stderr', res.stderr); - - success = !ops.failOnStdErr; - if (!ops.silent) { - var s = ops.failOnStdErr ? ops.errStream : ops.outStream; - s.write(res.stderr + os.EOL); - } - const stdErrArray = res.stderr.split(os.EOL); - for (const line of stdErrArray.slice(0, -1)) { - this.emit('errline', line); - } - if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { - this.emit('errline', stdErrArray[stdErrArray.length - 1]); - } - } - - - var code = res.code; - - if (!ops.silent) { - ops.outStream.write('rc:' + res.code + os.EOL); - } - - if (code != 0 && !ops.ignoreReturnCode) { - success = false; - } - - if (!ops.silent) { - ops.outStream.write('success:' + success + os.EOL); - } - - return new Promise((resolve, reject) => { - if (success) { - resolve(code); - } - else { - reject(new Error(this.toolPath + ' failed with return code: ' + code)); - } - }); - } - - /** - * Exec - use for long running tools where you need to stream live output as it runs - * @deprecated use `execAsync` instead - * @returns a promise with return code. - */ - public exec(options?: IExecOptions): Q.Promise { - var defer = Q.defer(); - - this._debug('exec tool: ' + this.toolPath); - this._debug('Arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); - - var success = true; - options = options || {}; - - var ops: IExecOptions = { - cwd: options.cwd || process.cwd(), - env: options.env || process.env, - silent: options.silent || false, - outStream: options.outStream || process.stdout, - errStream: options.errStream || process.stderr, - failOnStdErr: options.failOnStdErr || false, - ignoreReturnCode: options.ignoreReturnCode || false, - windowsVerbatimArguments: options.windowsVerbatimArguments - }; - - var argString = this.args.join(' ') || ''; - var cmdString = this.toolPath; - if (argString) { - cmdString += (' ' + argString); - } - - // Using split/join to replace the temp path - cmdString = this.ignoreTempPath(cmdString); - - if (!ops.silent) { - if(this.pipeOutputToTool) { - var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; - var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); - if(pipeToolArgString) { - pipeToolCmdString += (' ' + pipeToolArgString); - } - - cmdString += ' | ' + pipeToolCmdString; - } - - ops.outStream.write('[command]' + cmdString + os.EOL); - } - - // TODO: filter process.env - var res = mock.getResponse('exec', cmdString, debug); - if (res.stdout) { - this.emit('stdout', res.stdout); - if (!ops.silent) { - ops.outStream.write(res.stdout + os.EOL); - } - const stdLineArray = res.stdout.split(os.EOL); - for (const line of stdLineArray.slice(0, -1)) { - this.emit('stdline', line); - } - if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { - this.emit('stdline', stdLineArray[stdLineArray.length - 1]); - } - } - - if (res.stderr) { - this.emit('stderr', res.stderr); - - success = !ops.failOnStdErr; - if (!ops.silent) { - var s = ops.failOnStdErr ? ops.errStream : ops.outStream; - s.write(res.stderr + os.EOL); - } - const stdErrArray = res.stderr.split(os.EOL); - for (const line of stdErrArray.slice(0, -1)) { - this.emit('errline', line); - } - if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { - this.emit('errline', stdErrArray[stdErrArray.length - 1]); - } - } - - - var code = res.code; - - if (!ops.silent) { - ops.outStream.write('rc:' + res.code + os.EOL); - } - - if (code != 0 && !ops.ignoreReturnCode) { - success = false; - } - - if (!ops.silent) { - ops.outStream.write('success:' + success + os.EOL); - } - if (success) { - defer.resolve(code); - } - else { - defer.reject(new Error(this.toolPath + ' failed with return code: ' + code)); - } - - return >defer.promise; - } - - // - // ExecSync - use for short running simple commands. Simple and convenient (synchronous) - // but also has limits. For example, no live output and limited to max buffer - // - public execSync(options?: IExecSyncOptions): IExecSyncResult { - this._debug('exec tool: ' + this.toolPath); - this._debug('Arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); - - var success = true; - options = options || {}; - - var ops: IExecSyncOptions = { - cwd: options.cwd || process.cwd(), - env: options.env || process.env, - silent: options.silent || false, - outStream: options.outStream || process.stdout, - errStream: options.errStream || process.stderr, - windowsVerbatimArguments: options.windowsVerbatimArguments, - }; - - var argString = this.args.join(' ') || ''; - var cmdString = this.toolPath; - - // Using split/join to replace the temp path - cmdString = this.ignoreTempPath(cmdString); - - if (argString) { - cmdString += (' ' + argString); - } - - if (!ops.silent) { - ops.outStream.write('[command]' + cmdString + os.EOL); - } - - var r = mock.getResponse('exec', cmdString, debug); - if (!ops.silent && r.stdout && r.stdout.length > 0) { - ops.outStream.write(r.stdout); - } - - if (!ops.silent && r.stderr && r.stderr.length > 0) { - ops.errStream.write(r.stderr); - } - - return { - code: r.code, - stdout: (r.stdout) ? r.stdout.toString() : null, - stderr: (r.stderr) ? r.stderr.toString() : null - }; - } -} +import os = require('os'); +import events = require('events'); +import ma = require('./mock-answer'); + +let mock: ma.MockAnswers = new ma.MockAnswers(); + +export function setAnswers(answers: ma.TaskLibAnswers) { + mock.initialize(answers); +} + +export interface IExecOptions extends IExecSyncOptions { + failOnStdErr?: boolean; + ignoreReturnCode?: boolean; +}; + +export interface IExecSyncOptions { + cwd?: string; + env?: { [key: string]: string | undefined }; + silent?: boolean; + outStream: NodeJS.WritableStream; + errStream: NodeJS.WritableStream; + windowsVerbatimArguments?: boolean; +}; + +export interface IExecSyncResult { + stdout: string; + stderr: string; + code: number; + error: Error; +} + +export function debug(message) { + // do nothing, overridden +} + +export class ToolRunner extends events.EventEmitter { + constructor(toolPath: string) { + debug('toolRunner toolPath: ' + toolPath); + + super(); + + this.toolPath = toolPath; + this.args = []; + } + + private toolPath: string; + private args: string[]; + private pipeOutputToTool: ToolRunner | undefined; + + private _debug(message) { + debug(message); + this.emit('debug', message); + } + + private _argStringToArray(argString: string): string[] { + var args: string[] = []; + + var inQuotes = false; + var escaped =false; + var arg = ''; + + var append = function(c: string) { + // we only escape double quotes. + if (escaped && c !== '"') { + arg += '\\'; + } + + arg += c; + escaped = false; + } + + for (var i=0; i < argString.length; i++) { + var c = argString.charAt(i); + + if (c === '"') { + if (!escaped) { + inQuotes = !inQuotes; + } + else { + append(c); + } + continue; + } + + if (c === "\\" && inQuotes) { + escaped = true; + continue; + } + + if (c === ' ' && !inQuotes) { + if (arg.length > 0) { + args.push(arg); + arg = ''; + } + continue; + } + + append(c); + } + + if (arg.length > 0) { + args.push(arg.trim()); + } + + return args; + } + + public arg(val: any): ToolRunner { + if (!val) { + return this; + } + + if (val instanceof Array) { + this._debug(this.toolPath + ' arg: ' + JSON.stringify(val)); + this.args = this.args.concat(val); + } + else if (typeof(val) === 'string') { + this._debug(this.toolPath + ' arg: ' + val); + this.args = this.args.concat(val.trim()); + } + + return this; + } + + public argIf(condition: any, val: any): ToolRunner { + if (condition) { + this.arg(val); + } + + return this; + } + + public line(val: string): ToolRunner { + if (!val) { + return this; + } + + this._debug(this.toolPath + ' arg: ' + val); + this.args = this.args.concat(this._argStringToArray(val)); + return this; + } + + public pipeExecOutputToTool(tool: ToolRunner) : ToolRunner { + this.pipeOutputToTool = tool; + return this; + } + + private ignoreTempPath(cmdString: string): string { + this._debug('ignoreTempPath=' + process.env['MOCK_IGNORE_TEMP_PATH']); + this._debug('tempPath=' + process.env['MOCK_TEMP_PATH']); + if (process.env['MOCK_IGNORE_TEMP_PATH'] === 'true') { + // Using split/join to replace the temp path + cmdString = cmdString.split(process.env['MOCK_TEMP_PATH'] || "").join(''); + } + + return cmdString; + } + + // + // Exec - use for long running tools where you need to stream live output as it runs + // returns a promise with return code. + // + public execAsync(options?: IExecOptions): Promise { + this._debug('exec tool: ' + this.toolPath); + this._debug('Arguments:'); + this.args.forEach((arg) => { + this._debug(' ' + arg); + }); + + var success = true; + options = options || {}; + + var ops: IExecOptions = { + cwd: options.cwd || process.cwd(), + env: options.env || process.env, + silent: options.silent || false, + outStream: options.outStream || process.stdout, + errStream: options.errStream || process.stderr, + failOnStdErr: options.failOnStdErr || false, + ignoreReturnCode: options.ignoreReturnCode || false, + windowsVerbatimArguments: options.windowsVerbatimArguments + }; + + var argString = this.args.join(' ') || ''; + var cmdString = this.toolPath; + if (argString) { + cmdString += (' ' + argString); + } + + // Using split/join to replace the temp path + cmdString = this.ignoreTempPath(cmdString); + + if (!ops.silent) { + if(this.pipeOutputToTool) { + var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; + var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); + if(pipeToolArgString) { + pipeToolCmdString += (' ' + pipeToolArgString); + } + + cmdString += ' | ' + pipeToolCmdString; + } + + ops.outStream.write('[command]' + cmdString + os.EOL); + } + + // TODO: filter process.env + var res = mock.getResponse('exec', cmdString, debug); + if (res.stdout) { + this.emit('stdout', res.stdout); + if (!ops.silent) { + ops.outStream.write(res.stdout + os.EOL); + } + const stdLineArray = res.stdout.split(os.EOL); + for (const line of stdLineArray.slice(0, -1)) { + this.emit('stdline', line); + } + if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { + this.emit('stdline', stdLineArray[stdLineArray.length - 1]); + } + } + + if (res.stderr) { + this.emit('stderr', res.stderr); + + success = !ops.failOnStdErr; + if (!ops.silent) { + var s = ops.failOnStdErr ? ops.errStream : ops.outStream; + s.write(res.stderr + os.EOL); + } + const stdErrArray = res.stderr.split(os.EOL); + for (const line of stdErrArray.slice(0, -1)) { + this.emit('errline', line); + } + if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { + this.emit('errline', stdErrArray[stdErrArray.length - 1]); + } + } + + + var code = res.code; + + if (!ops.silent) { + ops.outStream.write('rc:' + res.code + os.EOL); + } + + if (code != 0 && !ops.ignoreReturnCode) { + success = false; + } + + if (!ops.silent) { + ops.outStream.write('success:' + success + os.EOL); + } + + return new Promise((resolve, reject) => { + if (success) { + resolve(code); + } + else { + reject(new Error(this.toolPath + ' failed with return code: ' + code)); + } + }); + } + + /** + * Exec - use for long running tools where you need to stream live output as it runs + * @deprecated use `execAsync` instead + * @returns a promise with return code. + */ + public exec(options?: IExecOptions): Promise { + return new Promise((resolve, reject) => { + this._debug('exec tool: ' + this.toolPath); + this._debug('Arguments:'); + this.args.forEach((arg) => { + this._debug(' ' + arg); + }); + + var success = true; + options = options || {}; + + var ops: IExecOptions = { + cwd: options.cwd || process.cwd(), + env: options.env || process.env, + silent: options.silent || false, + outStream: options.outStream || process.stdout, + errStream: options.errStream || process.stderr, + failOnStdErr: options.failOnStdErr || false, + ignoreReturnCode: options.ignoreReturnCode || false, + windowsVerbatimArguments: options.windowsVerbatimArguments + }; + + var argString = this.args.join(' ') || ''; + var cmdString = this.toolPath; + if (argString) { + cmdString += (' ' + argString); + } + + // Using split/join to replace the temp path + cmdString = this.ignoreTempPath(cmdString); + + if (!ops.silent) { + if(this.pipeOutputToTool) { + var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; + var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); + if(pipeToolArgString) { + pipeToolCmdString += (' ' + pipeToolArgString); + } + + cmdString += ' | ' + pipeToolCmdString; + } + + ops.outStream.write('[command]' + cmdString + os.EOL); + } + + // TODO: filter process.env + var res = mock.getResponse('exec', cmdString, debug); + if (res.stdout) { + this.emit('stdout', res.stdout); + if (!ops.silent) { + ops.outStream.write(res.stdout + os.EOL); + } + const stdLineArray = res.stdout.split(os.EOL); + for (const line of stdLineArray.slice(0, -1)) { + this.emit('stdline', line); + } + if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { + this.emit('stdline', stdLineArray[stdLineArray.length - 1]); + } + } + + if (res.stderr) { + this.emit('stderr', res.stderr); + + success = !ops.failOnStdErr; + if (!ops.silent) { + var s = ops.failOnStdErr ? ops.errStream : ops.outStream; + s.write(res.stderr + os.EOL); + } + const stdErrArray = res.stderr.split(os.EOL); + for (const line of stdErrArray.slice(0, -1)) { + this.emit('errline', line); + } + if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { + this.emit('errline', stdErrArray[stdErrArray.length - 1]); + } + } + + + var code = res.code; + + if (!ops.silent) { + ops.outStream.write('rc:' + res.code + os.EOL); + } + + if (code != 0 && !ops.ignoreReturnCode) { + success = false; + } + + if (!ops.silent) { + ops.outStream.write('success:' + success + os.EOL); + } + if (success) { + return resolve(code); + } + else { + return reject(new Error(this.toolPath + ' failed with return code: ' + code)); + } + }); + } + + // + // ExecSync - use for short running simple commands. Simple and convenient (synchronous) + // but also has limits. For example, no live output and limited to max buffer + // + public execSync(options?: IExecSyncOptions): IExecSyncResult { + this._debug('exec tool: ' + this.toolPath); + this._debug('Arguments:'); + this.args.forEach((arg) => { + this._debug(' ' + arg); + }); + + var success = true; + options = options || {}; + + var ops: IExecSyncOptions = { + cwd: options.cwd || process.cwd(), + env: options.env || process.env, + silent: options.silent || false, + outStream: options.outStream || process.stdout, + errStream: options.errStream || process.stderr, + windowsVerbatimArguments: options.windowsVerbatimArguments, + }; + + var argString = this.args.join(' ') || ''; + var cmdString = this.toolPath; + + // Using split/join to replace the temp path + cmdString = this.ignoreTempPath(cmdString); + + if (argString) { + cmdString += (' ' + argString); + } + + if (!ops.silent) { + ops.outStream.write('[command]' + cmdString + os.EOL); + } + + var r = mock.getResponse('exec', cmdString, debug); + if (!ops.silent && r.stdout && r.stdout.length > 0) { + ops.outStream.write(r.stdout); + } + + if (!ops.silent && r.stderr && r.stderr.length > 0) { + ops.errStream.write(r.stderr); + } + + return { + code: r.code, + stdout: (r.stdout) ? r.stdout.toString() : null, + stderr: (r.stderr) ? r.stderr.toString() : null + }; + } +} diff --git a/node/package-lock.json b/node/package-lock.json index 01c3085b1..2b50089d7 100644 --- a/node/package-lock.json +++ b/node/package-lock.json @@ -32,12 +32,6 @@ "integrity": "sha1-cUcXaFJ3TsTW3WJoA4iK32uZn+s=", "dev": true }, - "@types/q": { - "version": "1.5.8", - "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/@types/q/-/q-1.5.8.tgz", - "integrity": "sha1-lfbGoI8q2Gi6Iw6tHS1/e+PbODc=", - "dev": true - }, "@types/semver": { "version": "7.5.8", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/@types/semver/-/semver-7.5.8.tgz", @@ -674,11 +668,6 @@ "integrity": "sha1-O6ODNzNkbZ0+SZWUbBNlpn+wekI=", "dev": true }, - "q": { - "version": "1.5.1", - "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" - }, "randombytes": { "version": "2.1.0", "resolved": "https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/randombytes/-/randombytes-2.1.0.tgz", diff --git a/node/package.json b/node/package.json index 3073e290d..a6b526564 100644 --- a/node/package.json +++ b/node/package.json @@ -30,7 +30,6 @@ "adm-zip": "^0.5.10", "minimatch": "3.0.5", "nodejs-file-downloader": "^4.11.1", - "q": "^1.5.1", "semver": "^5.7.2", "shelljs": "^0.8.5", "uuid": "^3.0.1" @@ -39,7 +38,6 @@ "@types/minimatch": "3.0.3", "@types/mocha": "^9.1.1", "@types/node": "^16.11.39", - "@types/q": "^1.5.4", "@types/semver": "^7.3.4", "@types/shelljs": "^0.8.8", "mocha": "^9.2.2", diff --git a/node/task.ts b/node/task.ts index 7c11beb9a..81d715908 100644 --- a/node/task.ts +++ b/node/task.ts @@ -1,4 +1,3 @@ -import Q = require('q'); import shell = require('shelljs'); import childProcess = require('child_process'); import fs = require('fs'); @@ -1534,7 +1533,7 @@ export function execAsync(tool: string, args: any, options?: trm.IExecOptions): * @param options optional exec options. See IExecOptions * @returns number */ -export function exec(tool: string, args: any, options?: trm.IExecOptions): Q.Promise { +export function exec(tool: string, args: any, options?: trm.IExecOptions): Promise { let tr: trm.ToolRunner = this.tool(tool); if (args) { if (args instanceof Array) { diff --git a/node/toolrunner.ts b/node/toolrunner.ts index 17e102610..2826c01a9 100644 --- a/node/toolrunner.ts +++ b/node/toolrunner.ts @@ -1,4 +1,3 @@ -import Q = require('q'); import os = require('os'); import events = require('events'); import child = require('child_process'); @@ -799,203 +798,201 @@ export class ToolRunner extends events.EventEmitter { }); } - private execWithPiping(pipeOutputToTool: ToolRunner, options?: IExecOptions): Q.Promise { - var defer = Q.defer(); + private execWithPiping(pipeOutputToTool: ToolRunner, options?: IExecOptions): Promise { + return new Promise((resolve, reject) => { + this._debug('exec tool: ' + this.toolPath); + this._debug('arguments:'); + this.args.forEach((arg) => { + this._debug(' ' + arg); + }); - this._debug('exec tool: ' + this.toolPath); - this._debug('arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); + let success = true; + const optionsNonNull = this._cloneExecOptions(options); - let success = true; - const optionsNonNull = this._cloneExecOptions(options); + if (!optionsNonNull.silent) { + optionsNonNull.outStream!.write(this._getCommandString(optionsNonNull) + os.EOL); + } - if (!optionsNonNull.silent) { - optionsNonNull.outStream!.write(this._getCommandString(optionsNonNull) + os.EOL); - } + let cp: child.ChildProcess; + let toolPath: string = pipeOutputToTool.toolPath; + let toolPathFirst: string; + let successFirst = true; + let returnCodeFirst: number; + let fileStream: fs.WriteStream | null; + let waitingEvents: number = 0; // number of process or stream events we are waiting on to complete + let returnCode: number = 0; + let error: any; - let cp: child.ChildProcess; - let toolPath: string = pipeOutputToTool.toolPath; - let toolPathFirst: string; - let successFirst = true; - let returnCodeFirst: number; - let fileStream: fs.WriteStream | null; - let waitingEvents: number = 0; // number of process or stream events we are waiting on to complete - let returnCode: number = 0; - let error: any; + toolPathFirst = this.toolPath; - toolPathFirst = this.toolPath; + // Following node documentation example from this link on how to pipe output of one process to another + // https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options - // Following node documentation example from this link on how to pipe output of one process to another - // https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options + //start the child process for both tools + waitingEvents++; + var cpFirst = child.spawn( + this._getSpawnFileName(optionsNonNull), + this._getSpawnArgs(optionsNonNull), + this._getSpawnOptions(optionsNonNull)); - //start the child process for both tools - waitingEvents++; - var cpFirst = child.spawn( - this._getSpawnFileName(optionsNonNull), - this._getSpawnArgs(optionsNonNull), - this._getSpawnOptions(optionsNonNull)); + waitingEvents++; + cp = child.spawn( + pipeOutputToTool._getSpawnFileName(optionsNonNull), + pipeOutputToTool._getSpawnArgs(optionsNonNull), + pipeOutputToTool._getSpawnOptions(optionsNonNull)); - waitingEvents++; - cp = child.spawn( - pipeOutputToTool._getSpawnFileName(optionsNonNull), - pipeOutputToTool._getSpawnArgs(optionsNonNull), - pipeOutputToTool._getSpawnOptions(optionsNonNull)); + fileStream = this.pipeOutputToFile ? fs.createWriteStream(this.pipeOutputToFile) : null; + if (fileStream) { + waitingEvents++; + fileStream.on('finish', () => { + waitingEvents--; //file write is complete + fileStream = null; + if (waitingEvents == 0) { + if (error) { + return reject(error); + } else { + return resolve(returnCode); + } + } + }); + fileStream.on('error', (err: Error) => { + waitingEvents--; //there were errors writing to the file, write is done + this._debug(`Failed to pipe output of ${toolPathFirst} to file ${this.pipeOutputToFile}. Error = ${err}`); + fileStream = null; + if (waitingEvents == 0) { + if (error) { + return reject(error); + } else { + return resolve(returnCode); + } + } + }); + } - fileStream = this.pipeOutputToFile ? fs.createWriteStream(this.pipeOutputToFile) : null; - if (fileStream) { - waitingEvents++; - fileStream.on('finish', () => { - waitingEvents--; //file write is complete - fileStream = null; - if (waitingEvents == 0) { - if (error) { - defer.reject(error); - } else { - defer.resolve(returnCode); + //pipe stdout of first tool to stdin of second tool + cpFirst.stdout?.on('data', (data: Buffer) => { + try { + if (fileStream) { + fileStream.write(data); } + cp.stdin?.write(data); + } catch (err) { + this._debug('Failed to pipe output of ' + toolPathFirst + ' to ' + toolPath); + this._debug(toolPath + ' might have exited due to errors prematurely. Verify the arguments passed are valid.'); + } + }); + cpFirst.stderr?.on('data', (data: Buffer) => { + if (fileStream) { + fileStream.write(data); + } + successFirst = !optionsNonNull.failOnStdErr; + if (!optionsNonNull.silent) { + var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream! : optionsNonNull.outStream!; + s.write(data); } }); - fileStream.on('error', (err: Error) => { - waitingEvents--; //there were errors writing to the file, write is done - this._debug(`Failed to pipe output of ${toolPathFirst} to file ${this.pipeOutputToFile}. Error = ${err}`); - fileStream = null; + cpFirst.on('error', (err: Error) => { + waitingEvents--; //first process is complete with errors + if (fileStream) { + fileStream.end(); + } + cp.stdin?.end(); + error = new Error(toolPathFirst + ' failed. ' + err.message); if (waitingEvents == 0) { - if (error) { - defer.reject(error); - } else { - defer.resolve(returnCode); - } + return reject(error); } }); - } - - //pipe stdout of first tool to stdin of second tool - cpFirst.stdout?.on('data', (data: Buffer) => { - try { + cpFirst.on('close', (code: number, signal: any) => { + waitingEvents--; //first process is complete + if (code != 0 && !optionsNonNull.ignoreReturnCode) { + successFirst = false; + returnCodeFirst = code; + returnCode = returnCodeFirst; + } + this._debug('success of first tool:' + successFirst); if (fileStream) { - fileStream.write(data); + fileStream.end(); } - cp.stdin?.write(data); - } catch (err) { - this._debug('Failed to pipe output of ' + toolPathFirst + ' to ' + toolPath); - this._debug(toolPath + ' might have exited due to errors prematurely. Verify the arguments passed are valid.'); - } - }); - cpFirst.stderr?.on('data', (data: Buffer) => { - if (fileStream) { - fileStream.write(data); - } - successFirst = !optionsNonNull.failOnStdErr; - if (!optionsNonNull.silent) { - var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream! : optionsNonNull.outStream!; - s.write(data); - } - }); - cpFirst.on('error', (err: Error) => { - waitingEvents--; //first process is complete with errors - if (fileStream) { - fileStream.end(); - } - cp.stdin?.end(); - error = new Error(toolPathFirst + ' failed. ' + err.message); - if (waitingEvents == 0) { - defer.reject(error); - } - }); - cpFirst.on('close', (code: number, signal: any) => { - waitingEvents--; //first process is complete - if (code != 0 && !optionsNonNull.ignoreReturnCode) { - successFirst = false; - returnCodeFirst = code; - returnCode = returnCodeFirst; - } - this._debug('success of first tool:' + successFirst); - if (fileStream) { - fileStream.end(); - } - cp.stdin?.end(); - if (waitingEvents == 0) { - if (error) { - defer.reject(error); - } else { - defer.resolve(returnCode); + cp.stdin?.end(); + if (waitingEvents == 0) { + if (error) { + return reject(error); + } else { + return resolve(returnCode); + } } - } - }); + }); - let stdLineBuffer = ''; - cp.stdout?.on('data', (data: Buffer) => { - this.emit('stdout', data); + let stdLineBuffer = ''; + cp.stdout?.on('data', (data: Buffer) => { + this.emit('stdout', data); - if (!optionsNonNull.silent) { - optionsNonNull.outStream!.write(data); - } + if (!optionsNonNull.silent) { + optionsNonNull.outStream!.write(data); + } - stdLineBuffer = this._processLineBuffer(data, stdLineBuffer, (line: string) => { - this.emit('stdline', line); + stdLineBuffer = this._processLineBuffer(data, stdLineBuffer, (line: string) => { + this.emit('stdline', line); + }); }); - }); - let errLineBuffer = ''; - cp.stderr?.on('data', (data: Buffer) => { - this.emit('stderr', data); + let errLineBuffer = ''; + cp.stderr?.on('data', (data: Buffer) => { + this.emit('stderr', data); - success = !optionsNonNull.failOnStdErr; - if (!optionsNonNull.silent) { - var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream! : optionsNonNull.outStream!; - s.write(data); - } + success = !optionsNonNull.failOnStdErr; + if (!optionsNonNull.silent) { + var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream! : optionsNonNull.outStream!; + s.write(data); + } - errLineBuffer = this._processLineBuffer(data, errLineBuffer, (line: string) => { - this.emit('errline', line); + errLineBuffer = this._processLineBuffer(data, errLineBuffer, (line: string) => { + this.emit('errline', line); + }); }); - }); - cp.on('error', (err: Error) => { - waitingEvents--; //process is done with errors - error = new Error(toolPath + ' failed. ' + err.message); - if (waitingEvents == 0) { - defer.reject(error); - } - }); + cp.on('error', (err: Error) => { + waitingEvents--; //process is done with errors + error = new Error(toolPath + ' failed. ' + err.message); + if (waitingEvents == 0) { + return reject(error); + } + }); - cp.on('close', (code: number, signal: any) => { - waitingEvents--; //process is complete - this._debug('rc:' + code); - returnCode = code; + cp.on('close', (code: number, signal: any) => { + waitingEvents--; //process is complete + this._debug('rc:' + code); + returnCode = code; - if (stdLineBuffer.length > 0) { - this.emit('stdline', stdLineBuffer); - } + if (stdLineBuffer.length > 0) { + this.emit('stdline', stdLineBuffer); + } - if (errLineBuffer.length > 0) { - this.emit('errline', errLineBuffer); - } + if (errLineBuffer.length > 0) { + this.emit('errline', errLineBuffer); + } - if (code != 0 && !optionsNonNull.ignoreReturnCode) { - success = false; - } + if (code != 0 && !optionsNonNull.ignoreReturnCode) { + success = false; + } - this._debug('success:' + success); + this._debug('success:' + success); - if (!successFirst) { //in the case output is piped to another tool, check exit code of both tools - error = new Error(toolPathFirst + ' failed with return code: ' + returnCodeFirst); - } else if (!success) { - error = new Error(toolPath + ' failed with return code: ' + code); - } + if (!successFirst) { //in the case output is piped to another tool, check exit code of both tools + error = new Error(toolPathFirst + ' failed with return code: ' + returnCodeFirst); + } else if (!success) { + error = new Error(toolPath + ' failed with return code: ' + code); + } - if (waitingEvents == 0) { - if (error) { - defer.reject(error); - } else { - defer.resolve(returnCode); + if (waitingEvents == 0) { + if (error) { + return reject(error); + } else { + return resolve(returnCode); + } } - } + }); }); - - return >defer.promise; } /** @@ -1213,127 +1210,127 @@ export class ToolRunner extends events.EventEmitter { * @param options optional exec options. See IExecOptions * @returns number */ - public exec(options?: IExecOptions): Q.Promise { + public exec(options?: IExecOptions): Promise { if (this.pipeOutputToTool) { return this.execWithPiping(this.pipeOutputToTool, options); } - var defer = Q.defer(); - - this._debug('exec tool: ' + this.toolPath); - this._debug('arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); - - const optionsNonNull = this._cloneExecOptions(options); - if (!optionsNonNull.silent) { - optionsNonNull.outStream!.write(this._getCommandString(optionsNonNull) + os.EOL); - } - - let state = new ExecState(optionsNonNull, this.toolPath); - state.on('debug', (message: string) => { - this._debug(message); - }); + return new Promise((resolve, reject) => { + this._debug('exec tool: ' + this.toolPath); + this._debug('arguments:'); + this.args.forEach((arg) => { + this._debug(' ' + arg); + }); - let stdLineBuffer = ''; - let errLineBuffer = ''; - state.on('done', (error: Error, exitCode: number) => { - if (stdLineBuffer.length > 0) { - this.emit('stdline', stdLineBuffer); + const optionsNonNull = this._cloneExecOptions(options); + if (!optionsNonNull.silent) { + optionsNonNull.outStream!.write(this._getCommandString(optionsNonNull) + os.EOL); } - if (errLineBuffer.length > 0) { - this.emit('errline', errLineBuffer); - } + let state = new ExecState(optionsNonNull, this.toolPath); + state.on('debug', (message: string) => { + this._debug(message); + }); - if (cp) { - cp.removeAllListeners(); - } + let stdLineBuffer = ''; + let errLineBuffer = ''; + state.on('done', (error: Error, exitCode: number) => { + if (stdLineBuffer.length > 0) { + this.emit('stdline', stdLineBuffer); + } - if (error) { - defer.reject(error); - } - else { - defer.resolve(exitCode); - } - }); + if (errLineBuffer.length > 0) { + this.emit('errline', errLineBuffer); + } + if (cp) { + cp.removeAllListeners(); + } - // Edge case when the node itself cant's spawn and emit event - let cp: child.ChildProcess; - try { - cp = child.spawn(this._getSpawnFileName(options), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(options)); - } catch (error) { - state.processError = error.message; - state.processExited = true; - state.processClosed = true; - state.CheckComplete(); + if (error) { + return reject(error); + } + else { + return resolve(exitCode); + } + }); - return defer.promise; - } - this.childProcess = cp; - // it is possible for the child process to end its last line without a new line. - // because stdout is buffered, this causes the last line to not get sent to the parent - // stream. Adding this event forces a flush before the child streams are closed. - cp.stdout?.on('finish', () => { - if (!optionsNonNull.silent) { - optionsNonNull.outStream!.write(os.EOL); + // Edge case when the node itself cant's spawn and emit event + let cp: child.ChildProcess; + try { + cp = child.spawn(this._getSpawnFileName(options), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(options)); + } catch (error) { + state.processError = error.message; + state.processExited = true; + state.processClosed = true; + state.CheckComplete(); + + return Promise.resolve(); } - }); - cp.stdout?.on('data', (data: Buffer) => { - this.emit('stdout', data); + this.childProcess = cp; + // it is possible for the child process to end its last line without a new line. + // because stdout is buffered, this causes the last line to not get sent to the parent + // stream. Adding this event forces a flush before the child streams are closed. + cp.stdout?.on('finish', () => { + if (!optionsNonNull.silent) { + optionsNonNull.outStream!.write(os.EOL); + } + }); - if (!optionsNonNull.silent) { - optionsNonNull.outStream!.write(data); - } + cp.stdout?.on('data', (data: Buffer) => { + this.emit('stdout', data); - stdLineBuffer = this._processLineBuffer(data, stdLineBuffer, (line: string) => { - this.emit('stdline', line); + if (!optionsNonNull.silent) { + optionsNonNull.outStream!.write(data); + } + + stdLineBuffer = this._processLineBuffer(data, stdLineBuffer, (line: string) => { + this.emit('stdline', line); + }); }); - }); - cp.stderr?.on('data', (data: Buffer) => { - state.processStderr = true; - this.emit('stderr', data); + cp.stderr?.on('data', (data: Buffer) => { + state.processStderr = true; + this.emit('stderr', data); - if (!optionsNonNull.silent) { - var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream! : optionsNonNull.outStream!; - s.write(data); - } + if (!optionsNonNull.silent) { + var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream! : optionsNonNull.outStream!; + s.write(data); + } - errLineBuffer = this._processLineBuffer(data, errLineBuffer, (line: string) => { - this.emit('errline', line); + errLineBuffer = this._processLineBuffer(data, errLineBuffer, (line: string) => { + this.emit('errline', line); + }); }); - }); - cp.on('error', (err: Error) => { - state.processError = err.message; - state.processExited = true; - state.processClosed = true; - state.CheckComplete(); - }); + cp.on('error', (err: Error) => { + state.processError = err.message; + state.processExited = true; + state.processClosed = true; + state.CheckComplete(); + }); - // Do not write debug logs here. Sometimes stdio not closed yet and you can damage user output commands. - cp.on('exit', (code: number | null, signal: NodeJS.Signals | null) => { - state.processExitCode = code; - state.processExitSignal = signal; - state.processExited = true; - state.CheckComplete() - }); + // Do not write debug logs here. Sometimes stdio not closed yet and you can damage user output commands. + cp.on('exit', (code: number | null, signal: NodeJS.Signals | null) => { + state.processExitCode = code; + state.processExitSignal = signal; + state.processExited = true; + state.CheckComplete() + }); - cp.on('close', (code: number | null, signal: NodeJS.Signals | null) => { - state.processCloseCode = code; - state.processCloseSignal = signal; - state.processClosed = true; - state.processExited = true; - state.CheckComplete(); - }); + cp.on('close', (code: number | null, signal: NodeJS.Signals | null) => { + state.processCloseCode = code; + state.processCloseSignal = signal; + state.processClosed = true; + state.processExited = true; + state.CheckComplete(); + }); - return defer.promise; + return Promise.resolve(); + }); } /** From ce13f47af56a1efc2e36cac4849e8a9b0d001198 Mon Sep 17 00:00:00 2001 From: Ivan Duplenskikh <115665590+ivanduplenskikh@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:28:53 +0100 Subject: [PATCH 2/3] Change crlf to lf --- node/mock-task.ts | 1080 +++++++++++++++++++-------------------- node/mock-toolrunner.ts | 846 +++++++++++++++--------------- 2 files changed, 963 insertions(+), 963 deletions(-) diff --git a/node/mock-task.ts b/node/mock-task.ts index ed5bc1fd0..4aa986dea 100644 --- a/node/mock-task.ts +++ b/node/mock-task.ts @@ -1,541 +1,541 @@ -import path = require('path'); -import fs = require('fs'); -import task = require('./task'); -import tcm = require('./taskcommand'); -import trm = require('./mock-toolrunner'); -import ma = require('./mock-answer'); - -let mock: ma.MockAnswers = new ma.MockAnswers(); - -export function setAnswers(answers: ma.TaskLibAnswers) { - mock.initialize(answers); - trm.setAnswers(answers); -} - -//----------------------------------------------------- -// Enums -//----------------------------------------------------- - -module.exports.TaskResult = task.TaskResult; -module.exports.TaskState = task.TaskState; -module.exports.IssueType = task.IssueType; -module.exports.ArtifactType = task.ArtifactType; -module.exports.FieldType = task.FieldType; -module.exports.Platform = task.Platform; - -//----------------------------------------------------- -// Results and Exiting -//----------------------------------------------------- - -module.exports.setStdStream = task.setStdStream; -module.exports.setErrStream = task.setErrStream; -module.exports.setResult = task.setResult; -module.exports.setSanitizedResult = task.setSanitizedResult; - -//----------------------------------------------------- -// Loc Helpers -//----------------------------------------------------- -export function setResourcePath(path: string): void { - // nothing in mock -} - -export function loc(key: string, ...args: any[]): string { - let str: string = 'loc_mock_' + key; - if (args.length) { - str += ' ' + args.join(' '); - } - - return str; -} - -//----------------------------------------------------- -// Input Helpers -//----------------------------------------------------- -module.exports.assertAgent = task.assertAgent; -module.exports.getVariable = task.getVariable; -module.exports.getVariables = task.getVariables; -module.exports.setVariable = task.setVariable; -module.exports.setSecret = task.setSecret; -module.exports.getTaskVariable = task.getTaskVariable; -module.exports.setTaskVariable = task.setTaskVariable; -module.exports.getInput = task.getInput; -module.exports.getInputRequired = task.getInputRequired; -module.exports.getBoolInput = task.getBoolInput; -module.exports.getBoolFeatureFlag = task.getBoolFeatureFlag; -module.exports.getPipelineFeature = task.getPipelineFeature; -module.exports.getDelimitedInput = task.getDelimitedInput; -module.exports.filePathSupplied = task.filePathSupplied; - -function getPathInput(name: string, required?: boolean, check?: boolean): string { - var inval = module.exports.getInput(name, required); - if (inval) { - if (check) { - checkPath(inval, name); - } - } - return inval; -} -module.exports.getPathInput = getPathInput; - -function getPathInputRequired(name: string, check?: boolean): string { - return getPathInput(name, true, check)!; -} -module.exports.getPathInputRequired = getPathInputRequired; - -//----------------------------------------------------- -// Endpoint Helpers -//----------------------------------------------------- -module.exports.getEndpointUrl = task.getEndpointUrl; -module.exports.getEndpointUrlRequired = task.getEndpointUrlRequired; -module.exports.getEndpointDataParameter = task.getEndpointDataParameter; -module.exports.getEndpointDataParameterRequired = task.getEndpointDataParameterRequired; -module.exports.getEndpointAuthorizationScheme = task.getEndpointAuthorizationScheme; -module.exports.getEndpointAuthorizationSchemeRequired = task.getEndpointAuthorizationSchemeRequired; -module.exports.getEndpointAuthorizationParameter = task.getEndpointAuthorizationParameter; -module.exports.getEndpointAuthorizationParameterRequired = task.getEndpointAuthorizationParameterRequired; -module.exports.getEndpointAuthorization = task.getEndpointAuthorization; - -// TODO: should go away when task lib -export interface EndpointAuthorization { - parameters: { - [key: string]: string; - }; - scheme: string; -} - -//----------------------------------------------------- -// SecureFile Helpers -//----------------------------------------------------- -module.exports.getSecureFileName = task.getSecureFileName; -module.exports.getSecureFileTicket = task.getSecureFileTicket; - -//----------------------------------------------------- -// Fs Helpers -//----------------------------------------------------- - -export class FsStats implements fs.Stats { - private m_isFile: boolean = false; - private m_isDirectory: boolean = false; - private m_isBlockDevice: boolean = false; - private m_isCharacterDevice: boolean = false; - private m_isSymbolicLink: boolean = false; - private m_isFIFO: boolean = false; - private m_isSocket: boolean = false; - - dev: number = 0; - ino: number = 0; - mode: number = 0; - nlink: number = 0; - uid: number = 0; - gid: number = 0; - rdev: number = 0; - size: number = 0; - blksize: number = 0; - blocks: number = 0; - atime: Date = new Date(); - mtime: Date = new Date(); - ctime: Date = new Date(); - birthtime: Date = new Date(); - atimeMs: number; - mtimeMs: number; - ctimeMs: number; - birthtimeMs: number; - - setAnswers(mockResponses: any): void { - this.m_isFile = mockResponses['isFile'] || this.m_isFile; - this.m_isDirectory = mockResponses['isDirectory'] || this.m_isDirectory; - this.m_isBlockDevice = mockResponses['isBlockDevice'] || this.m_isBlockDevice; - this.m_isCharacterDevice = mockResponses['isCharacterDevice'] || this.m_isCharacterDevice; - this.m_isSymbolicLink = mockResponses['isSymbolicLink'] || this.m_isSymbolicLink; - this.m_isFIFO = mockResponses['isFIFO'] || this.m_isFIFO; - this.m_isSocket = mockResponses['isSocket'] || this.m_isSocket; - - this.dev = mockResponses['dev'] || this.dev; - this.ino = mockResponses['ino'] || this.ino; - this.mode = mockResponses['mode'] || this.mode; - this.nlink = mockResponses['nlink'] || this.nlink; - this.uid = mockResponses['uid'] || this.uid; - this.gid = mockResponses['gid'] || this.gid; - this.rdev = mockResponses['rdev'] || this.rdev; - this.size = mockResponses['size'] || this.size; - this.blksize = mockResponses['blksize'] || this.blksize; - this.blocks = mockResponses['blocks'] || this.blocks; - this.atime = mockResponses['atime'] || this.atime; - this.mtime = mockResponses['mtime'] || this.mtime; - this.ctime = mockResponses['ctime'] || this.ctime; - this.m_isSocket = mockResponses['isSocket'] || this.m_isSocket; - } - - isFile(): boolean { - return this.m_isFile; - } - - isDirectory(): boolean { - return this.m_isDirectory; - } - - isBlockDevice(): boolean { - return this.m_isBlockDevice; - } - - isCharacterDevice(): boolean { - return this.m_isCharacterDevice; - } - - isSymbolicLink(): boolean { - return this.m_isSymbolicLink; - } - - isFIFO(): boolean { - return this.m_isFIFO; - } - - isSocket(): boolean { - return this.m_isSocket; - } -} - -export function stats(path: string): FsStats { - var fsStats = new FsStats(); - fsStats.setAnswers(mock.getResponse('stats', path, module.exports.debug) || {}); - return fsStats; -} - -export function exist(path: string): boolean { - return mock.getResponse('exist', path, module.exports.debug) || false; -} - -export interface FsOptions { - encoding?:string; - mode?:number; - flag?:string; -} - -export function writeFile(file: string, data: string|Buffer, options?: string|FsOptions) { - //do nothing -} - -export function osType(): string { - return mock.getResponse('osType', 'osType', module.exports.debug); -} - -export function getPlatform(): task.Platform { - return mock.getResponse('getPlatform', 'getPlatform', module.exports.debug); -} - -export function getNodeMajorVersion(): Number { - return mock.getResponse('getNodeMajorVersion', 'getNodeMajorVersion', module.exports.debug); -} - -export function getAgentMode(): task.AgentHostedMode { - return mock.getResponse('getAgentMode', 'getAgentMode', module.exports.debug); -} - -export function cwd(): string { - return mock.getResponse('cwd', 'cwd', module.exports.debug); -} - -//----------------------------------------------------- -// Cmd Helpers -//----------------------------------------------------- -module.exports.command = task.command; -module.exports.warning = task.warning; -module.exports.error = task.error; -module.exports.debug = task.debug; - -export function cd(path: string): void { - // do nothing. TODO: keep stack with asserts -} - -export function pushd(path: string): void { - // do nothing. TODO: keep stack with asserts -} - -export function popd(): void { - // do nothing. TODO: keep stack with asserts -} - -//------------------------------------------------ -// Validation Helpers -//------------------------------------------------ - -export function checkPath(p: string, name: string): void { - module.exports.debug('check path : ' + p); - if (!p || !mock.getResponse('checkPath', p, module.exports.debug)) { - throw new Error('Not found ' + p); - } -} - -//----------------------------------------------------- -// Shell/File I/O Helpers -// Abstract these away so we can -// - default to good error handling -// - inject system.debug info -// - have option to switch internal impl (shelljs now) -//----------------------------------------------------- -export function mkdirP(p): void { - module.exports.debug('creating path: ' + p); -} - -export function resolve(): string { - // we can't do ...param if we target ES6 and node 5. This is what <=ES5 compiles down to. - //return the posix implementation in the mock, so paths will be consistent when L0 tests are run on Windows or Mac/Linux - var absolutePath = path.posix.resolve.apply(this, arguments); - module.exports.debug('Absolute path for pathSegments: ' + arguments + ' = ' + absolutePath); - return absolutePath; -} - -export function which(tool: string, check?: boolean): string { - var response = mock.getResponse('which', tool, module.exports.debug); - if (check) { - checkPath(response, tool); - } - return response; -} - -export function ls(options: string, paths: string[]): string[] { - var response = mock.getResponse('ls', paths[0], module.exports.debug); - if(!response){ - return []; - } - return response; -} - -export function cp(source: string, dest: string): void { - module.exports.debug('###copying###'); - module.exports.debug('copying ' + source + ' to ' + dest); -} - -export function retry(func: Function, args: any[], retryOptions: task.RetryOptions): any { - module.exports.debug(`trying to execute ${func?.name}(${args.toString()}) with ${retryOptions.retryCount} retries`); -} - -export function find(findPath: string): string[] { - return mock.getResponse('find', findPath, module.exports.debug); -} - -export function rmRF(path: string): void { - module.exports.debug('rmRF ' + path); - var response = mock.getResponse('rmRF', path, module.exports.debug); - if (!response['success']) { - module.exports.setResult(1, response['message']); - } -} - -export function mv(source: string, dest: string, force: boolean, continueOnError?: boolean): boolean { - module.exports.debug('moving ' + source + ' to ' + dest); - return true; -} - -//----------------------------------------------------- -// Exec convenience wrapper -//----------------------------------------------------- -export function exec(tool: string, args: any, options?: trm.IExecOptions): Promise { - var toolPath = which(tool, true); - var tr: trm.ToolRunner = this.tool(toolPath); - if (args) { - tr.arg(args); - } - return tr.exec(options); -} - -//----------------------------------------------------- -// Exec convenience wrapper -//----------------------------------------------------- -export function execAsync(tool: string, args: any, options?: trm.IExecOptions): Promise { - var toolPath = which(tool, true); - var tr: trm.ToolRunner = this.tool(toolPath); - if (args) { - tr.arg(args); - } - return tr.execAsync(options); -} - -export function execSync(tool: string, args: any, options?: trm.IExecSyncOptions): trm.IExecSyncResult { - var toolPath = which(tool, true); - var tr: trm.ToolRunner = this.tool(toolPath); - if (args) { - tr.arg(args); - } - - return tr.execSync(options); -} - -export function tool(tool: string): trm.ToolRunner { - var tr: trm.ToolRunner = new trm.ToolRunner(tool); - tr.on('debug', (message: string) => { - module.exports.debug(message); - }) - - return tr; -} - -//----------------------------------------------------- -// Matching helpers -//----------------------------------------------------- -module.exports.filter = task.filter; -module.exports.match = task.match; - -// redefine to avoid folks having to typings install minimatch -export interface MatchOptions { - debug?: boolean; - nobrace?: boolean; - noglobstar?: boolean; - dot?: boolean; - noext?: boolean; - nocase?: boolean; - nonull?: boolean; - matchBase?: boolean; - nocomment?: boolean; - nonegate?: boolean; - flipNegate?: boolean; -} - -export function findMatch(defaultRoot: string, patterns: string[] | string) : string[] { - let responseKey: string = typeof patterns == 'object' ? (patterns as string[]).join('\n') : patterns as string; - return mock.getResponse('findMatch', responseKey, module.exports.debug); -} - -export function legacyFindFiles(rootDirectory: string, pattern: string, includeFiles?: boolean, includeDirectories?: boolean) : string[] { - return mock.getResponse('legacyFindFiles', pattern, module.exports.debug); -} - -//----------------------------------------------------- -// Test Publisher -//----------------------------------------------------- -export class TestPublisher { - constructor(public testRunner: string) { - } - - public publish(resultFiles?: string, mergeResults?: string, platform?: string, config?: string, runTitle?: string, publishRunAttachments?: string) { - - var properties = <{ [key: string]: string }>{}; - properties['type'] = this.testRunner; - - if (mergeResults) { - properties['mergeResults'] = mergeResults; - } - - if (platform) { - properties['platform'] = platform; - } - - if (config) { - properties['config'] = config; - } - - if (runTitle) { - properties['runTitle'] = runTitle; - } - - if (publishRunAttachments) { - properties['publishRunAttachments'] = publishRunAttachments; - } - - if (resultFiles) { - properties['resultFiles'] = resultFiles; - } - - module.exports.command('results.publish', properties, ''); - } -} - -//----------------------------------------------------- -// Code Coverage Publisher -//----------------------------------------------------- -export class CodeCoveragePublisher { - constructor() { - } - public publish(codeCoverageTool?: string, summaryFileLocation?: string, reportDirectory?: string, additionalCodeCoverageFiles?: string) { - - var properties = <{ [key: string]: string }>{}; - - if (codeCoverageTool) { - properties['codecoveragetool'] = codeCoverageTool; - } - - if (summaryFileLocation) { - properties['summaryfile'] = summaryFileLocation; - } - - if (reportDirectory) { - properties['reportdirectory'] = reportDirectory; - } - - if (additionalCodeCoverageFiles) { - properties['additionalcodecoveragefiles'] = additionalCodeCoverageFiles; - } - - module.exports.command('codecoverage.publish', properties, ""); - } -} - -//----------------------------------------------------- -// Code coverage Publisher -//----------------------------------------------------- -export class CodeCoverageEnabler { - private buildTool: string; - private ccTool: string; - - constructor(buildTool: string, ccTool: string) { - this.buildTool = buildTool; - this.ccTool = ccTool; - } - - public enableCodeCoverage(buildProps: { [key: string]: string }) { - buildProps['buildtool'] = this.buildTool; - buildProps['codecoveragetool'] = this.ccTool; - module.exports.command('codecoverage.enable', buildProps, ""); - } -} - -//----------------------------------------------------- -// Task Logging Commands -//----------------------------------------------------- -exports.uploadFile = task.uploadFile; -exports.prependPath = task.prependPath; -exports.uploadSummary = task.uploadSummary; -exports.addAttachment = task.addAttachment; -exports.setEndpoint = task.setEndpoint; -exports.setProgress = task.setProgress; -exports.logDetail = task.logDetail; -exports.logIssue = task.logIssue; - -//----------------------------------------------------- -// Artifact Logging Commands -//----------------------------------------------------- -exports.uploadArtifact = task.uploadArtifact; -exports.associateArtifact = task.associateArtifact; - -//----------------------------------------------------- -// Build Logging Commands -//----------------------------------------------------- -exports.uploadBuildLog = task.uploadBuildLog; -exports.updateBuildNumber = task.updateBuildNumber; -exports.addBuildTag = task.addBuildTag; - -//----------------------------------------------------- -// Release Logging Commands -//----------------------------------------------------- -exports.updateReleaseName = task.updateReleaseName; - -//----------------------------------------------------- -// Tools -//----------------------------------------------------- -exports.TaskCommand = tcm.TaskCommand; -exports.commandFromString = tcm.commandFromString; -exports.ToolRunner = trm.ToolRunner; - -//----------------------------------------------------- -// Http Proxy Helper -//----------------------------------------------------- -export function getHttpProxyConfiguration(requestUrl?: string): task.ProxyConfiguration | null { - return null; -} - -//----------------------------------------------------- -// Http Certificate Helper -//----------------------------------------------------- -export function getHttpCertConfiguration(): task.CertConfiguration | null { - return null +import path = require('path'); +import fs = require('fs'); +import task = require('./task'); +import tcm = require('./taskcommand'); +import trm = require('./mock-toolrunner'); +import ma = require('./mock-answer'); + +let mock: ma.MockAnswers = new ma.MockAnswers(); + +export function setAnswers(answers: ma.TaskLibAnswers) { + mock.initialize(answers); + trm.setAnswers(answers); +} + +//----------------------------------------------------- +// Enums +//----------------------------------------------------- + +module.exports.TaskResult = task.TaskResult; +module.exports.TaskState = task.TaskState; +module.exports.IssueType = task.IssueType; +module.exports.ArtifactType = task.ArtifactType; +module.exports.FieldType = task.FieldType; +module.exports.Platform = task.Platform; + +//----------------------------------------------------- +// Results and Exiting +//----------------------------------------------------- + +module.exports.setStdStream = task.setStdStream; +module.exports.setErrStream = task.setErrStream; +module.exports.setResult = task.setResult; +module.exports.setSanitizedResult = task.setSanitizedResult; + +//----------------------------------------------------- +// Loc Helpers +//----------------------------------------------------- +export function setResourcePath(path: string): void { + // nothing in mock +} + +export function loc(key: string, ...args: any[]): string { + let str: string = 'loc_mock_' + key; + if (args.length) { + str += ' ' + args.join(' '); + } + + return str; +} + +//----------------------------------------------------- +// Input Helpers +//----------------------------------------------------- +module.exports.assertAgent = task.assertAgent; +module.exports.getVariable = task.getVariable; +module.exports.getVariables = task.getVariables; +module.exports.setVariable = task.setVariable; +module.exports.setSecret = task.setSecret; +module.exports.getTaskVariable = task.getTaskVariable; +module.exports.setTaskVariable = task.setTaskVariable; +module.exports.getInput = task.getInput; +module.exports.getInputRequired = task.getInputRequired; +module.exports.getBoolInput = task.getBoolInput; +module.exports.getBoolFeatureFlag = task.getBoolFeatureFlag; +module.exports.getPipelineFeature = task.getPipelineFeature; +module.exports.getDelimitedInput = task.getDelimitedInput; +module.exports.filePathSupplied = task.filePathSupplied; + +function getPathInput(name: string, required?: boolean, check?: boolean): string { + var inval = module.exports.getInput(name, required); + if (inval) { + if (check) { + checkPath(inval, name); + } + } + return inval; +} +module.exports.getPathInput = getPathInput; + +function getPathInputRequired(name: string, check?: boolean): string { + return getPathInput(name, true, check)!; +} +module.exports.getPathInputRequired = getPathInputRequired; + +//----------------------------------------------------- +// Endpoint Helpers +//----------------------------------------------------- +module.exports.getEndpointUrl = task.getEndpointUrl; +module.exports.getEndpointUrlRequired = task.getEndpointUrlRequired; +module.exports.getEndpointDataParameter = task.getEndpointDataParameter; +module.exports.getEndpointDataParameterRequired = task.getEndpointDataParameterRequired; +module.exports.getEndpointAuthorizationScheme = task.getEndpointAuthorizationScheme; +module.exports.getEndpointAuthorizationSchemeRequired = task.getEndpointAuthorizationSchemeRequired; +module.exports.getEndpointAuthorizationParameter = task.getEndpointAuthorizationParameter; +module.exports.getEndpointAuthorizationParameterRequired = task.getEndpointAuthorizationParameterRequired; +module.exports.getEndpointAuthorization = task.getEndpointAuthorization; + +// TODO: should go away when task lib +export interface EndpointAuthorization { + parameters: { + [key: string]: string; + }; + scheme: string; +} + +//----------------------------------------------------- +// SecureFile Helpers +//----------------------------------------------------- +module.exports.getSecureFileName = task.getSecureFileName; +module.exports.getSecureFileTicket = task.getSecureFileTicket; + +//----------------------------------------------------- +// Fs Helpers +//----------------------------------------------------- + +export class FsStats implements fs.Stats { + private m_isFile: boolean = false; + private m_isDirectory: boolean = false; + private m_isBlockDevice: boolean = false; + private m_isCharacterDevice: boolean = false; + private m_isSymbolicLink: boolean = false; + private m_isFIFO: boolean = false; + private m_isSocket: boolean = false; + + dev: number = 0; + ino: number = 0; + mode: number = 0; + nlink: number = 0; + uid: number = 0; + gid: number = 0; + rdev: number = 0; + size: number = 0; + blksize: number = 0; + blocks: number = 0; + atime: Date = new Date(); + mtime: Date = new Date(); + ctime: Date = new Date(); + birthtime: Date = new Date(); + atimeMs: number; + mtimeMs: number; + ctimeMs: number; + birthtimeMs: number; + + setAnswers(mockResponses: any): void { + this.m_isFile = mockResponses['isFile'] || this.m_isFile; + this.m_isDirectory = mockResponses['isDirectory'] || this.m_isDirectory; + this.m_isBlockDevice = mockResponses['isBlockDevice'] || this.m_isBlockDevice; + this.m_isCharacterDevice = mockResponses['isCharacterDevice'] || this.m_isCharacterDevice; + this.m_isSymbolicLink = mockResponses['isSymbolicLink'] || this.m_isSymbolicLink; + this.m_isFIFO = mockResponses['isFIFO'] || this.m_isFIFO; + this.m_isSocket = mockResponses['isSocket'] || this.m_isSocket; + + this.dev = mockResponses['dev'] || this.dev; + this.ino = mockResponses['ino'] || this.ino; + this.mode = mockResponses['mode'] || this.mode; + this.nlink = mockResponses['nlink'] || this.nlink; + this.uid = mockResponses['uid'] || this.uid; + this.gid = mockResponses['gid'] || this.gid; + this.rdev = mockResponses['rdev'] || this.rdev; + this.size = mockResponses['size'] || this.size; + this.blksize = mockResponses['blksize'] || this.blksize; + this.blocks = mockResponses['blocks'] || this.blocks; + this.atime = mockResponses['atime'] || this.atime; + this.mtime = mockResponses['mtime'] || this.mtime; + this.ctime = mockResponses['ctime'] || this.ctime; + this.m_isSocket = mockResponses['isSocket'] || this.m_isSocket; + } + + isFile(): boolean { + return this.m_isFile; + } + + isDirectory(): boolean { + return this.m_isDirectory; + } + + isBlockDevice(): boolean { + return this.m_isBlockDevice; + } + + isCharacterDevice(): boolean { + return this.m_isCharacterDevice; + } + + isSymbolicLink(): boolean { + return this.m_isSymbolicLink; + } + + isFIFO(): boolean { + return this.m_isFIFO; + } + + isSocket(): boolean { + return this.m_isSocket; + } +} + +export function stats(path: string): FsStats { + var fsStats = new FsStats(); + fsStats.setAnswers(mock.getResponse('stats', path, module.exports.debug) || {}); + return fsStats; +} + +export function exist(path: string): boolean { + return mock.getResponse('exist', path, module.exports.debug) || false; +} + +export interface FsOptions { + encoding?:string; + mode?:number; + flag?:string; +} + +export function writeFile(file: string, data: string|Buffer, options?: string|FsOptions) { + //do nothing +} + +export function osType(): string { + return mock.getResponse('osType', 'osType', module.exports.debug); +} + +export function getPlatform(): task.Platform { + return mock.getResponse('getPlatform', 'getPlatform', module.exports.debug); +} + +export function getNodeMajorVersion(): Number { + return mock.getResponse('getNodeMajorVersion', 'getNodeMajorVersion', module.exports.debug); +} + +export function getAgentMode(): task.AgentHostedMode { + return mock.getResponse('getAgentMode', 'getAgentMode', module.exports.debug); +} + +export function cwd(): string { + return mock.getResponse('cwd', 'cwd', module.exports.debug); +} + +//----------------------------------------------------- +// Cmd Helpers +//----------------------------------------------------- +module.exports.command = task.command; +module.exports.warning = task.warning; +module.exports.error = task.error; +module.exports.debug = task.debug; + +export function cd(path: string): void { + // do nothing. TODO: keep stack with asserts +} + +export function pushd(path: string): void { + // do nothing. TODO: keep stack with asserts +} + +export function popd(): void { + // do nothing. TODO: keep stack with asserts +} + +//------------------------------------------------ +// Validation Helpers +//------------------------------------------------ + +export function checkPath(p: string, name: string): void { + module.exports.debug('check path : ' + p); + if (!p || !mock.getResponse('checkPath', p, module.exports.debug)) { + throw new Error('Not found ' + p); + } +} + +//----------------------------------------------------- +// Shell/File I/O Helpers +// Abstract these away so we can +// - default to good error handling +// - inject system.debug info +// - have option to switch internal impl (shelljs now) +//----------------------------------------------------- +export function mkdirP(p): void { + module.exports.debug('creating path: ' + p); +} + +export function resolve(): string { + // we can't do ...param if we target ES6 and node 5. This is what <=ES5 compiles down to. + //return the posix implementation in the mock, so paths will be consistent when L0 tests are run on Windows or Mac/Linux + var absolutePath = path.posix.resolve.apply(this, arguments); + module.exports.debug('Absolute path for pathSegments: ' + arguments + ' = ' + absolutePath); + return absolutePath; +} + +export function which(tool: string, check?: boolean): string { + var response = mock.getResponse('which', tool, module.exports.debug); + if (check) { + checkPath(response, tool); + } + return response; +} + +export function ls(options: string, paths: string[]): string[] { + var response = mock.getResponse('ls', paths[0], module.exports.debug); + if(!response){ + return []; + } + return response; +} + +export function cp(source: string, dest: string): void { + module.exports.debug('###copying###'); + module.exports.debug('copying ' + source + ' to ' + dest); +} + +export function retry(func: Function, args: any[], retryOptions: task.RetryOptions): any { + module.exports.debug(`trying to execute ${func?.name}(${args.toString()}) with ${retryOptions.retryCount} retries`); +} + +export function find(findPath: string): string[] { + return mock.getResponse('find', findPath, module.exports.debug); +} + +export function rmRF(path: string): void { + module.exports.debug('rmRF ' + path); + var response = mock.getResponse('rmRF', path, module.exports.debug); + if (!response['success']) { + module.exports.setResult(1, response['message']); + } +} + +export function mv(source: string, dest: string, force: boolean, continueOnError?: boolean): boolean { + module.exports.debug('moving ' + source + ' to ' + dest); + return true; +} + +//----------------------------------------------------- +// Exec convenience wrapper +//----------------------------------------------------- +export function exec(tool: string, args: any, options?: trm.IExecOptions): Promise { + var toolPath = which(tool, true); + var tr: trm.ToolRunner = this.tool(toolPath); + if (args) { + tr.arg(args); + } + return tr.exec(options); +} + +//----------------------------------------------------- +// Exec convenience wrapper +//----------------------------------------------------- +export function execAsync(tool: string, args: any, options?: trm.IExecOptions): Promise { + var toolPath = which(tool, true); + var tr: trm.ToolRunner = this.tool(toolPath); + if (args) { + tr.arg(args); + } + return tr.execAsync(options); +} + +export function execSync(tool: string, args: any, options?: trm.IExecSyncOptions): trm.IExecSyncResult { + var toolPath = which(tool, true); + var tr: trm.ToolRunner = this.tool(toolPath); + if (args) { + tr.arg(args); + } + + return tr.execSync(options); +} + +export function tool(tool: string): trm.ToolRunner { + var tr: trm.ToolRunner = new trm.ToolRunner(tool); + tr.on('debug', (message: string) => { + module.exports.debug(message); + }) + + return tr; +} + +//----------------------------------------------------- +// Matching helpers +//----------------------------------------------------- +module.exports.filter = task.filter; +module.exports.match = task.match; + +// redefine to avoid folks having to typings install minimatch +export interface MatchOptions { + debug?: boolean; + nobrace?: boolean; + noglobstar?: boolean; + dot?: boolean; + noext?: boolean; + nocase?: boolean; + nonull?: boolean; + matchBase?: boolean; + nocomment?: boolean; + nonegate?: boolean; + flipNegate?: boolean; +} + +export function findMatch(defaultRoot: string, patterns: string[] | string) : string[] { + let responseKey: string = typeof patterns == 'object' ? (patterns as string[]).join('\n') : patterns as string; + return mock.getResponse('findMatch', responseKey, module.exports.debug); +} + +export function legacyFindFiles(rootDirectory: string, pattern: string, includeFiles?: boolean, includeDirectories?: boolean) : string[] { + return mock.getResponse('legacyFindFiles', pattern, module.exports.debug); +} + +//----------------------------------------------------- +// Test Publisher +//----------------------------------------------------- +export class TestPublisher { + constructor(public testRunner: string) { + } + + public publish(resultFiles?: string, mergeResults?: string, platform?: string, config?: string, runTitle?: string, publishRunAttachments?: string) { + + var properties = <{ [key: string]: string }>{}; + properties['type'] = this.testRunner; + + if (mergeResults) { + properties['mergeResults'] = mergeResults; + } + + if (platform) { + properties['platform'] = platform; + } + + if (config) { + properties['config'] = config; + } + + if (runTitle) { + properties['runTitle'] = runTitle; + } + + if (publishRunAttachments) { + properties['publishRunAttachments'] = publishRunAttachments; + } + + if (resultFiles) { + properties['resultFiles'] = resultFiles; + } + + module.exports.command('results.publish', properties, ''); + } +} + +//----------------------------------------------------- +// Code Coverage Publisher +//----------------------------------------------------- +export class CodeCoveragePublisher { + constructor() { + } + public publish(codeCoverageTool?: string, summaryFileLocation?: string, reportDirectory?: string, additionalCodeCoverageFiles?: string) { + + var properties = <{ [key: string]: string }>{}; + + if (codeCoverageTool) { + properties['codecoveragetool'] = codeCoverageTool; + } + + if (summaryFileLocation) { + properties['summaryfile'] = summaryFileLocation; + } + + if (reportDirectory) { + properties['reportdirectory'] = reportDirectory; + } + + if (additionalCodeCoverageFiles) { + properties['additionalcodecoveragefiles'] = additionalCodeCoverageFiles; + } + + module.exports.command('codecoverage.publish', properties, ""); + } +} + +//----------------------------------------------------- +// Code coverage Publisher +//----------------------------------------------------- +export class CodeCoverageEnabler { + private buildTool: string; + private ccTool: string; + + constructor(buildTool: string, ccTool: string) { + this.buildTool = buildTool; + this.ccTool = ccTool; + } + + public enableCodeCoverage(buildProps: { [key: string]: string }) { + buildProps['buildtool'] = this.buildTool; + buildProps['codecoveragetool'] = this.ccTool; + module.exports.command('codecoverage.enable', buildProps, ""); + } +} + +//----------------------------------------------------- +// Task Logging Commands +//----------------------------------------------------- +exports.uploadFile = task.uploadFile; +exports.prependPath = task.prependPath; +exports.uploadSummary = task.uploadSummary; +exports.addAttachment = task.addAttachment; +exports.setEndpoint = task.setEndpoint; +exports.setProgress = task.setProgress; +exports.logDetail = task.logDetail; +exports.logIssue = task.logIssue; + +//----------------------------------------------------- +// Artifact Logging Commands +//----------------------------------------------------- +exports.uploadArtifact = task.uploadArtifact; +exports.associateArtifact = task.associateArtifact; + +//----------------------------------------------------- +// Build Logging Commands +//----------------------------------------------------- +exports.uploadBuildLog = task.uploadBuildLog; +exports.updateBuildNumber = task.updateBuildNumber; +exports.addBuildTag = task.addBuildTag; + +//----------------------------------------------------- +// Release Logging Commands +//----------------------------------------------------- +exports.updateReleaseName = task.updateReleaseName; + +//----------------------------------------------------- +// Tools +//----------------------------------------------------- +exports.TaskCommand = tcm.TaskCommand; +exports.commandFromString = tcm.commandFromString; +exports.ToolRunner = trm.ToolRunner; + +//----------------------------------------------------- +// Http Proxy Helper +//----------------------------------------------------- +export function getHttpProxyConfiguration(requestUrl?: string): task.ProxyConfiguration | null { + return null; +} + +//----------------------------------------------------- +// Http Certificate Helper +//----------------------------------------------------- +export function getHttpCertConfiguration(): task.CertConfiguration | null { + return null } \ No newline at end of file diff --git a/node/mock-toolrunner.ts b/node/mock-toolrunner.ts index 95c59ebf6..51bd51b6d 100644 --- a/node/mock-toolrunner.ts +++ b/node/mock-toolrunner.ts @@ -1,423 +1,423 @@ -import os = require('os'); -import events = require('events'); -import ma = require('./mock-answer'); - -let mock: ma.MockAnswers = new ma.MockAnswers(); - -export function setAnswers(answers: ma.TaskLibAnswers) { - mock.initialize(answers); -} - -export interface IExecOptions extends IExecSyncOptions { - failOnStdErr?: boolean; - ignoreReturnCode?: boolean; -}; - -export interface IExecSyncOptions { - cwd?: string; - env?: { [key: string]: string | undefined }; - silent?: boolean; - outStream: NodeJS.WritableStream; - errStream: NodeJS.WritableStream; - windowsVerbatimArguments?: boolean; -}; - -export interface IExecSyncResult { - stdout: string; - stderr: string; - code: number; - error: Error; -} - -export function debug(message) { - // do nothing, overridden -} - -export class ToolRunner extends events.EventEmitter { - constructor(toolPath: string) { - debug('toolRunner toolPath: ' + toolPath); - - super(); - - this.toolPath = toolPath; - this.args = []; - } - - private toolPath: string; - private args: string[]; - private pipeOutputToTool: ToolRunner | undefined; - - private _debug(message) { - debug(message); - this.emit('debug', message); - } - - private _argStringToArray(argString: string): string[] { - var args: string[] = []; - - var inQuotes = false; - var escaped =false; - var arg = ''; - - var append = function(c: string) { - // we only escape double quotes. - if (escaped && c !== '"') { - arg += '\\'; - } - - arg += c; - escaped = false; - } - - for (var i=0; i < argString.length; i++) { - var c = argString.charAt(i); - - if (c === '"') { - if (!escaped) { - inQuotes = !inQuotes; - } - else { - append(c); - } - continue; - } - - if (c === "\\" && inQuotes) { - escaped = true; - continue; - } - - if (c === ' ' && !inQuotes) { - if (arg.length > 0) { - args.push(arg); - arg = ''; - } - continue; - } - - append(c); - } - - if (arg.length > 0) { - args.push(arg.trim()); - } - - return args; - } - - public arg(val: any): ToolRunner { - if (!val) { - return this; - } - - if (val instanceof Array) { - this._debug(this.toolPath + ' arg: ' + JSON.stringify(val)); - this.args = this.args.concat(val); - } - else if (typeof(val) === 'string') { - this._debug(this.toolPath + ' arg: ' + val); - this.args = this.args.concat(val.trim()); - } - - return this; - } - - public argIf(condition: any, val: any): ToolRunner { - if (condition) { - this.arg(val); - } - - return this; - } - - public line(val: string): ToolRunner { - if (!val) { - return this; - } - - this._debug(this.toolPath + ' arg: ' + val); - this.args = this.args.concat(this._argStringToArray(val)); - return this; - } - - public pipeExecOutputToTool(tool: ToolRunner) : ToolRunner { - this.pipeOutputToTool = tool; - return this; - } - - private ignoreTempPath(cmdString: string): string { - this._debug('ignoreTempPath=' + process.env['MOCK_IGNORE_TEMP_PATH']); - this._debug('tempPath=' + process.env['MOCK_TEMP_PATH']); - if (process.env['MOCK_IGNORE_TEMP_PATH'] === 'true') { - // Using split/join to replace the temp path - cmdString = cmdString.split(process.env['MOCK_TEMP_PATH'] || "").join(''); - } - - return cmdString; - } - - // - // Exec - use for long running tools where you need to stream live output as it runs - // returns a promise with return code. - // - public execAsync(options?: IExecOptions): Promise { - this._debug('exec tool: ' + this.toolPath); - this._debug('Arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); - - var success = true; - options = options || {}; - - var ops: IExecOptions = { - cwd: options.cwd || process.cwd(), - env: options.env || process.env, - silent: options.silent || false, - outStream: options.outStream || process.stdout, - errStream: options.errStream || process.stderr, - failOnStdErr: options.failOnStdErr || false, - ignoreReturnCode: options.ignoreReturnCode || false, - windowsVerbatimArguments: options.windowsVerbatimArguments - }; - - var argString = this.args.join(' ') || ''; - var cmdString = this.toolPath; - if (argString) { - cmdString += (' ' + argString); - } - - // Using split/join to replace the temp path - cmdString = this.ignoreTempPath(cmdString); - - if (!ops.silent) { - if(this.pipeOutputToTool) { - var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; - var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); - if(pipeToolArgString) { - pipeToolCmdString += (' ' + pipeToolArgString); - } - - cmdString += ' | ' + pipeToolCmdString; - } - - ops.outStream.write('[command]' + cmdString + os.EOL); - } - - // TODO: filter process.env - var res = mock.getResponse('exec', cmdString, debug); - if (res.stdout) { - this.emit('stdout', res.stdout); - if (!ops.silent) { - ops.outStream.write(res.stdout + os.EOL); - } - const stdLineArray = res.stdout.split(os.EOL); - for (const line of stdLineArray.slice(0, -1)) { - this.emit('stdline', line); - } - if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { - this.emit('stdline', stdLineArray[stdLineArray.length - 1]); - } - } - - if (res.stderr) { - this.emit('stderr', res.stderr); - - success = !ops.failOnStdErr; - if (!ops.silent) { - var s = ops.failOnStdErr ? ops.errStream : ops.outStream; - s.write(res.stderr + os.EOL); - } - const stdErrArray = res.stderr.split(os.EOL); - for (const line of stdErrArray.slice(0, -1)) { - this.emit('errline', line); - } - if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { - this.emit('errline', stdErrArray[stdErrArray.length - 1]); - } - } - - - var code = res.code; - - if (!ops.silent) { - ops.outStream.write('rc:' + res.code + os.EOL); - } - - if (code != 0 && !ops.ignoreReturnCode) { - success = false; - } - - if (!ops.silent) { - ops.outStream.write('success:' + success + os.EOL); - } - - return new Promise((resolve, reject) => { - if (success) { - resolve(code); - } - else { - reject(new Error(this.toolPath + ' failed with return code: ' + code)); - } - }); - } - - /** - * Exec - use for long running tools where you need to stream live output as it runs - * @deprecated use `execAsync` instead - * @returns a promise with return code. - */ - public exec(options?: IExecOptions): Promise { - return new Promise((resolve, reject) => { - this._debug('exec tool: ' + this.toolPath); - this._debug('Arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); - - var success = true; - options = options || {}; - - var ops: IExecOptions = { - cwd: options.cwd || process.cwd(), - env: options.env || process.env, - silent: options.silent || false, - outStream: options.outStream || process.stdout, - errStream: options.errStream || process.stderr, - failOnStdErr: options.failOnStdErr || false, - ignoreReturnCode: options.ignoreReturnCode || false, - windowsVerbatimArguments: options.windowsVerbatimArguments - }; - - var argString = this.args.join(' ') || ''; - var cmdString = this.toolPath; - if (argString) { - cmdString += (' ' + argString); - } - - // Using split/join to replace the temp path - cmdString = this.ignoreTempPath(cmdString); - - if (!ops.silent) { - if(this.pipeOutputToTool) { - var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; - var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); - if(pipeToolArgString) { - pipeToolCmdString += (' ' + pipeToolArgString); - } - - cmdString += ' | ' + pipeToolCmdString; - } - - ops.outStream.write('[command]' + cmdString + os.EOL); - } - - // TODO: filter process.env - var res = mock.getResponse('exec', cmdString, debug); - if (res.stdout) { - this.emit('stdout', res.stdout); - if (!ops.silent) { - ops.outStream.write(res.stdout + os.EOL); - } - const stdLineArray = res.stdout.split(os.EOL); - for (const line of stdLineArray.slice(0, -1)) { - this.emit('stdline', line); - } - if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { - this.emit('stdline', stdLineArray[stdLineArray.length - 1]); - } - } - - if (res.stderr) { - this.emit('stderr', res.stderr); - - success = !ops.failOnStdErr; - if (!ops.silent) { - var s = ops.failOnStdErr ? ops.errStream : ops.outStream; - s.write(res.stderr + os.EOL); - } - const stdErrArray = res.stderr.split(os.EOL); - for (const line of stdErrArray.slice(0, -1)) { - this.emit('errline', line); - } - if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { - this.emit('errline', stdErrArray[stdErrArray.length - 1]); - } - } - - - var code = res.code; - - if (!ops.silent) { - ops.outStream.write('rc:' + res.code + os.EOL); - } - - if (code != 0 && !ops.ignoreReturnCode) { - success = false; - } - - if (!ops.silent) { - ops.outStream.write('success:' + success + os.EOL); - } - if (success) { - return resolve(code); - } - else { - return reject(new Error(this.toolPath + ' failed with return code: ' + code)); - } - }); - } - - // - // ExecSync - use for short running simple commands. Simple and convenient (synchronous) - // but also has limits. For example, no live output and limited to max buffer - // - public execSync(options?: IExecSyncOptions): IExecSyncResult { - this._debug('exec tool: ' + this.toolPath); - this._debug('Arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); - - var success = true; - options = options || {}; - - var ops: IExecSyncOptions = { - cwd: options.cwd || process.cwd(), - env: options.env || process.env, - silent: options.silent || false, - outStream: options.outStream || process.stdout, - errStream: options.errStream || process.stderr, - windowsVerbatimArguments: options.windowsVerbatimArguments, - }; - - var argString = this.args.join(' ') || ''; - var cmdString = this.toolPath; - - // Using split/join to replace the temp path - cmdString = this.ignoreTempPath(cmdString); - - if (argString) { - cmdString += (' ' + argString); - } - - if (!ops.silent) { - ops.outStream.write('[command]' + cmdString + os.EOL); - } - - var r = mock.getResponse('exec', cmdString, debug); - if (!ops.silent && r.stdout && r.stdout.length > 0) { - ops.outStream.write(r.stdout); - } - - if (!ops.silent && r.stderr && r.stderr.length > 0) { - ops.errStream.write(r.stderr); - } - - return { - code: r.code, - stdout: (r.stdout) ? r.stdout.toString() : null, - stderr: (r.stderr) ? r.stderr.toString() : null - }; - } -} +import os = require('os'); +import events = require('events'); +import ma = require('./mock-answer'); + +let mock: ma.MockAnswers = new ma.MockAnswers(); + +export function setAnswers(answers: ma.TaskLibAnswers) { + mock.initialize(answers); +} + +export interface IExecOptions extends IExecSyncOptions { + failOnStdErr?: boolean; + ignoreReturnCode?: boolean; +}; + +export interface IExecSyncOptions { + cwd?: string; + env?: { [key: string]: string | undefined }; + silent?: boolean; + outStream: NodeJS.WritableStream; + errStream: NodeJS.WritableStream; + windowsVerbatimArguments?: boolean; +}; + +export interface IExecSyncResult { + stdout: string; + stderr: string; + code: number; + error: Error; +} + +export function debug(message) { + // do nothing, overridden +} + +export class ToolRunner extends events.EventEmitter { + constructor(toolPath: string) { + debug('toolRunner toolPath: ' + toolPath); + + super(); + + this.toolPath = toolPath; + this.args = []; + } + + private toolPath: string; + private args: string[]; + private pipeOutputToTool: ToolRunner | undefined; + + private _debug(message) { + debug(message); + this.emit('debug', message); + } + + private _argStringToArray(argString: string): string[] { + var args: string[] = []; + + var inQuotes = false; + var escaped =false; + var arg = ''; + + var append = function(c: string) { + // we only escape double quotes. + if (escaped && c !== '"') { + arg += '\\'; + } + + arg += c; + escaped = false; + } + + for (var i=0; i < argString.length; i++) { + var c = argString.charAt(i); + + if (c === '"') { + if (!escaped) { + inQuotes = !inQuotes; + } + else { + append(c); + } + continue; + } + + if (c === "\\" && inQuotes) { + escaped = true; + continue; + } + + if (c === ' ' && !inQuotes) { + if (arg.length > 0) { + args.push(arg); + arg = ''; + } + continue; + } + + append(c); + } + + if (arg.length > 0) { + args.push(arg.trim()); + } + + return args; + } + + public arg(val: any): ToolRunner { + if (!val) { + return this; + } + + if (val instanceof Array) { + this._debug(this.toolPath + ' arg: ' + JSON.stringify(val)); + this.args = this.args.concat(val); + } + else if (typeof(val) === 'string') { + this._debug(this.toolPath + ' arg: ' + val); + this.args = this.args.concat(val.trim()); + } + + return this; + } + + public argIf(condition: any, val: any): ToolRunner { + if (condition) { + this.arg(val); + } + + return this; + } + + public line(val: string): ToolRunner { + if (!val) { + return this; + } + + this._debug(this.toolPath + ' arg: ' + val); + this.args = this.args.concat(this._argStringToArray(val)); + return this; + } + + public pipeExecOutputToTool(tool: ToolRunner) : ToolRunner { + this.pipeOutputToTool = tool; + return this; + } + + private ignoreTempPath(cmdString: string): string { + this._debug('ignoreTempPath=' + process.env['MOCK_IGNORE_TEMP_PATH']); + this._debug('tempPath=' + process.env['MOCK_TEMP_PATH']); + if (process.env['MOCK_IGNORE_TEMP_PATH'] === 'true') { + // Using split/join to replace the temp path + cmdString = cmdString.split(process.env['MOCK_TEMP_PATH'] || "").join(''); + } + + return cmdString; + } + + // + // Exec - use for long running tools where you need to stream live output as it runs + // returns a promise with return code. + // + public execAsync(options?: IExecOptions): Promise { + this._debug('exec tool: ' + this.toolPath); + this._debug('Arguments:'); + this.args.forEach((arg) => { + this._debug(' ' + arg); + }); + + var success = true; + options = options || {}; + + var ops: IExecOptions = { + cwd: options.cwd || process.cwd(), + env: options.env || process.env, + silent: options.silent || false, + outStream: options.outStream || process.stdout, + errStream: options.errStream || process.stderr, + failOnStdErr: options.failOnStdErr || false, + ignoreReturnCode: options.ignoreReturnCode || false, + windowsVerbatimArguments: options.windowsVerbatimArguments + }; + + var argString = this.args.join(' ') || ''; + var cmdString = this.toolPath; + if (argString) { + cmdString += (' ' + argString); + } + + // Using split/join to replace the temp path + cmdString = this.ignoreTempPath(cmdString); + + if (!ops.silent) { + if(this.pipeOutputToTool) { + var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; + var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); + if(pipeToolArgString) { + pipeToolCmdString += (' ' + pipeToolArgString); + } + + cmdString += ' | ' + pipeToolCmdString; + } + + ops.outStream.write('[command]' + cmdString + os.EOL); + } + + // TODO: filter process.env + var res = mock.getResponse('exec', cmdString, debug); + if (res.stdout) { + this.emit('stdout', res.stdout); + if (!ops.silent) { + ops.outStream.write(res.stdout + os.EOL); + } + const stdLineArray = res.stdout.split(os.EOL); + for (const line of stdLineArray.slice(0, -1)) { + this.emit('stdline', line); + } + if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { + this.emit('stdline', stdLineArray[stdLineArray.length - 1]); + } + } + + if (res.stderr) { + this.emit('stderr', res.stderr); + + success = !ops.failOnStdErr; + if (!ops.silent) { + var s = ops.failOnStdErr ? ops.errStream : ops.outStream; + s.write(res.stderr + os.EOL); + } + const stdErrArray = res.stderr.split(os.EOL); + for (const line of stdErrArray.slice(0, -1)) { + this.emit('errline', line); + } + if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { + this.emit('errline', stdErrArray[stdErrArray.length - 1]); + } + } + + + var code = res.code; + + if (!ops.silent) { + ops.outStream.write('rc:' + res.code + os.EOL); + } + + if (code != 0 && !ops.ignoreReturnCode) { + success = false; + } + + if (!ops.silent) { + ops.outStream.write('success:' + success + os.EOL); + } + + return new Promise((resolve, reject) => { + if (success) { + resolve(code); + } + else { + reject(new Error(this.toolPath + ' failed with return code: ' + code)); + } + }); + } + + /** + * Exec - use for long running tools where you need to stream live output as it runs + * @deprecated use `execAsync` instead + * @returns a promise with return code. + */ + public exec(options?: IExecOptions): Promise { + return new Promise((resolve, reject) => { + this._debug('exec tool: ' + this.toolPath); + this._debug('Arguments:'); + this.args.forEach((arg) => { + this._debug(' ' + arg); + }); + + var success = true; + options = options || {}; + + var ops: IExecOptions = { + cwd: options.cwd || process.cwd(), + env: options.env || process.env, + silent: options.silent || false, + outStream: options.outStream || process.stdout, + errStream: options.errStream || process.stderr, + failOnStdErr: options.failOnStdErr || false, + ignoreReturnCode: options.ignoreReturnCode || false, + windowsVerbatimArguments: options.windowsVerbatimArguments + }; + + var argString = this.args.join(' ') || ''; + var cmdString = this.toolPath; + if (argString) { + cmdString += (' ' + argString); + } + + // Using split/join to replace the temp path + cmdString = this.ignoreTempPath(cmdString); + + if (!ops.silent) { + if(this.pipeOutputToTool) { + var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; + var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); + if(pipeToolArgString) { + pipeToolCmdString += (' ' + pipeToolArgString); + } + + cmdString += ' | ' + pipeToolCmdString; + } + + ops.outStream.write('[command]' + cmdString + os.EOL); + } + + // TODO: filter process.env + var res = mock.getResponse('exec', cmdString, debug); + if (res.stdout) { + this.emit('stdout', res.stdout); + if (!ops.silent) { + ops.outStream.write(res.stdout + os.EOL); + } + const stdLineArray = res.stdout.split(os.EOL); + for (const line of stdLineArray.slice(0, -1)) { + this.emit('stdline', line); + } + if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { + this.emit('stdline', stdLineArray[stdLineArray.length - 1]); + } + } + + if (res.stderr) { + this.emit('stderr', res.stderr); + + success = !ops.failOnStdErr; + if (!ops.silent) { + var s = ops.failOnStdErr ? ops.errStream : ops.outStream; + s.write(res.stderr + os.EOL); + } + const stdErrArray = res.stderr.split(os.EOL); + for (const line of stdErrArray.slice(0, -1)) { + this.emit('errline', line); + } + if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { + this.emit('errline', stdErrArray[stdErrArray.length - 1]); + } + } + + + var code = res.code; + + if (!ops.silent) { + ops.outStream.write('rc:' + res.code + os.EOL); + } + + if (code != 0 && !ops.ignoreReturnCode) { + success = false; + } + + if (!ops.silent) { + ops.outStream.write('success:' + success + os.EOL); + } + if (success) { + return resolve(code); + } + else { + return reject(new Error(this.toolPath + ' failed with return code: ' + code)); + } + }); + } + + // + // ExecSync - use for short running simple commands. Simple and convenient (synchronous) + // but also has limits. For example, no live output and limited to max buffer + // + public execSync(options?: IExecSyncOptions): IExecSyncResult { + this._debug('exec tool: ' + this.toolPath); + this._debug('Arguments:'); + this.args.forEach((arg) => { + this._debug(' ' + arg); + }); + + var success = true; + options = options || {}; + + var ops: IExecSyncOptions = { + cwd: options.cwd || process.cwd(), + env: options.env || process.env, + silent: options.silent || false, + outStream: options.outStream || process.stdout, + errStream: options.errStream || process.stderr, + windowsVerbatimArguments: options.windowsVerbatimArguments, + }; + + var argString = this.args.join(' ') || ''; + var cmdString = this.toolPath; + + // Using split/join to replace the temp path + cmdString = this.ignoreTempPath(cmdString); + + if (argString) { + cmdString += (' ' + argString); + } + + if (!ops.silent) { + ops.outStream.write('[command]' + cmdString + os.EOL); + } + + var r = mock.getResponse('exec', cmdString, debug); + if (!ops.silent && r.stdout && r.stdout.length > 0) { + ops.outStream.write(r.stdout); + } + + if (!ops.silent && r.stderr && r.stderr.length > 0) { + ops.errStream.write(r.stderr); + } + + return { + code: r.code, + stdout: (r.stdout) ? r.stdout.toString() : null, + stderr: (r.stderr) ? r.stderr.toString() : null + }; + } +} From 6309fdffc0cf6990a97d49cefa955710967b98e8 Mon Sep 17 00:00:00 2001 From: Ivan Duplenskikh <115665590+ivanduplenskikh@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:45:37 +0100 Subject: [PATCH 3/3] Call execAsync method from deprecated exec since both method are similar after removing Q module --- node/mock-toolrunner.ts | 99 +---------------------------------------- 1 file changed, 1 insertion(+), 98 deletions(-) diff --git a/node/mock-toolrunner.ts b/node/mock-toolrunner.ts index 51bd51b6d..8a83caf4b 100644 --- a/node/mock-toolrunner.ts +++ b/node/mock-toolrunner.ts @@ -268,104 +268,7 @@ export class ToolRunner extends events.EventEmitter { * @returns a promise with return code. */ public exec(options?: IExecOptions): Promise { - return new Promise((resolve, reject) => { - this._debug('exec tool: ' + this.toolPath); - this._debug('Arguments:'); - this.args.forEach((arg) => { - this._debug(' ' + arg); - }); - - var success = true; - options = options || {}; - - var ops: IExecOptions = { - cwd: options.cwd || process.cwd(), - env: options.env || process.env, - silent: options.silent || false, - outStream: options.outStream || process.stdout, - errStream: options.errStream || process.stderr, - failOnStdErr: options.failOnStdErr || false, - ignoreReturnCode: options.ignoreReturnCode || false, - windowsVerbatimArguments: options.windowsVerbatimArguments - }; - - var argString = this.args.join(' ') || ''; - var cmdString = this.toolPath; - if (argString) { - cmdString += (' ' + argString); - } - - // Using split/join to replace the temp path - cmdString = this.ignoreTempPath(cmdString); - - if (!ops.silent) { - if(this.pipeOutputToTool) { - var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || ''; - var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath); - if(pipeToolArgString) { - pipeToolCmdString += (' ' + pipeToolArgString); - } - - cmdString += ' | ' + pipeToolCmdString; - } - - ops.outStream.write('[command]' + cmdString + os.EOL); - } - - // TODO: filter process.env - var res = mock.getResponse('exec', cmdString, debug); - if (res.stdout) { - this.emit('stdout', res.stdout); - if (!ops.silent) { - ops.outStream.write(res.stdout + os.EOL); - } - const stdLineArray = res.stdout.split(os.EOL); - for (const line of stdLineArray.slice(0, -1)) { - this.emit('stdline', line); - } - if(stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) { - this.emit('stdline', stdLineArray[stdLineArray.length - 1]); - } - } - - if (res.stderr) { - this.emit('stderr', res.stderr); - - success = !ops.failOnStdErr; - if (!ops.silent) { - var s = ops.failOnStdErr ? ops.errStream : ops.outStream; - s.write(res.stderr + os.EOL); - } - const stdErrArray = res.stderr.split(os.EOL); - for (const line of stdErrArray.slice(0, -1)) { - this.emit('errline', line); - } - if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) { - this.emit('errline', stdErrArray[stdErrArray.length - 1]); - } - } - - - var code = res.code; - - if (!ops.silent) { - ops.outStream.write('rc:' + res.code + os.EOL); - } - - if (code != 0 && !ops.ignoreReturnCode) { - success = false; - } - - if (!ops.silent) { - ops.outStream.write('success:' + success + os.EOL); - } - if (success) { - return resolve(code); - } - else { - return reject(new Error(this.toolPath + ' failed with return code: ' + code)); - } - }); + return this.execAsync(options); } //