1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-05 17:53:12 +02:00

Merge branch 'master' into feat/metrics_env

This commit is contained in:
Ivar Conradi Østhus 2021-10-06 12:32:34 +02:00 committed by GitHub
commit 601ab5ccf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 432 additions and 98 deletions

View File

@ -0,0 +1,45 @@
name: PullRequestJestReport
on:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
services:
# Label used to access the service container
postgres:
# Docker Hub image
image: postgres
# Provide the password for postgres
env:
POSTGRES_PASSWORD: postgres
# Set health checks to wait until postgres has started
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Tests on ${{ matrix.node-version }}
uses: artiomtr/jest-coverage-report-action@v2.0-rc.1
with:
package-manager: yarn
github-token: ${{ secrets.GITHUB_TOKEN }}
test-script: yarn run test:coverage
env:
CI: true
TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres

View File

@ -127,8 +127,8 @@
"@types/stoppable": "1.1.1",
"@types/supertest": "2.0.11",
"@types/uuid": "8.3.1",
"@typescript-eslint/eslint-plugin": "4.32.0",
"@typescript-eslint/parser": "4.32.0",
"@typescript-eslint/eslint-plugin": "4.33.0",
"@typescript-eslint/parser": "4.33.0",
"copyfiles": "2.4.1",
"coveralls": "3.1.1",
"del-cli": "4.0.1",
@ -143,7 +143,7 @@
"husky": "7.0.2",
"jest": "27.2.4",
"jest-fetch-mock": "3.0.3",
"lint-staged": "11.1.2",
"lint-staged": "11.2.0",
"prettier": "2.4.1",
"proxyquire": "2.1.3",
"source-map-support": "0.5.20",

View File

@ -10,7 +10,10 @@ import { DB_TIME } from '../metric-events';
import { IFeatureEnvironment } from '../types/model';
import NotFoundError from '../error/notfound-error';
const T = { featureEnvs: 'feature_environments' };
const T = {
featureEnvs: 'feature_environments',
featureStrategies: 'feature_strategies',
};
interface IFeatureEnvironmentRow {
environment: string;
@ -92,6 +95,22 @@ export class FeatureEnvironmentStore implements IFeatureEnvironmentStore {
}));
}
async disableEnvironmentIfNoStrategies(
featureName: string,
environment: string,
): Promise<void> {
const result = await this.db.raw(
`SELECT EXISTS (SELECT 1 FROM ${T.featureStrategies} WHERE feature_name = ? AND environment = ?) AS enabled`,
[featureName, environment],
);
const { enabled } = result.rows[0];
if (!enabled) {
await this.db(T.featureEnvs)
.update({ enabled: false })
.where({ feature_name: featureName, environment });
}
}
async addEnvironmentToFeature(
featureName: string,
environment: string,

View File

@ -351,7 +351,14 @@ class FeatureStrategiesStore implements IFeatureStrategiesStore {
}, {});
return Object.values(overview).map((o: IFeatureOverview) => ({
...o,
environments: o.environments.filter((f) => f.name),
environments: o.environments
.filter((f) => f.name)
.sort((a, b) => {
if (a.sortOrder === b.sortOrder) {
return a.name.localeCompare(b.name);
}
return a.sortOrder - b.sortOrder;
}),
}));
}
return [];

View File

@ -300,12 +300,13 @@ export default class ProjectFeaturesController extends Controller {
res: Response,
): Promise<void> {
this.logger.info('Deleting strategy');
const { environment, projectId } = req.params;
const { environment, projectId, featureName } = req.params;
const userName = extractUsername(req);
const { strategyId } = req.params;
this.logger.info(strategyId);
const strategy = await this.featureService.deleteStrategy(
strategyId,
featureName,
userName,
projectId,
environment,

View File

@ -226,6 +226,7 @@ class FeatureToggleServiceV2 {
*/
async deleteStrategy(
id: string,
featureName: string,
userName: string,
project: string = 'default',
environment: string = DEFAULT_ENV,
@ -240,6 +241,11 @@ class FeatureToggleServiceV2 {
id,
},
});
// If there are no strategies left for environment disable it
await this.featureEnvironmentStore.disableEnvironmentIfNoStrategies(
featureName,
environment,
);
}
async getStrategiesForEnvironment(

View File

@ -34,7 +34,10 @@ export interface IFeatureEnvironmentStore
environment: string,
enabled: boolean,
): Promise<void>;
disableEnvironmentIfNoStrategies(
featureName: string,
environment: string,
): Promise<void>;
disconnectFeatures(environment: string, project: string): Promise<void>;
connectFeatures(environment: string, projectId: string): Promise<void>;

View File

@ -1108,3 +1108,140 @@ test('Feature strategies list should respect strategy sortorders for each enviro
expect(strategies[1].sortOrder).toBe(sortOrderSecond);
expect(strategies[2].sortOrder).toBe(sortOrderDefault);
});
test('Deleting last strategy for feature environment should disable that environment', async () => {
const envName = 'last_strategy_delete_env';
const featureName = 'last_strategy_delete_feature';
// Create environment
await db.stores.environmentStore.create({
name: envName,
type: 'test',
});
// Connect environment to project
await app.request
.post('/api/admin/projects/default/environments')
.send({
environment: envName,
})
.expect(200);
await app.request
.post('/api/admin/projects/default/features')
.send({ name: featureName })
.expect(201);
let strategyId;
await app.request
.post(
`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`,
)
.send({
name: 'default',
parameters: {
userId: 'string',
},
})
.expect(200)
.expect((res) => {
strategyId = res.body.id;
});
// Enable feature_environment
await app.request
.post(
`/api/admin/projects/default/features/${featureName}/environments/${envName}/on`,
)
.send({})
.expect(200);
await app.request
.get(
`/api/admin/projects/default/features/${featureName}/environments/${envName}`,
)
.expect(200)
.expect((res) => {
expect(res.body.enabled).toBeTruthy();
});
// Delete last strategy, this should also disable the environment
await app.request.delete(
`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/${strategyId}`,
);
await app.request
.get(
`/api/admin/projects/default/features/${featureName}/environments/${envName}`,
)
.expect(200)
.expect((res) => {
expect(res.body.enabled).toBeFalsy();
});
});
test('Deleting strategy for feature environment should not disable that environment as long as there are other strategies', async () => {
const envName = 'any_strategy_delete_env';
const featureName = 'any_strategy_delete_feature';
// Create environment
await db.stores.environmentStore.create({
name: envName,
type: 'test',
});
// Connect environment to project
await app.request
.post('/api/admin/projects/default/environments')
.send({
environment: envName,
})
.expect(200);
await app.request
.post('/api/admin/projects/default/features')
.send({ name: featureName })
.expect(201);
let strategyId;
await app.request
.post(
`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`,
)
.send({
name: 'default',
parameters: {
userId: 'string',
},
})
.expect(200)
.expect((res) => {
strategyId = res.body.id;
});
await app.request
.post(
`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies`,
)
.send({
name: 'default',
parameters: {
customerId: 'string',
},
})
.expect(200);
// Enable feature_environment
await app.request
.post(
`/api/admin/projects/default/features/${featureName}/environments/${envName}/on`,
)
.send({})
.expect(200);
await app.request
.get(
`/api/admin/projects/default/features/${featureName}/environments/${envName}`,
)
.expect(200)
.expect((res) => {
expect(res.body.enabled).toBeTruthy();
});
// Delete a strategy, this should also disable the environment
await app.request.delete(
`/api/admin/projects/default/features/${featureName}/environments/${envName}/strategies/${strategyId}`,
);
await app.request
.get(
`/api/admin/projects/default/features/${featureName}/environments/${envName}`,
)
.expect(200)
.expect((res) => {
expect(res.body.enabled).toBeTruthy();
});
});

View File

@ -155,3 +155,90 @@ test('Health report for non-existing project yields 404', async () => {
.get('/api/admin/projects/some-crazy-project-name/health-report')
.expect(404);
});
test('Sorts environments by sort order', async () => {
const envOne = 'my-sorted-env1';
const envTwo = 'my-sorted-env2';
const featureName = 'My-new-toggle';
const defaultEnvName = 'default';
await db.stores.environmentStore.create({
name: envOne,
type: 'production',
sortOrder: 0,
});
await db.stores.environmentStore.create({
name: envTwo,
type: 'production',
sortOrder: 500,
});
await app.request
.post('/api/admin/projects/default/environments')
.send({
environment: envOne,
})
.expect(200);
await app.request
.post('/api/admin/projects/default/environments')
.send({
environment: envTwo,
})
.expect(200);
await app.request
.post('/api/admin/projects/default/features')
.send({ name: featureName })
.expect(201);
await app.request.get('/api/admin/projects/default').expect((res) => {
const feature = res.body.features[0];
expect(feature.environments[0].name).toBe(envOne);
expect(feature.environments[1].name).toBe(defaultEnvName);
expect(feature.environments[2].name).toBe(envTwo);
});
});
test('Sorts environments correctly if sort order is equal', async () => {
const envOne = 'my-sorted-env3';
const envTwo = 'my-sorted-env4';
const featureName = 'My-new-toggle-2';
await db.stores.environmentStore.create({
name: envOne,
type: 'production',
sortOrder: -5,
});
await db.stores.environmentStore.create({
name: envTwo,
type: 'production',
sortOrder: -5,
});
await app.request
.post('/api/admin/projects/default/environments')
.send({
environment: envOne,
})
.expect(200);
await app.request
.post('/api/admin/projects/default/environments')
.send({
environment: envTwo,
})
.expect(200);
await app.request
.post('/api/admin/projects/default/features')
.send({ name: featureName })
.expect(201);
await app.request.get('/api/admin/projects/default').expect((res) => {
const feature = res.body.features[0];
expect(feature.environments[0].name).toBe(envOne);
expect(feature.environments[1].name).toBe(envTwo);
});
});

View File

@ -148,4 +148,13 @@ export default class FakeFeatureEnvironmentStore
): Promise<void> {
return Promise.reject(new Error('Not implemented'));
}
disableEnvironmentIfNoStrategies(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
featureName: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
environment: string,
): Promise<void> {
return Promise.reject(new Error('Not implemented'));
}
}

View File

@ -49,5 +49,6 @@ To make use of toggle variants, you need to use a compatible client. Client SDK
- [unleash-client-python](https://github.com/Unleash/unleash-client-python) (from v3.3.0)
- [unleash-client-dotnet](https://github.com/Unleash/unleash-client-dotnet) (from v1.3.6)
- [unleash-client-go](https://github.com/Unleash/unleash-client-go) (from v3 branch)
- [unleash-client-php](https://github.com/Unleash/unleash-client-php) (from v1.0.0)
If you would like to give feedback on this feature, experience issues or have questions, please feel free to open an issue on [GitHub](https://github.com/Unleash/unleash/).

View File

@ -76,4 +76,26 @@ $context = new UnleashContext(
$unleash->isEnabled("someToggle", $context);
```
**b) Via a UnleashContextProvider**
This is a bit more advanced approach, where you configure a unleash-context provider. By doing this you do not have to rebuild or to pass the unleash-context object to every place you are calling `$unleash->isEnabled()`.
```php
<?php
use Unleash\Client\UnleashBuilder;
$contextProvider = new MyAwesomeContextProvider();
$unleash = UnleashBuilder::create()
->withAppName('my.php-app')
->withInstanceId('your-instance-1')
->withAppUrl('http://unleash.herokuapp.com/api/')
->withContextProvider($contextProvider)
->build();
// Anywhere in the code unleash will get the unleash context from your registered provider.
$unleash->isEnabled("someToggle");
```
> You can read more complete documentation in the [Client SDK repository](https://github.com/Unleash/unleash-client-php).

179
yarn.lock
View File

@ -925,13 +925,13 @@
dependencies:
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@4.32.0":
version "4.32.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.32.0.tgz#46d2370ae9311092f2a6f7246d28357daf2d4e89"
integrity sha512-+OWTuWRSbWI1KDK8iEyG/6uK2rTm3kpS38wuVifGUTDB6kjEuNrzBI1MUtxnkneuWG/23QehABe2zHHrj+4yuA==
"@typescript-eslint/eslint-plugin@4.33.0":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276"
integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==
dependencies:
"@typescript-eslint/experimental-utils" "4.32.0"
"@typescript-eslint/scope-manager" "4.32.0"
"@typescript-eslint/experimental-utils" "4.33.0"
"@typescript-eslint/scope-manager" "4.33.0"
debug "^4.3.1"
functional-red-black-tree "^1.0.1"
ignore "^5.1.8"
@ -939,60 +939,60 @@
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/experimental-utils@4.32.0":
version "4.32.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.32.0.tgz#53a8267d16ca5a79134739129871966c56a59dc4"
integrity sha512-WLoXcc+cQufxRYjTWr4kFt0DyEv6hDgSaFqYhIzQZ05cF+kXfqXdUh+//kgquPJVUBbL3oQGKQxwPbLxHRqm6A==
"@typescript-eslint/experimental-utils@4.33.0":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd"
integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==
dependencies:
"@types/json-schema" "^7.0.7"
"@typescript-eslint/scope-manager" "4.32.0"
"@typescript-eslint/types" "4.32.0"
"@typescript-eslint/typescript-estree" "4.32.0"
"@typescript-eslint/scope-manager" "4.33.0"
"@typescript-eslint/types" "4.33.0"
"@typescript-eslint/typescript-estree" "4.33.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/parser@4.32.0":
version "4.32.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.32.0.tgz#751ecca0e2fecd3d44484a9b3049ffc1871616e5"
integrity sha512-lhtYqQ2iEPV5JqV7K+uOVlPePjClj4dOw7K4/Z1F2yvjIUvyr13yJnDzkK6uon4BjHYuHy3EG0c2Z9jEhFk56w==
"@typescript-eslint/parser@4.33.0":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899"
integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==
dependencies:
"@typescript-eslint/scope-manager" "4.32.0"
"@typescript-eslint/types" "4.32.0"
"@typescript-eslint/typescript-estree" "4.32.0"
"@typescript-eslint/scope-manager" "4.33.0"
"@typescript-eslint/types" "4.33.0"
"@typescript-eslint/typescript-estree" "4.33.0"
debug "^4.3.1"
"@typescript-eslint/scope-manager@4.32.0":
version "4.32.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.32.0.tgz#e03c8668f8b954072b3f944d5b799c0c9225a7d5"
integrity sha512-DK+fMSHdM216C0OM/KR1lHXjP1CNtVIhJ54kQxfOE6x8UGFAjha8cXgDMBEIYS2XCYjjCtvTkjQYwL3uvGOo0w==
"@typescript-eslint/scope-manager@4.33.0":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3"
integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==
dependencies:
"@typescript-eslint/types" "4.32.0"
"@typescript-eslint/visitor-keys" "4.32.0"
"@typescript-eslint/types" "4.33.0"
"@typescript-eslint/visitor-keys" "4.33.0"
"@typescript-eslint/types@4.32.0":
version "4.32.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.32.0.tgz#52c633c18da47aee09449144bf59565ab36df00d"
integrity sha512-LE7Z7BAv0E2UvqzogssGf1x7GPpUalgG07nGCBYb1oK4mFsOiFC/VrSMKbZQzFJdN2JL5XYmsx7C7FX9p9ns0w==
"@typescript-eslint/types@4.33.0":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72"
integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==
"@typescript-eslint/typescript-estree@4.32.0":
version "4.32.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.32.0.tgz#db00ccc41ccedc8d7367ea3f50c6994b8efa9f3b"
integrity sha512-tRYCgJ3g1UjMw1cGG8Yn1KzOzNlQ6u1h9AmEtPhb5V5a1TmiHWcRyF/Ic+91M4f43QeChyYlVTcf3DvDTZR9vw==
"@typescript-eslint/typescript-estree@4.33.0":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609"
integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==
dependencies:
"@typescript-eslint/types" "4.32.0"
"@typescript-eslint/visitor-keys" "4.32.0"
"@typescript-eslint/types" "4.33.0"
"@typescript-eslint/visitor-keys" "4.33.0"
debug "^4.3.1"
globby "^11.0.3"
is-glob "^4.0.1"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/visitor-keys@4.32.0":
version "4.32.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.32.0.tgz#455ba8b51242f2722a497ffae29313f33b14cb7f"
integrity sha512-e7NE0qz8W+atzv3Cy9qaQ7BTLwWsm084Z0c4nIO2l3Bp6u9WIgdqCgyPyV5oSPDMIW3b20H59OOCmVk3jw3Ptw==
"@typescript-eslint/visitor-keys@4.33.0":
version "4.33.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd"
integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==
dependencies:
"@typescript-eslint/types" "4.32.0"
"@typescript-eslint/types" "4.33.0"
eslint-visitor-keys "^2.0.0"
abab@^2.0.3, abab@^2.0.5:
@ -1563,7 +1563,7 @@ chalk@^2.0.0:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1:
chalk@^4.0.0:
version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@ -1613,9 +1613,9 @@ cli-cursor@^3.1.0:
dependencies:
restore-cursor "^3.1.0"
cli-truncate@^2.1.0:
cli-truncate@2.1.0, cli-truncate@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7"
integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==
dependencies:
slice-ansi "^3.0.0"
@ -1696,6 +1696,11 @@ colorette@^1.2.2:
resolved "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
colorette@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==
colors@1.0.x:
version "1.0.3"
resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz"
@ -1718,11 +1723,16 @@ commander@^6.2.0:
resolved "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz"
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
commander@^7.1.0, commander@^7.2.0:
commander@^7.1.0:
version "7.2.0"
resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
commander@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8"
integrity sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA==
component-emitter@^1.2.1, component-emitter@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz"
@ -1882,10 +1892,10 @@ cors@^2.8.5:
object-assign "^4"
vary "^1"
cosmiconfig@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz"
integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==
cosmiconfig@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
dependencies:
"@types/parse-json" "^4.0.0"
import-fresh "^3.2.1"
@ -2045,7 +2055,7 @@ debug@3.2.6:
dependencies:
ms "^2.1.1"
debug@4, debug@4.3.2, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
debug@4, debug@4.3.2, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
version "4.3.2"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
@ -2641,7 +2651,7 @@ event-stream@=3.3.4:
stream-combiner "~0.0.4"
through "~2.3.1"
execa@^5.0.0:
execa@^5.0.0, execa@^5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz"
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
@ -3799,11 +3809,6 @@ is-unc-path@^1.0.0:
dependencies:
unc-path-regex "^0.1.2"
is-unicode-supported@^0.1.0:
version "0.1.0"
resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz"
integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
is-windows@^1.0.1, is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz"
@ -4581,33 +4586,33 @@ lines-and-columns@^1.1.6:
resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
lint-staged@11.1.2:
version "11.1.2"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.1.2.tgz#4dd78782ae43ee6ebf2969cad9af67a46b33cd90"
integrity sha512-6lYpNoA9wGqkL6Hew/4n1H6lRqF3qCsujVT0Oq5Z4hiSAM7S6NksPJ3gnr7A7R52xCtiZMcEUNNQ6d6X5Bvh9w==
lint-staged@11.2.0:
version "11.2.0"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.2.0.tgz#6b9774a74b3eb4bef5c59fb6475bff84d6853008"
integrity sha512-0KIcRuO4HQS2Su7qWtjrfTXgSklvyIb9Fk9qVWRZkGHa5S81Vj6WBbs+ogQBvHUwLJYq1eQ4R+H82GSak4OM7w==
dependencies:
chalk "^4.1.1"
cli-truncate "^2.1.0"
commander "^7.2.0"
cosmiconfig "^7.0.0"
debug "^4.3.1"
cli-truncate "2.1.0"
colorette "^1.4.0"
commander "^8.2.0"
cosmiconfig "^7.0.1"
debug "^4.3.2"
enquirer "^2.3.6"
execa "^5.0.0"
listr2 "^3.8.2"
log-symbols "^4.1.0"
execa "^5.1.1"
listr2 "^3.12.2"
micromatch "^4.0.4"
normalize-path "^3.0.0"
please-upgrade-node "^3.2.0"
string-argv "0.3.1"
stringify-object "^3.3.0"
stringify-object "3.3.0"
supports-color "8.1.1"
listr2@^3.8.2:
version "3.11.0"
resolved "https://registry.npmjs.org/listr2/-/listr2-3.11.0.tgz"
integrity sha512-XLJVe2JgXCyQTa3FbSv11lkKExYmEyA4jltVo8z4FX10Vt1Yj8IMekBfwim0BSOM9uj1QMTJvDQQpHyuPbB/dQ==
listr2@^3.12.2:
version "3.12.2"
resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.12.2.tgz#2d55cc627111603ad4768a9e87c9c7bb9b49997e"
integrity sha512-64xC2CJ/As/xgVI3wbhlPWVPx0wfTqbUAkpb7bjDi0thSWMqrf07UFhrfsGoo8YSXmF049Rp9C0cjLC8rZxK9A==
dependencies:
cli-truncate "^2.1.0"
colorette "^1.2.2"
colorette "^1.4.0"
log-update "^4.0.0"
p-map "^4.0.0"
rxjs "^6.6.7"
@ -4686,14 +4691,6 @@ log-driver@^1.2.7:
resolved "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz"
integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==
log-symbols@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz"
integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
dependencies:
chalk "^4.1.0"
is-unicode-supported "^0.1.0"
log-update@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz"
@ -6560,9 +6557,9 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
stringify-object@^3.3.0:
stringify-object@3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz"
resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
dependencies:
get-own-enumerable-property-symbols "^3.0.0"
@ -6647,6 +6644,13 @@ supertest@6.1.6:
methods "^1.1.2"
superagent "^6.1.0"
supports-color@8.1.1, supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
@ -6661,13 +6665,6 @@ supports-color@^7.0.0, supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-hyperlinks@^2.0.0:
version "2.2.0"
resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz"