From 7f9774779f0cd229dc063d0425ee6988bc8e4cd9 Mon Sep 17 00:00:00 2001 From: David First Date: Mon, 2 Oct 2023 16:26:42 -0400 Subject: [PATCH] fix(snap/tag), remove duplicated extensions generated in old bit version --- scopes/workspace/workspace/aspects-merger.ts | 23 +++++++++++++++++--- src/consumer/config/extension-data.ts | 5 +++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/scopes/workspace/workspace/aspects-merger.ts b/scopes/workspace/workspace/aspects-merger.ts index 52370d26f346..2aadb4736c39 100644 --- a/scopes/workspace/workspace/aspects-merger.ts +++ b/scopes/workspace/workspace/aspects-merger.ts @@ -4,8 +4,8 @@ import { UnmergedComponent } from '@teambit/legacy/dist/scope/lanes/unmerged-com import { BitId } from '@teambit/legacy-bit-id'; import { EnvsAspect } from '@teambit/envs'; import { DependencyResolverAspect } from '@teambit/dependency-resolver'; -import { ExtensionDataList } from '@teambit/legacy/dist/consumer/config/extension-data'; -import { partition, mergeWith, merge } from 'lodash'; +import { ExtensionDataList, ignoreVersionPredicate } from '@teambit/legacy/dist/consumer/config/extension-data'; +import { partition, mergeWith, merge, uniq, uniqWith } from 'lodash'; import { MergeConfigConflict } from './exceptions/merge-config-conflict'; import { AspectSpecificField, ExtensionsOrigin, Workspace } from './workspace'; import { MergeConflictFile } from './merge-conflict-file'; @@ -93,7 +93,7 @@ export class AspectsMerger { : undefined; this.removeAutoDepsFromConfig(componentId, configMergeExtensions); - const scopeExtensions = componentFromScope?.config?.extensions || new ExtensionDataList(); + const scopeExtensions = this.getComponentFromScopeWithoutDuplications(componentFromScope); // backward compatibility. previously, it was saved as an array into the model (when there was merge-config) this.removeAutoDepsFromConfig(componentId, scopeExtensions, true); const [specific, nonSpecific] = partition(scopeExtensions, (entry) => entry.config[AspectSpecificField] === true); @@ -203,6 +203,23 @@ export class AspectsMerger { }; } + /** + * before version 0.0.882 it was possible to save Version object with the same extension twice. + */ + private getComponentFromScopeWithoutDuplications(componentFromScope?: Component) { + if (!componentFromScope) return new ExtensionDataList(); + const scopeExtensions = componentFromScope.config.extensions; + const scopeExtIds = scopeExtensions.ids; + const scopeExtHasDuplications = scopeExtIds.length !== uniq(scopeExtIds).length; + if (!scopeExtHasDuplications) { + return scopeExtensions; + } + // let's remove this duplicated extension blindly without trying to merge. (no need to merge coz it's old data from scope + // which will be overridden anyway by the workspace or other config strategies). + const arr = uniqWith(scopeExtensions, ignoreVersionPredicate); + return ExtensionDataList.fromArray(arr); + } + /** * from the merge-config we get the dep-resolver policy as an array, because it needs to support "force" prop. * however, when we save the config, we want to save it as an object, so we need split the data into two: diff --git a/src/consumer/config/extension-data.ts b/src/consumer/config/extension-data.ts index 04a4602681d3..fb83c4f77bf7 100644 --- a/src/consumer/config/extension-data.ts +++ b/src/consumer/config/extension-data.ts @@ -9,7 +9,8 @@ import { reStructureBuildArtifacts, } from '../component/sources/artifact-files'; -const mergeReducer = (accumulator, currentValue) => R.unionWith(ignoreVersionPredicate, accumulator, currentValue); +const mergeReducer = (accumulator: ExtensionDataList, currentValue: ExtensionDataList) => + R.unionWith(ignoreVersionPredicate, accumulator, currentValue); type ExtensionConfig = { [extName: string]: any } | RemoveExtensionSpecialSign; type ConfigOnlyEntry = { id: string; @@ -270,7 +271,7 @@ export class ExtensionDataList extends Array { } } -function ignoreVersionPredicate(extensionEntry1: ExtensionDataEntry, extensionEntry2: ExtensionDataEntry) { +export function ignoreVersionPredicate(extensionEntry1: ExtensionDataEntry, extensionEntry2: ExtensionDataEntry) { if (extensionEntry1.extensionId && extensionEntry2.extensionId) { return extensionEntry1.extensionId.isEqualWithoutVersion(extensionEntry2.extensionId); }