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

improvement, filter out unchanged files from the output of checkout/switch/merge #7851

Merged
merged 5 commits into from
Aug 30, 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
6 changes: 3 additions & 3 deletions e2e/harmony/checkout-harmony.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as path from 'path';
import { MissingBitMapComponent } from '../../src/consumer/bit-map/exceptions';
import { NewerVersionFound } from '../../src/consumer/exceptions';
import Helper, { FileStatusWithoutChalk } from '../../src/e2e-helper/e2e-helper';
import { FILE_CHANGES_CHECKOUT_MSG } from '../../src/constants';

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

Expand Down Expand Up @@ -362,7 +363,7 @@ describe('bit checkout command', function () {
expect(output).to.have.string('bar/foo');
});
it('should indicate that the file was not changed', () => {
expect(output).to.have.string(FileStatusWithoutChalk.unchanged);
expect(output).to.not.have.string(FILE_CHANGES_CHECKOUT_MSG);
});
it('should leave the file intact', () => {
const fileContent = fs.readFileSync(path.join(helper.scopes.localPath, 'bar/foo.js')).toString();
Expand Down Expand Up @@ -419,8 +420,7 @@ describe('bit checkout command', function () {
output = helper.command.checkoutVersion('0.0.1', 'bar/foo', '--auto-merge-resolve ours');
});
it('should indicate that the new file was not changed', () => {
expect(output).to.have.string(FileStatusWithoutChalk.unchanged);
expect(output).to.have.string('foo2.js');
expect(output).to.not.have.string(FILE_CHANGES_CHECKOUT_MSG);
});
it('should not delete the file', () => {
expect(path.join(helper.scopes.localPath, 'bar/foo2.js')).to.be.a.file();
Expand Down
30 changes: 29 additions & 1 deletion e2e/harmony/lanes/merge-lanes.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ describe('merge lanes', function () {
mergeOutput = helper.command.mergeLane('main', '--resolve-unrelated');
});
it('should merge successfully', () => {
expect(mergeOutput).to.have.string('successfully merged components');
expect(mergeOutput).to.have.string('successfully merged');
});
it('bit status should show the component as staged and not everywhere else', () => {
helper.command.expectStatusToBeClean(['stagedComponents']);
Expand Down Expand Up @@ -1524,4 +1524,32 @@ describe('merge lanes', function () {
});
});
});
describe('multiple files, some are not changes', () => {
let switchOutput: string;
before(() => {
helper.scopeHelper.setNewLocalAndRemoteScopes();
helper.command.createLane('lane-a');
helper.fixtures.populateComponents(1, false);
helper.fs.outputFile('comp1/foo.js');
helper.command.snapAllComponentsWithoutBuild();
helper.command.export();
helper.command.createLane('lane-b');
helper.command.snapAllComponentsWithoutBuild('--unmodified');
helper.command.export();

switchOutput = helper.command.switchLocalLane('lane-a', '-x');
});
it('expect to have all files as unchanged, not updated', () => {
expect(switchOutput).to.not.have.string('updated');
});
describe('merge the lane', () => {
let mergeOutput: string;
before(() => {
mergeOutput = helper.command.mergeLane('lane-b', '-x');
});
it('expect to have all files as unchanged, not updated', () => {
expect(mergeOutput).to.not.have.string('updated');
});
});
});
});
6 changes: 3 additions & 3 deletions e2e/harmony/snap.e2e.2.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import chai, { expect } from 'chai';
import fs from 'fs-extra';
import path from 'path';
import { HASH_SIZE, AUTO_SNAPPED_MSG } from '../../src/constants';
import { HASH_SIZE, AUTO_SNAPPED_MSG, FILE_CHANGES_CHECKOUT_MSG } from '../../src/constants';
import ComponentsPendingMerge from '../../src/consumer/component-ops/exceptions/components-pending-merge';
import Helper from '../../src/e2e-helper/e2e-helper';
import * as fixtures from '../../src/fixtures/fixtures';
Expand Down Expand Up @@ -266,7 +266,7 @@ describe('bit snap command', function () {
mergeOutput = helper.command.merge('bar/foo --auto-merge-resolve ours');
});
it('should succeed and indicate that the files were not changed', () => {
expect(mergeOutput).to.have.string('unchanged');
expect(mergeOutput).to.not.have.string(FILE_CHANGES_CHECKOUT_MSG);
});
it('should indicate that a component was snapped', () => {
expect(mergeOutput).to.have.string('merge-snapped components');
Expand Down Expand Up @@ -298,7 +298,7 @@ describe('bit snap command', function () {
mergeOutput = helper.command.merge('bar/foo --auto-merge-resolve ours --no-snap');
});
it('should succeed and indicate that the files were not changed', () => {
expect(mergeOutput).to.have.string('unchanged');
expect(mergeOutput).to.not.have.string(FILE_CHANGES_CHECKOUT_MSG);
});
it('should not show a message about merge-snapped components', () => {
expect(mergeOutput).to.not.have.string('merge-snapped components');
Expand Down
3 changes: 1 addition & 2 deletions e2e/harmony/updates-from-main-and-lane.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,7 @@ describe('updates from main and lane', function () {
);
});
it('should update not only components belong to the main but also components that are available on the workspace and have updates from main', () => {
expect(mergeOutput).to.have.string('comp1');
expect(mergeOutput).to.have.string('comp2');
expect(mergeOutput).to.have.string('Total Merged: 2');

const status = helper.command.statusJson(undefined, '--lanes');
expect(status.pendingUpdatesFromMain).to.have.lengthOf(0);
Expand Down
7 changes: 3 additions & 4 deletions scopes/component/checkout/checkout-cmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ once ready, snap/tag the components to persist the changes`;
// @ts-ignore version is defined when !reset
head || latest ? component.id.version : version
)}\n`;
return `${chalk.underline(title)} ${applyVersionReport(components, false)}`;
return chalk.bold(title) + applyVersionReport(components, false);
}
if (reset) {
const title = 'successfully reset the following components\n\n';
Expand All @@ -215,10 +215,9 @@ once ready, snap/tag the components to persist the changes`;
return `version ${chalk.bold(version)}`;
};
const versionOutput = getVerOutput();
const title = `successfully ${switchedOrReverted} the following components to ${versionOutput}\n\n`;
const title = `successfully ${switchedOrReverted} ${components.length} components to ${versionOutput}\n`;
const showVersion = head || reset;
const componentsStr = applyVersionReport(components, true, showVersion);
return chalk.underline(title) + componentsStr;
return chalk.bold(title) + applyVersionReport(components, true, showVersion);
};
const getNewOnLaneOutput = () => {
if (!newFromLane?.length) return '';
Expand Down
13 changes: 10 additions & 3 deletions scopes/component/checkout/checkout-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ export async function applyVersion(
if (componentFromFS && !componentMap) throw new GeneralError('applyVersion: componentMap was not found');

const files = component.files;
files.forEach((file) => {
filesStatus[pathNormalizeToLinux(file.relative)] = FileStatus.updated;
});
updateFileStatus(files, filesStatus, componentFromFS || undefined);

await removeFilesIfNeeded(filesStatus, componentFromFS || undefined);

Expand All @@ -110,6 +108,15 @@ export async function applyVersion(
};
}

export function updateFileStatus(files: SourceFile[], filesStatus: FilesStatus, componentFromFS?: ConsumerComponent) {
files.forEach((file) => {
const fileFromFs = componentFromFS?.files.find((f) => f.relative === file.relative);
const areFilesEqual = fileFromFs && Buffer.compare(fileFromFs.contents, file.contents) === 0;
// @ts-ignore
filesStatus[pathNormalizeToLinux(file.relative)] = areFilesEqual ? FileStatus.unchanged : FileStatus.updated;
});
}

/**
* when files exist on the filesystem but not on the checked out versions, they need to be deleted.
* without this function, these files would be left on the filesystem. (we don't delete the comp-dir before writing).
Expand Down
1 change: 1 addition & 0 deletions scopes/component/checkout/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ export {
ComponentStatusBase,
ApplyVersionWithComps,
removeFilesIfNeeded,
updateFileStatus,
} from './checkout-version';
export { checkoutOutput } from './checkout-cmd';
40 changes: 29 additions & 11 deletions scopes/component/merging/merge-cmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import { Command, CommandOptions } from '@teambit/cli';
import { BitId } from '@teambit/legacy-bit-id';
import { ComponentID } from '@teambit/component-id';
import { compact } from 'lodash';
import { WILDCARD_HELP, AUTO_SNAPPED_MSG, MergeConfigFilename } from '@teambit/legacy/dist/constants';
import {
WILDCARD_HELP,
AUTO_SNAPPED_MSG,
MergeConfigFilename,
FILE_CHANGES_CHECKOUT_MSG,
} from '@teambit/legacy/dist/constants';
import {
FileStatus,
ApplyVersionResult,
Expand Down Expand Up @@ -148,10 +153,12 @@ export function mergeReport({
}: ApplyVersionResults & { configMergeResults?: ConfigMergeResult[] }): string {
const getSuccessOutput = () => {
if (!components || !components.length) return '';
// @ts-ignore version is set in case of merge command
const title = `successfully merged components${version ? `from version ${chalk.bold(version)}` : ''}\n`;
// @ts-ignore components is set in case of merge command
return chalk.underline(title) + chalk.green(applyVersionReport(components));
const title = `successfully merged ${components.length} components${
version ? `from version ${chalk.bold(version)}` : ''
}\n`;
const fileChangesReport = applyVersionReport(components);

return chalk.bold(title) + fileChangesReport;
};

const getConflictSummary = () => {
Expand Down Expand Up @@ -263,13 +270,18 @@ ${mergeSnapError.message}
);
}

/**
* shows only the file-changes section.
* if all files are "unchanged", it returns an empty string
*/
export function applyVersionReport(components: ApplyVersionResult[], addName = true, showVersion = false): string {
const tab = addName ? '\t' : '';
return components
.map((component: ApplyVersionResult) => {
const fileChanges = compact(
components.map((component: ApplyVersionResult) => {
const name = showVersion ? component.id.toString() : component.id.toStringWithoutVersion();
const files = Object.keys(component.filesStatus)
.map((file) => {
const files = compact(
Object.keys(component.filesStatus).map((file) => {
if (component.filesStatus[file] === FileStatus.unchanged) return null;
const note =
component.filesStatus[file] === FileStatus.manual
? chalk.white(
Expand All @@ -278,10 +290,16 @@ export function applyVersionReport(components: ApplyVersionResult[], addName = t
: '';
return `${tab}${component.filesStatus[file]} ${chalk.bold(file)} ${note}`;
})
.join('\n');
).join('\n');
if (!files) return null;
return `${addName ? name : ''}\n${chalk.cyan(files)}`;
})
.join('\n\n');
).join('\n\n');
if (!fileChanges) {
return '';
}
const title = `\n${FILE_CHANGES_CHECKOUT_MSG}\n`;
return chalk.underline(title) + fileChanges;
}

export function conflictSummaryReport(components: ApplyVersionResult[]): string {
Expand Down
6 changes: 2 additions & 4 deletions scopes/component/merging/merging.main.runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
ComponentStatusBase,
applyModifiedVersion,
removeFilesIfNeeded,
updateFileStatus,
} from '@teambit/checkout';
import { ComponentID } from '@teambit/component-id';
import { DEPENDENCIES_FIELDS } from '@teambit/legacy/dist/constants';
Expand Down Expand Up @@ -597,10 +598,7 @@ export class MergingMain {
legacyComponent.version = id.version;
}
const files = legacyComponent.files;
files.forEach((file) => {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
filesStatus[pathNormalizeToLinux(file.relative)] = FileStatus.updated;
});
updateFileStatus(files, filesStatus, currentComponent || undefined);

if (mergeResults) {
// update files according to the merge results
Expand Down
13 changes: 2 additions & 11 deletions scopes/lanes/lanes/switch.cmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,8 @@ ${COMPONENT_PATTERN_HELP}`,
const getSuccessfulOutput = () => {
const laneSwitched = chalk.green(`\nsuccessfully set "${chalk.bold(lane)}" as the active lane`);
if (!components || !components.length) return `No components have been changed.${laneSwitched}`;
if (components.length === 1) {
const component = components[0];
const componentName = component.id.toStringWithoutVersion();
const title = `successfully switched ${chalk.bold(componentName)} to version ${chalk.bold(
component.id.version as string
)}\n`;
return `${title} ${applyVersionReport(components, false)}${laneSwitched}`;
}
const title = `successfully switched the following components to the head of lane ${lane}\n\n`;
const componentsStr = applyVersionReport(components, true, false);
return title + componentsStr + laneSwitched;
const title = `successfully switched ${components.length} components to the head of lane ${lane}\n`;
return chalk.bold(title) + applyVersionReport(components, true, false) + laneSwitched;
};
const failedOutput = getFailureOutput();
const successOutput = getSuccessfulOutput();
Expand Down
2 changes: 1 addition & 1 deletion scopes/lanes/merge-lanes/merge-lanes.main.runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export class MergeLanesMain {
const readmeComponentId = otherLane.readmeComponent.id.changeVersion(otherLane.readmeComponent?.head?.hash);
deleteResults = await this.remove.removeLocallyByIds([readmeComponentId]);
} else if (otherLane && !otherLane.readmeComponent) {
deleteResults = { readmeResult: `\nlane ${otherLane.name} doesn't have a readme component` };
deleteResults = { readmeResult: '' };
}
const configMergeResults = allComponentsStatus.map((c) => c.configMergeResult);

Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,3 +609,5 @@ export enum BuildStatus {
}

export const SOURCE_DIR_SYMLINK_TO_NM = '_src'; // symlink from node_modules to the workspace sources files

export const FILE_CHANGES_CHECKOUT_MSG = 'components with file changes';