@sasjs/cli 6.4.1 → 6.4.3

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
+ });
@@ -52,7 +52,8 @@ function printHelpText() {
52
52
  description: [
53
53
  "Creates the 'sasjs' folder and doxy subfolder (with content files + configuration) for docs",
54
54
  "- Inserted in the current working directory.",
55
- "- If an existing NPM project, package.json is updated with the @sasjs/core dependency."
55
+ "- If an existing NPM project, package.json is updated with the @sasjs/core dependency.",
56
+ "- Aborts without changing anything if this folder already contains sasjs/sasjsconfig.json."
56
57
  ]
57
58
  },
58
59
  {
@@ -1,7 +1,22 @@
1
+ export declare class AlreadyInitialisedError extends Error {
2
+ constructor(message: string);
3
+ }
1
4
  export declare function init(): Promise<void>;
5
+ /**
6
+ * Creates the macro folder that the generated `macroFolders` points at.
7
+ * `sasjs compile` fails with ENOENT when that folder is absent, so an
8
+ * initialised project compiles before the user has written a macro.
9
+ * The folder carries a `.gitkeep` because git does not track empty directories -
10
+ * without it the folder disappears on clone and compilation breaks again.
11
+ * @param {string} parentFolderName- the name of the project folder.
12
+ */
13
+ export declare const createMacroFolder: (parentFolderName: string) => Promise<void>;
2
14
  /**
3
15
  * Creates a SASjs configuration file.
4
16
  * Its name will be of the form 'sasjsconfig.json'
17
+ * The target's `serverUrl` is empty rather than a placeholder URL: an empty
18
+ * value reads as "not configured yet", while any non-empty placeholder has to
19
+ * pass URL validation every time the config is read.
5
20
  * @param {string} parentFolderName- the name of the project folder.
6
21
  */
7
22
  export declare const createConfigFile: (parentFolderName: string) => Promise<void>;
@@ -1,4 +1,19 @@
1
1
  "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
2
17
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
18
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
19
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -39,49 +54,104 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
39
54
  return (mod && mod.__esModule) ? mod : { "default": mod };
40
55
  };
41
56
  Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.createConfigFile = void 0;
57
+ exports.createConfigFile = exports.createMacroFolder = exports.AlreadyInitialisedError = void 0;
43
58
  exports.init = init;
44
59
  var path_1 = __importDefault(require("path"));
45
60
  var utils_1 = require("../../utils/utils");
46
61
  var utils_2 = require("@sasjs/utils");
47
62
  var createLintConfigFile_1 = require("../shared/createLintConfigFile");
63
+ var AlreadyInitialisedError = /** @class */ (function (_super) {
64
+ __extends(AlreadyInitialisedError, _super);
65
+ function AlreadyInitialisedError(message) {
66
+ var _this = _super.call(this, message) || this;
67
+ _this.name = 'AlreadyInitialisedError';
68
+ // The build targets ES5, where extending a built-in does not repair the
69
+ // prototype chain - without this, `instanceof` is false at runtime.
70
+ Object.setPrototypeOf(_this, AlreadyInitialisedError.prototype);
71
+ return _this;
72
+ }
73
+ return AlreadyInitialisedError;
74
+ }(Error));
75
+ exports.AlreadyInitialisedError = AlreadyInitialisedError;
48
76
  function init() {
49
77
  return __awaiter(this, void 0, void 0, function () {
50
- var parentFolderName, lintConfigPath;
78
+ var parentFolderName, existingConfigPath, lintConfigPath;
51
79
  var _a;
52
80
  return __generator(this, function (_b) {
53
81
  switch (_b.label) {
54
82
  case 0:
55
83
  (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info('Initialising SASjs...');
56
84
  parentFolderName = '.';
57
- return [4 /*yield*/, (0, utils_1.setupNpmProject)(parentFolderName)];
85
+ existingConfigPath = path_1.default.join(process.projectDir, parentFolderName, 'sasjs', 'sasjsconfig.json');
86
+ return [4 /*yield*/, (0, utils_2.fileExists)(existingConfigPath)];
58
87
  case 1:
88
+ if (_b.sent()) {
89
+ throw new AlreadyInitialisedError('This folder is already a SASjs project (sasjs/sasjsconfig.json exists). Aborting without making changes.');
90
+ }
91
+ return [4 /*yield*/, (0, utils_1.setupNpmProject)(parentFolderName)];
92
+ case 2:
59
93
  _b.sent();
60
94
  return [4 /*yield*/, (0, utils_1.setupGitIgnore)(parentFolderName)];
61
- case 2:
95
+ case 3:
62
96
  _b.sent();
63
97
  return [4 /*yield*/, (0, utils_1.setupDoxygen)(parentFolderName)];
64
- case 3:
98
+ case 4:
65
99
  _b.sent();
66
100
  return [4 /*yield*/, (0, exports.createConfigFile)(parentFolderName)];
67
- case 4:
101
+ case 5:
102
+ _b.sent();
103
+ return [4 /*yield*/, (0, exports.createMacroFolder)(parentFolderName)];
104
+ case 6:
68
105
  _b.sent();
69
106
  lintConfigPath = path_1.default.join(process.projectDir, parentFolderName, '.sasjslint');
70
107
  return [4 /*yield*/, (0, utils_2.fileExists)(lintConfigPath)];
71
- case 5:
72
- if (!!(_b.sent())) return [3 /*break*/, 7];
108
+ case 7:
109
+ if (!!(_b.sent())) return [3 /*break*/, 9];
73
110
  return [4 /*yield*/, (0, createLintConfigFile_1.createLintConfigFile)(parentFolderName)];
74
- case 6:
111
+ case 8:
75
112
  _b.sent();
76
- _b.label = 7;
77
- case 7: return [2 /*return*/];
113
+ _b.label = 9;
114
+ case 9: return [2 /*return*/];
78
115
  }
79
116
  });
80
117
  });
81
118
  }
119
+ /**
120
+ * Creates the macro folder that the generated `macroFolders` points at.
121
+ * `sasjs compile` fails with ENOENT when that folder is absent, so an
122
+ * initialised project compiles before the user has written a macro.
123
+ * The folder carries a `.gitkeep` because git does not track empty directories -
124
+ * without it the folder disappears on clone and compilation breaks again.
125
+ * @param {string} parentFolderName- the name of the project folder.
126
+ */
127
+ var createMacroFolder = function (parentFolderName) { return __awaiter(void 0, void 0, void 0, function () {
128
+ var macroFolderPath, gitKeepPath;
129
+ return __generator(this, function (_a) {
130
+ switch (_a.label) {
131
+ case 0:
132
+ macroFolderPath = path_1.default.join(process.projectDir, parentFolderName, 'sasjs', 'macros');
133
+ return [4 /*yield*/, (0, utils_2.createFolder)(macroFolderPath)];
134
+ case 1:
135
+ _a.sent();
136
+ gitKeepPath = path_1.default.join(macroFolderPath, '.gitkeep');
137
+ return [4 /*yield*/, (0, utils_2.fileExists)(gitKeepPath)];
138
+ case 2:
139
+ if (!!(_a.sent())) return [3 /*break*/, 4];
140
+ return [4 /*yield*/, (0, utils_2.createFile)(gitKeepPath, '')];
141
+ case 3:
142
+ _a.sent();
143
+ _a.label = 4;
144
+ case 4: return [2 /*return*/];
145
+ }
146
+ });
147
+ }); };
148
+ exports.createMacroFolder = createMacroFolder;
82
149
  /**
83
150
  * Creates a SASjs configuration file.
84
151
  * Its name will be of the form 'sasjsconfig.json'
152
+ * The target's `serverUrl` is empty rather than a placeholder URL: an empty
153
+ * value reads as "not configured yet", while any non-empty placeholder has to
154
+ * pass URL validation every time the config is read.
85
155
  * @param {string} parentFolderName- the name of the project folder.
86
156
  */
87
157
  var createConfigFile = function (parentFolderName) { return __awaiter(void 0, void 0, void 0, function () {
@@ -97,7 +167,7 @@ var createConfigFile = function (parentFolderName) { return __awaiter(void 0, vo
97
167
  {
98
168
  name: 'mytarget',
99
169
  serverType: 'SASJS',
100
- serverUrl: ' ',
170
+ serverUrl: '',
101
171
  appLoc: '/Public/apps/myapp'
102
172
  }
103
173
  ]
@@ -85,8 +85,15 @@ var InitCommand = /** @class */ (function (_super) {
85
85
  return command_1.ReturnCode.Success;
86
86
  })
87
87
  .catch(function (err) {
88
- var _a;
89
- (_a = process.logger) === null || _a === void 0 ? void 0 : _a.error('Error initialising SASjs: ', err);
88
+ var _a, _b;
89
+ // Refusing an already-initialised folder is an expected outcome, not a
90
+ // crash: report it on one line, and exit with a code a script can tell
91
+ // apart from a genuine failure.
92
+ if (err instanceof init_1.AlreadyInitialisedError) {
93
+ (_a = process.logger) === null || _a === void 0 ? void 0 : _a.error(err.message);
94
+ return command_1.ReturnCode.AlreadyInitialised;
95
+ }
96
+ (_b = process.logger) === null || _b === void 0 ? void 0 : _b.error('Error initialising SASjs: ', err);
90
97
  return command_1.ReturnCode.InternalError;
91
98
  })];
92
99
  case 1: return [2 /*return*/, _a.sent()];