@mriekki/project-forge 4.4.2 → 4.5.0

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.
@@ -1,7 +1,7 @@
1
1
  {
2
- "schemaVersion": 1,
2
+ "schemaVersion": 2,
3
3
  "package": "@mriekki/project-forge",
4
- "version": "4.4.2",
4
+ "version": "4.5.0",
5
5
  "defaultProfile": "greenfield-project",
6
6
  "profiles": {
7
7
  "greenfield-project": {
@@ -13,8 +13,7 @@
13
13
  },
14
14
  "components": {
15
15
  "core": {
16
- "repository": "mriekki/project-forge-core",
17
- "commit": "d106b1834a8c44bdae0b16e4af5d8dab0711a120",
16
+ "revision": "d106b1834a8c44bdae0b16e4af5d8dab0711a120",
18
17
  "version": "4.0.0",
19
18
  "distribution": "greenfield-workspace",
20
19
  "descriptor": "assets/core/distribution.json",
@@ -22,8 +21,7 @@
22
21
  "canonicalDescriptor": "distributions/greenfield-workspace.json"
23
22
  },
24
23
  "deployment": {
25
- "repository": "mriekki/project-forge-deployment-kit",
26
- "commit": "880a911bc87e38c74ca4b336c9563a6f026ac3b4",
24
+ "revision": "880a911bc87e38c74ca4b336c9563a6f026ac3b4",
27
25
  "distribution": "greenfield-project",
28
26
  "descriptor": "assets/deployment/distribution.json",
29
27
  "sourceRoot": "assets/generated/deployment",
@@ -1,11 +1,10 @@
1
1
  {
2
- "schemaVersion": 1,
2
+ "schemaVersion": 2,
3
3
  "package": "@mriekki/project-forge",
4
- "version": "4.4.2",
4
+ "version": "4.5.0",
5
5
  "components": {
6
6
  "core": {
7
- "repository": "mriekki/project-forge-core",
8
- "commit": "d106b1834a8c44bdae0b16e4af5d8dab0711a120",
7
+ "revision": "d106b1834a8c44bdae0b16e4af5d8dab0711a120",
9
8
  "version": "4.0.0",
10
9
  "distribution": "greenfield-workspace",
11
10
  "files": [
@@ -327,8 +326,7 @@
327
326
  ]
328
327
  },
329
328
  "deployment": {
330
- "repository": "mriekki/project-forge-deployment-kit",
331
- "commit": "880a911bc87e38c74ca4b336c9563a6f026ac3b4",
329
+ "revision": "880a911bc87e38c74ca4b336c9563a6f026ac3b4",
332
330
  "distribution": "greenfield-project",
333
331
  "files": [
334
332
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mriekki/project-forge",
3
- "version": "4.4.2",
3
+ "version": "4.5.0",
4
4
  "description": "Public consumer distribution and updater for Project Forge engineering assets.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/engine.mjs CHANGED
@@ -54,6 +54,12 @@ function baselineMap(baseline, filename) {
54
54
  return map;
55
55
  }
56
56
 
57
+ function componentRevision(component) {
58
+ const revision = component.revision ?? component.commit;
59
+ if (typeof revision !== 'string' || !/^[0-9a-f]{40}$/i.test(revision)) throw new Error('Component revision must be an exact 40-character Git revision');
60
+ return revision.toLowerCase();
61
+ }
62
+
57
63
  export function componentEntries(packageData, componentId) {
58
64
  const component = packageData.assets.components[componentId];
59
65
  if (!component) throw new Error(`Package does not define component ${componentId}`);
@@ -95,22 +101,27 @@ function classifyDesired(componentId, src, dst, baselineItem) {
95
101
  return { state: 'CONFLICT', desiredHash, currentHash };
96
102
  }
97
103
 
98
- function coreMetadataCurrent(baseline, component) {
99
- return baseline.schemaVersion === 1 && baseline.coreRepository === component.repository && baseline.coreVersion === component.version && baseline.coreCommit === component.commit && baseline.distribution === component.distribution && Array.isArray(baseline.managedPaths) && baseline.managedPaths.length > 0;
104
+ function validateBaselineIdentity(baseline, componentId, component, filename) {
105
+ if (!Object.keys(baseline).length) return;
106
+ if (![1, 2].includes(baseline.schemaVersion)) throw new Error(`Unsupported ${filename} schemaVersion`);
107
+ if (baseline.schemaVersion === 2 && baseline.component !== componentId) throw new Error(`${filename} records a different component`);
108
+ if (baseline.distribution && baseline.distribution !== component.distribution) throw new Error(`${filename} records a different distribution`);
100
109
  }
101
110
 
102
- function deploymentMetadataCurrent(baseline, component) {
103
- return baseline.schemaVersion === 1 && baseline.deploymentKitRepository === component.repository && baseline.deploymentKitCommit === component.commit && baseline.distribution === component.distribution && Array.isArray(baseline.managedPaths) && baseline.managedPaths.length > 0;
111
+ function componentMetadataCurrent(baseline, componentId, component) {
112
+ if (baseline.schemaVersion !== 2 || baseline.component !== componentId) return false;
113
+ if (baseline.revision !== componentRevision(component) || baseline.distribution !== component.distribution) return false;
114
+ if (componentId === 'core' && baseline.version !== component.version) return false;
115
+ return Array.isArray(baseline.managedPaths) && baseline.managedPaths.length > 0;
104
116
  }
105
117
 
106
118
  export function planComponent(packageData, componentId, targetRoot, acceptedRetired = new Set()) {
107
119
  const component = packageData.assets.components[componentId];
120
+ if (!component) throw new Error(`Package does not define component ${componentId}`);
121
+ componentRevision(component);
108
122
  const filename = baselineFile(componentId);
109
123
  const baseline = loadOptionalJson(path.join(targetRoot, filename));
110
- if (Object.keys(baseline).length && baseline.schemaVersion !== 1) throw new Error(`Unsupported ${filename} schemaVersion`);
111
- if (componentId === 'core' && baseline.coreRepository && baseline.coreRepository !== component.repository) throw new Error(`${filename} records a different Core repository`);
112
- if (componentId === 'deployment' && baseline.deploymentKitRepository && baseline.deploymentKitRepository !== component.repository) throw new Error(`${filename} records a different Deployment Kit repository`);
113
- if (baseline.distribution && baseline.distribution !== component.distribution) throw new Error(`${filename} records a different distribution`);
124
+ validateBaselineIdentity(baseline, componentId, component, filename);
114
125
 
115
126
  const entries = componentEntries(packageData, componentId);
116
127
  const baseMap = baselineMap(baseline, filename);
@@ -151,30 +162,19 @@ export function planComponent(packageData, componentId, targetRoot, acceptedReti
151
162
  rows,
152
163
  retired,
153
164
  unsafe,
154
- metadataCurrent: componentId === 'core' ? coreMetadataCurrent(baseline, component) : deploymentMetadataCurrent(baseline, component)
165
+ metadataCurrent: componentMetadataCurrent(baseline, componentId, component)
155
166
  };
156
167
  }
157
168
 
158
169
  function buildComponentBaseline(plan, consumer, consumerBaseline) {
159
170
  const managedPaths = plan.rows.map((row) => ({ source: row.source, path: row.path, sha256: row.desiredHash }));
160
- if (plan.componentId === 'core') {
161
- return {
162
- schemaVersion: 1,
163
- consumer,
164
- consumerBaseline,
165
- coreRepository: plan.component.repository,
166
- coreVersion: plan.component.version,
167
- coreCommit: plan.component.commit,
168
- distribution: plan.component.distribution,
169
- managedPaths
170
- };
171
- }
172
171
  return {
173
- schemaVersion: 1,
172
+ schemaVersion: 2,
173
+ component: plan.componentId,
174
174
  consumer,
175
175
  consumerBaseline,
176
- deploymentKitRepository: plan.component.repository,
177
- deploymentKitCommit: plan.component.commit,
176
+ revision: componentRevision(plan.component),
177
+ ...(plan.component.version ? { version: plan.component.version } : {}),
178
178
  distribution: plan.component.distribution,
179
179
  managedPaths
180
180
  };
@@ -213,15 +213,14 @@ export function applyProfile(packageData, profilePlan, targetRoot, consumer, con
213
213
  fs.writeFileSync(path.join(targetRoot, plan.filename), JSON.stringify(baseline, null, 2) + '\n');
214
214
  }
215
215
  const projectForgeBaseline = {
216
- schemaVersion: 1,
216
+ schemaVersion: 2,
217
217
  package: packageData.pkg.name,
218
218
  version: packageData.pkg.version,
219
219
  profile: profilePlan.profileName,
220
220
  consumer,
221
221
  consumerBaseline,
222
222
  components: Object.fromEntries(profilePlan.plans.map((plan) => [plan.componentId, {
223
- repository: plan.component.repository,
224
- commit: plan.component.commit,
223
+ revision: componentRevision(plan.component),
225
224
  ...(plan.component.version ? { version: plan.component.version } : {}),
226
225
  distribution: plan.component.distribution
227
226
  }]))
@@ -233,7 +232,7 @@ export function applyProfile(packageData, profilePlan, targetRoot, consumer, con
233
232
  export function checkProfile(packageData, profileName, targetRoot) {
234
233
  const plan = planProfile(packageData, profileName, targetRoot);
235
234
  const projectForgeBaseline = loadOptionalJson(path.join(targetRoot, 'PROJECT_FORGE_BASELINE.json'));
236
- const projectForgeCurrent = projectForgeBaseline.schemaVersion === 1 && projectForgeBaseline.package === packageData.pkg.name && projectForgeBaseline.version === packageData.pkg.version && projectForgeBaseline.profile === profileName;
235
+ const projectForgeCurrent = projectForgeBaseline.schemaVersion === 2 && projectForgeBaseline.package === packageData.pkg.name && projectForgeBaseline.version === packageData.pkg.version && projectForgeBaseline.profile === profileName;
237
236
  const componentClean = plan.plans.every((component) => component.metadataCurrent && component.rows.every((row) => row.state === 'SAME') && component.retired.length === 0);
238
237
  return { clean: projectForgeCurrent && componentClean, projectForgeCurrent, plan, projectForgeBaseline };
239
238
  }