diff --git a/e2e/commands/import.e2e.js b/e2e/commands/import.e2e.js index 1ca88783f331..cdcda501e93a 100644 --- a/e2e/commands/import.e2e.js +++ b/e2e/commands/import.e2e.js @@ -13,9 +13,9 @@ describe('bit import', function () { this.timeout(0); const helper = new Helper(); - after(() => { + /* after(() => { helper.destroyEnv(); - }); + }); */ const isTypeFixture = "module.exports = function isType() { return 'got is-type'; };"; const isStringFixture = @@ -1810,7 +1810,64 @@ describe('bit import', function () { }); }); }); - + describe('import component with dependencies with yarn workspaces', () => { + let dependencies; + before(() => { + helper.setNewLocalAndRemoteScopes(); + dependencies = path.join( + helper.localScopePath, + 'components', + '.dependencies', + 'global', + 'simple', + helper.remoteScope, + '0.0.1' + ); + helper.addNpmPackage('lodash.isboolean', '3.0.0'); + const simpleFixture = 'import a from "lodash.isboolean"; '; + helper.createFile('global', 'simple.js', simpleFixture); + helper.addComponentWithOptions('global/simple.js', { i: 'global/simple' }); + helper.commitComponent('simple'); + helper.exportComponent('simple'); + helper.addNpmPackage('lodash.isstring', '4.0.0'); + const withDepsFixture = 'import a from "./global/simple.js"; import c from "lodash.isstring"'; + helper.createFile('', 'with-deps.js', withDepsFixture); + helper.addComponentWithOptions('with-deps.js', { i: 'comp/with-deps' }); + helper.commitAllComponents(); + helper.exportComponent('comp/with-deps'); + helper.reInitLocalScope(); + helper.createPackageJson(); + helper.addRemoteScope(helper.remoteScopePath); + helper.changePackageManagerToYarn(); + helper.importComponent('comp/with-deps'); + }); + it('should install component dependencie as separate packages with yarn workspaces', () => { + expect(dependencies).to.be.a.directory('should not be empty').and.not.empty; + }); + it('Should contain yarn lock file', () => { + expect(path.join(helper.localScopePath, 'yarn.lock')).to.be.a.file('no yarn lock file'); + }); + it('should install global/simple package dependencies with yarn', () => { + expect(path.join(helper.localScopePath, 'node_modules')).to.be.a.directory('should not be empty').and.not.empty; + expect(path.join(helper.localScopePath, 'node_modules', 'lodash.isboolean')).to.be.a.directory( + 'should contain lodash.isboolean' + ).and.not.empty; + }); + it('should contain workspaces array in package.json and private true', () => { + const pkgJson = helper.readPackageJson(helper.localScopePath); + expect(pkgJson.workspaces).to.include('components/.dependencies/*/*/*/*', 'components/*/*'); + expect(pkgJson.private).to.be.true; + }); + it('component dep should be install as npm package', () => { + const modulePath = path.join( + helper.localScopePath, + 'node_modules', + '@bit', + `${helper.remoteScope}.global.simple` + ); + expect(modulePath).to.be.a.directory('should contain component dep as npm package dep').and.not.empty; + }); + }); describe.skip('Import compiler', () => { before(() => { helper.reInitLocalScope(); diff --git a/e2e/e2e-helper.js b/e2e/e2e-helper.js index 647f253829e3..29f81aa7056f 100644 --- a/e2e/e2e-helper.js +++ b/e2e/e2e-helper.js @@ -64,6 +64,24 @@ export default class Helper { return fs.readJSONSync(bitJsonPath) || {}; } + createPackageJson( + name: string = 'test', + version: string = '0.0.1', + packageJsonPath: string = path.join(this.localScopePath, 'package.json') + ) { + const packageJson = { name, version }; + fs.writeJSONSync(packageJsonPath, packageJson); + } + changePackageManagerToYarn( + withWorkspaces: boolean = true, + bitJsonPath: string = path.join(this.localScopePath, 'bit.json') + ) { + const bitJson = this.readBitJson(bitJsonPath); + bitJson.packageManager = 'yarn'; + bitJson.manageWorkspaces = withWorkspaces; + this.writeBitJson(bitJson); + } + readPackageJson(packageJsonFolder: string = this.localScopePath) { const packageJsonPath = path.join(packageJsonFolder, 'package.json'); return fs.readJSONSync(packageJsonPath) || {}; diff --git a/package.json b/package.json index a632b8a0b30b..d5b84d00c545 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "dependencies": { "array-difference": "^0.0.1", "babel-runtime": "^6.23.0", - "bit-javascript": "0.10.8-dev.10", + "bit-javascript": "0.10.8-dev.11", "buffer-from": "^0.1.1", "chalk": "^2.1.0", "chokidar": "^1.7.0", diff --git a/src/constants.js b/src/constants.js index f2fc980e3dd9..4847ed213491 100644 --- a/src/constants.js +++ b/src/constants.js @@ -274,6 +274,10 @@ export const BIT_CACHE_DIRNAME = 'cache'; export const LATEST_TESTED_MARK = '*'; +export const BIT_DEPENDECIES_REGEX = '/*/*/*/*'; + +export const YARN_WORKSPACES_REGEX = '*'; + export const SCOPE_JSON = 'scope.json'; export const DEFAULT_RESOLVER = () => ''; diff --git a/src/consumer/bit-json/consumer-bit-json.js b/src/consumer/bit-json/consumer-bit-json.js index 4a9fc9c9674e..b490b4b2a162 100644 --- a/src/consumer/bit-json/consumer-bit-json.js +++ b/src/consumer/bit-json/consumer-bit-json.js @@ -36,7 +36,8 @@ type consumerBitJsonProps = { packageManager?: 'npm' | 'yarn', packageManagerArgs?: string[], packageManagerProcessOptions?: Object, - useWorkspaces?: boolean + useWorkspaces?: boolean, + manageWorkspaces?: boolean }; export default class ConsumerBitJson extends AbstractBitJson { @@ -51,6 +52,7 @@ export default class ConsumerBitJson extends AbstractBitJson { packageManagerArgs: ?(string[]); // package manager client to use packageManagerProcessOptions: ?Object; // package manager process options useWorkspaces: boolean; // Enables integration with Yarn Workspaces + manageWorkspaces: boolean; // manage workspaces with yarn constructor({ impl, @@ -69,7 +71,8 @@ export default class ConsumerBitJson extends AbstractBitJson { packageManager = DEFAULT_PACKAGE_MANAGER, packageManagerArgs, packageManagerProcessOptions, - useWorkspaces = false + useWorkspaces = false, + manageWorkspaces = true }: consumerBitJsonProps) { super({ impl, spec, compiler, tester, dependencies, lang, bindingPrefix, extensions }); this.distTarget = distTarget; @@ -81,6 +84,7 @@ export default class ConsumerBitJson extends AbstractBitJson { this.packageManagerArgs = packageManagerArgs; this.packageManagerProcessOptions = packageManagerProcessOptions; this.useWorkspaces = useWorkspaces; + this.manageWorkspaces = manageWorkspaces; } toPlainObject() { @@ -92,7 +96,8 @@ export default class ConsumerBitJson extends AbstractBitJson { packageManager: this.packageManager, packageManagerArgs: this.packageManagerArgs, packageManagerProcessOptions: this.packageManagerProcessOptions, - useWorkspaces: this.useWorkspaces + useWorkspaces: this.useWorkspaces, + manageWorkspaces: this.manageWorkspaces }); if (this.distEntry || this.distTarget) { const dist = {}; @@ -145,7 +150,8 @@ export default class ConsumerBitJson extends AbstractBitJson { packageManager, packageManagerArgs, packageManagerProcessOptions, - useWorkspaces + useWorkspaces, + manageWorkspaces } = object; return new ConsumerBitJson({ @@ -164,6 +170,7 @@ export default class ConsumerBitJson extends AbstractBitJson { packageManagerArgs, packageManagerProcessOptions, useWorkspaces, + manageWorkspaces, distTarget: R.propOr(undefined, 'target', dist), distEntry: R.propOr(undefined, 'entry', dist) }); diff --git a/src/consumer/consumer.js b/src/consumer/consumer.js index 8d868564271d..5827b5e8303f 100644 --- a/src/consumer/consumer.js +++ b/src/consumer/consumer.js @@ -22,7 +22,10 @@ import { NODE_PATH_SEPARATOR, LATEST_BIT_VERSION, CFG_REGISTRY_DOMAIN_PREFIX, - DEFAULT_REGISTRY_DOMAIN_PREFIX + DEFAULT_REGISTRY_DOMAIN_PREFIX, + DEFAULT_SEPARATOR, + BIT_DEPENDECIES_REGEX, + YARN_WORKSPACES_REGEX } from '../constants'; import { Scope, ComponentWithDependencies } from '../scope'; import migratonManifest from './migrations/consumer-migrator-manifest'; @@ -480,6 +483,30 @@ export default class Consumer { }); } + /** + * Adds workspace array to package.json - only if user wants to work with yarn workspaces + */ + async addWorkspacesToPackageJson() { + const driver = await this.driver.getDriver(); + const PackageJson = driver.PackageJson; + const pkg = await PackageJson.load(this.getPath(), false); + if (pkg) { + const workSpaces = pkg.workspaces || []; + workSpaces.push(this.bitJson.dependenciesDirectory + BIT_DEPENDECIES_REGEX); + const formatedComponentsPath = format(this.bitJson.componentsDefaultDirectory, { + name: YARN_WORKSPACES_REGEX, + scope: YARN_WORKSPACES_REGEX, + namespace: YARN_WORKSPACES_REGEX + }); + const formatedRegexPath = formatedComponentsPath + .split(DEFAULT_SEPARATOR) + .map(part => (R.contains(YARN_WORKSPACES_REGEX, part) ? YARN_WORKSPACES_REGEX : part)) + .join(DEFAULT_SEPARATOR); + workSpaces.push(formatedRegexPath); + pkg.workspaces = R.uniq(workSpaces); + await pkg.write({ override: true }); + } + } /** * write the components into '/components' dir (or according to the bit.map) and its dependencies in the * '/components/.dependencies' dir. Both directories are configurable in bit.json @@ -603,6 +630,10 @@ export default class Consumer { } }); } + + // add workspaces if flag is true + if (this.bitJson.manageWorkspaces) await this.addWorkspacesToPackageJson(); + await bitMap.write(); if (installNpmPackages) await this.installNpmPackages(componentsWithDependencies, verbose); await this.addComponentsToRootPackageJson(writtenComponents, bitMap);