@rightkit/git 0.2.16 → 0.2.17
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
|
@@ -38,6 +38,6 @@ Node builtins only; no runtime dependencies.
|
|
|
38
38
|
|
|
39
39
|
## Profiles
|
|
40
40
|
|
|
41
|
-
`profile` defaults to `node`. `rust-hybrid` requires `ci`, accepts optional `release-candidate`, installs pinned Node plus Rust, then runs product-owned package scripts. Candidate configuration is `{ buildScript, checkScript, artifactRoot, os, targets?, signWindows?, signMacos?, releaseChain? }`. Legacy `os` remains supported & derives one target per runner; explicit `targets` is `{ os, platform, architecture }[]`, independent of main CI matrix. Each target maps to native runner, Rust target triple, exact unsigned artifact, & platform signing matrix. Supported platform values are `windows`, `macos`, `linux`; architectures are `x86_64`, `arm64`. RightGit always uploads an unsigned handoff. `signWindows: true` adds Azure OIDC signing. `signMacos: true` adds Developer ID signing plus notarization from protected environment secrets.
|
|
41
|
+
`profile` defaults to `node`. `rust-hybrid` requires `ci`, accepts optional `release-candidate`, installs pinned Node plus Rust, then runs product-owned package scripts. `rustCache.workspaces` declares every independent Cargo workspace whose `target` directory participates in dependency caching. Rust-hybrid workflows also enable source-aware sccache compilation caching, reuse one stable cache namespace across CI & candidate jobs, & keep workspace-crate artifacts out of rust-cache to prevent stale exact hits. Candidate configuration is `{ buildScript, checkScript, artifactRoot, os, targets?, signWindows?, signMacos?, releaseChain? }`. Legacy `os` remains supported & derives one target per runner; explicit `targets` is `{ os, platform, architecture }[]`, independent of main CI matrix. Each target maps to native runner, Rust target triple, exact unsigned artifact, & platform signing matrix. Supported platform values are `windows`, `macos`, `linux`; architectures are `x86_64`, `arm64`. RightGit always uploads an unsigned handoff. `signWindows: true` adds Azure OIDC signing. `signMacos: true` adds Developer ID signing plus notarization from protected environment secrets.
|
|
42
42
|
|
|
43
43
|
`releaseChain` lets RightGit own full protected DAG while product scripts own artifact semantics: `{ windowsFinalizeScript, macosFinalizeScript?, installedQualificationScript, publishScript, qualificationRunnerVariable, publishSecrets? }`. Generated ordering is unsigned candidate → platform signing/finalization → installed qualification → publication. It deliberately rejects more than one Windows target or more than one macOS target because its installed-qualification/publish handoff has one canonical signed artifact per platform. Every protected job is tag-gated, publication needs successful installed qualification plus macOS finalization when enabled, & only publish job receives declared publication secrets plus `contents: write`.
|
package/manifest.mjs
CHANGED
|
@@ -57,9 +57,11 @@ const TOP_LEVEL_KEYS = new Set([
|
|
|
57
57
|
"templateVersion",
|
|
58
58
|
"profile",
|
|
59
59
|
"gate",
|
|
60
|
+
"rustCache",
|
|
60
61
|
"candidate",
|
|
61
62
|
]);
|
|
62
63
|
const GATE_PATH_RE = /^(?!.*\.\.)(?!.*\s)[A-Za-z0-9][A-Za-z0-9._/-]*$/;
|
|
64
|
+
const RUST_WORKSPACE_PATH_RE = /^(?:\.|(?!.*\.\.)(?!.*\s)[A-Za-z0-9][A-Za-z0-9._/-]*)$/;
|
|
63
65
|
const PACKAGE_SCRIPT_RE = /^[A-Za-z0-9][A-Za-z0-9:_-]*$/;
|
|
64
66
|
const GITHUB_VARIABLE_RE = /^[A-Z][A-Z0-9_]*$/;
|
|
65
67
|
const RELEASE_PLATFORMS = new Set(["windows", "macos", "linux"]);
|
|
@@ -153,6 +155,26 @@ export function validateManifest(manifest) {
|
|
|
153
155
|
errors.push("gate is only valid for profile 'rust-hybrid'");
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
const rustCache = manifest.rustCache;
|
|
159
|
+
if (rustCache !== undefined) {
|
|
160
|
+
if (profile !== "rust-hybrid") {
|
|
161
|
+
errors.push("rustCache is only valid for profile 'rust-hybrid'");
|
|
162
|
+
} else if (rustCache === null || typeof rustCache !== "object" || Array.isArray(rustCache)) {
|
|
163
|
+
errors.push("rustCache must be an object");
|
|
164
|
+
} else {
|
|
165
|
+
for (const key of Object.keys(rustCache)) {
|
|
166
|
+
if (key !== "workspaces") errors.push(`unknown rustCache field: ${key}`);
|
|
167
|
+
}
|
|
168
|
+
if (!Array.isArray(rustCache.workspaces) || rustCache.workspaces.length === 0) {
|
|
169
|
+
errors.push("rustCache.workspaces must be a non-empty array");
|
|
170
|
+
} else if (rustCache.workspaces.some((value) => typeof value !== "string" || !RUST_WORKSPACE_PATH_RE.test(value))) {
|
|
171
|
+
errors.push("rustCache.workspaces entries must be safe relative paths");
|
|
172
|
+
} else if (new Set(rustCache.workspaces).size !== rustCache.workspaces.length) {
|
|
173
|
+
errors.push("rustCache.workspaces entries must be unique");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
156
178
|
const candidate = manifest.candidate;
|
|
157
179
|
if (candidate !== undefined) {
|
|
158
180
|
if (candidate === null || typeof candidate !== "object" || Array.isArray(candidate)) {
|
|
@@ -733,6 +755,7 @@ export function buildRenderContext(manifest, repoPath) {
|
|
|
733
755
|
const pm = parsePackageManager(manifest.packageManager);
|
|
734
756
|
const projectName = deriveProjectName(repoPath);
|
|
735
757
|
const artifactPrefix = projectName.toLowerCase().replace(/[^a-z0-9-]+/g, "-");
|
|
758
|
+
const rustWorkspaces = manifest.rustCache?.workspaces ?? ["engine"];
|
|
736
759
|
|
|
737
760
|
const context = {
|
|
738
761
|
OS_MATRIX: yamlFlowStringList(manifest.matrix.os),
|
|
@@ -747,6 +770,7 @@ export function buildRenderContext(manifest, repoPath) {
|
|
|
747
770
|
ARTIFACT_PREFIX: artifactPrefix,
|
|
748
771
|
TEMPLATE_VERSION: manifest.templateVersion,
|
|
749
772
|
GATE_PATH: manifest.gate?.path,
|
|
773
|
+
RUST_CACHE_WORKSPACES: rustWorkspaces.map((workspace) => ` ${workspace} -> target`).join("\n"),
|
|
750
774
|
CANDIDATE_BUILD_SCRIPT: manifest.candidate?.buildScript,
|
|
751
775
|
CANDIDATE_CHECK_SCRIPT: manifest.candidate?.checkScript,
|
|
752
776
|
CANDIDATE_ARTIFACT_ROOT: manifest.candidate?.artifactRoot,
|
package/manifest.schema.json
CHANGED
|
@@ -82,6 +82,19 @@
|
|
|
82
82
|
"pattern": "^\\d+\\.\\d+\\.\\d+$"
|
|
83
83
|
}
|
|
84
84
|
,"profile": { "enum": ["node", "rust-hybrid"] },
|
|
85
|
+
"rustCache": {
|
|
86
|
+
"type": "object",
|
|
87
|
+
"required": ["workspaces"],
|
|
88
|
+
"additionalProperties": false,
|
|
89
|
+
"properties": {
|
|
90
|
+
"workspaces": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"minItems": 1,
|
|
93
|
+
"uniqueItems": true,
|
|
94
|
+
"items": { "type": "string", "pattern": "^(?:\\.|(?!.*\\.\\.)(?!.*\\s)[A-Za-z0-9][A-Za-z0-9._/-]*)$" }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
85
98
|
"gate": {
|
|
86
99
|
"type": "object", "required": ["path"], "additionalProperties": false,
|
|
87
100
|
"properties": { "path": { "type": "string", "pattern": "^(?!.*\\.\\.)(?!.*\\s)[A-Za-z0-9][A-Za-z0-9._/-]*$" } }
|
package/package.json
CHANGED
package/render.test.mjs
CHANGED
|
@@ -69,6 +69,8 @@ test("rust-hybrid release candidate renders product scripts, artifact handoff, a
|
|
|
69
69
|
);
|
|
70
70
|
assert.match(content, /pnpm run ci:candidate/);
|
|
71
71
|
assert.match(content, /pnpm run ci:candidate-check/);
|
|
72
|
+
assert.match(content, /Mozilla-Actions\/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba/);
|
|
73
|
+
assert.match(content, /shared-key: widgets-rust/);
|
|
72
74
|
assert.doesNotMatch(content, /bash \.\/scripts\/gate\.sh/);
|
|
73
75
|
assert.match(content, /RIGHT_GIT_ARTIFACT_ROOT/);
|
|
74
76
|
assert.match(content, /os: "macos-latest"/);
|
|
@@ -78,6 +80,25 @@ test("rust-hybrid release candidate renders product scripts, artifact handoff, a
|
|
|
78
80
|
assert.doesNotMatch(content, /secrets\.|AZURE_|APPLE_|certificate|private.key/i);
|
|
79
81
|
});
|
|
80
82
|
|
|
83
|
+
test("rust-hybrid cache contract renders every declared Cargo workspace", () => {
|
|
84
|
+
const manifest = {
|
|
85
|
+
...FULL_MANIFEST,
|
|
86
|
+
lanes: ["ci"],
|
|
87
|
+
profile: "rust-hybrid",
|
|
88
|
+
gate: { path: "scripts/gate.sh" },
|
|
89
|
+
rustCache: { workspaces: [".", "apps/studio/src-tauri"] },
|
|
90
|
+
matrix: { os: ["windows-2025"], node: ["22.23.2"] },
|
|
91
|
+
};
|
|
92
|
+
const content = renderTemplate(
|
|
93
|
+
fs.readFileSync(path.join(templatesDir, "profiles/rust-hybrid/ci.yml"), "utf8"),
|
|
94
|
+
buildRenderContext(manifest, "/repos/widgets"),
|
|
95
|
+
);
|
|
96
|
+
assert.match(content, /workspaces: \|\n \. -> target\n apps\/studio\/src-tauri -> target/);
|
|
97
|
+
assert.match(content, /add-job-id-key: false/);
|
|
98
|
+
assert.match(content, /cache-workspace-crates: false/);
|
|
99
|
+
assert.match(content, /RUSTC_WRAPPER: "sccache"/);
|
|
100
|
+
});
|
|
101
|
+
|
|
81
102
|
test("rust-hybrid release candidate can opt into OIDC Windows signing without long-lived secrets", () => {
|
|
82
103
|
const manifest = {
|
|
83
104
|
...FULL_MANIFEST,
|
|
@@ -16,6 +16,9 @@ jobs:
|
|
|
16
16
|
run: exit 1
|
|
17
17
|
ci:
|
|
18
18
|
needs: [private-repo-guard]
|
|
19
|
+
env:
|
|
20
|
+
SCCACHE_GHA_ENABLED: "true"
|
|
21
|
+
RUSTC_WRAPPER: "sccache"
|
|
19
22
|
strategy:
|
|
20
23
|
fail-fast: false
|
|
21
24
|
matrix:
|
|
@@ -37,5 +40,13 @@ ${PACKAGE_MANAGER_SETUP}
|
|
|
37
40
|
components: rustfmt, clippy
|
|
38
41
|
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
|
39
42
|
with:
|
|
40
|
-
workspaces:
|
|
43
|
+
workspaces: |
|
|
44
|
+
${RUST_CACHE_WORKSPACES}
|
|
45
|
+
shared-key: ${ARTIFACT_PREFIX}-rust
|
|
46
|
+
add-job-id-key: false
|
|
47
|
+
cache-workspace-crates: false
|
|
48
|
+
save-if: ${{ github.event_name != 'pull_request' }}
|
|
49
|
+
- uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
50
|
+
with:
|
|
51
|
+
version: "v0.16.0"
|
|
41
52
|
- run: bash ./${GATE_PATH}
|
|
@@ -24,6 +24,9 @@ jobs:
|
|
|
24
24
|
run: exit 1
|
|
25
25
|
candidate:
|
|
26
26
|
needs: [private-repo-guard]
|
|
27
|
+
env:
|
|
28
|
+
SCCACHE_GHA_ENABLED: "true"
|
|
29
|
+
RUSTC_WRAPPER: "sccache"
|
|
27
30
|
strategy:
|
|
28
31
|
fail-fast: false
|
|
29
32
|
matrix:
|
|
@@ -43,7 +46,15 @@ ${PACKAGE_MANAGER_SETUP}
|
|
|
43
46
|
targets: ${{ matrix.targetTriple }}
|
|
44
47
|
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
|
45
48
|
with:
|
|
46
|
-
workspaces:
|
|
49
|
+
workspaces: |
|
|
50
|
+
${RUST_CACHE_WORKSPACES}
|
|
51
|
+
shared-key: ${ARTIFACT_PREFIX}-rust
|
|
52
|
+
add-job-id-key: false
|
|
53
|
+
cache-workspace-crates: false
|
|
54
|
+
save-if: true
|
|
55
|
+
- uses: Mozilla-Actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
|
|
56
|
+
with:
|
|
57
|
+
version: "v0.16.0"
|
|
47
58
|
- run: ${INSTALL_COMMAND}
|
|
48
59
|
- name: Build unsigned release candidate
|
|
49
60
|
run: ${PM_RUN} ${CANDIDATE_BUILD_SCRIPT}
|