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

Harmony/merge master #2314

Merged
merged 6 commits into from
Feb 9, 2020
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [unreleased]

- support configuring the logger level by running `bit config set log_level <level>`.
- [#2268](https://github.com/teambit/bit/issues/2268) prevent logger from holding the terminal once a command is completed

## [[14.7.5-dev.1] - 2020-02-06]

- [#2211](https://github.com/teambit/bit/issues/2211) fix bit export to not export non-staged dependencies
- [#2308](https://github.com/teambit/bit/issues/2308) fix "Cannot read property 'scope' of undefined" error on bit export

## [[14.7.4] - 2020-02-06](https://github.com/teambit/bit/releases/tag/v14.7.4)

- [#2300](https://github.com/teambit/bit/issues/2300) improve `bit export` performance by pushing new tags only
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ In some cases, you might get very helpful info by prefixing Bit command with `BI

To print the log messages on the console, prefix your command with `BIT_LOG=<debug-level>`, e.g. `BIT_LOG=error`.

The log level written to the log file is by default "debug". To change it, run `bit config set log_level <level>`, e.g. `bit config set log_level silly`.

### Lint

Run eslint and tsc (for type checking)
Expand Down
33 changes: 33 additions & 0 deletions e2e/commands/export.e2e.1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,39 @@ describe('bit export command', function() {
expect(output).to.have.string(`${anotherRemote}/foo2`);
});
});
// fixes https://github.com/teambit/bit/issues/2308
// here, the component foo1 has a new dependency "bar", this dependency has been exported
// already, so we expect "bit export" to not attempt to export it.
describe('export with no ids, no remote and no flags when a dependency is from another collection', () => {
let output;
before(() => {
helper.scopeHelper.getClonedLocalScope(localScopeBefore);
helper.scopeHelper.getClonedRemoteScope(remoteScopeBefore);
helper.scopeHelper.getClonedScope(anotherRemoteScopeBefore, anotherRemotePath);
const { scopeName, scopePath } = helper.scopeHelper.getNewBareScope();
helper.scopeHelper.addRemoteScope(scopePath);
helper.scopeHelper.addRemoteScope(scopePath, helper.scopes.remotePath);
helper.fs.outputFile('bar.js', '');
helper.command.addComponent('bar.js');
helper.fs.outputFile('foo1.js', 'require("./bar");');
helper.command.tagAllComponents();
helper.command.exportComponent('bar', scopeName);
output = helper.command.runCmd('bit export');
});
it('should export successfully all ids, each to its own remote', () => {
const remoteList = helper.command.listRemoteScopeParsed();
expect(remoteList).to.have.lengthOf(1);
expect(remoteList[0].id).to.have.string('foo1');

const anotherRemoteListJson = helper.command.runCmd(`bit list ${anotherRemote} --json`);
const anotherRemoteList = JSON.parse(anotherRemoteListJson);
expect(anotherRemoteList).to.have.lengthOf(1);
expect(anotherRemoteList[0].id).to.have.string('foo2');
});
it('should not export the dependency that was not intended to be exported', () => {
expect(output).to.not.have.string('bar');
});
});
describe('export with ids, no remote and the flag --last-scope', () => {
let output;
before(() => {
Expand Down
2 changes: 1 addition & 1 deletion e2e/commands/link.e2e.1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('bit link', function() {
).to.be.a.directory();
});
});
describe('when scopeDefault is overridden for this component', () => {
describe('when defaultScope is overridden for this component', () => {
let linkOutput;
before(() => {
helper.scopeHelper.getClonedLocalScope(beforeLink);
Expand Down
51 changes: 51 additions & 0 deletions e2e/functionalities/default-scope.e2e.2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import chai, { expect } from 'chai';
import Helper from '../../src/e2e-helper/e2e-helper';

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

describe('default scope functionality', function() {
this.timeout(0);
const helper = new Helper();
after(() => {
helper.scopeHelper.destroy();
});
describe('basic flow', () => {
helper.scopeHelper.setNewLocalAndRemoteScopes();
helper.fixtures.populateWorkspaceWithThreeComponentsAndModulePath();
helper.bitJson.addDefaultScope();
helper.command.runCmd('bit link');
});
it('bit status should not break', () => {
const status = helper.command.statusJson();
expect(status.newComponents).have.lengthOf(3);
expect(status.invalidComponents).have.lengthOf(0);
});
describe('tagging the components', () => {
let tagOutput;
before(() => {
tagOutput = helper.command.tagAllComponents();
});
it('should be able to to tag them successfully', () => {
expect(tagOutput).to.have.string('tagged');
});
it('bit status should not show any issue', () => {
const status = helper.command.statusJson();
expect(status.stagedComponents).have.lengthOf(3);
expect(status.newComponents).have.lengthOf(0);
expect(status.modifiedComponent).have.lengthOf(0);
expect(status.invalidComponents).have.lengthOf(0);
});
describe('exporting the components', () => {
before(() => {
helper.command.exportAllComponents();
});
it('should be able to export them all successfully', () => {
const status = helper.command.statusJson();
expect(status.stagedComponents).have.lengthOf(0);
expect(status.newComponents).have.lengthOf(0);
expect(status.modifiedComponent).have.lengthOf(0);
expect(status.invalidComponents).have.lengthOf(0);
});
});
});
});
8 changes: 7 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bit-bin",
"version": "14.7.4",
"version": "14.7.5-dev.1",
"license": "Apache-2.0",
"main": "./dist/api.js",
"preferGlobal": true,
Expand Down Expand Up @@ -203,6 +203,7 @@
"@babel/preset-env": "^7.7.7",
"@babel/preset-typescript": "^7.7.7",
"@babel/register": "^7.4.4",
"@types/bluebird": "^3.5.29",
"@types/chai": "^4.2.5",
"@types/chai-arrays": "^1.0.3",
"@types/chai-fs": "^2.0.2",
Expand Down
6 changes: 3 additions & 3 deletions src/api/consumer/lib/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ export default (async function migrate(
scopePath: string,
verbose: boolean
): Promise<MigrationResult | null | undefined> {
logger.debug('migrate.migrate, starting migration process');
logger.silly('migrate.migrate, starting migration process');
if (verbose) console.log('starting migration process'); // eslint-disable-line no-console
let scope;
// If a scope path provided we will run the migrate only for the scope
if (scopePath) {
logger.debug(`migrate.migrate, running migration process for scope in path ${scopePath}`);
logger.silly(`migrate.migrate, running migration process for scope in path ${scopePath}`);
if (verbose) console.log(`running migration process for scope in path ${scopePath}`); // eslint-disable-line no-console
scope = await loadScope(scopePath);
return scope.migrate(verbose);
Expand All @@ -34,7 +34,7 @@ export default (async function migrate(
await consumer.migrate(verbose);
// const consumerMigrationResult = await consumer.migrate(verbose);
// if (!consumerMigrationResult)
logger.debug('migrate.migrate, running migration process for scope in consumer');
logger.silly('migrate.migrate, running migration process for scope in consumer');
if (verbose) console.log('running migration process for scope in consumer'); // eslint-disable-line no-console
return scope.migrate(verbose);
});
4 changes: 2 additions & 2 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'reflect-metadata';
import * as BPromise from 'bluebird';
import Bluebird from 'bluebird';
import { Harmony } from './harmony';
import HooksManager from './hooks';
import { BitCliExt } from './extensions/cli';
Expand All @@ -12,7 +12,7 @@ process.env.MEMFS_DONT_WARN = 'true'; // suppress fs experimental warnings from

// removing this, default to longStackTraces also when env is `development`, which impacts the
// performance dramatically. (see http://bluebirdjs.com/docs/api/promise.longstacktraces.html)
BPromise.config({
Bluebird.config({
longStackTraces: true
});

Expand Down
3 changes: 2 additions & 1 deletion src/bit-id/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ That's the preferable representation of BitId. Wherever possible, use this forma
A string representation of BitId. `BitId.toString()` generates this string.
For example: `my-scope/[email protected]`.
When an ID is entered by the end user it's always a string.
The problem with the string representation is that since the dynamic-namespace introduced, it's not clear from the string whether an ID has a scope or not. In the previous example, `my-scope/my-name` could be interpreted as a scopereadonly name or only a name.
The problem with the string representation is that since the dynamic-namespace introduced, it's not clear from the string whether an ID has a scope or not.
In the previous example, `my-scope/my-name` could be interpreted as an id with scope (`{ scope: 'my-scope', name: 'my-name' }`) or an id without a scope (`{ scope: null, name: 'my-scope/my-name' }`).
See the next section how to safely parse the string.

## How to transform a Bit ID string to a BitId instance
Expand Down
4 changes: 4 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ export const CFG_GIT_EXECUTABLE_PATH = 'git_path';

export const CFG_LOG_JSON_FORMAT = 'log_json_format';

export const CFG_LOG_LEVEL = 'log_level';

export const CFG_NO_WARNINGS = 'no_warnings';

export const CFG_INTERACTIVE = 'interactive';
Expand Down Expand Up @@ -403,3 +405,5 @@ export const DEPENDENCIES_FIELDS = ['dependencies', 'devDependencies', 'peerDepe
const MISSING_DEPS_SPACE_COUNT = 10;
export const MISSING_DEPS_SPACE = ' '.repeat(MISSING_DEPS_SPACE_COUNT);
export const MISSING_NESTED_DEPS_SPACE = ' '.repeat(MISSING_DEPS_SPACE_COUNT + 2);

export const CONCURRENT_IO_LIMIT = 100; // limit number of files to read/write/delete/symlink at the same time
1 change: 0 additions & 1 deletion src/consumer/component/package-json-vinyl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export default class PackageJsonVinyl extends AbstractVinyl {
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
logger.debug(`package-json-vinyl.write, path ${this.path}`);
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
await fs.outputFile(this.path, this.contents);
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return this.path;
Expand Down
8 changes: 5 additions & 3 deletions src/consumer/component/sources/data-to-persist.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as path from 'path';
import Bluebird from 'bluebird';
import fs from 'fs-extra';
import { ComponentCapsule } from '../../../extensions/capsule-ext';
import AbstractVinyl from './abstract-vinyl';
import Symlink from '../../../links/symlink';
import logger from '../../../logger/logger';
import RemovePath from './remove-path';
import removeFilesAndEmptyDirsRecursively from '../../../utils/fs/remove-files-and-empty-dirs-recursively';
import { CONCURRENT_IO_LIMIT as concurrency } from '../../../constants';

export default class DataToPersist {
files: AbstractVinyl[];
Expand Down Expand Up @@ -161,18 +163,18 @@ export default class DataToPersist {
return dataToPersist;
}
async _persistFilesToFS() {
return Promise.all(this.files.map(file => file.write()));
return Bluebird.map(this.files, file => file.write(), { concurrency });
}
async _persistSymlinksToFS() {
return Promise.all(this.symlinks.map(symlink => symlink.write()));
return Bluebird.map(this.symlinks, symlink => symlink.write(), { concurrency });
}
async _deletePathsFromFS() {
const pathWithRemoveItsDirIfEmptyEnabled = this.remove.filter(p => p.removeItsDirIfEmpty).map(p => p.path);
const restPaths = this.remove.filter(p => !p.removeItsDirIfEmpty);
if (pathWithRemoveItsDirIfEmptyEnabled.length) {
await removeFilesAndEmptyDirsRecursively(pathWithRemoveItsDirIfEmptyEnabled);
}
return Promise.all(restPaths.map(removePath => removePath.persistToFS()));
return Bluebird.map(restPaths, removePath => removePath.persistToFS(), { concurrency });
}
_validateAbsolute() {
// it's important to make sure that all paths are absolute before writing them to the
Expand Down
42 changes: 14 additions & 28 deletions src/consumer/consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import { AutoTagResult } from '../scope/component-ops/auto-tag';
import ShowDoctorError from '../error/show-doctor-error';
import { EnvType } from '../legacy-extensions/env-extension-types';
import loadFlattenedDependenciesForCapsule from './component-ops/load-flattened-dependencies';
import { packageNameToComponentId } from '../utils/bit/package-name-to-component-id';

type ConsumerProps = {
projectPath: string;
Expand Down Expand Up @@ -240,7 +241,7 @@ export default class Consumer {
const bitmapVersion = this.bitMap.version || '0.10.9';

if (semver.gte(bitmapVersion, BIT_VERSION)) {
logger.debug('bit.map version is up to date');
logger.silly('bit.map version is up to date');
return {
run: false
};
Expand Down Expand Up @@ -711,34 +712,19 @@ export default class Consumer {

getComponentIdFromNodeModulesPath(requirePath: string, bindingPrefix: string): BitId {
requirePath = pathNormalizeToLinux(requirePath);
// Temp fix to support old components before the migration has been running
bindingPrefix = bindingPrefix === 'bit' ? '@bit' : bindingPrefix;
const prefix = requirePath.includes('node_modules') ? `node_modules/${bindingPrefix}/` : `${bindingPrefix}/`;
const withoutPrefix = requirePath.substr(requirePath.indexOf(prefix) + prefix.length);
const componentName = withoutPrefix.includes('/')
? withoutPrefix.substr(0, withoutPrefix.indexOf('/')) // the part after the first slash is the path inside the package
: withoutPrefix;
const pathSplit = componentName.split(NODE_PATH_COMPONENT_SEPARATOR);
if (pathSplit.length < 2) throw new GeneralError(`component has an invalid require statement: ${requirePath}`);
// since the dynamic namespaces feature introduced, the require statement doesn't have a fixed
// number of separators.
// also, a scope name may or may not include a dot. depends whether it's on bitHub or self hosted.
// we must check against BitMap to get the correct scope and name of the id.
if (pathSplit.length === 2) {
return new BitId({ scope: pathSplit[0], name: pathSplit[1] });
const prefix = requirePath.includes('node_modules') ? 'node_modules/' : '';
const withoutPrefix = prefix ? requirePath.substr(requirePath.indexOf(prefix) + prefix.length) : requirePath;

if (!withoutPrefix.includes('/')) {
throw new GeneralError(
'getComponentIdFromNodeModulesPath expects the path to have at least one slash for the scoped package, such as @bit/'
);
}
const mightBeScope = R.head(pathSplit);
const mightBeName = R.tail(pathSplit).join('/');
const mightBeId = new BitId({ scope: mightBeScope, name: mightBeName });
const allBitIds = this.bitMap.getAllBitIds();
if (allBitIds.searchWithoutVersion(mightBeId)) return mightBeId;
// only bit hub has the concept of having the username in the scope name.
if (bindingPrefix !== 'bit' && bindingPrefix !== '@bit') return mightBeId;
// pathSplit has 3 or more items. the first two are the scope, the rest is the name.
// for example "user.scopeName.utils.is-string" => scope: user.scopeName, name: utils/is-string
const scope = pathSplit.splice(0, 2).join('.');
const name = pathSplit.join('/');
return new BitId({ scope, name });
const packageSplitBySlash = withoutPrefix.split('/');
// the part after the second slash is the path inside the package, just ignore it.
// (e.g. @bit/my-scope.my-name/internal-path.js).
const packageName = `${packageSplitBySlash[0]}/${packageSplitBySlash[1]}`;
return packageNameToComponentId(this, packageName, bindingPrefix);
}

composeRelativeComponentPath(bitId: BitId): string {
Expand Down
3 changes: 3 additions & 0 deletions src/e2e-helper/e2e-bit-json-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export default class BitJsonHelper {
bitJson.overrides = overrides;
this.write(bitJson);
}
addDefaultScope(scope = this.scopes.remote) {
this.addKeyVal(undefined, 'defaultScope', scope);
}
getEnvByType(bitJson: Record<string, any>, envType: 'compiler' | 'tester') {
const basePath = ['env', envType];
const env = R.path(basePath, bitJson);
Expand Down
9 changes: 9 additions & 0 deletions src/e2e-helper/e2e-fixtures-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ export default class FixtureHelper {
this.addComponentBarFoo();
}

populateWorkspaceWithThreeComponentsAndModulePath() {
this.fs.createFile('utils', 'is-type.js', fixtures.isType);
this.addComponentUtilsIsType();
this.fs.createFile('utils', 'is-string.js', fixtures.isStringModulePath(this.scopes.remote));
this.addComponentUtilsIsString();
this.createComponentBarFoo(fixtures.barFooModulePath(this.scopes.remote));
this.addComponentBarFoo();
}

/**
* @deprecated use populateWorkspaceWithThreeComponents()
*/
Expand Down
2 changes: 1 addition & 1 deletion src/jsdoc/jsdoc/jsdoc-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default async function parse(data: string, filePath?: PathOsBased): Promi
docs.forEach(doc => extractDataRegex(doc, doclets, filePath));
} catch (e) {
// never mind, ignore the doc of this source
logger.debug(`failed parsing docs using on path ${filePath} with error`, e);
logger.silly(`failed parsing docs using on path ${filePath} with error`, e);
}
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
return doclets.filter(doclet => doclet.access === 'public');
Expand Down
2 changes: 1 addition & 1 deletion src/jsdoc/react/react-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export default async function parse(data: string, filePath?: PathOsBased): Promi
return formatted;
}
} catch (err) {
logger.debug(`failed parsing docs using docgen on path ${filePath} with error`, err);
logger.silly(`failed parsing docs using docgen on path ${filePath} with error`, err);
}
return undefined;
}
Loading