@rightkit/git 0.2.27 → 0.2.29
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 +14 -0
- package/manifest.mjs +27 -3
- package/manifest.schema.json +5 -0
- package/manifest.test.mjs +15 -0
- package/package.json +1 -1
- package/render.test.mjs +29 -0
- package/templates/profiles/rust-hybrid/ci.yml +1 -3
package/README.md
CHANGED
|
@@ -37,6 +37,20 @@ Set `qaEvidencePath` in `.rightgit.json` to upload the gate's QA output as a wor
|
|
|
37
37
|
- `qaEvidenceRetentionDays` is an integer from 1 to 90 and defaults to 7. It requires `qaEvidencePath`.
|
|
38
38
|
- Omit the key and the rendered `ci.yml` is unchanged.
|
|
39
39
|
|
|
40
|
+
## Full validation on every OS (rust-hybrid)
|
|
41
|
+
|
|
42
|
+
Set `"ciAllOs": true` to run the rust-hybrid `ci` gate on every `matrix.os` runner instead of one. Runners run in declared order with `fail-fast: false`. Each leg uploads its own artifact, because the QA artifact name already includes the runner label.
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"profile": "rust-hybrid",
|
|
47
|
+
"matrix": { "os": ["xcode-27", "windows-2025"], "node": ["26.8.1"] },
|
|
48
|
+
"ciAllOs": true
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Omit the key, or set it to `false`, and the rendered `ci.yml` keeps one runner, preferring the first `windows-*` entry. `ciAllOs: true` is rejected for other profiles.
|
|
53
|
+
|
|
40
54
|
## Entry points
|
|
41
55
|
|
|
42
56
|
No importable API. The package has no `main` and no `exports` map. The supported surface is the `right-git` bin.
|
package/manifest.mjs
CHANGED
|
@@ -61,6 +61,7 @@ const TOP_LEVEL_KEYS = new Set([
|
|
|
61
61
|
"rustCache",
|
|
62
62
|
"qaEvidencePath",
|
|
63
63
|
"qaEvidenceRetentionDays",
|
|
64
|
+
"ciAllOs",
|
|
64
65
|
"candidate",
|
|
65
66
|
"ownership",
|
|
66
67
|
]);
|
|
@@ -83,8 +84,11 @@ const NATIVE_RUNNER_TARGETS = new Map([
|
|
|
83
84
|
["macos-15-intel", ["macos", "x86_64"]],
|
|
84
85
|
]);
|
|
85
86
|
|
|
87
|
+
// Hosted `macos-*` runners plus the self-hosted Xcode runner labels (`xcode-27`).
|
|
88
|
+
const MACOS_RUNNER_RE = /^(macos|xcode)-/i;
|
|
89
|
+
|
|
86
90
|
function inferredTarget(os) {
|
|
87
|
-
const platform = /^windows-/i.test(os) ? "windows" :
|
|
91
|
+
const platform = /^windows-/i.test(os) ? "windows" : MACOS_RUNNER_RE.test(os) ? "macos" : "linux";
|
|
88
92
|
return { os, platform, architecture: platform === "macos" ? "arm64" : "x86_64" };
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -183,6 +187,16 @@ export function validateManifest(manifest) {
|
|
|
183
187
|
}
|
|
184
188
|
}
|
|
185
189
|
|
|
190
|
+
// ciAllOs (rust-hybrid ci only): run the gate on every matrix.os runner
|
|
191
|
+
// instead of one declared runner. Omitted or false keeps the single-runner ci job.
|
|
192
|
+
if (manifest.ciAllOs !== undefined) {
|
|
193
|
+
if (typeof manifest.ciAllOs !== "boolean") {
|
|
194
|
+
errors.push("ciAllOs must be a boolean");
|
|
195
|
+
} else if (manifest.ciAllOs === true && profile !== "rust-hybrid") {
|
|
196
|
+
errors.push("ciAllOs is only valid for profile 'rust-hybrid'");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
186
200
|
const rustCache = manifest.rustCache;
|
|
187
201
|
if (rustCache !== undefined) {
|
|
188
202
|
if (profile !== "rust-hybrid") {
|
|
@@ -253,7 +267,7 @@ export function validateManifest(manifest) {
|
|
|
253
267
|
if (nativeTarget && (target.platform !== nativeTarget[0] || target.architecture !== nativeTarget[1])) {
|
|
254
268
|
errors.push(`candidate.targets[] must declare ${target.os} as ${nativeTarget[0]}/${nativeTarget[1]}`);
|
|
255
269
|
}
|
|
256
|
-
if ((target.platform === "windows" && !/^windows-/i.test(target.os)) || (target.platform === "macos" &&
|
|
270
|
+
if ((target.platform === "windows" && !/^windows-/i.test(target.os)) || (target.platform === "macos" && !MACOS_RUNNER_RE.test(target.os))) {
|
|
257
271
|
errors.push("candidate.targets[].os must match its Windows or macOS platform");
|
|
258
272
|
}
|
|
259
273
|
const targetKey = `${target.os}|${target.platform}|${target.architecture}`;
|
|
@@ -1055,10 +1069,20 @@ export function buildRenderContext(manifest, repoPath, lane = "ci") {
|
|
|
1055
1069
|
const rustWorkspaces = manifest.rustCache?.workspaces ?? ["engine"];
|
|
1056
1070
|
const configuredWindowsRunner = manifest.matrix.os.find((runner) => runner.startsWith("windows-"));
|
|
1057
1071
|
const ciOs = configuredWindowsRunner ?? manifest.matrix.os[0];
|
|
1072
|
+
const ciMatrixOs = manifest.ciAllOs === true
|
|
1073
|
+
? [
|
|
1074
|
+
" # ciAllOs: the gate runs on every matrix.os runner, in declared order.",
|
|
1075
|
+
` os: ${yamlFlowStringList(manifest.matrix.os)}`,
|
|
1076
|
+
]
|
|
1077
|
+
: [
|
|
1078
|
+
" # Full validation stays on one declared runner; prefer configured",
|
|
1079
|
+
" # Windows when available, otherwise preserve first configured OS.",
|
|
1080
|
+
` os: ${yamlFlowStringList([ciOs])}`,
|
|
1081
|
+
];
|
|
1058
1082
|
|
|
1059
1083
|
const context = {
|
|
1060
1084
|
OS_MATRIX: yamlFlowStringList(manifest.matrix.os),
|
|
1061
|
-
|
|
1085
|
+
CI_MATRIX_OS: ciMatrixOs.join("\n"),
|
|
1062
1086
|
NODE_MATRIX: yamlFlowStringList(manifest.matrix.node),
|
|
1063
1087
|
NODE_PUBLISH_VERSION: JSON.stringify(String(manifest.matrix.node[0])),
|
|
1064
1088
|
PM_NAME: pm.name,
|
package/manifest.schema.json
CHANGED
|
@@ -128,6 +128,11 @@
|
|
|
128
128
|
"default": 7,
|
|
129
129
|
"description": "rust-hybrid only, requires qaEvidencePath. Artifact retention in days."
|
|
130
130
|
},
|
|
131
|
+
"ciAllOs": {
|
|
132
|
+
"type": "boolean",
|
|
133
|
+
"default": false,
|
|
134
|
+
"description": "rust-hybrid only. When true, the ci job runs the gate on every matrix.os runner in declared order (fail-fast: false). When false or unset, the ci job uses one runner (preferring the first windows-* entry, else the first matrix.os entry)."
|
|
135
|
+
},
|
|
131
136
|
"candidate": {
|
|
132
137
|
"type": "object",
|
|
133
138
|
"required": ["buildScript", "checkScript", "admissionScript", "stageSummaryScript", "artifactRoot", "os"],
|
package/manifest.test.mjs
CHANGED
|
@@ -207,6 +207,9 @@ test("candidate targets permit native multi-architecture matrices independent of
|
|
|
207
207
|
assert.equal(validateManifest({ ...multiArchitecture, candidate: { ...multiArchitecture.candidate, targets: [{ os: "windows-2025", platform: "windows", architecture: "riscv64" }] } }).valid, false);
|
|
208
208
|
assert.equal(validateManifest({ ...multiArchitecture, candidate: { ...multiArchitecture.candidate, targets: [{ os: "windows-11-arm", platform: "windows", architecture: "x86_64" }] } }).valid, false);
|
|
209
209
|
assert.equal(validateManifest({ ...multiArchitecture, candidate: { ...multiArchitecture.candidate, targets: [{ os: "ubuntu-24.04", platform: "windows", architecture: "x86_64" }] } }).valid, false);
|
|
210
|
+
const xcodeRunner = { ...multiArchitecture, candidate: { ...multiArchitecture.candidate, os: ["xcode-27"], targets: [{ os: "xcode-27", platform: "macos", architecture: "arm64" }], signWindows: false } };
|
|
211
|
+
assert.equal(validateManifest(xcodeRunner).valid, true, JSON.stringify(validateManifest(xcodeRunner).errors));
|
|
212
|
+
assert.equal(validateManifest({ ...multiArchitecture, candidate: { ...multiArchitecture.candidate, os: ["ubuntu-24.04"], targets: [{ os: "ubuntu-24.04", platform: "macos", architecture: "arm64" }] } }).valid, false);
|
|
210
213
|
assert.equal(validateManifest({ ...multiArchitecture, candidate: { ...multiArchitecture.candidate, targets: [{ os: "${{ secrets.X }}", platform: "windows", architecture: "x86_64" }] } }).valid, false);
|
|
211
214
|
assert.equal(validateManifest({ ...multiArchitecture, candidate: { ...multiArchitecture.candidate, releaseChain: { windowsFinalizeScript: "release:finalize:win", macosFinalizeScript: "release:finalize:mac", installedQualificationScript: "release:qualify", publishScript: "release:publish", qualificationRunnerVariable: "QUALIFICATION_RUNNER_LABEL" } } }).valid, false);
|
|
212
215
|
});
|
|
@@ -403,3 +406,15 @@ test("qaEvidencePath and qaEvidenceRetentionDays are optional, rust-hybrid only,
|
|
|
403
406
|
assert.equal(validateManifest({ ...valid, qaEvidenceRetentionDays: 7 }).valid, false, "retention requires a path");
|
|
404
407
|
assert.equal(validateManifest({ ...VALID_MINIMAL, qaEvidencePath: "pulse-hub-qa" }).valid, false, "node profile rejects qaEvidencePath");
|
|
405
408
|
});
|
|
409
|
+
|
|
410
|
+
test("ciAllOs is an optional boolean, rust-hybrid only", () => {
|
|
411
|
+
const valid = { ...VALID_MINIMAL, profile: "rust-hybrid", gate: { path: "scripts/gate.sh" } };
|
|
412
|
+
assert.equal(validateManifest(valid).valid, true);
|
|
413
|
+
assert.equal(validateManifest({ ...valid, ciAllOs: true }).valid, true);
|
|
414
|
+
assert.equal(validateManifest({ ...valid, ciAllOs: false }).valid, true);
|
|
415
|
+
for (const ciAllOs of ["true", 1, null]) {
|
|
416
|
+
assert.equal(validateManifest({ ...valid, ciAllOs }).valid, false, String(ciAllOs));
|
|
417
|
+
}
|
|
418
|
+
assert.equal(validateManifest({ ...VALID_MINIMAL, ciAllOs: true }).valid, false, "node profile rejects ciAllOs true");
|
|
419
|
+
assert.equal(validateManifest({ ...VALID_MINIMAL, ciAllOs: false }).valid, true, "false is accepted for any profile");
|
|
420
|
+
});
|
package/package.json
CHANGED
package/render.test.mjs
CHANGED
|
@@ -119,6 +119,35 @@ test("rust-hybrid ci preserves a declared macOS-only lane", () => {
|
|
|
119
119
|
assert.doesNotMatch(content, /windows-2025/);
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
+
test("rust-hybrid ci runs every matrix.os runner when ciAllOs is true, in declared order", () => {
|
|
123
|
+
const base = {
|
|
124
|
+
...FULL_MANIFEST,
|
|
125
|
+
lanes: ["ci"],
|
|
126
|
+
profile: "rust-hybrid",
|
|
127
|
+
gate: { path: "scripts/gate.sh" },
|
|
128
|
+
qaEvidencePath: "pulse-hub-qa",
|
|
129
|
+
matrix: { os: ["xcode-27", "windows-2025"], node: ["26.8.1"] },
|
|
130
|
+
};
|
|
131
|
+
const render = (manifest) => renderTemplate(
|
|
132
|
+
fs.readFileSync(path.join(templatesDir, "profiles/rust-hybrid/ci.yml"), "utf8"),
|
|
133
|
+
buildRenderContext(manifest, "/repos/pulse"),
|
|
134
|
+
);
|
|
135
|
+
const all = render({ ...base, ciAllOs: true });
|
|
136
|
+
assert.match(all, /^ {8}os: \["xcode-27", "windows-2025"\]$/m);
|
|
137
|
+
assert.match(all, /runs-on: \$\{\{ matrix\.os \}\}/);
|
|
138
|
+
assert.match(all, /fail-fast: false/);
|
|
139
|
+
assert.match(all, /name: qa-evidence-\$\{\{ matrix\.os \|\| runner\.os \}\}-\$\{\{ github\.run_attempt \}\}/);
|
|
140
|
+
assert.doesNotMatch(all, /Full validation stays/);
|
|
141
|
+
// ciAllOs false and unset render the same single-runner matrix as before.
|
|
142
|
+
for (const manifest of [base, { ...base, ciAllOs: false }]) {
|
|
143
|
+
const single = render(manifest);
|
|
144
|
+
assert.match(single, /# Full validation stays on one declared runner; prefer configured\n {8}# Windows when available, otherwise preserve first configured OS\.\n {8}os: \["windows-2025"\]\n/);
|
|
145
|
+
assert.doesNotMatch(single, /xcode-27/);
|
|
146
|
+
}
|
|
147
|
+
// Unset and false produce byte-identical output.
|
|
148
|
+
assert.equal(render({ ...base, ciAllOs: false }), render(base));
|
|
149
|
+
});
|
|
150
|
+
|
|
122
151
|
test("rust-hybrid release candidate renders product scripts, artifact handoff, and no signing secret", () => {
|
|
123
152
|
const manifest = {
|
|
124
153
|
...FULL_MANIFEST,
|
|
@@ -22,9 +22,7 @@ jobs:
|
|
|
22
22
|
strategy:
|
|
23
23
|
fail-fast: false
|
|
24
24
|
matrix:
|
|
25
|
-
|
|
26
|
-
# Windows when available, otherwise preserve first configured OS.
|
|
27
|
-
os: ${CI_OS_MATRIX}
|
|
25
|
+
${CI_MATRIX_OS}
|
|
28
26
|
node: ${NODE_MATRIX}
|
|
29
27
|
runs-on: ${{ matrix.os }}
|
|
30
28
|
steps:
|