mirror of
https://github.com/yldio/copilot.git
synced 2024-12-29 05:10:05 +02:00
import existing deployment groups (#516)
* refactor: config() from mutation to query * refactor(cp-frontend): remove unused dependency * feat(portal-watch): expose getContainers() and compose tags * fix(portal-watch): assert services by name AND hash * feat(portal-data): expose importable and import APIs * fix(portal-data): add missing dependencies * feat(portal-api): expose import/importable * feat(cp-gql-schema): add import/importable * feat(cp-frontend): import existing project * style(portal-watch): lint * style(portal-data): lint * chore: update lockfile
This commit is contained in:
parent
59043760b6
commit
7f1d731dc6
@ -5,6 +5,7 @@
|
||||
"new-cap": 0,
|
||||
// temp
|
||||
"no-undef": 1,
|
||||
"no-debugger": 1
|
||||
"no-debugger": 1,
|
||||
"no-negated-condition": 0
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,6 @@
|
||||
"unitcalc": "^1.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"apr-find": "^1.0.5",
|
||||
"apr-for-each": "^1.0.6",
|
||||
"apr-main": "^1.0.7",
|
||||
"babel-plugin-inline-react-svg": "^0.4.0",
|
||||
|
@ -14,6 +14,15 @@
|
||||
border: solid 1px #d8d8d8;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
html, body, #root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -1,7 +1,6 @@
|
||||
const { readFile, writeFile, exists } = require('mz/fs');
|
||||
const main = require('apr-main');
|
||||
const forEach = require('apr-for-each');
|
||||
const find = require('apr-find');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT = path.join(__dirname, '../node_modules/react-scripts/config');
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Article } from 'normalized-styled-components';
|
||||
import { ThemeProvider, injectGlobal } from 'styled-components';
|
||||
import { theme, global } from 'joyent-ui-toolkit';
|
||||
import { ApolloProvider } from 'react-apollo';
|
||||
@ -19,9 +18,7 @@ class App extends Component {
|
||||
return (
|
||||
<ApolloProvider client={client} store={store}>
|
||||
<ThemeProvider theme={theme}>
|
||||
<Article>
|
||||
{Router}
|
||||
</Article>
|
||||
{Router}
|
||||
</ThemeProvider>
|
||||
</ApolloProvider>
|
||||
);
|
||||
|
@ -1,10 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Col, Row } from 'react-styled-flexboxgrid';
|
||||
|
||||
export default () =>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<p>you don't have any deployment groups</p>
|
||||
</Col>
|
||||
</Row>;
|
@ -1 +1,2 @@
|
||||
export { default as EmptyDeployementGroups } from './empty';
|
||||
export { default as DeploymentGroupsLoading } from './loading';
|
||||
export { default as CreateDeploymentGroup } from './create';
|
||||
|
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Col, Row } from 'react-styled-flexboxgrid';
|
||||
import { Dots2 } from 'styled-text-spinners';
|
||||
|
||||
const LoadingRow = Row.extend`
|
||||
flex: 1 1 auto;
|
||||
`;
|
||||
|
||||
export default () =>
|
||||
<LoadingRow center="xs" around="xs" middle="xs">
|
||||
<Col xs={1}>
|
||||
<Dots2 />
|
||||
</Col>
|
||||
</LoadingRow>;
|
@ -1,3 +1,13 @@
|
||||
import { Grid } from 'react-styled-flexboxgrid';
|
||||
import remcalc from 'remcalc';
|
||||
import { isNot } from 'styled-is';
|
||||
|
||||
export default Grid;
|
||||
export default Grid.extend`
|
||||
padding-top: ${remcalc(19)};
|
||||
|
||||
${isNot('plain')`
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
`};
|
||||
`;
|
||||
|
@ -19,7 +19,6 @@ const BreadcrumbLink = styled(Link)`
|
||||
|
||||
const BreadcrumbContainer = styled.div`
|
||||
border-bottom: solid ${remcalc(1)} ${props => props.theme.grey};
|
||||
margin-bottom: ${remcalc(19)};
|
||||
`;
|
||||
|
||||
const getBreadcrumbItems = (...links) =>
|
||||
|
@ -22,7 +22,7 @@ const getMenuItems = (...links) =>
|
||||
);
|
||||
|
||||
const Menu = ({ links = [] }) =>
|
||||
<LayoutContainer>
|
||||
<LayoutContainer plain>
|
||||
<SectionList>
|
||||
{getMenuItems(...links)}
|
||||
</SectionList>
|
||||
|
@ -8,7 +8,7 @@ import paramCase from 'param-case';
|
||||
import DeploymentGroupBySlug from '@graphql/DeploymentGroupBySlug.gql';
|
||||
import DeploymentGroupCreateMutation from '@graphql/DeploymentGroupCreate.gql';
|
||||
import DeploymentGroupProvisionMutation from '@graphql/DeploymentGroupProvision.gql';
|
||||
import DeploymentGroupConfigMutation from '@graphql/DeploymentGroupConfig.gql';
|
||||
import DeploymentGroupConfigQuery from '@graphql/DeploymentGroupConfig.gql';
|
||||
|
||||
import { client } from '@state/store';
|
||||
import { LayoutContainer } from '@components/layout';
|
||||
@ -262,7 +262,7 @@ export default compose(
|
||||
provisionManifest: variables => mutate({ variables })
|
||||
})
|
||||
}),
|
||||
graphql(DeploymentGroupConfigMutation, {
|
||||
graphql(DeploymentGroupConfigQuery, {
|
||||
props: ({ mutate }) => ({
|
||||
config: variables => mutate({ variables })
|
||||
})
|
||||
|
@ -0,0 +1,58 @@
|
||||
import React, { Component } from 'react';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import intercept from 'apr-intercept';
|
||||
|
||||
import DeploymentGroupImportMutation from '@graphql/DeploymentGroupImport.gql';
|
||||
|
||||
import { LayoutContainer } from '@components/layout';
|
||||
import { DeploymentGroupsLoading } from '@components/deployment-groups';
|
||||
import { Dots2 } from 'styled-text-spinners';
|
||||
import { H2 } from 'joyent-ui-toolkit';
|
||||
|
||||
class DeploymentGroupImport extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
loading: true,
|
||||
error: false
|
||||
};
|
||||
|
||||
setTimeout(this.importDeploymentGroup, 16);
|
||||
}
|
||||
|
||||
importDeploymentGroup = async () => {
|
||||
const { importDeploymentGroup, match, history } = this.props;
|
||||
const { slug } = match.params;
|
||||
|
||||
const [error] = await intercept(
|
||||
importDeploymentGroup({
|
||||
slug
|
||||
})
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return this.setState({ loading: false, error });
|
||||
}
|
||||
|
||||
history.push(`/deployment-groups/${slug}`);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loading, error } = this.state;
|
||||
|
||||
return (
|
||||
<LayoutContainer>
|
||||
<H2>Importing deployment group</H2>
|
||||
{loading && <DeploymentGroupsLoading />}
|
||||
{error && <span>{error.toString()}</span>}
|
||||
</LayoutContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default graphql(DeploymentGroupImportMutation, {
|
||||
props: ({ mutate }) => ({
|
||||
importDeploymentGroup: variables => mutate({ variables })
|
||||
})
|
||||
})(DeploymentGroupImport);
|
@ -1,2 +1,3 @@
|
||||
export { default as DeploymentGroupList } from './list';
|
||||
export { default as DeploymentGroupCreate } from './create';
|
||||
export { default as DeploymentGroupImport } from './import';
|
||||
|
@ -1,73 +1,133 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { graphql } from 'react-apollo';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import { Link } from 'react-router-dom';
|
||||
import DeploymentGroupsQuery from '@graphql/DeploymentGroups.gql';
|
||||
import styled from 'styled-components';
|
||||
import { Col, Row } from 'react-styled-flexboxgrid';
|
||||
import forceArray from 'force-array';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import { LayoutContainer } from '@components/layout';
|
||||
import { Loader, ErrorMessage } from '@components/messaging';
|
||||
import { EmptyDeployementGroups } from '@components/deployment-groups';
|
||||
import { Button } from 'joyent-ui-toolkit';
|
||||
import { DeploymentGroupsLoading } from '@components/deployment-groups';
|
||||
import DeploymentGroupsQuery from '@graphql/DeploymentGroups.gql';
|
||||
import DeploymentGroupsImportableQuery from '@graphql/DeploymentGroupsImportable.gql';
|
||||
import { Button, H2, H3, Small } from 'joyent-ui-toolkit';
|
||||
|
||||
const Title = H2.extend`
|
||||
margin-top: ${remcalc(2)};
|
||||
`;
|
||||
|
||||
const DGsRows = Row.extend`
|
||||
margin-top: ${remcalc(-7)};
|
||||
`;
|
||||
|
||||
const Box = Col.withComponent(Link).extend`
|
||||
text-decoration: none;
|
||||
color: ${props => props.theme.secondary};
|
||||
background-color: ${props => props.theme.white};
|
||||
box-shadow: 0 ${remcalc(2)} 0 0 rgba(0, 0, 0, 0.05);
|
||||
border: solid ${remcalc(1)} ${props => props.theme.grey};
|
||||
margin-top: ${remcalc(20)};
|
||||
margin-bottom: 0;
|
||||
padding: ${remcalc(18)};
|
||||
min-height: ${remcalc(258)};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: ${remcalc(20)};
|
||||
}
|
||||
`;
|
||||
|
||||
const BoxCreate = Box.extend`
|
||||
background-color: ${props => props.theme.disabled};
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
display: flex;
|
||||
|
||||
&:hover {
|
||||
background-color: ${props => props.theme.white};
|
||||
}
|
||||
`;
|
||||
|
||||
const Oval = styled.div`
|
||||
border: solid ${remcalc(1)} ${props => props.theme.grey};
|
||||
border-radius: 50%;
|
||||
|
||||
width: ${remcalc(48)};
|
||||
height: ${remcalc(48)};
|
||||
line-height: ${remcalc(48)};
|
||||
font-size: ${remcalc(24)};
|
||||
text-align: center;
|
||||
|
||||
margin-bottom: ${remcalc(20)};
|
||||
`;
|
||||
|
||||
const CreateTitle = Small.extend`
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const ServiceTitle = H3.extend`
|
||||
margin-top: ${remcalc(10)};
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
const DeploymentGroupList = ({
|
||||
location,
|
||||
deploymentGroups,
|
||||
importable,
|
||||
loading,
|
||||
error
|
||||
error,
|
||||
match
|
||||
}) => {
|
||||
if (loading) {
|
||||
return (
|
||||
<LayoutContainer>
|
||||
<Loader />
|
||||
</LayoutContainer>
|
||||
);
|
||||
} else if (error) {
|
||||
return (
|
||||
<LayoutContainer>
|
||||
const _loading = !loading ? null : <DeploymentGroupsLoading />;
|
||||
|
||||
// todo improve this error message style according to new designs
|
||||
const _error = !error
|
||||
? null
|
||||
: <Row>
|
||||
<ErrorMessage message="Oops, and error occured while loading your deployment groups." />
|
||||
</LayoutContainer>
|
||||
);
|
||||
}
|
||||
</Row>;
|
||||
|
||||
let emptyDeployementGroups = null;
|
||||
let deploymentGroupList = null;
|
||||
const groups = forceArray(deploymentGroups).map(({ slug, name }) =>
|
||||
<Col xs={12} sm={4} md={3} lg={3} key={slug}>
|
||||
<Box to={`${match.path}/${slug}`}>
|
||||
<ServiceTitle>{name}</ServiceTitle>
|
||||
</Box>
|
||||
</Col>
|
||||
);
|
||||
|
||||
if (deploymentGroups.length) {
|
||||
const list = deploymentGroups.map((deploymentGroup, index) => {
|
||||
return (
|
||||
<p key={index}>
|
||||
<Link to={`${location.pathname}/${deploymentGroup.slug}/services`}>
|
||||
{deploymentGroup.name}
|
||||
</Link>
|
||||
</p>
|
||||
);
|
||||
});
|
||||
|
||||
deploymentGroupList = (
|
||||
<Row>
|
||||
<Col>
|
||||
<ul>
|
||||
{list}
|
||||
</ul>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else {
|
||||
emptyDeployementGroups = <EmptyDeployementGroups />;
|
||||
}
|
||||
const create = [
|
||||
<Col xs={12} sm={4} md={3} lg={3} key="~create">
|
||||
<BoxCreate to={`${match.path}/~create`}>
|
||||
<Oval>+</Oval>
|
||||
<CreateTitle>Create new deployment group</CreateTitle>
|
||||
</BoxCreate>
|
||||
</Col>
|
||||
].concat(
|
||||
forceArray(importable).map(({ slug, name }) =>
|
||||
<Col xs={12} sm={4} md={3} lg={3} key={slug}>
|
||||
<BoxCreate to={`${match.path}/~import/${slug}`}>
|
||||
<Oval>⤵</Oval>
|
||||
<CreateTitle>{name}</CreateTitle>
|
||||
</BoxCreate>
|
||||
</Col>
|
||||
)
|
||||
);
|
||||
|
||||
return (
|
||||
<LayoutContainer>
|
||||
{emptyDeployementGroups}
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<Button to={`/deployment-groups/~create`}>
|
||||
Create new
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
{deploymentGroupList}
|
||||
<Title>Deployment groups</Title>
|
||||
{_loading}
|
||||
{_error}
|
||||
<DGsRows>
|
||||
{groups}
|
||||
{create}
|
||||
</DGsRows>
|
||||
</LayoutContainer>
|
||||
);
|
||||
};
|
||||
@ -81,15 +141,20 @@ DeploymentGroupList.propTypes = {
|
||||
)
|
||||
};
|
||||
|
||||
const DeploymentGroupListWithData = graphql(DeploymentGroupsQuery, {
|
||||
options: {
|
||||
pollInterval: 1000
|
||||
},
|
||||
props: ({ data: { deploymentGroups, loading, error } }) => ({
|
||||
deploymentGroups,
|
||||
loading,
|
||||
error
|
||||
export default compose(
|
||||
graphql(DeploymentGroupsQuery, {
|
||||
options: {
|
||||
pollInterval: 1000
|
||||
},
|
||||
props: ({ data: { deploymentGroups, loading, error } }) => ({
|
||||
deploymentGroups,
|
||||
loading,
|
||||
error
|
||||
})
|
||||
}),
|
||||
graphql(DeploymentGroupsImportableQuery, {
|
||||
props: ({ data: { importableDeploymentGroups } }) => ({
|
||||
importable: importableDeploymentGroups
|
||||
})
|
||||
})
|
||||
})(DeploymentGroupList);
|
||||
|
||||
export default DeploymentGroupListWithData;
|
||||
)(DeploymentGroupList);
|
||||
|
@ -65,7 +65,7 @@ const ServicesMenu = ({ location, history: { push } }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<LayoutContainer>
|
||||
<LayoutContainer plain>
|
||||
<H2>Services</H2>
|
||||
<PaddedRow>
|
||||
<Col xs={5}>
|
||||
|
@ -1,6 +1,6 @@
|
||||
#import "./ServiceInfo.gql"
|
||||
|
||||
mutation config($deploymentGroupName: String!, $type: ManifestType!, $format: ManifestFormat!, $raw: String!) {
|
||||
query config($deploymentGroupName: String!, $type: ManifestType!, $format: ManifestFormat!, $raw: String!) {
|
||||
config(deploymentGroupName: $deploymentGroupName, type: $type, format: $format, raw: $raw) {
|
||||
image
|
||||
...ServiceInfo
|
||||
|
@ -0,0 +1,7 @@
|
||||
#import "./DeploymentGroupInfo.gql"
|
||||
|
||||
mutation importDeploymentGroup($slug: String!) {
|
||||
importDeploymentGroup(deploymentGroupSlug: $slug) {
|
||||
...DeploymentGroupInfo
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#import "./DeploymentGroupInfo.gql"
|
||||
|
||||
query DeploymentGroupsImportable {
|
||||
importableDeploymentGroups {
|
||||
...DeploymentGroupInfo
|
||||
}
|
||||
}
|
@ -1,11 +1,15 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Header, Breadcrumb, Menu } from '@containers/navigation';
|
||||
import { ServiceScale, ServiceDelete } from '@containers/service';
|
||||
import { InstanceList } from '@containers/instances';
|
||||
|
||||
import {
|
||||
DeploymentGroupList,
|
||||
DeploymentGroupCreate
|
||||
DeploymentGroupCreate,
|
||||
DeploymentGroupImport
|
||||
} from '@containers/deployment-groups';
|
||||
|
||||
import {
|
||||
@ -14,9 +18,12 @@ import {
|
||||
ServicesMenu
|
||||
} from '@containers/services';
|
||||
|
||||
import { ServiceScale, ServiceDelete } from '@containers/service';
|
||||
|
||||
import { InstanceList } from '@containers/instances';
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
position: relative;
|
||||
flex-flow: column;
|
||||
`;
|
||||
|
||||
const rootRedirect = p => <Redirect to="/deployment-groups" />;
|
||||
|
||||
@ -33,7 +40,7 @@ const serviceRedirect = p =>
|
||||
|
||||
const Router = (
|
||||
<BrowserRouter>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<Container>
|
||||
|
||||
<Route path="/" component={Header} />
|
||||
|
||||
@ -65,6 +72,11 @@ const Router = (
|
||||
exact
|
||||
component={DeploymentGroupCreate}
|
||||
/>
|
||||
<Route
|
||||
path="/deployment-groups/~import/:slug"
|
||||
exact
|
||||
component={DeploymentGroupImport}
|
||||
/>
|
||||
<Route
|
||||
path="/deployment-groups/:deploymentGroup"
|
||||
exact
|
||||
@ -132,7 +144,7 @@ const Router = (
|
||||
component={InstanceList}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</Container>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
|
@ -19,7 +19,7 @@ type User {
|
||||
type DeploymentGroup {
|
||||
id: ID!
|
||||
name: String!
|
||||
slug: String!
|
||||
slug: String!
|
||||
services(name: String, slug: String, parentId: ID): [Service]
|
||||
version: Version
|
||||
history: [Version]
|
||||
@ -186,6 +186,9 @@ type Query {
|
||||
instance(id: ID!): Instance
|
||||
datacenter(id: ID, region: String): Datacenter
|
||||
datacenters: [Datacenter]
|
||||
|
||||
config(deploymentGroupName: String!, type: ManifestType!, format: ManifestFormat!, raw: String!): [Service]
|
||||
importableDeploymentGroups: [DeploymentGroup]
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
@ -194,7 +197,6 @@ type Mutation {
|
||||
|
||||
provisionManifest(deploymentGroupId: ID!, type: ManifestType!, format: ManifestFormat!, raw: String!): Version
|
||||
scale(serviceId: ID!, replicas: Int!): Version
|
||||
config(deploymentGroupName: String!, type: ManifestType!, format: ManifestFormat!, raw: String!): [Service]
|
||||
|
||||
stopServices(ids: [ID]!): [Service]
|
||||
startServices(ids: [ID]!): [Service]
|
||||
@ -205,5 +207,5 @@ type Mutation {
|
||||
startInstances(ids: [ID]!): [Instance]
|
||||
restartInstances(ids: [ID]!): [Instance]
|
||||
|
||||
# reprovision() ???
|
||||
importDeploymentGroup(deploymentGroupSlug: String!): DeploymentGroup
|
||||
}
|
||||
|
@ -19,11 +19,16 @@ module.exports = function (server, options, next) {
|
||||
}
|
||||
|
||||
const data = new PortalData(options.data);
|
||||
|
||||
const watch = new PortalWatch(Object.assign(options.watch, {
|
||||
const watcher = new PortalWatch(Object.assign(options.watch, {
|
||||
data
|
||||
}));
|
||||
|
||||
// watcher <-> watcher
|
||||
// portal depends on watcher and vice-versa
|
||||
// I'm sure there is a better way to organize this domains
|
||||
// but this works for now
|
||||
data.setWatcher(watcher);
|
||||
|
||||
data.on('error', (err) => {
|
||||
server.log(['error'], err);
|
||||
});
|
||||
@ -33,12 +38,10 @@ module.exports = function (server, options, next) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
server.bind(Object.assign(data, {
|
||||
watch
|
||||
}));
|
||||
server.bind(data);
|
||||
|
||||
Piloted.on('refresh', internals.refresh(data));
|
||||
watch.poll();
|
||||
watcher.poll();
|
||||
|
||||
server.register([
|
||||
{
|
||||
|
@ -25,7 +25,9 @@ module.exports = (data) => {
|
||||
'metricData',
|
||||
'package',
|
||||
'datacenters',
|
||||
'instanceMetric'
|
||||
'instanceMetric',
|
||||
'config',
|
||||
'importableDeploymentGroups'
|
||||
];
|
||||
|
||||
const mutations = [
|
||||
@ -33,14 +35,14 @@ module.exports = (data) => {
|
||||
'updateDeploymentGroup',
|
||||
'provisionManifest',
|
||||
'scale',
|
||||
'config',
|
||||
'stopServices',
|
||||
'startServices',
|
||||
'restartServices',
|
||||
'deleteServices',
|
||||
'stopInstances',
|
||||
'startInstances',
|
||||
'restartInstances'
|
||||
'restartInstances',
|
||||
'importDeploymentGroup'
|
||||
];
|
||||
|
||||
const resolvers = {};
|
||||
|
@ -3,12 +3,23 @@
|
||||
const ParamCase = require('param-case');
|
||||
const EventEmitter = require('events');
|
||||
const DockerClient = require('docker-compose-client');
|
||||
const { DEPLOYMENT_GROUP, SERVICE, HASH } = require('portal-watch');
|
||||
const Dockerode = require('dockerode');
|
||||
const Hoek = require('hoek');
|
||||
const Penseur = require('penseur');
|
||||
const VAsync = require('vasync');
|
||||
const uniqBy = require('lodash.uniqby');
|
||||
const Transform = require('./transform');
|
||||
const Uuid = require('uuid/v4');
|
||||
const Util = require('util');
|
||||
|
||||
|
||||
const NON_IMPORTABLE_STATES = [
|
||||
'EXITED',
|
||||
'DELETED',
|
||||
'STOPPED',
|
||||
'FAILED'
|
||||
];
|
||||
|
||||
const internals = {
|
||||
defaults: {
|
||||
@ -51,12 +62,17 @@ module.exports = class Data extends EventEmitter {
|
||||
this._db = new Penseur.Db(settings.name, settings.db);
|
||||
this._dockerCompose = new DockerClient(settings.dockerComposeHost);
|
||||
this._docker = new Dockerode(settings.docker);
|
||||
this._watcher = null;
|
||||
|
||||
this._dockerCompose.on('error', (err) => {
|
||||
this.emit('error', err);
|
||||
});
|
||||
}
|
||||
|
||||
setWatcher (watcher) {
|
||||
this._watcher = watcher;
|
||||
}
|
||||
|
||||
connect (cb) {
|
||||
this._db.establish(internals.tables, cb);
|
||||
}
|
||||
@ -284,10 +300,8 @@ module.exports = class Data extends EventEmitter {
|
||||
const deploymentGroup = deploymentGroups[0];
|
||||
|
||||
const getServices = (args) => {
|
||||
console.log(args);
|
||||
args = args || {};
|
||||
args.deploymentGroupId = deploymentGroup.id;
|
||||
console.log(args);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getServices(args, resolveCb(resolve, reject));
|
||||
@ -1285,7 +1299,7 @@ module.exports = class Data extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
config ({deploymentGroupName = '', type = '', format = '', raw = '' }, cb) {
|
||||
getConfig ({deploymentGroupName = '', type = '', format = '', raw = '' }, cb) {
|
||||
if (type.toUpperCase() !== 'COMPOSE') {
|
||||
return cb(new Error('"COMPOSE" is the only `type` supported'));
|
||||
}
|
||||
@ -1330,4 +1344,133 @@ module.exports = class Data extends EventEmitter {
|
||||
}, []));
|
||||
});
|
||||
}
|
||||
|
||||
getImportableDeploymentGroups (args, cb) {
|
||||
if (!this._watcher) {
|
||||
return cb(null, []);
|
||||
}
|
||||
|
||||
const machines = this._watcher.getContainers();
|
||||
|
||||
if (!Array.isArray(machines)) {
|
||||
return cb(null, []);
|
||||
}
|
||||
|
||||
return cb(
|
||||
null,
|
||||
uniqBy(
|
||||
machines
|
||||
.filter(({ state }) => { return NON_IMPORTABLE_STATES.indexOf(state.toUpperCase()) < 0; })
|
||||
.filter(({ tags = {} }) => { return [DEPLOYMENT_GROUP, SERVICE, HASH].every((name) => { return tags[name]; }); }
|
||||
)
|
||||
.map(({ tags = {} }) => {
|
||||
return ({
|
||||
id: Uuid(),
|
||||
name: tags[DEPLOYMENT_GROUP],
|
||||
slug: ParamCase(tags[DEPLOYMENT_GROUP])
|
||||
});
|
||||
}),
|
||||
'slug'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
importDeploymentGroup ({ deploymentGroupSlug }, cb) {
|
||||
console.log(`-> import requested for ${deploymentGroupSlug}`);
|
||||
|
||||
if (!this._watcher) {
|
||||
console.log('-> watcher not yet defined');
|
||||
return cb(null, null);
|
||||
}
|
||||
|
||||
const machines = this._watcher.getContainers();
|
||||
|
||||
if (!Array.isArray(machines)) {
|
||||
console.log('-> no machines found');
|
||||
return cb(null, null);
|
||||
}
|
||||
|
||||
const containers = machines
|
||||
.filter(
|
||||
({ tags = {} }) => { return tags[DEPLOYMENT_GROUP] && ParamCase(tags[DEPLOYMENT_GROUP]) === deploymentGroupSlug; }
|
||||
)
|
||||
.filter(
|
||||
({ state }) => { return NON_IMPORTABLE_STATES.indexOf(state.toUpperCase()) < 0; }
|
||||
);
|
||||
|
||||
if (!containers.length) {
|
||||
console.log(`-> no containers found for ${deploymentGroupSlug}`);
|
||||
return cb(null, null);
|
||||
}
|
||||
|
||||
const { tags = [] } = containers[0];
|
||||
|
||||
const services = containers.reduce((acc, { tags = [], id = '', state = '', name = '' }) => {
|
||||
const hash = tags[HASH];
|
||||
const slug = ParamCase(tags[SERVICE]);
|
||||
const attr = `${hash}-${slug}`;
|
||||
|
||||
const instance = {
|
||||
name: name,
|
||||
machineId: id,
|
||||
status: state.toUpperCase()
|
||||
};
|
||||
|
||||
if (acc[attr]) {
|
||||
acc[attr].instances.push(instance);
|
||||
return acc;
|
||||
}
|
||||
|
||||
return Object.assign(acc, {
|
||||
[attr]: {
|
||||
hash,
|
||||
name: tags[SERVICE],
|
||||
slug,
|
||||
instances: [instance]
|
||||
}
|
||||
});
|
||||
}, {});
|
||||
|
||||
const createService = (deploymentGroupId) => {
|
||||
return (serviceId, next) => {
|
||||
const service = services[serviceId];
|
||||
|
||||
console.log(`-> creating Service ${Util.inspect(service)}`);
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: service.instances,
|
||||
func: (instance, next) => { return this.createInstance(instance, next); }
|
||||
}, (err, results) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
console.log(`-> created Instances ${Util.inspect(results.successes)}`);
|
||||
|
||||
this.createService(Object.assign(service, {
|
||||
instances: results.successes,
|
||||
deploymentGroupId
|
||||
}), next);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const deploymentGroup = {
|
||||
name: tags[DEPLOYMENT_GROUP],
|
||||
slug: ParamCase(tags[DEPLOYMENT_GROUP])
|
||||
};
|
||||
|
||||
console.log(`-> creating DeploymentGroup ${Util.inspect(deploymentGroup)}`);
|
||||
|
||||
this.createDeploymentGroup(deploymentGroup, (err, dg) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
VAsync.forEachParallel({
|
||||
inputs: Object.keys(services),
|
||||
func: createService(dg.id)
|
||||
}, (err) => { return cb(err, dg); });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -21,6 +21,8 @@
|
||||
"hoek": "^4.1.1",
|
||||
"param-case": "^2.1.1",
|
||||
"penseur": "^7.12.3",
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
"portal-watch": "^1.0.0",
|
||||
"uuid": "^3.1.0",
|
||||
"vasync": "^1.6.4",
|
||||
"yamljs": "^0.2.10"
|
||||
|
@ -9,7 +9,6 @@ const DEPLOYMENT_GROUP = 'docker:label:com.docker.compose.project';
|
||||
const SERVICE = 'docker:label:com.docker.compose.service';
|
||||
const HASH = 'docker:label:com.docker.compose.config-hash';
|
||||
|
||||
|
||||
module.exports = class Watcher {
|
||||
constructor (options) {
|
||||
options = options || {};
|
||||
@ -35,6 +34,10 @@ module.exports = class Watcher {
|
||||
this._tritonWatch.poll();
|
||||
}
|
||||
|
||||
getContainers () {
|
||||
return this._tritonWatch.getContainers();
|
||||
}
|
||||
|
||||
getDeploymentGroupId (name, cb) {
|
||||
this._data.getDeploymentGroup({ name }, (err, deploymentGroup) => {
|
||||
if (err) {
|
||||
@ -45,8 +48,8 @@ module.exports = class Watcher {
|
||||
});
|
||||
}
|
||||
|
||||
getService ({ serviceName, deploymentGroupId }, cb) {
|
||||
this._data.getServices({ name: serviceName, deploymentGroupId }, (err, services) => {
|
||||
getService ({ serviceName, serviceHash, deploymentGroupId }, cb) {
|
||||
this._data.getServices({ name: serviceName, hash: serviceHash, deploymentGroupId }, (err, services) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
@ -131,7 +134,7 @@ module.exports = class Watcher {
|
||||
|
||||
console.log('-> `change` event received', util.inspect(machine));
|
||||
|
||||
const { id, tags = [] } = machine;
|
||||
const { id, tags = {} } = machine;
|
||||
|
||||
// assert id existence
|
||||
if (!id) {
|
||||
@ -175,7 +178,7 @@ module.exports = class Watcher {
|
||||
|
||||
// assert that service exists
|
||||
const assertService = (deploymentGroupId) => {
|
||||
this.getService({ serviceName, deploymentGroupId }, handleError((service) => {
|
||||
this.getService({ serviceName, serviceHash: tags[HASH], deploymentGroupId }, handleError((service) => {
|
||||
if (!service) {
|
||||
console.error(`Service "${serviceName}" form DeploymentGroup "${deploymentGroupName}" for machine ${id} not found`);
|
||||
return;
|
||||
@ -200,3 +203,7 @@ module.exports = class Watcher {
|
||||
assertDeploymentGroup();
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.DEPLOYMENT_GROUP = DEPLOYMENT_GROUP;
|
||||
module.exports.SERVICE = SERVICE;
|
||||
module.exports.HASH = HASH;
|
||||
|
@ -12,7 +12,7 @@
|
||||
"test-ci": "echo 0 `# lab -c -r console -o stdout -r tap -o $CIRCLE_TEST_REPORTS/test/portal-watch.xml`"
|
||||
},
|
||||
"dependencies": {
|
||||
"triton-watch": "^1.0.1"
|
||||
"triton-watch": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"belly-button": "^3.1.0",
|
||||
|
102
yarn.lock
102
yarn.lock
@ -42,8 +42,8 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/async/-/async-2.0.40.tgz#ac02de68e66c004a61b7cb16df8b1db3a254cca9"
|
||||
|
||||
"@types/graphql@^0.9.0":
|
||||
version "0.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.9.1.tgz#b04ebe84bc997cc60dbea2ed4d0d4342c737f99d"
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.9.2.tgz#5e3a2919a998d0bd9bb86b4b23e9630425bff1b2"
|
||||
|
||||
"@types/isomorphic-fetch@0.0.34":
|
||||
version "0.0.34"
|
||||
@ -305,15 +305,6 @@ apr-filter@^1.0.5:
|
||||
apr-engine-sum "^1.0.3"
|
||||
apr-map "^1.0.5"
|
||||
|
||||
apr-find@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/apr-find/-/apr-find-1.0.5.tgz#e166abc66f53cfd08aadb3ecab38049faa378301"
|
||||
dependencies:
|
||||
apr-engine-each "^1.0.3"
|
||||
apr-engine-sum "^1.0.3"
|
||||
lodash.defaults "^4.2.0"
|
||||
lodash.isarraylike "^4.2.0"
|
||||
|
||||
apr-for-each@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/apr-for-each/-/apr-for-each-1.0.6.tgz#3947bb25fdb7b79a7f02bfa925fdb79576098903"
|
||||
@ -502,6 +493,10 @@ 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"
|
||||
@ -511,8 +506,8 @@ async@^1.4.0, async@^1.5.0:
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
|
||||
|
||||
async@^2.0.1, async@^2.1.2, async@^2.1.4:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7"
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d"
|
||||
dependencies:
|
||||
lodash "^4.14.0"
|
||||
|
||||
@ -896,10 +891,10 @@ babel-plugin-istanbul@^4.1.4:
|
||||
test-exclude "^4.1.1"
|
||||
|
||||
babel-plugin-styled-components@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.1.4.tgz#b0e6d5bb01059bc7ab9118d3d686f6472ee8e91f"
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.1.5.tgz#ff2c8e0e2f3a0d3279e7454a7aaa2973749e714d"
|
||||
dependencies:
|
||||
stylis "2.0.0"
|
||||
stylis "^3.0.19"
|
||||
|
||||
babel-plugin-syntax-async-functions@^6.8.0:
|
||||
version "6.13.0"
|
||||
@ -1370,7 +1365,7 @@ babelrc-rollup@3.0.0:
|
||||
dependencies:
|
||||
resolve "^1.1.7"
|
||||
|
||||
babylon@^6.1.0, babylon@^6.10.0, babylon@^6.12.0, babylon@^6.13.0, babylon@^6.17.0, babylon@^6.17.2:
|
||||
babylon@^6.1.0, babylon@^6.10.0, babylon@^6.12.0, babylon@^6.17.0, babylon@^6.17.2, babylon@^6.17.4:
|
||||
version "6.17.4"
|
||||
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.4.tgz#3e8b7402b88d22c3423e137a1577883b15ff869a"
|
||||
|
||||
@ -1766,12 +1761,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.30000693"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000693.tgz#8510e7a9ab04adcca23a5dcefa34df9d28c1ce20"
|
||||
version "1.0.30000694"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000694.tgz#02009f4f82d2f0126e4c691b7cd5adb351935c01"
|
||||
|
||||
caniuse-lite@^1.0.30000684:
|
||||
version "1.0.30000693"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000693.tgz#c9c6298697c71fdf6cb13eefe8aa93926f2f8613"
|
||||
version "1.0.30000694"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000694.tgz#1492dab7c10c608c9d37a723e6e3e7873e0ce94f"
|
||||
|
||||
capture-stack-trace@^1.0.0:
|
||||
version "1.0.0"
|
||||
@ -2027,8 +2022,8 @@ coleman-liau@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/coleman-liau/-/coleman-liau-1.0.0.tgz#de1f39901e164f49eff2a6ec88f3a9dbbb6686c1"
|
||||
|
||||
collapse-white-space@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.2.tgz#9c463fb9c6d190d2dcae21a356a01bcae9eeef6d"
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.3.tgz#4b906f670e5a963a87b76b0e1689643341b6023c"
|
||||
|
||||
color-convert@^1.0.0:
|
||||
version "1.9.0"
|
||||
@ -2081,8 +2076,8 @@ command-join@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/command-join/-/command-join-2.0.0.tgz#52e8b984f4872d952ff1bdc8b98397d27c7144cf"
|
||||
|
||||
commander@2, commander@^2.7.1, commander@^2.8.1, commander@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.10.0.tgz#e1f5d3245de246d1a5ca04702fa1ad1bd7e405fe"
|
||||
dependencies:
|
||||
graceful-readlink ">= 1.0.0"
|
||||
|
||||
@ -3352,8 +3347,8 @@ eslint-plugin-hapi@4.x.x:
|
||||
no-arrowception "1.x.x"
|
||||
|
||||
eslint-plugin-import@^2.3.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.5.0.tgz#293b5ea7910a901a05a47ccdd7546e611725406c"
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.6.0.tgz#2a4bbad36a078e052a3c830ce3dfbd6b8a12c6e5"
|
||||
dependencies:
|
||||
builtin-modules "^1.1.1"
|
||||
contains-path "^0.1.0"
|
||||
@ -3498,7 +3493,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.1, esprima@~3.1.0:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
|
||||
|
||||
@ -5009,14 +5004,14 @@ istanbul-lib-hook@^1.0.7:
|
||||
append-transform "^0.4.0"
|
||||
|
||||
istanbul-lib-instrument@^1.7.2:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.2.tgz#6014b03d3470fb77638d5802508c255c06312e56"
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.3.tgz#925b239163eabdd68cc4048f52c2fa4f899ecfa7"
|
||||
dependencies:
|
||||
babel-generator "^6.18.0"
|
||||
babel-template "^6.16.0"
|
||||
babel-traverse "^6.18.0"
|
||||
babel-types "^6.18.0"
|
||||
babylon "^6.13.0"
|
||||
babylon "^6.17.4"
|
||||
istanbul-lib-coverage "^1.1.1"
|
||||
semver "^5.3.0"
|
||||
|
||||
@ -5196,8 +5191,8 @@ jest-snapshot@^20.0.3:
|
||||
pretty-format "^20.0.3"
|
||||
|
||||
jest-styled-components@^3.0.2:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-3.1.3.tgz#eba50074b426e36fd2be99187dffa4b5569eab00"
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-3.1.5.tgz#c1e4fc60e534e54b26c3b733b65b44afd4f2795e"
|
||||
dependencies:
|
||||
css "^2.2.1"
|
||||
|
||||
@ -5460,8 +5455,8 @@ known-css-properties@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.2.0.tgz#899c94be368e55b42d7db8d5be7d73a4a4a41454"
|
||||
|
||||
lab@^14.0.1:
|
||||
version "14.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lab/-/lab-14.0.1.tgz#1a20100ecc692dbf91e849cd6b945b8e016a0527"
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/lab/-/lab-14.1.0.tgz#2632b9a416d5f391d9a6f1d98d607b0d69f75629"
|
||||
dependencies:
|
||||
bossy "3.x.x"
|
||||
code "4.1.x"
|
||||
@ -5934,8 +5929,8 @@ matcher@^0.1.1:
|
||||
escape-string-regexp "^1.0.4"
|
||||
|
||||
mathml-tag-names@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.0.0.tgz#eee615112a2b127e70f558d69c9ebe14076503d7"
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.0.1.tgz#8d41268168bf86d1102b98109e28e531e7a34578"
|
||||
|
||||
max-safe-int@^1.0.0:
|
||||
version "1.0.0"
|
||||
@ -6916,8 +6911,8 @@ podium@1.x.x:
|
||||
joi "10.x.x"
|
||||
|
||||
polished@^1.1.3:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/polished/-/polished-1.2.0.tgz#241cbbbd848d62ca8776eee618383d72e95830c5"
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/polished/-/polished-1.2.1.tgz#83c18a85bf9d7023477cfc7049763b657d50f0f7"
|
||||
|
||||
pos@0.4.2:
|
||||
version "0.4.2"
|
||||
@ -7036,8 +7031,8 @@ pretty-ms@^2.0.0:
|
||||
plur "^1.0.0"
|
||||
|
||||
primer-support@*:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/primer-support/-/primer-support-4.0.0.tgz#3dbbb37e4e0f2ed2ea6035e0b79dd0cb33bae85e"
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/primer-support/-/primer-support-4.0.4.tgz#7f16ad577a61a960d0bccd72f2a6df506a14d69f"
|
||||
|
||||
primer-utilities@^3.0.0:
|
||||
version "3.5.0"
|
||||
@ -7526,7 +7521,7 @@ readline2@^1.0.1:
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
mute-stream "0.0.5"
|
||||
|
||||
recast@0.11.12, recast@^0.11.5:
|
||||
recast@0.11.12:
|
||||
version "0.11.12"
|
||||
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.12.tgz#a79e4d3f82d5d72a82ee177aeaa791e793bbe5d6"
|
||||
dependencies:
|
||||
@ -7535,6 +7530,15 @@ recast@0.11.12, recast@^0.11.5:
|
||||
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"
|
||||
@ -8314,8 +8318,8 @@ spache@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/spache/-/spache-1.1.0.tgz#8c68ba807630f0199429c2035c82ed96f5438cd5"
|
||||
|
||||
spawn-wrap@^1.3.6:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.3.6.tgz#ccec4a949d8ce7e2b1a35cf4671d683d2e76a1d1"
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.3.7.tgz#beb8bf4426d64b2b06871e0d7dee2643f1f8d1bc"
|
||||
dependencies:
|
||||
foreground-child "^1.5.6"
|
||||
mkdirp "^0.5.0"
|
||||
@ -8714,10 +8718,6 @@ stylelint@^7.0.0, stylelint@^7.0.3, stylelint@^7.11.1:
|
||||
svg-tags "^1.0.0"
|
||||
table "^4.0.1"
|
||||
|
||||
stylis@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-2.0.0.tgz#6785a6546bd73478799a67d49d67086953b50ad5"
|
||||
|
||||
stylis@^3.0.19:
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.1.9.tgz#638370451f980437f57c59e58d2e296be29fafb7"
|
||||
@ -9128,9 +9128,9 @@ trim@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd"
|
||||
|
||||
triton-watch@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/triton-watch/-/triton-watch-1.0.1.tgz#b1087f6a57383f1e83d0a308e65110ca9a2a38d0"
|
||||
triton-watch@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/triton-watch/-/triton-watch-1.1.0.tgz#d2b47fbf6a45174198c196152bb86c696a923c35"
|
||||
dependencies:
|
||||
triton "5.2.x"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user