@uns-kit/cli 0.0.11 → 0.0.13
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/dist/index.js +119 -1
- package/package.json +2 -2
- package/templates/default/src/config/project.config.extension.example +2 -2
- package/templates/default/src/examples/data-example.ts +10 -12
- package/templates/default/src/examples/load-test-data.ts +6 -5
- package/templates/default/src/examples/table-example.ts +9 -10
- package/templates/default/tsconfig.json +1 -1
- package/templates/default/uns-library.json +4 -0
package/dist/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
2
3
|
import { access, cp, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { createRequire } from "node:module";
|
|
6
7
|
import process from "node:process";
|
|
7
8
|
import readline from "node:readline/promises";
|
|
9
|
+
import { promisify } from "node:util";
|
|
8
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
11
|
const __dirname = path.dirname(__filename);
|
|
10
12
|
const require = createRequire(import.meta.url);
|
|
11
13
|
const coreVersion = resolveCoreVersion();
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
12
15
|
async function main() {
|
|
13
16
|
const args = process.argv.slice(2);
|
|
14
17
|
const command = args[0];
|
|
@@ -91,7 +94,21 @@ async function configureDevops(targetPath) {
|
|
|
91
94
|
}
|
|
92
95
|
const pkg = JSON.parse(pkgRaw);
|
|
93
96
|
const config = JSON.parse(configRaw);
|
|
94
|
-
|
|
97
|
+
await ensureGitRepository(targetDir);
|
|
98
|
+
const remoteUrl = await getGitRemoteUrl(targetDir, "origin");
|
|
99
|
+
let gitRemoteMessage;
|
|
100
|
+
let ensuredRemoteUrl = remoteUrl;
|
|
101
|
+
if (!ensuredRemoteUrl) {
|
|
102
|
+
const remoteAnswer = (await promptQuestion("Azure DevOps repository URL (e.g. https://dev.azure.com/sijit/industry40/_git/my-repo): ")).trim();
|
|
103
|
+
if (!remoteAnswer) {
|
|
104
|
+
throw new Error("A repository URL is required to set the git remote origin.");
|
|
105
|
+
}
|
|
106
|
+
await addGitRemote(targetDir, "origin", remoteAnswer);
|
|
107
|
+
ensuredRemoteUrl = remoteAnswer;
|
|
108
|
+
gitRemoteMessage = ` Added git remote origin -> ${remoteAnswer}`;
|
|
109
|
+
}
|
|
110
|
+
const inferredOrganization = ensuredRemoteUrl ? inferAzureOrganization(ensuredRemoteUrl) : undefined;
|
|
111
|
+
const defaultOrg = config.devops?.organization?.trim() || inferredOrganization || "sijit";
|
|
95
112
|
const answer = (await promptQuestion(`Azure DevOps organization [${defaultOrg}]: `)).trim();
|
|
96
113
|
const organization = answer || defaultOrg;
|
|
97
114
|
if (!config.devops || typeof config.devops !== "object") {
|
|
@@ -124,6 +141,9 @@ async function configureDevops(targetPath) {
|
|
|
124
141
|
}
|
|
125
142
|
console.log(`\nDevOps tooling configured.`);
|
|
126
143
|
console.log(` Azure organization: ${organization}`);
|
|
144
|
+
if (gitRemoteMessage) {
|
|
145
|
+
console.log(gitRemoteMessage);
|
|
146
|
+
}
|
|
127
147
|
if (pkgChanged) {
|
|
128
148
|
console.log(" Updated package.json scripts/devDependencies. Run pnpm install to fetch new packages.");
|
|
129
149
|
}
|
|
@@ -131,6 +151,104 @@ async function configureDevops(targetPath) {
|
|
|
131
151
|
console.log(" Existing package.json already contained required entries.");
|
|
132
152
|
}
|
|
133
153
|
}
|
|
154
|
+
async function ensureGitRepository(dir) {
|
|
155
|
+
try {
|
|
156
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
157
|
+
cwd: dir,
|
|
158
|
+
encoding: "utf8",
|
|
159
|
+
});
|
|
160
|
+
if (stdout.trim() !== "true") {
|
|
161
|
+
throw new Error(`Directory ${dir} is not a git repository.`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
if (isGitCommandNotFoundError(error)) {
|
|
166
|
+
throw new Error("Git is required to run configure-devops but was not found in PATH.");
|
|
167
|
+
}
|
|
168
|
+
const execError = error;
|
|
169
|
+
const stderr = typeof execError.stderr === "string" ? execError.stderr : "";
|
|
170
|
+
if (stderr.includes("not a git repository")) {
|
|
171
|
+
throw new Error(`Directory ${dir} is not a git repository.`);
|
|
172
|
+
}
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async function getGitRemoteUrl(dir, remoteName) {
|
|
177
|
+
try {
|
|
178
|
+
const { stdout } = await execFileAsync("git", ["remote", "get-url", remoteName], {
|
|
179
|
+
cwd: dir,
|
|
180
|
+
encoding: "utf8",
|
|
181
|
+
});
|
|
182
|
+
return stdout.trim();
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
if (isGitCommandNotFoundError(error)) {
|
|
186
|
+
throw new Error("Git is required to run configure-devops but was not found in PATH.");
|
|
187
|
+
}
|
|
188
|
+
if (isGitRemoteMissingError(error)) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function addGitRemote(dir, remoteName, remoteUrl) {
|
|
195
|
+
try {
|
|
196
|
+
await execFileAsync("git", ["remote", "add", remoteName, remoteUrl], {
|
|
197
|
+
cwd: dir,
|
|
198
|
+
encoding: "utf8",
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
if (isGitCommandNotFoundError(error)) {
|
|
203
|
+
throw new Error("Git is required to run configure-devops but was not found in PATH.");
|
|
204
|
+
}
|
|
205
|
+
const execError = error;
|
|
206
|
+
const stderr = typeof execError.stderr === "string" ? execError.stderr.trim() : "";
|
|
207
|
+
if (stderr) {
|
|
208
|
+
throw new Error(`Failed to add git remote origin: ${stderr}`);
|
|
209
|
+
}
|
|
210
|
+
throw new Error(`Failed to add git remote origin: ${error.message}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function inferAzureOrganization(remoteUrl) {
|
|
214
|
+
try {
|
|
215
|
+
const url = new URL(remoteUrl);
|
|
216
|
+
const hostname = url.hostname.toLowerCase();
|
|
217
|
+
if (hostname === "dev.azure.com" || hostname.endsWith(".visualstudio.com")) {
|
|
218
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
219
|
+
if (segments.length >= 1) {
|
|
220
|
+
return segments[0];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
// ignore parse errors for non-HTTP(S) remotes
|
|
226
|
+
}
|
|
227
|
+
if (remoteUrl.startsWith("git@ssh.dev.azure.com:")) {
|
|
228
|
+
const [, pathPart] = remoteUrl.split(":", 2);
|
|
229
|
+
if (pathPart) {
|
|
230
|
+
const segments = pathPart.split("/").filter(Boolean);
|
|
231
|
+
// Format: v3/{organization}/{project}/{repo}
|
|
232
|
+
if (segments.length >= 2) {
|
|
233
|
+
return segments[1];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
function isGitRemoteMissingError(error) {
|
|
240
|
+
if (!error || typeof error !== "object") {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
const execError = error;
|
|
244
|
+
if (typeof execError.stderr === "string") {
|
|
245
|
+
return execError.stderr.includes("No such remote");
|
|
246
|
+
}
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
function isGitCommandNotFoundError(error) {
|
|
250
|
+
return Boolean(error && typeof error === "object" && error.code === "ENOENT");
|
|
251
|
+
}
|
|
134
252
|
async function promptQuestion(message) {
|
|
135
253
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
136
254
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uns-kit/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "Command line scaffolding tool for UNS applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"templates"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@uns-kit/core": "0.0.
|
|
28
|
+
"@uns-kit/core": "0.0.16"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"build": "tsc -p tsconfig.build.json",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { secretValueSchema } from "@uns-kit/core/
|
|
3
|
-
import { hostValueSchema } from "@uns-kit/core/
|
|
2
|
+
import { secretValueSchema } from "@uns-kit/core/uns-config/secret-placeholders.js";
|
|
3
|
+
import { hostValueSchema } from "@uns-kit/core/uns-config/host-placeholders.js";
|
|
4
4
|
|
|
5
5
|
// Extend this schema with project-specific configuration sections.
|
|
6
6
|
export const projectExtrasSchema = z.object({
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Change this file according to your specifications and rename it to index.ts
|
|
3
3
|
*/
|
|
4
|
-
import { UnsProxyProcess } from "@uns-kit/core";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { UnsPacket } from "@uns-kit/core/dist/uns/uns-packet";
|
|
10
|
-
import { UnsTags } from "@uns-kit/core/dist/uns/uns-tags";
|
|
11
|
-
import { UnsTopics } from "@uns-kit/core/dist/uns/uns-topics";
|
|
4
|
+
import { UnsProxyProcess, ConfigFile, logger, type IUnsMessage } from "@uns-kit/core";
|
|
5
|
+
import { PhysicalMeasurements } from "@uns-kit/core/uns/uns-measurements.js";
|
|
6
|
+
import { UnsPacket } from "@uns-kit/core/uns/uns-packet.js";
|
|
7
|
+
import { UnsTags } from "@uns-kit/core/uns/uns-tags.js";
|
|
8
|
+
import { UnsTopics } from "@uns-kit/core/uns/uns-topics.js";
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
11
|
* Load the configuration from a file.
|
|
@@ -21,10 +18,10 @@ const config = await ConfigFile.loadConfig();
|
|
|
21
18
|
* Connect to input and output brokers
|
|
22
19
|
*/
|
|
23
20
|
const unsProxyProcess = new UnsProxyProcess(config.infra.host!, {processName: config.uns.processName!});
|
|
24
|
-
const mqttInput = await unsProxyProcess.createUnsMqttProxy((config.input?.host)!, "templateUnsRttInput", config.uns.instanceMode
|
|
21
|
+
const mqttInput = await unsProxyProcess.createUnsMqttProxy((config.input?.host)!, "templateUnsRttInput", config.uns.instanceMode!, config.uns.handover!, {
|
|
25
22
|
mqttSubToTopics: ["raw/#"],
|
|
26
23
|
});
|
|
27
|
-
const mqttOutput = await unsProxyProcess.createUnsMqttProxy((config.output?.host)!, "templateUnsRttOutput", config.uns.instanceMode
|
|
24
|
+
const mqttOutput = await unsProxyProcess.createUnsMqttProxy((config.output?.host)!, "templateUnsRttOutput", config.uns.instanceMode!, config.uns.handover!, { publishThrottlingDelay: 1000});
|
|
28
25
|
|
|
29
26
|
|
|
30
27
|
/**
|
|
@@ -44,7 +41,8 @@ mqttInput.event.on("input", async (event) => {
|
|
|
44
41
|
mqttOutput.publishMqttMessage({ topic, attribute: "data-number", packet, description: "Number value", tags });
|
|
45
42
|
}
|
|
46
43
|
} catch (error) {
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const reason = error instanceof Error ? error : new Error(String(error));
|
|
45
|
+
logger.error(`Error publishing message to MQTT: ${reason.message}`);
|
|
46
|
+
throw reason;
|
|
49
47
|
}
|
|
50
48
|
});
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* In the development environment, you are responsible for creating and maintaining this file and its contents.
|
|
5
5
|
*/
|
|
6
6
|
import readline from "readline";
|
|
7
|
-
import { ConfigFile } from "@uns-kit/core";
|
|
8
|
-
import UnsMqttProxy from "@uns-kit/core/
|
|
9
|
-
import { logger } from "@uns-kit/core";
|
|
7
|
+
import { ConfigFile, logger } from "@uns-kit/core";
|
|
8
|
+
import UnsMqttProxy from "@uns-kit/core/uns-mqtt/uns-mqtt-proxy.js";
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
/**
|
|
@@ -54,7 +53,8 @@ async function main() {
|
|
|
54
53
|
const rawData = `${count},${currentDate.getTime()}`;
|
|
55
54
|
await mqttOutput.publishMessage("raw/data", rawData);
|
|
56
55
|
} catch (error) {
|
|
57
|
-
|
|
56
|
+
const reason = error instanceof Error ? error : new Error(String(error));
|
|
57
|
+
logger.error("Error publishing message:", reason.message);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
count++;
|
|
@@ -84,7 +84,8 @@ async function main() {
|
|
|
84
84
|
}
|
|
85
85
|
});
|
|
86
86
|
} catch (error) {
|
|
87
|
-
|
|
87
|
+
const reason = error instanceof Error ? error : new Error(String(error));
|
|
88
|
+
logger.error("Error initializing load test:", reason.message);
|
|
88
89
|
process.exit(1);
|
|
89
90
|
}
|
|
90
91
|
}
|
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
* Change this file according to your specifications and rename it to index.ts
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { UnsProxyProcess } from "@uns-kit/core";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { UnsPacket } from "@uns-kit/core/dist/uns/uns-packet";
|
|
10
|
-
import { UnsTags } from "@uns-kit/core/dist/uns/uns-tags";
|
|
11
|
-
import { UnsTopics } from "@uns-kit/core/dist/uns/uns-topics";
|
|
5
|
+
import { UnsProxyProcess, ConfigFile, logger, type IUnsMessage } from "@uns-kit/core";
|
|
6
|
+
import { UnsPacket } from "@uns-kit/core/uns/uns-packet.js";
|
|
7
|
+
import { UnsTags } from "@uns-kit/core/uns/uns-tags.js";
|
|
8
|
+
import { UnsTopics } from "@uns-kit/core/uns/uns-topics.js";
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
11
|
* Load the configuration from a file.
|
|
@@ -21,12 +18,12 @@ const config = await ConfigFile.loadConfig();
|
|
|
21
18
|
* Load and configure input and output brokers from config.json
|
|
22
19
|
*/
|
|
23
20
|
const unsProxyProcess = new UnsProxyProcess(config.infra.host!, {processName: config.uns.processName!});
|
|
24
|
-
const mqttInput = await unsProxyProcess.createUnsMqttProxy((config.input?.host)!, "templateUnsRttInput", config.uns.instanceMode
|
|
21
|
+
const mqttInput = await unsProxyProcess.createUnsMqttProxy((config.input?.host)!, "templateUnsRttInput", config.uns.instanceMode!, config.uns.handover!, {
|
|
25
22
|
mqttSubToTopics: ["iba/zrm"],
|
|
26
23
|
publishThrottlingDelay:0,
|
|
27
24
|
subscribeThrottlingDelay:0
|
|
28
25
|
});
|
|
29
|
-
const mqttOutput = await unsProxyProcess.createUnsMqttProxy((config.output?.host)!, "templateUnsRttOutput", config.uns.instanceMode
|
|
26
|
+
const mqttOutput = await unsProxyProcess.createUnsMqttProxy((config.output?.host)!, "templateUnsRttOutput", config.uns.instanceMode!, config.uns.handover!, {
|
|
30
27
|
publishThrottlingDelay:0,
|
|
31
28
|
subscribeThrottlingDelay:0
|
|
32
29
|
});
|
|
@@ -51,6 +48,8 @@ mqttInput.event.on("input", async (event) => {
|
|
|
51
48
|
mqttOutput.publishMqttMessage({ topic, attribute: "zrm", packet, description: "Table", tags });
|
|
52
49
|
}
|
|
53
50
|
} catch (error) {
|
|
54
|
-
|
|
51
|
+
const reason = error instanceof Error ? error : new Error(String(error));
|
|
52
|
+
logger.error(`Error publishing message to MQTT: ${reason.message}`);
|
|
53
|
+
throw reason;
|
|
55
54
|
}
|
|
56
55
|
});
|