@sasjs/cli 6.7.0 → 6.8.1
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/fs/fsCommand.d.ts +2 -2
- package/build/commands/fs/fsCommand.js +44 -15
- package/build/commands/fs/internal/executeCode.d.ts +6 -0
- package/build/commands/fs/internal/executeCode.js +6 -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 +46 -36
- package/build/commands/job/jobCommand.js +13 -0
- package/build/commands/job/spec/execute.spec.js +29 -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,58 @@ 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();
|
|
237
|
+
// A log-check failure is the verdict the caller asked for, not a parse
|
|
238
|
+
// error: swallowing it here printed "Logcheck failed" and then exited 0,
|
|
239
|
+
// which is the green pipeline the feature exists to prevent.
|
|
240
|
+
if ((0, logcheck_1.isLogCheckFailure)(error_1))
|
|
241
|
+
throw error_1;
|
|
232
242
|
// handle use case when submitted job can't be parsed
|
|
233
243
|
result = false;
|
|
234
244
|
(0, displayResult_1.displayError)(null, 'An error has occurred when parsing an output of the job.');
|
|
235
|
-
return [3 /*break*/,
|
|
236
|
-
case
|
|
245
|
+
return [3 /*break*/, 21];
|
|
246
|
+
case 21:
|
|
237
247
|
// wait for job state and return status(0,1,2) based on it
|
|
238
248
|
if (waitForJob && submittedJob.state) {
|
|
239
249
|
switch (submittedJob.state) {
|
|
240
250
|
case 'completed':
|
|
241
|
-
(0,
|
|
251
|
+
(0, utils_3.terminateProcess)(0);
|
|
242
252
|
case 'warning':
|
|
243
253
|
// if ignoreWarnings flag is present, process will be terminated with
|
|
244
254
|
// status code 0, otherwise status code will be 1
|
|
245
|
-
(0,
|
|
255
|
+
(0, utils_3.terminateProcess)(ignoreWarnings ? 0 : 1);
|
|
246
256
|
case 'error':
|
|
247
|
-
(0,
|
|
257
|
+
(0, utils_3.terminateProcess)(2);
|
|
248
258
|
default:
|
|
249
259
|
break;
|
|
250
260
|
}
|
|
251
261
|
}
|
|
252
|
-
return [3 /*break*/,
|
|
253
|
-
case
|
|
262
|
+
return [3 /*break*/, 23];
|
|
263
|
+
case 22:
|
|
254
264
|
if (result) {
|
|
255
|
-
(0,
|
|
265
|
+
(0, utils_3.terminateProcess)(command_1.ReturnCode.InternalError);
|
|
256
266
|
}
|
|
257
|
-
_c.label =
|
|
258
|
-
case
|
|
267
|
+
_c.label = 23;
|
|
268
|
+
case 23:
|
|
259
269
|
(_b = process.logger) === null || _b === void 0 ? void 0 : _b.info("This job was executed in ".concat((endTime - startTime) / 1000, " seconds"));
|
|
260
270
|
return [2 /*return*/, result];
|
|
261
271
|
}
|
|
@@ -271,7 +281,7 @@ function executeJobViya(sasjs, authConfig, jobPath, target, waitForJob, output,
|
|
|
271
281
|
function getContextName(target) {
|
|
272
282
|
var _a;
|
|
273
283
|
// default execution context of @sasjs/cli
|
|
274
|
-
var defaultContextName =
|
|
284
|
+
var defaultContextName = utils_3.contextName;
|
|
275
285
|
// get gontext name from target
|
|
276
286
|
if (target === null || target === void 0 ? void 0 : target.contextName)
|
|
277
287
|
return target.contextName;
|
|
@@ -311,14 +321,14 @@ function displayStatus(submittedJob_1, statusFile_1) {
|
|
|
311
321
|
folderPath = statusFile.split(path_1.default.sep);
|
|
312
322
|
folderPath.pop();
|
|
313
323
|
parentFolderPath = folderPath.join(path_1.default.sep);
|
|
314
|
-
return [4 /*yield*/, (0,
|
|
324
|
+
return [4 /*yield*/, (0, utils_2.folderExists)(parentFolderPath)];
|
|
315
325
|
case 1:
|
|
316
326
|
if (!!(_a.sent())) return [3 /*break*/, 3];
|
|
317
|
-
return [4 /*yield*/, (0,
|
|
327
|
+
return [4 /*yield*/, (0, utils_2.createFolder)(parentFolderPath)];
|
|
318
328
|
case 2:
|
|
319
329
|
_a.sent();
|
|
320
330
|
_a.label = 3;
|
|
321
|
-
case 3: return [4 /*yield*/, (0,
|
|
331
|
+
case 3: return [4 /*yield*/, (0, utils_2.createFile)(statusFile, status)
|
|
322
332
|
// display file path to status file
|
|
323
333
|
];
|
|
324
334
|
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
|
})];
|
|
@@ -79,6 +79,9 @@ var path_1 = __importDefault(require("path"));
|
|
|
79
79
|
var utils_2 = require("../../../utils");
|
|
80
80
|
var utilsModule = __importStar(require("../../../utils/utils"));
|
|
81
81
|
var configUtils = __importStar(require("../../../utils/config"));
|
|
82
|
+
var logcheckModule = __importStar(require("../../../utils/logcheck"));
|
|
83
|
+
var fetchLogFileContentModule = __importStar(require("../../shared/fetchLogFileContent"));
|
|
84
|
+
var logcheck_1 = require("../../../utils/logcheck");
|
|
82
85
|
var execute_1 = require("../internal/execute");
|
|
83
86
|
var mocks_1 = require("./mocks");
|
|
84
87
|
var sasjs = new node_1.default();
|
|
@@ -165,6 +168,32 @@ describe('executeJobViya', function () {
|
|
|
165
168
|
}
|
|
166
169
|
});
|
|
167
170
|
}); });
|
|
171
|
+
it('propagates a log-check failure instead of reporting a parse error', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
172
|
+
var failure;
|
|
173
|
+
return __generator(this, function (_a) {
|
|
174
|
+
switch (_a.label) {
|
|
175
|
+
case 0:
|
|
176
|
+
// a job whose log fails the check used to print the verdict and then exit 0,
|
|
177
|
+
// because this function's catch-all treated the failure as a bad output
|
|
178
|
+
jest.spyOn(sasjs, 'startComputeJob').mockResolvedValue({
|
|
179
|
+
job: {
|
|
180
|
+
state: 'completed',
|
|
181
|
+
links: [{ rel: 'log', method: 'GET', href: '/log' }],
|
|
182
|
+
logStatistics: { lineCount: 5 }
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
jest
|
|
186
|
+
.spyOn(fetchLogFileContentModule, 'fetchLogFileContent')
|
|
187
|
+
.mockResolvedValue('ERROR: deliberate');
|
|
188
|
+
failure = new logcheck_1.LogCheckFailure('SAS log check failed for test/job');
|
|
189
|
+
jest.spyOn(logcheckModule, 'checkLog').mockRejectedValue(failure);
|
|
190
|
+
return [4 /*yield*/, expect((0, execute_1.executeJobViya)(sasjs, mocks_1.mockAuthConfig, 'test/job', target, true, false, testLogsPath, undefined, false, undefined, false)).rejects.toBe(failure)];
|
|
191
|
+
case 1:
|
|
192
|
+
_a.sent();
|
|
193
|
+
return [2 /*return*/];
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}); });
|
|
168
197
|
});
|
|
169
198
|
describe('executeJobSasjs', function () {
|
|
170
199
|
beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -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
|
*
|