@sasjs/cli 6.4.0 → 6.4.2

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.
@@ -76,7 +76,8 @@ function executeDeployScriptSas9(deployScriptName, target, linesToExecute, logFi
76
76
  case 2:
77
77
  executionResult = _f.sent();
78
78
  if (!executionResult) {
79
- return [2 /*return*/, (_b = process.logger) === null || _b === void 0 ? void 0 : _b.error('Error getting execution log')];
79
+ (_b = process.logger) === null || _b === void 0 ? void 0 : _b.error("Deployment failed: the runner returned no execution log for ".concat(deployScriptName, "."));
80
+ throw new Error("Deployment failed.");
80
81
  }
81
82
  logContent = completedWithError
82
83
  ? executionResult.result
@@ -53,7 +53,7 @@ var _1 = require(".");
53
53
  */
54
54
  function executeDeployScriptSasjs(deployScriptName, target, linesToExecute, logFilePath, streamConfig) {
55
55
  return __awaiter(this, void 0, void 0, function () {
56
- var authConfig, _a, sasjs, completedWithError, executionResult, logContent, webAppStreamUrl;
56
+ var authConfig, _a, sasjs, completedWithError, executionResult, webAppStreamUrl;
57
57
  var _b, _c, _d, _e;
58
58
  return __generator(this, function (_f) {
59
59
  switch (_f.label) {
@@ -82,14 +82,12 @@ function executeDeployScriptSasjs(deployScriptName, target, linesToExecute, logF
82
82
  .catch(function (err) {
83
83
  var errorString = (0, _1.formatErrorString)(err);
84
84
  process.logger.error('executeScript Error:', errorString);
85
+ completedWithError = true;
85
86
  return errorString;
86
87
  })];
87
88
  case 5:
88
89
  executionResult = _f.sent();
89
- logContent = completedWithError
90
- ? executionResult.result
91
- : executionResult;
92
- return [4 /*yield*/, (0, utils_1.createFile)(logFilePath, logContent !== null && logContent !== void 0 ? logContent : '')];
90
+ return [4 /*yield*/, (0, utils_1.createFile)(logFilePath, executionResult !== null && executionResult !== void 0 ? executionResult : '')];
93
91
  case 6:
94
92
  _f.sent();
95
93
  if (completedWithError) {
@@ -0,0 +1,229 @@
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 path_1 = __importDefault(require("path"));
76
+ var utils_1 = require("@sasjs/utils");
77
+ var configUtils = __importStar(require("../../../../utils/config"));
78
+ var executeDeployScriptSas9_1 = require("../executeDeployScriptSas9");
79
+ var errorLogContents = "ERROR: Expecting an arithmetic operator.\nERROR: %ABORT statement is not valid in open code.";
80
+ /**
81
+ * A stored process error as the adapter surfaces it - JobExecutionError
82
+ * carries the SAS log in `result`. Reproduced here as a plain object so the
83
+ * test does not depend on the adapter's node entry re-exporting the class.
84
+ */
85
+ var jobExecutionError = function (result) {
86
+ return Object.assign(new Error('Error Code 500: This request completed with errors.'), {
87
+ name: 'JobExecutionError',
88
+ errorCode: 500,
89
+ errorMessage: 'This request completed with errors.',
90
+ result: result
91
+ });
92
+ };
93
+ describe('executeDeployScriptSas9', function () {
94
+ var logFilePath = path_1.default.join(__dirname, 'sasjsbuild', 'mysas9deploy.log');
95
+ var deployScriptName = 'mysas9deploy.sas';
96
+ var linesToExecute = ['proc sql;', 'quit;'];
97
+ var target = new utils_1.Target({
98
+ name: 'sas9',
99
+ serverUrl: 'https://sas.example.com:8343',
100
+ appLoc: '/Public/app',
101
+ serverType: utils_1.ServerType.Sas9
102
+ });
103
+ var executeScript;
104
+ beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () {
105
+ return __generator(this, function (_a) {
106
+ process.logger = new utils_1.Logger();
107
+ jest.spyOn(process.logger, 'success').mockImplementation(function () { });
108
+ jest.spyOn(process.logger, 'error').mockImplementation(function () { });
109
+ jest.spyOn(process.logger, 'info').mockImplementation(function () { });
110
+ jest.spyOn(process.logger, 'log').mockImplementation(function () { });
111
+ executeScript = jest.fn();
112
+ jest.spyOn(configUtils, 'getSASjsAndAuthConfig').mockResolvedValue({
113
+ sasjs: { executeScript: executeScript },
114
+ authConfigSas9: {
115
+ userName: 'sasjsuser',
116
+ password: (0, utils_1.encodeToBase64)('secret')
117
+ }
118
+ });
119
+ return [2 /*return*/];
120
+ });
121
+ }); });
122
+ it('should write the execution log and report success', function () { return __awaiter(void 0, void 0, void 0, function () {
123
+ var _a;
124
+ var _b, _c;
125
+ return __generator(this, function (_d) {
126
+ switch (_d.label) {
127
+ case 0:
128
+ executeScript.mockResolvedValue('NOTE: Services deployed.');
129
+ return [4 /*yield*/, (0, executeDeployScriptSas9_1.executeDeployScriptSas9)(deployScriptName, target, linesToExecute, logFilePath)];
130
+ case 1:
131
+ _d.sent();
132
+ expect(executeScript).toHaveBeenCalledWith({
133
+ linesOfCode: linesToExecute,
134
+ authConfigSas9: { userName: 'sasjsuser', password: 'secret' }
135
+ });
136
+ _a = expect;
137
+ return [4 /*yield*/, (0, utils_1.readFile)(logFilePath)];
138
+ case 2:
139
+ _a.apply(void 0, [_d.sent()]).toEqual('NOTE: Services deployed.');
140
+ expect((_b = process.logger) === null || _b === void 0 ? void 0 : _b.success).toHaveBeenCalledWith("Deployment completed! Log is available at ".concat(logFilePath));
141
+ expect((_c = process.logger) === null || _c === void 0 ? void 0 : _c.error).not.toHaveBeenCalled();
142
+ return [2 /*return*/];
143
+ }
144
+ });
145
+ }); });
146
+ it('should write the SAS log, report the log path and fail the deploy when the job errors', function () { return __awaiter(void 0, void 0, void 0, function () {
147
+ var _a;
148
+ var _b, _c;
149
+ return __generator(this, function (_d) {
150
+ switch (_d.label) {
151
+ case 0:
152
+ executeScript.mockRejectedValue(jobExecutionError(errorLogContents));
153
+ return [4 /*yield*/, expect((0, executeDeployScriptSas9_1.executeDeployScriptSas9)(deployScriptName, target, linesToExecute, logFilePath)).rejects.toThrow('Deployment failed.')];
154
+ case 1:
155
+ _d.sent();
156
+ _a = expect;
157
+ return [4 /*yield*/, (0, utils_1.readFile)(logFilePath)];
158
+ case 2:
159
+ _a.apply(void 0, [_d.sent()]).toEqual(errorLogContents);
160
+ expect((_b = process.logger) === null || _b === void 0 ? void 0 : _b.error).toHaveBeenCalledWith("Deployment failed with errors! Log is available at ".concat(logFilePath));
161
+ expect((_c = process.logger) === null || _c === void 0 ? void 0 : _c.success).not.toHaveBeenCalled();
162
+ return [2 /*return*/];
163
+ }
164
+ });
165
+ }); });
166
+ it('should fail the deploy when the SASjs runner is missing, with the runner message and no stale success line', function () { return __awaiter(void 0, void 0, void 0, function () {
167
+ var runnerError;
168
+ var _a, _b;
169
+ return __generator(this, function (_c) {
170
+ switch (_c.label) {
171
+ case 0:
172
+ runnerError = jobExecutionError('');
173
+ runnerError.message =
174
+ "Error Code 500: SASJS runner not found. Here's the link (https://cli.sasjs.io/auth/#sasjs-runner) to the SAS code for registering the SASjs runner";
175
+ executeScript.mockRejectedValue(runnerError);
176
+ return [4 /*yield*/, expect((0, executeDeployScriptSas9_1.executeDeployScriptSas9)(deployScriptName, target, linesToExecute, logFilePath)).rejects.toThrow('Deployment failed.')];
177
+ case 1:
178
+ _c.sent();
179
+ expect((_a = process.logger) === null || _a === void 0 ? void 0 : _a.error).toHaveBeenCalledWith(expect.stringContaining('SASJS runner not found'));
180
+ expect((_b = process.logger) === null || _b === void 0 ? void 0 : _b.success).not.toHaveBeenCalled();
181
+ return [2 /*return*/];
182
+ }
183
+ });
184
+ }); });
185
+ it('should still fail the deploy when a non-job error is raised', function () { return __awaiter(void 0, void 0, void 0, function () {
186
+ var _a, _b;
187
+ return __generator(this, function (_c) {
188
+ switch (_c.label) {
189
+ case 0:
190
+ executeScript.mockRejectedValue(new Error('socket hang up'));
191
+ return [4 /*yield*/, expect((0, executeDeployScriptSas9_1.executeDeployScriptSas9)(deployScriptName, target, linesToExecute, logFilePath)).rejects.toThrow('Deployment failed.')];
192
+ case 1:
193
+ _c.sent();
194
+ expect((_a = process.logger) === null || _a === void 0 ? void 0 : _a.error).toHaveBeenCalledWith(expect.stringContaining('socket hang up'));
195
+ expect((_b = process.logger) === null || _b === void 0 ? void 0 : _b.success).not.toHaveBeenCalled();
196
+ return [2 /*return*/];
197
+ }
198
+ });
199
+ }); });
200
+ it('should fail the deploy when the runner returns no execution log', function () { return __awaiter(void 0, void 0, void 0, function () {
201
+ var _a, _b;
202
+ return __generator(this, function (_c) {
203
+ switch (_c.label) {
204
+ case 0:
205
+ executeScript.mockResolvedValue(undefined);
206
+ return [4 /*yield*/, expect((0, executeDeployScriptSas9_1.executeDeployScriptSas9)(deployScriptName, target, linesToExecute, logFilePath)).rejects.toThrow('Deployment failed.')];
207
+ case 1:
208
+ _c.sent();
209
+ expect((_a = process.logger) === null || _a === void 0 ? void 0 : _a.error).toHaveBeenCalledWith("Deployment failed: the runner returned no execution log for ".concat(deployScriptName, "."));
210
+ expect((_b = process.logger) === null || _b === void 0 ? void 0 : _b.success).not.toHaveBeenCalled();
211
+ return [2 /*return*/];
212
+ }
213
+ });
214
+ }); });
215
+ it('should print the web app URL for a streaming target', function () { return __awaiter(void 0, void 0, void 0, function () {
216
+ var _a;
217
+ return __generator(this, function (_b) {
218
+ switch (_b.label) {
219
+ case 0:
220
+ executeScript.mockResolvedValue('NOTE: Services deployed.');
221
+ return [4 /*yield*/, (0, executeDeployScriptSas9_1.executeDeployScriptSas9)(deployScriptName, target, linesToExecute, logFilePath, { streamWeb: true, streamServiceName: 'clickme' })];
222
+ case 1:
223
+ _b.sent();
224
+ expect((_a = process.logger) === null || _a === void 0 ? void 0 : _a.info).toHaveBeenCalledWith("Web app is available at ".concat(target.serverUrl, "/SASStoredProcess/?_PROGRAM=").concat(encodeURI(target.appLoc), "/services/clickme"));
225
+ return [2 /*return*/];
226
+ }
227
+ });
228
+ }); });
229
+ });
@@ -0,0 +1,159 @@
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 path_1 = __importDefault(require("path"));
76
+ var utils_1 = require("@sasjs/utils");
77
+ var configUtils = __importStar(require("../../../../utils/config"));
78
+ var utilsModule = __importStar(require("../../../../utils/utils"));
79
+ var executeDeployScriptSasjs_1 = require("../executeDeployScriptSasjs");
80
+ describe('executeDeployScriptSasjs', function () {
81
+ var logFilePath = path_1.default.join(__dirname, 'sasjsbuild', 'sasjsdeploy.log');
82
+ var deployScriptName = 'sasjsdeploy.sas';
83
+ var linesToExecute = ['data _null_;', 'run;'];
84
+ var target = new utils_1.Target({
85
+ name: 'sasjs',
86
+ serverUrl: 'http://localhost:5000',
87
+ appLoc: '/Public/app',
88
+ serverType: utils_1.ServerType.Sasjs
89
+ });
90
+ var executeScript;
91
+ beforeEach(function () {
92
+ process.logger = new utils_1.Logger();
93
+ jest.spyOn(process.logger, 'success').mockImplementation(function () { });
94
+ jest.spyOn(process.logger, 'error').mockImplementation(function () { });
95
+ jest.spyOn(process.logger, 'info').mockImplementation(function () { });
96
+ jest.spyOn(process.logger, 'log').mockImplementation(function () { });
97
+ jest
98
+ .spyOn(utilsModule, 'isSasJsServerInServerMode')
99
+ .mockResolvedValue(false);
100
+ executeScript = jest.fn();
101
+ jest.spyOn(configUtils, 'getSASjs').mockReturnValue({
102
+ executeScript: executeScript
103
+ });
104
+ });
105
+ it('should write the execution log and report success', function () { return __awaiter(void 0, void 0, void 0, function () {
106
+ var _a;
107
+ var _b, _c;
108
+ return __generator(this, function (_d) {
109
+ switch (_d.label) {
110
+ case 0:
111
+ executeScript.mockResolvedValue('NOTE: Services deployed.');
112
+ return [4 /*yield*/, (0, executeDeployScriptSasjs_1.executeDeployScriptSasjs)(deployScriptName, target, linesToExecute, logFilePath)];
113
+ case 1:
114
+ _d.sent();
115
+ _a = expect;
116
+ return [4 /*yield*/, (0, utils_1.readFile)(logFilePath)];
117
+ case 2:
118
+ _a.apply(void 0, [_d.sent()]).toEqual('NOTE: Services deployed.');
119
+ expect((_b = process.logger) === null || _b === void 0 ? void 0 : _b.success).toHaveBeenCalledWith("Deployment completed! Log is available at ".concat(logFilePath));
120
+ expect((_c = process.logger) === null || _c === void 0 ? void 0 : _c.error).not.toHaveBeenCalled();
121
+ return [2 /*return*/];
122
+ }
123
+ });
124
+ }); });
125
+ it('should write the error to the log and fail the deploy when the runner errors', function () { return __awaiter(void 0, void 0, void 0, function () {
126
+ var _a;
127
+ var _b, _c;
128
+ return __generator(this, function (_d) {
129
+ switch (_d.label) {
130
+ case 0:
131
+ executeScript.mockRejectedValue(new Error('Error executing script: job failed'));
132
+ return [4 /*yield*/, expect((0, executeDeployScriptSasjs_1.executeDeployScriptSasjs)(deployScriptName, target, linesToExecute, logFilePath)).rejects.toThrow('Deployment failed.')];
133
+ case 1:
134
+ _d.sent();
135
+ _a = expect;
136
+ return [4 /*yield*/, (0, utils_1.readFile)(logFilePath)];
137
+ case 2:
138
+ _a.apply(void 0, [_d.sent()]).toContain('Error executing script: job failed');
139
+ expect((_b = process.logger) === null || _b === void 0 ? void 0 : _b.error).toHaveBeenCalledWith("Deployment failed with errors! Log is available at ".concat(logFilePath));
140
+ expect((_c = process.logger) === null || _c === void 0 ? void 0 : _c.success).not.toHaveBeenCalled();
141
+ return [2 /*return*/];
142
+ }
143
+ });
144
+ }); });
145
+ it('should print the web app URL for a streaming target', function () { return __awaiter(void 0, void 0, void 0, function () {
146
+ var _a;
147
+ return __generator(this, function (_b) {
148
+ switch (_b.label) {
149
+ case 0:
150
+ executeScript.mockResolvedValue('NOTE: Services deployed.');
151
+ return [4 /*yield*/, (0, executeDeployScriptSasjs_1.executeDeployScriptSasjs)(deployScriptName, target, linesToExecute, logFilePath, { streamWeb: true, streamServiceName: 'clickme' })];
152
+ case 1:
153
+ _b.sent();
154
+ expect((_a = process.logger) === null || _a === void 0 ? void 0 : _a.info).toHaveBeenCalledWith("Web app is available at ".concat(target.serverUrl, "/AppStream/clickme"));
155
+ return [2 /*return*/];
156
+ }
157
+ });
158
+ }); });
159
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,394 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
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
+ };
63
+ var __importDefault = (this && this.__importDefault) || function (mod) {
64
+ return (mod && mod.__esModule) ? mod : { "default": mod };
65
+ };
66
+ Object.defineProperty(exports, "__esModule", { value: true });
67
+ var path_1 = __importDefault(require("path"));
68
+ var config_1 = require("../config");
69
+ /**
70
+ * The folder and stream accessors in config.ts read the global configuration
71
+ * `setConstants` writes to `process`, merge the target's own entries over it and
72
+ * resolve everything against the build source folder. None of that was covered:
73
+ * the functions returned whatever the caller's target happened to contain, so a
74
+ * regression in the merge (a dropped target folder, a duplicated path, a
75
+ * relative path that never got resolved) had nothing to fail against.
76
+ */
77
+ var buildSourceFolder = '/project/sasjsbuild';
78
+ // `getAbsolutePath` joins with the platform separator, so an expectation has to
79
+ // be built the same way: a hardcoded '/project/sasjsbuild/sas' is only right on
80
+ // a POSIX runner, and the Windows job runs this suite too.
81
+ var inBuild = function () {
82
+ var parts = [];
83
+ for (var _i = 0; _i < arguments.length; _i++) {
84
+ parts[_i] = arguments[_i];
85
+ }
86
+ return path_1.default.join.apply(path_1.default, __spreadArray([buildSourceFolder], __read(parts), false));
87
+ };
88
+ var sas9CredentialsError = 'SAS9 credentials are required.';
89
+ var targetWith = function (properties) { return properties; };
90
+ describe('config folder accessors', function () {
91
+ var originalConfig = process.sasjsConfig;
92
+ var originalConstants = process.sasjsConstants;
93
+ beforeEach(function () {
94
+ ;
95
+ process.sasjsConfig = {};
96
+ process.sasjsConstants = {
97
+ buildSourceFolder: buildSourceFolder,
98
+ sas9CredentialsError: sas9CredentialsError
99
+ };
100
+ });
101
+ afterAll(function () {
102
+ ;
103
+ process.sasjsConfig = originalConfig;
104
+ process.sasjsConstants = originalConstants;
105
+ });
106
+ describe('getProgramFolders', function () {
107
+ it('returns an empty list when neither the config nor the target names a folder', function () { return __awaiter(void 0, void 0, void 0, function () {
108
+ var _a;
109
+ return __generator(this, function (_b) {
110
+ switch (_b.label) {
111
+ case 0:
112
+ _a = expect;
113
+ return [4 /*yield*/, (0, config_1.getProgramFolders)(targetWith({}))];
114
+ case 1:
115
+ _a.apply(void 0, [_b.sent()]).toEqual([]);
116
+ return [2 /*return*/];
117
+ }
118
+ });
119
+ }); });
120
+ it('resolves the configuration folders against the build source folder', function () { return __awaiter(void 0, void 0, void 0, function () {
121
+ var _a;
122
+ return __generator(this, function (_b) {
123
+ switch (_b.label) {
124
+ case 0:
125
+ ;
126
+ process.sasjsConfig = { programFolders: ['sas'] };
127
+ _a = expect;
128
+ return [4 /*yield*/, (0, config_1.getProgramFolders)(targetWith({}))];
129
+ case 1:
130
+ _a.apply(void 0, [_b.sent()]).toEqual([inBuild('sas')]);
131
+ return [2 /*return*/];
132
+ }
133
+ });
134
+ }); });
135
+ it("appends the target's own folders after the configuration ones", function () { return __awaiter(void 0, void 0, void 0, function () {
136
+ var _a;
137
+ return __generator(this, function (_b) {
138
+ switch (_b.label) {
139
+ case 0:
140
+ ;
141
+ process.sasjsConfig = { programFolders: ['sas'] };
142
+ _a = expect;
143
+ return [4 /*yield*/, (0, config_1.getProgramFolders)(targetWith({ programFolders: ['extra'] }))];
144
+ case 1:
145
+ _a.apply(void 0, [_b.sent()]).toEqual([inBuild('sas'), inBuild('extra')]);
146
+ return [2 /*return*/];
147
+ }
148
+ });
149
+ }); });
150
+ it('collapses a folder named in both places', function () { return __awaiter(void 0, void 0, void 0, function () {
151
+ var _a;
152
+ return __generator(this, function (_b) {
153
+ switch (_b.label) {
154
+ case 0:
155
+ ;
156
+ process.sasjsConfig = { programFolders: ['sas'] };
157
+ _a = expect;
158
+ return [4 /*yield*/, (0, config_1.getProgramFolders)(targetWith({ programFolders: ['sas'] }))];
159
+ case 1:
160
+ _a.apply(void 0, [_b.sent()]).toEqual([inBuild('sas')]);
161
+ return [2 /*return*/];
162
+ }
163
+ });
164
+ }); });
165
+ it('leaves an absolute folder path alone', function () { return __awaiter(void 0, void 0, void 0, function () {
166
+ var _a;
167
+ return __generator(this, function (_b) {
168
+ switch (_b.label) {
169
+ case 0:
170
+ ;
171
+ process.sasjsConfig = { programFolders: ['/somewhere/else'] };
172
+ // kept absolute rather than joined onto the build folder, but
173
+ // `getAbsolutePath` normalises it, which on Windows means backslashes
174
+ _a = expect;
175
+ return [4 /*yield*/, (0, config_1.getProgramFolders)(targetWith({}))];
176
+ case 1:
177
+ // kept absolute rather than joined onto the build folder, but
178
+ // `getAbsolutePath` normalises it, which on Windows means backslashes
179
+ _a.apply(void 0, [_b.sent()]).toEqual([
180
+ path_1.default.normalize('/somewhere/else')
181
+ ]);
182
+ return [2 /*return*/];
183
+ }
184
+ });
185
+ }); });
186
+ });
187
+ describe('getBinaryFolders', function () {
188
+ it('returns an empty list with nothing configured', function () { return __awaiter(void 0, void 0, void 0, function () {
189
+ var _a;
190
+ return __generator(this, function (_b) {
191
+ switch (_b.label) {
192
+ case 0:
193
+ _a = expect;
194
+ return [4 /*yield*/, (0, config_1.getBinaryFolders)(targetWith({}))];
195
+ case 1:
196
+ _a.apply(void 0, [_b.sent()]).toEqual([]);
197
+ return [2 /*return*/];
198
+ }
199
+ });
200
+ }); });
201
+ it('merges the configuration and target binary folders', function () { return __awaiter(void 0, void 0, void 0, function () {
202
+ var _a;
203
+ return __generator(this, function (_b) {
204
+ switch (_b.label) {
205
+ case 0:
206
+ ;
207
+ process.sasjsConfig = { binaryFolders: ['bin'] };
208
+ _a = expect;
209
+ return [4 /*yield*/, (0, config_1.getBinaryFolders)(targetWith({ binaryFolders: ['macros/bin', 'bin'] }))];
210
+ case 1:
211
+ _a.apply(void 0, [_b.sent()]).toEqual([inBuild('bin'), inBuild('macros', 'bin')]);
212
+ return [2 /*return*/];
213
+ }
214
+ });
215
+ }); });
216
+ });
217
+ describe('getMacroFolders', function () {
218
+ it('returns an empty list when no target is given and nothing is configured', function () { return __awaiter(void 0, void 0, void 0, function () {
219
+ var _a;
220
+ return __generator(this, function (_b) {
221
+ switch (_b.label) {
222
+ case 0:
223
+ _a = expect;
224
+ return [4 /*yield*/, (0, config_1.getMacroFolders)()];
225
+ case 1:
226
+ _a.apply(void 0, [_b.sent()]).toEqual([]);
227
+ return [2 /*return*/];
228
+ }
229
+ });
230
+ }); });
231
+ it('merges the configuration and target macro folders', function () { return __awaiter(void 0, void 0, void 0, function () {
232
+ var _a;
233
+ return __generator(this, function (_b) {
234
+ switch (_b.label) {
235
+ case 0:
236
+ ;
237
+ process.sasjsConfig = { macroFolders: ['macros'] };
238
+ _a = expect;
239
+ return [4 /*yield*/, (0, config_1.getMacroFolders)(targetWith({ macroFolders: ['moremacros'] }))];
240
+ case 1:
241
+ _a.apply(void 0, [_b.sent()]).toEqual([inBuild('macros'), inBuild('moremacros')]);
242
+ return [2 /*return*/];
243
+ }
244
+ });
245
+ }); });
246
+ });
247
+ describe('getStreamConfig', function () {
248
+ it('defaults the service name when nothing is configured', function () { return __awaiter(void 0, void 0, void 0, function () {
249
+ var _a;
250
+ return __generator(this, function (_b) {
251
+ switch (_b.label) {
252
+ case 0:
253
+ _a = expect;
254
+ return [4 /*yield*/, (0, config_1.getStreamConfig)()];
255
+ case 1:
256
+ _a.apply(void 0, [_b.sent()]).toEqual({ streamServiceName: 'clickme' });
257
+ return [2 /*return*/];
258
+ }
259
+ });
260
+ }); });
261
+ it('takes the configuration stream settings', function () { return __awaiter(void 0, void 0, void 0, function () {
262
+ var _a;
263
+ return __generator(this, function (_b) {
264
+ switch (_b.label) {
265
+ case 0:
266
+ ;
267
+ process.sasjsConfig = {
268
+ streamConfig: {
269
+ streamServiceName: 'from_config',
270
+ streamWebFolder: 'web'
271
+ }
272
+ };
273
+ _a = expect;
274
+ return [4 /*yield*/, (0, config_1.getStreamConfig)()];
275
+ case 1:
276
+ _a.apply(void 0, [_b.sent()]).toEqual({
277
+ streamServiceName: 'from_config',
278
+ streamWebFolder: 'web'
279
+ });
280
+ return [2 /*return*/];
281
+ }
282
+ });
283
+ }); });
284
+ it('lets the target override the configuration', function () { return __awaiter(void 0, void 0, void 0, function () {
285
+ var target, _a;
286
+ return __generator(this, function (_b) {
287
+ switch (_b.label) {
288
+ case 0:
289
+ ;
290
+ process.sasjsConfig = {
291
+ streamConfig: { streamServiceName: 'from_config' }
292
+ };
293
+ target = targetWith({
294
+ streamConfig: { streamServiceName: 'from_target' }
295
+ });
296
+ _a = expect;
297
+ return [4 /*yield*/, (0, config_1.getStreamConfig)(target)];
298
+ case 1:
299
+ _a.apply(void 0, [_b.sent()]).toEqual({
300
+ streamServiceName: 'from_target'
301
+ });
302
+ return [2 /*return*/];
303
+ }
304
+ });
305
+ }); });
306
+ });
307
+ describe('getAuthConfigSAS9', function () {
308
+ var originalUsername = process.env.SAS_USERNAME;
309
+ var originalPassword = process.env.SAS_PASSWORD;
310
+ // Assigning `undefined` to process.env stores the string "undefined", so an
311
+ // absent variable has to be put back with a delete. The suite runs with
312
+ // --runInBand, so a leaked "undefined" would be visible to every spec file
313
+ // that follows and to anything asserting there are no SAS9 credentials.
314
+ var restore = function (name, value) {
315
+ if (value === undefined)
316
+ delete process.env[name];
317
+ else
318
+ process.env[name] = value;
319
+ };
320
+ afterEach(function () {
321
+ restore('SAS_USERNAME', originalUsername);
322
+ restore('SAS_PASSWORD', originalPassword);
323
+ });
324
+ it("takes the credentials from the target's authConfigSas9", function () {
325
+ delete process.env.SAS_USERNAME;
326
+ delete process.env.SAS_PASSWORD;
327
+ var target = targetWith({
328
+ authConfigSas9: { userName: 'target-user', password: 'target-pass' }
329
+ });
330
+ expect((0, config_1.getAuthConfigSAS9)(target)).toEqual({
331
+ userName: 'target-user',
332
+ password: 'target-pass'
333
+ });
334
+ });
335
+ it('falls back to the SAS_USERNAME and SAS_PASSWORD environment variables', function () {
336
+ process.env.SAS_USERNAME = 'env-user';
337
+ process.env.SAS_PASSWORD = 'env-pass';
338
+ expect((0, config_1.getAuthConfigSAS9)(targetWith({}))).toEqual({
339
+ userName: 'env-user',
340
+ password: 'env-pass'
341
+ });
342
+ });
343
+ it('prefers the target credentials over the environment', function () {
344
+ process.env.SAS_USERNAME = 'env-user';
345
+ process.env.SAS_PASSWORD = 'env-pass';
346
+ var target = targetWith({
347
+ authConfigSas9: { userName: 'target-user', password: 'target-pass' }
348
+ });
349
+ expect((0, config_1.getAuthConfigSAS9)(target).userName).toEqual('target-user');
350
+ });
351
+ it('throws the configured error when no credentials exist at all', function () {
352
+ delete process.env.SAS_USERNAME;
353
+ delete process.env.SAS_PASSWORD;
354
+ expect(function () { return (0, config_1.getAuthConfigSAS9)(targetWith({})); }).toThrow(sas9CredentialsError);
355
+ });
356
+ it('throws when only the user name is present', function () {
357
+ process.env.SAS_USERNAME = 'env-user';
358
+ delete process.env.SAS_PASSWORD;
359
+ expect(function () { return (0, config_1.getAuthConfigSAS9)(targetWith({})); }).toThrow(sas9CredentialsError);
360
+ });
361
+ });
362
+ describe('test hooks', function () {
363
+ it("returns the target's testSetUp without looking at the local config", function () { return __awaiter(void 0, void 0, void 0, function () {
364
+ var target, _a;
365
+ return __generator(this, function (_b) {
366
+ switch (_b.label) {
367
+ case 0:
368
+ target = targetWith({ testConfig: { testSetUp: 'setup.sas' } });
369
+ _a = expect;
370
+ return [4 /*yield*/, (0, config_1.getTestSetUp)(target)];
371
+ case 1:
372
+ _a.apply(void 0, [_b.sent()]).toEqual('setup.sas');
373
+ return [2 /*return*/];
374
+ }
375
+ });
376
+ }); });
377
+ it("returns the target's testTearDown without looking at the local config", function () { return __awaiter(void 0, void 0, void 0, function () {
378
+ var target, _a;
379
+ return __generator(this, function (_b) {
380
+ switch (_b.label) {
381
+ case 0:
382
+ target = targetWith({
383
+ testConfig: { testTearDown: 'teardown.sas' }
384
+ });
385
+ _a = expect;
386
+ return [4 /*yield*/, (0, config_1.getTestTearDown)(target)];
387
+ case 1:
388
+ _a.apply(void 0, [_b.sent()]).toEqual('teardown.sas');
389
+ return [2 /*return*/];
390
+ }
391
+ });
392
+ }); });
393
+ });
394
+ });
package/package.json CHANGED
@@ -72,6 +72,7 @@
72
72
  "dependencies": {
73
73
  "@sasjs/adapter": "^5.1.1",
74
74
  "@sasjs/core": "^6.1.1",
75
+ "@sasjs/lint": "4.8.1",
75
76
  "@sasjs/utils": "^4.1.1",
76
77
  "axios": "1.20.0",
77
78
  "chalk": "4.1.2",
@@ -94,7 +95,6 @@
94
95
  "@babel/preset-env": "7.29.7",
95
96
  "@babel/preset-typescript": "7.29.7",
96
97
  "@nogoo9/gitleaks": "8.30.1-post.2",
97
- "@sasjs/lint": "4.6.1",
98
98
  "@types/debug": "4.1.13",
99
99
  "@types/find": "0.2.4",
100
100
  "@types/jest": "30.0.0",
@@ -123,8 +123,5 @@
123
123
  "ws": "8.21.0",
124
124
  "nanoid": "3.3.18"
125
125
  },
126
- "peerDependencies": {
127
- "@sasjs/lint": "^4.4.0"
128
- },
129
- "version": "6.4.0"
126
+ "version": "6.4.2"
130
127
  }