@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,
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rightkit/git",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "Public-repo-only GitHub Actions workflow layer: templates, visibility gate, sync/drift/adopt/uninstall for right-git.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",
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: engine
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: engine
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}