systemview 1.20.1 → 1.22.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.
- package/README.md +76 -40
- package/api/CLIHistory.js +29 -0
- package/api/Connections.js +14 -0
- package/api/cli-history.json +1 -0
- package/api/connections.json +1 -1
- package/api/index.js +45 -12
- package/build/asset-manifest.json +8 -6
- package/build/index.html +1 -1
- package/build/static/css/main.1916c1d1.css +15 -0
- package/build/static/css/main.1916c1d1.css.map +1 -0
- package/build/static/js/422.05c538a9.chunk.js +2 -0
- package/build/static/js/422.05c538a9.chunk.js.map +1 -0
- package/build/static/js/main.e9f9f4f8.js +3 -0
- package/build/static/js/{main.c3485d98.js.LICENSE.txt → main.e9f9f4f8.js.LICENSE.txt} +26 -48
- package/build/static/js/main.e9f9f4f8.js.map +1 -0
- package/cli/connectService.js +147 -55
- package/cli/cookieClient.js +1 -4
- package/cli/index.js +92 -37
- package/cli/launchApp.js +8 -4
- package/cli/listTests.js +37 -19
- package/cli/logs.js +412 -0
- package/cli/manifest.js +97 -0
- package/cli/openBrowser.js +1 -1
- package/cli/probe.js +36 -19
- package/cli/runTests.js +35 -40
- package/cli/startLineReader.js +160 -15
- package/cli/utils/cli.js +86 -12
- package/package.json +3 -3
- package/testing-utilities/Test.class.js +2 -1
- package/testing-utilities/transformTests.js +7 -6
- package/build/static/css/main.3396e24d.css +0 -15
- package/build/static/css/main.3396e24d.css.map +0 -1
- package/build/static/js/main.c3485d98.js +0 -3
- package/build/static/js/main.c3485d98.js.map +0 -1
package/cli/connectService.js
CHANGED
|
@@ -1,80 +1,172 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const Client = createCookieClient();
|
|
1
|
+
const { HttpClient, createClient } = require("systemlynx");
|
|
2
|
+
const { createCookieHttpClient } = require("./cookieClient");
|
|
3
|
+
const cookieHttpClient = createCookieHttpClient();
|
|
4
|
+
const Client = createClient(cookieHttpClient);
|
|
6
5
|
const log = require("./logger");
|
|
7
6
|
|
|
8
|
-
async function
|
|
9
|
-
const connectionData = await HttpClient.request({ url });
|
|
10
|
-
if (!connectionData.SystemLynxService) {
|
|
11
|
-
throw new Error(`No SystemLynx service found at ${url}`);
|
|
12
|
-
}
|
|
13
|
-
const client = Client.createService(connectionData);
|
|
14
|
-
const connection = await client.Plugin.getConnection();
|
|
15
|
-
return connection; // { projectCode, serviceId, system, specList }
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function readManifest(manifestFile) {
|
|
19
|
-
if (!fs.existsSync(manifestFile)) return null;
|
|
7
|
+
async function getUiSvc(uiUrl) {
|
|
20
8
|
try {
|
|
21
|
-
|
|
9
|
+
const { SystemView } = await Client.loadService(`${uiUrl}/systemview/api`);
|
|
10
|
+
return SystemView;
|
|
22
11
|
} catch {
|
|
23
12
|
return null;
|
|
24
13
|
}
|
|
25
14
|
}
|
|
26
15
|
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
16
|
+
async function notifyUi(uiSvc, project) {
|
|
17
|
+
if (!uiSvc) return;
|
|
18
|
+
try {
|
|
19
|
+
await uiSvc.connect(project);
|
|
20
|
+
} catch {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function serviceIdFromRoute(route) {
|
|
24
|
+
const segments = (route || "").split("/").filter(Boolean);
|
|
25
|
+
return [...segments].reverse().find((s) => s.toLowerCase() !== "api") || "Service";
|
|
36
26
|
}
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
function printSummary(entries) {
|
|
29
|
+
console.log("");
|
|
30
|
+
entries.forEach(({ projectCode, serviceId, url }) => {
|
|
31
|
+
log.plain(` ${projectCode} › ${serviceId}${url ? " " + url : ""}`);
|
|
32
|
+
});
|
|
33
|
+
console.log("");
|
|
34
|
+
}
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
module.exports = async function connectService(target, { useManifest, force, connectedUrls, uiUrl } = {}) {
|
|
37
|
+
const uiSvc = await getUiSvc(uiUrl);
|
|
38
|
+
|
|
39
|
+
// connect (no args) — connect to every service stored in UI
|
|
40
|
+
if (!target) {
|
|
41
|
+
if (!uiSvc) {
|
|
42
|
+
log.warn("SystemView UI not running. Start it first or provide a URL.");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const projects = await uiSvc.getProjects();
|
|
46
|
+
const all = Object.entries(projects).flatMap(([pc, svcs]) =>
|
|
47
|
+
svcs.map((s) => ({ projectCode: pc, ...s }))
|
|
48
|
+
);
|
|
49
|
+
if (!all.length) {
|
|
50
|
+
log.warn("No services in UI store. Use: systemview connect <url>");
|
|
46
51
|
return;
|
|
47
52
|
}
|
|
48
|
-
log.info(`
|
|
49
|
-
|
|
53
|
+
log.info(`Connecting to ${all.length} stored service(s)...`);
|
|
54
|
+
const summary = [];
|
|
55
|
+
for (const { projectCode, serviceId, connectionData, serviceUrl } of all) {
|
|
56
|
+
const url = serviceUrl || (connectionData && connectionData.serviceUrl);
|
|
57
|
+
if (!url) continue;
|
|
50
58
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
if (force) {
|
|
60
|
+
await Client.loadService(url);
|
|
61
|
+
} else {
|
|
62
|
+
Client.createService(connectionData);
|
|
63
|
+
}
|
|
64
|
+
connectedUrls.add(url);
|
|
65
|
+
log.success(`${projectCode} › ${serviceId}`);
|
|
66
|
+
summary.push({ projectCode, serviceId, url });
|
|
54
67
|
} catch (err) {
|
|
55
|
-
log.error(`${
|
|
68
|
+
log.error(`${serviceId} failed: ${err.message}`);
|
|
56
69
|
}
|
|
57
70
|
}
|
|
58
|
-
|
|
71
|
+
printSummary(summary);
|
|
59
72
|
return;
|
|
60
73
|
}
|
|
61
74
|
|
|
62
|
-
|
|
75
|
+
const isUrl = /^https?:\/\//i.test(target);
|
|
76
|
+
|
|
77
|
+
// connect <projectCode> — look up from UI store
|
|
78
|
+
if (!isUrl) {
|
|
79
|
+
if (!uiSvc) {
|
|
80
|
+
log.warn("SystemView UI not running. Cannot look up project by code.");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const services = await uiSvc.getServices(target);
|
|
84
|
+
if (!services || !services.length) {
|
|
85
|
+
log.warn(`No services found for project: ${target}`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
log.info(`Connecting to ${services.length} service(s) for ${target}...`);
|
|
89
|
+
const summary = [];
|
|
90
|
+
for (const { serviceId, system } of services) {
|
|
91
|
+
const { serviceUrl } = system.connectionData;
|
|
92
|
+
try {
|
|
93
|
+
if (force) {
|
|
94
|
+
await Client.loadService(serviceUrl);
|
|
95
|
+
} else {
|
|
96
|
+
Client.createService(system.connectionData);
|
|
97
|
+
}
|
|
98
|
+
connectedUrls.add(serviceUrl);
|
|
99
|
+
log.success(`${target} › ${serviceId}`);
|
|
100
|
+
summary.push({ projectCode: target, serviceId, url: serviceUrl });
|
|
101
|
+
} catch (err) {
|
|
102
|
+
log.error(`${serviceId} failed: ${err.message}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
printSummary(summary);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// connect <url> [--manifest]
|
|
110
|
+
log.info(`Connecting to ${target}...`);
|
|
63
111
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
112
|
+
if (useManifest) {
|
|
113
|
+
const svc = await Client.loadService(target);
|
|
114
|
+
let manifest = null;
|
|
115
|
+
try { manifest = await svc.Plugin.getManifest(); } catch {}
|
|
116
|
+
if (manifest && manifest.services && manifest.services.length) {
|
|
117
|
+
log.info(`Plugin manifest found: ${manifest.projectCode} (${manifest.services.length} service(s))`);
|
|
118
|
+
const summary = [];
|
|
119
|
+
for (const service of manifest.services) {
|
|
120
|
+
try {
|
|
121
|
+
Client.createService(service.system.connectionData);
|
|
122
|
+
connectedUrls.add(service.system.connectionData.serviceUrl);
|
|
123
|
+
await notifyUi(uiSvc, {
|
|
124
|
+
system: service.system,
|
|
125
|
+
projectCode: manifest.projectCode,
|
|
126
|
+
serviceId: service.serviceId,
|
|
127
|
+
specList: service.specList || { tests: [], docs: [] },
|
|
128
|
+
});
|
|
129
|
+
log.success(`${manifest.projectCode} › ${service.serviceId}`);
|
|
130
|
+
summary.push({ projectCode: manifest.projectCode, serviceId: service.serviceId, url: service.system.connectionData.serviceUrl });
|
|
131
|
+
} catch (err) {
|
|
132
|
+
log.error(`${service.serviceId} failed: ${err.message}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
printSummary(summary);
|
|
136
|
+
} else {
|
|
137
|
+
log.warn("No plugin manifest found. Storing as connected-services.");
|
|
138
|
+
const connectionData = await HttpClient.request({ url: target });
|
|
139
|
+
const serviceId = serviceIdFromRoute(connectionData.route);
|
|
140
|
+
const project = {
|
|
141
|
+
system: { connectionData },
|
|
142
|
+
projectCode: "connected-services",
|
|
143
|
+
serviceId,
|
|
144
|
+
specList: { tests: [], docs: [] },
|
|
145
|
+
};
|
|
146
|
+
Client.createService(connectionData);
|
|
147
|
+
connectedUrls.add(target);
|
|
148
|
+
await notifyUi(uiSvc, project);
|
|
149
|
+
printSummary([{ projectCode: "connected-services", serviceId, url: target }]);
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
const connectionData = await HttpClient.request({ url: target });
|
|
153
|
+
if (!connectionData || !connectionData.SystemLynxService) {
|
|
154
|
+
throw new Error("No SystemLynx service found at " + target);
|
|
155
|
+
}
|
|
156
|
+
const serviceId = serviceIdFromRoute(connectionData.route);
|
|
157
|
+
const project = {
|
|
158
|
+
system: { connectionData },
|
|
159
|
+
projectCode: "connected-services",
|
|
160
|
+
serviceId,
|
|
161
|
+
specList: { tests: [], docs: [] },
|
|
162
|
+
};
|
|
163
|
+
Client.createService(connectionData);
|
|
164
|
+
connectedUrls.add(target);
|
|
165
|
+
await notifyUi(uiSvc, project);
|
|
166
|
+
log.success(`connected-services › ${serviceId}`);
|
|
167
|
+
printSummary([{ projectCode: "connected-services", serviceId, url: target }]);
|
|
168
|
+
}
|
|
67
169
|
} catch (err) {
|
|
68
170
|
log.error(`Connection failed: ${err.message}`);
|
|
69
171
|
}
|
|
70
172
|
};
|
|
71
|
-
|
|
72
|
-
function printManifestSummary(manifest) {
|
|
73
|
-
if (!manifest) return;
|
|
74
|
-
log.plain(`\n Project: ${manifest.projectCode}`);
|
|
75
|
-
log.plain(` Services:`);
|
|
76
|
-
(manifest.services || []).forEach(({ serviceId, system }) => {
|
|
77
|
-
log.plain(` - ${serviceId} @ ${system.connectionData.serviceUrl}`);
|
|
78
|
-
});
|
|
79
|
-
log.plain("");
|
|
80
|
-
}
|
package/cli/cookieClient.js
CHANGED
|
@@ -87,7 +87,4 @@ function createCookieHttpClient(extraHeaders = {}) {
|
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
module.exports = {
|
|
91
|
-
createCookieHttpClient,
|
|
92
|
-
createCookieClient: (extraHeaders = {}) => createClient(createCookieHttpClient(extraHeaders)),
|
|
93
|
-
};
|
|
90
|
+
module.exports = { createCookieHttpClient };
|
package/cli/index.js
CHANGED
|
@@ -13,17 +13,39 @@ const listTests = require("./listTests");
|
|
|
13
13
|
const appIsRunning = require("./appIsRunning");
|
|
14
14
|
const openBrowser = require("./openBrowser");
|
|
15
15
|
const connectService = require("./connectService");
|
|
16
|
+
const manifestCommands = require("./manifest");
|
|
16
17
|
const probe = require("./probe");
|
|
17
|
-
const
|
|
18
|
-
const {
|
|
18
|
+
const logsCommand = require("./logs");
|
|
19
|
+
const { createClient } = require("systemlynx");
|
|
20
|
+
const { createCookieHttpClient } = require("./cookieClient");
|
|
21
|
+
const cookieHttpClient = createCookieHttpClient();
|
|
22
|
+
const Client = createClient(cookieHttpClient);
|
|
19
23
|
|
|
20
24
|
const DEFAULT_PORT = 3000;
|
|
21
25
|
const VERSION = require("../package.json").version;
|
|
26
|
+
const UI_URL = `http://localhost:${DEFAULT_PORT}`;
|
|
27
|
+
|
|
28
|
+
const MANIFEST_FILE = flags.manifest || path.join(process.cwd(), "systemview.manifest.json");
|
|
29
|
+
const connectedUrls = new Set();
|
|
30
|
+
|
|
31
|
+
function loadManifest() {
|
|
32
|
+
if (!fs.existsSync(MANIFEST_FILE)) return;
|
|
33
|
+
try {
|
|
34
|
+
const manifest = JSON.parse(fs.readFileSync(MANIFEST_FILE, "utf8"));
|
|
35
|
+
const services = manifest.services || [manifest];
|
|
36
|
+
for (const { system } of services) {
|
|
37
|
+
if (system && system.connectionData) {
|
|
38
|
+
Client.createService(system.connectionData);
|
|
39
|
+
connectedUrls.add(system.connectionData.serviceUrl);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch {}
|
|
43
|
+
}
|
|
22
44
|
|
|
23
45
|
async function startApp() {
|
|
24
46
|
const port = isNaN(input[1]) ? DEFAULT_PORT : Number(input[1]);
|
|
25
47
|
try {
|
|
26
|
-
await launchApp(port, { interactive: true });
|
|
48
|
+
await launchApp(port, { interactive: true, connectedUrls, client: Client });
|
|
27
49
|
} catch (error) {
|
|
28
50
|
log.error("Launch failed: " + error.message);
|
|
29
51
|
}
|
|
@@ -32,13 +54,11 @@ async function startApp() {
|
|
|
32
54
|
async function startTest() {
|
|
33
55
|
const project_code = input[1];
|
|
34
56
|
const namespace = input[2];
|
|
35
|
-
const url = `http://localhost:${DEFAULT_PORT}`;
|
|
36
57
|
try {
|
|
37
58
|
await launchApp(DEFAULT_PORT);
|
|
38
|
-
const exitCode = await runTests(
|
|
59
|
+
const exitCode = await runTests(UI_URL, project_code, namespace, {
|
|
39
60
|
json: flags.json,
|
|
40
61
|
verbose: flags.verbose,
|
|
41
|
-
manifest: flags.manifest,
|
|
42
62
|
headers: flags.headers,
|
|
43
63
|
bail: flags.bail,
|
|
44
64
|
dryRun: flags.dryRun,
|
|
@@ -56,41 +76,35 @@ async function startTest() {
|
|
|
56
76
|
async function list() {
|
|
57
77
|
const project_code = input[1];
|
|
58
78
|
const namespace = input[2];
|
|
59
|
-
const
|
|
60
|
-
const api = `${url}/systemview/api`;
|
|
79
|
+
const api = `${UI_URL}/systemview/api`;
|
|
61
80
|
if (!(await appIsRunning(api))) {
|
|
62
81
|
await launchApp(DEFAULT_PORT);
|
|
63
82
|
}
|
|
64
|
-
await listTests(
|
|
83
|
+
await listTests(UI_URL, project_code, namespace, {
|
|
84
|
+
connectedUrls,
|
|
85
|
+
verbose: flags.verbose,
|
|
86
|
+
json: flags.json,
|
|
87
|
+
});
|
|
65
88
|
process.exit(0);
|
|
66
89
|
}
|
|
67
90
|
|
|
68
91
|
async function open() {
|
|
69
92
|
const project_code = input[1];
|
|
70
93
|
const namespace = input[2];
|
|
71
|
-
const
|
|
72
|
-
const api = `${ui}/systemview/api`;
|
|
94
|
+
const api = `${UI_URL}/systemview/api`;
|
|
73
95
|
if (!(await appIsRunning(api))) {
|
|
74
96
|
await launchApp(DEFAULT_PORT);
|
|
75
97
|
}
|
|
76
98
|
|
|
77
99
|
let connectedServices = [];
|
|
78
100
|
if (namespace && project_code) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
connectedServices = raw.services ? raw.services : [raw];
|
|
84
|
-
} catch {}
|
|
85
|
-
} else {
|
|
86
|
-
try {
|
|
87
|
-
const { SystemView } = await createCookieClient().loadService(api);
|
|
88
|
-
connectedServices = (await SystemView.getServices(project_code)) || [];
|
|
89
|
-
} catch {}
|
|
90
|
-
}
|
|
101
|
+
try {
|
|
102
|
+
const { SystemView } = await Client.loadService(api);
|
|
103
|
+
connectedServices = (await SystemView.getServices(project_code)) || [];
|
|
104
|
+
} catch {}
|
|
91
105
|
}
|
|
92
106
|
|
|
93
|
-
openBrowser(
|
|
107
|
+
openBrowser(UI_URL, project_code, namespace, connectedServices);
|
|
94
108
|
process.exit(0);
|
|
95
109
|
}
|
|
96
110
|
|
|
@@ -100,24 +114,20 @@ async function quitApp() {
|
|
|
100
114
|
|
|
101
115
|
if (await appIsRunning(api)) {
|
|
102
116
|
log.info("Attempting remote shutdown...");
|
|
103
|
-
const url = `${api}/SystemView/shutdown`;
|
|
104
117
|
try {
|
|
105
|
-
|
|
118
|
+
const { SystemView } = await Client.loadService(api);
|
|
119
|
+
await SystemView.shutdown();
|
|
120
|
+
} catch {}
|
|
121
|
+
if (!(await appIsRunning(api))) {
|
|
106
122
|
log.success("SystemView shutdown successful!");
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
log.success("SystemView shutdown successful!");
|
|
111
|
-
process.exit(0);
|
|
112
|
-
} else {
|
|
113
|
-
log.error("Remote shutdown failed!");
|
|
114
|
-
process.exit(1);
|
|
115
|
-
}
|
|
123
|
+
} else {
|
|
124
|
+
log.error("Remote shutdown failed!");
|
|
125
|
+
process.exit(1);
|
|
116
126
|
}
|
|
117
127
|
} else {
|
|
118
128
|
log.warn(`No SystemView instance found @ ${api}`);
|
|
119
|
-
process.exit(0);
|
|
120
129
|
}
|
|
130
|
+
process.exit(0);
|
|
121
131
|
}
|
|
122
132
|
|
|
123
133
|
(async () => {
|
|
@@ -127,6 +137,8 @@ async function quitApp() {
|
|
|
127
137
|
}
|
|
128
138
|
|
|
129
139
|
init();
|
|
140
|
+
loadManifest();
|
|
141
|
+
|
|
130
142
|
const command = input[0];
|
|
131
143
|
|
|
132
144
|
if (command === "open") {
|
|
@@ -140,15 +152,58 @@ async function quitApp() {
|
|
|
140
152
|
} else if (["exit", "q", "shutdown", "stop"].includes(command)) {
|
|
141
153
|
await quitApp();
|
|
142
154
|
} else if (command === "connect") {
|
|
143
|
-
|
|
155
|
+
const useManifest = process.argv.includes("--manifest");
|
|
156
|
+
await connectService(input[1], {
|
|
157
|
+
useManifest,
|
|
158
|
+
force: flags.force,
|
|
159
|
+
connectedUrls,
|
|
160
|
+
uiUrl: UI_URL,
|
|
161
|
+
});
|
|
162
|
+
process.exit(0);
|
|
163
|
+
} else if (command === "disconnect") {
|
|
164
|
+
await manifestCommands.disconnect(input[1], input[2], {
|
|
165
|
+
connectedUrls,
|
|
166
|
+
uiUrl: UI_URL,
|
|
167
|
+
});
|
|
168
|
+
process.exit(0);
|
|
169
|
+
} else if (command === "manifest") {
|
|
170
|
+
const sub = input[1];
|
|
171
|
+
if (sub === "save") {
|
|
172
|
+
log.warn("manifest save requires an interactive session. Run: systemview start");
|
|
173
|
+
} else if (sub === "clean") {
|
|
174
|
+
await manifestCommands.clean(MANIFEST_FILE);
|
|
175
|
+
} else {
|
|
176
|
+
log.warn("Usage: systemview manifest <save|clean>");
|
|
177
|
+
}
|
|
144
178
|
process.exit(0);
|
|
145
179
|
} else if (command === "probe") {
|
|
180
|
+
await launchApp(DEFAULT_PORT);
|
|
146
181
|
const exitCode = await probe(input[1], input[2], {
|
|
147
182
|
json: flags.json,
|
|
148
183
|
manifest: flags.manifest,
|
|
149
184
|
headers: flags.headers,
|
|
185
|
+
uiUrl: UI_URL,
|
|
150
186
|
});
|
|
151
187
|
process.exit(exitCode || 0);
|
|
188
|
+
} else if (command === "logs" || command === "log") {
|
|
189
|
+
await launchApp(DEFAULT_PORT);
|
|
190
|
+
await logsCommand(input[1], input[2], {
|
|
191
|
+
uiUrl: UI_URL,
|
|
192
|
+
level: flags.level,
|
|
193
|
+
limit: flags.limit,
|
|
194
|
+
clear: flags.clear,
|
|
195
|
+
json: flags.json,
|
|
196
|
+
current: flags.current,
|
|
197
|
+
follow: flags.follow,
|
|
198
|
+
verbose: flags.verbose,
|
|
199
|
+
filter: flags.filter,
|
|
200
|
+
or: flags.or,
|
|
201
|
+
include: flags.include,
|
|
202
|
+
save: flags.save,
|
|
203
|
+
saved: flags.saved,
|
|
204
|
+
saveLimit: flags.saveLimit,
|
|
205
|
+
});
|
|
206
|
+
if (!flags.follow) process.exit(0);
|
|
152
207
|
} else {
|
|
153
208
|
await startApp();
|
|
154
209
|
}
|
package/cli/launchApp.js
CHANGED
|
@@ -2,8 +2,9 @@ const log = require("./logger");
|
|
|
2
2
|
const appIsRunning = require("./appIsRunning");
|
|
3
3
|
const launchSystemView = require("../api");
|
|
4
4
|
const startLineReader = require("./startLineReader");
|
|
5
|
+
const listTests = require("./listTests");
|
|
5
6
|
|
|
6
|
-
module.exports = async function launchApp(port, { interactive = false } = {}) {
|
|
7
|
+
module.exports = async function launchApp(port, { interactive = false, connectedUrls = new Set() } = {}) {
|
|
7
8
|
const ui = `http://localhost:${port}`;
|
|
8
9
|
const api = `${ui}/systemview/api`;
|
|
9
10
|
|
|
@@ -15,17 +16,20 @@ module.exports = async function launchApp(port, { interactive = false } = {}) {
|
|
|
15
16
|
|
|
16
17
|
if (await appIsRunning(api)) {
|
|
17
18
|
if (interactive) {
|
|
18
|
-
log.
|
|
19
|
+
log.warn(`SystemView already running on port ${port} — attaching.`);
|
|
19
20
|
logConnection();
|
|
21
|
+
await listTests(ui, null, null, { connectedUrls });
|
|
22
|
+
return startLineReader(ui, { connectedUrls });
|
|
20
23
|
}
|
|
21
24
|
return;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
if (interactive) log.info(
|
|
27
|
+
if (interactive) log.info(`Launching on port ${port}...`);
|
|
25
28
|
await launchSystemView(port);
|
|
26
29
|
logConnection();
|
|
27
30
|
|
|
28
31
|
if (interactive) {
|
|
29
|
-
|
|
32
|
+
await listTests(ui, null, null, { connectedUrls });
|
|
33
|
+
return startLineReader(ui, { connectedUrls });
|
|
30
34
|
}
|
|
31
35
|
};
|
package/cli/listTests.js
CHANGED
|
@@ -1,24 +1,44 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const { createCookieClient } = require("./cookieClient");
|
|
1
|
+
const { createClient } = require("systemlynx");
|
|
2
|
+
const { createCookieHttpClient } = require("./cookieClient");
|
|
4
3
|
const log = require("./logger");
|
|
5
4
|
const chalk = require("chalk");
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
const cookieHttpClient = createCookieHttpClient();
|
|
7
|
+
const Client = createClient(cookieHttpClient);
|
|
8
|
+
|
|
9
|
+
module.exports = async function listTests(url, project_code, namespace, { connectedUrls = new Set(), verbose = false, json = false } = {}) {
|
|
8
10
|
const api = `${url}/systemview/api`;
|
|
9
|
-
const Client = createCookieClient();
|
|
10
11
|
|
|
11
12
|
if (!project_code) {
|
|
12
|
-
await listAllProjects(api, Client, verbose);
|
|
13
|
+
await listAllProjects(api, Client, verbose, connectedUrls, json);
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const connectedServices = await loadServices(api, project_code,
|
|
17
|
+
const connectedServices = await loadServices(api, project_code, Client);
|
|
17
18
|
if (!connectedServices.length) {
|
|
18
19
|
log.warn("No connected services found for project: " + project_code);
|
|
19
20
|
return;
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
if (json) {
|
|
24
|
+
const output = [];
|
|
25
|
+
for (const { serviceId, system } of connectedServices) {
|
|
26
|
+
let testList = [];
|
|
27
|
+
try {
|
|
28
|
+
const svc = Client.createService(system.connectionData);
|
|
29
|
+
testList = await svc.Plugin.getTests();
|
|
30
|
+
} catch { continue; }
|
|
31
|
+
const filtered = namespace
|
|
32
|
+
? testList.filter(({ namespace: n }) =>
|
|
33
|
+
`${n.serviceId}.${n.moduleName}.${n.methodName}`.includes(namespace)
|
|
34
|
+
)
|
|
35
|
+
: testList;
|
|
36
|
+
output.push({ serviceId, tests: filtered });
|
|
37
|
+
}
|
|
38
|
+
console.log(JSON.stringify(output, null, 2));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
22
42
|
console.log("");
|
|
23
43
|
console.log(` ${chalk.bold(project_code)}`);
|
|
24
44
|
|
|
@@ -30,7 +50,7 @@ module.exports = async function listTests(url, project_code, namespace, { manife
|
|
|
30
50
|
|
|
31
51
|
let testList = [];
|
|
32
52
|
try {
|
|
33
|
-
const svc =
|
|
53
|
+
const svc = Client.createService(system.connectionData);
|
|
34
54
|
testList = await svc.Plugin.getTests();
|
|
35
55
|
} catch {
|
|
36
56
|
console.log(`${servicePrefix}${chalk.dim(serviceId)} ${chalk.dim("(could not load tests)")}`);
|
|
@@ -93,7 +113,7 @@ module.exports = async function listTests(url, project_code, namespace, { manife
|
|
|
93
113
|
console.log("");
|
|
94
114
|
};
|
|
95
115
|
|
|
96
|
-
async function listAllProjects(api, Client, verbose = false) {
|
|
116
|
+
async function listAllProjects(api, Client, verbose = false, connectedUrls = new Set(), json = false) {
|
|
97
117
|
let projects;
|
|
98
118
|
try {
|
|
99
119
|
const { SystemView } = await Client.loadService(api);
|
|
@@ -105,10 +125,13 @@ async function listAllProjects(api, Client, verbose = false) {
|
|
|
105
125
|
|
|
106
126
|
const codes = Object.keys(projects);
|
|
107
127
|
if (!codes.length) {
|
|
128
|
+
if (json) { console.log(JSON.stringify({})); return; }
|
|
108
129
|
log.warn("No connected projects found.");
|
|
109
130
|
return;
|
|
110
131
|
}
|
|
111
132
|
|
|
133
|
+
if (json) { console.log(JSON.stringify(projects, null, 2)); return; }
|
|
134
|
+
|
|
112
135
|
const total = codes.reduce((n, c) => n + projects[c].length, 0);
|
|
113
136
|
console.log("");
|
|
114
137
|
console.log(chalk.dim(` ${codes.length} ${codes.length === 1 ? "project" : "projects"}, ${total} ${total === 1 ? "service" : "services"}`));
|
|
@@ -120,9 +143,11 @@ async function listAllProjects(api, Client, verbose = false) {
|
|
|
120
143
|
const isLastService = si === services.length - 1;
|
|
121
144
|
const servicePrefix = isLastService ? " └── " : " ├── ";
|
|
122
145
|
const childPad = isLastService ? " " : " │ ";
|
|
146
|
+
const connected = connectedUrls.has(serviceUrl);
|
|
147
|
+
const connectedMark = connected ? chalk.green(" ●") : chalk.dim(" ○");
|
|
123
148
|
|
|
124
149
|
if (verbose && connectionData && connectionData.modules) {
|
|
125
|
-
console.log(`${servicePrefix}${chalk.bold(serviceId)} ${chalk.dim(serviceUrl)}`);
|
|
150
|
+
console.log(`${servicePrefix}${chalk.bold(serviceId)}${connectedMark} ${chalk.dim(serviceUrl)}`);
|
|
126
151
|
const mods = connectionData.modules.filter((m) => m.name !== "Plugin");
|
|
127
152
|
mods.forEach((mod, mi) => {
|
|
128
153
|
const isLastMod = mi === mods.length - 1;
|
|
@@ -137,7 +162,7 @@ async function listAllProjects(api, Client, verbose = false) {
|
|
|
137
162
|
});
|
|
138
163
|
});
|
|
139
164
|
} else {
|
|
140
|
-
console.log(`${servicePrefix}${serviceId} ${chalk.dim(serviceUrl)}`);
|
|
165
|
+
console.log(`${servicePrefix}${serviceId}${connectedMark} ${chalk.dim(serviceUrl)}`);
|
|
141
166
|
}
|
|
142
167
|
});
|
|
143
168
|
if (pi < codes.length - 1) console.log("");
|
|
@@ -145,14 +170,7 @@ async function listAllProjects(api, Client, verbose = false) {
|
|
|
145
170
|
console.log("");
|
|
146
171
|
}
|
|
147
172
|
|
|
148
|
-
async function loadServices(api, project_code,
|
|
149
|
-
const manifestFile = manifestPath || path.join(process.cwd(), "systemview.manifest.json");
|
|
150
|
-
if (fs.existsSync(manifestFile)) {
|
|
151
|
-
try {
|
|
152
|
-
const raw = JSON.parse(fs.readFileSync(manifestFile, "utf8"));
|
|
153
|
-
return raw.services ? raw.services : [raw];
|
|
154
|
-
} catch {}
|
|
155
|
-
}
|
|
173
|
+
async function loadServices(api, project_code, Client) {
|
|
156
174
|
try {
|
|
157
175
|
const { SystemView } = await Client.loadService(api);
|
|
158
176
|
return (await SystemView.getServices(project_code)) || [];
|