@decohere/ci-tools 0.0.1-dev.38 → 0.0.1-dev.4
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/bench/bench.mjs +2 -2
- package/src/bench/trace.mjs +1 -1
- package/src/coverage/badge.mjs +2 -2
- package/src/pages/restore-bench-history.mjs +2 -1
- package/src/release/push-prerelease-commit.mjs +15 -57
- package/src/release/sync-dependencies.mjs +1 -1
- package/tests/lib/lcov.test.mjs +7 -7
package/package.json
CHANGED
package/src/bench/bench.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* bench.mjs — run the
|
|
4
|
+
* bench.mjs — run the forgev2 benchmark and compare against the last saved baseline.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
7
|
* node bench.mjs — run and compare, do not save
|
|
@@ -34,7 +34,7 @@ const HISTORY_FILE = join(
|
|
|
34
34
|
"projects/ci-tools/dist/ci/bench/bench-history.json",
|
|
35
35
|
);
|
|
36
36
|
const VITEST_BIN = join(WORKSPACE_ROOT, "node_modules/.bin/vitest");
|
|
37
|
-
const BENCH_FILE = "projects/
|
|
37
|
+
const BENCH_FILE = "projects/foundry/e2e/build.benchmark.bench.ts";
|
|
38
38
|
const CONFIG = join(WORKSPACE_ROOT, "vitest.e2e.config.ts");
|
|
39
39
|
const TRACE_LOG_DIR = join(WORKSPACE_ROOT, ".decohere", "logs");
|
|
40
40
|
const MAX_RUNS = 10;
|
package/src/bench/trace.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { join } from "node:path";
|
|
|
7
7
|
const WORKSPACE_ROOT = process.cwd();
|
|
8
8
|
const VITEST_BIN = join(WORKSPACE_ROOT, "node_modules/.bin/vitest");
|
|
9
9
|
const CONFIG = join(WORKSPACE_ROOT, "vitest.e2e.config.ts");
|
|
10
|
-
const TRACE_SPEC = "projects/
|
|
10
|
+
const TRACE_SPEC = "projects/foundry/e2e/build.trace.e2e.spec.ts";
|
|
11
11
|
const TRACE_LOG_DIR = join(WORKSPACE_ROOT, ".decohere", "logs");
|
|
12
12
|
|
|
13
13
|
function truthy(value, defaultValue = false) {
|
package/src/coverage/badge.mjs
CHANGED
|
@@ -10,8 +10,8 @@ import path from "node:path";
|
|
|
10
10
|
import { parseLcovByProject } from "../lib/lcov.mjs";
|
|
11
11
|
import { createBadgeSvg, getColor } from "../lib/svg.mjs";
|
|
12
12
|
|
|
13
|
-
const summaryPath = path.resolve("
|
|
14
|
-
const lcovPath = path.resolve("
|
|
13
|
+
const summaryPath = path.resolve(".forge/coverage/coverage-summary.json");
|
|
14
|
+
const lcovPath = path.resolve(".forge/coverage/lcov.info");
|
|
15
15
|
const badgesDirectory = path.resolve("projects/ci-tools/dist/ci/badges");
|
|
16
16
|
const globalBadgePath = path.join(badgesDirectory, "coverage.svg");
|
|
17
17
|
const projectBadgesDirectory = path.join(badgesDirectory, "projects");
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// Restore benchmark history from Pages, or initialize empty if not found
|
|
4
4
|
|
|
5
5
|
import { execSync } from "node:child_process";
|
|
6
|
-
import { writeFileSync } from "node:fs";
|
|
6
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { mkdir } from "node:fs/promises";
|
|
8
|
+
import { dirname } from "node:path";
|
|
8
9
|
|
|
9
10
|
const HISTORY_DIR = "projects/ci-tools/dist/ci/bench";
|
|
10
11
|
const HISTORY_FILE = `${HISTORY_DIR}/bench-history.json`;
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* Validates working tree
|
|
5
|
-
* and creates/updates a PR targeting the protected base branch.
|
|
3
|
+
* Push prerelease version commit before publish
|
|
4
|
+
* Validates working tree and pushes new prerelease commit to remote
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
7
|
import { execSync } from "node:child_process";
|
|
9
8
|
|
|
10
|
-
function run(command) {
|
|
11
|
-
return execSync(command, { encoding: "utf8" }).trim();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function runInherit(command, env) {
|
|
15
|
-
execSync(command, { stdio: "inherit", env });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
9
|
try {
|
|
19
10
|
// Check if working tree is dirty
|
|
20
|
-
const status =
|
|
11
|
+
const status = execSync("git status --porcelain", { encoding: "utf8" });
|
|
21
12
|
if (status.trim().length > 0) {
|
|
22
13
|
console.error(
|
|
23
14
|
"::error::Working tree is dirty after version/dependency sync; refusing to publish with uncommitted changes.",
|
|
@@ -26,58 +17,25 @@ try {
|
|
|
26
17
|
process.exit(1);
|
|
27
18
|
}
|
|
28
19
|
|
|
29
|
-
// Compare HEAD with origin
|
|
30
|
-
const head =
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
20
|
+
// Compare HEAD with origin
|
|
21
|
+
const head = execSync("git rev-parse HEAD", { encoding: "utf8" }).trim();
|
|
22
|
+
const branch =
|
|
23
|
+
process.env.GITHUB_REF_NAME ||
|
|
24
|
+
execSync("git rev-parse --abbrev-ref HEAD", {
|
|
25
|
+
encoding: "utf8",
|
|
26
|
+
}).trim();
|
|
36
27
|
|
|
37
28
|
try {
|
|
38
|
-
const origin =
|
|
29
|
+
const origin = execSync(`git rev-parse origin/${branch}`, { encoding: "utf8" }).trim();
|
|
39
30
|
|
|
40
31
|
if (head !== origin) {
|
|
41
|
-
console.log(
|
|
42
|
-
|
|
43
|
-
);
|
|
44
|
-
runInherit(`git push origin HEAD:${releasePrBranch} --force`, process.env);
|
|
45
|
-
|
|
46
|
-
if (token == null || token.length === 0) {
|
|
47
|
-
throw new Error("Missing GITHUB_TOKEN/GH_TOKEN for PR upsert");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const version = process.env.RELEASE_VERSION ?? "(unknown)";
|
|
51
|
-
const ownerRepo = run("git config --get remote.origin.url")
|
|
52
|
-
.replace(/^.*github\.com[:/]/, "")
|
|
53
|
-
.replace(/\.git$/, "");
|
|
54
|
-
|
|
55
|
-
runInherit(
|
|
56
|
-
[
|
|
57
|
-
"node projects/ci-tools/src/github/create-or-update-pr.mjs",
|
|
58
|
-
`--title "chore(release): ${channel} ${version}"`,
|
|
59
|
-
`--base "${baseBranch}"`,
|
|
60
|
-
`--head "${releasePrBranch}"`,
|
|
61
|
-
`--body "Automated ${channel} version bump and dependency sync.\\n\\n- Channel: ${channel}\\n- Version: ${version}\\n- Source branch: ${sourceBranch}\\n- Base branch: ${baseBranch}\\n- Source commit: ${head}\\n\\nGenerated by pull-request workflow."`,
|
|
62
|
-
`--owner "${ownerRepo.split("/")[0]}"`,
|
|
63
|
-
`--repo "${ownerRepo.split("/")[1]}"`,
|
|
64
|
-
].join(" "),
|
|
65
|
-
{ ...process.env, GITHUB_TOKEN: token },
|
|
66
|
-
);
|
|
32
|
+
console.log(`Pushing prerelease version commit to origin/${branch}`);
|
|
33
|
+
execSync(`git push origin HEAD:${branch}`, { stdio: "inherit" });
|
|
67
34
|
} else {
|
|
68
35
|
console.log("No prerelease version commit to push.");
|
|
69
36
|
}
|
|
70
|
-
} catch
|
|
71
|
-
|
|
72
|
-
if (
|
|
73
|
-
message.includes(`origin/${sourceBranch}`) &&
|
|
74
|
-
message.includes("Needed a single revision")
|
|
75
|
-
) {
|
|
76
|
-
console.log(`Remote branch origin/${sourceBranch} not found, skipping push.`);
|
|
77
|
-
} else {
|
|
78
|
-
console.error("::error::Failed to publish release commit via PR branch.");
|
|
79
|
-
throw err;
|
|
80
|
-
}
|
|
37
|
+
} catch {
|
|
38
|
+
console.log(`Remote branch origin/${branch} not found, skipping push.`);
|
|
81
39
|
}
|
|
82
40
|
} catch (e) {
|
|
83
41
|
console.error(`Push failed: ${e.message}`);
|
|
@@ -10,7 +10,7 @@ const DRY_RUN = process.env.DRY_RUN === "true";
|
|
|
10
10
|
const TERMINAL_CLI = process.env.TERMINAL_CLI || "dist/debug/projects/terminal/src/cli.js";
|
|
11
11
|
const DECOHERE_CONFIG = process.env.DECOHERE_CONFIG || ".decohere.js";
|
|
12
12
|
|
|
13
|
-
const baseCmd = `node "${TERMINAL_CLI}" --log-level trace --config-file "${DECOHERE_CONFIG}"
|
|
13
|
+
const baseCmd = `node "${TERMINAL_CLI}" --log-level trace --config-file "${DECOHERE_CONFIG}" foundry dependencies --configuration release sync`;
|
|
14
14
|
|
|
15
15
|
try {
|
|
16
16
|
if (DRY_RUN) {
|
package/tests/lib/lcov.test.mjs
CHANGED
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
parseLcovFiles,
|
|
6
6
|
} from "../../src/lib/lcov.mjs";
|
|
7
7
|
|
|
8
|
-
const sampleLcov = `SF:projects/
|
|
8
|
+
const sampleLcov = `SF:projects/foundry/src/index.ts
|
|
9
9
|
LF:10
|
|
10
10
|
LH:9
|
|
11
11
|
end_of_record
|
|
12
|
-
SF:projects/
|
|
12
|
+
SF:projects/foundry/src/build/index.ts
|
|
13
13
|
LF:20
|
|
14
14
|
LH:15
|
|
15
15
|
end_of_record
|
|
@@ -32,7 +32,7 @@ end_of_record
|
|
|
32
32
|
|
|
33
33
|
describe("getProjectFromPath", () => {
|
|
34
34
|
it("extracts project name from projects/ path", () => {
|
|
35
|
-
expect(getProjectFromPath("projects/
|
|
35
|
+
expect(getProjectFromPath("projects/foundry/src/index.ts")).toBe("foundry");
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it("returns undefined for unrecognized paths", () => {
|
|
@@ -43,16 +43,16 @@ describe("getProjectFromPath", () => {
|
|
|
43
43
|
describe("parseLcovByProject", () => {
|
|
44
44
|
it("groups files by project and sums coverage", () => {
|
|
45
45
|
const result = parseLcovByProject(sampleLcov);
|
|
46
|
-
expect(result.get("
|
|
47
|
-
expect(result.get("
|
|
48
|
-
expect(result.get("
|
|
46
|
+
expect(result.get("foundry")).toBeDefined();
|
|
47
|
+
expect(result.get("foundry").totalLines).toBe(30);
|
|
48
|
+
expect(result.get("foundry").coveredLines).toBe(24);
|
|
49
49
|
expect(result.get("nexus")).toBeDefined();
|
|
50
50
|
expect(result.get("nexus").totalLines).toBe(5);
|
|
51
51
|
expect(result.get("nexus").coveredLines).toBe(5);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
it("ignores records with LF:0", () => {
|
|
55
|
-
const lcov = `SF:projects/
|
|
55
|
+
const lcov = `SF:projects/foundry/src/empty.ts\nLF:0\nLH:0\nend_of_record\n`;
|
|
56
56
|
const result = parseLcovByProject(lcov);
|
|
57
57
|
expect(result.size).toBe(0);
|
|
58
58
|
});
|