azure-pipelines-task-lib 4.4.0 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ThirdPartyNotice.txt +5 -3
- package/mock-task.d.ts +1 -0
- package/mock-task.js +13 -1
- package/mock-test.d.ts +7 -1
- package/mock-test.js +288 -147
- package/mock-toolrunner.d.ts +6 -0
- package/mock-toolrunner.js +93 -1
- package/package.json +5 -3
- package/task.d.ts +14 -1
- package/task.js +28 -17
- package/toolrunner.d.ts +12 -0
- package/toolrunner.js +276 -0
package/ThirdPartyNotice.txt
CHANGED
|
@@ -36,7 +36,7 @@ This Azure Pipelines extension (azure-pipelines-task-lib) is based on or incorpo
|
|
|
36
36
|
30. semver (git+https://github.com/npm/node-semver.git)
|
|
37
37
|
31. shelljs (git://github.com/arturadib/shelljs.git)
|
|
38
38
|
32. string_decoder (git://github.com/rvagg/string_decoder.git)
|
|
39
|
-
33.
|
|
39
|
+
33. nodejs-file-downloader (git://github.com/ibrod83/nodejs-file-downloader.git)
|
|
40
40
|
34. then-request (git+https://github.com/then/then-request.git)
|
|
41
41
|
35. typedarray (git://github.com/substack/typedarray.git)
|
|
42
42
|
36. typescript (git+https://github.com/Microsoft/TypeScript.git)
|
|
@@ -889,7 +889,8 @@ IN THE SOFTWARE.
|
|
|
889
889
|
=========================================
|
|
890
890
|
END OF string_decoder NOTICES, INFORMATION, AND LICENSE
|
|
891
891
|
|
|
892
|
-
|
|
892
|
+
|
|
893
|
+
%% nodejs-file-downloader NOTICES, INFORMATION, AND LICENSE BEGIN HERE
|
|
893
894
|
=========================================
|
|
894
895
|
Copyright (c) 2014 Forbes Lindesay
|
|
895
896
|
|
|
@@ -911,7 +912,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
911
912
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
912
913
|
THE SOFTWARE.
|
|
913
914
|
=========================================
|
|
914
|
-
END OF
|
|
915
|
+
END OF nodejs-file-downloader NOTICES, INFORMATION, AND LICENSE
|
|
916
|
+
|
|
915
917
|
|
|
916
918
|
%% then-request NOTICES, INFORMATION, AND LICENSE BEGIN HERE
|
|
917
919
|
=========================================
|
package/mock-task.d.ts
CHANGED
|
@@ -74,6 +74,7 @@ export declare function find(findPath: string): string[];
|
|
|
74
74
|
export declare function rmRF(path: string): void;
|
|
75
75
|
export declare function mv(source: string, dest: string, force: boolean, continueOnError?: boolean): boolean;
|
|
76
76
|
export declare function exec(tool: string, args: any, options?: trm.IExecOptions): Q.Promise<number>;
|
|
77
|
+
export declare function execAsync(tool: string, args: any, options?: trm.IExecOptions): Promise<number>;
|
|
77
78
|
export declare function execSync(tool: string, args: any, options?: trm.IExecSyncOptions): trm.IExecSyncResult;
|
|
78
79
|
export declare function tool(tool: string): trm.ToolRunner;
|
|
79
80
|
export interface MatchOptions {
|
package/mock-task.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getHttpCertConfiguration = exports.getHttpProxyConfiguration = exports.CodeCoverageEnabler = exports.CodeCoveragePublisher = exports.TestPublisher = exports.legacyFindFiles = exports.findMatch = exports.tool = exports.execSync = exports.exec = exports.mv = exports.rmRF = exports.find = exports.retry = exports.cp = exports.ls = exports.which = exports.resolve = exports.mkdirP = exports.checkPath = exports.popd = exports.pushd = exports.cd = exports.cwd = exports.getAgentMode = exports.getPlatform = exports.osType = exports.writeFile = exports.exist = exports.stats = exports.FsStats = exports.loc = exports.setResourcePath = exports.setAnswers = void 0;
|
|
3
|
+
exports.getHttpCertConfiguration = exports.getHttpProxyConfiguration = exports.CodeCoverageEnabler = exports.CodeCoveragePublisher = exports.TestPublisher = exports.legacyFindFiles = exports.findMatch = exports.tool = exports.execSync = exports.execAsync = exports.exec = exports.mv = exports.rmRF = exports.find = exports.retry = exports.cp = exports.ls = exports.which = exports.resolve = exports.mkdirP = exports.checkPath = exports.popd = exports.pushd = exports.cd = exports.cwd = exports.getAgentMode = exports.getPlatform = exports.osType = exports.writeFile = exports.exist = exports.stats = exports.FsStats = exports.loc = exports.setResourcePath = exports.setAnswers = void 0;
|
|
4
4
|
var path = require("path");
|
|
5
5
|
var task = require("./task");
|
|
6
6
|
var tcm = require("./taskcommand");
|
|
@@ -299,6 +299,18 @@ function exec(tool, args, options) {
|
|
|
299
299
|
return tr.exec(options);
|
|
300
300
|
}
|
|
301
301
|
exports.exec = exec;
|
|
302
|
+
//-----------------------------------------------------
|
|
303
|
+
// Exec convenience wrapper
|
|
304
|
+
//-----------------------------------------------------
|
|
305
|
+
function execAsync(tool, args, options) {
|
|
306
|
+
var toolPath = which(tool, true);
|
|
307
|
+
var tr = this.tool(toolPath);
|
|
308
|
+
if (args) {
|
|
309
|
+
tr.arg(args);
|
|
310
|
+
}
|
|
311
|
+
return tr.execAsync(options);
|
|
312
|
+
}
|
|
313
|
+
exports.execAsync = execAsync;
|
|
302
314
|
function execSync(tool, args, options) {
|
|
303
315
|
var toolPath = which(tool, true);
|
|
304
316
|
var tr = this.tool(toolPath);
|
package/mock-test.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare class MockTestRunner {
|
|
2
|
-
constructor(testPath
|
|
2
|
+
constructor(testPath?: string, taskJsonPath?: string);
|
|
3
3
|
private _testPath;
|
|
4
4
|
private _taskJsonPath;
|
|
5
5
|
nodePath: string;
|
|
@@ -10,14 +10,20 @@ export declare class MockTestRunner {
|
|
|
10
10
|
succeeded: boolean;
|
|
11
11
|
errorIssues: string[];
|
|
12
12
|
warningIssues: string[];
|
|
13
|
+
LoadAsync(testPath: string, taskJsonPath?: string): Promise<MockTestRunner>;
|
|
13
14
|
get failed(): boolean;
|
|
14
15
|
ran(cmdline: string): boolean;
|
|
15
16
|
createdErrorIssue(message: string): boolean;
|
|
16
17
|
createdWarningIssue(message: string): boolean;
|
|
17
18
|
stdOutContained(message: string): boolean;
|
|
18
19
|
stdErrContained(message: string): boolean;
|
|
20
|
+
runAsync(nodeVersion?: number): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated This method uses library which is not prefered to use on production
|
|
23
|
+
*/
|
|
19
24
|
run(nodeVersion?: number): void;
|
|
20
25
|
private getNodePath;
|
|
26
|
+
private getNodePathSync;
|
|
21
27
|
private getNodeVersion;
|
|
22
28
|
private getTaskJsonPath;
|
|
23
29
|
private downloadNode;
|
package/mock-test.js
CHANGED
|
@@ -1,4 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (_) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
2
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
39
|
exports.MockTestRunner = void 0;
|
|
4
40
|
var cp = require("child_process");
|
|
@@ -8,7 +44,8 @@ var os = require("os");
|
|
|
8
44
|
var path = require("path");
|
|
9
45
|
var cmdm = require("./taskcommand");
|
|
10
46
|
var shelljs = require("shelljs");
|
|
11
|
-
var
|
|
47
|
+
var deasync = require("deasync");
|
|
48
|
+
var Downloader = require("nodejs-file-downloader");
|
|
12
49
|
var COMMAND_TAG = '[command]';
|
|
13
50
|
var COMMAND_LENGTH = COMMAND_TAG.length;
|
|
14
51
|
var downloadDirectory = path.join(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE, 'azure-pipelines-task-lib', '_download');
|
|
@@ -24,10 +61,39 @@ var MockTestRunner = /** @class */ (function () {
|
|
|
24
61
|
this.succeeded = false;
|
|
25
62
|
this.errorIssues = [];
|
|
26
63
|
this.warningIssues = [];
|
|
64
|
+
if (testPath === undefined)
|
|
65
|
+
return;
|
|
27
66
|
this._taskJsonPath = taskJsonPath || '';
|
|
28
67
|
this._testPath = testPath;
|
|
29
|
-
this.nodePath = this.
|
|
68
|
+
this.nodePath = this.getNodePathSync();
|
|
30
69
|
}
|
|
70
|
+
MockTestRunner.prototype.LoadAsync = function (testPath, taskJsonPath) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
72
|
+
var _this = this;
|
|
73
|
+
return __generator(this, function (_a) {
|
|
74
|
+
return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
|
|
75
|
+
var _a;
|
|
76
|
+
return __generator(this, function (_b) {
|
|
77
|
+
switch (_b.label) {
|
|
78
|
+
case 0:
|
|
79
|
+
if (this.nodePath != '') {
|
|
80
|
+
resolve(this);
|
|
81
|
+
return [2 /*return*/];
|
|
82
|
+
}
|
|
83
|
+
this._taskJsonPath = taskJsonPath || '';
|
|
84
|
+
this._testPath = testPath;
|
|
85
|
+
_a = this;
|
|
86
|
+
return [4 /*yield*/, this.getNodePath()];
|
|
87
|
+
case 1:
|
|
88
|
+
_a.nodePath = _b.sent();
|
|
89
|
+
resolve(this);
|
|
90
|
+
return [2 /*return*/];
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}); })];
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
};
|
|
31
97
|
Object.defineProperty(MockTestRunner.prototype, "failed", {
|
|
32
98
|
get: function () {
|
|
33
99
|
return !this.succeeded;
|
|
@@ -50,103 +116,135 @@ var MockTestRunner = /** @class */ (function () {
|
|
|
50
116
|
MockTestRunner.prototype.stdErrContained = function (message) {
|
|
51
117
|
return this.stderr.indexOf(message) > 0;
|
|
52
118
|
};
|
|
53
|
-
MockTestRunner.prototype.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
MockTestRunner.prototype.runAsync = function (nodeVersion) {
|
|
120
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
121
|
+
var nodePath, spawn, lines, traceFile;
|
|
122
|
+
var _this = this;
|
|
123
|
+
return __generator(this, function (_a) {
|
|
124
|
+
switch (_a.label) {
|
|
125
|
+
case 0:
|
|
126
|
+
this.cmdlines = {};
|
|
127
|
+
this.invokedToolCount = 0;
|
|
128
|
+
this.succeeded = true;
|
|
129
|
+
this.errorIssues = [];
|
|
130
|
+
this.warningIssues = [];
|
|
131
|
+
nodePath = this.nodePath;
|
|
132
|
+
if (!nodeVersion) return [3 /*break*/, 2];
|
|
133
|
+
return [4 /*yield*/, this.getNodePath(nodeVersion)];
|
|
134
|
+
case 1:
|
|
135
|
+
nodePath = _a.sent();
|
|
136
|
+
_a.label = 2;
|
|
137
|
+
case 2:
|
|
138
|
+
spawn = cp.spawnSync(nodePath, [this._testPath]);
|
|
139
|
+
// Clean environment
|
|
140
|
+
Object.keys(process.env)
|
|
141
|
+
.filter(function (key) { return (key.substr(0, 'INPUT_'.length) === 'INPUT_' ||
|
|
142
|
+
key.substr(0, 'SECRET_'.length) === 'SECRET_' ||
|
|
143
|
+
key.substr(0, 'VSTS_TASKVARIABLE_'.length) === 'VSTS_TASKVARIABLE_'); })
|
|
144
|
+
.forEach(function (key) { return delete process.env[key]; });
|
|
145
|
+
if (spawn.error) {
|
|
146
|
+
console.error('Running test failed');
|
|
147
|
+
console.error(spawn.error.message);
|
|
148
|
+
return [2 /*return*/];
|
|
149
|
+
}
|
|
150
|
+
this.stdout = spawn.stdout.toString();
|
|
151
|
+
this.stderr = spawn.stderr.toString();
|
|
152
|
+
if (process.env['TASK_TEST_TRACE']) {
|
|
153
|
+
console.log('');
|
|
154
|
+
}
|
|
155
|
+
lines = this.stdout.replace(/\r\n/g, '\n').split('\n');
|
|
156
|
+
traceFile = this._testPath + '.log';
|
|
157
|
+
lines.forEach(function (line) {
|
|
158
|
+
var ci = line.indexOf('##vso[');
|
|
159
|
+
var cmd;
|
|
160
|
+
var cmi = line.indexOf(COMMAND_TAG);
|
|
161
|
+
if (ci >= 0) {
|
|
162
|
+
cmd = cmdm.commandFromString(line.substring(ci));
|
|
163
|
+
if (cmd.command === 'task.complete' && cmd.properties['result'] === 'Failed') {
|
|
164
|
+
_this.succeeded = false;
|
|
165
|
+
}
|
|
166
|
+
if (cmd.command === 'task.issue' && cmd.properties['type'] === 'error') {
|
|
167
|
+
_this.errorIssues.push(cmd.message.trim());
|
|
168
|
+
}
|
|
169
|
+
if (cmd.command === 'task.issue' && cmd.properties['type'] === 'warning') {
|
|
170
|
+
_this.warningIssues.push(cmd.message.trim());
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (cmi == 0 && line.length > COMMAND_LENGTH) {
|
|
174
|
+
var cmdline = line.substr(COMMAND_LENGTH).trim();
|
|
175
|
+
_this.cmdlines[cmdline] = true;
|
|
176
|
+
_this.invokedToolCount++;
|
|
177
|
+
}
|
|
178
|
+
if (process.env['TASK_TEST_TRACE']) {
|
|
179
|
+
fs.appendFileSync(traceFile, line + os.EOL);
|
|
180
|
+
if (line && !cmd) {
|
|
181
|
+
console.log(line);
|
|
182
|
+
}
|
|
183
|
+
// don't print task.debug commands to console - too noisy.
|
|
184
|
+
// otherwise omit command details - can interfere during CI.
|
|
185
|
+
else if (cmd && cmd.command != 'task.debug') {
|
|
186
|
+
console.log(cmd.command + " details omitted");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
if (this.stderr && process.env['TASK_TEST_TRACE']) {
|
|
191
|
+
console.log('STDERR: ' + this.stderr);
|
|
192
|
+
fs.appendFileSync(traceFile, 'STDERR: ' + this.stderr + os.EOL);
|
|
193
|
+
}
|
|
194
|
+
if (process.env['TASK_TEST_TRACE']) {
|
|
195
|
+
console.log('TRACE FILE: ' + traceFile);
|
|
196
|
+
}
|
|
197
|
+
return [2 /*return*/];
|
|
91
198
|
}
|
|
92
|
-
|
|
93
|
-
_this.errorIssues.push(cmd.message.trim());
|
|
94
|
-
}
|
|
95
|
-
if (cmd.command === 'task.issue' && cmd.properties['type'] === 'warning') {
|
|
96
|
-
_this.warningIssues.push(cmd.message.trim());
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
else if (cmi == 0 && line.length > COMMAND_LENGTH) {
|
|
100
|
-
var cmdline = line.substr(COMMAND_LENGTH).trim();
|
|
101
|
-
_this.cmdlines[cmdline] = true;
|
|
102
|
-
_this.invokedToolCount++;
|
|
103
|
-
}
|
|
104
|
-
if (process.env['TASK_TEST_TRACE']) {
|
|
105
|
-
fs.appendFileSync(traceFile, line + os.EOL);
|
|
106
|
-
if (line && !cmd) {
|
|
107
|
-
console.log(line);
|
|
108
|
-
}
|
|
109
|
-
// don't print task.debug commands to console - too noisy.
|
|
110
|
-
// otherwise omit command details - can interfere during CI.
|
|
111
|
-
else if (cmd && cmd.command != 'task.debug') {
|
|
112
|
-
console.log(cmd.command + " details omitted");
|
|
113
|
-
}
|
|
114
|
-
}
|
|
199
|
+
});
|
|
115
200
|
});
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* @deprecated This method uses library which is not prefered to use on production
|
|
204
|
+
*/
|
|
205
|
+
MockTestRunner.prototype.run = function (nodeVersion) {
|
|
206
|
+
var completeExecution = false;
|
|
207
|
+
this.runAsync(nodeVersion).then(function (t) { return completeExecution = true; });
|
|
208
|
+
deasync.loopWhile(function () { return !completeExecution; });
|
|
123
209
|
};
|
|
124
210
|
// Returns a path to node.exe with the correct version for this task (based on if its node10 or node)
|
|
125
211
|
MockTestRunner.prototype.getNodePath = function (nodeVersion) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
212
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
213
|
+
var version, downloadVersion, downloadDestination, pathToExe, result;
|
|
214
|
+
return __generator(this, function (_a) {
|
|
215
|
+
switch (_a.label) {
|
|
216
|
+
case 0:
|
|
217
|
+
version = nodeVersion || this.getNodeVersion();
|
|
218
|
+
switch (version) {
|
|
219
|
+
case 6:
|
|
220
|
+
downloadVersion = 'v6.17.1';
|
|
221
|
+
break;
|
|
222
|
+
case 10:
|
|
223
|
+
downloadVersion = 'v10.21.0';
|
|
224
|
+
break;
|
|
225
|
+
case 16:
|
|
226
|
+
downloadVersion = 'v16.13.0';
|
|
227
|
+
break;
|
|
228
|
+
default:
|
|
229
|
+
throw new Error('Invalid node version, must be 6, 10, or 16 (received ' + version + ')');
|
|
230
|
+
}
|
|
231
|
+
downloadDestination = path.join(downloadDirectory, 'node' + version);
|
|
232
|
+
pathToExe = this.getPathToNodeExe(downloadVersion, downloadDestination);
|
|
233
|
+
if (!pathToExe) return [3 /*break*/, 1];
|
|
234
|
+
return [2 /*return*/, pathToExe];
|
|
235
|
+
case 1: return [4 /*yield*/, this.downloadNode(downloadVersion, downloadDestination)];
|
|
236
|
+
case 2:
|
|
237
|
+
result = _a.sent();
|
|
238
|
+
return [2 /*return*/, result];
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
};
|
|
243
|
+
MockTestRunner.prototype.getNodePathSync = function (nodeVersion) {
|
|
244
|
+
var nodePath = '';
|
|
245
|
+
this.getNodePath(nodeVersion).then(function (t) { return nodePath = t; });
|
|
246
|
+
deasync.loopWhile(function () { return nodePath == ''; });
|
|
247
|
+
return nodePath;
|
|
150
248
|
};
|
|
151
249
|
// Determines the correct version of node to use based on the contents of the task's task.json. Defaults to Node 16.
|
|
152
250
|
MockTestRunner.prototype.getNodeVersion = function () {
|
|
@@ -201,65 +299,108 @@ var MockTestRunner = /** @class */ (function () {
|
|
|
201
299
|
};
|
|
202
300
|
// Downloads the specified node version to the download destination. Returns a path to node.exe
|
|
203
301
|
MockTestRunner.prototype.downloadNode = function (nodeVersion, downloadDestination) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
302
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
303
|
+
var nodeUrl, downloadPath, _a, marker;
|
|
304
|
+
return __generator(this, function (_b) {
|
|
305
|
+
switch (_b.label) {
|
|
306
|
+
case 0:
|
|
307
|
+
shelljs.rm('-rf', downloadDestination);
|
|
308
|
+
nodeUrl = process.env['TASK_NODE_URL'] || 'https://nodejs.org/dist';
|
|
309
|
+
nodeUrl = nodeUrl.replace(/\/$/, ''); // ensure there is no trailing slash on the base URL
|
|
310
|
+
downloadPath = '';
|
|
311
|
+
_a = this.getPlatform();
|
|
312
|
+
switch (_a) {
|
|
313
|
+
case 'darwin': return [3 /*break*/, 1];
|
|
314
|
+
case 'linux': return [3 /*break*/, 3];
|
|
315
|
+
case 'win32': return [3 /*break*/, 5];
|
|
316
|
+
}
|
|
317
|
+
return [3 /*break*/, 8];
|
|
318
|
+
case 1: return [4 /*yield*/, this.downloadTarGz(nodeUrl + '/' + nodeVersion + '/node-' + nodeVersion + '-darwin-x64.tar.gz', downloadDestination)];
|
|
319
|
+
case 2:
|
|
320
|
+
_b.sent();
|
|
321
|
+
downloadPath = path.join(downloadDestination, 'node-' + nodeVersion + '-darwin-x64', 'bin', 'node');
|
|
322
|
+
return [3 /*break*/, 8];
|
|
323
|
+
case 3: return [4 /*yield*/, this.downloadTarGz(nodeUrl + '/' + nodeVersion + '/node-' + nodeVersion + '-linux-x64.tar.gz', downloadDestination)];
|
|
324
|
+
case 4:
|
|
325
|
+
_b.sent();
|
|
326
|
+
downloadPath = path.join(downloadDestination, 'node-' + nodeVersion + '-linux-x64', 'bin', 'node');
|
|
327
|
+
return [3 /*break*/, 8];
|
|
328
|
+
case 5: return [4 /*yield*/, this.downloadFile(nodeUrl + '/' + nodeVersion + '/win-x64/node.exe', downloadDestination, 'node.exe')];
|
|
329
|
+
case 6:
|
|
330
|
+
_b.sent();
|
|
331
|
+
return [4 /*yield*/, this.downloadFile(nodeUrl + '/' + nodeVersion + '/win-x64/node.lib', downloadDestination, 'node.lib')];
|
|
332
|
+
case 7:
|
|
333
|
+
_b.sent();
|
|
334
|
+
downloadPath = path.join(downloadDestination, 'node.exe');
|
|
335
|
+
_b.label = 8;
|
|
336
|
+
case 8:
|
|
337
|
+
marker = downloadDestination + '.completed';
|
|
338
|
+
fs.writeFileSync(marker, '');
|
|
339
|
+
return [2 /*return*/, downloadPath];
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
});
|
|
226
343
|
};
|
|
227
344
|
// Downloads file to the downloadDestination, making any necessary folders along the way.
|
|
228
345
|
MockTestRunner.prototype.downloadFile = function (url, downloadDestination, fileName) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
346
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
347
|
+
var downloader;
|
|
348
|
+
return __generator(this, function (_a) {
|
|
349
|
+
switch (_a.label) {
|
|
350
|
+
case 0:
|
|
351
|
+
if (!url) {
|
|
352
|
+
throw new Error('Parameter "url" must be set.');
|
|
353
|
+
}
|
|
354
|
+
if (!downloadDestination) {
|
|
355
|
+
throw new Error('Parameter "downloadDestination" must be set.');
|
|
356
|
+
}
|
|
357
|
+
console.log('Downloading file:', url);
|
|
358
|
+
shelljs.mkdir('-p', downloadDestination);
|
|
359
|
+
downloader = new Downloader({
|
|
360
|
+
url: url,
|
|
361
|
+
directory: downloadDestination,
|
|
362
|
+
fileName: fileName
|
|
363
|
+
});
|
|
364
|
+
return [4 /*yield*/, downloader.download()];
|
|
365
|
+
case 1:
|
|
366
|
+
_a.sent();
|
|
367
|
+
return [2 /*return*/];
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
});
|
|
240
371
|
};
|
|
241
372
|
// Downloads tarGz to the download destination, making any necessary folders along the way.
|
|
242
373
|
MockTestRunner.prototype.downloadTarGz = function (url, downloadDestination) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
374
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
375
|
+
var tarGzName, originalCwd;
|
|
376
|
+
return __generator(this, function (_a) {
|
|
377
|
+
switch (_a.label) {
|
|
378
|
+
case 0:
|
|
379
|
+
if (!url) {
|
|
380
|
+
throw new Error('Parameter "url" must be set.');
|
|
381
|
+
}
|
|
382
|
+
if (!downloadDestination) {
|
|
383
|
+
throw new Error('Parameter "downloadDestination" must be set.');
|
|
384
|
+
}
|
|
385
|
+
tarGzName = 'node.tar.gz';
|
|
386
|
+
return [4 /*yield*/, this.downloadFile(url, downloadDestination, tarGzName)];
|
|
387
|
+
case 1:
|
|
388
|
+
_a.sent();
|
|
389
|
+
originalCwd = process.cwd();
|
|
390
|
+
process.chdir(downloadDestination);
|
|
391
|
+
try {
|
|
392
|
+
ncp.execSync("tar -xzf \"" + path.join(downloadDestination, tarGzName) + "\"");
|
|
393
|
+
}
|
|
394
|
+
catch (_b) {
|
|
395
|
+
throw new Error('Failed to unzip node tar.gz from ' + url);
|
|
396
|
+
}
|
|
397
|
+
finally {
|
|
398
|
+
process.chdir(originalCwd);
|
|
399
|
+
}
|
|
400
|
+
return [2 /*return*/];
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
});
|
|
263
404
|
};
|
|
264
405
|
// Checks if node is installed at downloadDestination. If it is, returns a path to node.exe, otherwise returns null.
|
|
265
406
|
MockTestRunner.prototype.getPathToNodeExe = function (nodeVersion, downloadDestination) {
|
package/mock-toolrunner.d.ts
CHANGED
|
@@ -36,6 +36,12 @@ export declare class ToolRunner extends events.EventEmitter {
|
|
|
36
36
|
line(val: string): ToolRunner;
|
|
37
37
|
pipeExecOutputToTool(tool: ToolRunner): ToolRunner;
|
|
38
38
|
private ignoreTempPath;
|
|
39
|
+
execAsync(options?: IExecOptions): Promise<number>;
|
|
40
|
+
/**
|
|
41
|
+
* Exec - use for long running tools where you need to stream live output as it runs
|
|
42
|
+
* @deprecated use `execAsync` instead
|
|
43
|
+
* @returns a promise with return code.
|
|
44
|
+
*/
|
|
39
45
|
exec(options?: IExecOptions): Q.Promise<number>;
|
|
40
46
|
execSync(options?: IExecSyncOptions): IExecSyncResult;
|
|
41
47
|
}
|
package/mock-toolrunner.js
CHANGED
|
@@ -130,6 +130,99 @@ var ToolRunner = /** @class */ (function (_super) {
|
|
|
130
130
|
// Exec - use for long running tools where you need to stream live output as it runs
|
|
131
131
|
// returns a promise with return code.
|
|
132
132
|
//
|
|
133
|
+
ToolRunner.prototype.execAsync = function (options) {
|
|
134
|
+
var _this = this;
|
|
135
|
+
this._debug('exec tool: ' + this.toolPath);
|
|
136
|
+
this._debug('Arguments:');
|
|
137
|
+
this.args.forEach(function (arg) {
|
|
138
|
+
_this._debug(' ' + arg);
|
|
139
|
+
});
|
|
140
|
+
var success = true;
|
|
141
|
+
options = options || {};
|
|
142
|
+
var ops = {
|
|
143
|
+
cwd: options.cwd || process.cwd(),
|
|
144
|
+
env: options.env || process.env,
|
|
145
|
+
silent: options.silent || false,
|
|
146
|
+
outStream: options.outStream || process.stdout,
|
|
147
|
+
errStream: options.errStream || process.stderr,
|
|
148
|
+
failOnStdErr: options.failOnStdErr || false,
|
|
149
|
+
ignoreReturnCode: options.ignoreReturnCode || false,
|
|
150
|
+
windowsVerbatimArguments: options.windowsVerbatimArguments
|
|
151
|
+
};
|
|
152
|
+
var argString = this.args.join(' ') || '';
|
|
153
|
+
var cmdString = this.toolPath;
|
|
154
|
+
if (argString) {
|
|
155
|
+
cmdString += (' ' + argString);
|
|
156
|
+
}
|
|
157
|
+
// Using split/join to replace the temp path
|
|
158
|
+
cmdString = this.ignoreTempPath(cmdString);
|
|
159
|
+
if (!ops.silent) {
|
|
160
|
+
if (this.pipeOutputToTool) {
|
|
161
|
+
var pipeToolArgString = this.pipeOutputToTool.args.join(' ') || '';
|
|
162
|
+
var pipeToolCmdString = this.ignoreTempPath(this.pipeOutputToTool.toolPath);
|
|
163
|
+
if (pipeToolArgString) {
|
|
164
|
+
pipeToolCmdString += (' ' + pipeToolArgString);
|
|
165
|
+
}
|
|
166
|
+
cmdString += ' | ' + pipeToolCmdString;
|
|
167
|
+
}
|
|
168
|
+
ops.outStream.write('[command]' + cmdString + os.EOL);
|
|
169
|
+
}
|
|
170
|
+
// TODO: filter process.env
|
|
171
|
+
var res = mock.getResponse('exec', cmdString, debug);
|
|
172
|
+
if (res.stdout) {
|
|
173
|
+
this.emit('stdout', res.stdout);
|
|
174
|
+
if (!ops.silent) {
|
|
175
|
+
ops.outStream.write(res.stdout + os.EOL);
|
|
176
|
+
}
|
|
177
|
+
var stdLineArray = res.stdout.split(os.EOL);
|
|
178
|
+
for (var _i = 0, _a = stdLineArray.slice(0, -1); _i < _a.length; _i++) {
|
|
179
|
+
var line = _a[_i];
|
|
180
|
+
this.emit('stdline', line);
|
|
181
|
+
}
|
|
182
|
+
if (stdLineArray.length > 0 && stdLineArray[stdLineArray.length - 1].length > 0) {
|
|
183
|
+
this.emit('stdline', stdLineArray[stdLineArray.length - 1]);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (res.stderr) {
|
|
187
|
+
this.emit('stderr', res.stderr);
|
|
188
|
+
success = !ops.failOnStdErr;
|
|
189
|
+
if (!ops.silent) {
|
|
190
|
+
var s = ops.failOnStdErr ? ops.errStream : ops.outStream;
|
|
191
|
+
s.write(res.stderr + os.EOL);
|
|
192
|
+
}
|
|
193
|
+
var stdErrArray = res.stderr.split(os.EOL);
|
|
194
|
+
for (var _b = 0, _c = stdErrArray.slice(0, -1); _b < _c.length; _b++) {
|
|
195
|
+
var line = _c[_b];
|
|
196
|
+
this.emit('errline', line);
|
|
197
|
+
}
|
|
198
|
+
if (stdErrArray.length > 0 && stdErrArray[stdErrArray.length - 1].length > 0) {
|
|
199
|
+
this.emit('errline', stdErrArray[stdErrArray.length - 1]);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
var code = res.code;
|
|
203
|
+
if (!ops.silent) {
|
|
204
|
+
ops.outStream.write('rc:' + res.code + os.EOL);
|
|
205
|
+
}
|
|
206
|
+
if (code != 0 && !ops.ignoreReturnCode) {
|
|
207
|
+
success = false;
|
|
208
|
+
}
|
|
209
|
+
if (!ops.silent) {
|
|
210
|
+
ops.outStream.write('success:' + success + os.EOL);
|
|
211
|
+
}
|
|
212
|
+
return new Promise(function (resolve, reject) {
|
|
213
|
+
if (success) {
|
|
214
|
+
resolve(code);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
reject(new Error(_this.toolPath + ' failed with return code: ' + code));
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Exec - use for long running tools where you need to stream live output as it runs
|
|
223
|
+
* @deprecated use `execAsync` instead
|
|
224
|
+
* @returns a promise with return code.
|
|
225
|
+
*/
|
|
133
226
|
ToolRunner.prototype.exec = function (options) {
|
|
134
227
|
var _this = this;
|
|
135
228
|
var defer = Q.defer();
|
|
@@ -224,7 +317,6 @@ var ToolRunner = /** @class */ (function (_super) {
|
|
|
224
317
|
//
|
|
225
318
|
ToolRunner.prototype.execSync = function (options) {
|
|
226
319
|
var _this = this;
|
|
227
|
-
var defer = Q.defer();
|
|
228
320
|
this._debug('exec tool: ' + this.toolPath);
|
|
229
321
|
this._debug('Arguments:');
|
|
230
322
|
this.args.forEach(function (arg) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azure-pipelines-task-lib",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "Azure Pipelines Task SDK",
|
|
5
5
|
"main": "./task.js",
|
|
6
6
|
"typings": "./task.d.ts",
|
|
@@ -27,19 +27,21 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/Microsoft/azure-pipelines-task-lib",
|
|
29
29
|
"dependencies": {
|
|
30
|
+
"adm-zip": "^0.5.10",
|
|
31
|
+
"deasync": "^0.1.28",
|
|
30
32
|
"minimatch": "3.0.5",
|
|
31
33
|
"mockery": "^2.1.0",
|
|
34
|
+
"nodejs-file-downloader": "^4.11.1",
|
|
32
35
|
"q": "^1.5.1",
|
|
33
36
|
"semver": "^5.1.0",
|
|
34
37
|
"shelljs": "^0.8.5",
|
|
35
|
-
"sync-request": "6.1.0",
|
|
36
38
|
"uuid": "^3.0.1"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
39
41
|
"@types/minimatch": "3.0.3",
|
|
40
42
|
"@types/mocha": "^9.1.1",
|
|
41
43
|
"@types/mockery": "^1.4.29",
|
|
42
|
-
"@types/node": "^
|
|
44
|
+
"@types/node": "^10.17.0",
|
|
43
45
|
"@types/q": "^1.5.4",
|
|
44
46
|
"@types/semver": "^7.3.4",
|
|
45
47
|
"@types/shelljs": "^0.8.8",
|
package/task.d.ts
CHANGED
|
@@ -58,7 +58,8 @@ export declare const setErrStream: typeof im._setErrStream;
|
|
|
58
58
|
* from agent version 2.142.0 or higher (otherwise will no-op).
|
|
59
59
|
* @returns void
|
|
60
60
|
*/
|
|
61
|
-
export declare function setResult(result: TaskResult, message
|
|
61
|
+
export declare function setResult(result: TaskResult.Succeeded, message?: string, done?: boolean): void;
|
|
62
|
+
export declare function setResult(result: Exclude<TaskResult, 'Succeeded'>, message: string, done?: boolean): void;
|
|
62
63
|
export declare const setResourcePath: typeof im._setResourcePath;
|
|
63
64
|
export declare const loc: typeof im._loc;
|
|
64
65
|
export declare const getVariable: typeof im._getVariable;
|
|
@@ -485,6 +486,18 @@ export declare function rmRF(inputPath: string): void;
|
|
|
485
486
|
* @param options optional exec options. See IExecOptions
|
|
486
487
|
* @returns number
|
|
487
488
|
*/
|
|
489
|
+
export declare function execAsync(tool: string, args: any, options?: trm.IExecOptions): Promise<number>;
|
|
490
|
+
/**
|
|
491
|
+
* Exec a tool. Convenience wrapper over ToolRunner to exec with args in one call.
|
|
492
|
+
* Output will be streamed to the live console.
|
|
493
|
+
* Returns promise with return code
|
|
494
|
+
*
|
|
495
|
+
* @deprecated Use the {@link execAsync} method that returns a native Javascript Promise instead
|
|
496
|
+
* @param tool path to tool to exec
|
|
497
|
+
* @param args an arg string or array of args
|
|
498
|
+
* @param options optional exec options. See IExecOptions
|
|
499
|
+
* @returns number
|
|
500
|
+
*/
|
|
488
501
|
export declare function exec(tool: string, args: any, options?: trm.IExecOptions): Q.Promise<number>;
|
|
489
502
|
/**
|
|
490
503
|
* Exec a tool synchronously. Convenience wrapper over ToolRunner to execSync with args in one call.
|
package/task.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.updateReleaseName = exports.addBuildTag = exports.updateBuildNumber = exports.uploadBuildLog = exports.associateArtifact = exports.uploadArtifact = exports.logIssue = exports.logDetail = exports.setProgress = exports.setEndpoint = exports.addAttachment = exports.uploadSummary = exports.prependPath = exports.uploadFile = exports.CodeCoverageEnabler = exports.CodeCoveragePublisher = exports.TestPublisher = exports.getHttpCertConfiguration = exports.getHttpProxyConfiguration = exports.findMatch = exports.filter = exports.match = exports.tool = exports.execSync = exports.exec = exports.rmRF = exports.legacyFindFiles = exports.find = exports.retry = exports.mv = exports.cp = exports.ls = exports.which = exports.resolve = exports.mkdirP = exports.popd = exports.pushd = exports.cd = exports.checkPath = exports.cwd = exports.getAgentMode = exports.getPlatform = exports.osType = exports.writeFile = exports.exist = exports.stats = exports.debug = exports.error = exports.warning = exports.command = exports.setTaskVariable = exports.getTaskVariable = exports.getSecureFileTicket = exports.getSecureFileName = exports.getEndpointAuthorization = exports.getEndpointAuthorizationParameterRequired = exports.getEndpointAuthorizationParameter = exports.getEndpointAuthorizationSchemeRequired = exports.getEndpointAuthorizationScheme = exports.getEndpointDataParameterRequired = exports.getEndpointDataParameter = exports.getEndpointUrlRequired = exports.getEndpointUrl = exports.getPathInputRequired = exports.getPathInput = exports.filePathSupplied = exports.getDelimitedInput = exports.getBoolFeatureFlag = exports.getBoolInput = exports.getInputRequired = exports.getInput = exports.setSecret = exports.setVariable = exports.getVariables = exports.assertAgent = exports.getVariable = exports.loc = exports.setResourcePath = exports.setResult = exports.setErrStream = exports.setStdStream = exports.AgentHostedMode = exports.Platform = exports.FieldType = exports.ArtifactType = exports.IssueType = exports.TaskState = exports.TaskResult = void 0;
|
|
3
|
+
exports.updateReleaseName = exports.addBuildTag = exports.updateBuildNumber = exports.uploadBuildLog = exports.associateArtifact = exports.uploadArtifact = exports.logIssue = exports.logDetail = exports.setProgress = exports.setEndpoint = exports.addAttachment = exports.uploadSummary = exports.prependPath = exports.uploadFile = exports.CodeCoverageEnabler = exports.CodeCoveragePublisher = exports.TestPublisher = exports.getHttpCertConfiguration = exports.getHttpProxyConfiguration = exports.findMatch = exports.filter = exports.match = exports.tool = exports.execSync = exports.exec = exports.execAsync = exports.rmRF = exports.legacyFindFiles = exports.find = exports.retry = exports.mv = exports.cp = exports.ls = exports.which = exports.resolve = exports.mkdirP = exports.popd = exports.pushd = exports.cd = exports.checkPath = exports.cwd = exports.getAgentMode = exports.getPlatform = exports.osType = exports.writeFile = exports.exist = exports.stats = exports.debug = exports.error = exports.warning = exports.command = exports.setTaskVariable = exports.getTaskVariable = exports.getSecureFileTicket = exports.getSecureFileName = exports.getEndpointAuthorization = exports.getEndpointAuthorizationParameterRequired = exports.getEndpointAuthorizationParameter = exports.getEndpointAuthorizationSchemeRequired = exports.getEndpointAuthorizationScheme = exports.getEndpointDataParameterRequired = exports.getEndpointDataParameter = exports.getEndpointUrlRequired = exports.getEndpointUrl = exports.getPathInputRequired = exports.getPathInput = exports.filePathSupplied = exports.getDelimitedInput = exports.getBoolFeatureFlag = exports.getBoolInput = exports.getInputRequired = exports.getInput = exports.setSecret = exports.setVariable = exports.getVariables = exports.assertAgent = exports.getVariable = exports.loc = exports.setResourcePath = exports.setResult = exports.setErrStream = exports.setStdStream = exports.AgentHostedMode = exports.Platform = exports.FieldType = exports.ArtifactType = exports.IssueType = exports.TaskState = exports.TaskResult = void 0;
|
|
4
4
|
var shell = require("shelljs");
|
|
5
5
|
var childProcess = require("child_process");
|
|
6
6
|
var fs = require("fs");
|
|
@@ -63,22 +63,6 @@ var AgentHostedMode;
|
|
|
63
63
|
//-----------------------------------------------------
|
|
64
64
|
exports.setStdStream = im._setStdStream;
|
|
65
65
|
exports.setErrStream = im._setErrStream;
|
|
66
|
-
//-----------------------------------------------------
|
|
67
|
-
// Results
|
|
68
|
-
//-----------------------------------------------------
|
|
69
|
-
/**
|
|
70
|
-
* Sets the result of the task.
|
|
71
|
-
* Execution will continue.
|
|
72
|
-
* If not set, task will be Succeeded.
|
|
73
|
-
* If multiple calls are made to setResult the most pessimistic call wins (Failed) regardless of the order of calls.
|
|
74
|
-
*
|
|
75
|
-
* @param result TaskResult enum of Succeeded, SucceededWithIssues, Failed, Cancelled or Skipped.
|
|
76
|
-
* @param message A message which will be logged as an error issue if the result is Failed.
|
|
77
|
-
* @param done Optional. Instructs the agent the task is done. This is helpful when child processes
|
|
78
|
-
* may still be running and prevent node from fully exiting. This argument is supported
|
|
79
|
-
* from agent version 2.142.0 or higher (otherwise will no-op).
|
|
80
|
-
* @returns void
|
|
81
|
-
*/
|
|
82
66
|
function setResult(result, message, done) {
|
|
83
67
|
exports.debug('task result: ' + TaskResult[result]);
|
|
84
68
|
// add an error issue
|
|
@@ -1280,6 +1264,33 @@ exports.rmRF = rmRF;
|
|
|
1280
1264
|
* @param options optional exec options. See IExecOptions
|
|
1281
1265
|
* @returns number
|
|
1282
1266
|
*/
|
|
1267
|
+
function execAsync(tool, args, options) {
|
|
1268
|
+
var tr = this.tool(tool);
|
|
1269
|
+
tr.on('debug', function (data) {
|
|
1270
|
+
exports.debug(data);
|
|
1271
|
+
});
|
|
1272
|
+
if (args) {
|
|
1273
|
+
if (args instanceof Array) {
|
|
1274
|
+
tr.arg(args);
|
|
1275
|
+
}
|
|
1276
|
+
else if (typeof (args) === 'string') {
|
|
1277
|
+
tr.line(args);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
return tr.execAsync(options);
|
|
1281
|
+
}
|
|
1282
|
+
exports.execAsync = execAsync;
|
|
1283
|
+
/**
|
|
1284
|
+
* Exec a tool. Convenience wrapper over ToolRunner to exec with args in one call.
|
|
1285
|
+
* Output will be streamed to the live console.
|
|
1286
|
+
* Returns promise with return code
|
|
1287
|
+
*
|
|
1288
|
+
* @deprecated Use the {@link execAsync} method that returns a native Javascript Promise instead
|
|
1289
|
+
* @param tool path to tool to exec
|
|
1290
|
+
* @param args an arg string or array of args
|
|
1291
|
+
* @param options optional exec options. See IExecOptions
|
|
1292
|
+
* @returns number
|
|
1293
|
+
*/
|
|
1283
1294
|
function exec(tool, args, options) {
|
|
1284
1295
|
var tr = this.tool(tool);
|
|
1285
1296
|
tr.on('debug', function (data) {
|
package/toolrunner.d.ts
CHANGED
|
@@ -94,6 +94,7 @@ export declare class ToolRunner extends events.EventEmitter {
|
|
|
94
94
|
private _cloneExecOptions;
|
|
95
95
|
private _getSpawnOptions;
|
|
96
96
|
private _getSpawnSyncOptions;
|
|
97
|
+
private execWithPipingAsync;
|
|
97
98
|
private execWithPiping;
|
|
98
99
|
/**
|
|
99
100
|
* Add argument
|
|
@@ -139,6 +140,17 @@ export declare class ToolRunner extends events.EventEmitter {
|
|
|
139
140
|
* @param options optional exec options. See IExecOptions
|
|
140
141
|
* @returns number
|
|
141
142
|
*/
|
|
143
|
+
execAsync(options?: IExecOptions): Promise<number>;
|
|
144
|
+
/**
|
|
145
|
+
* Exec a tool.
|
|
146
|
+
* Output will be streamed to the live console.
|
|
147
|
+
* Returns promise with return code
|
|
148
|
+
*
|
|
149
|
+
* @deprecated Use the `execAsync` method that returns a native Javascript promise instead
|
|
150
|
+
* @param tool path to tool to exec
|
|
151
|
+
* @param options optional exec options. See IExecOptions
|
|
152
|
+
* @returns number
|
|
153
|
+
*/
|
|
142
154
|
exec(options?: IExecOptions): Q.Promise<number>;
|
|
143
155
|
/**
|
|
144
156
|
* Exec a tool synchronously.
|
package/toolrunner.js
CHANGED
|
@@ -516,6 +516,184 @@ var ToolRunner = /** @class */ (function (_super) {
|
|
|
516
516
|
result['windowsVerbatimArguments'] = options.windowsVerbatimArguments || this._isCmdFile();
|
|
517
517
|
return result;
|
|
518
518
|
};
|
|
519
|
+
ToolRunner.prototype.execWithPipingAsync = function (pipeOutputToTool, options) {
|
|
520
|
+
var _this = this;
|
|
521
|
+
this._debug('exec tool: ' + this.toolPath);
|
|
522
|
+
this._debug('arguments:');
|
|
523
|
+
this.args.forEach(function (arg) {
|
|
524
|
+
_this._debug(' ' + arg);
|
|
525
|
+
});
|
|
526
|
+
var success = true;
|
|
527
|
+
var optionsNonNull = this._cloneExecOptions(options);
|
|
528
|
+
if (!optionsNonNull.silent) {
|
|
529
|
+
optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL);
|
|
530
|
+
}
|
|
531
|
+
var cp;
|
|
532
|
+
var toolPath = pipeOutputToTool.toolPath;
|
|
533
|
+
var toolPathFirst;
|
|
534
|
+
var successFirst = true;
|
|
535
|
+
var returnCodeFirst;
|
|
536
|
+
var fileStream;
|
|
537
|
+
var waitingEvents = 0; // number of process or stream events we are waiting on to complete
|
|
538
|
+
var returnCode = 0;
|
|
539
|
+
var error;
|
|
540
|
+
toolPathFirst = this.toolPath;
|
|
541
|
+
// Following node documentation example from this link on how to pipe output of one process to another
|
|
542
|
+
// https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
|
|
543
|
+
//start the child process for both tools
|
|
544
|
+
waitingEvents++;
|
|
545
|
+
var cpFirst = child.spawn(this._getSpawnFileName(optionsNonNull), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(optionsNonNull));
|
|
546
|
+
waitingEvents++;
|
|
547
|
+
cp = child.spawn(pipeOutputToTool._getSpawnFileName(optionsNonNull), pipeOutputToTool._getSpawnArgs(optionsNonNull), pipeOutputToTool._getSpawnOptions(optionsNonNull));
|
|
548
|
+
fileStream = this.pipeOutputToFile ? fs.createWriteStream(this.pipeOutputToFile) : null;
|
|
549
|
+
return new Promise(function (resolve, reject) {
|
|
550
|
+
var _a, _b, _c, _d;
|
|
551
|
+
if (fileStream) {
|
|
552
|
+
waitingEvents++;
|
|
553
|
+
fileStream.on('finish', function () {
|
|
554
|
+
waitingEvents--; //file write is complete
|
|
555
|
+
fileStream = null;
|
|
556
|
+
if (waitingEvents == 0) {
|
|
557
|
+
if (error) {
|
|
558
|
+
reject(error);
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
resolve(returnCode);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
fileStream.on('error', function (err) {
|
|
566
|
+
waitingEvents--; //there were errors writing to the file, write is done
|
|
567
|
+
_this._debug("Failed to pipe output of " + toolPathFirst + " to file " + _this.pipeOutputToFile + ". Error = " + err);
|
|
568
|
+
fileStream = null;
|
|
569
|
+
if (waitingEvents == 0) {
|
|
570
|
+
if (error) {
|
|
571
|
+
reject(error);
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
resolve(returnCode);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
//pipe stdout of first tool to stdin of second tool
|
|
580
|
+
(_a = cpFirst.stdout) === null || _a === void 0 ? void 0 : _a.on('data', function (data) {
|
|
581
|
+
var _a;
|
|
582
|
+
try {
|
|
583
|
+
if (fileStream) {
|
|
584
|
+
fileStream.write(data);
|
|
585
|
+
}
|
|
586
|
+
(_a = cp.stdin) === null || _a === void 0 ? void 0 : _a.write(data);
|
|
587
|
+
}
|
|
588
|
+
catch (err) {
|
|
589
|
+
_this._debug('Failed to pipe output of ' + toolPathFirst + ' to ' + toolPath);
|
|
590
|
+
_this._debug(toolPath + ' might have exited due to errors prematurely. Verify the arguments passed are valid.');
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
(_b = cpFirst.stderr) === null || _b === void 0 ? void 0 : _b.on('data', function (data) {
|
|
594
|
+
if (fileStream) {
|
|
595
|
+
fileStream.write(data);
|
|
596
|
+
}
|
|
597
|
+
successFirst = !optionsNonNull.failOnStdErr;
|
|
598
|
+
if (!optionsNonNull.silent) {
|
|
599
|
+
var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream : optionsNonNull.outStream;
|
|
600
|
+
s.write(data);
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
cpFirst.on('error', function (err) {
|
|
604
|
+
var _a;
|
|
605
|
+
waitingEvents--; //first process is complete with errors
|
|
606
|
+
if (fileStream) {
|
|
607
|
+
fileStream.end();
|
|
608
|
+
}
|
|
609
|
+
(_a = cp.stdin) === null || _a === void 0 ? void 0 : _a.end();
|
|
610
|
+
error = new Error(toolPathFirst + ' failed. ' + err.message);
|
|
611
|
+
if (waitingEvents == 0) {
|
|
612
|
+
reject(error);
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
cpFirst.on('close', function (code, signal) {
|
|
616
|
+
var _a;
|
|
617
|
+
waitingEvents--; //first process is complete
|
|
618
|
+
if (code != 0 && !optionsNonNull.ignoreReturnCode) {
|
|
619
|
+
successFirst = false;
|
|
620
|
+
returnCodeFirst = code;
|
|
621
|
+
returnCode = returnCodeFirst;
|
|
622
|
+
}
|
|
623
|
+
_this._debug('success of first tool:' + successFirst);
|
|
624
|
+
if (fileStream) {
|
|
625
|
+
fileStream.end();
|
|
626
|
+
}
|
|
627
|
+
(_a = cp.stdin) === null || _a === void 0 ? void 0 : _a.end();
|
|
628
|
+
if (waitingEvents == 0) {
|
|
629
|
+
if (error) {
|
|
630
|
+
reject(error);
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
resolve(returnCode);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
var stdbuffer = '';
|
|
638
|
+
(_c = cp.stdout) === null || _c === void 0 ? void 0 : _c.on('data', function (data) {
|
|
639
|
+
_this.emit('stdout', data);
|
|
640
|
+
if (!optionsNonNull.silent) {
|
|
641
|
+
optionsNonNull.outStream.write(data);
|
|
642
|
+
}
|
|
643
|
+
_this._processLineBuffer(data, stdbuffer, function (line) {
|
|
644
|
+
_this.emit('stdline', line);
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
var errbuffer = '';
|
|
648
|
+
(_d = cp.stderr) === null || _d === void 0 ? void 0 : _d.on('data', function (data) {
|
|
649
|
+
_this.emit('stderr', data);
|
|
650
|
+
success = !optionsNonNull.failOnStdErr;
|
|
651
|
+
if (!optionsNonNull.silent) {
|
|
652
|
+
var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream : optionsNonNull.outStream;
|
|
653
|
+
s.write(data);
|
|
654
|
+
}
|
|
655
|
+
_this._processLineBuffer(data, errbuffer, function (line) {
|
|
656
|
+
_this.emit('errline', line);
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
cp.on('error', function (err) {
|
|
660
|
+
waitingEvents--; //process is done with errors
|
|
661
|
+
error = new Error(toolPath + ' failed. ' + err.message);
|
|
662
|
+
if (waitingEvents == 0) {
|
|
663
|
+
reject(error);
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
cp.on('close', function (code, signal) {
|
|
667
|
+
waitingEvents--; //process is complete
|
|
668
|
+
_this._debug('rc:' + code);
|
|
669
|
+
returnCode = code;
|
|
670
|
+
if (stdbuffer.length > 0) {
|
|
671
|
+
_this.emit('stdline', stdbuffer);
|
|
672
|
+
}
|
|
673
|
+
if (errbuffer.length > 0) {
|
|
674
|
+
_this.emit('errline', errbuffer);
|
|
675
|
+
}
|
|
676
|
+
if (code != 0 && !optionsNonNull.ignoreReturnCode) {
|
|
677
|
+
success = false;
|
|
678
|
+
}
|
|
679
|
+
_this._debug('success:' + success);
|
|
680
|
+
if (!successFirst) { //in the case output is piped to another tool, check exit code of both tools
|
|
681
|
+
error = new Error(toolPathFirst + ' failed with return code: ' + returnCodeFirst);
|
|
682
|
+
}
|
|
683
|
+
else if (!success) {
|
|
684
|
+
error = new Error(toolPath + ' failed with return code: ' + code);
|
|
685
|
+
}
|
|
686
|
+
if (waitingEvents == 0) {
|
|
687
|
+
if (error) {
|
|
688
|
+
reject(error);
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
resolve(returnCode);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
});
|
|
696
|
+
};
|
|
519
697
|
ToolRunner.prototype.execWithPiping = function (pipeOutputToTool, options) {
|
|
520
698
|
var _this = this;
|
|
521
699
|
var _a, _b, _c, _d;
|
|
@@ -767,6 +945,104 @@ var ToolRunner = /** @class */ (function (_super) {
|
|
|
767
945
|
* @param options optional exec options. See IExecOptions
|
|
768
946
|
* @returns number
|
|
769
947
|
*/
|
|
948
|
+
ToolRunner.prototype.execAsync = function (options) {
|
|
949
|
+
var _this = this;
|
|
950
|
+
var _a, _b, _c;
|
|
951
|
+
if (this.pipeOutputToTool) {
|
|
952
|
+
return this.execWithPipingAsync(this.pipeOutputToTool, options);
|
|
953
|
+
}
|
|
954
|
+
this._debug('exec tool: ' + this.toolPath);
|
|
955
|
+
this._debug('arguments:');
|
|
956
|
+
this.args.forEach(function (arg) {
|
|
957
|
+
_this._debug(' ' + arg);
|
|
958
|
+
});
|
|
959
|
+
var optionsNonNull = this._cloneExecOptions(options);
|
|
960
|
+
if (!optionsNonNull.silent) {
|
|
961
|
+
optionsNonNull.outStream.write(this._getCommandString(optionsNonNull) + os.EOL);
|
|
962
|
+
}
|
|
963
|
+
var state = new ExecState(optionsNonNull, this.toolPath);
|
|
964
|
+
state.on('debug', function (message) {
|
|
965
|
+
_this._debug(message);
|
|
966
|
+
});
|
|
967
|
+
var cp = child.spawn(this._getSpawnFileName(options), this._getSpawnArgs(optionsNonNull), this._getSpawnOptions(options));
|
|
968
|
+
this.childProcess = cp;
|
|
969
|
+
// it is possible for the child process to end its last line without a new line.
|
|
970
|
+
// because stdout is buffered, this causes the last line to not get sent to the parent
|
|
971
|
+
// stream. Adding this event forces a flush before the child streams are closed.
|
|
972
|
+
(_a = cp.stdout) === null || _a === void 0 ? void 0 : _a.on('finish', function () {
|
|
973
|
+
if (!optionsNonNull.silent) {
|
|
974
|
+
optionsNonNull.outStream.write(os.EOL);
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
var stdbuffer = '';
|
|
978
|
+
(_b = cp.stdout) === null || _b === void 0 ? void 0 : _b.on('data', function (data) {
|
|
979
|
+
_this.emit('stdout', data);
|
|
980
|
+
if (!optionsNonNull.silent) {
|
|
981
|
+
optionsNonNull.outStream.write(data);
|
|
982
|
+
}
|
|
983
|
+
_this._processLineBuffer(data, stdbuffer, function (line) {
|
|
984
|
+
_this.emit('stdline', line);
|
|
985
|
+
});
|
|
986
|
+
});
|
|
987
|
+
var errbuffer = '';
|
|
988
|
+
(_c = cp.stderr) === null || _c === void 0 ? void 0 : _c.on('data', function (data) {
|
|
989
|
+
state.processStderr = true;
|
|
990
|
+
_this.emit('stderr', data);
|
|
991
|
+
if (!optionsNonNull.silent) {
|
|
992
|
+
var s = optionsNonNull.failOnStdErr ? optionsNonNull.errStream : optionsNonNull.outStream;
|
|
993
|
+
s.write(data);
|
|
994
|
+
}
|
|
995
|
+
_this._processLineBuffer(data, errbuffer, function (line) {
|
|
996
|
+
_this.emit('errline', line);
|
|
997
|
+
});
|
|
998
|
+
});
|
|
999
|
+
cp.on('error', function (err) {
|
|
1000
|
+
state.processError = err.message;
|
|
1001
|
+
state.processExited = true;
|
|
1002
|
+
state.processClosed = true;
|
|
1003
|
+
state.CheckComplete();
|
|
1004
|
+
});
|
|
1005
|
+
cp.on('exit', function (code, signal) {
|
|
1006
|
+
state.processExitCode = code;
|
|
1007
|
+
state.processExited = true;
|
|
1008
|
+
_this._debug("Exit code " + code + " received from tool '" + _this.toolPath + "'");
|
|
1009
|
+
state.CheckComplete();
|
|
1010
|
+
});
|
|
1011
|
+
cp.on('close', function (code, signal) {
|
|
1012
|
+
state.processExitCode = code;
|
|
1013
|
+
state.processExited = true;
|
|
1014
|
+
state.processClosed = true;
|
|
1015
|
+
_this._debug("STDIO streams have closed for tool '" + _this.toolPath + "'");
|
|
1016
|
+
state.CheckComplete();
|
|
1017
|
+
});
|
|
1018
|
+
return new Promise(function (resolve, reject) {
|
|
1019
|
+
state.on('done', function (error, exitCode) {
|
|
1020
|
+
if (stdbuffer.length > 0) {
|
|
1021
|
+
_this.emit('stdline', stdbuffer);
|
|
1022
|
+
}
|
|
1023
|
+
if (errbuffer.length > 0) {
|
|
1024
|
+
_this.emit('errline', errbuffer);
|
|
1025
|
+
}
|
|
1026
|
+
cp.removeAllListeners();
|
|
1027
|
+
if (error) {
|
|
1028
|
+
reject(error);
|
|
1029
|
+
}
|
|
1030
|
+
else {
|
|
1031
|
+
resolve(exitCode);
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
});
|
|
1035
|
+
};
|
|
1036
|
+
/**
|
|
1037
|
+
* Exec a tool.
|
|
1038
|
+
* Output will be streamed to the live console.
|
|
1039
|
+
* Returns promise with return code
|
|
1040
|
+
*
|
|
1041
|
+
* @deprecated Use the `execAsync` method that returns a native Javascript promise instead
|
|
1042
|
+
* @param tool path to tool to exec
|
|
1043
|
+
* @param options optional exec options. See IExecOptions
|
|
1044
|
+
* @returns number
|
|
1045
|
+
*/
|
|
770
1046
|
ToolRunner.prototype.exec = function (options) {
|
|
771
1047
|
var _this = this;
|
|
772
1048
|
var _a, _b, _c;
|