@kntic/kntic 0.3.0 → 0.4.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/package.json +1 -1
- package/src/commands/start.js +34 -2
- package/src/commands/start.test.js +72 -0
- package/src/commands/update.js +33 -0
- package/src/commands/update.test.js +58 -1
package/package.json
CHANGED
package/src/commands/start.js
CHANGED
|
@@ -1,10 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const { execSync } = require("child_process");
|
|
4
|
+
const { readFileSync } = require("fs");
|
|
5
|
+
const { basename } = require("path");
|
|
6
|
+
|
|
7
|
+
function isScreenAvailable() {
|
|
8
|
+
try {
|
|
9
|
+
execSync("which screen", { stdio: "ignore" });
|
|
10
|
+
return true;
|
|
11
|
+
} catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getScreenName() {
|
|
17
|
+
try {
|
|
18
|
+
const content = readFileSync(".kntic.env", "utf8");
|
|
19
|
+
const match = content.match(/^KNTIC_PRJ_PREFIX=(.+)$/m);
|
|
20
|
+
if (match && match[1].trim()) {
|
|
21
|
+
return match[1].trim();
|
|
22
|
+
}
|
|
23
|
+
} catch {
|
|
24
|
+
// .kntic.env not found or unreadable — fall through
|
|
25
|
+
}
|
|
26
|
+
return basename(process.cwd());
|
|
27
|
+
}
|
|
4
28
|
|
|
5
29
|
function start() {
|
|
6
|
-
|
|
7
|
-
|
|
30
|
+
const composeCmd = "docker compose -f kntic.yml --env-file .kntic.env up --build";
|
|
31
|
+
|
|
32
|
+
if (isScreenAvailable()) {
|
|
33
|
+
const screenName = getScreenName();
|
|
34
|
+
console.log(`Starting KNTIC services in screen session "${screenName}"…`);
|
|
35
|
+
execSync(`screen -S ${screenName} ${composeCmd}`, { stdio: "inherit" });
|
|
36
|
+
} else {
|
|
37
|
+
console.log("Starting KNTIC services…");
|
|
38
|
+
execSync(composeCmd, { stdio: "inherit" });
|
|
39
|
+
}
|
|
8
40
|
}
|
|
9
41
|
|
|
10
42
|
module.exports = start;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { describe, it, beforeEach, afterEach } = require("node:test");
|
|
4
|
+
const assert = require("node:assert/strict");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const os = require("os");
|
|
8
|
+
|
|
9
|
+
// We test the helper logic by requiring the module and inspecting behaviour.
|
|
10
|
+
// Since start.js uses execSync (side-effecting), we test the screen-name
|
|
11
|
+
// resolution logic and the screen-detection path indirectly.
|
|
12
|
+
|
|
13
|
+
describe("start — getScreenName resolution", () => {
|
|
14
|
+
let tmpDir, origCwd;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "kntic-start-test-"));
|
|
18
|
+
origCwd = process.cwd();
|
|
19
|
+
process.chdir(tmpDir);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
process.chdir(origCwd);
|
|
24
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("uses KNTIC_PRJ_PREFIX from .kntic.env when present", () => {
|
|
28
|
+
fs.writeFileSync(path.join(tmpDir, ".kntic.env"), "UID=1000\nKNTIC_PRJ_PREFIX=myproject\nGID=1000\n");
|
|
29
|
+
// Re-require to get fresh module (clear cache)
|
|
30
|
+
delete require.cache[require.resolve("./start")];
|
|
31
|
+
// We can't call start() directly (it execs docker), so we extract getScreenName
|
|
32
|
+
// by reading the source and evaluating the helper in isolation.
|
|
33
|
+
const src = fs.readFileSync(require.resolve("./start"), "utf8");
|
|
34
|
+
const getScreenName = new Function("require", "process",
|
|
35
|
+
src.replace(/^"use strict";\s*/, "")
|
|
36
|
+
.replace(/module\.exports\s*=\s*start;/, "return getScreenName;")
|
|
37
|
+
)(require, process);
|
|
38
|
+
assert.equal(getScreenName(), "myproject");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("falls back to current directory name when KNTIC_PRJ_PREFIX is missing", () => {
|
|
42
|
+
fs.writeFileSync(path.join(tmpDir, ".kntic.env"), "UID=1000\nGID=1000\n");
|
|
43
|
+
delete require.cache[require.resolve("./start")];
|
|
44
|
+
const src = fs.readFileSync(require.resolve("./start"), "utf8");
|
|
45
|
+
const getScreenName = new Function("require", "process",
|
|
46
|
+
src.replace(/^"use strict";\s*/, "")
|
|
47
|
+
.replace(/module\.exports\s*=\s*start;/, "return getScreenName;")
|
|
48
|
+
)(require, process);
|
|
49
|
+
assert.equal(getScreenName(), path.basename(tmpDir));
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("falls back to current directory name when .kntic.env does not exist", () => {
|
|
53
|
+
delete require.cache[require.resolve("./start")];
|
|
54
|
+
const src = fs.readFileSync(require.resolve("./start"), "utf8");
|
|
55
|
+
const getScreenName = new Function("require", "process",
|
|
56
|
+
src.replace(/^"use strict";\s*/, "")
|
|
57
|
+
.replace(/module\.exports\s*=\s*start;/, "return getScreenName;")
|
|
58
|
+
)(require, process);
|
|
59
|
+
assert.equal(getScreenName(), path.basename(tmpDir));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("ignores empty KNTIC_PRJ_PREFIX value", () => {
|
|
63
|
+
fs.writeFileSync(path.join(tmpDir, ".kntic.env"), "KNTIC_PRJ_PREFIX=\nUID=1000\n");
|
|
64
|
+
delete require.cache[require.resolve("./start")];
|
|
65
|
+
const src = fs.readFileSync(require.resolve("./start"), "utf8");
|
|
66
|
+
const getScreenName = new Function("require", "process",
|
|
67
|
+
src.replace(/^"use strict";\s*/, "")
|
|
68
|
+
.replace(/module\.exports\s*=\s*start;/, "return getScreenName;")
|
|
69
|
+
)(require, process);
|
|
70
|
+
assert.equal(getScreenName(), path.basename(tmpDir));
|
|
71
|
+
});
|
|
72
|
+
});
|
package/src/commands/update.js
CHANGED
|
@@ -109,6 +109,35 @@ function extractVersion(artifactFilename) {
|
|
|
109
109
|
return match[1];
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Update or create the KNTIC_VERSION variable in a .kntic.env file.
|
|
114
|
+
* If the file exists and contains a KNTIC_VERSION line, that line is replaced.
|
|
115
|
+
* If the file exists but has no KNTIC_VERSION, it is appended.
|
|
116
|
+
* If the file does not exist, it is created with the variable.
|
|
117
|
+
*
|
|
118
|
+
* @param {string} version – semantic version string (e.g. "0.0.10")
|
|
119
|
+
* @param {string} envPath – path to .kntic.env (default: ".kntic.env")
|
|
120
|
+
*/
|
|
121
|
+
function updateEnvVersion(version, envPath = ".kntic.env") {
|
|
122
|
+
const line = `KNTIC_VERSION=${version}`;
|
|
123
|
+
|
|
124
|
+
if (!fs.existsSync(envPath)) {
|
|
125
|
+
fs.writeFileSync(envPath, line + "\n");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const content = fs.readFileSync(envPath, "utf8");
|
|
130
|
+
const regex = /^KNTIC_VERSION=.*$/m;
|
|
131
|
+
|
|
132
|
+
if (regex.test(content)) {
|
|
133
|
+
const updated = content.replace(regex, line);
|
|
134
|
+
fs.writeFileSync(envPath, updated);
|
|
135
|
+
} else {
|
|
136
|
+
const separator = content.endsWith("\n") ? "" : "\n";
|
|
137
|
+
fs.writeFileSync(envPath, content + separator + line + "\n");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
112
141
|
/**
|
|
113
142
|
* Recursively remove all contents of a directory (but not the directory itself).
|
|
114
143
|
*/
|
|
@@ -166,6 +195,9 @@ async function update() {
|
|
|
166
195
|
console.log("Updating .kntic/lib …");
|
|
167
196
|
extractLibOnly(tmpFile, ".");
|
|
168
197
|
|
|
198
|
+
// Update KNTIC_VERSION in .kntic.env
|
|
199
|
+
updateEnvVersion(version);
|
|
200
|
+
|
|
169
201
|
// Clean up
|
|
170
202
|
fs.unlinkSync(tmpFile);
|
|
171
203
|
|
|
@@ -177,3 +209,4 @@ module.exports = update;
|
|
|
177
209
|
module.exports.extractLibOnly = extractLibOnly;
|
|
178
210
|
module.exports.extractVersion = extractVersion;
|
|
179
211
|
module.exports.clearDirectory = clearDirectory;
|
|
212
|
+
module.exports.updateEnvVersion = updateEnvVersion;
|
|
@@ -7,7 +7,7 @@ const path = require("path");
|
|
|
7
7
|
const os = require("os");
|
|
8
8
|
const { execSync } = require("child_process");
|
|
9
9
|
|
|
10
|
-
const { extractLibOnly, extractVersion, clearDirectory } = require("./update");
|
|
10
|
+
const { extractLibOnly, extractVersion, clearDirectory, updateEnvVersion } = require("./update");
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Helper — create a tar.gz archive in `tmpDir` containing the given files.
|
|
@@ -202,6 +202,63 @@ describe("extractLibOnly", () => {
|
|
|
202
202
|
});
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
+
describe("updateEnvVersion", () => {
|
|
206
|
+
let tmpDir;
|
|
207
|
+
|
|
208
|
+
beforeEach(() => {
|
|
209
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "kntic-test-env-"));
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
afterEach(() => {
|
|
213
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("creates the file with KNTIC_VERSION if it does not exist", () => {
|
|
217
|
+
const envPath = path.join(tmpDir, ".kntic.env");
|
|
218
|
+
updateEnvVersion("1.2.3", envPath);
|
|
219
|
+
|
|
220
|
+
assert.equal(fs.readFileSync(envPath, "utf8"), "KNTIC_VERSION=1.2.3\n");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it("appends KNTIC_VERSION if file exists but variable is missing", () => {
|
|
224
|
+
const envPath = path.join(tmpDir, ".kntic.env");
|
|
225
|
+
fs.writeFileSync(envPath, "UID=1000\nGID=1000\n");
|
|
226
|
+
|
|
227
|
+
updateEnvVersion("0.0.10", envPath);
|
|
228
|
+
|
|
229
|
+
const content = fs.readFileSync(envPath, "utf8");
|
|
230
|
+
assert.ok(content.includes("UID=1000"), "existing content must be preserved");
|
|
231
|
+
assert.ok(content.includes("GID=1000"), "existing content must be preserved");
|
|
232
|
+
assert.ok(content.includes("KNTIC_VERSION=0.0.10"), "version must be appended");
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("replaces existing KNTIC_VERSION in-place", () => {
|
|
236
|
+
const envPath = path.join(tmpDir, ".kntic.env");
|
|
237
|
+
fs.writeFileSync(envPath, "UID=1000\nKNTIC_VERSION=0.0.1\nGID=1000\n");
|
|
238
|
+
|
|
239
|
+
updateEnvVersion("2.0.0", envPath);
|
|
240
|
+
|
|
241
|
+
const content = fs.readFileSync(envPath, "utf8");
|
|
242
|
+
assert.ok(content.includes("KNTIC_VERSION=2.0.0"), "version must be updated");
|
|
243
|
+
assert.ok(!content.includes("KNTIC_VERSION=0.0.1"), "old version must be gone");
|
|
244
|
+
assert.ok(content.includes("UID=1000"), "other vars must be preserved");
|
|
245
|
+
assert.ok(content.includes("GID=1000"), "other vars must be preserved");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("handles file without trailing newline when appending", () => {
|
|
249
|
+
const envPath = path.join(tmpDir, ".kntic.env");
|
|
250
|
+
fs.writeFileSync(envPath, "UID=1000");
|
|
251
|
+
|
|
252
|
+
updateEnvVersion("0.1.0", envPath);
|
|
253
|
+
|
|
254
|
+
const content = fs.readFileSync(envPath, "utf8");
|
|
255
|
+
assert.ok(content.includes("UID=1000"), "existing content must be preserved");
|
|
256
|
+
assert.ok(content.includes("KNTIC_VERSION=0.1.0"), "version must be appended");
|
|
257
|
+
// Ensure they're on separate lines
|
|
258
|
+
assert.ok(content.includes("UID=1000\nKNTIC_VERSION=0.1.0"), "must be on separate lines");
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
205
262
|
describe("extractVersion (update module)", () => {
|
|
206
263
|
it("parses version from artifact filename", () => {
|
|
207
264
|
assert.equal(extractVersion("kntic-bootstrap-v0.0.10.tar.gz"), "0.0.10");
|