feat(portal-api): integrate portal-watch (#510)

This commit is contained in:
Sérgio Ramos 2017-06-22 18:09:13 +01:00 committed by Wyatt Preul
parent 8530b24691
commit bc679d6ac6
16 changed files with 705 additions and 468 deletions

View File

@ -101,6 +101,12 @@ api:
- CONSUL=consul
- PORT=3000
- RETHINK_HOST=rethinkdb
- DOCKER_HOST=$DOCKER_HOST
- DOCKER_CERT_PATH=$DOCKER_CERT_PATH
- DOCKER_CLIENT_TIMEOUT=$DOCKER_CLIENT_TIMEOUT
- SDC_URL=$SDC_URL
- SDC_ACCOUNT=$SDC_ACCOUNT
- SDC_KEY_ID=$SDC_KEY_ID
expose:
- 3000

View File

@ -22,6 +22,7 @@
"apollo": "^0.2.2",
"apr-intercept": "^1.0.4",
"constant-case": "^2.0.0",
"force-array": "^3.1.0",
"graphql-tag": "^2.4.0",
"jest-cli": "^20.0.4",
"joyent-manifest-editor": "^1.0.0",

View File

@ -138,6 +138,7 @@ const UiConnect = connect(mapStateToProps, mapDispatchToProps);
const ServicesGql = graphql(ServicesQuery, {
options(props) {
return {
pollInterval: 1000,
variables: {
deploymentGroupSlug: props.match.params.deploymentGroup
}

View File

@ -1,9 +1,17 @@
mutation provisionManifest($deploymentGroupId: ID!, $type: ManifestType!, $format: ManifestFormat!, $raw: String!) {
provisionManifest(deploymentGroupId: $deploymentGroupId, type: $type, format: $format, raw: $raw) {
id
created
type
format
obj
manifestId
scale {
serviceName
replicas
}
plan {
running
actions {
type
service
machines
}
}
}
}

View File

@ -1,4 +1,5 @@
import { createSelector } from 'reselect';
import forceArray from 'force-array';
const apollo = state => state.apollo;
@ -76,7 +77,7 @@ const getService = (service, index, datacenter) => ({
const processServices = (services, datacenter) => {
console.log('services = ', services);
return services.reduce((ss, s, i) => {
return forceArray(services).reduce((ss, s, i) => {
// Check whether it exits in thing, if so, add as child
// if not, create and add as child

View File

@ -53,7 +53,7 @@ type StateConvergencePlan {
type Version {
created: Date! # Either Int or define scalar
manifest: Manifest!
manifestId: ID!
scale(serviceName: String): [ServiceScale]!
plan(running: Boolean): StateConvergencePlan
}
@ -90,6 +90,7 @@ type Service {
parent: ID # parent service id
package: Package! # we don't have this in current mock data,
environment: [Environment]
active: Boolean! # let's say that we update the manifest, and remove a service. we still want to track this service even though it might not exist because it might have machines running still
}
# for metrics max / min (I guess)
@ -190,7 +191,7 @@ type Mutation {
createDeploymentGroup(name: String!) : DeploymentGroup
updateDeploymentGroup(id: ID!, name: String!) : DeploymentGroup
provisionManifest(deploymentGroupId: ID!, type: ManifestType!, format: ManifestFormat!, raw: String!) : Manifest
provisionManifest(deploymentGroupId: ID!, type: ManifestType!, format: ManifestFormat!, raw: String!) : Version
scale(serviceId: ID!, replicas: Int!) : Version
stopServices(ids: [ID]!) : [Service]

View File

@ -4,6 +4,7 @@ const Schema = require('joyent-cp-gql-schema');
const Graphi = require('graphi');
const Piloted = require('piloted');
const PortalData = require('portal-data');
const PortalWatch = require('portal-watch');
const Pack = require('../package.json');
const Resolvers = require('./resolvers');
@ -18,14 +19,22 @@ module.exports = function (server, options, next) {
}
const data = new PortalData(options.data);
const watch = new PortalWatch(Object.assign(options.watch, {
data
}));
data.connect((err) => {
if (err) {
return next(err);
}
server.bind(data);
server.bind(Object.assign(data, {
watch
}));
Piloted.on('refresh', internals.refresh(data));
watch.poll();
server.register([
{

View File

@ -37,6 +37,7 @@
"joyent-cp-gql-schema": "^1.0.4",
"piloted": "^3.1.1",
"portal-data": "^1.1.0",
"portal-watch": "^1.0.0",
"toppsy": "^1.1.0"
}
}

View File

@ -9,6 +9,8 @@ const Toppsy = require('toppsy');
const Vision = require('vision');
const Pack = require('./package');
const Portal = require('./lib');
const Path = require('path');
const Fs = require('fs');
const server = new Hapi.Server();
server.connection({ port: 3000 });
@ -20,11 +22,38 @@ const swaggerOptions = {
}
};
const {
DOCKER_HOST,
DOCKER_CERT_PATH,
DOCKER_CLIENT_TIMEOUT,
SDC_URL,
SDC_ACCOUNT,
SDC_KEY_ID
} = process.env;
const portalOptions = {
data: {
db: {
host: process.env.RETHINK_HOST || 'localhost'
},
docker: {
host: DOCKER_HOST,
ca: DOCKER_CERT_PATH ?
Fs.readFileSync(Path.join(DOCKER_CERT_PATH, 'ca.pem')) :
undefined,
cert: DOCKER_CERT_PATH ?
Fs.readFileSync(Path.join(DOCKER_CERT_PATH, 'cert.pem')) :
undefined,
key: DOCKER_CERT_PATH ?
Fs.readFileSync(Path.join(DOCKER_CERT_PATH, 'key.pem')) :
undefined,
timeout: DOCKER_CLIENT_TIMEOUT
}
},
watch: {
url: SDC_URL,
account: SDC_ACCOUNT,
keyId: SDC_KEY_ID
}
};

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,7 @@ exports.toDeploymentGroup = function ({ name }) {
return {
name,
slug: name,
services: [],
service_ids: [],
version_id: '',
history_version_ids: []
};
@ -57,12 +57,15 @@ exports.fromService = function ({ service, instances, packages }) {
currentMetrics: [],
connections: service.service_dependency_ids,
package: packages ? exports.fromPackage(packages) : {},
parent: service.parent_id || ''
parent: service.parent_id || '',
active: service.active
};
};
exports.toService = function (clientService) {
return {
// wat??
return JSON.parse(JSON.stringify({
id: clientService.id,
version_hash: clientService.hash || clientService.name,
deployment_group_id: clientService.deploymentGroupId,
name: clientService.name,
@ -71,8 +74,9 @@ exports.toService = function (clientService) {
instance_ids: clientService.instances ? clientService.instances.map((instance) => { return instance.id; }) : [],
service_dependency_ids: clientService.connections || [],
package_id: clientService.package ? clientService.package.id : '',
parent_id: clientService.parent || ''
};
parent_id: clientService.parent || '',
active: clientService.ative
}));
};
@ -81,7 +85,7 @@ exports.toVersion = function (clientVersion) {
id: clientVersion.id,
created: clientVersion.created || Date.now(),
manifest_id: clientVersion.manifestId,
service_scales: clientVersion.scales ? clientVersion.scales.map(exports.toScale) : [],
service_scales: clientVersion.scale ? clientVersion.scale.map(exports.toScale) : [],
plan: exports.toPlan(clientVersion.plan || {})
};
};
@ -91,7 +95,7 @@ exports.fromVersion = function (version) {
id: version.id,
created: version.created,
manifestId: version.manifest_id,
scales: version.service_scales ? version.service_scales.map(exports.fromScale) : [],
scale: version.service_scales ? version.service_scales.map(exports.fromScale) : [],
plan: exports.fromPlan(version.plan || {})
};
};

View File

@ -19,6 +19,7 @@
"docker-compose-client": "^1.0.8",
"dockerode": "^2.5.0",
"hoek": "^4.1.1",
"param-case": "^2.1.1",
"penseur": "^7.12.3",
"vasync": "^1.6.4",
"yamljs": "^0.2.10"

View File

@ -253,7 +253,7 @@ describe('versions', () => {
const clientVersion = {
deploymentGroupId: deploymentGroup.id,
manifestId: manifest.id,
scales: [{
scale: [{
serviceName: 'consul',
replicas: 3
}],
@ -270,7 +270,7 @@ describe('versions', () => {
data.createVersion(clientVersion, (err, result) => {
expect(err).to.not.exist();
expect(result.id).to.exist();
expect(result.scales).to.equal(clientVersion.scales);
expect(result.scale).to.equal(clientVersion.scale);
done();
});
});
@ -299,7 +299,7 @@ describe('versions', () => {
const clientVersion = {
manifestId: manifest.id,
deploymentGroupId: deploymentGroup.id,
scales: [{
scale: [{
serviceName: 'consul',
replicas: 3
}],
@ -316,7 +316,7 @@ describe('versions', () => {
data.createVersion(clientVersion, (err, result) => {
expect(err).to.not.exist();
expect(result.id).to.exist();
expect(result.scales).to.equal(clientVersion.scales);
expect(result.scale).to.equal(clientVersion.scale);
data.getVersion({ id: result.id }, (err, retrievedVersion1) => {
expect(err).to.not.exist();
expect(retrievedVersion1.id).to.equal(result.id);
@ -353,7 +353,7 @@ describe('versions', () => {
const clientVersion = {
manifestId: manifest.id,
deploymentGroupId: deploymentGroup.id,
scales: [{
scale: [{
serviceName: 'consul',
replicas: 3
}],
@ -370,7 +370,7 @@ describe('versions', () => {
data.createVersion(clientVersion, (err, result) => {
expect(err).to.not.exist();
expect(result.id).to.exist();
expect(result.scales).to.equal(clientVersion.scales);
expect(result.scale).to.equal(clientVersion.scale);
data.getVersions({ manifestId: clientVersion.manifestId }, (err, versions) => {
expect(err).to.not.exist();
expect(versions.length).to.equal(1);
@ -401,7 +401,7 @@ describe('versions', () => {
const clientVersion = {
manifestId: manifest.id,
deploymentGroupId: deploymentGroup.id,
scales: [{
scale: [{
serviceName: 'consul',
replicas: 3
}],
@ -695,7 +695,7 @@ describe.skip('scale()', () => {
data.scale({ id: deploymentGroupServices[0].id, replicas: 3 }, (err, version) => {
expect(err).to.not.exist();
expect(version).to.exist();
expect(version.scales[0].replicas).to.equal(3);
expect(version.scale[0].replicas).to.equal(3);
done();
});
});

View File

@ -2,6 +2,7 @@
// const Assert = require('assert');
const TritonWatch = require('triton-watch');
const util = require('util');
const DEPLOYMENT_GROUP = 'docker:label:com.docker.compose.project';
@ -30,6 +31,10 @@ module.exports = class Watcher {
this._tritonWatch.on('change', (container) => { return this.onChange(container); });
}
poll () {
this._tritonWatch.poll();
}
getDeploymentGroupId (name, cb) {
this._data.getDeploymentGroup({ name }, (err, deploymentGroup) => {
if (err) {
@ -40,7 +45,7 @@ module.exports = class Watcher {
});
}
getServiceId ({ serviceName, deploymentGroupId }, cb) {
getService ({ serviceName, deploymentGroupId }, cb) {
this._data.getServices({ name: serviceName, deploymentGroupId }, (err, services) => {
if (err) {
return cb(err);
@ -50,62 +55,87 @@ module.exports = class Watcher {
return cb();
}
return cb(null, services.pop().id);
return cb(null, services.pop());
});
}
getInstance (machineId, cb) {
this._data.getInstances({ machineId }, (err, instances) => {
if (err) {
return cb(err);
}
if (!instances || !instances.length) {
return cb();
}
return cb(null, instances.pop());
});
getInstances (service, cb) {
service.instances()
.then((instances) => { return cb(null, instances); })
.catch((err) => { return cb(err); });
}
resolveChanges ({ machine, deploymentGroupId, serviceId, instance }) {
const handleError = (err) => {
if (err) {
console.error(err);
}
resolveChanges ({ machine, service, instances }) {
// 1. if instance doesn't exist, create new
// 2. if instance exist, update status
const handleError = (cb) => {
return (err, data) => {
if (err) {
console.error(err);
return;
}
if (cb) {
cb(err, data);
}
};
};
const isNew = instances
.every(({ machineId }) => { return machine.id !== machineId; });
const instance = instances
.filter(({ machineId }) => { return machine.id === machineId; })
.pop();
const create = () => {
return this._data.updateInstance({
const instance = {
name: machine.name,
status: machine.state.toUpperCase(),
status: (machine.state || '').toUpperCase(),
machineId: machine.id
}, handleError);
};
console.log('-> creating instance', util.inspect(instance));
return this._data.createInstance(instance, handleError((_, instance) => {
const updatedService = {
id: service.id,
instances: instances.concat(instance)
};
console.log('-> updating service', util.inspect(updatedService));
return this._data.updateService(updatedService, handleError);
}));
};
const update = () => {
return this._data.updateInstance({
const updatedInstance = {
id: instance.id,
status: machine.state.toUpperCase()
}, handleError);
status: (machine.state || '').toUpperCase()
};
console.log('-> updating instance', util.inspect(updatedInstance));
return this._data.updateInstance(updatedInstance, handleError);
};
return (!instance || !instance.id) ?
return isNew ?
create() :
update();
}
onChange (machine) {
if (!machine) {
console.error('`change` event received without machine data');
console.error('-> `change` event received without machine data');
return;
}
console.log('-> `change` event received', util.inspect(machine));
const { id, tags = [] } = machine;
// assert id existence
if (!id) {
console.error('`change` event received for a machine without `id`');
console.error('-> `change` event received for a machine without `id`');
return;
}
@ -115,7 +145,7 @@ module.exports = class Watcher {
);
if (!isCompose) {
console.error(`Changed machine ${id} was not provisioned by docker-compose`);
console.error(`-> Changed machine ${id} was not provisioned by docker-compose`);
return;
}
@ -133,26 +163,25 @@ module.exports = class Watcher {
};
};
const getInstance = (deploymentGroupId, serviceId) => {
this.getInstance(id, handleError((instance) => {
const getInstances = (service) => {
this.getInstances(service, handleError((instances) => {
return this.resolveChanges({
machine,
deploymentGroupId,
serviceId,
instance
service,
instances
});
}));
};
// assert that service exists
const assertService = (deploymentGroupId) => {
this.getServiceId({ serviceName, deploymentGroupId }, handleError((serviceId) => {
if (!serviceId) {
this.getService({ serviceName, deploymentGroupId }, handleError((service) => {
if (!service) {
console.error(`Service "${serviceName}" form DeploymentGroup "${deploymentGroupName}" for machine ${id} not found`);
return;
}
getInstance(deploymentGroupId, serviceId);
getInstances(service);
}));
};

View File

@ -10,27 +10,6 @@ const expect = Lab.expect;
it('updates instances with the current status', (done) => {
const data = {
getDeploymentGroup: (options, next) => {
expect(options.name).to.equal('test-project');
next(null, { id: 'deployment-group-id' });
},
getServices: (options, next) => {
expect(options.deploymentGroupId).to.equal('deployment-group-id');
expect(options.name).to.equal('test-service');
next(null, [{ id: 'service-id' }]);
},
getInstances: (options, next) => {
expect(options.machineId).to.equal('test-id');
next(null, [{ id: 'instance-id' }]);
},
updateInstance: (options, next) => {
expect(options.id).to.equal('instance-id');
expect(options.status).to.equal('DELETED');
done();
}
};
const machine = {
id: 'test-id',
tags: {
@ -41,6 +20,70 @@ it('updates instances with the current status', (done) => {
state: 'deleted'
};
const data = {
getDeploymentGroup: (options, next) => {
expect(options.name).to.equal('test-project');
next(null, { id: 'deployment-group-id' });
},
getServices: (options, next) => {
expect(options.deploymentGroupId).to.equal('deployment-group-id');
expect(options.name).to.equal('test-service');
next(null, [{
id: 'service-id',
instances: () => {
return Promise.resolve([{
machineId: machine.id,
id: 'instance-id'
}]);
}
}]);
},
updateInstance: (options, next) => {
expect(options.id).to.equal('instance-id');
expect(options.status).to.equal('DELETED');
done();
}
};
const portalOptions = { data, url: 'url', account: 'account', keyId: 'de:e7:73:9a:aa:91:bb:3e:72:8d:cc:62:ca:58:a2:ec' };
const portalWatch = new PortalWatch(portalOptions);
portalWatch._tritonWatch.removeAllListeners('change');
portalWatch.onChange(machine);
});
it('creates new instance', (done) => {
const machine = {
id: 'test-id',
tags: {
'docker:label:com.docker.compose.project': 'test-project',
'docker:label:com.docker.compose.service': 'test-service',
'docker:label:com.docker.compose.config-hash': 'test-hash'
},
state: 'created'
};
const data = {
getDeploymentGroup: (options, next) => {
expect(options.name).to.equal('test-project');
next(null, { id: 'deployment-group-id' });
},
getServices: (options, next) => {
expect(options.deploymentGroupId).to.equal('deployment-group-id');
expect(options.name).to.equal('test-service');
next(null, [{
id: 'service-id',
instances: () => { return Promise.resolve([]); }
}]);
},
createInstance: (options, next) => {
expect(options.id).to.equal(undefined);
expect(options.status).to.equal('CREATED');
expect(options.machineId).to.equal('test-id');
done();
}
};
const portalOptions = { data, url: 'url', account: 'account', keyId: 'de:e7:73:9a:aa:91:bb:3e:72:8d:cc:62:ca:58:a2:ec' };
const portalWatch = new PortalWatch(portalOptions);
portalWatch._tritonWatch.removeAllListeners('change');

View File

@ -502,10 +502,6 @@ ast-types@0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.0.tgz#c8721c8747ae4d5b29b929e99c5317b4e8745623"
ast-types@0.9.6:
version "0.9.6"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@ -1401,8 +1397,8 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
base64-js@^1.0.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
version "1.2.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
bcrypt-pbkdf@^1.0.0:
version "1.0.1"
@ -1770,12 +1766,12 @@ camelcase@^4.0.0, camelcase@^4.1.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000692"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000692.tgz#3da9a99353adbcea1e142b99f60ecc6216df47a5"
version "1.0.30000693"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000693.tgz#8510e7a9ab04adcca23a5dcefa34df9d28c1ce20"
caniuse-lite@^1.0.30000684:
version "1.0.30000692"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000692.tgz#34600fd7152352d85a47f4662a3b51b02d8b646f"
version "1.0.30000693"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000693.tgz#c9c6298697c71fdf6cb13eefe8aa93926f2f8613"
capture-stack-trace@^1.0.0:
version "1.0.0"
@ -2023,8 +2019,8 @@ code@4.1.x, code@^4.1.0:
hoek "4.x.x"
codemirror@^5.18.2:
version "5.26.0"
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.26.0.tgz#bcbee86816ed123870c260461c2b5c40b68746e5"
version "5.27.0"
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.27.0.tgz#0c72f70c321a7d494fd8db1976698c249c985eb3"
coleman-liau@^1.0.0:
version "1.0.0"
@ -2861,12 +2857,6 @@ debug-log@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f"
debug@2.2.0, debug@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
dependencies:
ms "0.7.1"
debug@2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e"
@ -2879,6 +2869,12 @@ debug@^2.1.1, debug@^2.2.0, debug@^2.6.0, debug@^2.6.3, debug@^2.6.8:
dependencies:
ms "2.0.0"
debug@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
dependencies:
ms "0.7.1"
debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
@ -3334,10 +3330,10 @@ eslint-import-resolver-node@^0.2.0:
resolve "^1.1.6"
eslint-module-utils@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.0.0.tgz#a6f8c21d901358759cdc35dbac1982ae1ee58bce"
version "2.1.1"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449"
dependencies:
debug "2.2.0"
debug "^2.6.8"
pkg-dir "^1.0.0"
eslint-plugin-flowtype@^2.34.0:
@ -3356,12 +3352,12 @@ eslint-plugin-hapi@4.x.x:
no-arrowception "1.x.x"
eslint-plugin-import@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.3.0.tgz#37c801e0ada0e296cbdf20c3f393acb5b52af36b"
version "2.5.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.5.0.tgz#293b5ea7910a901a05a47ccdd7546e611725406c"
dependencies:
builtin-modules "^1.1.1"
contains-path "^0.1.0"
debug "^2.2.0"
debug "^2.6.8"
doctrine "1.5.0"
eslint-import-resolver-node "^0.2.0"
eslint-module-utils "^2.0.0"
@ -3502,7 +3498,7 @@ esprima@^2.6.0, esprima@~2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esprima@^3.1.1, esprima@~3.1.0:
esprima@^3.1.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
@ -3712,11 +3708,11 @@ extsprintf@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
extsprintf@1.2.0, extsprintf@^1.2.0:
extsprintf@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.2.0.tgz#5ad946c22f5b32ba7f8cd7426711c6e8a3fc2529"
extsprintf@1.3.0:
extsprintf@1.3.0, extsprintf@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@ -4008,8 +4004,8 @@ get-caller-file@^1.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
get-pkg-repo@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-1.3.0.tgz#43c6b4c048b75dd604fc5388edecde557f6335df"
version "1.4.0"
resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz#c73b489c06d80cc5536c2c853f9e05232056972d"
dependencies:
hosted-git-info "^2.1.4"
meow "^3.3.0"
@ -4247,8 +4243,8 @@ graphql-anywhere@^3.0.0, graphql-anywhere@^3.0.1:
resolved "https://registry.yarnpkg.com/graphql-anywhere/-/graphql-anywhere-3.1.0.tgz#3ea0d8e8646b5cee68035016a9a7557c15c21e96"
graphql-tag@^2.0.0, graphql-tag@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.4.0.tgz#0fe137348d4db2efaf29b52ba4c1cbf84ac138cb"
version "2.4.2"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.4.2.tgz#6a63297d8522d03a2b72d26f1b239aab343840cd"
graphql@^0.10.0, graphql@^0.10.1:
version "0.10.3"
@ -5200,8 +5196,8 @@ jest-snapshot@^20.0.3:
pretty-format "^20.0.3"
jest-styled-components@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-3.1.1.tgz#d859a73c7844ecb47204b7240c00b499502a1fc8"
version "3.1.2"
resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-3.1.2.tgz#4e1a1da604824c7f31507e80c43e88a2d8d8c4c9"
dependencies:
css "^2.2.1"
@ -6141,7 +6137,7 @@ mooremachine@^2.0.1:
optionalDependencies:
dtrace-provider "~0.8"
ms@0.7.1, ms@^0.7.1:
ms@0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
@ -6149,6 +6145,10 @@ ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
ms@^0.7.1:
version "0.7.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff"
msgpack@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/msgpack/-/msgpack-1.0.2.tgz#923e2c5cffa65c8418e9b228d1124793969c429c"
@ -7454,8 +7454,8 @@ read@1.0.7:
mute-stream "~0.0.4"
"readable-stream@>= 1.0.2", readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6:
version "2.3.1"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.1.tgz#84e26965bb9e785535ed256e8d38e92c69f09d10"
version "2.3.2"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.2.tgz#5a04df05e4f57fe3f0dc68fdd11dc5c97c7e6f4d"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
@ -7526,7 +7526,7 @@ readline2@^1.0.1:
is-fullwidth-code-point "^1.0.0"
mute-stream "0.0.5"
recast@0.11.12:
recast@0.11.12, recast@^0.11.5:
version "0.11.12"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.12.tgz#a79e4d3f82d5d72a82ee177aeaa791e793bbe5d6"
dependencies:
@ -7535,15 +7535,6 @@ recast@0.11.12:
private "~0.1.5"
source-map "~0.5.0"
recast@^0.11.5:
version "0.11.23"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
dependencies:
ast-types "0.9.6"
esprima "~3.1.0"
private "~0.1.5"
source-map "~0.5.0"
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
@ -8081,8 +8072,8 @@ rx-lite@^3.1.2:
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
safe-buffer@~5.0.1:
version "5.0.1"
@ -9228,8 +9219,8 @@ typedarray@^0.0.6, typedarray@~0.0.5:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
ua-parser-js@^0.7.9:
version "0.7.12"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
version "0.7.13"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.13.tgz#cd9dd2f86493b3f44dbeeef3780fda74c5ee14be"
uglify-js@^2.6, uglify-js@^2.8.27:
version "2.8.29"