@xemahq/repo-build-tooling 0.31.0 → 0.31.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xemahq/repo-build-tooling",
3
- "version": "0.31.0",
3
+ "version": "0.31.1",
4
4
  "description": "Dev-time build tooling shared by every Xema repository. Ships as plain ESM, depending only on @xemahq/release-policy for registry access, so the published artifact is the reviewed source.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Neuralchowder Inc. <developer@xema.dev> (https://xema.dev)",
@@ -53,6 +53,6 @@
53
53
  "test": "node src/scrub-swagger-plugin-paths.mjs --self-test && node --test src/check-workspace-range-matches-local.test.mjs && node --test src/check-no-vendored-deps.test.mjs && node --test src/readiness.test.mjs && node --test src/composed-image.test.mjs && node --test src/composed-image-class.test.mjs && node --test src/composed-image-coordinate-cli.test.mjs && node --test src/declaration-refusal.test.mjs && node --test src/smoke-refusal.test.mjs && node --test src/load-image.test.mjs && node --test src/composed-image-coordinate.test.mjs && node --test src/composed-image-dockerfile.test.mjs && node --test src/service-bootstrap.test.mjs && node --test src/service-bootstrap-protocols.test.mjs && node --test src/composed-image-prebuilt-dockerfile.test.mjs && node --test src/composed-image-in-image-closure.test.mjs && node --test src/composed-image-stage.test.mjs && node --test src/composed-image-stage-tree.test.mjs && node --test src/composed-image-install.test.mjs && node --test src/composed-image-proof.test.mjs && node --test src/composed-image-pnpm-context.test.mjs && node --test src/composed-image-sync-injected.test.mjs && node --test src/composed-image-prisma-check.test.mjs && node --test src/composed-image-prisma-engine.test.mjs && node --test src/composed-migrate.test.mjs && node --test src/promote-image.test.mjs && node --test src/arm64-supplement-needed.test.mjs && node --test src/service-image.test.mjs && node --test src/image-cpu-arch.test.mjs && node --test src/staged-image-proof.test.mjs && node --test src/effective-input.test.mjs"
54
54
  },
55
55
  "xemaRelease": {
56
- "sourceDigest": "sha256:724bdf902b48fed78564a3b6d52abb15d5ed2a6962da85e7a88f17eab1b085c2"
56
+ "sourceDigest": "sha256:a1e1068eca88fad502417b887f16c732ecf0c9ed0ca339849880ea780aa894d4"
57
57
  }
58
58
  }
@@ -4,7 +4,9 @@
4
4
  // <stage>/layers/store/monorepo/node_modules/.pnpm/ the registry packages (stable until the lockfile changes)
5
5
  // <stage>/layers/workspace/monorepo/ root manifests, the closure's package.json + declared `files` (the
6
6
  // non-member built outputs among them), the injected workspace copies, the Prisma
7
- // clients and engine, the migrate script
7
+ // clients and engine, the migrate script. No source tree: the `--copy` directories
8
+ // reach the install only as their workspace manifests (removed again unless the
9
+ // closure ships them), and their bytes reach only the proof stage (`/proof/copied`)
8
10
  // <stage>/layers/dist/monorepo/ the members' build outputs (default `dist`), the member index and the host link: the
9
11
  // only layer a commit that changes no dependency changes
10
12
  //
@@ -68,6 +70,41 @@ function copyPackageFiles({ root, treeRoot, closure, problems }) {
68
70
  }
69
71
  }
70
72
 
73
+ /**
74
+ * The install's view of the `--copy` directories: every workspace `package.json` and `.patch` file under them (less what
75
+ * the `.dockerignore` keeps out), so pnpm sees the workspace the lockfile describes. Never their sources: those reach
76
+ * only the proof stage, and a source edit must leave the shipped layers byte-identical. Returns the repository-relative
77
+ * paths it wrote.
78
+ */
79
+ function copyInstallManifests({ root, treeRoot, copy }) {
80
+ const written = [];
81
+ const walk = (rel) => {
82
+ for (const entry of readdirSync(join(root, rel), { withFileTypes: true }).sort((a, b) => (a.name < b.name ? -1 : 1))) {
83
+ const path = posix.join(rel, entry.name);
84
+ if (isIgnoredEntry(entry) || entry.name === '.git') continue;
85
+ if (entry.isDirectory()) walk(path);
86
+ else if (entry.isFile() && (entry.name === 'package.json' || entry.name.endsWith('.patch')) && !existsSync(join(treeRoot, path))) {
87
+ mkdirSync(dirname(join(treeRoot, path)), { recursive: true });
88
+ copyFileSync(join(root, path), join(treeRoot, path));
89
+ written.push(path);
90
+ }
91
+ }
92
+ };
93
+ for (const directory of copy) walk(posix.normalize(directory).replace(/\/$/, ''));
94
+ return written;
95
+ }
96
+
97
+ /** Remove the install-only manifests from the tree, and the directories they leave empty: nothing at runtime reads them. */
98
+ function removeInstallManifests({ treeRoot, paths }) {
99
+ for (const rel of paths) {
100
+ rmSync(join(treeRoot, rel), { force: true });
101
+ for (let dir = posix.dirname(rel); dir !== '.' && dir !== ''; dir = posix.dirname(dir)) {
102
+ if (!existsSync(join(treeRoot, dir)) || readdirSync(join(treeRoot, dir)).length > 0) break;
103
+ rmSync(join(treeRoot, dir), { recursive: true });
104
+ }
105
+ }
106
+ }
107
+
71
108
  /** `node_modules/.pnpm` entries that are registry packages: directories without an injected (`@file+`) workspace copy, and not pnpm's hoist directory. */
72
109
  const isStoreEntry = (entry) => entry.isDirectory() && !entry.name.includes('@file+') && entry.name !== 'node_modules';
73
110
 
@@ -131,8 +168,8 @@ export async function stageComposedTree({
131
168
  problems.push(...inputProblems);
132
169
 
133
170
  for (const name of INSTALL_INPUTS.filter((file) => existsSync(join(root, file)))) copyFileSync(join(root, name), join(treeRoot, name));
134
- for (const directory of copy) copyEntry(join(root, directory), join(treeRoot, directory));
135
171
  copyPackageFiles({ root, treeRoot, closure, problems });
172
+ const installOnly = copyInstallManifests({ root, treeRoot, copy });
136
173
  for (const manifest of memberManifests({ root, imageDir })) copyFileSync(join(root, manifest), join(treeRoot, manifest));
137
174
  mkdirSync(join(treeRoot, imageDir), { recursive: true });
138
175
  copyFileSync(join(root, imageDir, IMAGE_BUILD_INPUTS_FILE), join(treeRoot, imageDir, IMAGE_BUILD_INPUTS_FILE));
@@ -182,6 +219,7 @@ export async function stageComposedTree({
182
219
  // Written on the runner: the index resolves modules in the tree, whatever the platform. The host link is relative.
183
220
  const index = writeIndex({ root: treeRoot, imageDir, commit, buildSourceRepository: buildSource });
184
221
  copyFileSync(join(dirname(fileURLToPath(import.meta.url)), MIGRATE_SCRIPT), join(treeRoot, MIGRATE_TARGET));
222
+ removeInstallManifests({ treeRoot, paths: installOnly });
185
223
  const moved = splitLayers(stageRoot);
186
224
  const members = readMembers({ root, imageDir }).map(([, directory]) => directory);
187
225
  splitDistLayer({ stageRoot, members, outputs });
@@ -20,7 +20,7 @@ const git = (args) => {
20
20
  throw new Error(`unexpected git ${args.join(' ')}`);
21
21
  };
22
22
 
23
- function ready() {
23
+ function ready({ copy = ['tooling/dev'] } = {}) {
24
24
  const root = workspace();
25
25
  write(root, 'package.json', { name: 'r' });
26
26
  write(root, 'pnpm-lock.yaml', "lockfileVersion: '9.0'\n");
@@ -29,7 +29,7 @@ function ready() {
29
29
  write(root, 'tooling/dev/node_modules/ignored.js', 'x');
30
30
  write(root, 'packages/sdks/lib-a/assets/data.json', '{}');
31
31
  write(root, 'biomes/alpha/api/alpha-api/README.md', 'ignored');
32
- write(root, 'infra/composed-process/Dockerfile', renderPrebuiltDockerfile({ root, imageClass: ComposedImageClass.Common, copy: ['tooling/dev'], buildSource: 'alpha', base: BASE, nodeMajor: String(process.versions.node.split('.')[0]) }).dockerfile);
32
+ write(root, 'infra/composed-process/Dockerfile', renderPrebuiltDockerfile({ root, imageClass: ComposedImageClass.Common, copy, buildSource: 'alpha', base: BASE, nodeMajor: String(process.versions.node.split('.')[0]) }).dockerfile);
33
33
  return root;
34
34
  }
35
35
 
@@ -66,12 +66,12 @@ test('stages the layers, the manifest and the tool; only package.json + declared
66
66
  assert.equal(calls[0].arch, 'amd64');
67
67
  assert.deepEqual(calls[0].filters, ['--filter', '@t/alpha-api...', '--filter', '@t/alpha-db-api...']);
68
68
  const appFiles = [...files(path.join(root, '.xema-stage/layers/workspace/monorepo')), ...files(path.join(root, '.xema-stage/layers/dist/monorepo'))];
69
- for (const expected of ['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', '.npmrc', 'tooling/dev/patch.txt', 'infra/composed-process/image-build-inputs.json', 'biomes/alpha/xema-biome.json',
69
+ for (const expected of ['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', '.npmrc', 'infra/composed-process/image-build-inputs.json', 'biomes/alpha/xema-biome.json',
70
70
  'biomes/alpha/api/alpha-api/package.json', 'biomes/alpha/api/alpha-api/dist/main.js', 'biomes/alpha/api/alpha-db-api/prisma/schema.prisma', 'biomes/alpha/api/alpha-db-api/node_modules/.prisma/alpha-db/index.js',
71
71
  'packages/sdks/lib-a/assets/data.json', 'packages/sdks/lib-a/dist/index.js', 'xema-composed-migrate.mjs', 'xema-composed-member-index.json']) {
72
72
  assert.ok(appFiles.includes(expected), expected);
73
73
  }
74
- for (const absent of ['turbo.json', 'tooling/dev/node_modules/ignored.js', 'biomes/alpha/api/alpha-api/README.md', 'biomes/alpha/api/alpha-api/src/main.test.ts', 'infra/composed-process/Dockerfile', 'node_modules/.modules.yaml', 'node_modules/.pnpm-workspace-state-v1.json']) {
74
+ for (const absent of ['turbo.json', 'tooling/dev/patch.txt', 'tooling/dev/node_modules/ignored.js', 'biomes/alpha/api/alpha-api/README.md', 'biomes/alpha/api/alpha-api/src/main.test.ts', 'infra/composed-process/Dockerfile', 'node_modules/.modules.yaml', 'node_modules/.pnpm-workspace-state-v1.json']) {
75
75
  assert.ok(!appFiles.includes(absent), `${absent} must not ship`);
76
76
  }
77
77
  assert.ok(fs.existsSync(path.join(root, '.xema-stage/tool/src/composed-image-in-image.mjs')));
@@ -190,3 +190,40 @@ test('a change to a library (workspace package) changes the workspace layer and
190
190
  await run(dep, { install: (args) => { fakeInstall()(args); write(args.treeRoot, 'node_modules/.pnpm/left-pad@1.0.1/node_modules/left-pad/package.json', { name: 'left-pad' }); } });
191
191
  assert.notEqual(layerDigests(dep).store, before.store);
192
192
  });
193
+
194
+ test('the --copy directories reach the install as workspace manifests and the proof as bytes, never a shipped layer: a member src edit leaves every layer byte-identical', async () => {
195
+ const sources = (root) => {
196
+ write(root, 'biomes/alpha/api/alpha-api/src/main.ts', 'export const main = 1;\n');
197
+ write(root, 'packages/sdks/lib-a/src/index.ts', 'export const lib = 1;\n');
198
+ write(root, 'packages/sdks/unused/package.json', { name: '@t/unused', files: ['dist'] });
199
+ write(root, 'packages/sdks/unused/src/index.ts', '// not in the closure\n');
200
+ write(root, 'patches/left-pad.patch', 'diff\n');
201
+ };
202
+ const copy = ['tooling/dev', 'biomes', 'packages', 'patches'];
203
+ const seen = [];
204
+ const install = (args) => {
205
+ seen.push(fs.readdirSync(args.treeRoot, { recursive: true }).map(String).sort());
206
+ fakeInstall()(args);
207
+ };
208
+ const first = ready({ copy });
209
+ sources(first);
210
+ const manifest = await run(first, { install });
211
+ assert.ok(seen[0].includes('packages/sdks/unused/package.json') && seen[0].includes('patches/left-pad.patch'), 'the install sees every workspace manifest and patch');
212
+ assert.ok(!seen[0].some((f) => f.endsWith('.ts') || f === 'tooling/dev/patch.txt'), 'the install sees no source');
213
+ assert.deepEqual(Object.keys(manifest.copied).sort(), ['biomes', 'packages', 'patches', 'tooling/dev'], 'the proof still binds the --copy bytes');
214
+ const shipped = LAYERS.flatMap((layer) => files(path.join(first, '.xema-stage/layers', layer, 'monorepo')));
215
+ for (const absent of ['biomes/alpha/api/alpha-api/src/main.ts', 'biomes/alpha/api/alpha-api/src/main.test.ts', 'packages/sdks/lib-a/src/index.ts', 'packages/sdks/unused/package.json', 'packages/sdks/unused', 'patches/left-pad.patch', 'patches', 'tooling/dev/patch.txt']) {
216
+ assert.ok(!shipped.includes(absent), `${absent} must not ship`);
217
+ }
218
+ for (const present of ['biomes/alpha/api/alpha-api/package.json', 'packages/sdks/lib-a/package.json', 'packages/sdks/lib-a/dist/index.js', 'biomes/alpha/api/alpha-db-api/prisma/schema.prisma']) {
219
+ assert.ok(shipped.includes(present), present);
220
+ }
221
+ const before = layerDigests(first);
222
+ const second = ready({ copy });
223
+ sources(second);
224
+ write(second, 'biomes/alpha/api/alpha-api/src/main.ts', 'export const main = 2; // edited\n');
225
+ write(second, 'biomes/alpha/api/alpha-api/src/added.ts', '// a new source file\n');
226
+ const edited = await run(second);
227
+ assert.deepEqual(layerDigests(second), before);
228
+ assert.notEqual(edited.copied.biomes, manifest.copied.biomes, 'the edit reaches the proof stage');
229
+ });