Skip to content

Commit

Permalink
enable executing commands on remote components outside of bit-workspa…
Browse files Browse the repository at this point in the history
…ce (#1884)

* implements #1837, enable running "bit list" of a remote scope without a bit-workspace

* allow bit-deprecate and bit-undeprecate to work outside bit-workspace

* change the machine of lint to be medium instead of small (hopefully it will fix the error of "Flow returned an error: Out of retries, exiting!")

* enable remove remote components using wildcards regardless whether the components exist locally

* enable remove components from a remote scope outside of a bit-workspace
  • Loading branch information
davidfirst authored Aug 1, 2019
1 parent 0401d3b commit 5ffb681
Show file tree
Hide file tree
Showing 18 changed files with 300 additions and 90 deletions.
22 changes: 11 additions & 11 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/.ssh
steps:
-
Expand All @@ -47,7 +47,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
steps:
# prod registry
Expand All @@ -70,7 +70,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
# skipping the pre-built binaries to make sure we build them by the pack step
# testing the install script will be done in different workflow dedicated for this
Expand Down Expand Up @@ -112,7 +112,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
steps:
-
Expand All @@ -131,7 +131,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
steps:
-
Expand All @@ -154,7 +154,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
steps:
-
Expand Down Expand Up @@ -206,7 +206,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
steps:
-
Expand All @@ -229,7 +229,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
steps:
-
Expand Down Expand Up @@ -258,7 +258,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
steps:
-
Expand Down Expand Up @@ -287,7 +287,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: medium
working_directory: ~/bit
steps:
-
Expand Down Expand Up @@ -315,7 +315,7 @@ jobs:
docker:
-
image: 'circleci/node:8.12.0'
resource_class: small
resource_class: small
working_directory: ~/bit
environment:
# change the npm config to avoid using sudo
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [unreleased]

- [#1837](/~https://github.com/teambit/bit/issues/1837) enable executing commands on remote components outside of bit-workspace
- [#1774](/~https://github.com/teambit/bit/issues/1774) improve access errors and warn when sudo is used

## [14.2.4-dev.1] - 2019-07-30
Expand Down
3 changes: 2 additions & 1 deletion e2e/e2e-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import { FileStatus } from '../src/consumer/versions-ops/merge-version';
const generateRandomStr = (size: number = 8): string => {
return Math.random()
.toString(36)
.slice(size * -1);
.slice(size * -1)
.replace('.', ''); // it's rare but possible that the first char is '.', which is invalid for a scope-name
};

export default class Helper {
Expand Down
37 changes: 34 additions & 3 deletions e2e/flows/id-with-wildcard.e2e.2.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,46 @@ describe('component id with wildcard', function () {
});
describe('when wildcard does not match any component', () => {
it('should throw an error saying the wildcard does not match any id', () => {
const removeFunc = () => helper.removeComponent('none/* --silent --remote');
const error = new NoIdMatchWildcard(['none/*']);
const removeFunc = () => helper.removeComponent(`${helper.remoteScope}/none/* --silent --remote`);
const error = new NoIdMatchWildcard([`${helper.remoteScope}/none/*`]);
helper.expectToThrow(removeFunc, error);
});
});
describe('when wildcard match some of the components', () => {
let output;
before(() => {
output = helper.removeComponent('"utils/fs/*" --silent --remote');
output = helper.removeComponent(`${helper.remoteScope}/utils/fs/* --silent --remote`);
});
it('should indicate the removed components', () => {
expect(output).to.have.string('utils/fs/read');
expect(output).to.have.string('utils/fs/write');
});
it('should remove only the matched components', () => {
const ls = helper.listRemoteScopeParsed();
expect(ls).to.have.lengthOf(3);
});
});
});
describe('remove from remote with wildcard after removed locally', () => {
before(() => {
helper.getClonedLocalScope(scopeAfterAdd);
helper.reInitRemoteScope();
helper.tagAllComponents();
helper.exportAllComponents();
helper.removeComponent(`${helper.remoteScope}/* -s`);

// as an intermediate step, make sure the remote scope has all components
const ls = helper.listRemoteScopeParsed();
expect(ls).to.have.lengthOf(5);

// as an intermediate step, make sure the local scope does not have any components
const lsLocal = helper.listLocalScopeParsed();
expect(lsLocal).to.have.lengthOf(0);
});
describe('when wildcard match some of the components', () => {
let output;
before(() => {
output = helper.removeComponent(`${helper.remoteScope}/utils/fs/* --silent --remote`);
});
it('should indicate the removed components', () => {
expect(output).to.have.string('utils/fs/read');
Expand Down
83 changes: 83 additions & 0 deletions e2e/flows/remote-commands-outside-workspace.e2e.2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { expect } from 'chai';
import Helper from '../e2e-helper';
import { ConsumerNotFound } from '../../src/consumer/exceptions';

describe('bit remote command', function () {
this.timeout(0);
const helper = new Helper();
after(() => {
helper.destroyEnv();
});
describe('exporting a component to a global remote', () => {
before(() => {
helper.reInitLocalScope();
helper.reInitRemoteScope();
helper.runCmd(`bit remote add file://${helper.remoteScopePath} --global`);
helper.createComponentBarFoo();
helper.addComponentBarFoo();
helper.tagAllComponents();
helper.exportAllComponents();
helper.cleanLocalScope();
});
after(() => {
helper.runCmd(`bit remote del ${helper.remoteScope} --global`);
});
it('bit status should throw an error ConsumerNotFound', () => {
const error = new ConsumerNotFound();
const func = () => helper.status();
helper.expectToThrow(func, error);
});
it('bit list without --remote flag should throw an error ConsumerNotFound', () => {
const error = new ConsumerNotFound();
const func = () => helper.listLocalScope();
helper.expectToThrow(func, error);
});
it('bit list with --remote flag should list the global remote successfully', () => {
const output = helper.listRemoteScope();
expect(output).to.have.string('found 1 components');
});
it('bit show should show the component and not throw an error about missing workspace', () => {
const output = helper.showComponent(`${helper.remoteScope}/bar/foo --remote`);
expect(output).to.have.string('bar/foo');
});
describe('bit deprecate with --remote flag', () => {
let output;
before(() => {
output = helper.deprecateComponent(`${helper.remoteScope}/bar/foo`, '--remote');
});
it('should not throw an error', () => {
expect(output).to.have.string('deprecated components');
});
it('should deprecate successfully', () => {
const list = helper.listRemoteScopeParsed();
expect(list[0].deprecated).to.be.true;
});
describe('bit undeprecate with --remote flag', () => {
let undeprecateOutput;
before(() => {
undeprecateOutput = helper.undeprecateComponent(`${helper.remoteScope}/bar/foo`, '--remote');
});
it('should not throw an error', () => {
expect(undeprecateOutput).to.have.string('undeprecated components');
});
it('should deprecate successfully', () => {
const list = helper.listRemoteScopeParsed();
expect(list[0].deprecated).to.be.false;
});
});
});
describe('bit remove with --remote flag', () => {
let output;
before(() => {
output = helper.removeComponent(`${helper.remoteScope}/bar/foo`, '--silent --remote');
});
it('should not throw an error', () => {
expect(output).to.have.string('successfully removed');
});
it('should remove successfully', () => {
const list = helper.listRemoteScopeParsed();
expect(list).to.have.lengthOf(0);
});
});
});
});
2 changes: 1 addition & 1 deletion src/api/consumer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import init from './lib/init';
import isolate from './lib/isolate';
import remove from './lib/remove';
import { deprecate, undeprecate } from './lib/deprecation';
import listScope from './lib/list-scope';
import { listScope } from './lib/list-scope';
import { tagAction, tagAllAction } from './lib/tag';
import status from './lib/status';
import { build, buildAll } from './lib/build';
Expand Down
51 changes: 40 additions & 11 deletions src/api/consumer/lib/deprecation.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,54 @@
/** @flow */
import { loadConsumer, Consumer } from '../../../consumer';
import { loadConsumer, loadConsumerIfExist, Consumer } from '../../../consumer';
import loader from '../../../cli/loader';
import { BEFORE_REMOTE_DEPRECATE, BEFORE_REMOTE_UNDEPRECATE } from '../../../cli/loader/loader-messages';
import { BitId } from '../../../bit-id';
import {
deprecateRemote,
deprecateMany,
undeprecateRemote,
undeprecateMany
} from '../../../scope/component-ops/components-deprecation';
import { Remotes } from '../../../remotes';
import { getScopeRemotes } from '../../../scope/scope-remotes';
import BitIds from '../../../bit-id/bit-ids';

export async function deprecate({ ids, remote }: { ids: string[], remote: boolean }): Promise<any> {
if (remote) loader.start(BEFORE_REMOTE_DEPRECATE);
if (remote) {
loader.start(BEFORE_REMOTE_DEPRECATE);
const consumer = await loadConsumerIfExist();
const bitIds = getBitIdsForRemote(ids);
const remotes = await getRemotes(consumer);
const scope = consumer ? consumer.scope : null;
return deprecateRemote(remotes, scope, bitIds);
}
const consumer = await loadConsumer();
const bitIds = getBitIds(ids, remote, consumer);
return consumer.deprecate(bitIds, remote);
const bitIds = getBitIdsForLocal(ids, consumer);
return deprecateMany(consumer.scope, bitIds);
}

export async function undeprecate({ ids, remote }: { ids: string[], remote: boolean }): Promise<any> {
if (remote) loader.start(BEFORE_REMOTE_UNDEPRECATE);
if (remote) {
loader.start(BEFORE_REMOTE_UNDEPRECATE);
const consumer = await loadConsumerIfExist();
const bitIds = getBitIdsForRemote(ids);
const remotes = await getRemotes(consumer);
const scope = consumer ? consumer.scope : null;
return undeprecateRemote(remotes, scope, bitIds);
}
const consumer = await loadConsumer();
const bitIds = getBitIds(ids, remote, consumer);
return consumer.undeprecate(bitIds, remote);
const bitIds = getBitIdsForLocal(ids, consumer);
return undeprecateMany(consumer.scope, bitIds);
}

function getBitIds(ids: string[], remote: boolean, consumer: Consumer): BitId[] {
return ids.map((id) => {
return remote ? BitId.parse(id, true) : consumer.getParsedId(id);
});
function getRemotes(consumer: ?Consumer): Promise<Remotes> {
return consumer ? getScopeRemotes(consumer.scope) : Remotes.getGlobalRemotes();
}

function getBitIdsForLocal(ids: string[], consumer: Consumer): BitIds {
return BitIds.fromArray(ids.map(id => consumer.getParsedId(id)));
}

function getBitIdsForRemote(ids: string[]): BitId[] {
return ids.map(id => BitId.parse(id, true));
}
Loading

0 comments on commit 5ffb681

Please sign in to comment.