systemview 2.0.0 → 2.1.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 +41 -47
- package/build/asset-manifest.json +6 -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/{main.72103448.js → main.e9f9f4f8.js} +3 -3
- package/build/static/js/main.e9f9f4f8.js.map +1 -0
- package/cli/connectService.js +143 -52
- package/cli/index.js +80 -45
- package/cli/launchApp.js +8 -5
- package/cli/listTests.js +31 -16
- package/cli/logs.js +286 -93
- package/cli/manifest.js +97 -0
- package/cli/openBrowser.js +1 -1
- package/cli/probe.js +30 -18
- package/cli/runTests.js +30 -36
- package/cli/startLineReader.js +140 -15
- package/cli/utils/cli.js +64 -17
- package/package.json +1 -1
- package/build/static/css/main.ff3d0549.css +0 -15
- package/build/static/css/main.ff3d0549.css.map +0 -1
- package/build/static/js/main.72103448.js.map +0 -1
- /package/build/static/js/{main.72103448.js.LICENSE.txt → main.e9f9f4f8.js.LICENSE.txt} +0 -0
package/cli/connectService.js
CHANGED
|
@@ -1,81 +1,172 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
1
|
const { HttpClient, createClient } = require("systemlynx");
|
|
4
2
|
const { createCookieHttpClient } = require("./cookieClient");
|
|
5
3
|
const cookieHttpClient = createCookieHttpClient();
|
|
6
4
|
const Client = createClient(cookieHttpClient);
|
|
7
5
|
const log = require("./logger");
|
|
8
6
|
|
|
9
|
-
async function
|
|
10
|
-
const connectionData = await HttpClient.request({ url });
|
|
11
|
-
if (!connectionData.SystemLynxService) {
|
|
12
|
-
throw new Error(`No SystemLynx service found at ${url}`);
|
|
13
|
-
}
|
|
14
|
-
const client = Client.createService(connectionData);
|
|
15
|
-
const connection = await client.Plugin.getConnection();
|
|
16
|
-
return connection; // { projectCode, serviceId, system, specList }
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function readManifest(manifestFile) {
|
|
20
|
-
if (!fs.existsSync(manifestFile)) return null;
|
|
7
|
+
async function getUiSvc(uiUrl) {
|
|
21
8
|
try {
|
|
22
|
-
|
|
9
|
+
const { SystemView } = await Client.loadService(`${uiUrl}/systemview/api`);
|
|
10
|
+
return SystemView;
|
|
23
11
|
} catch {
|
|
24
12
|
return null;
|
|
25
13
|
}
|
|
26
14
|
}
|
|
27
15
|
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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";
|
|
37
26
|
}
|
|
38
27
|
|
|
39
|
-
|
|
40
|
-
|
|
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
|
+
}
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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>");
|
|
47
51
|
return;
|
|
48
52
|
}
|
|
49
|
-
log.info(`
|
|
50
|
-
|
|
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;
|
|
51
58
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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 });
|
|
55
67
|
} catch (err) {
|
|
56
|
-
log.error(`${
|
|
68
|
+
log.error(`${serviceId} failed: ${err.message}`);
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
|
-
|
|
71
|
+
printSummary(summary);
|
|
60
72
|
return;
|
|
61
73
|
}
|
|
62
74
|
|
|
63
|
-
|
|
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}...`);
|
|
64
111
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
+
}
|
|
68
169
|
} catch (err) {
|
|
69
170
|
log.error(`Connection failed: ${err.message}`);
|
|
70
171
|
}
|
|
71
172
|
};
|
|
72
|
-
|
|
73
|
-
function printManifestSummary(manifest) {
|
|
74
|
-
if (!manifest) return;
|
|
75
|
-
log.plain(`\n Project: ${manifest.projectCode}`);
|
|
76
|
-
log.plain(` Services:`);
|
|
77
|
-
(manifest.services || []).forEach(({ serviceId, system }) => {
|
|
78
|
-
log.plain(` - ${serviceId} @ ${system.connectionData.serviceUrl}`);
|
|
79
|
-
});
|
|
80
|
-
log.plain("");
|
|
81
|
-
}
|
package/cli/index.js
CHANGED
|
@@ -13,20 +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
18
|
const logsCommand = require("./logs");
|
|
18
|
-
const {
|
|
19
|
+
const { createClient } = require("systemlynx");
|
|
19
20
|
const { createCookieHttpClient } = require("./cookieClient");
|
|
20
21
|
const cookieHttpClient = createCookieHttpClient();
|
|
21
22
|
const Client = createClient(cookieHttpClient);
|
|
22
23
|
|
|
23
24
|
const DEFAULT_PORT = 3000;
|
|
24
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
|
+
}
|
|
25
44
|
|
|
26
45
|
async function startApp() {
|
|
27
46
|
const port = isNaN(input[1]) ? DEFAULT_PORT : Number(input[1]);
|
|
28
47
|
try {
|
|
29
|
-
await launchApp(port, { interactive: true });
|
|
48
|
+
await launchApp(port, { interactive: true, connectedUrls, client: Client });
|
|
30
49
|
} catch (error) {
|
|
31
50
|
log.error("Launch failed: " + error.message);
|
|
32
51
|
}
|
|
@@ -35,13 +54,11 @@ async function startApp() {
|
|
|
35
54
|
async function startTest() {
|
|
36
55
|
const project_code = input[1];
|
|
37
56
|
const namespace = input[2];
|
|
38
|
-
const url = `http://localhost:${DEFAULT_PORT}`;
|
|
39
57
|
try {
|
|
40
58
|
await launchApp(DEFAULT_PORT);
|
|
41
|
-
const exitCode = await runTests(
|
|
59
|
+
const exitCode = await runTests(UI_URL, project_code, namespace, {
|
|
42
60
|
json: flags.json,
|
|
43
61
|
verbose: flags.verbose,
|
|
44
|
-
manifest: flags.manifest,
|
|
45
62
|
headers: flags.headers,
|
|
46
63
|
bail: flags.bail,
|
|
47
64
|
dryRun: flags.dryRun,
|
|
@@ -59,41 +76,35 @@ async function startTest() {
|
|
|
59
76
|
async function list() {
|
|
60
77
|
const project_code = input[1];
|
|
61
78
|
const namespace = input[2];
|
|
62
|
-
const
|
|
63
|
-
const api = `${url}/systemview/api`;
|
|
79
|
+
const api = `${UI_URL}/systemview/api`;
|
|
64
80
|
if (!(await appIsRunning(api))) {
|
|
65
81
|
await launchApp(DEFAULT_PORT);
|
|
66
82
|
}
|
|
67
|
-
await listTests(
|
|
83
|
+
await listTests(UI_URL, project_code, namespace, {
|
|
84
|
+
connectedUrls,
|
|
85
|
+
verbose: flags.verbose,
|
|
86
|
+
json: flags.json,
|
|
87
|
+
});
|
|
68
88
|
process.exit(0);
|
|
69
89
|
}
|
|
70
90
|
|
|
71
91
|
async function open() {
|
|
72
92
|
const project_code = input[1];
|
|
73
93
|
const namespace = input[2];
|
|
74
|
-
const
|
|
75
|
-
const api = `${ui}/systemview/api`;
|
|
94
|
+
const api = `${UI_URL}/systemview/api`;
|
|
76
95
|
if (!(await appIsRunning(api))) {
|
|
77
96
|
await launchApp(DEFAULT_PORT);
|
|
78
97
|
}
|
|
79
98
|
|
|
80
99
|
let connectedServices = [];
|
|
81
100
|
if (namespace && project_code) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
connectedServices = raw.services ? raw.services : [raw];
|
|
87
|
-
} catch {}
|
|
88
|
-
} else {
|
|
89
|
-
try {
|
|
90
|
-
const { SystemView } = await Client.loadService(api);
|
|
91
|
-
connectedServices = (await SystemView.getServices(project_code)) || [];
|
|
92
|
-
} catch {}
|
|
93
|
-
}
|
|
101
|
+
try {
|
|
102
|
+
const { SystemView } = await Client.loadService(api);
|
|
103
|
+
connectedServices = (await SystemView.getServices(project_code)) || [];
|
|
104
|
+
} catch {}
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
openBrowser(
|
|
107
|
+
openBrowser(UI_URL, project_code, namespace, connectedServices);
|
|
97
108
|
process.exit(0);
|
|
98
109
|
}
|
|
99
110
|
|
|
@@ -103,24 +114,20 @@ async function quitApp() {
|
|
|
103
114
|
|
|
104
115
|
if (await appIsRunning(api)) {
|
|
105
116
|
log.info("Attempting remote shutdown...");
|
|
106
|
-
const url = `${api}/SystemView/shutdown`;
|
|
107
117
|
try {
|
|
108
|
-
|
|
118
|
+
const { SystemView } = await Client.loadService(api);
|
|
119
|
+
await SystemView.shutdown();
|
|
120
|
+
} catch {}
|
|
121
|
+
if (!(await appIsRunning(api))) {
|
|
109
122
|
log.success("SystemView shutdown successful!");
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
log.success("SystemView shutdown successful!");
|
|
114
|
-
process.exit(0);
|
|
115
|
-
} else {
|
|
116
|
-
log.error("Remote shutdown failed!");
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
123
|
+
} else {
|
|
124
|
+
log.error("Remote shutdown failed!");
|
|
125
|
+
process.exit(1);
|
|
119
126
|
}
|
|
120
127
|
} else {
|
|
121
128
|
log.warn(`No SystemView instance found @ ${api}`);
|
|
122
|
-
process.exit(0);
|
|
123
129
|
}
|
|
130
|
+
process.exit(0);
|
|
124
131
|
}
|
|
125
132
|
|
|
126
133
|
(async () => {
|
|
@@ -130,6 +137,8 @@ async function quitApp() {
|
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
init();
|
|
140
|
+
loadManifest();
|
|
141
|
+
|
|
133
142
|
const command = input[0];
|
|
134
143
|
|
|
135
144
|
if (command === "open") {
|
|
@@ -143,32 +152,58 @@ async function quitApp() {
|
|
|
143
152
|
} else if (["exit", "q", "shutdown", "stop"].includes(command)) {
|
|
144
153
|
await quitApp();
|
|
145
154
|
} else if (command === "connect") {
|
|
146
|
-
|
|
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
|
+
}
|
|
147
178
|
process.exit(0);
|
|
148
179
|
} else if (command === "probe") {
|
|
180
|
+
await launchApp(DEFAULT_PORT);
|
|
149
181
|
const exitCode = await probe(input[1], input[2], {
|
|
150
182
|
json: flags.json,
|
|
151
183
|
manifest: flags.manifest,
|
|
152
184
|
headers: flags.headers,
|
|
185
|
+
uiUrl: UI_URL,
|
|
153
186
|
});
|
|
154
187
|
process.exit(exitCode || 0);
|
|
155
|
-
} else if (command === "logs") {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
await launchApp(DEFAULT_PORT);
|
|
160
|
-
}
|
|
161
|
-
await logsCommand(url, input[1], input[2], {
|
|
188
|
+
} else if (command === "logs" || command === "log") {
|
|
189
|
+
await launchApp(DEFAULT_PORT);
|
|
190
|
+
await logsCommand(input[1], input[2], {
|
|
191
|
+
uiUrl: UI_URL,
|
|
162
192
|
level: flags.level,
|
|
163
193
|
limit: flags.limit,
|
|
164
194
|
clear: flags.clear,
|
|
165
195
|
json: flags.json,
|
|
166
|
-
|
|
196
|
+
current: flags.current,
|
|
197
|
+
follow: flags.follow,
|
|
167
198
|
verbose: flags.verbose,
|
|
168
199
|
filter: flags.filter,
|
|
169
200
|
or: flags.or,
|
|
201
|
+
include: flags.include,
|
|
202
|
+
save: flags.save,
|
|
203
|
+
saved: flags.saved,
|
|
204
|
+
saveLimit: flags.saveLimit,
|
|
170
205
|
});
|
|
171
|
-
process.exit(0);
|
|
206
|
+
if (!flags.follow) process.exit(0);
|
|
172
207
|
} else {
|
|
173
208
|
await startApp();
|
|
174
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,18 +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();
|
|
20
|
-
|
|
21
|
+
await listTests(ui, null, null, { connectedUrls });
|
|
22
|
+
return startLineReader(ui, { connectedUrls });
|
|
21
23
|
}
|
|
22
24
|
return;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
if (interactive) log.info(
|
|
27
|
+
if (interactive) log.info(`Launching on port ${port}...`);
|
|
26
28
|
await launchSystemView(port);
|
|
27
29
|
logConnection();
|
|
28
30
|
|
|
29
31
|
if (interactive) {
|
|
30
|
-
|
|
32
|
+
await listTests(ui, null, null, { connectedUrls });
|
|
33
|
+
return startLineReader(ui, { connectedUrls });
|
|
31
34
|
}
|
|
32
35
|
};
|
package/cli/listTests.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
1
|
const { createClient } = require("systemlynx");
|
|
4
2
|
const { createCookieHttpClient } = require("./cookieClient");
|
|
5
3
|
const log = require("./logger");
|
|
@@ -8,20 +6,39 @@ const chalk = require("chalk");
|
|
|
8
6
|
const cookieHttpClient = createCookieHttpClient();
|
|
9
7
|
const Client = createClient(cookieHttpClient);
|
|
10
8
|
|
|
11
|
-
module.exports = async function listTests(url, project_code, namespace, {
|
|
9
|
+
module.exports = async function listTests(url, project_code, namespace, { connectedUrls = new Set(), verbose = false, json = false } = {}) {
|
|
12
10
|
const api = `${url}/systemview/api`;
|
|
13
11
|
|
|
14
12
|
if (!project_code) {
|
|
15
|
-
await listAllProjects(api, Client, verbose);
|
|
13
|
+
await listAllProjects(api, Client, verbose, connectedUrls, json);
|
|
16
14
|
return;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
const connectedServices = await loadServices(api, project_code,
|
|
17
|
+
const connectedServices = await loadServices(api, project_code, Client);
|
|
20
18
|
if (!connectedServices.length) {
|
|
21
19
|
log.warn("No connected services found for project: " + project_code);
|
|
22
20
|
return;
|
|
23
21
|
}
|
|
24
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
|
+
|
|
25
42
|
console.log("");
|
|
26
43
|
console.log(` ${chalk.bold(project_code)}`);
|
|
27
44
|
|
|
@@ -96,7 +113,7 @@ module.exports = async function listTests(url, project_code, namespace, { manife
|
|
|
96
113
|
console.log("");
|
|
97
114
|
};
|
|
98
115
|
|
|
99
|
-
async function listAllProjects(api, Client, verbose = false) {
|
|
116
|
+
async function listAllProjects(api, Client, verbose = false, connectedUrls = new Set(), json = false) {
|
|
100
117
|
let projects;
|
|
101
118
|
try {
|
|
102
119
|
const { SystemView } = await Client.loadService(api);
|
|
@@ -108,10 +125,13 @@ async function listAllProjects(api, Client, verbose = false) {
|
|
|
108
125
|
|
|
109
126
|
const codes = Object.keys(projects);
|
|
110
127
|
if (!codes.length) {
|
|
128
|
+
if (json) { console.log(JSON.stringify({})); return; }
|
|
111
129
|
log.warn("No connected projects found.");
|
|
112
130
|
return;
|
|
113
131
|
}
|
|
114
132
|
|
|
133
|
+
if (json) { console.log(JSON.stringify(projects, null, 2)); return; }
|
|
134
|
+
|
|
115
135
|
const total = codes.reduce((n, c) => n + projects[c].length, 0);
|
|
116
136
|
console.log("");
|
|
117
137
|
console.log(chalk.dim(` ${codes.length} ${codes.length === 1 ? "project" : "projects"}, ${total} ${total === 1 ? "service" : "services"}`));
|
|
@@ -123,9 +143,11 @@ async function listAllProjects(api, Client, verbose = false) {
|
|
|
123
143
|
const isLastService = si === services.length - 1;
|
|
124
144
|
const servicePrefix = isLastService ? " └── " : " ├── ";
|
|
125
145
|
const childPad = isLastService ? " " : " │ ";
|
|
146
|
+
const connected = connectedUrls.has(serviceUrl);
|
|
147
|
+
const connectedMark = connected ? chalk.green(" ●") : chalk.dim(" ○");
|
|
126
148
|
|
|
127
149
|
if (verbose && connectionData && connectionData.modules) {
|
|
128
|
-
console.log(`${servicePrefix}${chalk.bold(serviceId)} ${chalk.dim(serviceUrl)}`);
|
|
150
|
+
console.log(`${servicePrefix}${chalk.bold(serviceId)}${connectedMark} ${chalk.dim(serviceUrl)}`);
|
|
129
151
|
const mods = connectionData.modules.filter((m) => m.name !== "Plugin");
|
|
130
152
|
mods.forEach((mod, mi) => {
|
|
131
153
|
const isLastMod = mi === mods.length - 1;
|
|
@@ -140,7 +162,7 @@ async function listAllProjects(api, Client, verbose = false) {
|
|
|
140
162
|
});
|
|
141
163
|
});
|
|
142
164
|
} else {
|
|
143
|
-
console.log(`${servicePrefix}${serviceId} ${chalk.dim(serviceUrl)}`);
|
|
165
|
+
console.log(`${servicePrefix}${serviceId}${connectedMark} ${chalk.dim(serviceUrl)}`);
|
|
144
166
|
}
|
|
145
167
|
});
|
|
146
168
|
if (pi < codes.length - 1) console.log("");
|
|
@@ -148,14 +170,7 @@ async function listAllProjects(api, Client, verbose = false) {
|
|
|
148
170
|
console.log("");
|
|
149
171
|
}
|
|
150
172
|
|
|
151
|
-
async function loadServices(api, project_code,
|
|
152
|
-
const manifestFile = manifestPath || path.join(process.cwd(), "systemview.manifest.json");
|
|
153
|
-
if (fs.existsSync(manifestFile)) {
|
|
154
|
-
try {
|
|
155
|
-
const raw = JSON.parse(fs.readFileSync(manifestFile, "utf8"));
|
|
156
|
-
return raw.services ? raw.services : [raw];
|
|
157
|
-
} catch {}
|
|
158
|
-
}
|
|
173
|
+
async function loadServices(api, project_code, Client) {
|
|
159
174
|
try {
|
|
160
175
|
const { SystemView } = await Client.loadService(api);
|
|
161
176
|
return (await SystemView.getServices(project_code)) || [];
|