@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
|
@@ -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
|
},
|
|
@@ -75,16 +75,21 @@ describe('parseLogCheckSection', function () {
|
|
|
75
75
|
maxWarnings: 4,
|
|
76
76
|
ignoreCodes: ['49-169'],
|
|
77
77
|
ignorePaths: ['sasjsresults/legacy'],
|
|
78
|
-
folder: 'logs'
|
|
78
|
+
folder: 'logs',
|
|
79
|
+
autoCheck: true
|
|
79
80
|
});
|
|
80
81
|
expect(config).toEqual({
|
|
81
82
|
failOn: 'warning',
|
|
82
83
|
maxWarnings: 4,
|
|
83
84
|
ignoreCodes: ['49-169'],
|
|
84
85
|
ignorePaths: ['sasjsresults/legacy'],
|
|
85
|
-
folder: 'logs'
|
|
86
|
+
folder: 'logs',
|
|
87
|
+
autoCheck: true
|
|
86
88
|
});
|
|
87
89
|
});
|
|
90
|
+
it('refuses an autoCheck that is not a boolean', function () {
|
|
91
|
+
expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ autoCheck: 'yes' }); }).toThrow('must be true or false');
|
|
92
|
+
});
|
|
88
93
|
it('refuses a failOn that is not one of the four policies', function () {
|
|
89
94
|
expect(function () { return (0, logCheckConfig_1.parseLogCheckSection)({ failOn: 'warnings' }); }).toThrow('must be one of error, warning, note, never');
|
|
90
95
|
});
|
|
@@ -150,6 +155,54 @@ describe('readLogCheckConfig', function () {
|
|
|
150
155
|
}
|
|
151
156
|
});
|
|
152
157
|
}); });
|
|
158
|
+
it('reads the config from the SASjs convention, sasjs/sasjsconfig.json', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
159
|
+
var folder, config;
|
|
160
|
+
return __generator(this, function (_a) {
|
|
161
|
+
switch (_a.label) {
|
|
162
|
+
case 0: return [4 /*yield*/, tempFolder()];
|
|
163
|
+
case 1:
|
|
164
|
+
folder = _a.sent();
|
|
165
|
+
process.projectDir = folder;
|
|
166
|
+
return [4 /*yield*/, fs_1.promises.mkdir(path_1.default.join(folder, 'sasjs'))];
|
|
167
|
+
case 2:
|
|
168
|
+
_a.sent();
|
|
169
|
+
return [4 /*yield*/, fs_1.promises.writeFile(path_1.default.join(folder, 'sasjs', 'sasjsconfig.json'), JSON.stringify({ logCheck: { failOn: 'warning', autoCheck: true } }))];
|
|
170
|
+
case 3:
|
|
171
|
+
_a.sent();
|
|
172
|
+
return [4 /*yield*/, (0, logCheckConfig_1.readLogCheckConfig)()];
|
|
173
|
+
case 4:
|
|
174
|
+
config = _a.sent();
|
|
175
|
+
expect(config.failOn).toEqual('warning');
|
|
176
|
+
expect(config.autoCheck).toBeTrue();
|
|
177
|
+
return [2 /*return*/];
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}); });
|
|
181
|
+
it('prefers sasjs/sasjsconfig.json when a root file also exists', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
182
|
+
var folder, _a;
|
|
183
|
+
return __generator(this, function (_b) {
|
|
184
|
+
switch (_b.label) {
|
|
185
|
+
case 0: return [4 /*yield*/, tempFolder()];
|
|
186
|
+
case 1:
|
|
187
|
+
folder = _b.sent();
|
|
188
|
+
process.projectDir = folder;
|
|
189
|
+
return [4 /*yield*/, fs_1.promises.mkdir(path_1.default.join(folder, 'sasjs'))];
|
|
190
|
+
case 2:
|
|
191
|
+
_b.sent();
|
|
192
|
+
return [4 /*yield*/, fs_1.promises.writeFile(path_1.default.join(folder, 'sasjs', 'sasjsconfig.json'), JSON.stringify({ logCheck: { failOn: 'note' } }))];
|
|
193
|
+
case 3:
|
|
194
|
+
_b.sent();
|
|
195
|
+
return [4 /*yield*/, fs_1.promises.writeFile(path_1.default.join(folder, 'sasjsconfig.json'), JSON.stringify({ logCheck: { failOn: 'never' } }))];
|
|
196
|
+
case 4:
|
|
197
|
+
_b.sent();
|
|
198
|
+
_a = expect;
|
|
199
|
+
return [4 /*yield*/, (0, logCheckConfig_1.readLogCheckConfig)()];
|
|
200
|
+
case 5:
|
|
201
|
+
_a.apply(void 0, [(_b.sent()).failOn]).toEqual('note');
|
|
202
|
+
return [2 /*return*/];
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}); });
|
|
153
206
|
it('reads the section from the top level of the config', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
154
207
|
var _a;
|
|
155
208
|
return __generator(this, function (_b) {
|
|
@@ -227,6 +280,14 @@ describe('readLogCheckConfig', function () {
|
|
|
227
280
|
});
|
|
228
281
|
}); });
|
|
229
282
|
});
|
|
283
|
+
describe('configCandidates', function () {
|
|
284
|
+
it('tries the SASjs convention before the project root', function () {
|
|
285
|
+
expect((0, logCheckConfig_1.configCandidates)(path_1.default.join('some', 'project'))).toEqual([
|
|
286
|
+
path_1.default.join('some', 'project', 'sasjs', 'sasjsconfig.json'),
|
|
287
|
+
path_1.default.join('some', 'project', 'sasjsconfig.json')
|
|
288
|
+
]);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
230
291
|
describe('mergeConfig', function () {
|
|
231
292
|
var base = __assign(__assign({}, types_1.defaultLogCheckConfig), { ignoreCodes: ['49-169'], ignorePaths: ['legacy'] });
|
|
232
293
|
it('prefers the command line over the file', function () {
|
|
@@ -41,6 +41,14 @@ export interface LogCheckConfig {
|
|
|
41
41
|
* against the project folder.
|
|
42
42
|
*/
|
|
43
43
|
folder?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the commands that receive a SAS log (`run`, `request`, `job
|
|
46
|
+
* execute`, `flow execute`) fail on it as well as reporting it. Off by
|
|
47
|
+
* default: those commands' exit codes are already load-bearing in pipelines,
|
|
48
|
+
* and a job that prints a notable note is not a failed job. `--logcheck` and
|
|
49
|
+
* `--no-logcheck` override it per run.
|
|
50
|
+
*/
|
|
51
|
+
autoCheck?: boolean;
|
|
44
52
|
}
|
|
45
53
|
export declare const defaultLogCheckConfig: LogCheckConfig;
|
|
46
54
|
/** Counts of the issues a log carries, after suppression. */
|
|
@@ -35,6 +35,31 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
35
35
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
39
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
40
|
+
if (!m) return o;
|
|
41
|
+
var i = m.call(o), r, ar = [], e;
|
|
42
|
+
try {
|
|
43
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
44
|
+
}
|
|
45
|
+
catch (error) { e = { error: error }; }
|
|
46
|
+
finally {
|
|
47
|
+
try {
|
|
48
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
49
|
+
}
|
|
50
|
+
finally { if (e) throw e.error; }
|
|
51
|
+
}
|
|
52
|
+
return ar;
|
|
53
|
+
};
|
|
54
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
55
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
56
|
+
if (ar || !(i in from)) {
|
|
57
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
58
|
+
ar[i] = from[i];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
62
|
+
};
|
|
38
63
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
64
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
65
|
};
|
|
@@ -145,7 +170,7 @@ function runSasJob(target, isLocal, sasJobLocation, dataFilePath, configFilePath
|
|
|
145
170
|
case 4:
|
|
146
171
|
_a.sent();
|
|
147
172
|
_a.label = 5;
|
|
148
|
-
case 5: return [4 /*yield*/, saveLogFile(sasjs, sasJobLocation, logFile, jobPath)];
|
|
173
|
+
case 5: return [4 /*yield*/, saveLogFile(sasjs, sasJobLocation, logFile, jobPath, true)];
|
|
149
174
|
case 6:
|
|
150
175
|
_a.sent();
|
|
151
176
|
result = true;
|
|
@@ -170,33 +195,47 @@ function runSasJob(target, isLocal, sasJobLocation, dataFilePath, configFilePath
|
|
|
170
195
|
});
|
|
171
196
|
});
|
|
172
197
|
}
|
|
173
|
-
var saveLogFile = function (
|
|
174
|
-
var
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
+
var saveLogFile = function (sasjs_1, sasJobLocation_1, logFile_1, jobPath_1) {
|
|
199
|
+
var args_1 = [];
|
|
200
|
+
for (var _i = 4; _i < arguments.length; _i++) {
|
|
201
|
+
args_1[_i - 4] = arguments[_i];
|
|
202
|
+
}
|
|
203
|
+
return __awaiter(void 0, __spreadArray([sasjs_1, sasJobLocation_1, logFile_1, jobPath_1], __read(args_1), false), void 0, function (sasjs, sasJobLocation, logFile, jobPath, check) {
|
|
204
|
+
var sasRequests, currentRequestLog, logPath, timestamp, filename;
|
|
205
|
+
if (check === void 0) { check = false; }
|
|
206
|
+
return __generator(this, function (_a) {
|
|
207
|
+
switch (_a.label) {
|
|
208
|
+
case 0:
|
|
209
|
+
sasRequests = sasjs.getSasRequests();
|
|
210
|
+
currentRequestLog = sasRequests.find(function (x) { return x.serviceLink === sasJobLocation; });
|
|
211
|
+
if (!(currentRequestLog && jobPath)) return [3 /*break*/, 5];
|
|
212
|
+
if (!!logFile) return [3 /*break*/, 2];
|
|
213
|
+
return [4 /*yield*/, (0, utils_2.isSASjsProject)()];
|
|
214
|
+
case 1:
|
|
215
|
+
logPath = (_a.sent())
|
|
216
|
+
? path_1.default.join(process.sasjsConstants.buildDestinationResultsFolder, 'requests')
|
|
217
|
+
: process.projectDir;
|
|
218
|
+
timestamp = (0, utils_1.generateTimestamp)();
|
|
219
|
+
filename = sasJobLocation.split('/').pop() // always use forward slash in SAS Drive
|
|
220
|
+
;
|
|
221
|
+
logFile = path_1.default.join(logPath, "".concat(filename, "-").concat(timestamp, ".log"));
|
|
222
|
+
_a.label = 2;
|
|
223
|
+
case 2: return [4 /*yield*/, (0, utils_2.saveLog)(currentRequestLog.logFile, logFile, jobPath || '', false)
|
|
224
|
+
// after the write, not before: a request that fails the check is the one
|
|
225
|
+
// whose log is wanted on disk
|
|
226
|
+
];
|
|
227
|
+
case 3:
|
|
228
|
+
_a.sent();
|
|
229
|
+
if (!check) return [3 /*break*/, 5];
|
|
230
|
+
return [4 /*yield*/, (0, utils_2.checkLog)(currentRequestLog.logFile, sasJobLocation)];
|
|
231
|
+
case 4:
|
|
232
|
+
_a.sent();
|
|
233
|
+
_a.label = 5;
|
|
234
|
+
case 5: return [2 /*return*/];
|
|
235
|
+
}
|
|
236
|
+
});
|
|
198
237
|
});
|
|
199
|
-
}
|
|
238
|
+
};
|
|
200
239
|
/**
|
|
201
240
|
* Writes output to the file
|
|
202
241
|
* @param outputPathParam path to output file
|
|
@@ -58,6 +58,7 @@ var targetCommand_1 = require("../../types/command/targetCommand");
|
|
|
58
58
|
var utils_2 = require("../../utils");
|
|
59
59
|
var request_1 = require("./request");
|
|
60
60
|
var getLogFilePath_1 = require("../../utils/getLogFilePath");
|
|
61
|
+
var logcheck_1 = require("../../utils/logcheck");
|
|
61
62
|
var syntax = 'request <sasProgramPath> [options]';
|
|
62
63
|
var usage = 'sasjs request <sasProgramPath> --data <path-to-datafile> --config <path-to-configfile> --target <target-name> --output <path-to-outputfile> --log <path-to-logfile>';
|
|
63
64
|
var description = "Lets the user run a SAS job against a specified target.\n" +
|
|
@@ -104,6 +105,11 @@ var RequestCommand = /** @class */ (function (_super) {
|
|
|
104
105
|
type: 'string',
|
|
105
106
|
alias: 'o',
|
|
106
107
|
description: 'path where output of the finished job execution will be saved.'
|
|
108
|
+
},
|
|
109
|
+
logcheck: {
|
|
110
|
+
type: 'boolean',
|
|
111
|
+
default: undefined,
|
|
112
|
+
description: 'Check the SAS log this request received, and fail when logCheck in sasjsconfig.json says so. --no-logcheck switches both the report and the verdict off.'
|
|
107
113
|
}
|
|
108
114
|
},
|
|
109
115
|
syntax: syntax,
|
|
@@ -117,7 +123,9 @@ var RequestCommand = /** @class */ (function (_super) {
|
|
|
117
123
|
var _a, target, isLocal, jobPath, log, output, authConfig, _b, e_1, _c, sasProgramPath, data, config;
|
|
118
124
|
return __generator(this, function (_d) {
|
|
119
125
|
switch (_d.label) {
|
|
120
|
-
case 0:
|
|
126
|
+
case 0:
|
|
127
|
+
(0, logcheck_1.setLogCheckMode)((0, logcheck_1.logCheckModeOf)(this.parsed.logcheck));
|
|
128
|
+
return [4 /*yield*/, this.getTargetInfo()];
|
|
121
129
|
case 1:
|
|
122
130
|
_a = _d.sent(), target = _a.target, isLocal = _a.isLocal;
|
|
123
131
|
jobPath = (0, utils_2.prefixAppLoc)(target.appLoc, process.currentDir);
|
|
@@ -152,6 +160,8 @@ var RequestCommand = /** @class */ (function (_super) {
|
|
|
152
160
|
return command_1.ReturnCode.Success;
|
|
153
161
|
})
|
|
154
162
|
.catch(function (err) {
|
|
163
|
+
if ((0, logcheck_1.isLogCheckFailure)(err))
|
|
164
|
+
return command_1.ReturnCode.LogCheckError;
|
|
155
165
|
(0, utils_2.displayError)(err, 'An error has occurred when running your SAS job.');
|
|
156
166
|
return command_1.ReturnCode.InternalError;
|
|
157
167
|
})];
|
|
@@ -100,6 +100,7 @@ var utils_1 = require("@sasjs/utils");
|
|
|
100
100
|
var configUtils = __importStar(require("../../../utils/config"));
|
|
101
101
|
var setConstantsUtils = __importStar(require("../../../utils/setConstants"));
|
|
102
102
|
var command_1 = require("../../../types/command");
|
|
103
|
+
var logcheck_1 = require("../../../utils/logcheck");
|
|
103
104
|
var defaultArgs = ['node', 'sasjs'];
|
|
104
105
|
var target = new utils_1.Target({
|
|
105
106
|
name: 'test',
|
|
@@ -116,6 +117,45 @@ describe('RequestCommand', function () {
|
|
|
116
117
|
beforeEach(function () {
|
|
117
118
|
setupMocks();
|
|
118
119
|
});
|
|
120
|
+
afterEach(function () { return (0, logcheck_1.setLogCheckMode)('auto'); });
|
|
121
|
+
it('should return the logcheck code when the log check failed the request', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
122
|
+
var command, _a;
|
|
123
|
+
return __generator(this, function (_b) {
|
|
124
|
+
switch (_b.label) {
|
|
125
|
+
case 0:
|
|
126
|
+
jest
|
|
127
|
+
.spyOn(requestModule, 'runSasJob')
|
|
128
|
+
.mockImplementation(function () { return Promise.reject(new logcheck_1.LogCheckFailure('1 error')); });
|
|
129
|
+
command = new requestCommand_1.RequestCommand(__spreadArray(__spreadArray([], __read(defaultArgs), false), [
|
|
130
|
+
'request',
|
|
131
|
+
sasProgramPath
|
|
132
|
+
], false));
|
|
133
|
+
_a = expect;
|
|
134
|
+
return [4 /*yield*/, command.execute()];
|
|
135
|
+
case 1:
|
|
136
|
+
_a.apply(void 0, [_b.sent()]).toEqual(command_1.ReturnCode.LogCheckError);
|
|
137
|
+
return [2 /*return*/];
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}); });
|
|
141
|
+
it('should switch the log check off for --no-logcheck', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
142
|
+
var command;
|
|
143
|
+
return __generator(this, function (_a) {
|
|
144
|
+
switch (_a.label) {
|
|
145
|
+
case 0:
|
|
146
|
+
command = new requestCommand_1.RequestCommand(__spreadArray(__spreadArray([], __read(defaultArgs), false), [
|
|
147
|
+
'request',
|
|
148
|
+
sasProgramPath,
|
|
149
|
+
'--no-logcheck'
|
|
150
|
+
], false));
|
|
151
|
+
return [4 /*yield*/, command.execute()];
|
|
152
|
+
case 1:
|
|
153
|
+
_a.sent();
|
|
154
|
+
expect((0, logcheck_1.getLogCheckMode)()).toEqual('off');
|
|
155
|
+
return [2 /*return*/];
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}); });
|
|
119
159
|
it('should parse sasjs request command', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
120
160
|
var args, command, targetInfo;
|
|
121
161
|
return __generator(this, function (_a) {
|
|
@@ -6,6 +6,4 @@ import { Target } from '@sasjs/utils';
|
|
|
6
6
|
* @param {boolean} compile - compiles sas file present at 'filePath' before running code.
|
|
7
7
|
* @param {string} logFile - (Optional) Path to log file.
|
|
8
8
|
*/
|
|
9
|
-
export declare function runSasCode(target: Target, filePath: string, compile?: boolean, logFile?: string, source?: string): Promise<
|
|
10
|
-
log: any;
|
|
11
|
-
}>;
|
|
9
|
+
export declare function runSasCode(target: Target, filePath: string, compile?: boolean, logFile?: string, source?: string): Promise<any>;
|
|
@@ -74,6 +74,7 @@ var utils_2 = require("../../utils/");
|
|
|
74
74
|
var axios_1 = __importDefault(require("axios"));
|
|
75
75
|
var saveLog_1 = require("../../utils/saveLog");
|
|
76
76
|
var parseSourceFile_1 = require("../../utils/parseSourceFile");
|
|
77
|
+
var logcheck_1 = require("../../utils/logcheck");
|
|
77
78
|
/**
|
|
78
79
|
* Runs SAS code from a given file on the specified target.
|
|
79
80
|
* @param {Target} target - the target to run the SAS code on.
|
|
@@ -83,7 +84,7 @@ var parseSourceFile_1 = require("../../utils/parseSourceFile");
|
|
|
83
84
|
*/
|
|
84
85
|
function runSasCode(target_1, filePath_1) {
|
|
85
86
|
return __awaiter(this, arguments, void 0, function (target, filePath, compile, logFile, source) {
|
|
86
|
-
var isTempFile, sasFilePath, sasFileContent, linesToExecute, macroVars, macroVarStatements, _a;
|
|
87
|
+
var isTempFile, sasFilePath, sasFileContent, linesToExecute, macroVars, macroVarStatements, result, _a;
|
|
87
88
|
var _b;
|
|
88
89
|
var _c;
|
|
89
90
|
if (compile === void 0) { compile = false; }
|
|
@@ -137,12 +138,26 @@ function runSasCode(target_1, filePath_1) {
|
|
|
137
138
|
}
|
|
138
139
|
return [3 /*break*/, 17];
|
|
139
140
|
case 11: return [4 /*yield*/, executeOnSasViya(filePath, target, linesToExecute, logFile)];
|
|
140
|
-
case 12:
|
|
141
|
+
case 12:
|
|
142
|
+
result = _d.sent();
|
|
143
|
+
return [3 /*break*/, 17];
|
|
141
144
|
case 13: return [4 /*yield*/, executeOnSas9(target, linesToExecute, logFile)];
|
|
142
|
-
case 14:
|
|
145
|
+
case 14:
|
|
146
|
+
result = _d.sent();
|
|
147
|
+
return [3 /*break*/, 17];
|
|
143
148
|
case 15: return [4 /*yield*/, executeOnSasJS(filePath, target, linesToExecute, logFile)];
|
|
144
|
-
case 16:
|
|
145
|
-
|
|
149
|
+
case 16:
|
|
150
|
+
result = _d.sent();
|
|
151
|
+
_d.label = 17;
|
|
152
|
+
case 17:
|
|
153
|
+
// Only a run that claims to have worked is worth checking: an executor that
|
|
154
|
+
// threw has already written the log it failed on, truncated at the failure.
|
|
155
|
+
return [4 /*yield*/, (0, logcheck_1.checkLog)(result === null || result === void 0 ? void 0 : result.log, path_1.default.basename(filePath))];
|
|
156
|
+
case 18:
|
|
157
|
+
// Only a run that claims to have worked is worth checking: an executor that
|
|
158
|
+
// threw has already written the log it failed on, truncated at the failure.
|
|
159
|
+
_d.sent();
|
|
160
|
+
return [2 /*return*/, result];
|
|
146
161
|
}
|
|
147
162
|
});
|
|
148
163
|
});
|
|
@@ -55,6 +55,7 @@ exports.RunCommand = void 0;
|
|
|
55
55
|
var command_1 = require("../../types/command");
|
|
56
56
|
var targetCommand_1 = require("../../types/command/targetCommand");
|
|
57
57
|
var utils_1 = require("../../utils");
|
|
58
|
+
var logcheck_1 = require("../../utils/logcheck");
|
|
58
59
|
var run_1 = require("./run");
|
|
59
60
|
var syntax = 'run <sasFilePath> [options]';
|
|
60
61
|
var usage = 'sasjs run <sasFilePath> --target <target-name>';
|
|
@@ -103,6 +104,11 @@ var RunCommand = /** @class */ (function (_super) {
|
|
|
103
104
|
type: 'string',
|
|
104
105
|
alias: 's',
|
|
105
106
|
description: 'Path to an input JSON containing job variables.'
|
|
107
|
+
},
|
|
108
|
+
logcheck: {
|
|
109
|
+
type: 'boolean',
|
|
110
|
+
default: undefined,
|
|
111
|
+
description: 'Check the SAS log this command received, and fail when logCheck in sasjsconfig.json says so. --no-logcheck switches both the report and the verdict off.'
|
|
106
112
|
}
|
|
107
113
|
},
|
|
108
114
|
syntax: syntax,
|
|
@@ -120,11 +126,14 @@ var RunCommand = /** @class */ (function (_super) {
|
|
|
120
126
|
case 1:
|
|
121
127
|
target = (_b.sent()).target;
|
|
122
128
|
_a = this.parsed, sasFilePath = _a.sasFilePath, compile = _a.compile, log = _a.log, source = _a.source;
|
|
129
|
+
(0, logcheck_1.setLogCheckMode)((0, logcheck_1.logCheckModeOf)(this.parsed.logcheck));
|
|
123
130
|
return [4 /*yield*/, (0, run_1.runSasCode)(target, sasFilePath, compile, log, source)
|
|
124
131
|
.then(function () {
|
|
125
132
|
return command_1.ReturnCode.Success;
|
|
126
133
|
})
|
|
127
134
|
.catch(function (err) {
|
|
135
|
+
if ((0, logcheck_1.isLogCheckFailure)(err))
|
|
136
|
+
return command_1.ReturnCode.LogCheckError;
|
|
128
137
|
(0, utils_1.displayError)(err, 'An error has occurred when running your SAS code.');
|
|
129
138
|
return command_1.ReturnCode.InternalError;
|
|
130
139
|
})];
|