@opengsd/gsd-core 1.3.0 → 1.3.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.
|
@@ -175,16 +175,46 @@ function migrationChecksum(migration) {
|
|
|
175
175
|
};
|
|
176
176
|
return `sha256:${sha256Text(JSON.stringify(serializable))}`;
|
|
177
177
|
}
|
|
178
|
-
|
|
178
|
+
// Rewrite the stored checksum of any already-applied entry whose id drifted, so the
|
|
179
|
+
// drift is reconciled durably and not re-detected on every subsequent run (issue #670).
|
|
180
|
+
// Returns the number of entries actually changed (so callers know whether a write is needed).
|
|
181
|
+
function reconcileDriftedChecksums(appliedEntries, checksumDrift) {
|
|
182
|
+
if (!Array.isArray(checksumDrift) || checksumDrift.length === 0)
|
|
183
|
+
return 0;
|
|
184
|
+
const reconcile = new Map(checksumDrift.map((d) => [d.id, d.currentChecksum]));
|
|
185
|
+
let changed = 0;
|
|
186
|
+
for (let i = 0; i < appliedEntries.length; i++) {
|
|
187
|
+
const existing = appliedEntries[i];
|
|
188
|
+
if (existing && typeof existing.id === 'string' && reconcile.has(existing.id)) {
|
|
189
|
+
const next = reconcile.get(existing.id);
|
|
190
|
+
if (existing.checksum !== next) {
|
|
191
|
+
appliedEntries[i] = { ...existing, checksum: next };
|
|
192
|
+
changed += 1;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return changed;
|
|
197
|
+
}
|
|
198
|
+
function collectAppliedChecksumDrift(applied, migrations) {
|
|
199
|
+
const drift = [];
|
|
179
200
|
for (const migration of migrations) {
|
|
180
201
|
const entry = applied.get(migration.id);
|
|
181
202
|
if (!entry || !entry.checksum)
|
|
182
203
|
continue;
|
|
183
|
-
const
|
|
184
|
-
if (entry.checksum !==
|
|
185
|
-
|
|
204
|
+
const currentChecksum = migrationChecksum(migration);
|
|
205
|
+
if (entry.checksum !== currentChecksum) {
|
|
206
|
+
// An already-applied migration is never re-run (it is filtered out of `pending`),
|
|
207
|
+
// so a checksum drift here is functionally inert. A prior release may have edited a
|
|
208
|
+
// shipped migration body (see issue #670). Surface it for reconciliation instead of
|
|
209
|
+
// hard-aborting the user's upgrade.
|
|
210
|
+
drift.push({
|
|
211
|
+
id: migration.id,
|
|
212
|
+
storedChecksum: entry.checksum,
|
|
213
|
+
currentChecksum,
|
|
214
|
+
});
|
|
186
215
|
}
|
|
187
216
|
}
|
|
217
|
+
return drift;
|
|
188
218
|
}
|
|
189
219
|
function migrationMatchesContext(migration, { runtime, scope }) {
|
|
190
220
|
if (Array.isArray(migration.runtimes) && migration.runtimes.length > 0) {
|
|
@@ -387,7 +417,7 @@ function planInstallerMigrations({ configDir, runtime = null, scope = null, migr
|
|
|
387
417
|
const validatedMigrations = migrations.map((migration) => (0, installer_migration_authoring_cjs_1.validateInstallerMigrationRecord)(migration));
|
|
388
418
|
const scopedMigrations = validatedMigrations.filter((migration) => migrationMatchesContext(migration, { runtime, scope }));
|
|
389
419
|
const applied = appliedMigrationEntries(state);
|
|
390
|
-
|
|
420
|
+
const checksumDrift = collectAppliedChecksumDrift(applied, scopedMigrations);
|
|
391
421
|
const pending = scopedMigrations.filter((migration) => !applied.has(migration.id));
|
|
392
422
|
const actions = [];
|
|
393
423
|
const blocked = [];
|
|
@@ -474,6 +504,7 @@ function planInstallerMigrations({ configDir, runtime = null, scope = null, migr
|
|
|
474
504
|
pendingMigrations: pending,
|
|
475
505
|
actions,
|
|
476
506
|
blocked,
|
|
507
|
+
checksumDrift,
|
|
477
508
|
};
|
|
478
509
|
}
|
|
479
510
|
function uniqueActionMigrationIds(actions) {
|
|
@@ -630,6 +661,7 @@ function applyInstallerMigrationPlan({ configDir, plan, now = () => new Date().t
|
|
|
630
661
|
const state = readInstallState(configDir);
|
|
631
662
|
const applied = appliedMigrationIds(state);
|
|
632
663
|
const nextApplied = [...state.appliedMigrations];
|
|
664
|
+
reconcileDriftedChecksums(nextApplied, plan.checksumDrift);
|
|
633
665
|
const actionsByMigrationId = new Map();
|
|
634
666
|
for (const action of plan.actions) {
|
|
635
667
|
if (action.migrationId && !actionsByMigrationId.has(action.migrationId)) {
|
|
@@ -684,30 +716,36 @@ function applyInstallerMigrationPlan({ configDir, plan, now = () => new Date().t
|
|
|
684
716
|
}
|
|
685
717
|
}
|
|
686
718
|
function markPendingMigrationsApplied({ configDir, plan, now = () => new Date().toISOString(), }) {
|
|
687
|
-
if (!plan
|
|
719
|
+
if (!plan)
|
|
720
|
+
return [];
|
|
721
|
+
const hasPending = Array.isArray(plan.pendingMigrationIds) && plan.pendingMigrationIds.length > 0;
|
|
722
|
+
const hasDrift = Array.isArray(plan.checksumDrift) && plan.checksumDrift.length > 0;
|
|
723
|
+
if (!hasPending && !hasDrift)
|
|
688
724
|
return [];
|
|
689
|
-
}
|
|
690
725
|
const appliedAt = now();
|
|
691
726
|
const state = readInstallState(configDir);
|
|
692
727
|
const applied = appliedMigrationIds(state);
|
|
693
|
-
const checksumsByMigrationId = new Map();
|
|
694
|
-
for (const migration of plan.pendingMigrations || []) {
|
|
695
|
-
checksumsByMigrationId.set(migration.id, migrationChecksum(migration));
|
|
696
|
-
}
|
|
697
728
|
const nextApplied = [...state.appliedMigrations];
|
|
729
|
+
const reconciledCount = reconcileDriftedChecksums(nextApplied, plan.checksumDrift);
|
|
698
730
|
const newlyApplied = [];
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
731
|
+
if (hasPending) {
|
|
732
|
+
const checksumsByMigrationId = new Map();
|
|
733
|
+
for (const migration of plan.pendingMigrations || []) {
|
|
734
|
+
checksumsByMigrationId.set(migration.id, migrationChecksum(migration));
|
|
735
|
+
}
|
|
736
|
+
for (const id of plan.pendingMigrationIds) {
|
|
737
|
+
if (applied.has(id))
|
|
738
|
+
continue;
|
|
739
|
+
nextApplied.push({
|
|
740
|
+
id,
|
|
741
|
+
appliedAt,
|
|
742
|
+
journal: null,
|
|
743
|
+
checksum: checksumsByMigrationId.get(id) || null,
|
|
744
|
+
});
|
|
745
|
+
newlyApplied.push(id);
|
|
746
|
+
}
|
|
709
747
|
}
|
|
710
|
-
if (newlyApplied.length > 0) {
|
|
748
|
+
if (newlyApplied.length > 0 || reconciledCount > 0) {
|
|
711
749
|
writeInstallState(configDir, {
|
|
712
750
|
schemaVersion: 1,
|
|
713
751
|
appliedMigrations: nextApplied,
|
|
@@ -776,6 +814,7 @@ module.exports = {
|
|
|
776
814
|
applyInstallerMigrationPlan,
|
|
777
815
|
classifyArtifact,
|
|
778
816
|
discoverInstallerMigrations,
|
|
817
|
+
migrationChecksum,
|
|
779
818
|
planInstallerMigrations,
|
|
780
819
|
readInstallManifest,
|
|
781
820
|
readInstallState,
|
package/package.json
CHANGED