@rightkit/git 0.2.15 → 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)) {
|
|
@@ -657,6 +679,7 @@ ${pm.setup}
|
|
|
657
679
|
- name: Run installed-artifact qualification
|
|
658
680
|
run: ${pm.runPrefix} ${chain.installedQualificationScript}
|
|
659
681
|
env:
|
|
682
|
+
GH_TOKEN: \${{ github.token }}
|
|
660
683
|
RIGHT_GIT_FINALIZED_WINDOWS_ROOT: \${{ runner.temp }}/right-git-release/windows
|
|
661
684
|
RIGHT_GIT_QUALIFICATION_EVIDENCE_ROOT: \${{ runner.temp }}/right-git-release/qualification
|
|
662
685
|
RIGHT_GIT_SOURCE_REVISION: \${{ env.RIGHT_GIT_SOURCE_REVISION }}
|
|
@@ -732,6 +755,7 @@ export function buildRenderContext(manifest, repoPath) {
|
|
|
732
755
|
const pm = parsePackageManager(manifest.packageManager);
|
|
733
756
|
const projectName = deriveProjectName(repoPath);
|
|
734
757
|
const artifactPrefix = projectName.toLowerCase().replace(/[^a-z0-9-]+/g, "-");
|
|
758
|
+
const rustWorkspaces = manifest.rustCache?.workspaces ?? ["engine"];
|
|
735
759
|
|
|
736
760
|
const context = {
|
|
737
761
|
OS_MATRIX: yamlFlowStringList(manifest.matrix.os),
|
|
@@ -746,6 +770,7 @@ export function buildRenderContext(manifest, repoPath) {
|
|
|
746
770
|
ARTIFACT_PREFIX: artifactPrefix,
|
|
747
771
|
TEMPLATE_VERSION: manifest.templateVersion,
|
|
748
772
|
GATE_PATH: manifest.gate?.path,
|
|
773
|
+
RUST_CACHE_WORKSPACES: rustWorkspaces.map((workspace) => ` ${workspace} -> target`).join("\n"),
|
|
749
774
|
CANDIDATE_BUILD_SCRIPT: manifest.candidate?.buildScript,
|
|
750
775
|
CANDIDATE_CHECK_SCRIPT: manifest.candidate?.checkScript,
|
|
751
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,
|
|
@@ -214,6 +235,7 @@ test("rust-hybrid release chain preserves signed candidate, installed qualificat
|
|
|
214
235
|
assert.match(content, /shell: pwsh\n run: \|\n throw 'installed_qualification_failed \{ reason: prerequisites_absent, detail: "same-run Windows signing\/finalization did not succeed" \}'/);
|
|
215
236
|
assert.doesNotMatch(content, /^ run: throw 'installed_qualification_failed .*detail: /m);
|
|
216
237
|
assert.match(content, /pnpm run release:qualify:installed/);
|
|
238
|
+
assert.match(content, /installed-qualification:[\s\S]*GH_TOKEN: \$\{\{ github\.token \}\}/);
|
|
217
239
|
assert.match(content, /publish:\n needs: \[installed-qualification, macos-sign\]/);
|
|
218
240
|
assert.match(content, /publish:[\s\S]*startsWith\(github\.ref, 'refs\/tags\/v'\)/);
|
|
219
241
|
assert.doesNotMatch(content.slice(content.indexOf(" publish:")), /inputs\.signed_qualification/);
|
|
@@ -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}
|