@sasjs/cli 6.6.0 → 6.8.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/README.md +2 -1
- package/build/commands/flow/flowCommand.js +11 -1
- package/build/commands/flow/internal/executeFlow.js +44 -19
- package/build/commands/flow/internal/saveLog.d.ts +12 -1
- package/build/commands/flow/internal/saveLog.js +2 -2
- package/build/commands/flow/internal/spec/executeFlow.spec.js +44 -1
- package/build/commands/flow/spec/flowCommand.spec.js +44 -0
- package/build/commands/help/help.js +10 -0
- package/build/commands/index.d.ts +1 -0
- package/build/commands/index.js +3 -1
- package/build/commands/job/internal/execute/sas9.js +16 -13
- package/build/commands/job/internal/execute/sasjs.js +12 -9
- package/build/commands/job/internal/execute/viya.js +41 -36
- package/build/commands/job/jobCommand.js +13 -0
- package/build/commands/job/spec/executeLogOrder.spec.d.ts +1 -0
- package/build/commands/job/spec/executeLogOrder.spec.js +119 -0
- package/build/commands/job/spec/jobCommand.spec.js +32 -0
- package/build/commands/logcheck/collectLogs.d.ts +60 -0
- package/build/commands/logcheck/collectLogs.js +386 -0
- package/build/commands/logcheck/logCheckConfig.d.ts +83 -0
- package/build/commands/logcheck/logCheckConfig.js +343 -0
- package/build/commands/logcheck/logcheckCommand.d.ts +6 -0
- package/build/commands/logcheck/logcheckCommand.js +200 -0
- package/build/commands/logcheck/processLogCheck.d.ts +44 -0
- package/build/commands/logcheck/processLogCheck.js +242 -0
- package/build/commands/logcheck/renderLogCheck.d.ts +129 -0
- package/build/commands/logcheck/renderLogCheck.js +424 -0
- package/build/commands/logcheck/spec/collectLogs.spec.d.ts +1 -0
- package/build/commands/logcheck/spec/collectLogs.spec.js +477 -0
- package/build/commands/logcheck/spec/logCheckConfig.spec.d.ts +1 -0
- package/build/commands/logcheck/spec/logCheckConfig.spec.js +384 -0
- package/build/commands/logcheck/spec/logcheckCommand.spec.d.ts +1 -0
- package/build/commands/logcheck/spec/logcheckCommand.spec.js +360 -0
- package/build/commands/logcheck/spec/processLogCheck.spec.d.ts +1 -0
- package/build/commands/logcheck/spec/processLogCheck.spec.js +354 -0
- package/build/commands/logcheck/spec/renderLogCheck.spec.d.ts +1 -0
- package/build/commands/logcheck/spec/renderLogCheck.spec.js +426 -0
- package/build/commands/logcheck/types.d.ts +106 -0
- package/build/commands/logcheck/types.js +14 -0
- package/build/commands/request/request.js +66 -27
- package/build/commands/request/requestCommand.js +11 -1
- package/build/commands/request/spec/requestCommand.spec.js +40 -0
- package/build/commands/run/run.d.ts +1 -3
- package/build/commands/run/run.js +20 -5
- package/build/commands/run/runCommand.js +9 -0
- package/build/commands/run/spec/runCommand.spec.js +50 -0
- package/build/types/command/commandAliases.js +1 -0
- package/build/types/command/commandFactory.js +2 -0
- package/build/types/command/returnCode.d.ts +2 -1
- package/build/types/command/returnCode.js +4 -0
- package/build/utils/index.d.ts +1 -0
- package/build/utils/index.js +1 -0
- package/build/utils/logcheck.d.ts +44 -0
- package/build/utils/logcheck.js +224 -0
- package/build/utils/spec/logcheck.spec.d.ts +1 -0
- package/build/utils/spec/logcheck.spec.js +297 -0
- package/package.json +3 -3
|
@@ -44,12 +44,14 @@ exports.getContextName = getContextName;
|
|
|
44
44
|
var displayResult_1 = require("../../../../utils/displayResult");
|
|
45
45
|
var file_1 = require("../../../../utils/file");
|
|
46
46
|
var fetchLogFileContent_1 = require("../../../shared/fetchLogFileContent");
|
|
47
|
+
var logcheck_1 = require("../../../../utils/logcheck");
|
|
48
|
+
var utils_1 = require("../../../../utils/utils");
|
|
47
49
|
var path_1 = __importDefault(require("path"));
|
|
48
50
|
var node_1 = require("@sasjs/adapter/node");
|
|
49
|
-
var
|
|
50
|
-
var
|
|
51
|
+
var utils_2 = require("@sasjs/utils");
|
|
52
|
+
var utils_3 = require("../../../../utils/");
|
|
51
53
|
var command_1 = require("../../../../types/command");
|
|
52
|
-
var
|
|
54
|
+
var utils_4 = require("../utils");
|
|
53
55
|
/**
|
|
54
56
|
* Triggers existing job for execution on Viya server.
|
|
55
57
|
* @param {object} sasjs - configuration object of SAS adapter.
|
|
@@ -90,23 +92,23 @@ function executeJobViya(sasjs, authConfig, jobPath, target, waitForJob, output,
|
|
|
90
92
|
if (!source) return [3 /*break*/, 5];
|
|
91
93
|
if (!(0, file_1.isJsonFile)(source))
|
|
92
94
|
throw 'Source file has to be JSON.';
|
|
93
|
-
return [4 /*yield*/, (0,
|
|
95
|
+
return [4 /*yield*/, (0, utils_2.fileExists)(source).catch(function (_) {
|
|
94
96
|
throw 'Error while checking if source file exists.';
|
|
95
97
|
})];
|
|
96
98
|
case 3:
|
|
97
99
|
_c.sent();
|
|
98
|
-
return [4 /*yield*/, (0,
|
|
100
|
+
return [4 /*yield*/, (0, utils_2.readFile)(source).catch(function (_) {
|
|
99
101
|
throw 'Error while reading source file.';
|
|
100
102
|
})];
|
|
101
103
|
case 4:
|
|
102
104
|
source = _c.sent();
|
|
103
105
|
macroVars = JSON.parse(source);
|
|
104
|
-
if (!(0,
|
|
106
|
+
if (!(0, utils_2.isMacroVars)(macroVars)) {
|
|
105
107
|
throw "Provided source is not valid. An example of valid source:\n{ macroVars: { name1: 'value1', name2: 'value2' } }";
|
|
106
108
|
}
|
|
107
109
|
_c.label = 5;
|
|
108
110
|
case 5: return [4 /*yield*/, sasjs
|
|
109
|
-
.startComputeJob(jobPath, null, { contextName: contextName }, authConfig, waitForJob || !!logFile, pollOptions, true, macroVars === null || macroVars === void 0 ? void 0 : macroVars.macroVars, undefined, (0,
|
|
111
|
+
.startComputeJob(jobPath, null, { contextName: contextName }, authConfig, waitForJob || !!logFile, pollOptions, true, macroVars === null || macroVars === void 0 ? void 0 : macroVars.macroVars, undefined, (0, utils_3.persistTokensRefreshedByAdapter)(target))
|
|
110
112
|
.catch(function (err) { return __awaiter(_this, void 0, void 0, function () {
|
|
111
113
|
var logData;
|
|
112
114
|
var _a, _b;
|
|
@@ -121,7 +123,7 @@ function executeJobViya(sasjs, authConfig, jobPath, target, waitForJob, output,
|
|
|
121
123
|
case 1:
|
|
122
124
|
logData = _c.sent();
|
|
123
125
|
// save log
|
|
124
|
-
return [4 /*yield*/, (0,
|
|
126
|
+
return [4 /*yield*/, (0, utils_4.saveLog)(logData, logFile, jobPath)];
|
|
125
127
|
case 2:
|
|
126
128
|
// save log
|
|
127
129
|
_c.sent();
|
|
@@ -129,11 +131,11 @@ function executeJobViya(sasjs, authConfig, jobPath, target, waitForJob, output,
|
|
|
129
131
|
case 3:
|
|
130
132
|
(0, displayResult_1.displayError)(err);
|
|
131
133
|
// terminate process with status code 2
|
|
132
|
-
(0,
|
|
134
|
+
(0, utils_3.terminateProcess)(2);
|
|
133
135
|
_c.label = 4;
|
|
134
136
|
case 4:
|
|
135
137
|
if (!(err === null || err === void 0 ? void 0 : err.log)) return [3 /*break*/, 6];
|
|
136
|
-
return [4 /*yield*/, (0,
|
|
138
|
+
return [4 /*yield*/, (0, utils_4.saveLog)(err.log, logFile, jobPath)
|
|
137
139
|
// handle use case when job wasn't found
|
|
138
140
|
];
|
|
139
141
|
case 5:
|
|
@@ -174,13 +176,13 @@ function executeJobViya(sasjs, authConfig, jobPath, target, waitForJob, output,
|
|
|
174
176
|
_c.sent();
|
|
175
177
|
_c.label = 8;
|
|
176
178
|
case 8:
|
|
177
|
-
if (!(submittedJob && submittedJob.links)) return [3 /*break*/,
|
|
179
|
+
if (!(submittedJob && submittedJob.links)) return [3 /*break*/, 22];
|
|
178
180
|
if (!result)
|
|
179
181
|
result = true;
|
|
180
|
-
if (!(output || logFile)) return [3 /*break*/,
|
|
182
|
+
if (!(output || logFile)) return [3 /*break*/, 21];
|
|
181
183
|
_c.label = 9;
|
|
182
184
|
case 9:
|
|
183
|
-
_c.trys.push([9,
|
|
185
|
+
_c.trys.push([9, 20, , 21]);
|
|
184
186
|
outputJson = JSON.stringify(submittedJob, null, 2);
|
|
185
187
|
if (!(typeof output === 'string')) return [3 /*break*/, 14];
|
|
186
188
|
currentDirPath = path_1.default.isAbsolute(output)
|
|
@@ -192,14 +194,14 @@ function executeJobViya(sasjs, authConfig, jobPath, target, waitForJob, output,
|
|
|
192
194
|
folderPath = outputPath.split(path_1.default.sep);
|
|
193
195
|
folderPath.pop();
|
|
194
196
|
parentFolderPath = folderPath.join(path_1.default.sep);
|
|
195
|
-
return [4 /*yield*/, (0,
|
|
197
|
+
return [4 /*yield*/, (0, utils_2.folderExists)(parentFolderPath)];
|
|
196
198
|
case 10:
|
|
197
199
|
if (!!(_c.sent())) return [3 /*break*/, 12];
|
|
198
|
-
return [4 /*yield*/, (0,
|
|
200
|
+
return [4 /*yield*/, (0, utils_2.createFolder)(parentFolderPath)];
|
|
199
201
|
case 11:
|
|
200
202
|
_c.sent();
|
|
201
203
|
_c.label = 12;
|
|
202
|
-
case 12: return [4 /*yield*/, (0,
|
|
204
|
+
case 12: return [4 /*yield*/, (0, utils_2.createFile)(outputPath, outputJson)];
|
|
203
205
|
case 13:
|
|
204
206
|
_c.sent();
|
|
205
207
|
(0, displayResult_1.displaySuccess)("Output saved to: ".concat(outputPath));
|
|
@@ -212,50 +214,53 @@ function executeJobViya(sasjs, authConfig, jobPath, target, waitForJob, output,
|
|
|
212
214
|
}
|
|
213
215
|
_c.label = 15;
|
|
214
216
|
case 15:
|
|
215
|
-
if (!(logFile && !pollOptions.streamLog)) return [3 /*break*/,
|
|
217
|
+
if (!(logFile && !pollOptions.streamLog)) return [3 /*break*/, 19];
|
|
216
218
|
logObj = submittedJob.links.find(function (link) { return link.rel === 'log' && link.method === 'GET'; });
|
|
217
|
-
if (!logObj) return [3 /*break*/,
|
|
219
|
+
if (!logObj) return [3 /*break*/, 19];
|
|
218
220
|
logUrl = target.serverUrl + logObj.href;
|
|
219
221
|
logCount = submittedJob.logStatistics.lineCount;
|
|
220
222
|
return [4 /*yield*/, (0, fetchLogFileContent_1.fetchLogFileContent)(sasjs, authConfig.access_token, logUrl, logCount)];
|
|
221
223
|
case 16:
|
|
222
224
|
logData = _c.sent();
|
|
223
|
-
return [4 /*yield*/, (0,
|
|
225
|
+
return [4 /*yield*/, (0, utils_4.saveLog)(logData, logFile, jobPath)];
|
|
224
226
|
case 17:
|
|
225
227
|
_c.sent();
|
|
226
|
-
|
|
228
|
+
return [4 /*yield*/, (0, logcheck_1.checkLog)(typeof logData === 'string' ? logData : (0, utils_1.parseLogLines)(logData), jobPath)];
|
|
227
229
|
case 18:
|
|
228
|
-
|
|
229
|
-
|
|
230
|
+
_c.sent();
|
|
231
|
+
_c.label = 19;
|
|
230
232
|
case 19:
|
|
233
|
+
result = submittedJob;
|
|
234
|
+
return [3 /*break*/, 21];
|
|
235
|
+
case 20:
|
|
231
236
|
error_1 = _c.sent();
|
|
232
237
|
// handle use case when submitted job can't be parsed
|
|
233
238
|
result = false;
|
|
234
239
|
(0, displayResult_1.displayError)(null, 'An error has occurred when parsing an output of the job.');
|
|
235
|
-
return [3 /*break*/,
|
|
236
|
-
case
|
|
240
|
+
return [3 /*break*/, 21];
|
|
241
|
+
case 21:
|
|
237
242
|
// wait for job state and return status(0,1,2) based on it
|
|
238
243
|
if (waitForJob && submittedJob.state) {
|
|
239
244
|
switch (submittedJob.state) {
|
|
240
245
|
case 'completed':
|
|
241
|
-
(0,
|
|
246
|
+
(0, utils_3.terminateProcess)(0);
|
|
242
247
|
case 'warning':
|
|
243
248
|
// if ignoreWarnings flag is present, process will be terminated with
|
|
244
249
|
// status code 0, otherwise status code will be 1
|
|
245
|
-
(0,
|
|
250
|
+
(0, utils_3.terminateProcess)(ignoreWarnings ? 0 : 1);
|
|
246
251
|
case 'error':
|
|
247
|
-
(0,
|
|
252
|
+
(0, utils_3.terminateProcess)(2);
|
|
248
253
|
default:
|
|
249
254
|
break;
|
|
250
255
|
}
|
|
251
256
|
}
|
|
252
|
-
return [3 /*break*/,
|
|
253
|
-
case
|
|
257
|
+
return [3 /*break*/, 23];
|
|
258
|
+
case 22:
|
|
254
259
|
if (result) {
|
|
255
|
-
(0,
|
|
260
|
+
(0, utils_3.terminateProcess)(command_1.ReturnCode.InternalError);
|
|
256
261
|
}
|
|
257
|
-
_c.label =
|
|
258
|
-
case
|
|
262
|
+
_c.label = 23;
|
|
263
|
+
case 23:
|
|
259
264
|
(_b = process.logger) === null || _b === void 0 ? void 0 : _b.info("This job was executed in ".concat((endTime - startTime) / 1000, " seconds"));
|
|
260
265
|
return [2 /*return*/, result];
|
|
261
266
|
}
|
|
@@ -271,7 +276,7 @@ function executeJobViya(sasjs, authConfig, jobPath, target, waitForJob, output,
|
|
|
271
276
|
function getContextName(target) {
|
|
272
277
|
var _a;
|
|
273
278
|
// default execution context of @sasjs/cli
|
|
274
|
-
var defaultContextName =
|
|
279
|
+
var defaultContextName = utils_3.contextName;
|
|
275
280
|
// get gontext name from target
|
|
276
281
|
if (target === null || target === void 0 ? void 0 : target.contextName)
|
|
277
282
|
return target.contextName;
|
|
@@ -311,14 +316,14 @@ function displayStatus(submittedJob_1, statusFile_1) {
|
|
|
311
316
|
folderPath = statusFile.split(path_1.default.sep);
|
|
312
317
|
folderPath.pop();
|
|
313
318
|
parentFolderPath = folderPath.join(path_1.default.sep);
|
|
314
|
-
return [4 /*yield*/, (0,
|
|
319
|
+
return [4 /*yield*/, (0, utils_2.folderExists)(parentFolderPath)];
|
|
315
320
|
case 1:
|
|
316
321
|
if (!!(_a.sent())) return [3 /*break*/, 3];
|
|
317
|
-
return [4 /*yield*/, (0,
|
|
322
|
+
return [4 /*yield*/, (0, utils_2.createFolder)(parentFolderPath)];
|
|
318
323
|
case 2:
|
|
319
324
|
_a.sent();
|
|
320
325
|
_a.label = 3;
|
|
321
|
-
case 3: return [4 /*yield*/, (0,
|
|
326
|
+
case 3: return [4 /*yield*/, (0, utils_2.createFile)(statusFile, status)
|
|
322
327
|
// display file path to status file
|
|
323
328
|
];
|
|
324
329
|
case 4:
|
|
@@ -62,6 +62,7 @@ var targetCommand_1 = require("../../types/command/targetCommand");
|
|
|
62
62
|
var utils_2 = require("../../utils");
|
|
63
63
|
var getLogFilePath_1 = require("../../utils/getLogFilePath");
|
|
64
64
|
var prefixAppLoc_1 = require("../../utils/prefixAppLoc");
|
|
65
|
+
var logcheck_1 = require("../../utils/logcheck");
|
|
65
66
|
var execute_1 = require("./internal/execute");
|
|
66
67
|
var node_1 = __importDefault(require("@sasjs/adapter/node"));
|
|
67
68
|
var JobSubCommand;
|
|
@@ -126,6 +127,11 @@ var executeParseOptions = {
|
|
|
126
127
|
alias: 'v',
|
|
127
128
|
default: false,
|
|
128
129
|
description: "If present, CLI will return status 0, 1 or 2 together with HTTP response summaries. If set to 'bleached', HTTP response summaries will be logged without extra colors."
|
|
130
|
+
},
|
|
131
|
+
logcheck: {
|
|
132
|
+
type: 'boolean',
|
|
133
|
+
default: undefined,
|
|
134
|
+
description: 'Check the SAS log this job returned, and fail when logCheck in sasjsconfig.json says so. --no-logcheck switches both the report and the verdict off.'
|
|
129
135
|
}
|
|
130
136
|
};
|
|
131
137
|
var JobCommand = /** @class */ (function (_super) {
|
|
@@ -160,6 +166,7 @@ var JobCommand = /** @class */ (function (_super) {
|
|
|
160
166
|
return __generator(this, function (_f) {
|
|
161
167
|
switch (_f.label) {
|
|
162
168
|
case 0:
|
|
169
|
+
(0, logcheck_1.setLogCheckMode)((0, logcheck_1.logCheckModeOf)(this.parsed.logcheck));
|
|
163
170
|
returnStatusOnly = !!this.parsed.returnStatusOnly;
|
|
164
171
|
if (returnStatusOnly) {
|
|
165
172
|
process.logger.warn('--returnStatusOnly (-r) flag is deprecated.');
|
|
@@ -257,6 +264,8 @@ var JobCommand = /** @class */ (function (_super) {
|
|
|
257
264
|
.catch(function (err) {
|
|
258
265
|
var _a;
|
|
259
266
|
// handle job execution failure
|
|
267
|
+
if ((0, logcheck_1.isLogCheckFailure)(err))
|
|
268
|
+
return command_1.ReturnCode.LogCheckError;
|
|
260
269
|
(_a = process.logger) === null || _a === void 0 ? void 0 : _a.error('Error executing job: ', err);
|
|
261
270
|
return command_1.ReturnCode.InternalError;
|
|
262
271
|
})];
|
|
@@ -293,6 +302,8 @@ var JobCommand = /** @class */ (function (_super) {
|
|
|
293
302
|
.catch(function (err) {
|
|
294
303
|
var _a;
|
|
295
304
|
// handle job execution failure
|
|
305
|
+
if ((0, logcheck_1.isLogCheckFailure)(err))
|
|
306
|
+
return command_1.ReturnCode.LogCheckError;
|
|
296
307
|
(_a = process.logger) === null || _a === void 0 ? void 0 : _a.error('Error executing job: ', err);
|
|
297
308
|
return command_1.ReturnCode.InternalError;
|
|
298
309
|
})];
|
|
@@ -334,6 +345,8 @@ var JobCommand = /** @class */ (function (_super) {
|
|
|
334
345
|
.catch(function (err) {
|
|
335
346
|
var _a;
|
|
336
347
|
// handle job execution failure
|
|
348
|
+
if ((0, logcheck_1.isLogCheckFailure)(err))
|
|
349
|
+
return command_1.ReturnCode.LogCheckError;
|
|
337
350
|
(_a = process.logger) === null || _a === void 0 ? void 0 : _a.error('Error executing job: ', err);
|
|
338
351
|
return command_1.ReturnCode.InternalError;
|
|
339
352
|
})];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
45
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
46
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
47
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
48
|
+
function step(op) {
|
|
49
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
50
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
51
|
+
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;
|
|
52
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
53
|
+
switch (op[0]) {
|
|
54
|
+
case 0: case 1: t = op; break;
|
|
55
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
56
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
57
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
58
|
+
default:
|
|
59
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
60
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
61
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
62
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
63
|
+
if (t[2]) _.ops.pop();
|
|
64
|
+
_.trys.pop(); continue;
|
|
65
|
+
}
|
|
66
|
+
op = body.call(thisArg, _);
|
|
67
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
68
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
72
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
73
|
+
};
|
|
74
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
75
|
+
var node_1 = __importDefault(require("@sasjs/adapter/node"));
|
|
76
|
+
var jobUtils = __importStar(require("../internal/utils"));
|
|
77
|
+
var logcheck = __importStar(require("../../../utils/logcheck"));
|
|
78
|
+
var sas9_1 = require("../internal/execute/sas9");
|
|
79
|
+
/**
|
|
80
|
+
* A run that fails the log check is the run whose log someone wants to read, so
|
|
81
|
+
* the file has to be written before the check can throw - otherwise `--log`
|
|
82
|
+
* produces nothing exactly when it is needed.
|
|
83
|
+
*/
|
|
84
|
+
describe('job execute log handling', function () {
|
|
85
|
+
beforeEach(function () {
|
|
86
|
+
process.logger = {
|
|
87
|
+
success: jest.fn(),
|
|
88
|
+
info: jest.fn(),
|
|
89
|
+
warn: jest.fn(),
|
|
90
|
+
error: jest.fn()
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
it('writes the log before a failing check can throw', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
94
|
+
var sasjs, saveSpy, checkSpy;
|
|
95
|
+
return __generator(this, function (_a) {
|
|
96
|
+
switch (_a.label) {
|
|
97
|
+
case 0:
|
|
98
|
+
sasjs = new node_1.default();
|
|
99
|
+
jest.spyOn(sasjs, 'request').mockResolvedValue({
|
|
100
|
+
status: 200,
|
|
101
|
+
log: 'ERROR 22-322: Syntax error',
|
|
102
|
+
result: {}
|
|
103
|
+
});
|
|
104
|
+
saveSpy = jest
|
|
105
|
+
.spyOn(jobUtils, 'saveLog')
|
|
106
|
+
.mockResolvedValue(undefined);
|
|
107
|
+
checkSpy = jest
|
|
108
|
+
.spyOn(logcheck, 'checkLog')
|
|
109
|
+
.mockRejectedValue(new Error('SAS log check failed'));
|
|
110
|
+
return [4 /*yield*/, expect((0, sas9_1.executeJobSas9)(sasjs, {}, 'job/path', 'job.log')).rejects.toThrow('SAS log check failed')];
|
|
111
|
+
case 1:
|
|
112
|
+
_a.sent();
|
|
113
|
+
expect(saveSpy).toHaveBeenCalledWith('ERROR 22-322: Syntax error', 'job.log', 'job/path');
|
|
114
|
+
expect(saveSpy.mock.invocationCallOrder[0]).toBeLessThan(checkSpy.mock.invocationCallOrder[0]);
|
|
115
|
+
return [2 /*return*/];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}); });
|
|
119
|
+
});
|
|
@@ -106,6 +106,7 @@ var utils_1 = require("@sasjs/utils");
|
|
|
106
106
|
var SasjsUtilsFilesModule = __importStar(require("@sasjs/utils/file"));
|
|
107
107
|
var configUtils = __importStar(require("../../../utils/config"));
|
|
108
108
|
var command_1 = require("../../../types/command");
|
|
109
|
+
var logcheck_1 = require("../../../utils/logcheck");
|
|
109
110
|
var utilsModule = __importStar(require("../internal/utils"));
|
|
110
111
|
var defaultArgs = ['node', 'sasjs', 'job', 'execute'];
|
|
111
112
|
var targetViya = new utils_1.Target({
|
|
@@ -149,6 +150,37 @@ describe('JobCommand', function () {
|
|
|
149
150
|
beforeEach(function () {
|
|
150
151
|
setupMocksForViya();
|
|
151
152
|
});
|
|
153
|
+
afterEach(function () { return (0, logcheck_1.setLogCheckMode)('auto'); });
|
|
154
|
+
it('should return the logcheck code when the log check failed the job', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
155
|
+
var args, _a;
|
|
156
|
+
return __generator(this, function (_b) {
|
|
157
|
+
switch (_b.label) {
|
|
158
|
+
case 0:
|
|
159
|
+
jest
|
|
160
|
+
.spyOn(viyaExecuteModule, 'executeJobViya')
|
|
161
|
+
.mockImplementation(function () {
|
|
162
|
+
return Promise.reject(new logcheck_1.LogCheckFailure('2 errors'));
|
|
163
|
+
});
|
|
164
|
+
args = __spreadArray(__spreadArray([], __read(defaultArgs), false), [jobPath], false);
|
|
165
|
+
_a = expect;
|
|
166
|
+
return [4 /*yield*/, new jobCommand_1.JobCommand(args).execute()];
|
|
167
|
+
case 1:
|
|
168
|
+
_a.apply(void 0, [_b.sent()]).toEqual(command_1.ReturnCode.LogCheckError);
|
|
169
|
+
return [2 /*return*/];
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}); });
|
|
173
|
+
it('should switch the log check off for --no-logcheck', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
174
|
+
return __generator(this, function (_a) {
|
|
175
|
+
switch (_a.label) {
|
|
176
|
+
case 0: return [4 /*yield*/, executeCommandWrapper([jobPath, '--no-logcheck'])];
|
|
177
|
+
case 1:
|
|
178
|
+
_a.sent();
|
|
179
|
+
expect((0, logcheck_1.getLogCheckMode)()).toEqual('off');
|
|
180
|
+
return [2 /*return*/];
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}); });
|
|
152
184
|
it('should parse sasjs job execute command', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
153
185
|
var _a;
|
|
154
186
|
return __generator(this, function (_b) {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { LogIssue } from '@sasjs/utils/logs';
|
|
2
|
+
import { LogCheckConfig, ScannedLog, SkippedFile } from './types';
|
|
3
|
+
/** A log bigger than this is reported and skipped rather than read. */
|
|
4
|
+
export declare const MAX_LOG_BYTES: number;
|
|
5
|
+
export interface CollectedFiles {
|
|
6
|
+
/** Absolute paths of the files that will be read, in report order. */
|
|
7
|
+
files: string[];
|
|
8
|
+
/** Paths the user named that do not exist. */
|
|
9
|
+
missing: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Folders that could not be listed, with the reason.
|
|
12
|
+
*
|
|
13
|
+
* A folder the process cannot read is not an empty folder: the logs inside
|
|
14
|
+
* it were never looked at, so it has to reach the report and it has to fail
|
|
15
|
+
* the gate - a check that goes green on a directory it could not open is
|
|
16
|
+
* worse than no check.
|
|
17
|
+
*/
|
|
18
|
+
unreadable: SkippedFile[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Expands the paths a user named into the files to read.
|
|
22
|
+
*
|
|
23
|
+
* A file is taken as it is; a folder is walked, because the reason a user
|
|
24
|
+
* points at `sasjsresults` is that they do not know which run left which log.
|
|
25
|
+
* Order is sorted so that two runs over the same folder produce the same
|
|
26
|
+
* report, which is what makes a diff of two reports readable.
|
|
27
|
+
*/
|
|
28
|
+
export declare const collectLogFiles: (paths: string[]) => Promise<CollectedFiles>;
|
|
29
|
+
/**
|
|
30
|
+
* The path a report shows for a file: relative to the project folder where
|
|
31
|
+
* that is shorter and does not climb out of it, absolute otherwise.
|
|
32
|
+
*
|
|
33
|
+
* Forward slashes throughout, so a report generated on Windows and one
|
|
34
|
+
* generated on Linux describe the same log the same way, and so a path can be
|
|
35
|
+
* dropped into a CI annotation without escaping.
|
|
36
|
+
*/
|
|
37
|
+
export declare const toDisplayPath: (filePath: string) => string;
|
|
38
|
+
/**
|
|
39
|
+
* Parses one log and splits its issues into the ones reported and the ones
|
|
40
|
+
* suppressed by message code.
|
|
41
|
+
*
|
|
42
|
+
* A file that is not a SAS log is skipped rather than reported as clean: a
|
|
43
|
+
* Python traceback and a shell build log both begin lines with `ERROR:`, and
|
|
44
|
+
* `isSasLog` is what tells them from the real thing.
|
|
45
|
+
*/
|
|
46
|
+
export declare const scanLogFile: (filePath: string, config: LogCheckConfig) => Promise<ScannedLog>;
|
|
47
|
+
/**
|
|
48
|
+
* Splits parsed issues by the suppressed message codes.
|
|
49
|
+
*
|
|
50
|
+
* Matching is on the code alone, because that is what SAS keeps stable: the
|
|
51
|
+
* text of a note carries values from the data and changes between runs, while
|
|
52
|
+
* `49-169` means the same thing every time.
|
|
53
|
+
*/
|
|
54
|
+
export declare const partitionIssues: (issues: LogIssue[], ignoreCodes: string[]) => {
|
|
55
|
+
issues: LogIssue[];
|
|
56
|
+
suppressed: LogIssue[];
|
|
57
|
+
};
|
|
58
|
+
export declare const countIssues: (issues: LogIssue[]) => import("./types").IssueCounts;
|
|
59
|
+
/** A file the check declined to open, as the report shows it. */
|
|
60
|
+
export declare const toSkippedFile: (log: ScannedLog) => SkippedFile;
|