@uns-kit/cli 0.0.4 → 0.0.6

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 CHANGED
@@ -24,8 +24,25 @@ pnpm run dev
24
24
  ## Commands
25
25
 
26
26
  - `uns-kit create <name>` – create a new UNS project in the specified directory.
27
+ - `uns-kit configure-devops [path]` – add Azure DevOps tooling (dependencies, script, config) to an existing project.
27
28
  - `uns-kit help` – display usage information.
28
29
 
30
+ ### Configure Azure DevOps
31
+
32
+ Run inside a scaffolded project to add the Azure DevOps pull-request tooling:
33
+
34
+ ```bash
35
+ uns-kit configure-devops
36
+ pnpm install
37
+ pnpm run pull-request
38
+ ```
39
+
40
+ The command prompts for your Azure DevOps organization and updates `config.json` along with the necessary dev dependencies.
41
+
42
+ ### Extend the Config Schema
43
+
44
+ Edit `src/config/project.config.extension.ts` inside your generated project and run `pnpm run generate-config-schema`. This regenerates `config.schema.json` and `src/config/app-config.ts` so editors and runtime types stay in sync.
45
+
29
46
  ## License
30
47
 
31
48
  MIT © Aljoša Vister
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { createRequire } from "node:module";
6
6
  import process from "node:process";
7
+ import readline from "node:readline/promises";
7
8
  const __filename = fileURLToPath(import.meta.url);
8
9
  const __dirname = path.dirname(__filename);
9
10
  const require = createRequire(import.meta.url);
@@ -15,6 +16,17 @@ async function main() {
15
16
  printHelp();
16
17
  return;
17
18
  }
19
+ if (command === "configure-devops") {
20
+ const targetPath = args[1];
21
+ try {
22
+ await configureDevops(targetPath);
23
+ }
24
+ catch (error) {
25
+ console.error(error.message);
26
+ process.exitCode = 1;
27
+ }
28
+ return;
29
+ }
18
30
  if (command === "create") {
19
31
  const projectName = args[1];
20
32
  if (!projectName) {
@@ -36,7 +48,7 @@ async function main() {
36
48
  process.exitCode = 1;
37
49
  }
38
50
  function printHelp() {
39
- console.log(`\nUsage: uns-kit <command> [options]\n\nCommands:\n create <name> Scaffold a new UNS application\n help Show this message\n`);
51
+ console.log(`\nUsage: uns-kit <command> [options]\n\nCommands:\n create <name> Scaffold a new UNS application\n configure-devops [dir] Configure Azure DevOps tooling in an existing project\n help Show this message\n`);
40
52
  }
41
53
  async function createProject(projectName) {
42
54
  const targetDir = path.resolve(process.cwd(), projectName);
@@ -53,6 +65,81 @@ async function createProject(projectName) {
53
65
  console.log(" pnpm install");
54
66
  console.log(" pnpm run dev");
55
67
  }
68
+ async function configureDevops(targetPath) {
69
+ const targetDir = path.resolve(process.cwd(), targetPath ?? ".");
70
+ const packagePath = path.join(targetDir, "package.json");
71
+ const configPath = path.join(targetDir, "config.json");
72
+ let pkgRaw;
73
+ try {
74
+ pkgRaw = await readFile(packagePath, "utf8");
75
+ }
76
+ catch (error) {
77
+ if (error.code === "ENOENT") {
78
+ throw new Error(`Could not find package.json in ${targetDir}`);
79
+ }
80
+ throw error;
81
+ }
82
+ let configRaw;
83
+ try {
84
+ configRaw = await readFile(configPath, "utf8");
85
+ }
86
+ catch (error) {
87
+ if (error.code === "ENOENT") {
88
+ throw new Error(`Could not find config.json in ${targetDir}`);
89
+ }
90
+ throw error;
91
+ }
92
+ const pkg = JSON.parse(pkgRaw);
93
+ const config = JSON.parse(configRaw);
94
+ const defaultOrg = config.devops?.organization ?? "sijit";
95
+ const answer = (await promptQuestion(`Azure DevOps organization [${defaultOrg}]: `)).trim();
96
+ const organization = answer || defaultOrg;
97
+ if (!config.devops || typeof config.devops !== "object") {
98
+ config.devops = {};
99
+ }
100
+ config.devops.organization = organization;
101
+ const requiredDevDeps = {
102
+ "azure-devops-node-api": "^15.1.0",
103
+ "simple-git": "^3.27.0",
104
+ "chalk": "^5.4.1",
105
+ "prettier": "^3.5.3"
106
+ };
107
+ let pkgChanged = false;
108
+ const devDeps = (pkg.devDependencies ??= {});
109
+ const deps = pkg.dependencies ?? {};
110
+ for (const [name, version] of Object.entries(requiredDevDeps)) {
111
+ if (!devDeps[name] && !deps[name]) {
112
+ devDeps[name] = version;
113
+ pkgChanged = true;
114
+ }
115
+ }
116
+ const scripts = (pkg.scripts ??= {});
117
+ if (!scripts["pull-request"]) {
118
+ scripts["pull-request"] = "node ./node_modules/@uns-kit/core/dist/tools/pull-request.js";
119
+ pkgChanged = true;
120
+ }
121
+ await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
122
+ if (pkgChanged) {
123
+ await writeFile(packagePath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
124
+ }
125
+ console.log(`\nDevOps tooling configured.`);
126
+ console.log(` Azure organization: ${organization}`);
127
+ if (pkgChanged) {
128
+ console.log(" Updated package.json scripts/devDependencies. Run pnpm install to fetch new packages.");
129
+ }
130
+ else {
131
+ console.log(" Existing package.json already contained required entries.");
132
+ }
133
+ }
134
+ async function promptQuestion(message) {
135
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
136
+ try {
137
+ return await rl.question(message);
138
+ }
139
+ finally {
140
+ rl.close();
141
+ }
142
+ }
56
143
  async function ensureTargetDir(dir) {
57
144
  try {
58
145
  const stats = await stat(dir);
@@ -84,12 +171,20 @@ async function patchPackageJson(targetDir, packageName) {
84
171
  }
85
172
  async function patchConfigJson(targetDir, packageName) {
86
173
  const configFile = path.join(targetDir, "config.json");
87
- const raw = await readFile(configFile, "utf8");
88
- const config = JSON.parse(raw);
89
- if (config.uns && typeof config.uns === "object") {
90
- config.uns.processName = packageName;
174
+ try {
175
+ const raw = await readFile(configFile, "utf8");
176
+ const config = JSON.parse(raw);
177
+ if (config.uns && typeof config.uns === "object") {
178
+ config.uns.processName = packageName;
179
+ }
180
+ await writeFile(configFile, JSON.stringify(config, null, 2) + "\n", "utf8");
181
+ }
182
+ catch (error) {
183
+ if (error.code === "ENOENT") {
184
+ return;
185
+ }
186
+ throw error;
91
187
  }
92
- await writeFile(configFile, JSON.stringify(config, null, 2) + "\n", "utf8");
93
188
  }
94
189
  async function replacePlaceholders(targetDir, packageName) {
95
190
  const replacements = {
@@ -97,7 +192,8 @@ async function replacePlaceholders(targetDir, packageName) {
97
192
  };
98
193
  const filesToUpdate = [
99
194
  path.join(targetDir, "README.md"),
100
- path.join(targetDir, "src/index.ts")
195
+ path.join(targetDir, "src/index.ts"),
196
+ path.join(targetDir, "config.json")
101
197
  ];
102
198
  for (const file of filesToUpdate) {
103
199
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uns-kit/cli",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
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.1"
28
+ "@uns-kit/core": "^0.0.4"
29
29
  },
30
30
  "scripts": {
31
31
  "build": "tsc -p tsconfig.build.json",
@@ -8,6 +8,7 @@ Generated with `@uns-kit/cli`.
8
8
  pnpm run dev # start the local development loop
9
9
  pnpm run build # emit dist/ output
10
10
  pnpm run start # run the compiled entrypoint
11
+ pnpm run generate-config-schema # regenerate config.schema.json and AppConfig types
11
12
  ```
12
13
 
13
14
  ## Configuration
@@ -18,4 +19,6 @@ Update `config.json` with your broker, UNS URLs, and credentials. The generated
18
19
 
19
20
  - Install additional plugins: `pnpm add @uns-kit/api` etc.
20
21
  - Create MQTT proxies or Temporal workflows inside `src/index.ts`.
22
+ - Extend `src/config/project.config.extension.ts` with project-specific sections and run `pnpm run generate-config-schema`.
23
+ - Run `uns-kit configure-devops` to add the Azure DevOps pull-request tooling.
21
24
  - Commit your new project and start building!
@@ -16,5 +16,8 @@
16
16
  },
17
17
  "input": {
18
18
  "host": "localhost:1883"
19
+ },
20
+ "devops": {
21
+ "organization": "sijit"
19
22
  }
20
23
  }
@@ -10,7 +10,8 @@
10
10
  "generate-config-schema": "node ./node_modules/@uns-kit/core/dist/tools/generate-config-schema.js"
11
11
  },
12
12
  "dependencies": {
13
- "@uns-kit/core": "__UNS_KIT_CORE_VERSION__"
13
+ "@uns-kit/core": "__UNS_KIT_CORE_VERSION__",
14
+ "zod": "^3.23.8"
14
15
  },
15
16
  "devDependencies": {
16
17
  "tsx": "^4.20.5",
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import { secretValueSchema } from "@uns-kit/core/dist/uns-config/secret-placeholders";
3
+ import { hostValueSchema } from "@uns-kit/core/dist/uns-config/host-placeholders";
4
+
5
+ // Extend this schema with project-specific configuration sections.
6
+ export const projectExtrasSchema = z.object({
7
+ pg: z.object({
8
+ user: z.string().min(1, "pg.user is required"),
9
+ host: hostValueSchema,
10
+ port: z.number().int().positive().default(5432),
11
+ ssl: z.boolean().default(false),
12
+ database: z.string().min(1, "pg.database is required"),
13
+ isPoolConnection: z.boolean().default(false),
14
+ password: secretValueSchema.optional(),
15
+ }),
16
+
17
+ caddy: z.object({
18
+ adminUrl: z.string().url(),
19
+ proxyHost: z.string().url(),
20
+ }),
21
+ });
22
+
23
+ export type ProjectExtras = z.infer<typeof projectExtrasSchema>;
@@ -0,0 +1,6 @@
1
+ import { z } from "zod";
2
+
3
+ // Extend this schema with project-specific configuration sections.
4
+ export const projectExtrasSchema = z.object({});
5
+
6
+ export type ProjectExtras = z.infer<typeof projectExtrasSchema>;