From f664879ac143b3cf5f92b5e75c7c8596cf0766af Mon Sep 17 00:00:00 2001 From: David First Date: Fri, 7 Aug 2026 14:28:24 -0400 Subject: [PATCH 1/2] fix: install dependencies added on the other lane during lane merge --- e2e/harmony/lanes/merge-lanes-main.e2e.ts | 40 +++++++++++++++++++ .../component/merging/merging.main.runtime.ts | 5 +++ 2 files changed, 45 insertions(+) diff --git a/e2e/harmony/lanes/merge-lanes-main.e2e.ts b/e2e/harmony/lanes/merge-lanes-main.e2e.ts index bfc01a4957db..b24e323ffde4 100644 --- a/e2e/harmony/lanes/merge-lanes-main.e2e.ts +++ b/e2e/harmony/lanes/merge-lanes-main.e2e.ts @@ -1,4 +1,5 @@ import chai, { expect } from 'chai'; +import path from 'path'; import { Helper } from '@teambit/legacy.e2e-helper'; import chaiFs from 'chai-fs'; chai.use(chaiFs); @@ -316,4 +317,43 @@ describe('merge lanes - main lane operations', function () { expect(hashes).to.include(remoteHead); }); }); + + describe('merging main into a lane when main added a new package dependency', () => { + let mergeOutput: string; + // enough distance between the top of the file (changed on main) and the bottom + // (changed on the lane) for the merge to auto-resolve without conflicts + const filler = Array.from({ length: 10 }, (unused, index) => `// filler line ${index}`).join('\n'); + const baseFile = `${filler}\nmodule.exports = () => 'comp1';\n`; + before(() => { + helper.scopeHelper.setWorkspaceWithRemoteScope(); + helper.fixtures.populateComponents(1); + helper.fs.outputFile('comp1/index.js', baseFile); + helper.command.tagAllWithoutBuild(); + helper.command.export(); + helper.command.createLane('dev'); + helper.fs.outputFile('comp1/index.js', `${baseFile}// lane-only change\n`); + helper.command.snapAllComponentsWithoutBuild(); + helper.command.export(); + // create a lockfile that does not include is-positive + helper.command.install(); + const laneWs = helper.scopeHelper.cloneWorkspace(); + helper.command.switchLocalLane('main', '-x'); + helper.command.install('is-positive'); + helper.fs.outputFile('comp1/index.js', `const isPositive = require('is-positive');\n${baseFile}`); + helper.command.tagAllWithoutBuild(); + helper.command.export(); + // back to the lane workspace, whose lockfile knows nothing about is-positive + helper.scopeHelper.getClonedWorkspace(laneWs); + mergeOutput = helper.command.mergeLaneWithoutBuild('main'); + }); + it('should install the dependency added on main and complete the auto-snap', () => { + expect(mergeOutput).to.not.have.string('snap error'); + expect(mergeOutput).to.not.have.string('missing packages'); + // "Total Snapped: 1" is interrupted by ANSI styling, match the section title instead + expect(mergeOutput).to.have.string('merge-snapped components (1)'); + }); + it('should have the new dependency in node_modules', () => { + expect(path.join(helper.scopes.localPath, 'node_modules/is-positive')).to.be.a.directory(); + }); + }); }); diff --git a/scopes/component/merging/merging.main.runtime.ts b/scopes/component/merging/merging.main.runtime.ts index 18d692bb96f1..def69ae59ec1 100644 --- a/scopes/component/merging/merging.main.runtime.ts +++ b/scopes/component/merging/merging.main.runtime.ts @@ -287,6 +287,11 @@ export class MergingMain { const leftUnresolvedConflicts = componentWithConflict && mergeStrategy === 'manual'; if (!skipDependencyInstallation && !leftUnresolvedConflicts && !componentsHasConfigMergeConflicts) { + // the components were loaded (and cached) before the merge wrote the merged files and the + // merged config (unmerged-components store). without clearing the cache, the install below + // reloads them with pre-merge dependencies, so a package newly introduced on the other side + // never enters the install manifest and the package manager skips it ("lockfile is up to date"). + if (this.workspace) await this.workspace.clearCache(); // this is a workaround. // keep this here. although it gets called before snapping. // the reason is that when the installation is running, for some reason, some apps are unable to load in the same process. From 65689197782d632d44f6220a0fd0023d0a29d162 Mon Sep 17 00:00:00 2001 From: David First Date: Fri, 7 Aug 2026 14:59:48 -0400 Subject: [PATCH 2/2] fix: narrow merge cache clear to component caches, pin e2e dep version --- e2e/harmony/lanes/merge-lanes-main.e2e.ts | 2 +- scopes/component/merging/merging.main.runtime.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e/harmony/lanes/merge-lanes-main.e2e.ts b/e2e/harmony/lanes/merge-lanes-main.e2e.ts index b24e323ffde4..7d4b76dc1461 100644 --- a/e2e/harmony/lanes/merge-lanes-main.e2e.ts +++ b/e2e/harmony/lanes/merge-lanes-main.e2e.ts @@ -338,7 +338,7 @@ describe('merge lanes - main lane operations', function () { helper.command.install(); const laneWs = helper.scopeHelper.cloneWorkspace(); helper.command.switchLocalLane('main', '-x'); - helper.command.install('is-positive'); + helper.command.install('is-positive@3.1.0'); helper.fs.outputFile('comp1/index.js', `const isPositive = require('is-positive');\n${baseFile}`); helper.command.tagAllWithoutBuild(); helper.command.export(); diff --git a/scopes/component/merging/merging.main.runtime.ts b/scopes/component/merging/merging.main.runtime.ts index def69ae59ec1..9701231b4c97 100644 --- a/scopes/component/merging/merging.main.runtime.ts +++ b/scopes/component/merging/merging.main.runtime.ts @@ -291,7 +291,9 @@ export class MergingMain { // merged config (unmerged-components store). without clearing the cache, the install below // reloads them with pre-merge dependencies, so a package newly introduced on the other side // never enters the install manifest and the package manager skips it ("lockfile is up to date"). - if (this.workspace) await this.workspace.clearCache(); + // clear only the component caches — the scope objects were written by this very process, so + // the scope cache is current and clearing it would add avoidable overhead to every merge. + if (this.workspace) this.workspace.clearAllComponentsCache(); // this is a workaround. // keep this here. although it gets called before snapping. // the reason is that when the installation is running, for some reason, some apps are unable to load in the same process.