@sasjs/cli 6.7.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 +1 -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/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/logCheckConfig.d.ts +11 -0
- package/build/commands/logcheck/logCheckConfig.js +86 -26
- package/build/commands/logcheck/renderLogCheck.d.ts +1 -0
- package/build/commands/logcheck/renderLogCheck.js +1 -0
- package/build/commands/logcheck/spec/logCheckConfig.spec.js +63 -2
- package/build/commands/logcheck/types.d.ts +8 -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/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 +1 -1
|
@@ -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) {
|
|
@@ -14,6 +14,17 @@ export declare const DEFAULT_FOLDER = "sasjsresults";
|
|
|
14
14
|
* @param source - the file it came from, named in the error message.
|
|
15
15
|
*/
|
|
16
16
|
export declare const parseLogCheckSection: (section: unknown, source?: string) => LogCheckConfig;
|
|
17
|
+
/**
|
|
18
|
+
* Where a project's config may be, in the order they are tried.
|
|
19
|
+
*
|
|
20
|
+
* `sasjs/sasjsconfig.json` is the SASjs convention and the one the rest of the
|
|
21
|
+
* CLI reads, so it wins. A `sasjsconfig.json` at the project root is still
|
|
22
|
+
* honoured, because a folder holding a single log and a hand-written config is
|
|
23
|
+
* exactly the case this command is meant to serve - but the two are never
|
|
24
|
+
* confused for each other, and the convention cannot be shadowed by a stray
|
|
25
|
+
* file next to it.
|
|
26
|
+
*/
|
|
27
|
+
export declare const configCandidates: (projectDir: string) => string[];
|
|
17
28
|
/**
|
|
18
29
|
* Reads the `logCheck` policy from the project's `sasjsconfig.json`.
|
|
19
30
|
*
|
|
@@ -46,6 +46,17 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
46
46
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
|
+
var __values = (this && this.__values) || function(o) {
|
|
50
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
51
|
+
if (m) return m.call(o);
|
|
52
|
+
if (o && typeof o.length === "number") return {
|
|
53
|
+
next: function () {
|
|
54
|
+
if (o && i >= o.length) o = void 0;
|
|
55
|
+
return { value: o && o[i++], done: !o };
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
59
|
+
};
|
|
49
60
|
var __read = (this && this.__read) || function (o, n) {
|
|
50
61
|
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
51
62
|
if (!m) return o;
|
|
@@ -75,7 +86,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
75
86
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
76
87
|
};
|
|
77
88
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
78
|
-
exports.toPosix = exports.globToRegExp = exports.isIgnoredPath = exports.matchesSegments = exports.matchesPath = exports.mergeConfig = exports.readLogCheckConfig = exports.parseLogCheckSection = exports.DEFAULT_FOLDER = exports.CONFIG_KEY = void 0;
|
|
89
|
+
exports.toPosix = exports.globToRegExp = exports.isIgnoredPath = exports.matchesSegments = exports.matchesPath = exports.mergeConfig = exports.readLogCheckConfig = exports.configCandidates = exports.parseLogCheckSection = exports.DEFAULT_FOLDER = exports.CONFIG_KEY = void 0;
|
|
79
90
|
var path_1 = __importDefault(require("path"));
|
|
80
91
|
var utils_1 = require("@sasjs/utils");
|
|
81
92
|
var types_1 = require("./types");
|
|
@@ -102,7 +113,7 @@ var parseLogCheckSection = function (section, source) {
|
|
|
102
113
|
if (typeof section !== 'object' || Array.isArray(section)) {
|
|
103
114
|
throw new Error("The `".concat(exports.CONFIG_KEY, "` property in ").concat(source, " must be an object."));
|
|
104
115
|
}
|
|
105
|
-
var _a = section, failOn = _a.failOn, maxWarnings = _a.maxWarnings, ignoreCodes = _a.ignoreCodes, ignorePaths = _a.ignorePaths, folder = _a.folder;
|
|
116
|
+
var _a = section, failOn = _a.failOn, maxWarnings = _a.maxWarnings, ignoreCodes = _a.ignoreCodes, ignorePaths = _a.ignorePaths, folder = _a.folder, autoCheck = _a.autoCheck;
|
|
106
117
|
if (failOn !== undefined) {
|
|
107
118
|
if (!failOnValues.includes(failOn)) {
|
|
108
119
|
throw new Error("The `".concat(exports.CONFIG_KEY, ".failOn` property in ").concat(source, " must be one of ").concat(failOnValues.join(', '), " - received `").concat(String(failOn), "`."));
|
|
@@ -123,6 +134,12 @@ var parseLogCheckSection = function (section, source) {
|
|
|
123
134
|
if (ignorePaths !== undefined) {
|
|
124
135
|
config.ignorePaths = stringList(ignorePaths, "".concat(exports.CONFIG_KEY, ".ignorePaths"), source);
|
|
125
136
|
}
|
|
137
|
+
if (autoCheck !== undefined) {
|
|
138
|
+
if (typeof autoCheck !== 'boolean') {
|
|
139
|
+
throw new Error("The `".concat(exports.CONFIG_KEY, ".autoCheck` property in ").concat(source, " must be true or false - received `").concat(String(autoCheck), "`."));
|
|
140
|
+
}
|
|
141
|
+
config.autoCheck = autoCheck;
|
|
142
|
+
}
|
|
126
143
|
if (folder !== undefined) {
|
|
127
144
|
if (typeof folder !== 'string' || !folder.trim()) {
|
|
128
145
|
throw new Error("The `".concat(exports.CONFIG_KEY, ".folder` property in ").concat(source, " must be a non-empty string."));
|
|
@@ -132,6 +149,21 @@ var parseLogCheckSection = function (section, source) {
|
|
|
132
149
|
return config;
|
|
133
150
|
};
|
|
134
151
|
exports.parseLogCheckSection = parseLogCheckSection;
|
|
152
|
+
/**
|
|
153
|
+
* Where a project's config may be, in the order they are tried.
|
|
154
|
+
*
|
|
155
|
+
* `sasjs/sasjsconfig.json` is the SASjs convention and the one the rest of the
|
|
156
|
+
* CLI reads, so it wins. A `sasjsconfig.json` at the project root is still
|
|
157
|
+
* honoured, because a folder holding a single log and a hand-written config is
|
|
158
|
+
* exactly the case this command is meant to serve - but the two are never
|
|
159
|
+
* confused for each other, and the convention cannot be shadowed by a stray
|
|
160
|
+
* file next to it.
|
|
161
|
+
*/
|
|
162
|
+
var configCandidates = function (projectDir) { return [
|
|
163
|
+
path_1.default.join(projectDir, 'sasjs', 'sasjsconfig.json'),
|
|
164
|
+
path_1.default.join(projectDir, 'sasjsconfig.json')
|
|
165
|
+
]; };
|
|
166
|
+
exports.configCandidates = configCandidates;
|
|
135
167
|
/**
|
|
136
168
|
* Reads the `logCheck` policy from the project's `sasjsconfig.json`.
|
|
137
169
|
*
|
|
@@ -140,39 +172,67 @@ exports.parseLogCheckSection = parseLogCheckSection;
|
|
|
140
172
|
* whole point of checking a log somebody else produced.
|
|
141
173
|
*/
|
|
142
174
|
var readLogCheckConfig = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
143
|
-
var projectDir,
|
|
144
|
-
var
|
|
145
|
-
return __generator(this, function (
|
|
146
|
-
switch (
|
|
175
|
+
var projectDir, _a, _b, configPath, raw, e_1_1;
|
|
176
|
+
var e_1, _c;
|
|
177
|
+
return __generator(this, function (_d) {
|
|
178
|
+
switch (_d.label) {
|
|
147
179
|
case 0:
|
|
148
180
|
projectDir = process.projectDir || process.cwd();
|
|
149
|
-
|
|
150
|
-
return [4 /*yield*/, (0, utils_1.readFile)(configPath).catch(function () { return undefined; })];
|
|
181
|
+
_d.label = 1;
|
|
151
182
|
case 1:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
183
|
+
_d.trys.push([1, 6, 7, 8]);
|
|
184
|
+
_a = __values((0, exports.configCandidates)(projectDir)), _b = _a.next();
|
|
185
|
+
_d.label = 2;
|
|
186
|
+
case 2:
|
|
187
|
+
if (!!_b.done) return [3 /*break*/, 5];
|
|
188
|
+
configPath = _b.value;
|
|
189
|
+
return [4 /*yield*/, (0, utils_1.readFile)(configPath).catch(function () { return undefined; })];
|
|
190
|
+
case 3:
|
|
191
|
+
raw = _d.sent();
|
|
192
|
+
if (raw)
|
|
193
|
+
return [2 /*return*/, readConfigAt(configPath, raw)];
|
|
194
|
+
_d.label = 4;
|
|
195
|
+
case 4:
|
|
196
|
+
_b = _a.next();
|
|
197
|
+
return [3 /*break*/, 2];
|
|
198
|
+
case 5: return [3 /*break*/, 8];
|
|
199
|
+
case 6:
|
|
200
|
+
e_1_1 = _d.sent();
|
|
201
|
+
e_1 = { error: e_1_1 };
|
|
202
|
+
return [3 /*break*/, 8];
|
|
203
|
+
case 7:
|
|
155
204
|
try {
|
|
156
|
-
|
|
205
|
+
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
|
|
157
206
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
section = (_b = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.config) === null || _a === void 0 ? void 0 : _a[exports.CONFIG_KEY]) !== null && _b !== void 0 ? _b : parsed === null || parsed === void 0 ? void 0 : parsed[exports.CONFIG_KEY];
|
|
162
|
-
config = (0, exports.parseLogCheckSection)(section, configPath);
|
|
163
|
-
// A project may have moved its results folder; the bare command follows it,
|
|
164
|
-
// unless the logCheck section names a folder of its own.
|
|
165
|
-
if (!config.folder) {
|
|
166
|
-
resultsFolder = (_d = (_c = parsed === null || parsed === void 0 ? void 0 : parsed.config) === null || _c === void 0 ? void 0 : _c.sasjsResultsFolder) !== null && _d !== void 0 ? _d : parsed === null || parsed === void 0 ? void 0 : parsed.sasjsResultsFolder;
|
|
167
|
-
if (typeof resultsFolder === 'string' && resultsFolder.trim()) {
|
|
168
|
-
config.folder = resultsFolder.trim();
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return [2 /*return*/, config];
|
|
207
|
+
finally { if (e_1) throw e_1.error; }
|
|
208
|
+
return [7 /*endfinally*/];
|
|
209
|
+
case 8: return [2 /*return*/, __assign(__assign({}, types_1.defaultLogCheckConfig), { ignoreCodes: [], ignorePaths: [] })];
|
|
172
210
|
}
|
|
173
211
|
});
|
|
174
212
|
}); };
|
|
175
213
|
exports.readLogCheckConfig = readLogCheckConfig;
|
|
214
|
+
/** Parses one config document into the policy - see {@link readLogCheckConfig}. */
|
|
215
|
+
var readConfigAt = function (configPath, raw) {
|
|
216
|
+
var _a, _b, _c, _d;
|
|
217
|
+
var parsed;
|
|
218
|
+
try {
|
|
219
|
+
parsed = JSON.parse(raw);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
throw new Error("Could not parse ".concat(configPath, ": ").concat(error.message));
|
|
223
|
+
}
|
|
224
|
+
var section = (_b = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.config) === null || _a === void 0 ? void 0 : _a[exports.CONFIG_KEY]) !== null && _b !== void 0 ? _b : parsed === null || parsed === void 0 ? void 0 : parsed[exports.CONFIG_KEY];
|
|
225
|
+
var config = (0, exports.parseLogCheckSection)(section, configPath);
|
|
226
|
+
// A project may have moved its results folder; the bare command follows it,
|
|
227
|
+
// unless the logCheck section names a folder of its own.
|
|
228
|
+
if (!config.folder) {
|
|
229
|
+
var resultsFolder = (_d = (_c = parsed === null || parsed === void 0 ? void 0 : parsed.config) === null || _c === void 0 ? void 0 : _c.sasjsResultsFolder) !== null && _d !== void 0 ? _d : parsed === null || parsed === void 0 ? void 0 : parsed.sasjsResultsFolder;
|
|
230
|
+
if (typeof resultsFolder === 'string' && resultsFolder.trim()) {
|
|
231
|
+
config.folder = resultsFolder.trim();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return config;
|
|
235
|
+
};
|
|
176
236
|
/**
|
|
177
237
|
* Layers the command line over the config file. Suppressions are added, never
|
|
178
238
|
* replaced: a flag silences one more code for one run, it does not un-silence
|
|
@@ -346,6 +346,7 @@ var toJson = function (summary, config) {
|
|
|
346
346
|
config: {
|
|
347
347
|
failOn: config.failOn,
|
|
348
348
|
maxWarnings: (_a = config.maxWarnings) !== null && _a !== void 0 ? _a : null,
|
|
349
|
+
autoCheck: config.autoCheck === true,
|
|
349
350
|
ignoreCodes: config.ignoreCodes,
|
|
350
351
|
ignorePaths: config.ignorePaths
|
|
351
352
|
},
|