@sasjs/cli 6.24.2 → 6.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -99,6 +99,7 @@ var file_1 = require("../../utils/file");
99
99
  var internal_1 = require("../compile/internal");
100
100
  var config_2 = require("./internal/config");
101
101
  var getLaunchPageCode_1 = require("./internal/getLaunchPageCode");
102
+ var appManifest_1 = require("./internal/appManifest");
102
103
  var mockSite_1 = require("./internal/mockSite/mockSite");
103
104
  function build(target) {
104
105
  return __awaiter(this, void 0, void 0, function () {
@@ -241,6 +242,11 @@ function createFinalSasFiles(target) {
241
242
  servicePackSASjs.streamLogo = streamConfig.streamLogo;
242
243
  servicePackSASjs.streamServiceName = streamConfig.streamServiceName;
243
244
  servicePackSASjs.streamWebFolder = streamConfig.streamWebFolder;
245
+ // The deployment and the statement that it is an app travel together: the
246
+ // server indexes the app from this file in the same request that writes the
247
+ // files, so a publish cannot fail on its own after a deploy succeeded. It
248
+ // also means the zip a CI job keeps is everything needed to publish.
249
+ servicePackSASjs.fileTree = (0, appManifest_1.withAppManifest)(folderContentJSON, (0, appManifest_1.appManifest)(streamConfig));
244
250
  }
245
251
  }
246
252
  finalSasFileContent = (0, utils_1.removeHeader)(finalSasFileContent);
@@ -0,0 +1,42 @@
1
+ import { FileTree, StreamConfig } from '@sasjs/utils';
2
+ /**
3
+ * The file, at the root of a deployment, that says the folder is an app.
4
+ *
5
+ * It carries what a deploy payload names for a stream today - the label, the
6
+ * folder the compiled assets are in, the logo - inside the deployment itself, so
7
+ * one upload can be both the deployment and the publish.
8
+ *
9
+ * **This ships ahead of the reader.** The manifest is read by `splitAppBundle` in
10
+ * sasjs/api (PR #65), which takes it out of the tree before the tree is written
11
+ * and indexes the app in the same request; no released `@sasjs/api`, `@sasjs/adapter`
12
+ * or `sasjs/server` knows the file yet, so until a host adopts that package the
13
+ * manifest is deployed as an ordinary file and the publish still comes from the
14
+ * payload's `streamWebFolder` / `streamServiceName`, exactly as now. The name has
15
+ * to match `APP_MANIFEST` in that package - `sasjs.app.json` is spelled here
16
+ * rather than imported because the deployment does not ship the package.
17
+ */
18
+ export declare const APP_MANIFEST = "sasjs.app.json";
19
+ export interface AppManifest {
20
+ /** The label the app is listed under. */
21
+ name?: string;
22
+ /** The folder under `services/` holding the compiled web app. */
23
+ streamWebFolder: string;
24
+ /** An asset inside the app, used as its tile image. */
25
+ logo?: string;
26
+ }
27
+ /**
28
+ * What a target's stream configuration says about the app it deploys.
29
+ *
30
+ * Only fields the deployer actually set are written: a manifest that states
31
+ * `"logo": undefined` is not JSON, and one that states a default the server also
32
+ * defaults would freeze that default into every deployment.
33
+ */
34
+ export declare const appManifest: (streamConfig: StreamConfig) => AppManifest;
35
+ /**
36
+ * The deployment tree with the manifest at its root.
37
+ *
38
+ * A tree that already carries a manifest - a build output adjusted by hand, or a
39
+ * bundle built twice - has it replaced rather than duplicated, because two files
40
+ * with one name in one folder is not a tree any host can deploy.
41
+ */
42
+ export declare const withAppManifest: (tree: FileTree, manifest: AppManifest) => FileTree;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __read = (this && this.__read) || function (o, n) {
14
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
15
+ if (!m) return o;
16
+ var i = m.call(o), r, ar = [], e;
17
+ try {
18
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
19
+ }
20
+ catch (error) { e = { error: error }; }
21
+ finally {
22
+ try {
23
+ if (r && !r.done && (m = i["return"])) m.call(i);
24
+ }
25
+ finally { if (e) throw e.error; }
26
+ }
27
+ return ar;
28
+ };
29
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
30
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
31
+ if (ar || !(i in from)) {
32
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
33
+ ar[i] = from[i];
34
+ }
35
+ }
36
+ return to.concat(ar || Array.prototype.slice.call(from));
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.withAppManifest = exports.appManifest = exports.APP_MANIFEST = void 0;
40
+ var utils_1 = require("@sasjs/utils");
41
+ /**
42
+ * The file, at the root of a deployment, that says the folder is an app.
43
+ *
44
+ * It carries what a deploy payload names for a stream today - the label, the
45
+ * folder the compiled assets are in, the logo - inside the deployment itself, so
46
+ * one upload can be both the deployment and the publish.
47
+ *
48
+ * **This ships ahead of the reader.** The manifest is read by `splitAppBundle` in
49
+ * sasjs/api (PR #65), which takes it out of the tree before the tree is written
50
+ * and indexes the app in the same request; no released `@sasjs/api`, `@sasjs/adapter`
51
+ * or `sasjs/server` knows the file yet, so until a host adopts that package the
52
+ * manifest is deployed as an ordinary file and the publish still comes from the
53
+ * payload's `streamWebFolder` / `streamServiceName`, exactly as now. The name has
54
+ * to match `APP_MANIFEST` in that package - `sasjs.app.json` is spelled here
55
+ * rather than imported because the deployment does not ship the package.
56
+ */
57
+ exports.APP_MANIFEST = 'sasjs.app.json';
58
+ /**
59
+ * What a target's stream configuration says about the app it deploys.
60
+ *
61
+ * Only fields the deployer actually set are written: a manifest that states
62
+ * `"logo": undefined` is not JSON, and one that states a default the server also
63
+ * defaults would freeze that default into every deployment.
64
+ */
65
+ var appManifest = function (streamConfig) { return (__assign(__assign(__assign({}, (streamConfig.streamServiceName
66
+ ? { name: streamConfig.streamServiceName }
67
+ : {})), { streamWebFolder: streamConfig.streamWebFolder }), (streamConfig.streamLogo ? { logo: streamConfig.streamLogo } : {}))); };
68
+ exports.appManifest = appManifest;
69
+ /**
70
+ * The deployment tree with the manifest at its root.
71
+ *
72
+ * A tree that already carries a manifest - a build output adjusted by hand, or a
73
+ * bundle built twice - has it replaced rather than duplicated, because two files
74
+ * with one name in one folder is not a tree any host can deploy.
75
+ */
76
+ var withAppManifest = function (tree, manifest) { return (__assign(__assign({}, tree), { members: __spreadArray(__spreadArray([], __read(tree.members.filter(function (member) {
77
+ return !(member.type === utils_1.MemberType.file && member.name === exports.APP_MANIFEST);
78
+ })), false), [
79
+ {
80
+ name: exports.APP_MANIFEST,
81
+ type: utils_1.MemberType.file,
82
+ code: JSON.stringify(manifest, null, 2)
83
+ }
84
+ ], false) })); };
85
+ exports.withAppManifest = withAppManifest;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ var utils_1 = require("@sasjs/utils");
15
+ var appManifest_1 = require("../appManifest");
16
+ var streamConfig = function (over) {
17
+ if (over === void 0) { over = {}; }
18
+ return (__assign({ streamWeb: true, streamWebFolder: 'web', webSourcePath: 'dist', streamServiceName: 'mario', assetPaths: [] }, over));
19
+ };
20
+ var tree = {
21
+ members: [
22
+ {
23
+ name: 'services',
24
+ type: utils_1.MemberType.folder,
25
+ members: [{ name: 'run', type: utils_1.MemberType.service, code: '%put hi;' }]
26
+ }
27
+ ]
28
+ };
29
+ describe('the app manifest a build writes', function () {
30
+ it('names the app the target names, and the folder its web build is in', function () {
31
+ expect((0, appManifest_1.appManifest)(streamConfig())).toEqual({
32
+ name: 'mario',
33
+ streamWebFolder: 'web'
34
+ });
35
+ });
36
+ it('states a logo when the target has one', function () {
37
+ expect((0, appManifest_1.appManifest)(streamConfig({ streamLogo: 'logo.png' }))).toEqual({
38
+ name: 'mario',
39
+ streamWebFolder: 'web',
40
+ logo: 'logo.png'
41
+ });
42
+ });
43
+ it('states only what the target states', function () {
44
+ // a manifest carrying `"name": undefined` is not JSON, and one carrying a
45
+ // default would freeze that default into every deployment
46
+ var manifest = (0, appManifest_1.appManifest)(streamConfig({ streamServiceName: '' }));
47
+ expect(Object.keys(manifest)).toEqual(['streamWebFolder']);
48
+ });
49
+ it('is added at the root of the deployment tree', function () {
50
+ var deployed = (0, appManifest_1.withAppManifest)(tree, (0, appManifest_1.appManifest)(streamConfig()));
51
+ var manifest = deployed.members.find(function (member) {
52
+ return member.type === utils_1.MemberType.file && member.name === appManifest_1.APP_MANIFEST;
53
+ });
54
+ expect(JSON.parse(manifest.code)).toEqual({
55
+ name: 'mario',
56
+ streamWebFolder: 'web'
57
+ });
58
+ // the deployment is untouched: the manifest is added, nothing is replaced
59
+ expect(deployed.members).toHaveLength(2);
60
+ expect(tree.members).toHaveLength(1);
61
+ });
62
+ it('replaces a manifest the tree already carries, rather than adding a second', function () {
63
+ var once = (0, appManifest_1.withAppManifest)(tree, (0, appManifest_1.appManifest)(streamConfig()));
64
+ var twice = (0, appManifest_1.withAppManifest)(once, (0, appManifest_1.appManifest)(streamConfig({ streamServiceName: 'luigi' })));
65
+ var manifests = twice.members.filter(function (member) {
66
+ return member.type === utils_1.MemberType.file && member.name === appManifest_1.APP_MANIFEST;
67
+ });
68
+ expect(manifests).toHaveLength(1);
69
+ expect(JSON.parse(manifests[0].code).name).toBe('luigi');
70
+ });
71
+ });
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
14
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
15
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -45,6 +56,7 @@ var utils_2 = require("../../../utils");
45
56
  var build_1 = require("../build");
46
57
  var __1 = require("../..");
47
58
  var path_1 = __importDefault(require("path"));
59
+ var appManifest_1 = require("../internal/appManifest");
48
60
  describe('sasjs build', function () {
49
61
  var appName;
50
62
  beforeAll(function () {
@@ -104,6 +116,46 @@ describe('sasjs build', function () {
104
116
  }
105
117
  });
106
118
  }); }, 2 * 60 * 1000);
119
+ it("should write the app manifest into the pack a streamed SASjs target deploys", function () { return __awaiter(void 0, void 0, void 0, function () {
120
+ var base, target, pack, _a, _b, manifest;
121
+ return __generator(this, function (_c) {
122
+ switch (_c.label) {
123
+ case 0:
124
+ appName = "test-app-manifest-".concat((0, test_1.generateUniqueTimestamp)());
125
+ return [4 /*yield*/, (0, test_1.createTestApp)(__dirname, appName)];
126
+ case 1:
127
+ _c.sent();
128
+ return [4 /*yield*/, (0, utils_2.findTargetInConfiguration)('viya')];
129
+ case 2:
130
+ base = (_c.sent()).target;
131
+ target = __assign(__assign({}, base), { name: 'streamed', serverType: utils_1.ServerType.Sasjs, appLoc: '/Public/apps/demo', streamConfig: {
132
+ streamWeb: true,
133
+ streamWebFolder: 'web',
134
+ webSourcePath: 'web',
135
+ streamServiceName: 'demo',
136
+ assetPaths: []
137
+ } });
138
+ return [4 /*yield*/, (0, __1.compile)(base)];
139
+ case 3:
140
+ _c.sent();
141
+ return [4 /*yield*/, (0, build_1.build)(target)];
142
+ case 4:
143
+ _c.sent();
144
+ _b = (_a = JSON).parse;
145
+ return [4 /*yield*/, (0, utils_1.readFile)(path_1.default.join(process.sasjsConstants.buildDestinationFolder, 'streamed.json'))];
146
+ case 5:
147
+ pack = _b.apply(_a, [_c.sent()]);
148
+ manifest = pack.fileTree.members.find(function (member) { return member.name === appManifest_1.APP_MANIFEST; });
149
+ expect(manifest).toBeTruthy();
150
+ expect(manifest.type).toBe('file');
151
+ expect(JSON.parse(manifest.code)).toEqual({
152
+ name: 'demo',
153
+ streamWebFolder: 'web'
154
+ });
155
+ return [2 /*return*/];
156
+ }
157
+ });
158
+ }); }, 2 * 60 * 1000);
107
159
  it('reports a missing build folder instead of compiling one', function () { return __awaiter(void 0, void 0, void 0, function () {
108
160
  var target, buildDestinationFolder;
109
161
  return __generator(this, function (_a) {
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The address an app is served on, from the answer a deploy got back.
3
+ *
4
+ * The CLI does not guess it. A server that knows where it serves the app states
5
+ * the `url` on the app it answers, and that is printed - relative to the server
6
+ * URL when it is a path. Failing that, the stream name is the address every
7
+ * server so far has served apps on: `/app/<name>/`. An id is not turned into a URL
8
+ * here, because a server that has ids is a server that can say where it put them.
9
+ */
10
+ export interface DeployAppAnswer {
11
+ app?: {
12
+ id?: string;
13
+ url?: string;
14
+ };
15
+ streamServiceName?: string;
16
+ }
17
+ export declare const webAppStreamUrl: (serverUrl: string, answer: DeployAppAnswer | undefined) => string | undefined;
18
+ /**
19
+ * Says where the app is, when the deploy published one.
20
+ *
21
+ * The call is the whole of what a caller has to do, which keeps the uncovered
22
+ * path in the deploy command to one function call rather than a chain of
23
+ * conditions nothing exercises.
24
+ */
25
+ export declare const reportAppUrl: (serverUrl: string, answer: DeployAppAnswer | undefined, info?: (message: string) => void) => string | undefined;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reportAppUrl = exports.webAppStreamUrl = void 0;
4
+ var webAppStreamUrl = function (serverUrl, answer) {
5
+ var _a;
6
+ var stated = (_a = answer === null || answer === void 0 ? void 0 : answer.app) === null || _a === void 0 ? void 0 : _a.url;
7
+ if (stated)
8
+ return /^https?:\/\//i.test(stated) ? stated : "".concat(serverUrl).concat(stated);
9
+ return (answer === null || answer === void 0 ? void 0 : answer.streamServiceName)
10
+ ? "".concat(serverUrl, "/app/").concat(answer.streamServiceName, "/")
11
+ : undefined;
12
+ };
13
+ exports.webAppStreamUrl = webAppStreamUrl;
14
+ /**
15
+ * Says where the app is, when the deploy published one.
16
+ *
17
+ * The call is the whole of what a caller has to do, which keeps the uncovered
18
+ * path in the deploy command to one function call rather than a chain of
19
+ * conditions nothing exercises.
20
+ */
21
+ var reportAppUrl = function (serverUrl, answer, info) {
22
+ var url = (0, exports.webAppStreamUrl)(serverUrl, answer);
23
+ if (url)
24
+ info === null || info === void 0 ? void 0 : info("Web app is available at ".concat(url));
25
+ return url;
26
+ };
27
+ exports.reportAppUrl = reportAppUrl;
@@ -40,6 +40,7 @@ exports.deployToSasjsWithServicePack = deployToSasjsWithServicePack;
40
40
  var node_1 = require("@sasjs/adapter/node");
41
41
  var config_1 = require("../../../utils/config");
42
42
  var utils_1 = require("../../../utils/utils");
43
+ var appStreamUrl_1 = require("./appStreamUrl");
43
44
  var utils_2 = require("@sasjs/utils");
44
45
  /**
45
46
  * Deploys app to `SASJS` server.
@@ -48,28 +49,28 @@ var utils_2 = require("@sasjs/utils");
48
49
  */
49
50
  function deployToSasjsWithServicePack(jsonFilePath, target, streamConfig) {
50
51
  return __awaiter(this, void 0, void 0, function () {
51
- var sasjsApiClient, authConfig, _a, result, zipFilePath, jsonContent, payload, webAppStreamUrl;
52
- var _b, _c, _d;
53
- return __generator(this, function (_e) {
54
- switch (_e.label) {
52
+ var sasjsApiClient, authConfig, _a, result, zipFilePath, jsonContent, payload;
53
+ var _b, _c;
54
+ return __generator(this, function (_d) {
55
+ switch (_d.label) {
55
56
  case 0:
56
57
  sasjsApiClient = new node_1.SASjsApiClient(new node_1.SasjsRequestClient(target.serverUrl, target.httpsAgentOptions));
57
58
  return [4 /*yield*/, (0, utils_1.isSasJsServerInServerMode)(target)];
58
59
  case 1:
59
- if (!(_e.sent())) return [3 /*break*/, 3];
60
+ if (!(_d.sent())) return [3 /*break*/, 3];
60
61
  return [4 /*yield*/, (0, config_1.getAuthConfig)(target)];
61
62
  case 2:
62
- _a = _e.sent();
63
+ _a = _d.sent();
63
64
  return [3 /*break*/, 4];
64
65
  case 3:
65
66
  _a = undefined;
66
- _e.label = 4;
67
+ _d.label = 4;
67
68
  case 4:
68
69
  authConfig = _a;
69
70
  zipFilePath = jsonFilePath + '.zip';
70
71
  return [4 /*yield*/, (0, utils_2.fileExists)(zipFilePath)];
71
72
  case 5:
72
- if (!_e.sent()) return [3 /*break*/, 7];
73
+ if (!_d.sent()) return [3 /*break*/, 7];
73
74
  return [4 /*yield*/, sasjsApiClient
74
75
  .deployZipFile(zipFilePath, authConfig)
75
76
  .catch(function (err) {
@@ -78,11 +79,11 @@ function deployToSasjsWithServicePack(jsonFilePath, target, streamConfig) {
78
79
  throw new Error('Deploy service pack error');
79
80
  })];
80
81
  case 6:
81
- result = _e.sent();
82
+ result = _d.sent();
82
83
  return [3 /*break*/, 10];
83
84
  case 7: return [4 /*yield*/, (0, utils_2.readFile)(jsonFilePath)];
84
85
  case 8:
85
- jsonContent = _e.sent();
86
+ jsonContent = _d.sent();
86
87
  payload = JSON.parse(jsonContent);
87
88
  return [4 /*yield*/, sasjsApiClient
88
89
  .deploy(payload, target.appLoc, authConfig)
@@ -92,8 +93,8 @@ function deployToSasjsWithServicePack(jsonFilePath, target, streamConfig) {
92
93
  throw new Error('Deploy service pack error');
93
94
  })];
94
95
  case 9:
95
- result = _e.sent();
96
- _e.label = 10;
96
+ result = _d.sent();
97
+ _d.label = 10;
97
98
  case 10:
98
99
  if ((result === null || result === void 0 ? void 0 : result.status) === 'failure') {
99
100
  (_b = process.logger) === null || _b === void 0 ? void 0 : _b.error(result.message);
@@ -102,10 +103,10 @@ function deployToSasjsWithServicePack(jsonFilePath, target, streamConfig) {
102
103
  }
103
104
  throw new Error('Deploy service pack error');
104
105
  }
105
- if ((streamConfig === null || streamConfig === void 0 ? void 0 : streamConfig.streamWeb) && (result === null || result === void 0 ? void 0 : result.streamServiceName)) {
106
- webAppStreamUrl = "".concat(target.serverUrl, "/AppStream/").concat(result.streamServiceName);
107
- (_d = process.logger) === null || _d === void 0 ? void 0 : _d.info("Web app is available at ".concat(webAppStreamUrl));
108
- }
106
+ // a deploy that published an app says where it is - by id where the server
107
+ // answers one, by stream name where it still indexes apps by label
108
+ if (streamConfig === null || streamConfig === void 0 ? void 0 : streamConfig.streamWeb)
109
+ (0, appStreamUrl_1.reportAppUrl)(target.serverUrl, result, function (message) { var _a; return (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info(message); });
109
110
  return [2 /*return*/];
110
111
  }
111
112
  });
@@ -41,6 +41,7 @@ var utils_1 = require("@sasjs/utils");
41
41
  var config_1 = require("../../../utils/config");
42
42
  var utils_2 = require("../../../utils/utils");
43
43
  var _1 = require(".");
44
+ var appStreamUrl_1 = require("./appStreamUrl");
44
45
  /**
45
46
  * Execute deployScript on `SASJS` server.
46
47
  * @param {string} deployScriptName - name of deploy script.
@@ -53,22 +54,22 @@ var _1 = require(".");
53
54
  */
54
55
  function executeDeployScriptSasjs(deployScriptName, target, linesToExecute, logFilePath, streamConfig) {
55
56
  return __awaiter(this, void 0, void 0, function () {
56
- var authConfig, _a, sasjs, completedWithError, executionResult, webAppStreamUrl;
57
- var _b, _c, _d, _e;
58
- return __generator(this, function (_f) {
59
- switch (_f.label) {
57
+ var authConfig, _a, sasjs, completedWithError, executionResult;
58
+ var _b, _c, _d;
59
+ return __generator(this, function (_e) {
60
+ switch (_e.label) {
60
61
  case 0:
61
62
  (_b = process.logger) === null || _b === void 0 ? void 0 : _b.info("Sending ".concat(deployScriptName, " to SASJS server for execution."));
62
63
  return [4 /*yield*/, (0, utils_2.isSasJsServerInServerMode)(target)];
63
64
  case 1:
64
- if (!(_f.sent())) return [3 /*break*/, 3];
65
+ if (!(_e.sent())) return [3 /*break*/, 3];
65
66
  return [4 /*yield*/, (0, config_1.getAuthConfig)(target)];
66
67
  case 2:
67
- _a = _f.sent();
68
+ _a = _e.sent();
68
69
  return [3 /*break*/, 4];
69
70
  case 3:
70
71
  _a = undefined;
71
- _f.label = 4;
72
+ _e.label = 4;
72
73
  case 4:
73
74
  authConfig = _a;
74
75
  sasjs = (0, config_1.getSASjs)(target);
@@ -86,19 +87,19 @@ function executeDeployScriptSasjs(deployScriptName, target, linesToExecute, logF
86
87
  return errorString;
87
88
  })];
88
89
  case 5:
89
- executionResult = _f.sent();
90
+ executionResult = _e.sent();
90
91
  return [4 /*yield*/, (0, utils_1.createFile)(logFilePath, executionResult !== null && executionResult !== void 0 ? executionResult : '')];
91
92
  case 6:
92
- _f.sent();
93
+ _e.sent();
93
94
  if (completedWithError) {
94
95
  (_c = process.logger) === null || _c === void 0 ? void 0 : _c.error("Deployment failed with errors! Log is available at ".concat(logFilePath));
95
96
  throw new Error("Deployment failed.");
96
97
  }
97
98
  (_d = process.logger) === null || _d === void 0 ? void 0 : _d.success("Deployment completed! Log is available at ".concat(logFilePath));
98
- if (streamConfig === null || streamConfig === void 0 ? void 0 : streamConfig.streamWeb) {
99
- webAppStreamUrl = "".concat(target.serverUrl, "/AppStream/").concat(streamConfig.streamServiceName);
100
- (_e = process.logger) === null || _e === void 0 ? void 0 : _e.info("Web app is available at ".concat(webAppStreamUrl));
101
- }
99
+ if (streamConfig === null || streamConfig === void 0 ? void 0 : streamConfig.streamWeb)
100
+ // the same helper as the service-pack route, so one deployment is reported
101
+ // at one address whichever route deployed it
102
+ (0, appStreamUrl_1.reportAppUrl)(target.serverUrl, { streamServiceName: streamConfig.streamServiceName }, function (message) { var _a; return (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info(message); });
102
103
  return [2 /*return*/];
103
104
  }
104
105
  });
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var appStreamUrl_1 = require("../appStreamUrl");
4
+ describe('the url a deploy reports', function () {
5
+ it('is the address the server states, when it states one', function () {
6
+ expect((0, appStreamUrl_1.webAppStreamUrl)('https://server.example', {
7
+ app: { id: '0e6f1d2c', url: '/app/0e6f1d2c/' }
8
+ })).toBe('https://server.example/app/0e6f1d2c/');
9
+ expect((0, appStreamUrl_1.webAppStreamUrl)('https://server.example', {
10
+ app: { url: 'https://apps.example/mario/' }
11
+ })).toBe('https://apps.example/mario/');
12
+ });
13
+ it('is the stream name when that is all the server answered', function () {
14
+ expect((0, appStreamUrl_1.webAppStreamUrl)('https://server.example', { streamServiceName: 'mario' })).toBe('https://server.example/app/mario/');
15
+ });
16
+ it('does not invent a url from an id alone', function () {
17
+ // a server that answers an id can say where it serves the app; guessing would
18
+ // print an address that may not exist
19
+ expect((0, appStreamUrl_1.webAppStreamUrl)('https://server.example', { app: { id: '0e6f1d2c' } })).toBeUndefined();
20
+ });
21
+ it('prefers the stated url over the stream name', function () {
22
+ expect((0, appStreamUrl_1.webAppStreamUrl)('https://server.example', {
23
+ app: { id: '0e6f1d2c', url: '/app/0e6f1d2c/' },
24
+ streamServiceName: 'mario'
25
+ })).toBe('https://server.example/app/0e6f1d2c/');
26
+ });
27
+ it('is nothing when the deploy published no app', function () {
28
+ expect((0, appStreamUrl_1.webAppStreamUrl)('https://server.example', {})).toBeUndefined();
29
+ expect((0, appStreamUrl_1.webAppStreamUrl)('https://server.example', undefined)).toBeUndefined();
30
+ expect((0, appStreamUrl_1.webAppStreamUrl)('https://server.example', { app: {} })).toBeUndefined();
31
+ });
32
+ it('says where the app is, once, and only when there is an app', function () {
33
+ var said = [];
34
+ var info = function (message) { return said.push(message); };
35
+ (0, appStreamUrl_1.reportAppUrl)('https://server.example', { streamServiceName: 'mario' }, info);
36
+ (0, appStreamUrl_1.reportAppUrl)('https://server.example', {}, info);
37
+ (0, appStreamUrl_1.reportAppUrl)('https://server.example', undefined);
38
+ expect(said).toEqual([
39
+ 'Web app is available at https://server.example/app/mario/'
40
+ ]);
41
+ });
42
+ });
@@ -151,7 +151,7 @@ describe('executeDeployScriptSasjs', function () {
151
151
  return [4 /*yield*/, (0, executeDeployScriptSasjs_1.executeDeployScriptSasjs)(deployScriptName, target, linesToExecute, logFilePath, { streamWeb: true, streamServiceName: 'clickme' })];
152
152
  case 1:
153
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"));
154
+ expect((_a = process.logger) === null || _a === void 0 ? void 0 : _a.info).toHaveBeenCalledWith("Web app is available at ".concat(target.serverUrl, "/app/clickme/"));
155
155
  return [2 /*return*/];
156
156
  }
157
157
  });
package/package.json CHANGED
@@ -125,5 +125,5 @@
125
125
  "ws": "8.21.0",
126
126
  "nanoid": "3.3.18"
127
127
  },
128
- "version": "6.24.2"
128
+ "version": "6.25.0"
129
129
  }