Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lane-create): use the version from .bitmap when creating a lane from lane #6929

Merged
merged 2 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions e2e/harmony/lanes/lane-from-lane.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import chai, { expect } from 'chai';
import Helper from '../../../src/e2e-helper/e2e-helper';
import * as fixtures from '../../../src/fixtures/fixtures';
import { removeChalkCharacters } from '../../../src/utils';

chai.use(require('chai-fs'));

describe('bit lane command', function () {
this.timeout(0);
let helper: Helper;
before(() => {
helper = new Helper();
});
after(() => {
helper.scopeHelper.destroy();
});
describe('main => lane-a => lane-b, so laneB branched from laneA', () => {
let beforeSwitchingBack;
before(() => {
helper.scopeHelper.setNewLocalAndRemoteScopes();
// main
helper.fs.outputFile('utils/is-type/is-type.js', fixtures.isType);
helper.command.addComponent('utils/is-type', { i: 'utils/is-type' });
helper.command.snapAllComponentsWithoutBuild();

// laneA
helper.command.createLane('lane-a');
helper.fs.outputFile(
'utils/is-string/is-string.js',
"const isType = require('../is-type/is-type.js'); module.exports = function isString() { return isType() + ' and got is-string'; };"
);
helper.command.addComponent('utils/is-string', { i: 'utils/is-string' });
helper.command.linkAndRewire();
helper.command.compile();
helper.command.snapAllComponentsWithoutBuild();

// laneB
helper.command.createLane('lane-b');
helper.fixtures.createComponentBarFoo();
helper.fixtures.addComponentBarFooAsDir();
helper.command.snapAllComponentsWithoutBuild();

beforeSwitchingBack = helper.scopeHelper.cloneLocalScope();
});
it('lane-a should not contain components from main', () => {
const lane = helper.command.showOneLaneParsed('lane-a');
expect(lane.components).to.have.lengthOf(1);
});
it('laneB object should include components from laneA, but not from main', () => {
const lane = helper.command.showOneLaneParsed('lane-b');
expect(lane.components).to.have.lengthOf(2);
});
it('bit list should show all components available to lane-b', () => {
const list = helper.command.listLocalScopeParsed();
expect(list).to.have.lengthOf(3);
});
describe('checking out to lane-a', () => {
let switchOutput;
before(() => {
switchOutput = helper.command.switchLocalLane('lane-a');
});
it('should indicate that it switched to the new lane', () => {
expect(switchOutput).to.have.string(
removeChalkCharacters('successfully set "lane-a" as the active lane') as string
);
});
// main components belong to lane-a only if they are snapped on lane-a, so utils/is-type
// doesn't belong to lane-a and should not appear as staged when on lane-a.
it('bit status should not show neither lane-b nor main components as staged', () => {
const staged = helper.command.getStagedIdsFromStatus();
expect(staged).to.deep.equal(['utils/is-string']);
const status = helper.command.status();
expect(status).to.not.have.string('bar/foo');
});
it('bit list should not show lane-b components', () => {
const list = helper.command.listParsed();
expect(list).to.have.lengthOf(2);
});
// @todo: test each one of the commands on bar/foo
});
describe('checking out from lane-b to main', () => {
before(() => {
helper.scopeHelper.getClonedLocalScope(beforeSwitchingBack);
helper.command.switchLocalLane('main');
});
it('bit list should only show main components', () => {
const list = helper.command.listParsed();
expect(list).to.have.lengthOf(1);
});
it('bit status should show only main components as staged', () => {
const staged = helper.command.getStagedIdsFromStatus();
expect(staged).to.deep.equal(['utils/is-type']);
const status = helper.command.status();
expect(status).to.not.have.string('bar/foo');
expect(status).to.not.have.string('utils/is-string');
});
});
describe('switching to lane-a then to main', () => {
before(() => {
helper.scopeHelper.getClonedLocalScope(beforeSwitchingBack);
helper.command.switchLocalLane('lane-a');
helper.command.switchLocalLane('main');
});
it('bit list should only show main components', () => {
const list = helper.command.listParsed();
expect(list).to.have.lengthOf(1);
});
it('bit status should show only main components as staged', () => {
const staged = helper.command.getStagedIdsFromStatus();
expect(staged).to.deep.equal(['utils/is-type']);
const status = helper.command.status();
expect(status).to.not.have.string('bar/foo');
expect(status).to.not.have.string('utils/is-string');
});
});
});
describe('creating lane-b from lane-a when lane-a is out-of-date', () => {
let outOfDateState: string;
let firstSnap: string;
let secondSnap: string;
before(() => {
helper.scopeHelper.setNewLocalAndRemoteScopes();
helper.command.createLane('lane-a');
helper.fixtures.populateComponents(1, false);
helper.command.snapAllComponentsWithoutBuild();
firstSnap = helper.command.getHeadOfLane('lane-a', 'comp1');
helper.command.export();
outOfDateState = helper.scopeHelper.cloneLocalScope();

helper.fixtures.populateComponents(1, false, 'v2');
helper.command.snapAllComponentsWithoutBuild();
secondSnap = helper.command.getHeadOfLane('lane-a', 'comp1');
helper.command.export();

helper.scopeHelper.getClonedLocalScope(outOfDateState);
helper.command.import();
// intermediate step to make sure the lane is out-of-date
const status = helper.command.statusJson();
expect(status.outdatedComponents).to.have.lengthOf(1);

helper.command.createLane('lane-b');
});
it('should add the component from the current/first snap (from .bitmap) and not from the head (lane-a object)', () => {
const headOnLaneB = helper.command.getHeadOfLane('lane-b', 'comp1');
expect(headOnLaneB).to.equal(firstSnap);
expect(headOnLaneB).to.not.equal(secondSnap);
});
});
});
99 changes: 0 additions & 99 deletions e2e/harmony/lanes/lanes.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,106 +305,7 @@ describe('bit lane command', function () {
);
});
});
describe('main => lane-a => lane-b, so laneB branched from laneA', () => {
let beforeSwitchingBack;
before(() => {
helper.scopeHelper.setNewLocalAndRemoteScopes();
// main
helper.fs.outputFile('utils/is-type/is-type.js', fixtures.isType);
helper.command.addComponent('utils/is-type', { i: 'utils/is-type' });
helper.command.snapAllComponentsWithoutBuild();

// laneA
helper.command.createLane('lane-a');
helper.fs.outputFile(
'utils/is-string/is-string.js',
"const isType = require('../is-type/is-type.js'); module.exports = function isString() { return isType() + ' and got is-string'; };"
);
helper.command.addComponent('utils/is-string', { i: 'utils/is-string' });
helper.command.linkAndRewire();
helper.command.compile();
helper.command.snapAllComponentsWithoutBuild();

// laneB
helper.command.createLane('lane-b');
helper.fixtures.createComponentBarFoo();
helper.fixtures.addComponentBarFooAsDir();
helper.command.snapAllComponentsWithoutBuild();

beforeSwitchingBack = helper.scopeHelper.cloneLocalScope();
});
it('lane-a should not contain components from main', () => {
const lane = helper.command.showOneLaneParsed('lane-a');
expect(lane.components).to.have.lengthOf(1);
});
it('laneB object should include components from laneA, but not from main', () => {
const lane = helper.command.showOneLaneParsed('lane-b');
expect(lane.components).to.have.lengthOf(2);
});
it('bit list should show all components available to lane-b', () => {
const list = helper.command.listLocalScopeParsed();
expect(list).to.have.lengthOf(3);
});
describe('checking out to lane-a', () => {
let switchOutput;
before(() => {
switchOutput = helper.command.switchLocalLane('lane-a');
});
it('should indicate that it switched to the new lane', () => {
expect(switchOutput).to.have.string(
removeChalkCharacters('successfully set "lane-a" as the active lane') as string
);
});
// main components belong to lane-a only if they are snapped on lane-a, so utils/is-type
// doesn't belong to lane-a and should not appear as staged when on lane-a.
it('bit status should not show neither lane-b nor main components as staged', () => {
const staged = helper.command.getStagedIdsFromStatus();
expect(staged).to.deep.equal(['utils/is-string']);
const status = helper.command.status();
expect(status).to.not.have.string('bar/foo');
});
it('bit list should not show lane-b components', () => {
const list = helper.command.listParsed();
expect(list).to.have.lengthOf(2);
});
// @todo: test each one of the commands on bar/foo
});
describe('checking out from lane-b to main', () => {
before(() => {
helper.scopeHelper.getClonedLocalScope(beforeSwitchingBack);
helper.command.switchLocalLane('main');
});
it('bit list should only show main components', () => {
const list = helper.command.listParsed();
expect(list).to.have.lengthOf(1);
});
it('bit status should show only main components as staged', () => {
const staged = helper.command.getStagedIdsFromStatus();
expect(staged).to.deep.equal(['utils/is-type']);
const status = helper.command.status();
expect(status).to.not.have.string('bar/foo');
expect(status).to.not.have.string('utils/is-string');
});
});
describe('switching to lane-a then to main', () => {
before(() => {
helper.scopeHelper.getClonedLocalScope(beforeSwitchingBack);
helper.command.switchLocalLane('lane-a');
helper.command.switchLocalLane('main');
});
it('bit list should only show main components', () => {
const list = helper.command.listParsed();
expect(list).to.have.lengthOf(1);
});
it('bit status should show only main components as staged', () => {
const staged = helper.command.getStagedIdsFromStatus();
expect(staged).to.deep.equal(['utils/is-type']);
const status = helper.command.status();
expect(status).to.not.have.string('bar/foo');
expect(status).to.not.have.string('utils/is-string');
});
});
});
describe('main => lane => main => lane', () => {
before(() => {
helper.scopeHelper.setNewLocalAndRemoteScopes();
Expand Down
14 changes: 13 additions & 1 deletion scopes/lanes/lanes/create-lane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Consumer } from '@teambit/legacy/dist/consumer';
import { ScopeMain } from '@teambit/scope';
// import { BitIds } from '@teambit/legacy/dist/bit-id';
import Lane, { LaneComponent } from '@teambit/legacy/dist/scope/models/lane';
import { isHash } from '@teambit/component-version';
import { Ref } from '@teambit/legacy/dist/scope/objects';

export async function createLane(
consumer: Consumer,
Expand All @@ -21,7 +23,17 @@ export async function createLane(
// when branching from one lane to another, copy components from the origin lane
// when branching from main, no need to copy anything
const currentLaneObject = await consumer.getCurrentLaneObject();
return currentLaneObject ? currentLaneObject.components : [];
if (!currentLaneObject) return [];
const laneComponents = currentLaneObject.components;
const workspaceIds = consumer.bitMap.getAllBitIds();
const laneComponentWithBitmapHead = laneComponents.map(({ id, head }) => {
const bitmapHead = workspaceIds.searchWithoutVersion(id);
if (bitmapHead && isHash(bitmapHead.version)) {
return { id, head: Ref.from(bitmapHead.version as string) };
}
return { id, head };
});
return laneComponentWithBitmapHead;
};

const forkedFrom = await getLaneOrigin(consumer);
Expand Down