From 3713248dd046ee8a7adedb9083d44e81567a7144 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2020 07:38:56 +0000 Subject: [PATCH 01/56] chore(deps): bump @svgr/webpack from 4.3.3 to 5.4.0 Bumps [@svgr/webpack](https://github.com/gregberge/svgr) from 4.3.3 to 5.4.0. - [Release notes](https://github.com/gregberge/svgr/releases) - [Changelog](https://github.com/gregberge/svgr/blob/master/CHANGELOG.md) - [Commits](https://github.com/gregberge/svgr/compare/v4.3.3...v5.4.0) Signed-off-by: dependabot-preview[bot] --- packages/cli/package.json | 2 +- yarn.lock | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 1467b4a16b..09b7af8bc0 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -43,7 +43,7 @@ "@svgr/plugin-jsx": "4.3.x", "@svgr/plugin-svgo": "4.3.x", "@svgr/rollup": "5.4.x", - "@svgr/webpack": "4.3.x", + "@svgr/webpack": "5.4.x", "@types/start-server-webpack-plugin": "^2.2.0", "@types/webpack-env": "^1.15.2", "@types/webpack-node-externals": "^2.5.0", diff --git a/yarn.lock b/yarn.lock index ad4c7bee55..18868cf96e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -791,7 +791,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.2.0", "@babel/plugin-transform-react-constant-elements@^7.6.3", "@babel/plugin-transform-react-constant-elements@^7.7.4": +"@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.2.0", "@babel/plugin-transform-react-constant-elements@^7.6.3", "@babel/plugin-transform-react-constant-elements@^7.7.4", "@babel/plugin-transform-react-constant-elements@^7.9.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.10.4.tgz#0f485260bf1c29012bb973e7e404749eaac12c9e" integrity sha512-cYmQBW1pXrqBte1raMkAulXmi7rjg3VI6ZLg9QIic8Hq7BtYXaWuZSxsr2siOMI6SWwpxjWfnwhTUrd7JlAV7g== @@ -3810,7 +3810,21 @@ "@svgr/plugin-svgo" "^5.4.0" rollup-pluginutils "^2.8.2" -"@svgr/webpack@4.3.x", "@svgr/webpack@^4.0.3": +"@svgr/webpack@5.4.x": + version "5.4.0" + resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.4.0.tgz#b68bc86e29cf007292b96ced65f80971175632e0" + integrity sha512-LjepnS/BSAvelnOnnzr6Gg0GcpLmnZ9ThGFK5WJtm1xOqdBE/1IACZU7MMdVzjyUkfFqGz87eRE4hFaSLiUwYg== + dependencies: + "@babel/core" "^7.9.0" + "@babel/plugin-transform-react-constant-elements" "^7.9.0" + "@babel/preset-env" "^7.9.5" + "@babel/preset-react" "^7.9.4" + "@svgr/core" "^5.4.0" + "@svgr/plugin-jsx" "^5.4.0" + "@svgr/plugin-svgo" "^5.4.0" + loader-utils "^2.0.0" + +"@svgr/webpack@^4.0.3": version "4.3.3" resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.3.tgz#13cc2423bf3dff2d494f16b17eb7eacb86895017" integrity sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg== From 6f3b0b8c20e9d1c5309f20470f2c3acc2a1b0ed3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 25 Aug 2020 18:25:56 +0200 Subject: [PATCH 02/56] catalog-backend: initial catalog ingestion rules implementation --- .../src/ingestion/CatalogRules.test.ts | 114 +++++++++++ .../src/ingestion/CatalogRules.ts | 187 ++++++++++++++++++ .../src/ingestion/LocationReaders.ts | 24 ++- 3 files changed, 320 insertions(+), 5 deletions(-) create mode 100644 plugins/catalog-backend/src/ingestion/CatalogRules.test.ts create mode 100644 plugins/catalog-backend/src/ingestion/CatalogRules.ts diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts new file mode 100644 index 0000000000..7f2ccdc254 --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts @@ -0,0 +1,114 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LocationSpec, Entity } from '@backstage/catalog-model'; +import { CatalogRulesEnforcer } from './CatalogRules'; + +const entity = { + user: { + kind: 'User', + } as Entity, + group: { + kind: 'Group', + } as Entity, + component: { + kind: 'component', + } as Entity, +}; + +const location: Record = { + x: { + type: 'github', + target: 'https://github.com/a/b/blob/master/x.yaml', + }, + y: { + type: 'github', + target: 'https://github.com/a/b/blob/master/y.yaml', + }, + z: { + type: 'file', + target: '/root/z.yaml', + }, +}; + +describe('CatalogRulesEnforcer', () => { + it('should allow by default', () => { + const enforcer = new CatalogRulesEnforcer([]); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + }); + + it('should deny all', () => { + const enforcer = new CatalogRulesEnforcer([{ allow: [] }]); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + }); + + it('should allow all with override', () => { + const enforcer = new CatalogRulesEnforcer([{ allow: [] }, { deny: [] }]); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + }); + + it('should deny groups', () => { + const enforcer = new CatalogRulesEnforcer([ + { allow: [], deny: [{ kind: 'Group' }] }, + ]); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + }); + + it('should deny groups from github', () => { + const enforcer = new CatalogRulesEnforcer([ + { allow: [], deny: [{ kind: 'Group' }], locations: [{ type: 'github' }] }, + ]); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + }); + + it('should override to allow groups from files', () => { + const enforcer = new CatalogRulesEnforcer([ + { allow: [], deny: [{ kind: 'Group' }] }, + { allow: [{ kind: 'Group' }], deny: [], locations: [{ type: 'file' }] }, + ]); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + }); + + it('should not be sensitive to kind case', () => { + const enforcer = new CatalogRulesEnforcer([ + { allow: [], deny: [{ kind: 'group' }] }, + { allow: [], deny: [{ kind: 'Component' }] }, + ]); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + }); +}); diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.ts new file mode 100644 index 0000000000..a03d93852a --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.ts @@ -0,0 +1,187 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config } from '@backstage/config'; +import { LocationSpec, Entity } from '@backstage/catalog-model'; + +/** + * A structure for matching entities to a given rule. + */ +type EntityMatcher = { + kind: string; +}; + +/** + * A structure for matching locations to a given rule. + */ +type LocationMatcher = { + target?: string; + type: string; +}; + +/** + * Rules to apply to catalog entities + * + * An undefined list of matchers means match all, an empty list of matchers means match none + */ +type CatalogRule = { + deny?: EntityMatcher[]; + allow?: EntityMatcher[]; + locations?: LocationMatcher[]; +}; + +export class CatalogRulesEnforcer { + /** + * Default rules used by the catalog. + * + * Denies any location from specifying user or group entities. + */ + static readonly defaultRules: CatalogRule[] = [ + { + deny: [{ kind: 'User' }, { kind: 'Group' }], + allow: [], + }, + ]; + + /** + * Loads catalog rules from config. + * + * This reads `catalog.rules` and defaults to the default rules if no value is present. + * The value of the config should be a list of config objects, each with a single `deny` + * field which in turn is a list of entity kind to deny. + * + * It also reads in rules from `catalog.locations`, where each location can have a list + * of allowed entity for the location, specified in an `allow` field. + * + * For example: + * + * ```yaml + * catalog: + * rules: + * - deny: [User, Group, System] + * + * locations: + * - type: github + * target: https://github.com/org/repo/blob/master/users.yaml + * allow: [User, Group] + * - type: github + * target: https://github.com/org/repo/blob/master/systems.yaml + * allow: [System] + * ``` + */ + static fromConfig(config: Config) { + const rules = new Array(); + + if (config.has('catalog.rules')) { + const globalRules = config.getConfigArray('catalog.rules').map(sub => ({ + deny: sub.getStringArray('deny').map(kind => ({ kind })), + allow: [], + })); + rules.push(...globalRules); + } else { + rules.push(...CatalogRulesEnforcer.defaultRules); + } + + if (config.has('catalog.locations')) { + const locationRules = config + .getConfigArray('catalog.locations') + .flatMap(sub => { + if (!sub.has('allow')) { + return []; + } + + return [ + { + deny: [], + allow: sub.getStringArray('allow').map(kind => ({ kind })), + locations: [ + { + type: sub.getString('type'), + target: sub.getString('target'), + }, + ], + }, + ]; + }); + + rules.push(...locationRules); + } + + return new CatalogRulesEnforcer(rules); + } + + constructor(private readonly rules: CatalogRule[]) {} + + /** + * Checks wether a specific entity/location combination is allowed + * according to the configured rules. + */ + isAllowed(entity: Entity, location: LocationSpec) { + let result = true; + + for (const rule of this.rules) { + if (!this.matchLocation(location, rule.locations)) { + continue; + } + + if (this.matchEntity(entity, rule.allow)) { + result = true; + } + if (this.matchEntity(entity, rule.deny)) { + result = false; + } + } + + return result; + } + + private matchLocation( + location: LocationSpec, + matchers?: LocationMatcher[], + ): boolean { + if (!matchers) { + return true; + } + + for (const matcher of matchers) { + if (matcher.type !== location.type) { + continue; + } + if (matcher.target && matcher.target !== location.target) { + continue; + } + return true; + } + + return false; + } + + private matchEntity(entity: Entity, matchers?: EntityMatcher[]): boolean { + if (!matchers) { + return true; + } + + for (const matcher of matchers) { + if (entity.kind.toLowerCase() !== matcher.kind.toLowerCase()) { + continue; + } + + return true; + } + + return false; + } +} diff --git a/plugins/catalog-backend/src/ingestion/LocationReaders.ts b/plugins/catalog-backend/src/ingestion/LocationReaders.ts index 46fa6781f1..bddef6b4de 100644 --- a/plugins/catalog-backend/src/ingestion/LocationReaders.ts +++ b/plugins/catalog-backend/src/ingestion/LocationReaders.ts @@ -47,6 +47,7 @@ import { } from './processors/types'; import { YamlProcessor } from './processors/YamlProcessor'; import { LocationReader, ReadLocationResult } from './types'; +import { CatalogRulesEnforcer } from './CatalogRules'; // The max amount of nesting depth of generated work items const MAX_DEPTH = 10; @@ -63,6 +64,7 @@ type Options = { export class LocationReaders implements LocationReader { private readonly logger: Logger; private readonly processors: LocationProcessor[]; + private readonly rulesEnforcer: CatalogRulesEnforcer; static defaultProcessors(options: { config?: Config; @@ -96,6 +98,9 @@ export class LocationReaders implements LocationReader { }: Options) { this.logger = logger; this.processors = processors; + this.rulesEnforcer = config + ? CatalogRulesEnforcer.fromConfig(config) + : new CatalogRulesEnforcer(CatalogRulesEnforcer.defaultRules); } async read(location: LocationSpec): Promise { @@ -112,11 +117,20 @@ export class LocationReaders implements LocationReader { } else if (item.type === 'data') { await this.handleData(item, emit); } else if (item.type === 'entity') { - const entity = await this.handleEntity(item, emit); - output.entities.push({ - entity, - location: item.location, - }); + if (this.rulesEnforcer.isAllowed(item.entity, item.location)) { + const entity = await this.handleEntity(item, emit); + output.entities.push({ + entity, + location: item.location, + }); + } else { + output.errors.push({ + location: item.location, + error: new Error( + `Entity of kind ${item.entity.kind} is not allowed from location ${item.location.target}:${item.location.type}`, + ), + }); + } } else if (item.type === 'error') { await this.handleError(item, emit); output.errors.push({ From 8d07b541d7eb037cea5a8a79c01135a02b98cab9 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 27 Aug 2020 20:54:56 +0200 Subject: [PATCH 03/56] catalog-backend: switch catalog rules to deny by default --- .../src/ingestion/CatalogRules.test.ts | 42 ++++++++++--------- .../src/ingestion/CatalogRules.ts | 27 +++++------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts index 7f2ccdc254..1168db1080 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts @@ -45,11 +45,11 @@ const location: Record = { }; describe('CatalogRulesEnforcer', () => { - it('should allow by default', () => { + it('should deny by default', () => { const enforcer = new CatalogRulesEnforcer([]); - expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); - expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); - expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); }); it('should deny all', () => { @@ -59,8 +59,10 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); }); - it('should allow all with override', () => { - const enforcer = new CatalogRulesEnforcer([{ allow: [] }, { deny: [] }]); + it('should allow all', () => { + const enforcer = new CatalogRulesEnforcer([ + { allow: [{ kind: 'User' }, { kind: 'Group' }, { kind: 'Component' }] }, + ]); expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); @@ -68,7 +70,7 @@ describe('CatalogRulesEnforcer', () => { it('should deny groups', () => { const enforcer = new CatalogRulesEnforcer([ - { allow: [], deny: [{ kind: 'Group' }] }, + { allow: [{ kind: 'User' }, { kind: 'Component' }] }, ]); expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); @@ -79,7 +81,8 @@ describe('CatalogRulesEnforcer', () => { it('should deny groups from github', () => { const enforcer = new CatalogRulesEnforcer([ - { allow: [], deny: [{ kind: 'Group' }], locations: [{ type: 'github' }] }, + { allow: [{ kind: 'User' }, { kind: 'Component' }] }, + { allow: [{ kind: 'Group' }], locations: [{ type: 'file' }] }, ]); expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); @@ -88,27 +91,26 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); }); - it('should override to allow groups from files', () => { + it('should allow groups from files', () => { const enforcer = new CatalogRulesEnforcer([ - { allow: [], deny: [{ kind: 'Group' }] }, - { allow: [{ kind: 'Group' }], deny: [], locations: [{ type: 'file' }] }, + { allow: [{ kind: 'Group' }], locations: [{ type: 'file' }] }, ]); - expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); expect(enforcer.isAllowed(entity.group, location.z)).toBe(true); - expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); }); it('should not be sensitive to kind case', () => { const enforcer = new CatalogRulesEnforcer([ - { allow: [], deny: [{ kind: 'group' }] }, - { allow: [], deny: [{ kind: 'Component' }] }, + { allow: [{ kind: 'group' }] }, + { allow: [{ kind: 'Component' }] }, ]); - expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); - expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); - expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); - expect(enforcer.isAllowed(entity.group, location.z)).toBe(false); - expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); }); }); diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.ts index a03d93852a..eda93b552f 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.ts @@ -38,8 +38,7 @@ type LocationMatcher = { * An undefined list of matchers means match all, an empty list of matchers means match none */ type CatalogRule = { - deny?: EntityMatcher[]; - allow?: EntityMatcher[]; + allow: EntityMatcher[]; locations?: LocationMatcher[]; }; @@ -51,8 +50,7 @@ export class CatalogRulesEnforcer { */ static readonly defaultRules: CatalogRule[] = [ { - deny: [{ kind: 'User' }, { kind: 'Group' }], - allow: [], + allow: [{ kind: 'Component' }, { kind: 'API' }], }, ]; @@ -60,8 +58,10 @@ export class CatalogRulesEnforcer { * Loads catalog rules from config. * * This reads `catalog.rules` and defaults to the default rules if no value is present. - * The value of the config should be a list of config objects, each with a single `deny` - * field which in turn is a list of entity kind to deny. + * The value of the config should be a list of config objects, each with a single `allow` + * field which in turn is a list of entity kinds to allow. + * + * If there is no matching rule to allow an ingested entity, it will be rejected by the catalog. * * It also reads in rules from `catalog.locations`, where each location can have a list * of allowed entity for the location, specified in an `allow` field. @@ -71,7 +71,7 @@ export class CatalogRulesEnforcer { * ```yaml * catalog: * rules: - * - deny: [User, Group, System] + * - allow: [Component, API] * * locations: * - type: github @@ -87,8 +87,7 @@ export class CatalogRulesEnforcer { if (config.has('catalog.rules')) { const globalRules = config.getConfigArray('catalog.rules').map(sub => ({ - deny: sub.getStringArray('deny').map(kind => ({ kind })), - allow: [], + allow: sub.getStringArray('allow').map(kind => ({ kind })), })); rules.push(...globalRules); } else { @@ -105,7 +104,6 @@ export class CatalogRulesEnforcer { return [ { - deny: [], allow: sub.getStringArray('allow').map(kind => ({ kind })), locations: [ { @@ -130,22 +128,17 @@ export class CatalogRulesEnforcer { * according to the configured rules. */ isAllowed(entity: Entity, location: LocationSpec) { - let result = true; - for (const rule of this.rules) { if (!this.matchLocation(location, rule.locations)) { continue; } if (this.matchEntity(entity, rule.allow)) { - result = true; - } - if (this.matchEntity(entity, rule.deny)) { - result = false; + return true; } } - return result; + return false; } private matchLocation( From 903cbdcfb5120f3414662c51b839e89892404af3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 31 Aug 2020 00:24:18 +0200 Subject: [PATCH 04/56] catalog-backend: add tests for config rules --- .../src/ingestion/CatalogRules.test.ts | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts index 1168db1080..4a403f8dfa 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts @@ -16,6 +16,7 @@ import { LocationSpec, Entity } from '@backstage/catalog-model'; import { CatalogRulesEnforcer } from './CatalogRules'; +import { ConfigReader } from '@backstage/config'; const entity = { user: { @@ -113,4 +114,70 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.group, location.z)).toBe(true); expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); }); + + describe('fromConfig', () => { + it('should allow components by default', () => { + const enforcer = CatalogRulesEnforcer.fromConfig(new ConfigReader({})); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + }); + + it('should deny all', () => { + const enforcer = CatalogRulesEnforcer.fromConfig( + new ConfigReader({ catalog: { rules: [] } }), + ); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + }); + + it('should allow all', () => { + const enforcer = CatalogRulesEnforcer.fromConfig( + new ConfigReader({ + catalog: { + rules: [{ allow: ['User', 'Group'] }, { allow: ['Component'] }], + }, + }), + ); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + }); + + it('should deny groups', () => { + const enforcer = CatalogRulesEnforcer.fromConfig( + new ConfigReader({ + catalog: { rules: [{ allow: ['User'] }, { allow: ['Component'] }] }, + }), + ); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + }); + + it('should allow groups from a specific github location', () => { + const enforcer = CatalogRulesEnforcer.fromConfig( + new ConfigReader({ + catalog: { + rules: [{ allow: ['user'] }], + locations: [ + { + type: 'github', + target: 'https://github.com/a/b/blob/master/x.yaml', + allow: ['Group'], + }, + ], + }, + }), + ); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + }); + }); }); From f546bb3862893d85a7f3cfdf84005d2fd603065e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 31 Aug 2020 01:05:54 +0200 Subject: [PATCH 05/56] docs: added catalog configuration docs --- .../software-catalog/configuration.md | 60 +++++++++++++++++++ docs/features/software-catalog/index.md | 16 +++++ mkdocs.yml | 1 + 3 files changed, 77 insertions(+) create mode 100644 docs/features/software-catalog/configuration.md diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md new file mode 100644 index 0000000000..77b630d347 --- /dev/null +++ b/docs/features/software-catalog/configuration.md @@ -0,0 +1,60 @@ +--- +id: software-catalog-configuration +title: Catalog Configuration +--- + +## Static Location Configuration + +To enable declarative catalog setups, it is possible to add locations to the +catalog via [static configuration](../../conf/index.md). Locations are added to +the catalog under the `catalog.locations` key, for example: + +```yaml +catalog: + locations: + - type: github + target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml +``` + +The locations added through static configuration can not be removed through the +catalog locations API. To remove the locations, you have to remove them from the +configuration. + +## Catalog Rules + +By default the catalog will only allow ingestion of entities with the kind +`Component` and `API`. In order to allow entities of other kinds to be added, +you need to add rules to the catalog. Rules are added either in a separate +`catalog.rules` key, or added to statically configured locations. + +For example, given the following configuration: + +```yaml +catalog: + rules: + - allow: [Component, API] + - allow: [System] + locations: + type: github + + locations: + - type: github + target: https://github.com/org/example/blob/master/org-data.yaml + allow: [Group] +``` + +We are able to add entities of kind `Component` or `API` from any location, +entities of kind `System` from any `github` location, and `Group` entities from +the `org-data.yaml`, which will also be read as statically configured location. + +Note that if the `catalog.rules` key is present it will replace the default +value, meaning that you need to add rules for `Component` and `API` kinds if you +want those to be allowed. + +The following configuration will reject any kind of entities from being added to +the catalog: + +```yaml +catalog: + rules: [] +``` diff --git a/docs/features/software-catalog/index.md b/docs/features/software-catalog/index.md index db8c183390..bfc3d53d4d 100644 --- a/docs/features/software-catalog/index.md +++ b/docs/features/software-catalog/index.md @@ -79,6 +79,22 @@ All software created through the [Backstage Software Templates](../software-templates/index.md) are automatically registered in the catalog. +### Static catalog configuration + +In addition to manually registering components, it is also possible to register +components though [static configuration](../../conf/index.md). For example, the +above example can be added using the following configuration: + +```yaml +catalog: + locations: + - type: github + target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml +``` + +More information about catalog configuration can be found +[here](configuration.md). + ### Updating component metadata Teams owning the components are responsible for maintaining the metadata about diff --git a/mkdocs.yml b/mkdocs.yml index 637e45c0f0..b12c8f81c7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -28,6 +28,7 @@ nav: - Overview: 'features/software-catalog/index.md' - System model: 'features/software-catalog/system-model.md' - YAML File Format: 'features/software-catalog/descriptor-format.md' + - Configuration: 'features/software-catalog/configuration.md' - Extending the model: 'features/software-catalog/extending-the-model.md' - External integrations: 'features/software-catalog/external-integrations.md' - API: 'features/software-catalog/api.md' From 74e55ef32f173e2e89656bbe03802426453df5f2 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 31 Aug 2020 13:40:05 +0200 Subject: [PATCH 06/56] catalog-backend: updated docs to not include location in catalog.rules + test --- docs/features/software-catalog/configuration.md | 11 ++++------- .../src/ingestion/CatalogRules.test.ts | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 77b630d347..d4cc7fc0c2 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -32,10 +32,7 @@ For example, given the following configuration: ```yaml catalog: rules: - - allow: [Component, API] - - allow: [System] - locations: - type: github + - allow: [Component, API, System] locations: - type: github @@ -43,9 +40,9 @@ catalog: allow: [Group] ``` -We are able to add entities of kind `Component` or `API` from any location, -entities of kind `System` from any `github` location, and `Group` entities from -the `org-data.yaml`, which will also be read as statically configured location. +We are able to add entities of kind `Component`, `API`, or `System` from any +location, and `Group` entities from the `org-data.yaml`, which will also be read +as statically configured location. Note that if the `catalog.rules` key is present it will replace the default value, meaning that you need to add rules for `Component` and `API` kinds if you diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts index 4a403f8dfa..34484f6b1e 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts @@ -179,5 +179,20 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.group, location.z)).toBe(false); expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); }); + + it('should not care about location configuration in catalog.rules', () => { + const enforcer = CatalogRulesEnforcer.fromConfig( + new ConfigReader({ + catalog: { + rules: [{ allow: ['Group'], locations: [{ type: 'github' }] }], + }, + }), + ); + expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); + expect(enforcer.isAllowed(entity.group, location.x)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); + expect(enforcer.isAllowed(entity.group, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + }); }); }); From b602a7b729f8a3a388a8f6b8d61336bcbc0a6e82 Mon Sep 17 00:00:00 2001 From: Emma Indal Date: Mon, 31 Aug 2020 15:13:42 +0200 Subject: [PATCH 07/56] Remove WIP (#2185) --- packages/techdocs-container/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/techdocs-container/README.md b/packages/techdocs-container/README.md index 2bfa9a1d26..aa1bf15974 100644 --- a/packages/techdocs-container/README.md +++ b/packages/techdocs-container/README.md @@ -2,8 +2,6 @@ This is the Docker container that powers the creation of static documentation sites that are supported by [TechDocs](https://github.com/spotify/backstage/blob/master/plugins/techdocs). -**WIP: This is a work in progress. It is not ready for use yet. Follow our progress on [the Backstage Discord](https://discord.gg/MUpMjP2) under #docs-like-code or on [our GitHub Milestone](https://github.com/spotify/backstage/milestone/15).** - ## Getting Started Using the TechDocs CLI, we can invoke the latest version of `techdocs-container` via Docker Hub: From 0c29e3d410472c40ab939e1b73a934bebb410a3f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 31 Aug 2020 14:51:34 +0200 Subject: [PATCH 08/56] workflows: add discord notification --- .github/workflows/master.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 04b50c3e60..354838037e 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -74,3 +74,11 @@ jobs: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" package_root: "packages/core" tag_prefix: "v" + + - name: Discord notification + if: ${{ failure() }} + uses: Ilshidur/action-discord@0.2.0 + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + with: + args: 'Master build failed https://github.com/{{GITHUB_REPOSITORY}}/actions/runs/{{GITHUB_RUN_ID}}' From f14ebd6d186b85311347feda95df1f7ef9cbc7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20=C3=85lund?= Date: Mon, 31 Aug 2020 17:29:29 +0200 Subject: [PATCH 09/56] Add more plugins to Marketplace (#2192) --- microsite/data/plugins/circleci.yaml | 9 +++++++++ microsite/data/plugins/gitops-cluster.yaml | 14 ++++++++++++++ microsite/data/plugins/graphiql.yaml | 13 +++++++++++++ microsite/data/plugins/lighthouse.yaml | 14 ++++++++++++++ microsite/data/plugins/new-relic.yaml | 14 ++++++++++++++ microsite/data/plugins/tech-radar.yaml | 9 +++++++++ microsite/i18n/en.json | 2 +- 7 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 microsite/data/plugins/circleci.yaml create mode 100644 microsite/data/plugins/gitops-cluster.yaml create mode 100644 microsite/data/plugins/graphiql.yaml create mode 100644 microsite/data/plugins/lighthouse.yaml create mode 100644 microsite/data/plugins/new-relic.yaml create mode 100644 microsite/data/plugins/tech-radar.yaml diff --git a/microsite/data/plugins/circleci.yaml b/microsite/data/plugins/circleci.yaml new file mode 100644 index 0000000000..c8a3677614 --- /dev/null +++ b/microsite/data/plugins/circleci.yaml @@ -0,0 +1,9 @@ +--- +title: CircleCI +author: Spotify +authorUrl: https://www.spotify.com/ +category: CI +description: Automate your development process with CI hosted in the cloud or on a private server. +documentation: https://github.com/spotify/backstage/tree/master/plugins/circleci +iconUrl: https://d3r49iyjzglexf.cloudfront.net/logo-wordmark-26f8eaea9b0f6e13b90d3f4a8fd8fda31490f5af41daab98bbede45037682576.svg +npmPackageName: '@backstage/plugin-circleci' diff --git a/microsite/data/plugins/gitops-cluster.yaml b/microsite/data/plugins/gitops-cluster.yaml new file mode 100644 index 0000000000..6f8ab6b097 --- /dev/null +++ b/microsite/data/plugins/gitops-cluster.yaml @@ -0,0 +1,14 @@ +--- +title: GitOps Clusters +author: Weaveworks +authorUrl: https://www.weave.works/ +category: Kubernetes +description: Create GitOps-managed Kubernetes clusters. Currently, it supports provisioning EKS clusters on GitHub via GitHub Actions. +documentation: https://github.com/spotify/backstage/tree/master/plugins/gitops-profiles +iconUrl: https://res-5.cloudinary.com/crunchbase-production/image/upload/c_lpad,h_256,w_256,f_auto,q_auto:eco/v1462316670/i9d3delzvx1erzjhmcws.png +npmPackageName: '@backstage/plugin-gitops-profiles' +tags: + - kubernetes + - gitops + - github + - eks diff --git a/microsite/data/plugins/graphiql.yaml b/microsite/data/plugins/graphiql.yaml new file mode 100644 index 0000000000..73733c84fd --- /dev/null +++ b/microsite/data/plugins/graphiql.yaml @@ -0,0 +1,13 @@ +--- +title: GraphiQL +author: Spotify +authorUrl: https://www.spotify.com/ +category: Debugging +description: Integrates GraphiQL as a tool to browse GraphiQL endpoints inside Backstage. +documentation: https://github.com/spotify/backstage/tree/master/plugins/lighthouse +iconUrl: https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/GraphQL_Logo.svg/1024px-GraphQL_Logo.svg.png +npmPackageName: '@backstage/plugin-graphiql' +tags: + - graphql + - github + - gitlab diff --git a/microsite/data/plugins/lighthouse.yaml b/microsite/data/plugins/lighthouse.yaml new file mode 100644 index 0000000000..15a650f0bd --- /dev/null +++ b/microsite/data/plugins/lighthouse.yaml @@ -0,0 +1,14 @@ +--- +title: Lighthouse +author: Spotify +authorUrl: https://www.spotify.com/ +category: Accessibility +description: Google's Lighthouse tool is a great resource for benchmarking and improving the accessibility, performance, SEO, and best practices of your website. +documentation: https://github.com/spotify/backstage/tree/master/plugins/lighthouse +iconUrl: https://seeklogo.com/images/G/google-lighthouse-logo-1C7FA08580-seeklogo.com.png +npmPackageName: '@backstage/plugin-lighthouse' +tags: + - web + - seo + - accessibility + - performance diff --git a/microsite/data/plugins/new-relic.yaml b/microsite/data/plugins/new-relic.yaml new file mode 100644 index 0000000000..e3ddf18652 --- /dev/null +++ b/microsite/data/plugins/new-relic.yaml @@ -0,0 +1,14 @@ +--- +title: New Relic +author: '@timwheelercom' +authorUrl: https://github.com/timwheelercom +category: Monitoring +description: Observability platform built to help engineers create and monitor their software. +documentation: https://github.com/spotify/backstage/tree/master/plugins/newrelic +iconUrl: https://www.mulesoft.com/sites/default/files/2018-10/New_relic.png +npmPackageName: '@backstage/plugin-newrelic' +tags: + - performance + - monitoring + - errors + - alerting diff --git a/microsite/data/plugins/tech-radar.yaml b/microsite/data/plugins/tech-radar.yaml new file mode 100644 index 0000000000..a20667e8f0 --- /dev/null +++ b/microsite/data/plugins/tech-radar.yaml @@ -0,0 +1,9 @@ +--- +title: Tech Radar +author: Spotify +authorUrl: https://www.spotify.com/ +category: Discovery +description: Visualize the your company's official guidelines of different areas of software development. +documentation: https://github.com/spotify/backstage/tree/master/plugins/tech-radar +iconUrl: https://github.com/spotify/backstage/raw/master/plugins/tech-radar/docs/screenshot.png +npmPackageName: '@backstage/plugin-tech-radar' diff --git a/microsite/i18n/en.json b/microsite/i18n/en.json index f61442e938..96ffb780dc 100644 --- a/microsite/i18n/en.json +++ b/microsite/i18n/en.json @@ -296,9 +296,9 @@ "links": { "GitHub": "GitHub", "Docs": "Docs", + "Plugins": "Plugins", "Blog": "Blog", "Demos": "Demos", - "Plugins": "Plugins", "Newsletter": "Newsletter" }, "categories": { From 0d40a302ff0410c84bff96a9d8136db8e6058bdb Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 31 Aug 2020 17:30:47 +0200 Subject: [PATCH 10/56] cli: define BUILD_INFO in builds --- packages/cli/src/lib/bundler/bundle.ts | 2 +- packages/cli/src/lib/bundler/config.ts | 45 ++++++++++++++++++++++++-- packages/cli/src/lib/bundler/server.ts | 2 +- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/lib/bundler/bundle.ts b/packages/cli/src/lib/bundler/bundle.ts index 1193ed505e..8746c807e7 100644 --- a/packages/cli/src/lib/bundler/bundle.ts +++ b/packages/cli/src/lib/bundler/bundle.ts @@ -36,7 +36,7 @@ export async function buildBundle(options: BuildOptions) { const { statsJsonEnabled } = options; const paths = resolveBundlingPaths(options); - const config = createConfig(paths, { + const config = await createConfig(paths, { ...options, checksEnabled: false, isDev: false, diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index d432d6b64e..61f4448dd9 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import fs from 'fs-extra'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; @@ -25,6 +26,9 @@ import { Config } from '@backstage/config'; import { BundlingPaths } from './paths'; import { transforms } from './transforms'; import { BundlingOptions, BackendBundlingOptions } from './types'; +import { version } from '../../lib/version'; +import { paths as cliPaths } from '../../lib/paths'; +import { runPlain } from '../run'; export function resolveBaseUrl(config: Config): URL { const baseUrl = config.getString('app.baseUrl'); @@ -35,10 +39,40 @@ export function resolveBaseUrl(config: Config): URL { } } -export function createConfig( +async function readBuildInfo() { + const timestamp = Date.now(); + + let commit = 'unknown'; + try { + commit = await runPlain('git', 'rev-parse', 'HEAD'); + } catch (error) { + console.warn(`WARNING: Failed to read git commit, ${error}`); + } + + let gitVersion = 'unknown'; + try { + gitVersion = await runPlain('git', 'describe', '--always'); + } catch (error) { + console.warn(`WARNING: Failed to describe git version, ${error}`); + } + + const { version: packageVersion } = await fs.readJson( + cliPaths.resolveTarget('package.json'), + ); + + return { + cliVersion: version, + gitVersion, + packageVersion, + timestamp, + commit, + }; +} + +export async function createConfig( paths: BundlingPaths, options: BundlingOptions, -): webpack.Configuration { +): Promise { const { checksEnabled, isDev } = options; const { plugins, loaders } = transforms(options); @@ -81,6 +115,13 @@ export function createConfig( }), ); + const buildInfo = await readBuildInfo(); + plugins.push( + new webpack.DefinePlugin({ + 'process.env.BUILD_INFO': JSON.stringify(buildInfo), + }), + ); + return { mode: isDev ? 'development' : 'production', profile: false, diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index c7bacc0c7d..4c4a424d08 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -30,7 +30,7 @@ export async function serveBundle(options: ServeOptions) { const paths = resolveBundlingPaths(options); const pkgPath = paths.targetPackageJson; const pkg = await fs.readJson(pkgPath); - const config = createConfig(paths, { + const config = await createConfig(paths, { ...options, isDev: true, baseUrl: url, From 4788ee073ac4ebeef288ffb9d3b16e1fe25d20a3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 31 Aug 2020 20:36:05 +0200 Subject: [PATCH 11/56] cli: use regexps to match paths for rollup plugins --- packages/cli/src/lib/builder/config.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/lib/builder/config.ts b/packages/cli/src/lib/builder/config.ts index e62e1fc6cd..bc689a3eb0 100644 --- a/packages/cli/src/lib/builder/config.ts +++ b/packages/cli/src/lib/builder/config.ts @@ -88,15 +88,25 @@ export const makeConfigs = async ( }), resolve({ mainFields }), commonjs({ - include: ['node_modules/**', '../../node_modules/**'], - exclude: ['**/*.stories.*', '**/*.test.*'], + include: /node_modules/, + exclude: [/\/[^/]+\.(?:stories|test)\.[^/]+$/], }), postcss(), - imageFiles({ exclude: '**/*.icon.svg' }), + imageFiles({ + exclude: /\.icon\.svg$/, + include: [ + /\.css$/, + /\.svg$/, + /\.png$/, + /\.gif$/, + /\.jpg$/, + /\.jpeg$/, + ], + }), json(), yaml(), svgr({ - include: '**/*.icon.svg', + include: /\.icon\.svg$/, template: svgrTemplate, }), esbuild({ From 660de68e7e41b4c855ee084973ceabf96583fc0f Mon Sep 17 00:00:00 2001 From: nikek Date: Mon, 31 Aug 2020 23:01:40 +0200 Subject: [PATCH 12/56] Add AboutCard component to EntityPageOverview --- packages/core/src/layout/Header/Header.tsx | 2 +- .../components/AboutCard/AboutCard.test.tsx | 46 +++++ .../src/components/AboutCard/AboutCard.tsx | 182 ++++++++++++++++++ .../IconLinkVertical/IconLinkVertical.tsx | 53 +++++ .../IconLinkVertical/index.ts} | 14 +- .../index.ts} | 17 +- .../EntityPageOverview/EntityPageOverview.tsx | 4 +- 7 files changed, 286 insertions(+), 32 deletions(-) create mode 100644 plugins/catalog/src/components/AboutCard/AboutCard.test.tsx create mode 100644 plugins/catalog/src/components/AboutCard/AboutCard.tsx create mode 100644 plugins/catalog/src/components/AboutCard/IconLinkVertical/IconLinkVertical.tsx rename plugins/catalog/src/components/{EntityMetadataCard/EntityMetadataCard.tsx => AboutCard/IconLinkVertical/index.ts} (61%) rename plugins/catalog/src/components/{EntityMetadataCard/EntityMetadataCard.test.tsx => AboutCard/index.ts} (50%) diff --git a/packages/core/src/layout/Header/Header.tsx b/packages/core/src/layout/Header/Header.tsx index 7aafc2730e..6b9ea05245 100644 --- a/packages/core/src/layout/Header/Header.tsx +++ b/packages/core/src/layout/Header/Header.tsx @@ -38,7 +38,7 @@ const useStyles = makeStyles( alignItems: 'center', backgroundImage: props => props.backgroundImage, backgroundPosition: 'center', - backgroundSize: '100% 400px', + backgroundSize: 'cover', }, leftItemsBox: { flex: '1 1 auto', diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx new file mode 100644 index 0000000000..bf69818995 --- /dev/null +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { AboutCard } from './AboutCard'; + +describe('', () => { + it('renders info and "view source" link', () => { + const entity = { + apiVersion: 'v1', + kind: 'Component', + metadata: { + name: 'software', + annotations: { + 'backstage.io/managed-by-location': + 'github:https://github.com/spotify/backstage/blob/master/software.yaml', + }, + }, + spec: { + owner: 'guest', + type: 'service', + lifecycle: 'production', + }, + }; + const { getByText } = render(); + expect(getByText('service')).toBeInTheDocument(); + expect(getByText('View Source').closest('a')).toHaveAttribute( + 'href', + 'https://github.com/spotify/backstage/blob/master/software.yaml', + ); + }); +}); diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx new file mode 100644 index 0000000000..d27175fcf3 --- /dev/null +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -0,0 +1,182 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + Grid, + Typography, + makeStyles, + Chip, + IconButton, + Card, + CardContent, + CardHeader, + Divider, +} from '@material-ui/core'; +import { Entity } from '@backstage/catalog-model'; + +import GitHubIcon from '@material-ui/icons/GitHub'; +import { IconLinkVertical } from './IconLinkVertical'; +import EditIcon from '@material-ui/icons/Edit'; +import DocsIcon from '@material-ui/icons/Description'; + +const useStyles = makeStyles(theme => ({ + links: { + margin: theme.spacing(2, 0, 2), + display: 'grid', + gridAutoFlow: 'column', + gridAutoColumns: 'min-content', + gridGap: theme.spacing(2), + }, + label: { + color: '#9e9e9e', + textTransform: 'uppercase', + fontSize: '12px', + fontWeight: 'bold', + overflow: 'hidden', + whiteSpace: 'nowrap', + }, + value: { + fontWeight: 'bold', + overflow: 'hidden', + lineHeight: '24px', + wordBreak: 'break-word', + }, + description: { + wordBreak: 'break-word', + }, +})); + +const iconMap: Record = { + github: , +}; + +type CodeLinkInfo = { icon?: React.ReactNode; href?: string }; + +function getCodeLinkInfo(entity: Entity): CodeLinkInfo { + const location = + entity?.metadata?.annotations?.['backstage.io/managed-by-location']; + + if (location) { + // split by first `:` + // e.g. "github:https://github.com/spotify/backstage/blob/master/software.yaml" + const [type, target] = location.split(/:(.+)/); + + return { icon: iconMap[type], href: target }; + } + return {}; +} + +type AboutCardProps = { + entity: Entity; +}; + +export function AboutCard({ entity }: AboutCardProps) { + const classes = useStyles(); + const codeLink = getCodeLinkInfo(entity); + + return ( + + + + + } + subheader={ + + } + /> + + + + + + {entity?.metadata?.description || 'No description'} + + + + + + + {(entity?.metadata?.tags || []).map(t => ( + + ))} + + + + + ); +} + +function AboutField({ + label, + value, + gridSizes, + children, +}: { + label: string; + value?: string; + gridSizes?: Record; + children?: React.ReactNode; +}) { + const classes = useStyles(); + + // Content is either children or a string prop `value` + const content = React.Children.count(children) ? ( + children + ) : ( + + {value || `unknown`} + + ); + return ( + + + {label} + + {content} + + ); +} diff --git a/plugins/catalog/src/components/AboutCard/IconLinkVertical/IconLinkVertical.tsx b/plugins/catalog/src/components/AboutCard/IconLinkVertical/IconLinkVertical.tsx new file mode 100644 index 0000000000..91a5211925 --- /dev/null +++ b/plugins/catalog/src/components/AboutCard/IconLinkVertical/IconLinkVertical.tsx @@ -0,0 +1,53 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from 'react'; +import { makeStyles, Link } from '@material-ui/core'; +import LinkIcon from '@material-ui/icons/Link'; + +export type IconLinkVerticalProps = { + icon?: React.ReactNode; + href?: string; + label: string; +}; + +const useIconStyles = makeStyles({ + link: { + display: 'grid', + justifyItems: 'center', + gridGap: 4, + textAlign: 'center', + }, + label: { + fontSize: '0.7rem', + textTransform: 'uppercase', + fontWeight: 600, + letterSpacing: 1.2, + }, +}); + +export function IconLinkVertical({ + icon = , + href = '#', + ...props +}: IconLinkVerticalProps) { + const classes = useIconStyles(); + return ( + + {icon} + {props.label} + + ); +} diff --git a/plugins/catalog/src/components/EntityMetadataCard/EntityMetadataCard.tsx b/plugins/catalog/src/components/AboutCard/IconLinkVertical/index.ts similarity index 61% rename from plugins/catalog/src/components/EntityMetadataCard/EntityMetadataCard.tsx rename to plugins/catalog/src/components/AboutCard/IconLinkVertical/index.ts index 57082a9c91..ddc146dbd8 100644 --- a/plugins/catalog/src/components/EntityMetadataCard/EntityMetadataCard.tsx +++ b/plugins/catalog/src/components/AboutCard/IconLinkVertical/index.ts @@ -14,16 +14,4 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; -import { InfoCard, StructuredMetadataTable } from '@backstage/core'; -import React, { FC } from 'react'; - -type Props = { - entity: Entity; -}; - -export const EntityMetadataCard: FC = ({ entity }) => ( - - - -); +export { IconLinkVertical } from './IconLinkVertical'; diff --git a/plugins/catalog/src/components/EntityMetadataCard/EntityMetadataCard.test.tsx b/plugins/catalog/src/components/AboutCard/index.ts similarity index 50% rename from plugins/catalog/src/components/EntityMetadataCard/EntityMetadataCard.test.tsx rename to plugins/catalog/src/components/AboutCard/index.ts index 4bb64f221d..93765ff942 100644 --- a/plugins/catalog/src/components/EntityMetadataCard/EntityMetadataCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/index.ts @@ -14,19 +14,4 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; -import { render } from '@testing-library/react'; -import React from 'react'; -import { EntityMetadataCard } from './EntityMetadataCard'; - -describe('EntityMetadataCard component', () => { - it('should display entity name if provided', async () => { - const testEntity: Entity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Component', - metadata: { name: 'test' }, - }; - const rendered = await render(); - expect(await rendered.findByText('test')).toBeInTheDocument(); - }); -}); +export { AboutCard } from './AboutCard'; diff --git a/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx b/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx index 45a62198c7..4067fef29a 100644 --- a/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx +++ b/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx @@ -24,14 +24,14 @@ import { } from '@backstage/plugin-jenkins'; import { Grid } from '@material-ui/core'; import React, { FC } from 'react'; -import { EntityMetadataCard } from '../EntityMetadataCard/EntityMetadataCard'; +import { AboutCard } from '../AboutCard'; export const EntityPageOverview: FC<{ entity: Entity }> = ({ entity }) => { return ( - + {entity.metadata?.annotations?.[ 'backstage.io/jenkins-github-folder' From 0ff78005cd23e9d54e313b95548c0b7138b0dd5c Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Mon, 31 Aug 2020 23:07:16 +0200 Subject: [PATCH 13/56] fix(docs): code block background --- microsite/static/css/custom.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/static/css/custom.css b/microsite/static/css/custom.css index 3c0184a07b..5e078582cc 100644 --- a/microsite/static/css/custom.css +++ b/microsite/static/css/custom.css @@ -216,7 +216,7 @@ td { code { font-family: IBM Plex Mono, Menlo, Monaco, Consolas, Courier New, monospace; font-weight: 500; - background-color: #0e0e0e; + background-color: #272822; } /* .stripe { From 8a67a8df844d234fc1bcb007c2fa1b21b0674257 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Tue, 1 Sep 2020 00:21:25 +0200 Subject: [PATCH 14/56] fix(docs): add i18n to gitignore to avoid lerna errors in master --- .gitignore | 1 + microsite/i18n/en.json | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 743561c3b6..aee80f4c10 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ dist # Microsite build output microsite/build +microsite/i18n # Gatsby files .cache/ diff --git a/microsite/i18n/en.json b/microsite/i18n/en.json index 96ffb780dc..e9f63d5737 100644 --- a/microsite/i18n/en.json +++ b/microsite/i18n/en.json @@ -92,6 +92,9 @@ "features/software-catalog/software-catalog-api": { "title": "API" }, + "features/software-catalog/software-catalog-configuration": { + "title": "Catalog Configuration" + }, "features/software-catalog/descriptor-format": { "title": "Descriptor Format of Catalog Entities", "sidebar_label": "YAML File Format" From 329b663c93e28003b999271b4b35a044eddc2a01 Mon Sep 17 00:00:00 2001 From: Andrew Thauer <6507159+andrewthauer@users.noreply.github.com> Date: Sat, 29 Aug 2020 16:59:14 -0400 Subject: [PATCH 15/56] refactor: cleanup & renames to common db code --- .../src/database/connection.test.ts | 16 +- .../backend-common/src/database/connection.ts | 26 ++- .../src/database/postgres.test.ts | 176 ++++++++++-------- .../backend-common/src/database/postgres.ts | 45 +++-- .../src/database/sqlite3.test.ts | 17 +- .../backend-common/src/database/sqlite3.ts | 12 +- packages/backend/src/index.ts | 13 +- .../default-app/packages/backend/src/index.ts | 13 +- 8 files changed, 184 insertions(+), 134 deletions(-) diff --git a/packages/backend-common/src/database/connection.test.ts b/packages/backend-common/src/database/connection.test.ts index 814503fda1..2cc3a54e06 100644 --- a/packages/backend-common/src/database/connection.test.ts +++ b/packages/backend-common/src/database/connection.test.ts @@ -15,7 +15,7 @@ */ import { ConfigReader } from '@backstage/config'; -import { createDatabase } from './connection'; +import { createDatabaseClient } from './connection'; describe('database connection', () => { const createConfig = (data: any) => @@ -26,10 +26,10 @@ describe('database connection', () => { }, ]); - describe(createDatabase, () => { + describe(createDatabaseClient, () => { it('returns a postgres connection', () => { expect( - createDatabase( + createDatabaseClient( createConfig({ client: 'pg', connection: { @@ -45,7 +45,7 @@ describe('database connection', () => { it('returns an sqlite connection', () => { expect( - createDatabase( + createDatabaseClient( createConfig({ client: 'sqlite3', connection: ':memory:', @@ -56,7 +56,7 @@ describe('database connection', () => { it('tries to create a mysql connection as a passthrough', () => { expect(() => - createDatabase( + createDatabaseClient( createConfig({ client: 'mysql', connection: { @@ -72,7 +72,7 @@ describe('database connection', () => { it('accepts overrides', () => { expect( - createDatabase( + createDatabaseClient( createConfig({ client: 'pg', connection: { @@ -93,7 +93,7 @@ describe('database connection', () => { it('throws an error without a client', () => { expect(() => - createDatabase( + createDatabaseClient( createConfig({ connection: '', }), @@ -103,7 +103,7 @@ describe('database connection', () => { it('throws an error without a connection', () => { expect(() => - createDatabase( + createDatabaseClient( createConfig({ client: 'pg', }), diff --git a/packages/backend-common/src/database/connection.ts b/packages/backend-common/src/database/connection.ts index d968275482..009a85239f 100644 --- a/packages/backend-common/src/database/connection.ts +++ b/packages/backend-common/src/database/connection.ts @@ -15,30 +15,36 @@ */ import knex from 'knex'; -import { ConfigReader } from '@backstage/config'; +import { Config } from '@backstage/config'; import { mergeDatabaseConfig } from './config'; -import { createPgDatabase } from './postgres'; -import { createSqlite3Database } from './sqlite3'; +import { createPgDatabaseClient } from './postgres'; +import { createSqliteDatabaseClient } from './sqlite3'; type DatabaseClient = 'pg' | 'sqlite3' | string; /** * Creates a knex database connection * - * @param config The database config + * @param dbConfig The database config * @param overrides Additional options to merge with the config */ -export function createDatabase( - config: ConfigReader, +export function createDatabaseClient( + dbConfig: Config, overrides?: Partial, ) { - const client: DatabaseClient = config.getString('client'); + const client: DatabaseClient = dbConfig.getString('client'); if (client === 'pg') { - return createPgDatabase(config, overrides); + return createPgDatabaseClient(dbConfig, overrides); } else if (client === 'sqlite3') { - return createSqlite3Database(config); + return createSqliteDatabaseClient(dbConfig); } - return knex(mergeDatabaseConfig(config.get(), overrides)); + return knex(mergeDatabaseConfig(dbConfig.get(), overrides)); } + +/** + * Alias for createDatabaseClient + * @deprecated Use createDatabaseClient instead + */ +export const createDatabase = createDatabaseClient; diff --git a/packages/backend-common/src/database/postgres.test.ts b/packages/backend-common/src/database/postgres.test.ts index 8edfc2c15d..82161dc53c 100644 --- a/packages/backend-common/src/database/postgres.test.ts +++ b/packages/backend-common/src/database/postgres.test.ts @@ -14,15 +14,26 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/config'; +import { Config, ConfigReader } from '@backstage/config'; import { - parsePgConnectionString, + createPgDatabaseClient, buildPgDatabaseConfig, - createPgDatabase, + getPgConnectionConfig, + parsePgConnectionString, } from './postgres'; describe('postgres', () => { - const createConfig = (connection: any) => + const createMockConnection = () => ({ + host: 'acme', + user: 'foo', + password: 'bar', + database: 'foodb', + }); + + const createMockConnectionString = () => + 'postgresql://foo:bar@acme:5432/foodb'; + + const createConfig = (connection: any): Config => ConfigReader.fromConfigs([ { context: '', @@ -35,86 +46,58 @@ describe('postgres', () => { describe(buildPgDatabaseConfig, () => { it('builds a postgres config', () => { - expect( - buildPgDatabaseConfig( - createConfig({ - host: 'acme', - user: 'foo', - password: 'bar', - port: '5432', - database: 'foodb', - }), - ), - ).toEqual({ + const mockConnection = createMockConnection(); + + expect(buildPgDatabaseConfig(createConfig(mockConnection))).toEqual({ client: 'pg', - connection: { - host: 'acme', - user: 'foo', - password: 'bar', - port: '5432', - database: 'foodb', - }, + connection: mockConnection, useNullAsDefault: true, }); }); it('builds a connection string config', () => { - expect( - buildPgDatabaseConfig( - createConfig('postgresql://foo:bar@acme:5432/foodb'), - ), - ).toEqual({ - client: 'pg', - connection: 'postgresql://foo:bar@acme:5432/foodb', - useNullAsDefault: true, - }); + const mockConnectionString = createMockConnectionString(); + + expect(buildPgDatabaseConfig(createConfig(mockConnectionString))).toEqual( + { + client: 'pg', + connection: mockConnectionString, + useNullAsDefault: true, + }, + ); }); it('overrides the database name', () => { + const mockConnection = createMockConnection(); + expect( - buildPgDatabaseConfig( - createConfig({ - host: 'somehost', - user: 'postgres', - password: 'pass', - database: 'foo', - }), - { connection: { database: 'foodb' } }, - ), + buildPgDatabaseConfig(createConfig(mockConnection), { + connection: { database: 'other_db' }, + }), ).toEqual({ client: 'pg', connection: { - host: 'somehost', - user: 'postgres', - password: 'pass', - database: 'foodb', + ...mockConnection, + database: 'other_db', }, useNullAsDefault: true, }); }); it('adds additional config settings', () => { + const mockConnection = createMockConnection(); + expect( - buildPgDatabaseConfig( - createConfig({ - host: 'somehost', - user: 'postgres', - password: 'pass', - database: 'foo', - }), - { - connection: { database: 'foodb' }, - pool: { min: 0, max: 7 }, - debug: true, - }, - ), + buildPgDatabaseConfig(createConfig(mockConnection), { + connection: { database: 'other_db' }, + pool: { min: 0, max: 7 }, + debug: true, + }), ).toEqual({ client: 'pg', connection: { - host: 'somehost', - user: 'postgres', - password: 'pass', - database: 'foodb', + ...mockConnection, + database: 'other_db', }, useNullAsDefault: true, pool: { min: 0, max: 7 }, @@ -123,37 +106,72 @@ describe('postgres', () => { }); it('overrides the database from connection string', () => { + const mockConnectionString = createMockConnectionString(); + const mockConnection = createMockConnection(); + expect( - buildPgDatabaseConfig( - createConfig('postgresql://postgres:pass@localhost:5432/dbname'), - { connection: { database: 'foodb' } }, - ), + buildPgDatabaseConfig(createConfig(mockConnectionString), { + connection: { database: 'other_db' }, + }), ).toEqual({ client: 'pg', connection: { - host: 'localhost', - user: 'postgres', - password: 'pass', + ...mockConnection, port: '5432', - database: 'foodb', + database: 'other_db', }, useNullAsDefault: true, }); }); }); - describe(createPgDatabase, () => { + describe(getPgConnectionConfig, () => { + it('returns the connection object back', () => { + const mockConnection = createMockConnection(); + const config = createConfig(mockConnection); + + expect(getPgConnectionConfig(config)).toEqual(mockConnection); + }); + + it('does not parse the connection string', () => { + const mockConnection = createMockConnection(); + const config = createConfig(mockConnection); + + expect(getPgConnectionConfig(config, true)).toEqual(mockConnection); + }); + + it('automatically parses the connection string', () => { + const mockConnection = createMockConnection(); + const mockConnectionString = createMockConnectionString(); + const config = createConfig(mockConnectionString); + + expect(getPgConnectionConfig(config)).toEqual({ + ...mockConnection, + port: '5432', + }); + }); + + it('parses the connection string', () => { + const mockConnection = createMockConnection(); + const mockConnectionString = createMockConnectionString(); + const config = createConfig(mockConnectionString); + + expect(getPgConnectionConfig(config, true)).toEqual({ + ...mockConnection, + port: '5432', + }); + }); + }); + + describe(createPgDatabaseClient, () => { it('creates a postgres knex instance', () => { expect( - createPgDatabase( + createPgDatabaseClient( createConfig({ - client: 'pg', - connection: { - host: 'acme', - user: 'foo', - password: 'bar', - database: 'foodb', - }, + host: 'acme', + user: 'foo', + password: 'bar', + database: 'foodb', }), ), ).toBeTruthy(); @@ -161,7 +179,7 @@ describe('postgres', () => { it('attempts to read an ssl cert', () => { expect(() => - createPgDatabase( + createPgDatabaseClient( createConfig( 'postgresql://postgres:pass@localhost:5432/dbname?sslrootcert=/path/to/file', ), diff --git a/packages/backend-common/src/database/postgres.ts b/packages/backend-common/src/database/postgres.ts index 09b6d0653b..03a74156c7 100644 --- a/packages/backend-common/src/database/postgres.ts +++ b/packages/backend-common/src/database/postgres.ts @@ -14,18 +14,18 @@ * limitations under the License. */ -import knex from 'knex'; -import { ConfigReader } from '@backstage/config'; +import knex, { PgConnectionConfig } from 'knex'; +import { Config } from '@backstage/config'; import { mergeDatabaseConfig } from './config'; /** - * Creates a knex sqlite3 database connection + * Creates a knex postgres database connection * * @param dbConfig The database config * @param overrides Additional options to merge with the config */ -export function createPgDatabase( - dbConfig: ConfigReader, +export function createPgDatabaseClient( + dbConfig: Config, overrides?: knex.Config, ) { const knexConfig = buildPgDatabaseConfig(dbConfig, overrides); @@ -40,26 +40,43 @@ export function createPgDatabase( * @param overrides Additional options to merge with the config */ export function buildPgDatabaseConfig( - dbConfig: ConfigReader, + dbConfig: Config, overrides?: knex.Config, ) { - const connection = dbConfig.get('connection') as any; - return mergeDatabaseConfig( dbConfig.get(), { - // Only parse the connection string when overrides are provided - connection: - overrides && - (typeof connection === 'string' || connection instanceof String) - ? parsePgConnectionString(connection as string) - : connection, + connection: getPgConnectionConfig(dbConfig, !!overrides), useNullAsDefault: true, }, overrides, ); } +/** + * Gets the postgres connection config + * + * @param dbConfig The database config + * @param parseConnectionString Flag to explictly control connection string parsing + */ +export function getPgConnectionConfig( + dbConfig: Config, + parseConnectionString?: boolean, +): PgConnectionConfig | string { + const connection = dbConfig.get('connection') as any; + const isConnectionString = + typeof connection === 'string' || connection instanceof String; + const autoParse = typeof parseConnectionString !== 'boolean'; + + const shouldParseConnectionString = autoParse + ? isConnectionString + : parseConnectionString && isConnectionString; + + return shouldParseConnectionString + ? parsePgConnectionString(connection as string) + : connection; +} + /** * Parses a connection string using pg-connection-string * diff --git a/packages/backend-common/src/database/sqlite3.test.ts b/packages/backend-common/src/database/sqlite3.test.ts index a25720b81c..dbff5ee354 100644 --- a/packages/backend-common/src/database/sqlite3.test.ts +++ b/packages/backend-common/src/database/sqlite3.test.ts @@ -15,7 +15,10 @@ */ import { ConfigReader } from '@backstage/config'; -import { buildSqlite3DatabaseConfig, createSqlite3Database } from './sqlite3'; +import { + buildSqliteDatabaseConfig, + createSqliteDatabaseClient, +} from './sqlite3'; describe('sqlite3', () => { const createConfig = (connection: any) => @@ -29,9 +32,9 @@ describe('sqlite3', () => { }, ]); - describe(buildSqlite3DatabaseConfig, () => { + describe(buildSqliteDatabaseConfig, () => { it('buidls a string connection', () => { - expect(buildSqlite3DatabaseConfig(createConfig(':memory:'))).toEqual({ + expect(buildSqliteDatabaseConfig(createConfig(':memory:'))).toEqual({ client: 'sqlite3', connection: ':memory:', useNullAsDefault: true, @@ -40,7 +43,7 @@ describe('sqlite3', () => { it('builds a filename connection', () => { expect( - buildSqlite3DatabaseConfig( + buildSqliteDatabaseConfig( createConfig({ filename: '/path/to/foo', }), @@ -56,7 +59,7 @@ describe('sqlite3', () => { it('replaces the connection with an override', () => { expect( - buildSqlite3DatabaseConfig(createConfig(':memory:'), { + buildSqliteDatabaseConfig(createConfig(':memory:'), { connection: { filename: '/path/to/foo' }, }), ).toEqual({ @@ -69,10 +72,10 @@ describe('sqlite3', () => { }); }); - describe(createSqlite3Database, () => { + describe(createSqliteDatabaseClient, () => { it('creates an in memory knex instance', () => { expect( - createSqlite3Database( + createSqliteDatabaseClient( createConfig({ client: 'sqlite3', connection: ':memory:', diff --git a/packages/backend-common/src/database/sqlite3.ts b/packages/backend-common/src/database/sqlite3.ts index 6249394d05..7bdc4380a1 100644 --- a/packages/backend-common/src/database/sqlite3.ts +++ b/packages/backend-common/src/database/sqlite3.ts @@ -15,7 +15,7 @@ */ import knex from 'knex'; -import { ConfigReader } from '@backstage/config'; +import { Config } from '@backstage/config'; import { mergeDatabaseConfig } from './config'; /** @@ -24,11 +24,11 @@ import { mergeDatabaseConfig } from './config'; * @param dbConfig The database config * @param overrides Additional options to merge with the config */ -export function createSqlite3Database( - dbConfig: ConfigReader, +export function createSqliteDatabaseClient( + dbConfig: Config, overrides?: knex.Config, ) { - const knexConfig = buildSqlite3DatabaseConfig(dbConfig, overrides); + const knexConfig = buildSqliteDatabaseConfig(dbConfig, overrides); const database = knex(knexConfig); database.client.pool.on('createSuccess', (_eventId: any, resource: any) => { @@ -44,8 +44,8 @@ export function createSqlite3Database( * @param dbConfig The database config * @param overrides Additional options to merge with the config */ -export function buildSqlite3DatabaseConfig( - dbConfig: ConfigReader, +export function buildSqliteDatabaseConfig( + dbConfig: Config, overrides?: knex.Config, ) { return mergeDatabaseConfig( diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 6df593182d..0423047cf7 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -23,7 +23,7 @@ */ import { - createDatabase, + createDatabaseClient, createServiceBuilder, loadBackendConfig, getRootLogger, @@ -48,11 +48,14 @@ function makeCreateEnv(loadedConfigs: AppConfig[]) { return (plugin: string): PluginEnvironment => { const logger = getRootLogger().child({ type: 'plugin', plugin }); - const database = createDatabase(config.getConfig('backend.database'), { - connection: { - database: `backstage_plugin_${plugin}`, + const database = createDatabaseClient( + config.getConfig('backend.database'), + { + connection: { + database: `backstage_plugin_${plugin}`, + }, }, - }); + ); return { logger, database, config }; }; } diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index d6fba2478a..6a014727e9 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -7,7 +7,7 @@ */ import { - createDatabase, + createDatabaseClient, createServiceBuilder, loadBackendConfig, getRootLogger, @@ -27,11 +27,14 @@ function makeCreateEnv(loadedConfigs: AppConfig[]) { return (plugin: string): PluginEnvironment => { const logger = getRootLogger().child({ type: 'plugin', plugin }); - const database = createDatabase(config.getConfig('backend.database'), { - connection: { - database: `backstage_plugin_${plugin}`, + const database = createDatabaseClient( + config.getConfig('backend.database'), + { + connection: { + database: `backstage_plugin_${plugin}`, + }, }, - }); + ); return { logger, database, config }; }; } From 6b1e63c2fc0a0f5b37a52b8edea8a41f4818e08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20DOREAU?= Date: Sun, 23 Aug 2020 00:32:20 +0200 Subject: [PATCH 16/56] feat(create-app): add missing plugins --- .../default-app/packages/app/package.json.hbs | 6 +++ .../default-app/packages/app/src/apis.ts | 38 ++++++++++++++++++- .../default-app/packages/app/src/plugins.ts | 6 +++ .../default-app/packages/app/src/sidebar.tsx | 9 +++++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index 7d34a94c7b..704b04ceca 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -11,6 +11,12 @@ "@backstage/plugin-register-component": "^{{version}}", "@backstage/plugin-scaffolder": "^{{version}}", "@backstage/plugin-techdocs": "^{{version}}", + "@backstage/plugin-circleci": "^{{version}}", + "@backstage/plugin-explore": "^{{version}}", + "@backstage/plugin-lighthouse": "^{{version}}", + "@backstage/plugin-tech-radar": "^{{version}}", + "@backstage/plugin-github-actions": "^{{version}}", + "@backstage/plugin-sentry": "^{{version}}", "@backstage/test-utils": "^{{version}}", "@backstage/theme": "^{{version}}", "history": "^5.0.0", diff --git a/packages/create-app/templates/default-app/packages/app/src/apis.ts b/packages/create-app/templates/default-app/packages/app/src/apis.ts index 7fc59cc9d7..02b5898884 100644 --- a/packages/create-app/templates/default-app/packages/app/src/apis.ts +++ b/packages/create-app/templates/default-app/packages/app/src/apis.ts @@ -14,15 +14,33 @@ import { WebStorage, } from '@backstage/core'; -import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog'; +import { + lighthouseApiRef, + LighthouseRestApi, +} from '@backstage/plugin-lighthouse'; -import { scaffolderApiRef, ScaffolderApi } from '@backstage/plugin-scaffolder'; +import { + GithubActionsClient, + githubActionsApiRef, +} from '@backstage/plugin-github-actions'; import { techdocsStorageApiRef, TechDocsStorageApi, + + techdocsStorageApiRef, + TechDocsStorageApi, } from '@backstage/plugin-techdocs'; +import { techRadarApiRef, TechRadar } from '@backstage/plugin-tech-radar'; + +import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog'; +import { CircleCIApi, circleCIApiRef } from '@backstage/plugin-circleci'; + +import { scaffolderApiRef, ScaffolderApi } from '@backstage/plugin-scaffolder'; + + + export const apis = (config: ConfigApi) => { // eslint-disable-next-line no-console console.log(`Creating APIs for ${config.getString('app.title')}`); @@ -46,9 +64,25 @@ export const apis = (config: ConfigApi) => { builder.add(oauthRequestApiRef, new OAuthRequestManager()); builder.add(catalogApiRef, new CatalogClient({ discoveryApi })); + builder.add(githubActionsApiRef, new GithubActionsClient()); + + builder.add(lighthouseApiRef, new LighthouseRestApi('http://localhost:3003')); + + builder.add( + circleCIApiRef, + new CircleCIApi(`${backendUrl}/proxy/circleci/api`), + ); builder.add(scaffolderApiRef, new ScaffolderApi({ discoveryApi })); + builder.add( + techRadarApiRef, + new TechRadar({ + width: 1500, + height: 800, + }), + ); + builder.add( techdocsStorageApiRef, new TechDocsStorageApi({ apiOrigin: techdocsStorageUrl }), diff --git a/packages/create-app/templates/default-app/packages/app/src/plugins.ts b/packages/create-app/templates/default-app/packages/app/src/plugins.ts index f6bef70188..0d54c55649 100644 --- a/packages/create-app/templates/default-app/packages/app/src/plugins.ts +++ b/packages/create-app/templates/default-app/packages/app/src/plugins.ts @@ -2,3 +2,9 @@ export { plugin as CatalogPlugin } from '@backstage/plugin-catalog'; export { plugin as RegisterComponent } from '@backstage/plugin-register-component'; export { plugin as ScaffolderPlugin } from '@backstage/plugin-scaffolder'; export { plugin as TechDocsPlugin } from '@backstage/plugin-techdocs'; +export { plugin as Explore } from '@backstage/plugin-explore'; +export { plugin as Circleci } from '@backstage/plugin-circleci'; +export { plugin as LighthousePlugin } from '@backstage/plugin-lighthouse'; +export { plugin as TechRadar } from '@backstage/plugin-tech-radar'; +export { plugin as GithubActions } from '@backstage/plugin-github-actions'; +export { plugin as Sentry } from '@backstage/plugin-sentry'; diff --git a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx index 6520dfbe6e..28a43b2fb7 100644 --- a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx @@ -2,6 +2,10 @@ import React from 'react'; import HomeIcon from '@material-ui/icons/Home'; import LibraryBooks from '@material-ui/icons/LibraryBooks'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; +import ExploreIcon from '@material-ui/icons/Explore'; +import BuildIcon from '@material-ui/icons/BuildRounded'; +import RuleIcon from '@material-ui/icons/AssignmentTurnedIn'; +import MapIcon from '@material-ui/icons/MyLocation'; import { Sidebar, SidebarItem, @@ -20,6 +24,11 @@ export const AppSidebar = () => ( + + + + + {/* End global nav */} From 1637987b2a88e1b1e3c47cf83d097ed1a82f7d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20DOREAU?= Date: Sun, 23 Aug 2020 13:28:27 +0200 Subject: [PATCH 17/56] feat(create-app): add tech-docs plugin --- .../templates/default-app/packages/app/package.json.hbs | 1 + .../templates/default-app/packages/app/src/sidebar.tsx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index 704b04ceca..8ea7d44f76 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -16,6 +16,7 @@ "@backstage/plugin-lighthouse": "^{{version}}", "@backstage/plugin-tech-radar": "^{{version}}", "@backstage/plugin-github-actions": "^{{version}}", + "@backstage/plugin-techdocs": "^{{version}}", "@backstage/plugin-sentry": "^{{version}}", "@backstage/test-utils": "^{{version}}", "@backstage/theme": "^{{version}}", diff --git a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx index 28a43b2fb7..fa9a397751 100644 --- a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx @@ -6,6 +6,7 @@ import ExploreIcon from '@material-ui/icons/Explore'; import BuildIcon from '@material-ui/icons/BuildRounded'; import RuleIcon from '@material-ui/icons/AssignmentTurnedIn'; import MapIcon from '@material-ui/icons/MyLocation'; + import { Sidebar, SidebarItem, @@ -22,9 +23,9 @@ export const AppSidebar = () => ( {/* Global nav, not org-specific */} + - From bb92d909ea70fde11f1cc72c91e1510fa91ac296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20DOREAU?= Date: Tue, 1 Sep 2020 08:19:10 +0200 Subject: [PATCH 18/56] feat(create-app): sentry backend + lighthouse config --- .../templates/default-app/app-config.yaml.hbs | 6 +++++ .../default-app/packages/backend/src/index.ts | 3 +++ .../packages/backend/src/plugins/sentry.ts | 22 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 packages/create-app/templates/default-app/packages/backend/src/plugins/sentry.ts diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index aff375ad29..33f7f5dc60 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -44,6 +44,12 @@ proxy: techdocs: storageUrl: http://localhost:7000/techdocs/static/docs +sentry: + organization: spotify + +lighthouse: + baseUrl: http://localhost:3003 + auth: providers: {} diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 6a014727e9..6ba6c4dc8e 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -20,6 +20,7 @@ import identity from './plugins/identity'; import scaffolder from './plugins/scaffolder'; import proxy from './plugins/proxy'; import techdocs from './plugins/techdocs'; +import sentry from './plugins/sentry'; import { PluginEnvironment } from './types'; function makeCreateEnv(loadedConfigs: AppConfig[]) { @@ -50,11 +51,13 @@ async function main() { const identityEnv = useHotMemoize(module, () => createEnv('identity')); const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); + const sentryEnv = useHotMemoize(module, () => createEnv('sentry')); const service = createServiceBuilder(module) .loadConfig(configReader) .addRouter('/catalog', await catalog(catalogEnv)) .addRouter('/scaffolder', await scaffolder(scaffolderEnv)) + .addRouter('/sentry', await sentry(sentryEnv)) .addRouter('/auth', await auth(authEnv)) .addRouter('/identity', await identity(identityEnv)) .addRouter('/techdocs', await techdocs(techdocsEnv)) diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/sentry.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/sentry.ts new file mode 100644 index 0000000000..5cd0e55761 --- /dev/null +++ b/packages/create-app/templates/default-app/packages/backend/src/plugins/sentry.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createRouter } from '@backstage/plugin-sentry-backend'; +import type { PluginEnvironment } from '../types'; + +export default async function createPlugin({ logger }: PluginEnvironment) { + return await createRouter(logger); +} From 055b8baa6de8c5c5208f6d016510934b823c068f Mon Sep 17 00:00:00 2001 From: Iain Billett Date: Tue, 1 Sep 2020 07:55:31 +0100 Subject: [PATCH 19/56] Add Pull Request Plugin to the marketplace (#2190) * Add Pull Request Plugin to the marketplace * Add Pull Request Plugin to the marketplace * typo --- microsite/data/plugins/github-pull-requests.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 microsite/data/plugins/github-pull-requests.yaml diff --git a/microsite/data/plugins/github-pull-requests.yaml b/microsite/data/plugins/github-pull-requests.yaml new file mode 100644 index 0000000000..917198a221 --- /dev/null +++ b/microsite/data/plugins/github-pull-requests.yaml @@ -0,0 +1,10 @@ +--- +title: GitHub Pull Requests +author: roadie.io +authorUrl: https://roadie.io/ +category: CI +description: View GitHub pull requests for your service in Backstage. +documentation: https://roadie.io/backstage/plugins/github-pull-requests +iconUrl: https://roadie.io/static/7f13bb8d861d8dedc5112fb939d215f9/351f2/GitHub-Mark-Light-120px-plus.png +npmPackageName: '@roadiehq/backstage-plugin-github-pull-requests' + From 94da78133f16b1a5a346be445426633e07492870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 1 Sep 2020 09:03:44 +0200 Subject: [PATCH 20/56] fix(deps): yarn.lock update again --- yarn.lock | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index d90056f47d..aa85370465 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2724,7 +2724,7 @@ dependencies: "@types/node" ">= 8" -"@open-draft/until@^1.0.3": +"@open-draft/until@^1.0.0", "@open-draft/until@^1.0.3": version "1.0.3" resolved "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca" integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q== @@ -4106,6 +4106,11 @@ dependencies: "@types/express" "*" +"@types/cookie@^0.3.3": + version "0.3.3" + resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" + integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== + "@types/cookie@^0.4.0": version "0.4.0" resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz#14f854c0f93d326e39da6e3b6f34f7d37513d108" @@ -11650,7 +11655,7 @@ graphql-upload@^8.0.2: http-errors "^1.7.3" object-path "^0.11.4" -graphql@15.3.0, graphql@^15.3.0: +graphql@15.3.0, graphql@^15.0.0, graphql@^15.3.0: version "15.3.0" resolved "https://registry.npmjs.org/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278" integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w== @@ -11858,7 +11863,7 @@ he@^1.2.0: resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -headers-utils@^1.2.0: +headers-utils@^1.1.9, headers-utils@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/headers-utils/-/headers-utils-1.2.0.tgz#5e10d1bc9d2bccf789547afca5b991a3167241e8" integrity sha512-4/BMXcWrJErw7JpM87gF8MNEXcIMLzepYZjNRv/P9ctgupl2Ywa3u1PgHtNhSRq84bHH9Ndlkdy7bSi+bZ9I9A== @@ -15561,6 +15566,22 @@ ms@^2.0.0, ms@^2.1.1: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +msw@^0.19.5: + version "0.19.5" + resolved "https://registry.npmjs.org/msw/-/msw-0.19.5.tgz#7d2a1a852ccf1644d3db6735d69fff6777aac33f" + integrity sha512-J5eQ++gDVZoHPC8gVXtWcakLjgmPipvFj/sEnlRV/WViXuiq2CamSqO3Wbh6H8bAmj+k2vUWCfcVT1HjMdKB2Q== + dependencies: + "@open-draft/until" "^1.0.0" + "@types/cookie" "^0.3.3" + chalk "^4.0.0" + cookie "^0.4.1" + graphql "^15.0.0" + headers-utils "^1.1.9" + node-match-path "^0.4.2" + node-request-interceptor "^0.2.5" + statuses "^2.0.0" + yargs "^15.3.1" + msw@^0.20.5: version "0.20.5" resolved "https://registry.npmjs.org/msw/-/msw-0.20.5.tgz#b6141080c0d8b17c451d9ca36c28cc47b4ac487a" @@ -15807,7 +15828,7 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-match-path@^0.4.4: +node-match-path@^0.4.2, node-match-path@^0.4.4: version "0.4.4" resolved "https://registry.npmjs.org/node-match-path/-/node-match-path-0.4.4.tgz#516a10926093c0cc6f237d020685b593b19baebb" integrity sha512-pBq9gp7TG0r0VXuy/oeZmQsjBSnYQo7G886Ly/B3azRwZuEtHCY155dzmfoKWcDPGgyfIGD8WKVC7h3+6y7yTg== @@ -15866,6 +15887,14 @@ node-releases@^1.1.29, node-releases@^1.1.52, node-releases@^1.1.58: resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084" integrity sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA== +node-request-interceptor@^0.2.5: + version "0.2.6" + resolved "https://registry.npmjs.org/node-request-interceptor/-/node-request-interceptor-0.2.6.tgz#541278d7033bb6a8befb5dd793f83428cf6446a2" + integrity sha512-aJW1tPSM7nzuZFRe+C/KSz22GJO3CVFMxHHmMGX8Z+tjP7TCIVbzeckLFVfJG68BdVgrdOOP7Ejc57ag820eyA== + dependencies: + debug "^4.1.1" + headers-utils "^1.2.0" + node-request-interceptor@^0.3.5: version "0.3.5" resolved "https://registry.npmjs.org/node-request-interceptor/-/node-request-interceptor-0.3.5.tgz#4b26159617829c9a70643012c0fdc3ae4c78ae43" From 0627c246373f9073883a6808817e262e98fbaad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20=C3=85lund?= Date: Tue, 1 Sep 2020 09:26:21 +0200 Subject: [PATCH 21/56] Change templates to use Home theme (#2202) * Change templates to use Home theme * Update docs URL --- .../src/components/ScaffolderPage/ScaffolderPage.tsx | 4 ++-- .../scaffolder/src/components/TemplatePage/TemplatePage.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx index 12b3e303dd..6f8bf0d550 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx @@ -64,7 +64,7 @@ export const ScaffolderPage: React.FC<{}> = () => { }, [error, errorApi]); return ( - +
= () => { Shoot! Looks like you don't have any templates. Check out the documentation{' '} - + here! diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index 05cc249e41..3c22e8d50c 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -136,7 +136,7 @@ export const TemplatePage = () => { } return ( - +
Date: Tue, 1 Sep 2020 09:44:22 +0200 Subject: [PATCH 22/56] chore: remove gitignored files --- microsite/i18n/en.json | 328 ----------------------------------------- 1 file changed, 328 deletions(-) delete mode 100644 microsite/i18n/en.json diff --git a/microsite/i18n/en.json b/microsite/i18n/en.json deleted file mode 100644 index e9f63d5737..0000000000 --- a/microsite/i18n/en.json +++ /dev/null @@ -1,328 +0,0 @@ -{ - "_comment": "This file is auto-generated by write-translations.js", - "localized-strings": { - "next": "Next", - "previous": "Previous", - "tagline": "An open platform for building developer portals", - "docs": { - "api/backend": { - "title": "Backend" - }, - "api/utility-apis": { - "title": "Utility APIs" - }, - "architecture-decisions/adrs-adr001": { - "title": "ADR001: Architecture Decision Record (ADR) log", - "sidebar_label": "ADR001" - }, - "architecture-decisions/adrs-adr002": { - "title": "ADR002: Default Software Catalog File Format", - "sidebar_label": "ADR002" - }, - "architecture-decisions/adrs-adr003": { - "title": "ADR003: Avoid Default Exports and Prefer Named Exports", - "sidebar_label": "ADR003" - }, - "architecture-decisions/adrs-adr004": { - "title": "ADR004: Module Export Structure", - "sidebar_label": "ADR004" - }, - "architecture-decisions/adrs-adr005": { - "title": "ADR005: Catalog Core Entities", - "sidebar_label": "ADR005" - }, - "architecture-decisions/adrs-adr006": { - "title": "ADR006: Avoid React.FC and React.SFC", - "sidebar_label": "ADR006" - }, - "architecture-decisions/adrs-adr007": { - "title": "ADR007: Use MSW to mock http requests", - "sidebar_label": "ADR007" - }, - "architecture-decisions/adrs-adr008": { - "title": "ADR008: Default Catalog File Name", - "sidebar_label": "ADR008" - }, - "architecture-decisions/adrs-overview": { - "title": "Architecture Decision Records (ADR)", - "sidebar_label": "Overview" - }, - "auth/add-auth-provider": { - "title": "Adding authentication providers" - }, - "auth/auth-backend-classes": { - "title": "Auth backend classes" - }, - "auth/auth-backend": { - "title": "Auth backend" - }, - "auth/glossary": { - "title": "Glossary" - }, - "auth/index": { - "title": "User Authentication and Authorization in Backstage" - }, - "auth/oauth": { - "title": "OAuth and OpenID Connect" - }, - "conf/defining": { - "title": "Defining Configuration for your Plugin" - }, - "conf/index": { - "title": "Static Configuration in Backstage" - }, - "conf/reading": { - "title": "Reading Backstage Configuration" - }, - "conf/writing": { - "title": "Writing Backstage Configuration Files" - }, - "dls/contributing-to-storybook": { - "title": "Contributing to Storybook" - }, - "dls/design": { - "title": "Design" - }, - "dls/figma": { - "title": "Figma" - }, - "FAQ": { - "title": "FAQ" - }, - "features/software-catalog/software-catalog-api": { - "title": "API" - }, - "features/software-catalog/software-catalog-configuration": { - "title": "Catalog Configuration" - }, - "features/software-catalog/descriptor-format": { - "title": "Descriptor Format of Catalog Entities", - "sidebar_label": "YAML File Format" - }, - "features/software-catalog/extending-the-model": { - "title": "Extending the model" - }, - "features/software-catalog/external-integrations": { - "title": "External integrations" - }, - "features/software-catalog/software-catalog-overview": { - "title": "Backstage Service Catalog (alpha)", - "sidebar_label": "Backstage Service Catalog" - }, - "features/software-catalog/installation": { - "title": "features/software-catalog/installation" - }, - "features/software-catalog/system-model": { - "title": "System Model" - }, - "features/software-templates/adding-templates": { - "title": "Adding your own Templates" - }, - "features/software-templates/extending/extending-preparer": { - "title": "Create your own Preparer" - }, - "features/software-templates/extending/extending-publisher": { - "title": "Create your own Publisher" - }, - "features/software-templates/extending/extending-templater": { - "title": "Creating your own Templater" - }, - "features/software-templates/extending/extending-index": { - "title": "Extending the Scaffolder" - }, - "features/software-templates/software-templates-index": { - "title": "Software Templates" - }, - "features/software-templates/installation": { - "title": "features/software-templates/installation" - }, - "features/techdocs/concepts": { - "title": "Concepts" - }, - "features/techdocs/creating-and-publishing": { - "title": "Creating and publishing your docs", - "sidebar_label": "Creating and Publishing Documentation" - }, - "features/techdocs/faqs": { - "title": "TechDocs FAQ", - "sidebar_label": "FAQ" - }, - "features/techdocs/getting-started": { - "title": "Getting Started" - }, - "features/techdocs/techdocs-overview": { - "title": "TechDocs Documentation", - "sidebar_label": "Overview" - }, - "getting-started/app-custom-theme": { - "title": "Customize the look-and-feel of your App" - }, - "getting-started/configure-app-with-plugins": { - "title": "Configuring App with plugins" - }, - "getting-started/create-an-app": { - "title": "Create an App" - }, - "getting-started/deployment-k8s": { - "title": "Kubernetes" - }, - "getting-started/deployment-other": { - "title": "Other" - }, - "getting-started/development-environment": { - "title": "Development Environment" - }, - "getting-started/index": { - "title": "Running Backstage Locally" - }, - "getting-started/installation": { - "title": "Installation" - }, - "overview/adopting": { - "title": "Strategies for adopting" - }, - "overview/architecture-overview": { - "title": "Architecture overview" - }, - "overview/architecture-terminology": { - "title": "Architecture terminology" - }, - "overview/background": { - "title": "The Spotify Story" - }, - "overview/roadmap": { - "title": "Project roadmap" - }, - "overview/support": { - "title": "Support and community" - }, - "overview/vision": { - "title": "Vision" - }, - "overview/what-is-backstage": { - "title": "What is Backstage?" - }, - "plugins/add-to-marketplace": { - "title": "Add to Marketplace" - }, - "plugins/backend-plugin": { - "title": "Backend plugin" - }, - "plugins/call-existing-api": { - "title": "Call Existing API" - }, - "plugins/create-a-plugin": { - "title": "Create a Backstage Plugin" - }, - "plugins/existing-plugins": { - "title": "Existing plugins" - }, - "plugins/index": { - "title": "Intro to plugins" - }, - "plugins/plugin-development": { - "title": "Plugin Development" - }, - "plugins/proxying": { - "title": "Proxying" - }, - "plugins/publish-private": { - "title": "Publish private" - }, - "plugins/publishing": { - "title": "Publishing" - }, - "plugins/structure-of-a-plugin": { - "title": "Structure of a Plugin" - }, - "plugins/testing": { - "title": "Testing with Jest" - }, - "README": { - "title": "README" - }, - "reference/createPlugin-feature-flags": { - "title": "createPlugin - feature flags" - }, - "reference/createPlugin-router": { - "title": "createPlugin - router" - }, - "reference/createPlugin": { - "title": "createPlugin" - }, - "reference/utility-apis/AlertApi": { - "title": "reference/utility-apis/AlertApi" - }, - "reference/utility-apis/AppThemeApi": { - "title": "reference/utility-apis/AppThemeApi" - }, - "reference/utility-apis/BackstageIdentityApi": { - "title": "reference/utility-apis/BackstageIdentityApi" - }, - "reference/utility-apis/Config": { - "title": "reference/utility-apis/Config" - }, - "reference/utility-apis/ErrorApi": { - "title": "reference/utility-apis/ErrorApi" - }, - "reference/utility-apis/FeatureFlagsApi": { - "title": "reference/utility-apis/FeatureFlagsApi" - }, - "reference/utility-apis/IdentityApi": { - "title": "reference/utility-apis/IdentityApi" - }, - "reference/utility-apis/OAuthApi": { - "title": "reference/utility-apis/OAuthApi" - }, - "reference/utility-apis/OAuthRequestApi": { - "title": "reference/utility-apis/OAuthRequestApi" - }, - "reference/utility-apis/OpenIdConnectApi": { - "title": "reference/utility-apis/OpenIdConnectApi" - }, - "reference/utility-apis/ProfileInfoApi": { - "title": "reference/utility-apis/ProfileInfoApi" - }, - "reference/utility-apis/README": { - "title": "Utility API References" - }, - "reference/utility-apis/SessionStateApi": { - "title": "reference/utility-apis/SessionStateApi" - }, - "reference/utility-apis/StorageApi": { - "title": "reference/utility-apis/StorageApi" - }, - "tutorials/journey": { - "title": "Future developer journey" - } - }, - "links": { - "GitHub": "GitHub", - "Docs": "Docs", - "Plugins": "Plugins", - "Blog": "Blog", - "Demos": "Demos", - "Newsletter": "Newsletter" - }, - "categories": { - "Overview": "Overview", - "Getting Started": "Getting Started", - "Features": "Features", - "Plugins": "Plugins", - "Configuration": "Configuration", - "Auth and identity": "Auth and identity", - "Designing for Backstage": "Designing for Backstage", - "API references": "API references", - "Tutorials": "Tutorials", - "Architecture Decision Records (ADRs)": "Architecture Decision Records (ADRs)", - "Contribute": "Contribute", - "Support": "Support", - "FAQ": "FAQ" - } - }, - "pages-strings": { - "Help Translate|recruit community translators for your project": "Help Translate", - "Edit this Doc|recruitment message asking to edit the doc source": "Edit", - "Translate this Doc|recruitment message asking to translate the docs": "Translate" - } -} From bcbeb0b657945b55965260c67524621c17fb823e Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Tue, 1 Sep 2020 09:46:46 +0200 Subject: [PATCH 23/56] Add api-docs to marketplace (#2204) * docs: improve documentation about adding plugins to the marketplace The relative path is misleading as one has to come from root. * docs: add api-docs plugin to marketplace --- docs/plugins/add-to-marketplace.md | 4 +++- microsite/data/plugins/api-docs.yaml | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 microsite/data/plugins/api-docs.yaml diff --git a/docs/plugins/add-to-marketplace.md b/docs/plugins/add-to-marketplace.md index 23cfecd5d0..d85807a226 100644 --- a/docs/plugins/add-to-marketplace.md +++ b/docs/plugins/add-to-marketplace.md @@ -6,7 +6,9 @@ title: Add to Marketplace ## Adding a Plugin to the Marketplace To add a new plugin to the [plugin marketplace](https://backstage.io/plugins) -create a file in `data/plugins` with your plugin's information. Example: +create a file in +[`microsite/data/plugins`](https://github.com/spotify/backstage/tree/master/microsite/data/plugins) +with your plugin's information. Example: ```yaml --- diff --git a/microsite/data/plugins/api-docs.yaml b/microsite/data/plugins/api-docs.yaml new file mode 100644 index 0000000000..b7f85b62b3 --- /dev/null +++ b/microsite/data/plugins/api-docs.yaml @@ -0,0 +1,9 @@ +--- +title: API Docs +author: SDA SE +authorUrl: https://sda.se/ +category: Discovery +description: Components to discover and display API entities as an extension to the catalog plugin. +documentation: https://github.com/spotify/backstage/blob/master/plugins/api-docs/README.md +iconUrl: https://github.com/spotify/backstage/raw/master/plugins/api-docs/docs/entity_tab_api.png +npmPackageName: '@backstage/plugin-api-docs' From b9ed0d3088a6c3634d16a08d7bce4c992b4477dd Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Tue, 1 Sep 2020 09:51:00 +0200 Subject: [PATCH 24/56] feat(catalog): change the tags in the entity list to be gray (#2205) --- .../catalog/src/components/CatalogTable/CatalogTable.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx index c68eb10e66..cd4df13775 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx @@ -75,12 +75,7 @@ const columns: TableColumn[] = [ <> {entity.metadata.tags && entity.metadata.tags.map(t => ( - + ))} ), From ff5da01280cc79a7792b58a18de5bd604db431e1 Mon Sep 17 00:00:00 2001 From: Emma Indal Date: Tue, 1 Sep 2020 09:54:05 +0200 Subject: [PATCH 25/56] TechDocs: techdocs backend tests (#2196) * add tests for generators class * add tests for helpers * renaming * fixup --- .../stages/generate/generators.test.ts | 47 ++++++++ .../techdocs/stages/generate/generators.ts | 53 +++++---- .../techdocs/stages/generate/helpers.test.ts | 103 ++++++++++++++++++ 3 files changed, 175 insertions(+), 28 deletions(-) create mode 100644 plugins/techdocs-backend/src/techdocs/stages/generate/generators.test.ts create mode 100644 plugins/techdocs-backend/src/techdocs/stages/generate/helpers.test.ts diff --git a/plugins/techdocs-backend/src/techdocs/stages/generate/generators.test.ts b/plugins/techdocs-backend/src/techdocs/stages/generate/generators.test.ts new file mode 100644 index 0000000000..b339aef9f8 --- /dev/null +++ b/plugins/techdocs-backend/src/techdocs/stages/generate/generators.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Generators, TechdocsGenerator } from './'; +import { getVoidLogger } from '@backstage/backend-common'; + +const logger = getVoidLogger(); + +const mockEntity = { + apiVersion: 'version', + kind: 'TestKind', + metadata: { + name: 'testName', + }, +}; + +describe('generators', () => { + it('should return error if no generator is registered', async () => { + const generators = new Generators(); + + expect(() => generators.get(mockEntity)).toThrowError( + 'No generator registered for entity: "techdocs"', + ); + }); + + it('should return correct registered generator', async () => { + const generators = new Generators(); + const techdocs = new TechdocsGenerator(logger); + + generators.register('techdocs', techdocs); + + expect(generators.get(mockEntity)).toBe(techdocs); + }); +}); diff --git a/plugins/techdocs-backend/src/techdocs/stages/generate/generators.ts b/plugins/techdocs-backend/src/techdocs/stages/generate/generators.ts index da9d3c418b..f28a169942 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/generate/generators.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/generate/generators.ts @@ -15,32 +15,29 @@ */ import { - GeneratorBase, - SupportedGeneratorKey, - GeneratorBuilder, - } from './types'; - - import { Entity } from '@backstage/catalog-model'; - import { getGeneratorKey } from './helpers'; - - export class Generators implements GeneratorBuilder { - private generatorMap = new Map(); - - register(templaterKey: SupportedGeneratorKey, templater: GeneratorBase) { - this.generatorMap.set(templaterKey, templater); - } - - get(entity: Entity): GeneratorBase { - const generatorKey = getGeneratorKey(entity); - const generator = this.generatorMap.get(generatorKey); - - if (!generator) { - throw new Error( - `No generator registered for entity: "${generatorKey}"`, - ); - } - - return generator; - } + GeneratorBase, + SupportedGeneratorKey, + GeneratorBuilder, +} from './types'; + +import { Entity } from '@backstage/catalog-model'; +import { getGeneratorKey } from './helpers'; + +export class Generators implements GeneratorBuilder { + private generatorMap = new Map(); + + register(generatorKey: SupportedGeneratorKey, generator: GeneratorBase) { + this.generatorMap.set(generatorKey, generator); } - \ No newline at end of file + + get(entity: Entity): GeneratorBase { + const generatorKey = getGeneratorKey(entity); + const generator = this.generatorMap.get(generatorKey); + + if (!generator) { + throw new Error(`No generator registered for entity: "${generatorKey}"`); + } + + return generator; + } +} diff --git a/plugins/techdocs-backend/src/techdocs/stages/generate/helpers.test.ts b/plugins/techdocs-backend/src/techdocs/stages/generate/helpers.test.ts new file mode 100644 index 0000000000..799e79ef67 --- /dev/null +++ b/plugins/techdocs-backend/src/techdocs/stages/generate/helpers.test.ts @@ -0,0 +1,103 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import Stream, { PassThrough } from 'stream'; +import os from 'os'; +import Docker from 'dockerode'; +import { runDockerContainer, getGeneratorKey } from './helpers'; + +const mockEntity = { + apiVersion: 'version', + kind: 'TestKind', + metadata: { + name: 'testName', + }, +}; + +const mockDocker = new Docker() as jest.Mocked; + +describe('helpers', () => { + describe('getGeneratorKey', () => { + it('should return techdocs as the only generator key', () => { + const key = getGeneratorKey(mockEntity); + expect(key).toBe('techdocs'); + }); + }); + + describe('runDockerContainer', () => { + beforeEach(() => { + jest.spyOn(mockDocker, 'pull').mockImplementation((async ( + _image: string, + _something: any, + handler: (err: Error | undefined, stream: PassThrough) => void, + ) => { + const mockStream = new PassThrough(); + handler(undefined, mockStream); + mockStream.end(); + }) as any); + + jest + .spyOn(mockDocker, 'run') + .mockResolvedValue([{ Error: null, StatusCode: 0 }]); + }); + + const imageName = 'spotify/techdocs'; + const args = ['build', '-d', '/result']; + const docsDir = os.tmpdir(); + const resultDir = os.tmpdir(); + + it('should pull the techdocs docker container', async () => { + await runDockerContainer({ + imageName, + args, + docsDir, + resultDir, + dockerClient: mockDocker, + }); + + expect(mockDocker.pull).toHaveBeenCalledWith( + imageName, + {}, + expect.any(Function), + ); + }); + + it('should run the techdocs docker container', async () => { + await runDockerContainer({ + imageName, + args, + docsDir, + resultDir, + dockerClient: mockDocker, + }); + + expect(mockDocker.run).toHaveBeenCalledWith( + imageName, + args, + expect.any(Stream), + { + Volumes: { + '/content': {}, + '/result': {}, + }, + WorkingDir: '/content', + HostConfig: { + Binds: [`${docsDir}:/content`, `${resultDir}:/result`], + }, + }, + ); + }); + }); +}); From f7ac665b75ef63951a60be700dbede728806d6aa Mon Sep 17 00:00:00 2001 From: nikek Date: Tue, 1 Sep 2020 10:26:16 +0200 Subject: [PATCH 26/56] Add semantic color to AboutCard field titles --- plugins/catalog/src/components/AboutCard/AboutCard.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index d27175fcf3..d83beaedb5 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -35,17 +35,18 @@ import DocsIcon from '@material-ui/icons/Description'; const useStyles = makeStyles(theme => ({ links: { - margin: theme.spacing(2, 0, 2), + margin: theme.spacing(2, 0), display: 'grid', gridAutoFlow: 'column', gridAutoColumns: 'min-content', - gridGap: theme.spacing(2), + gridGap: theme.spacing(3), }, label: { - color: '#9e9e9e', + color: theme.palette.text.secondary, textTransform: 'uppercase', - fontSize: '12px', + fontSize: '10px', fontWeight: 'bold', + letterSpacing: 0.5, overflow: 'hidden', whiteSpace: 'nowrap', }, From a549ad53cea7f0b1ee9c3e28b4741e50ee8adcef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20DOREAU?= Date: Tue, 1 Sep 2020 10:37:04 +0200 Subject: [PATCH 27/56] fix(create-app): remove duplicate import --- .../create-app/templates/default-app/packages/app/src/apis.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/create-app/templates/default-app/packages/app/src/apis.ts b/packages/create-app/templates/default-app/packages/app/src/apis.ts index 02b5898884..14351eaba7 100644 --- a/packages/create-app/templates/default-app/packages/app/src/apis.ts +++ b/packages/create-app/templates/default-app/packages/app/src/apis.ts @@ -27,9 +27,6 @@ import { import { techdocsStorageApiRef, TechDocsStorageApi, - - techdocsStorageApiRef, - TechDocsStorageApi, } from '@backstage/plugin-techdocs'; import { techRadarApiRef, TechRadar } from '@backstage/plugin-tech-radar'; From 81cb294dacbf23bc863afb3b287a24ff9a68d61b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Sep 2020 10:36:21 +0200 Subject: [PATCH 28/56] config,docs: add templates as allowed kind and document process --- app-config.yaml | 2 ++ .../software-catalog/configuration.md | 4 ++-- .../software-templates/adding-templates.md | 22 +++++++++++++++++++ .../templates/default-app/app-config.yaml.hbs | 5 +++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index 3b3733cf54..ba556873aa 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -48,6 +48,8 @@ lighthouse: baseUrl: http://localhost:3003 catalog: + rules: + allow: [Component, API, Group, Template] processors: githubApi: privateToken: diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index d4cc7fc0c2..acfaf115de 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -32,7 +32,7 @@ For example, given the following configuration: ```yaml catalog: rules: - - allow: [Component, API, System] + - allow: [Component, API, Template] locations: - type: github @@ -40,7 +40,7 @@ catalog: allow: [Group] ``` -We are able to add entities of kind `Component`, `API`, or `System` from any +We are able to add entities of kind `Component`, `API`, or `Template` from any location, and `Group` entities from the `org-data.yaml`, which will also be read as statically configured location. diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index 67467bd98e..16419b4dfe 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -58,6 +58,28 @@ Currently the catalog supports loading definitions from GitHub + Local Files. To load from other places, not only will there need to be another preparer, but the support to load the location will also need to be added to the Catalog. +You can add the template files to the catalog through +[static location configuration](../software-catalog/configuration.md#static-location-configuration), +for example + +```yaml +catalog: + locations: + - type: github + target: https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml + allow: [Template] +``` + +Templates can also be added by posting the to the catalog directly. Note that if +you're doing this, you need to configure the catalog to allow template entities +to be ingested from any source, for example: + +```yaml +catalog: + rules: + allow: [Component, API, Template] +``` + For loading from a file, the following command should work when the backend is running: diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index aff375ad29..e194295df3 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -69,11 +69,16 @@ catalog: # Backstage example templates - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml + allow: [Template] - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml + allow: [Template] - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml + allow: [Template] - type: github target: https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml + allow: [Template] - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml + allow: [Template] From a85ca3123c8a00b590be214cb3f992965d2bf598 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Tue, 1 Sep 2020 10:46:52 +0200 Subject: [PATCH 29/56] Add non-legacy routes when in isolation --- packages/dev-utils/src/devApp/render.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx index 0e28a5bf8b..410f7592a5 100644 --- a/packages/dev-utils/src/devApp/render.tsx +++ b/packages/dev-utils/src/devApp/render.tsx @@ -199,8 +199,17 @@ class DevAppBuilder { for (const plugin of plugins) { for (const output of plugin.output()) { - if (output.type === 'legacy-route') { - paths.push(output.path); + switch (output.type) { + case 'legacy-route': { + paths.push(output.path); + break; + } + case 'route': { + paths.push(output.target.path); + break; + } + default: + break; } } } From 042f2cbb44faeb2a92ad43841a84776681947c49 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Tue, 1 Sep 2020 10:53:55 +0200 Subject: [PATCH 30/56] Fix formatting in plugin template --- .../cli/templates/default-plugin/src/plugin.ts.hbs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/cli/templates/default-plugin/src/plugin.ts.hbs b/packages/cli/templates/default-plugin/src/plugin.ts.hbs index 6a410a6a28..1bf4d07cdb 100644 --- a/packages/cli/templates/default-plugin/src/plugin.ts.hbs +++ b/packages/cli/templates/default-plugin/src/plugin.ts.hbs @@ -2,13 +2,13 @@ import { createPlugin, createRouteRef } from '@backstage/core'; import ExampleComponent from './components/ExampleComponent'; export const rootRouteRef = createRouteRef({ -path: '/{{ id }}', -title: '{{ id }}', + path: '/{{ id }}', + title: '{{ id }}', }); export const plugin = createPlugin({ -id: '{{ id }}', -register({ router }) { -router.addRoute(rootRouteRef, ExampleComponent); -}, + id: '{{ id }}', + register({ router }) { + router.addRoute(rootRouteRef, ExampleComponent); + }, }); From 6e8f4ca44a0c1ee429198a05f420867774c19172 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Sep 2020 11:30:59 +0200 Subject: [PATCH 31/56] catalog-backend: wrap location-specific rules in an additional rules field --- .../software-catalog/configuration.md | 3 +- .../software-templates/adding-templates.md | 3 +- .../templates/default-app/app-config.yaml.hbs | 15 ++++++---- .../src/ingestion/CatalogRules.test.ts | 6 +++- .../src/ingestion/CatalogRules.ts | 29 +++++++++---------- 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index acfaf115de..44e998d5a9 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -37,7 +37,8 @@ catalog: locations: - type: github target: https://github.com/org/example/blob/master/org-data.yaml - allow: [Group] + rules: + - allow: [Group] ``` We are able to add entities of kind `Component`, `API`, or `Template` from any diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index 16419b4dfe..6e6e22dd9a 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -67,7 +67,8 @@ catalog: locations: - type: github target: https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml - allow: [Template] + rules: + - allow: [Template] ``` Templates can also be added by posting the to the catalog directly. Note that if diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index e194295df3..16729e00e4 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -69,16 +69,21 @@ catalog: # Backstage example templates - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml - allow: [Template] + rules: + - allow: [Template] - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml - allow: [Template] + rules: + - allow: [Template] - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml - allow: [Template] + rules: + - allow: [Template] - type: github target: https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml - allow: [Template] + rules: + - allow: [Template] - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml - allow: [Template] + rules: + - allow: [Template] diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts index 34484f6b1e..794416786c 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts @@ -167,7 +167,11 @@ describe('CatalogRulesEnforcer', () => { { type: 'github', target: 'https://github.com/a/b/blob/master/x.yaml', - allow: ['Group'], + rules: [ + { + allow: ['Group'], + }, + ], }, ], }, diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.ts index eda93b552f..2b55ebef32 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.ts @@ -64,7 +64,7 @@ export class CatalogRulesEnforcer { * If there is no matching rule to allow an ingested entity, it will be rejected by the catalog. * * It also reads in rules from `catalog.locations`, where each location can have a list - * of allowed entity for the location, specified in an `allow` field. + * of rules for that specific location, specified in a `rules` field. * * For example: * @@ -76,10 +76,12 @@ export class CatalogRulesEnforcer { * locations: * - type: github * target: https://github.com/org/repo/blob/master/users.yaml - * allow: [User, Group] + * rules: + * - allow: [User, Group] * - type: github * target: https://github.com/org/repo/blob/master/systems.yaml - * allow: [System] + * rules: + * - allow: [System] * ``` */ static fromConfig(config: Config) { @@ -97,22 +99,17 @@ export class CatalogRulesEnforcer { if (config.has('catalog.locations')) { const locationRules = config .getConfigArray('catalog.locations') - .flatMap(sub => { - if (!sub.has('allow')) { + .flatMap(locConf => { + if (!locConf.has('rules')) { return []; } + const type = locConf.getString('type'); + const target = locConf.getString('target'); - return [ - { - allow: sub.getStringArray('allow').map(kind => ({ kind })), - locations: [ - { - type: sub.getString('type'), - target: sub.getString('target'), - }, - ], - }, - ]; + return locConf.getConfigArray('rules').map(ruleConf => ({ + allow: ruleConf.getStringArray('allow').map(kind => ({ kind })), + locations: [{ type, target }], + })); }); rules.push(...locationRules); From 568f398aa944fa2b87369d68da8fd428890db84d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 1 Sep 2020 11:59:31 +0200 Subject: [PATCH 32/56] BREAKING CHANGE: no longer add express.json() by default to backend --- CHANGELOG.md | 9 +++++++++ .../backend-common/src/service/lib/ServiceBuilderImpl.ts | 1 - plugins/auth-backend/package.json | 1 - plugins/auth-backend/src/service/router.ts | 5 ++--- plugins/graphql/src/service/router.ts | 4 ++-- plugins/identity-backend/src/service/router.ts | 4 +++- plugins/rollbar-backend/src/service/router.ts | 1 + plugins/scaffolder-backend/src/service/router.ts | 1 + plugins/sentry-backend/src/service/router.ts | 2 ++ yarn.lock | 2 +- 10 files changed, 21 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce39a9f8d2..20ae9a414d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,15 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re > Collect changes for the next release below +- The backend plugin + [service builder](https://github.com/spotify/backstage/blob/master/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts) + no longer adds `express.json()` automatically to all routes. While convenient + in a lot of cases, it also led to problems where for example the proxy + middleware could hang because the body had already been altered and could not + be streamed. Also, plugins that rather wanted to handle e.g. form encoded data + still had to cater to that manually. We therefore decided to let plugins add + `express.json()` themselves if they happen to deal with JSON data. + ## v0.1.1-alpha.20 - Includes https://github.com/spotify/backstage/pull/2097 to resolve issues with create-plugin command. diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index df69387e40..10f9ca4d9b 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -135,7 +135,6 @@ export class ServiceBuilderImpl implements ServiceBuilder { app.use(cors(corsOptions)); } app.use(compression()); - app.use(express.json()); if (this.enableMetrics) { app.use(metricsHandler()); } diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index e5838c9011..107a594c4d 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -23,7 +23,6 @@ "@backstage/backend-common": "^0.1.1-alpha.20", "@backstage/config": "^0.1.1-alpha.20", "@types/express": "^4.17.6", - "body-parser": "^1.19.0", "compression": "^1.7.4", "cookie-parser": "^1.4.5", "cors": "^2.8.5", diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 8ea1d412cb..b5451cad6c 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -17,7 +17,6 @@ import express from 'express'; import Router from 'express-promise-router'; import cookieParser from 'cookie-parser'; -import bodyParser from 'body-parser'; import Knex from 'knex'; import { Logger } from 'winston'; import { createAuthProviderRouter } from '../providers'; @@ -53,8 +52,8 @@ export async function createRouter( }); router.use(cookieParser()); - router.use(bodyParser.urlencoded({ extended: false })); - router.use(bodyParser.json()); + router.use(express.urlencoded({ extended: false })); + router.use(express.json()); const providersConfig = options.config.getConfig('auth.providers'); const providers = providersConfig.keys(); diff --git a/plugins/graphql/src/service/router.ts b/plugins/graphql/src/service/router.ts index 69e2394f11..0b91d7307a 100644 --- a/plugins/graphql/src/service/router.ts +++ b/plugins/graphql/src/service/router.ts @@ -39,8 +39,8 @@ export async function createRouter( const server = new ApolloServer({ typeDefs, logger: options.logger }); const router = Router(); - const apolloMiddlware = server.getMiddleware({ path: '/' }); - router.use(apolloMiddlware); + const apolloMiddleware = server.getMiddleware({ path: '/' }); + router.use(apolloMiddleware); router.get('/health', (_, response) => { response.send({ status: 'ok' }); diff --git a/plugins/identity-backend/src/service/router.ts b/plugins/identity-backend/src/service/router.ts index 9c6515ac04..9d16e8f332 100644 --- a/plugins/identity-backend/src/service/router.ts +++ b/plugins/identity-backend/src/service/router.ts @@ -27,13 +27,15 @@ export interface RouterOptions { const makeRouter = (adapter: IdentityApi): express.Router => { const router = Router(); + router.use(express.json()); + router.get('/users/:user/groups', async (req, res) => { const user = req.params.user; const type = req.query.type?.toString() ?? ''; - const response = await adapter.getUserGroups({ user, type }); res.send(response); }); + return router; }; diff --git a/plugins/rollbar-backend/src/service/router.ts b/plugins/rollbar-backend/src/service/router.ts index 0a8c58a9d7..5ee63b5b05 100644 --- a/plugins/rollbar-backend/src/service/router.ts +++ b/plugins/rollbar-backend/src/service/router.ts @@ -31,6 +31,7 @@ export async function createRouter( options: RouterOptions, ): Promise { const router = Router(); + const logger = options.logger.child({ plugin: 'rollbar' }); const config = options.config.getConfig('rollbar'); const accessToken = !options.rollbarApi diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index fcfd5765a1..1b96158fa4 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -42,6 +42,7 @@ export async function createRouter( options: RouterOptions, ): Promise { const router = Router(); + router.use(express.json()); const { preparers, diff --git a/plugins/sentry-backend/src/service/router.ts b/plugins/sentry-backend/src/service/router.ts index e7978042d3..153a8325b5 100644 --- a/plugins/sentry-backend/src/service/router.ts +++ b/plugins/sentry-backend/src/service/router.ts @@ -20,6 +20,8 @@ import { getSentryApiForwarder } from './sentry-api'; export async function createRouter(logger: Logger): Promise { const router = Router(); + router.use(express.json()); + const SENTRY_TOKEN = process.env.SENTRY_TOKEN; if (!SENTRY_TOKEN) { if (process.env.NODE_ENV !== 'development') { diff --git a/yarn.lock b/yarn.lock index aa85370465..84e4c4cbb4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6562,7 +6562,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -body-parser@1.19.0, body-parser@^1.18.3, body-parser@^1.19.0: +body-parser@1.19.0, body-parser@^1.18.3: version "1.19.0" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== From 1b658f4bc349018c06a96f6e1ac8cc29bcbba597 Mon Sep 17 00:00:00 2001 From: Dominik Henneke Date: Tue, 1 Sep 2020 13:31:45 +0200 Subject: [PATCH 33/56] fix: use correct rules syntax --- app-config.yaml | 2 +- docs/features/software-templates/adding-templates.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index ba556873aa..7a8863495e 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -49,7 +49,7 @@ lighthouse: catalog: rules: - allow: [Component, API, Group, Template] + - allow: [Component, API, Group, Template, Location] processors: githubApi: privateToken: diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index 16419b4dfe..58dbe847a5 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -77,7 +77,7 @@ to be ingested from any source, for example: ```yaml catalog: rules: - allow: [Component, API, Template] + - allow: [Component, API, Template] ``` For loading from a file, the following command should work when the backend is From ee0310213c41e385ec9c6bbab927392b8f66f676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20=C3=85lund?= Date: Tue, 1 Sep 2020 14:27:33 +0200 Subject: [PATCH 34/56] Tweaks to plugin marketplace (#2209) * Tweaks to plugin marketplace * Add plugin details to roadmap * Update README.md * Link to plugins from home * Update circleci.yaml --- CONTRIBUTING.md | 7 +- README.md | 2 +- docs/overview/roadmap.md | 21 ++-- microsite/core/Footer.js | 3 + microsite/data/plugins/api-docs.yaml | 2 +- microsite/data/plugins/circleci.yaml | 2 +- microsite/data/plugins/github-actions.yaml | 13 +++ microsite/data/plugins/tech-radar.yaml | 2 +- microsite/pages/en/index.js | 10 +- microsite/pages/en/plugins.js | 38 ++++++- microsite/static/css/plugins.css | 115 +++++++++++---------- 11 files changed, 133 insertions(+), 82 deletions(-) create mode 100644 microsite/data/plugins/github-actions.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5b8febd1d2..853332f74d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,4 @@ ---- -id: CONTRIBUTING -title: Contributing ---- +# Contributing to Backstage Our vision for Backstage is for it to become the trusted standard toolbox (read: UX layer) for the open source infrastructure landscape. Think of it like Kubernetes for developer experience. We realize this is an ambitious goal. We can’t do it alone. @@ -31,7 +28,7 @@ What kind of plugins should/could be created? Some inspiration from the 120+ plu ## Suggesting a plugin -If you start developing a plugin that you aim to release as open source, we suggest that you create a new [new Issue](https://github.com/spotify/backstage/issues/new?template=plugin_template.md). This helps the community know what plugins are in development. +If you start developing a plugin that you aim to release as open source, we suggest that you create a new [new Issue](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME). This helps the community know what plugins are in development. You can also use this process if you have an idea for a good plugin but you hope that someone else will pick up the work. diff --git a/README.md b/README.md index b5e8704548..4009864edc 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Take a look at the [Getting Started](https://backstage.io/docs/getting-started/i ## Documentation -- [Main documentation](https://backstage.io/docs/overview/what-is-backstage) +- [Main documentation](https://backstage.io/docs) - [Service Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview) - [Architecture](https://backstage.io/docs/overview/architecture-terminology) ([Decisions](https://backstage.io/docs/architecture-decisions/adrs-overview)) - [Designing for Backstage](https://backstage.io/docs/dls/design) diff --git a/docs/overview/roadmap.md b/docs/overview/roadmap.md index a84bc525c9..5a06f4544f 100644 --- a/docs/overview/roadmap.md +++ b/docs/overview/roadmap.md @@ -79,18 +79,26 @@ guidelines to get started. - Further improvements to platform documentation +### Plugins + +Building and maintaining [plugins](https://backstage.io/plugins) is the work of +the entire Backstage community. + +A list of plugins that are in development is +[available here](https://github.com/spotify/backstage/issues?q=is%3Aissue+is%3Aopen+label%3Aplugin+sort%3Areactions-%2B1-desc). +We strongly recommend to upvote 👍 plugins you are interested in. This helps us +and the community prioritize what plugins to build. + +Are you missing a plugin for your favorite tool? Please +[suggest a new one](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME). +Chances are that someone will jump in and help build it. + ### Future work 🔮 - **[Backstage platform is stable](https://github.com/spotify/backstage/milestone/19)** - The platform APIs and features are stable and can be depended on for production use. After this plugins will require little to no maintenance. -- **[Plugin marketplace](https://github.com/spotify/backstage/issues/2009)** - - As the ecosystem of Backstage plugins continues to grow it is becoming - increasingly hard to keep track of what plugins are available. To solve this - we imagine a "Plugin marketplace" that helps with discovery and installation - of plugins. - - **Deploy a product demo at `demo.backstage.io`** - Deploy a typical Backstage deployment available publicly so that people can click around and get a feel for the product without having to install anything. @@ -111,6 +119,7 @@ guidelines to get started. ### Completed milestones ✅ +- [Plugin marketplace](https://backstage.io/plugins) - [Improved and move documentation to backstage.io](https://backstage.io/docs/overview/what-is-backstage) - [Backstage Service Catalog (alpha)](https://backstage.io/blog/2020/06/22/backstage-service-catalog-alpha) - [Backstage Software Templates (alpha)](https://backstage.io/blog/2020/08/05/announcing-backstage-software-templates) diff --git a/microsite/core/Footer.js b/microsite/core/Footer.js index 407bebca84..761862c1fc 100644 --- a/microsite/core/Footer.js +++ b/microsite/core/Footer.js @@ -45,6 +45,9 @@ class Footer extends React.Component {
Community
Support chatroom + + Contributing + Subscribe to our newsletter diff --git a/microsite/data/plugins/api-docs.yaml b/microsite/data/plugins/api-docs.yaml index b7f85b62b3..babcbf74f1 100644 --- a/microsite/data/plugins/api-docs.yaml +++ b/microsite/data/plugins/api-docs.yaml @@ -5,5 +5,5 @@ authorUrl: https://sda.se/ category: Discovery description: Components to discover and display API entities as an extension to the catalog plugin. documentation: https://github.com/spotify/backstage/blob/master/plugins/api-docs/README.md -iconUrl: https://github.com/spotify/backstage/raw/master/plugins/api-docs/docs/entity_tab_api.png +iconUrl: https://thecoders.io/wp-content/uploads/2019/11/tech-swagger.svg npmPackageName: '@backstage/plugin-api-docs' diff --git a/microsite/data/plugins/circleci.yaml b/microsite/data/plugins/circleci.yaml index c8a3677614..6937064815 100644 --- a/microsite/data/plugins/circleci.yaml +++ b/microsite/data/plugins/circleci.yaml @@ -5,5 +5,5 @@ authorUrl: https://www.spotify.com/ category: CI description: Automate your development process with CI hosted in the cloud or on a private server. documentation: https://github.com/spotify/backstage/tree/master/plugins/circleci -iconUrl: https://d3r49iyjzglexf.cloudfront.net/logo-wordmark-26f8eaea9b0f6e13b90d3f4a8fd8fda31490f5af41daab98bbede45037682576.svg +iconUrl: https://www.saaves.com/storage/brochure/logo-circleci-icon1583764538.png npmPackageName: '@backstage/plugin-circleci' diff --git a/microsite/data/plugins/github-actions.yaml b/microsite/data/plugins/github-actions.yaml new file mode 100644 index 0000000000..b384980b2a --- /dev/null +++ b/microsite/data/plugins/github-actions.yaml @@ -0,0 +1,13 @@ +--- +title: GitHub Actions +author: Spotify +authorUrl: https://www.spotify.com/ +category: CI +description: GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. +documentation: https://github.com/spotify/backstage/tree/master/plugins/github-actions +iconUrl: https://avatars2.githubusercontent.com/u/44036562?s=400&v=4 +npmPackageName: '@backstage/plugin-github-actions' +tags: + - ci + - cd + - github diff --git a/microsite/data/plugins/tech-radar.yaml b/microsite/data/plugins/tech-radar.yaml index a20667e8f0..585e204b12 100644 --- a/microsite/data/plugins/tech-radar.yaml +++ b/microsite/data/plugins/tech-radar.yaml @@ -5,5 +5,5 @@ authorUrl: https://www.spotify.com/ category: Discovery description: Visualize the your company's official guidelines of different areas of software development. documentation: https://github.com/spotify/backstage/tree/master/plugins/tech-radar -iconUrl: https://github.com/spotify/backstage/raw/master/plugins/tech-radar/docs/screenshot.png +iconUrl: https://img.icons8.com/officel/2x/radar.png npmPackageName: '@backstage/plugin-tech-radar' diff --git a/microsite/pages/en/index.js b/microsite/pages/en/index.js index 986db4b732..7a58ede25f 100644 --- a/microsite/pages/en/index.js +++ b/microsite/pages/en/index.js @@ -455,12 +455,8 @@ class Index extends React.Component { Share with the community - Building{' '} - - open source plugins - {' '} - contributes to the entire Backstage ecosystem, which benefits - everyone + Building open source plugins contributes + to the entire Backstage ecosystem, which benefits everyone @@ -472,7 +468,7 @@ class Index extends React.Component { Build a plugin - + Contribute diff --git a/microsite/pages/en/plugins.js b/microsite/pages/en/plugins.js index 916f34c21e..8c5f017e24 100644 --- a/microsite/pages/en/plugins.js +++ b/microsite/pages/en/plugins.js @@ -29,13 +29,14 @@ const Plugins = () => (
-

Plugins

+

Plugin marketplace

+

Open source plugins that you can add to your Backstage deployment

- Add Plugin + Add to marketplace
@@ -69,13 +70,44 @@ const Plugins = () => ( className="PluginCardLink ButtonFilled" href={documentation} > - docs + Explore
), )} +
+
+

+ Do you have an existing plugin that you want to add to the + Marketplace? +

+

+ + Add to marketplace + +

+
+ +

+ See what plugins are already{' '} + + in progress + {' '} + and 👍. Missing a plugin for your favorite tool? Please{' '} + + suggest + {' '} + a new one. +

+
+
diff --git a/microsite/static/css/plugins.css b/microsite/static/css/plugins.css index 042e2954e1..96fe3dac35 100644 --- a/microsite/static/css/plugins.css +++ b/microsite/static/css/plugins.css @@ -1,111 +1,112 @@ .PluginCard { - background-color: #272822; - height: 100%; - padding: 16px; - display: flex; - flex-direction: column; + background-color: #272822; + height: 100%; + padding: 16px; + display: flex; + flex-direction: column; } .grid { - display: grid; - grid-gap: 1rem; - grid-template-columns: repeat(4, 1fr); - grid-auto-rows: 1fr; - padding-top: 32px; + display: grid; + grid-gap: 1rem; + grid-template-columns: repeat(4, 1fr); + grid-auto-rows: 1fr; + padding-top: 32px; } @media (max-width: 1200px) { - .grid { - grid-template-columns: repeat(3, 1fr); - } + .grid { + grid-template-columns: repeat(3, 1fr); + } } @media only screen and (max-width: 815px) { - .grid { - grid-template-columns: repeat(2, 1fr); - } + .grid { + grid-template-columns: repeat(2, 1fr); + } } .PluginCard img { - float: left; - margin: 0px 16px 8px 0px; - height: 100px; - width: 100px; + float: left; + margin: 0px 16px 8px 0px; + height: 80px; + width: 80px; } .PluginCardHeader { - max-height: fit-content; - min-height: fit-content; + max-height: fit-content; + min-height: fit-content; } .PluginCardTitle { - color: white; - vertical-align: top; - margin: 8px 0px 0px 16px; + color: white; + vertical-align: top; + margin: 8px 0px 0px 16px; } .PluginAddNewButton { - position: absolute; - bottom: 16px; - right: 0px; + position: absolute; + bottom: 16px; + right: 0px; } .ButtonFilled { - padding: 4px 8px; - border-radius: 4px; - background-color: #36BAA2; - color: white; - margin-top: 36px; + padding: 4px 8px; + border-radius: 4px; + background-color: #36baa2; + color: white; + margin-top: 36px; } .ButtonFilled:hover { - border: 1px solid #36BAA2; - background-color: transparent; + border: 1px solid #36baa2; + background-color: transparent; } .ChipOutlined { - font-size: small; - border-radius: 16px; - padding: 2px 8px; - border: 1px solid #36BAA2; - color: #36BAA2; + font-size: small; + border-radius: 16px; + padding: 2px 8px; + border: 1px solid #36baa2; + color: #36baa2; } .PluginCardLink { - padding: 2px 8px; - position: absolute; - bottom: 0; - right: 0; + padding: 2px 8px; + position: absolute; + bottom: 0; + right: 0; } .PluginPageLayout { - margin: auto; - max-width: 1430px; - padding: 20px; + margin: auto; + max-width: 1430px; + padding: 20px; } .PluginPageHeader { - position: relative; + position: relative; } .PluginPageHeader h2 { - display: inline-block; + display: inline-block; } .PluginCardBody { - padding-top: 8px; + padding-top: 8px; } .PluginCardFooter { - position: relative; - min-height: 2em; + position: relative; + min-height: 2em; } -.Author, .Author a { - margin-bottom: 0.25em; - color: rgba(255,255,255, 0.6); +.Author, +.Author a { + margin-bottom: 0.25em; + color: rgba(255, 255, 255, 0.6); } - .Author a:hover { - color: white; +.Author a:hover { + color: white; } From 379e5186bd7cebf60b7c72d15aed333325090fb4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Sep 2020 14:42:19 +0200 Subject: [PATCH 35/56] cli: set NODE_ENV to test when running tests if not already set --- packages/cli/src/commands/testCommand.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/cli/src/commands/testCommand.ts b/packages/cli/src/commands/testCommand.ts index 9969aee3b4..2c3f9fe895 100644 --- a/packages/cli/src/commands/testCommand.ts +++ b/packages/cli/src/commands/testCommand.ts @@ -57,6 +57,12 @@ export default async (cmd: Command) => { } } + // This is the only thing that is not implemented by jest.run(), so we do it here instead + // https://github.com/facebook/jest/blob/cd8828f7bbec6e55b4df5e41e853a5133c4a3ee1/packages/jest-cli/bin/jest.js#L12 + if (!process.env.NODE_ENV) { + (process.env as any).NODE_ENV = 'test'; + } + // eslint-disable-next-line jest/no-jest-import await require('jest').run(args); }; From f234f17853b5421bfb77b7b11d3950d523fae8f0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 31 Aug 2020 16:44:36 +0200 Subject: [PATCH 36/56] cli: fix version management in create-app --- packages/cli/src/commands/create-plugin/createPlugin.ts | 7 ++++++- packages/cli/src/commands/plugin/diff.ts | 5 ++++- packages/cli/templates/default-plugin/package.json.hbs | 8 ++++---- .../templates/default-app/{lerna.json.hbs => lerna.json} | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) rename packages/create-app/templates/default-app/{lerna.json.hbs => lerna.json} (77%) diff --git a/packages/cli/src/commands/create-plugin/createPlugin.ts b/packages/cli/src/commands/create-plugin/createPlugin.ts index 47b883882b..5e6882a4a0 100644 --- a/packages/cli/src/commands/create-plugin/createPlugin.ts +++ b/packages/cli/src/commands/create-plugin/createPlugin.ts @@ -28,6 +28,7 @@ import { } from '../../lib/codeowners'; import { paths } from '../../lib/paths'; import { Task, templatingTask } from '../../lib/tasks'; +import { version as backstageVersion } from '../../lib/version'; const exec = promisify(execCb); @@ -239,7 +240,11 @@ export default async () => { await createTemporaryPluginFolder(tempDir); Task.section('Preparing files'); - await templatingTask(templateDir, tempDir, { ...answers, version }); + await templatingTask(templateDir, tempDir, { + ...answers, + version, + backstageVersion, + }); Task.section('Moving to final location'); await movePlugin(tempDir, pluginDir, answers.id); diff --git a/packages/cli/src/commands/plugin/diff.ts b/packages/cli/src/commands/plugin/diff.ts index 66db692ab4..99af093f2c 100644 --- a/packages/cli/src/commands/plugin/diff.ts +++ b/packages/cli/src/commands/plugin/diff.ts @@ -25,7 +25,7 @@ import { yesPromptFunc, } from '../../lib/diff'; import { paths } from '../../lib/paths'; -import { version } from '../../lib/version'; +import { version as backstageVersion } from '../../lib/version'; export type PluginData = { id: string; @@ -62,9 +62,12 @@ export default async (cmd: Command) => { promptFunc = yesPromptFunc; } + const { version } = await fs.readJson(paths.resolveTargetRoot('lerna.json')); + const data = await readPluginData(); const templateFiles = await diffTemplateFiles('default-plugin', { version, + backstageVersion, ...data, }); await handleAllFiles(fileHandlers, templateFiles, promptFunc); diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index 4e85bf39bd..38d4e41b5b 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^{{version}}", - "@backstage/theme": "^{{version}}", + "@backstage/core": "^{{backstageVersion}}", + "@backstage/theme": "^{{backstageVersion}}", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -31,8 +31,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^{{version}}", - "@backstage/dev-utils": "^{{version}}", + "@backstage/cli": "^{{backstageVersion}}", + "@backstage/dev-utils": "^{{backstageVersion}}", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/packages/create-app/templates/default-app/lerna.json.hbs b/packages/create-app/templates/default-app/lerna.json similarity index 77% rename from packages/create-app/templates/default-app/lerna.json.hbs rename to packages/create-app/templates/default-app/lerna.json index ba627eaf80..322929db1d 100644 --- a/packages/create-app/templates/default-app/lerna.json.hbs +++ b/packages/create-app/templates/default-app/lerna.json @@ -2,5 +2,5 @@ "packages": ["packages/*", "plugins/*"], "npmClient": "yarn", "useWorkspaces": true, - "version": "{{version}}" + "version": "0.1.0" } From eee4283c65274db86ee2a47b93f6fb4d9246671f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Sep 2020 17:32:37 +0200 Subject: [PATCH 37/56] catalog-backend: add Locations to the set of default allowed kinds --- .../features/software-catalog/configuration.md | 18 +++++++++--------- .../src/ingestion/CatalogRules.test.ts | 17 ++++++++++++++++- .../src/ingestion/CatalogRules.ts | 2 +- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/docs/features/software-catalog/configuration.md b/docs/features/software-catalog/configuration.md index 44e998d5a9..be6314e494 100644 --- a/docs/features/software-catalog/configuration.md +++ b/docs/features/software-catalog/configuration.md @@ -23,16 +23,16 @@ configuration. ## Catalog Rules By default the catalog will only allow ingestion of entities with the kind -`Component` and `API`. In order to allow entities of other kinds to be added, -you need to add rules to the catalog. Rules are added either in a separate -`catalog.rules` key, or added to statically configured locations. +`Component`, `API` and `Location`. In order to allow entities of other kinds to +be added, you need to add rules to the catalog. Rules are added either in a +separate `catalog.rules` key, or added to statically configured locations. For example, given the following configuration: ```yaml catalog: rules: - - allow: [Component, API, Template] + - allow: [Component, API, Location, Template] locations: - type: github @@ -41,13 +41,13 @@ catalog: - allow: [Group] ``` -We are able to add entities of kind `Component`, `API`, or `Template` from any -location, and `Group` entities from the `org-data.yaml`, which will also be read -as statically configured location. +We are able to add entities of kind `Component`, `API`, `Location`, or +`Template` from any location, and `Group` entities from the `org-data.yaml`, +which will also be read as statically configured location. Note that if the `catalog.rules` key is present it will replace the default -value, meaning that you need to add rules for `Component` and `API` kinds if you -want those to be allowed. +value, meaning that you need to add rules for the default kinds if you want +those to still be allowed. The following configuration will reject any kind of entities from being added to the catalog: diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts index 794416786c..bb5c025c28 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.test.ts @@ -28,6 +28,9 @@ const entity = { component: { kind: 'component', } as Entity, + location: { + kind: 'Location', + } as Entity, }; const location: Record = { @@ -51,6 +54,7 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.location, location.z)).toBe(false); }); it('should deny all', () => { @@ -58,15 +62,21 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.location, location.z)).toBe(false); }); it('should allow all', () => { const enforcer = new CatalogRulesEnforcer([ - { allow: [{ kind: 'User' }, { kind: 'Group' }, { kind: 'Component' }] }, + { + allow: ['User', 'Group', 'Component', 'Location'].map(kind => ({ + kind, + })), + }, ]); expect(enforcer.isAllowed(entity.user, location.x)).toBe(true); expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.location, location.z)).toBe(true); }); it('should deny groups', () => { @@ -121,6 +131,7 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.location, location.z)).toBe(true); }); it('should deny all', () => { @@ -130,6 +141,7 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.user, location.x)).toBe(false); expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.location, location.z)).toBe(false); }); it('should allow all', () => { @@ -156,6 +168,7 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); expect(enforcer.isAllowed(entity.group, location.z)).toBe(false); expect(enforcer.isAllowed(entity.component, location.z)).toBe(true); + expect(enforcer.isAllowed(entity.location, location.z)).toBe(false); }); it('should allow groups from a specific github location', () => { @@ -182,6 +195,7 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.group, location.y)).toBe(false); expect(enforcer.isAllowed(entity.group, location.z)).toBe(false); expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.location, location.z)).toBe(false); }); it('should not care about location configuration in catalog.rules', () => { @@ -197,6 +211,7 @@ describe('CatalogRulesEnforcer', () => { expect(enforcer.isAllowed(entity.group, location.y)).toBe(true); expect(enforcer.isAllowed(entity.group, location.z)).toBe(true); expect(enforcer.isAllowed(entity.component, location.z)).toBe(false); + expect(enforcer.isAllowed(entity.location, location.z)).toBe(false); }); }); }); diff --git a/plugins/catalog-backend/src/ingestion/CatalogRules.ts b/plugins/catalog-backend/src/ingestion/CatalogRules.ts index 2b55ebef32..e964524bc7 100644 --- a/plugins/catalog-backend/src/ingestion/CatalogRules.ts +++ b/plugins/catalog-backend/src/ingestion/CatalogRules.ts @@ -50,7 +50,7 @@ export class CatalogRulesEnforcer { */ static readonly defaultRules: CatalogRule[] = [ { - allow: [{ kind: 'Component' }, { kind: 'API' }], + allow: ['Component', 'API', 'Location'].map(kind => ({ kind })), }, ]; From c8e77cfc45c69bae3b8dd91bb153b0654f44042c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Sep 2020 18:28:39 +0200 Subject: [PATCH 38/56] app: mark as bundled --- packages/app/package.json | 1 + .../templates/default-app/packages/app/package.json.hbs | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/app/package.json b/packages/app/package.json index d32808b48b..6d9595ad1b 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -2,6 +2,7 @@ "name": "example-app", "version": "0.1.1-alpha.20", "private": true, + "bundled": true, "dependencies": { "@backstage/cli": "^0.1.1-alpha.20", "@backstage/core": "^0.1.1-alpha.20", diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index 7d34a94c7b..ecdc8a7f96 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -2,6 +2,7 @@ "name": "app", "version": "0.0.0", "private": true, + "bundled": true, "dependencies": { "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", From c319de51a7373ae7d057465d41ff22c321aaa82b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Sep 2020 18:58:33 +0200 Subject: [PATCH 39/56] backend-common: add resolvePackagePath --- packages/backend-common/src/index.ts | 1 + packages/backend-common/src/paths.ts | 36 +++++++++++++++++++ plugins/app-backend/src/service/router.ts | 13 +++---- .../src/identity/DatabaseKeyStore.ts | 8 ++--- .../src/database/DatabaseManager.ts | 9 +++-- plugins/graphql/src/service/router.ts | 9 +++-- 6 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 packages/backend-common/src/paths.ts diff --git a/packages/backend-common/src/index.ts b/packages/backend-common/src/index.ts index f499613851..c527f5fea1 100644 --- a/packages/backend-common/src/index.ts +++ b/packages/backend-common/src/index.ts @@ -20,4 +20,5 @@ export * from './errors'; export * from './logging'; export * from './middleware'; export * from './service'; +export * from './paths'; export * from './hot'; diff --git a/packages/backend-common/src/paths.ts b/packages/backend-common/src/paths.ts new file mode 100644 index 0000000000..402c0e2252 --- /dev/null +++ b/packages/backend-common/src/paths.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* eslint-disable @typescript-eslint/camelcase */ + +import { resolve as resolvePath } from 'path'; + +/** + * Resolve a path relative to the root of a package directory. + * Additional path arguments are resolved relative to the package dir. + * + * This is particularly useful when you want to access assets shipped with + * your backend plugin package. When doing so, do not forget to include the assets + * in your published package by adding them to `files` in your `package.json`. + */ +export function resolvePackagePath(name: string, ...paths: string[]) { + const req = + typeof __non_webpack_require__ === 'undefined' + ? require + : __non_webpack_require__; + + return resolvePath(req.resolve(`${name}/package.json`), '..', ...paths); +} diff --git a/plugins/app-backend/src/service/router.ts b/plugins/app-backend/src/service/router.ts index ecc5b4fa4b..c9a06e4dda 100644 --- a/plugins/app-backend/src/service/router.ts +++ b/plugins/app-backend/src/service/router.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { resolve as resolvePath, dirname } from 'path'; -import { notFoundHandler } from '@backstage/backend-common'; +import { resolve as resolvePath } from 'path'; +import { notFoundHandler, resolvePackagePath } from '@backstage/backend-common'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; @@ -23,19 +23,14 @@ import { injectEnvConfig } from '../lib/config'; export interface RouterOptions { logger: Logger; - appPackageName?: string; + appPackageName: string; staticFallbackHandler?: express.Handler; } export async function createRouter( options: RouterOptions, ): Promise { - const appDistDir = resolvePath( - dirname( - __non_webpack_require__.resolve(`${options.appPackageName}/package.json`), - ), - 'dist', - ); + const appDistDir = resolvePackagePath(options.appPackageName, 'dist'); options.logger.info(`Serving static app content from ${appDistDir}`); await injectEnvConfig({ diff --git a/plugins/auth-backend/src/identity/DatabaseKeyStore.ts b/plugins/auth-backend/src/identity/DatabaseKeyStore.ts index c175cd6e12..c24cac55be 100644 --- a/plugins/auth-backend/src/identity/DatabaseKeyStore.ts +++ b/plugins/auth-backend/src/identity/DatabaseKeyStore.ts @@ -15,13 +15,13 @@ */ import Knex from 'knex'; -import path from 'path'; import { utc } from 'moment'; +import { resolvePackagePath } from '@backstage/backend-common'; import { AnyJWK, KeyStore, StoredKey } from './types'; -const migrationsDir = path.resolve( - require.resolve('@backstage/plugin-auth-backend/package.json'), - '../migrations', +const migrationsDir = resolvePackagePath( + '@backstage/plugin-auth-backend', + 'migrations', ); const TABLE = 'signing_keys'; diff --git a/plugins/catalog-backend/src/database/DatabaseManager.ts b/plugins/catalog-backend/src/database/DatabaseManager.ts index 28751f4830..ce91cc737f 100644 --- a/plugins/catalog-backend/src/database/DatabaseManager.ts +++ b/plugins/catalog-backend/src/database/DatabaseManager.ts @@ -14,17 +14,16 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; +import { getVoidLogger, resolvePackagePath } from '@backstage/backend-common'; import { makeValidator } from '@backstage/catalog-model'; import Knex from 'knex'; -import path from 'path'; import { Logger } from 'winston'; import { CommonDatabase } from './CommonDatabase'; import { Database } from './types'; -const migrationsDir = path.resolve( - require.resolve('@backstage/plugin-catalog-backend/package.json'), - '../migrations', +const migrationsDir = resolvePackagePath( + '@backstage/plugin-catalog-backend', + 'migrations', ); export type CreateDatabaseOptions = { diff --git a/plugins/graphql/src/service/router.ts b/plugins/graphql/src/service/router.ts index 0b91d7307a..df5185c1b1 100644 --- a/plugins/graphql/src/service/router.ts +++ b/plugins/graphql/src/service/router.ts @@ -14,17 +14,16 @@ * limitations under the License. */ -import { errorHandler } from '@backstage/backend-common'; +import { errorHandler, resolvePackagePath } from '@backstage/backend-common'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; import fs from 'fs'; -import path from 'path'; import { ApolloServer } from 'apollo-server-express'; -const schemaPath = path.resolve( - require.resolve('@backstage/plugin-graphql-backend/package.json'), - '../schema.gql', +const schemaPath = resolvePackagePath( + '@backstage/plugin-graphql-backend', + 'schema.gql', ); export interface RouterOptions { From 39b087bd0e6728260a545c47b2e804dd5cfeb752 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Sep 2020 19:51:02 +0200 Subject: [PATCH 40/56] cli: remove dependencies from bundled packages to avoid install --- packages/cli/src/lib/packager/index.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/cli/src/lib/packager/index.ts b/packages/cli/src/lib/packager/index.ts index d65d1af304..fda85dd68a 100644 --- a/packages/cli/src/lib/packager/index.ts +++ b/packages/cli/src/lib/packager/index.ts @@ -26,6 +26,7 @@ type LernaPackage = { private: boolean; location: string; scripts: Record; + get(key: string): any; }; type FileEntry = @@ -107,6 +108,26 @@ async function moveToDistWorkspace( strip: 1, }); await fs.remove(archivePath); + + // We remove the dependencies from package.json of packages that are marked + // as bundled, so that yarn doesn't try to install them. + if (target.get('bundled')) { + const pkgJson = await fs.readJson( + resolvePath(absoluteOutputPath, 'package.json'), + ); + delete pkgJson.dependencies; + delete pkgJson.devDependencies; + delete pkgJson.peerDependencies; + delete pkgJson.optionalDependencies; + + await fs.writeJson( + resolvePath(absoluteOutputPath, 'package.json'), + pkgJson, + { + spaces: 2, + }, + ); + } }), ); } From 8e94bffbcc9f2f962782c9ea507f96982f36eb77 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Sep 2020 19:56:16 +0200 Subject: [PATCH 41/56] cli: mark all monorepo packages as external, instead of @backstage ones --- packages/cli/src/lib/bundler/backend.ts | 2 +- packages/cli/src/lib/bundler/config.ts | 23 +++++++++++++++-------- packages/cli/src/lib/bundler/paths.ts | 1 - 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/lib/bundler/backend.ts b/packages/cli/src/lib/bundler/backend.ts index f5f233854f..e3cc8af8d1 100644 --- a/packages/cli/src/lib/bundler/backend.ts +++ b/packages/cli/src/lib/bundler/backend.ts @@ -25,7 +25,7 @@ export async function serveBackend( }, ) { const paths = resolveBundlingPaths(options); - const config = createBackendConfig(paths, { + const config = await createBackendConfig(paths, { ...options, isDev: true, }); diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 61f4448dd9..118cb1b40c 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -15,6 +15,7 @@ */ import fs from 'fs-extra'; +import { resolve as resolvePath } from 'path'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; @@ -171,14 +172,23 @@ export async function createConfig( }; } -export function createBackendConfig( +export async function createBackendConfig( paths: BundlingPaths, options: BackendBundlingOptions, -): webpack.Configuration { +): Promise { const { checksEnabled, isDev } = options; const { loaders } = transforms(options); + // Find all local monorepo packages and their node_modules, and mark them as external. + const LernaProject = require('@lerna/project'); + const project = new LernaProject(cliPaths.targetDir); + const packages = await project.getPackages(); + const localPackageNames = packages.map((p: any) => p.name); + const moduleDirs = packages.map((p: any) => + resolvePath(p.location, 'node_modules'), + ); + return { mode: isDev ? 'development' : 'production', profile: false, @@ -193,11 +203,8 @@ export function createBackendConfig( externals: [ nodeExternals({ modulesDir: paths.rootNodeModules, - allowlist: ['webpack/hot/poll?100', /\@backstage\/.*/], - }), - nodeExternals({ - modulesDir: paths.targetNodeModules, - allowlist: ['webpack/hot/poll?100', /\@backstage\/.*/], + additionalModuleDirs: moduleDirs, + allowlist: ['webpack/hot/poll?100', ...localPackageNames], }), ], target: 'node' as const, @@ -219,7 +226,7 @@ export function createBackendConfig( resolve: { extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'], mainFields: ['browser', 'module', 'main'], - modules: [paths.targetNodeModules, paths.rootNodeModules], + modules: [paths.rootNodeModules, ...moduleDirs], plugins: [ new ModuleScopePlugin( [paths.targetSrc, paths.targetDev], diff --git a/packages/cli/src/lib/bundler/paths.ts b/packages/cli/src/lib/bundler/paths.ts index 70e82d8d48..390e41a345 100644 --- a/packages/cli/src/lib/bundler/paths.ts +++ b/packages/cli/src/lib/bundler/paths.ts @@ -63,7 +63,6 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) { targetDev: paths.resolveTarget('dev'), targetEntry: resolveTargetModule(entry), targetTsConfig: paths.resolveTargetRoot('tsconfig.json'), - targetNodeModules: paths.resolveTarget('node_modules'), targetPackageJson: paths.resolveTarget('package.json'), rootNodeModules: paths.resolveTargetRoot('node_modules'), root: paths.targetRoot, From 86124cc9e362b951d69262484a824e8288da0cae Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2020 07:49:28 +0200 Subject: [PATCH 42/56] chore(deps-dev): bump @types/helmet from 0.0.47 to 0.0.48 (#2230) Bumps [@types/helmet](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/helmet) from 0.0.47 to 0.0.48. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/helmet) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- packages/backend/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 7393ede81e..a2a9e41a92 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -46,6 +46,6 @@ "@types/dockerode": "^2.5.32", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", - "@types/helmet": "^0.0.47" + "@types/helmet": "^0.0.48" } } diff --git a/yarn.lock b/yarn.lock index 84e4c4cbb4..1553a3e006 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4264,10 +4264,10 @@ "@types/koa" "*" graphql "^14.5.3" -"@types/helmet@^0.0.47": - version "0.0.47" - resolved "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz#ec5161541b649142205b7c558bca14801c5ce129" - integrity sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg== +"@types/helmet@^0.0.48": + version "0.0.48" + resolved "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.48.tgz#e754399d2f4672ba63962e8490efd3edd31d9799" + integrity sha512-C7MpnvSDrunS1q2Oy1VWCY7CDWHozqSnM8P4tFeRTuzwqni+PYOjEredwcqWG+kLpYcgLsgcY3orHB54gbx2Jw== dependencies: "@types/express" "*" From b3c4f0c85bc47a44d7724f519c3cd247b91b15f2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2020 07:49:55 +0200 Subject: [PATCH 43/56] chore(deps-dev): bump @testing-library/cypress from 6.0.0 to 6.0.1 (#2229) Bumps [@testing-library/cypress](https://github.com/kentcdodds/cypress-testing-library) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/kentcdodds/cypress-testing-library/releases) - [Changelog](https://github.com/testing-library/cypress-testing-library/blob/master/CHANGELOG.md) - [Commits](https://github.com/kentcdodds/cypress-testing-library/compare/v6.0.0...v6.0.1) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- yarn.lock | 115 +++++++++++++++++++++++++++--------------------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1553a3e006..1853507e63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1056,7 +1056,7 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.11.2" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== @@ -1677,15 +1677,6 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/types@^24.9.0": - version "24.9.0" - resolved "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^13.0.0" - "@jest/types@^25.5.0": version "25.5.0" resolved "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" @@ -1706,6 +1697,17 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jest/types@^26.3.0": + version "26.3.0" + resolved "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz#97627bf4bdb72c55346eef98e3b3f7ddc4941f71" + integrity sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + "@jsdevtools/ono@^7.1.3": version "7.1.3" resolved "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" @@ -3853,23 +3855,24 @@ defer-to-connect "^2.0.0" "@testing-library/cypress@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@testing-library/cypress/-/cypress-6.0.0.tgz#935f7716e0e495f02fd753a42621e4d350097dce" - integrity sha512-vWPQtPsIDk5STOH2XdJbJoYq9gxOSAItP0ail+MlylK230zNkf3ODKd6eqWnDdruuqrhTF3CyqvPNMA8Xks/UQ== + version "6.0.1" + resolved "https://registry.npmjs.org/@testing-library/cypress/-/cypress-6.0.1.tgz#c924a69617db6a403c498abcb63759b79318fc76" + integrity sha512-hcPu2OnVuSTX1yDubEe7TBRD6mP2VgyopP1WTBIrJP79INPZdgOAX+TMNH68uZ/r5b4C7100IB4hjPIEQ+/Xog== dependencies: - "@babel/runtime" "^7.8.7" - "@testing-library/dom" "^7.0.2" - "@types/testing-library__cypress" "^5.0.3" + "@babel/runtime" "^7.11.2" + "@testing-library/dom" "^7.22.2" + "@types/testing-library__cypress" "^5.0.6" -"@testing-library/dom@^7.0.2", "@testing-library/dom@^7.17.1": - version "7.17.2" - resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-7.17.2.tgz#d062e41336b885107bca8ffc7022eaf37cccaee1" - integrity sha512-TQAoIzoI9g64oNVJ+13i4cCh/DQp/n7fJOyMqlFB1oQVusPtSgiPImyb52CwtvPO7J0Im0+/4YcmxU9a+cVxxw== +"@testing-library/dom@^7.11.0", "@testing-library/dom@^7.17.1", "@testing-library/dom@^7.22.2": + version "7.23.0" + resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-7.23.0.tgz#c54c0fa53705ad867bcefb52fc0c96487fbc10f6" + integrity sha512-H5m090auYH+obdZmsaYLrSWC5OauWD2CvNbz88KBxQJoXgkJzbU0DpAG8BS7Evj5WqCC3nAAKrLS6vw0ljUYLg== dependencies: "@babel/runtime" "^7.10.3" + "@types/aria-query" "^4.2.0" aria-query "^4.2.2" - dom-accessibility-api "^0.4.5" - pretty-format "^25.5.0" + dom-accessibility-api "^0.5.1" + pretty-format "^26.4.2" "@testing-library/jest-dom@^5.10.1": version "5.10.1" @@ -3976,6 +3979,11 @@ resolved "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/aria-query@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" + integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A== + "@types/babel__core@^7.1.7": version "7.1.7" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89" @@ -4363,6 +4371,13 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/istanbul-reports@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" + integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== + dependencies: + "@types/istanbul-lib-report" "*" + "@types/jest@*", "@types/jest@^26.0.7": version "26.0.9" resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.9.tgz#0543b57da5f0cd949c5f423a00c56c492289c989" @@ -4848,21 +4863,14 @@ dependencies: "@types/estree" "*" -"@types/testing-library__cypress@^5.0.3": - version "5.0.3" - resolved "https://registry.npmjs.org/@types/testing-library__cypress/-/testing-library__cypress-5.0.3.tgz#94969b7c1eea96e09d8e023a1d225590fa75a1fe" - integrity sha512-efMwaVnsWEBDz0Ikm84Kh/oiUxMfz5LQtWx/Y6s2Bj0KkQ6+569/101X3Gz2bJy+otaXWPzOUOwDeAfzOJWoeQ== +"@types/testing-library__cypress@^5.0.6": + version "5.0.6" + resolved "https://registry.npmjs.org/@types/testing-library__cypress/-/testing-library__cypress-5.0.6.tgz#9015f575c1a98f05996a4fe769071134ee488c26" + integrity sha512-TUp5wfanU7zUZigKqIeQDChnHQ1MEzbYqrI5iCQMFiesWNOASWm/el1lFBh1JPqmd6GkdDdDiHYJnkqd9le2ww== dependencies: - "@types/testing-library__dom" "*" + "@testing-library/dom" "^7.11.0" cypress "*" -"@types/testing-library__dom@*": - version "6.14.0" - resolved "https://registry.npmjs.org/@types/testing-library__dom/-/testing-library__dom-6.14.0.tgz#1aede831cb4ed4a398448df5a2c54b54a365644e" - integrity sha512-sMl7OSv0AvMOqn1UJ6j1unPMIHRXen0Ita1ujnMX912rrOcawe4f7wu0Zt9GIQhBhJvH2BaibqFgQ3lP+Pj2hA== - dependencies: - pretty-format "^24.3.0" - "@types/testing-library__jest-dom@^5.9.1": version "5.9.1" resolved "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.1.tgz#aba5ee062b7880f69c212ef769389f30752806e5" @@ -4971,13 +4979,6 @@ resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== -"@types/yargs@^13.0.0": - version "13.0.8" - resolved "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.8.tgz#a38c22def2f1c2068f8971acb3ea734eb3c64a99" - integrity sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^15.0.0": version "15.0.4" resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299" @@ -5451,7 +5452,7 @@ ansi-regex@^3.0.0: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= -ansi-regex@^4.0.0, ansi-regex@^4.1.0: +ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== @@ -9149,10 +9150,10 @@ docusaurus@^2.0.0-alpha.61: tree-node-cli "^1.2.5" truncate-html "^1.0.3" -dom-accessibility-api@^0.4.5: - version "0.4.5" - resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.4.5.tgz#d9c1cefa89f509d8cf132ab5d250004d755e76e3" - integrity sha512-HcPDilI95nKztbVikaN2vzwvmv0sE8Y2ZJFODy/m15n7mGXLeOKGiys9qWVbFbh+aq/KYj2lqMLybBOkYAEXqg== +dom-accessibility-api@^0.5.1: + version "0.5.2" + resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.2.tgz#ef3cdb5d3f0d599d8f9c8b18df2fb63c9793739d" + integrity sha512-k7hRNKAiPJXD2aBqfahSo4/01cTsKWXf+LqJgglnkN2Nz8TsxXKQBXHhKe0Ye9fEfHEZY49uSA5Sr3AqP/sWKA== dom-converter@^0.2: version "0.2.0" @@ -17806,16 +17807,6 @@ pretty-error@^2.1.1: renderkid "^2.0.1" utila "~0.4" -pretty-format@^24.3.0: - version "24.9.0" - resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - pretty-format@^25.1.0, pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" @@ -17836,6 +17827,16 @@ pretty-format@^26.0.1: ansi-styles "^4.0.0" react-is "^16.12.0" +pretty-format@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz#d081d032b398e801e2012af2df1214ef75a81237" + integrity sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA== + dependencies: + "@jest/types" "^26.3.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + pretty-hrtime@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -18543,7 +18544,7 @@ react-inspector@^4.0.0: is-dom "^1.0.9" prop-types "^15.6.1" -react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: +react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.6, react-is@^16.9.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== From e9527a7796dce17c2600eb61d716f9adc6dca580 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2020 07:50:19 +0200 Subject: [PATCH 44/56] chore(deps): bump rollup-plugin-postcss from 3.1.1 to 3.1.8 (#2231) Bumps [rollup-plugin-postcss](https://github.com/egoist/rollup-plugin-postcss) from 3.1.1 to 3.1.8. - [Release notes](https://github.com/egoist/rollup-plugin-postcss/releases) - [Changelog](https://github.com/egoist/rollup-plugin-postcss/blob/master/CHANGELOG-OLD.md) - [Commits](https://github.com/egoist/rollup-plugin-postcss/compare/v3.1.1...v3.1.8) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1853507e63..3301f94f83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19513,9 +19513,9 @@ rollup-plugin-peer-deps-external@^2.2.2: integrity sha512-W6IePXTExGXVDAlfZbNUUrx3GxUOZP248u5n4a4ID1XZMrbQ+uGeNiEfapvdzwx0qZi5DNH/hDLiPUP+pzFIxg== rollup-plugin-postcss@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-3.1.1.tgz#eb895bd919285aaf6200324071103b4d3ea68607" - integrity sha512-4/FO5/2O5kv2uWRd7PPTN4mBCWoHwwFTnpEGokfPKfj6kygvTORqkBWNgVPXi7bBefNKtMA3FqQ10se6/J8kKw== + version "3.1.8" + resolved "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-3.1.8.tgz#d1bcaf8eb0fcb0936e3684c22dd8628d13a82fd1" + integrity sha512-JHnGfW8quNc6ePxEkZ05HEZ1YiRxDgY9RKEetMfsrwxR2kh/d90OVScTc6b1c2Q17Cs/5TRYL+1uddG21lQe3w== dependencies: chalk "^4.0.0" concat-with-sourcemaps "^1.1.0" From ab7d6e89a8f2614dfb595283f041bb6a23cec1fb Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Wed, 2 Sep 2020 07:52:12 +0200 Subject: [PATCH 45/56] Add "Example Plugin" to Storybook (#2212) * Add Page Story as Plugin Example * Change settings button to primary and clean up code * Simplfiy content header and remove unnecessary styling --- .../core/src/layout/Page/Page.stories.tsx | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 packages/core/src/layout/Page/Page.stories.tsx diff --git a/packages/core/src/layout/Page/Page.stories.tsx b/packages/core/src/layout/Page/Page.stories.tsx new file mode 100644 index 0000000000..786b4740fd --- /dev/null +++ b/packages/core/src/layout/Page/Page.stories.tsx @@ -0,0 +1,114 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { + Header, + Page, + HeaderLabel, + ContentHeader, + Content, + pageTheme, +} from '../'; +import { SupportButton, Table, StatusOK, TableColumn } from '../../components'; +import { Box, Typography, Link, Chip, Button } from '@material-ui/core'; + +export default { + title: 'Example Plugin', + component: Page, +}; + +interface TableData { + id: number; + branch: string; + hash: string; + status: string; +} + +const generateTestData = (rows = 10) => { + const data: Array = []; + while (data.length <= rows) { + data.push({ + id: data.length + 18534, + branch: 'techdocs: modify documentation header', + hash: 'techdocs/docs-header 5749c98e3f61f8bb116e5cb87b0e4e1 ', + status: 'Success', + }); + } + return data; +}; + +const columns: TableColumn[] = [ + { + title: 'ID', + field: 'id', + highlight: true, + type: 'numeric', + width: '80px', + }, + { + title: 'Message/Source', + highlight: true, + render: (row: Partial) => ( + <> + {row.branch} + {row.hash} + + ), + }, + { + title: 'Status', + render: (row: Partial) => ( + + + {row.status} + + ), + }, + { + title: 'Tags', + render: () => , + width: '10%', + }, +]; + +export const PluginWithTable = () => { + return ( + +
+ + +
+ + + + + This Plugin is an example. This text could provide usefull + information for the user. + + + + + + ); +}; From 7f4064975141b1b61a3d1800f3171f2350cac24f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 2 Sep 2020 05:55:52 +0000 Subject: [PATCH 46/56] chore(deps): bump jest from 26.0.1 to 26.4.2 Bumps [jest](https://github.com/facebook/jest) from 26.0.1 to 26.4.2. - [Release notes](https://github.com/facebook/jest/releases) - [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md) - [Commits](https://github.com/facebook/jest/compare/v26.0.1...v26.4.2) Signed-off-by: dependabot-preview[bot] --- yarn.lock | 776 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 406 insertions(+), 370 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3301f94f83..bea32a92aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -536,6 +536,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" @@ -1521,156 +1528,160 @@ resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@jest/console@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/console/-/console-26.0.1.tgz#62b3b2fa8990f3cbffbef695c42ae9ddbc8f4b39" - integrity sha512-9t1KUe/93coV1rBSxMmBAOIK3/HVpwxArCA1CxskKyRiv6o8J70V8C/V3OJminVCTa2M0hQI9AWRd5wxu2dAHw== +"@jest/console@^26.3.0": + version "26.3.0" + resolved "https://registry.npmjs.org/@jest/console/-/console-26.3.0.tgz#ed04063efb280c88ba87388b6f16427c0a85c856" + integrity sha512-/5Pn6sJev0nPUcAdpJHMVIsA8sKizL2ZkcKPE5+dJrCccks7tcM7c9wbgHudBJbxXLoTbqsHkG1Dofoem4F09w== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" + "@types/node" "*" chalk "^4.0.0" - jest-message-util "^26.0.1" - jest-util "^26.0.1" + jest-message-util "^26.3.0" + jest-util "^26.3.0" slash "^3.0.0" -"@jest/core@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/core/-/core-26.0.1.tgz#aa538d52497dfab56735efb00e506be83d841fae" - integrity sha512-Xq3eqYnxsG9SjDC+WLeIgf7/8KU6rddBxH+SCt18gEpOhAGYC/Mq+YbtlNcIdwjnnT+wDseXSbU0e5X84Y4jTQ== +"@jest/core@^26.4.2": + version "26.4.2" + resolved "https://registry.npmjs.org/@jest/core/-/core-26.4.2.tgz#85d0894f31ac29b5bab07aa86806d03dd3d33edc" + integrity sha512-sDva7YkeNprxJfepOctzS8cAk9TOekldh+5FhVuXS40+94SHbiicRO1VV2tSoRtgIo+POs/Cdyf8p76vPTd6dg== dependencies: - "@jest/console" "^26.0.1" - "@jest/reporters" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.3.0" + "@jest/reporters" "^26.4.1" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" - jest-changed-files "^26.0.1" - jest-config "^26.0.1" - jest-haste-map "^26.0.1" - jest-message-util "^26.0.1" + jest-changed-files "^26.3.0" + jest-config "^26.4.2" + jest-haste-map "^26.3.0" + jest-message-util "^26.3.0" jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-resolve-dependencies "^26.0.1" - jest-runner "^26.0.1" - jest-runtime "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" - jest-watcher "^26.0.1" + jest-resolve "^26.4.0" + jest-resolve-dependencies "^26.4.2" + jest-runner "^26.4.2" + jest-runtime "^26.4.2" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" + jest-watcher "^26.3.0" micromatch "^4.0.2" p-each-series "^2.1.0" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/environment/-/environment-26.0.1.tgz#82f519bba71959be9b483675ee89de8c8f72a5c8" - integrity sha512-xBDxPe8/nx251u0VJ2dFAFz2H23Y98qdIaNwnMK6dFQr05jc+Ne/2np73lOAx+5mSBO/yuQldRrQOf6hP1h92g== +"@jest/environment@^26.3.0": + version "26.3.0" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-26.3.0.tgz#e6953ab711ae3e44754a025f838bde1a7fd236a0" + integrity sha512-EW+MFEo0DGHahf83RAaiqQx688qpXgl99wdb8Fy67ybyzHwR1a58LHcO376xQJHfmoXTu89M09dH3J509cx2AA== dependencies: - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" -"@jest/fake-timers@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.0.1.tgz#f7aeff13b9f387e9d0cac9a8de3bba538d19d796" - integrity sha512-Oj/kCBnTKhm7CR+OJSjZty6N1bRDr9pgiYQr4wY221azLz5PHi08x/U+9+QpceAYOWheauLP8MhtSVFrqXQfhg== +"@jest/fake-timers@^26.3.0": + version "26.3.0" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.3.0.tgz#f515d4667a6770f60ae06ae050f4e001126c666a" + integrity sha512-ZL9ytUiRwVP8ujfRepffokBvD2KbxbqMhrXSBhSdAhISCw3gOkuntisiSFv+A6HN0n0fF4cxzICEKZENLmW+1A== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" "@sinonjs/fake-timers" "^6.0.1" - jest-message-util "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" + "@types/node" "*" + jest-message-util "^26.3.0" + jest-mock "^26.3.0" + jest-util "^26.3.0" -"@jest/globals@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/globals/-/globals-26.0.1.tgz#3f67b508a7ce62b6e6efc536f3d18ec9deb19a9c" - integrity sha512-iuucxOYB7BRCvT+TYBzUqUNuxFX1hqaR6G6IcGgEqkJ5x4htNKo1r7jk1ji9Zj8ZMiMw0oB5NaA7k5Tx6MVssA== +"@jest/globals@^26.4.2": + version "26.4.2" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-26.4.2.tgz#73c2a862ac691d998889a241beb3dc9cada40d4a" + integrity sha512-Ot5ouAlehhHLRhc+sDz2/9bmNv9p5ZWZ9LE1pXGGTCXBasmi5jnYjlgYcYt03FBwLmZXCZ7GrL29c33/XRQiow== dependencies: - "@jest/environment" "^26.0.1" - "@jest/types" "^26.0.1" - expect "^26.0.1" + "@jest/environment" "^26.3.0" + "@jest/types" "^26.3.0" + expect "^26.4.2" -"@jest/reporters@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-26.0.1.tgz#14ae00e7a93e498cec35b0c00ab21c375d9b078f" - integrity sha512-NWWy9KwRtE1iyG/m7huiFVF9YsYv/e+mbflKRV84WDoJfBqUrNRyDbL/vFxQcYLl8IRqI4P3MgPn386x76Gf2g== +"@jest/reporters@^26.4.1": + version "26.4.1" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-26.4.1.tgz#3b4d6faf28650f3965f8b97bc3d114077fb71795" + integrity sha512-aROTkCLU8++yiRGVxLsuDmZsQEKO6LprlrxtAuzvtpbIFl3eIjgIf3EUxDKgomkS25R9ZzwGEdB5weCcBZlrpQ== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.2" graceful-fs "^4.2.4" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^4.0.3" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.0.2" - jest-haste-map "^26.0.1" - jest-resolve "^26.0.1" - jest-util "^26.0.1" - jest-worker "^26.0.0" + jest-haste-map "^26.3.0" + jest-resolve "^26.4.0" + jest-util "^26.3.0" + jest-worker "^26.3.0" slash "^3.0.0" source-map "^0.6.0" string-length "^4.0.1" terminal-link "^2.0.0" - v8-to-istanbul "^4.1.3" + v8-to-istanbul "^5.0.1" optionalDependencies: - node-notifier "^7.0.0" + node-notifier "^8.0.0" -"@jest/source-map@^26.0.0": - version "26.0.0" - resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.0.0.tgz#fd7706484a7d3faf7792ae29783933bbf48a4749" - integrity sha512-S2Z+Aj/7KOSU2TfW0dyzBze7xr95bkm5YXNUqqCek+HE0VbNNSNzrRwfIi5lf7wvzDTSS0/ib8XQ1krFNyYgbQ== +"@jest/source-map@^26.3.0": + version "26.3.0" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.3.0.tgz#0e646e519883c14c551f7b5ae4ff5f1bfe4fc3d9" + integrity sha512-hWX5IHmMDWe1kyrKl7IhFwqOuAreIwHhbe44+XH2ZRHjrKIh0LO5eLQ/vxHFeAfRwJapmxuqlGAEYLadDq6ZGQ== dependencies: callsites "^3.0.0" graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/test-result@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-26.0.1.tgz#1ffdc1ba4bc289919e54b9414b74c9c2f7b2b718" - integrity sha512-oKwHvOI73ICSYRPe8WwyYPTtiuOAkLSbY8/MfWF3qDEd/sa8EDyZzin3BaXTqufir/O/Gzea4E8Zl14XU4Mlyg== +"@jest/test-result@^26.3.0": + version "26.3.0" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-26.3.0.tgz#46cde01fa10c0aaeb7431bf71e4a20d885bc7fdb" + integrity sha512-a8rbLqzW/q7HWheFVMtghXV79Xk+GWwOK1FrtimpI5n1la2SY0qHri3/b0/1F0Ve0/yJmV8pEhxDfVwiUBGtgg== dependencies: - "@jest/console" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.3.0" + "@jest/types" "^26.3.0" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.0.1.tgz#b0563424728f3fe9e75d1442b9ae4c11da73f090" - integrity sha512-ssga8XlwfP8YjbDcmVhwNlrmblddMfgUeAkWIXts1V22equp2GMIHxm7cyeD5Q/B0ZgKPK/tngt45sH99yLLGg== +"@jest/test-sequencer@^26.4.2": + version "26.4.2" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.4.2.tgz#58a3760a61eec758a2ce6080201424580d97cbba" + integrity sha512-83DRD8N3M0tOhz9h0bn6Kl6dSp+US6DazuVF8J9m21WAp5x7CqSMaNycMP0aemC/SH/pDQQddbsfHRTBXVUgog== dependencies: - "@jest/test-result" "^26.0.1" + "@jest/test-result" "^26.3.0" graceful-fs "^4.2.4" - jest-haste-map "^26.0.1" - jest-runner "^26.0.1" - jest-runtime "^26.0.1" + jest-haste-map "^26.3.0" + jest-runner "^26.4.2" + jest-runtime "^26.4.2" -"@jest/transform@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.0.1.tgz#0e3ecbb34a11cd4b2080ed0a9c4856cf0ceb0639" - integrity sha512-pPRkVkAQ91drKGbzCfDOoHN838+FSbYaEAvBXvKuWeeRRUD8FjwXkqfUNUZL6Ke48aA/1cqq/Ni7kVMCoqagWA== +"@jest/transform@^26.3.0": + version "26.3.0" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.3.0.tgz#c393e0e01459da8a8bfc6d2a7c2ece1a13e8ba55" + integrity sha512-Isj6NB68QorGoFWvcOjlUhpkT56PqNIsXKR7XfvoDlCANn/IANlh8DrKAA2l2JKC3yWSMH5wS0GwuQM20w3b2A== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" babel-plugin-istanbul "^6.0.0" chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.2.4" - jest-haste-map "^26.0.1" + jest-haste-map "^26.3.0" jest-regex-util "^26.0.0" - jest-util "^26.0.1" + jest-util "^26.3.0" micromatch "^4.0.2" pirates "^4.0.1" slash "^3.0.0" @@ -1687,16 +1698,6 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" -"@jest/types@^26.0.1": - version "26.0.1" - resolved "https://registry.npmjs.org/@jest/types/-/types-26.0.1.tgz#b78333fbd113fa7aec8d39de24f88de8686dac67" - integrity sha512-IbtjvqI9+eS1qFnOIEL7ggWmT+iK/U+Vde9cGWtYb/b6XgKb3X44ZAe/z9YZzoAAZ/E92m0DqrilF934IGNnQA== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - "@jest/types@^26.3.0": version "26.3.0" resolved "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz#97627bf4bdb72c55346eef98e3b3f7ddc4941f71" @@ -3984,6 +3985,17 @@ resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A== +"@types/babel__core@^7.0.0": + version "7.1.9" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.9.tgz#77e59d438522a6fb898fa43dc3455c6e72f3963d" + integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + "@types/babel__core@^7.1.7": version "7.1.7" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89" @@ -6088,16 +6100,16 @@ babel-helper-to-multiple-sequence-expressions@^0.5.0: resolved "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d" integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA== -babel-jest@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-26.0.1.tgz#450139ce4b6c17174b136425bda91885c397bc46" - integrity sha512-Z4GGmSNQ8pX3WS1O+6v3fo41YItJJZsVxG5gIQ+HuB/iuAQBJxMTHTwz292vuYws1LnHfwSRgoqI+nxdy/pcvw== +babel-jest@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-26.3.0.tgz#10d0ca4b529ca3e7d1417855ef7d7bd6fc0c3463" + integrity sha512-sxPnQGEyHAOPF8NcUsD0g7hDCnvLL2XyblRBcgrzTWBB/mAIpWow3n1bEL+VghnnZfreLhFSBsFluRoK2tRK4g== dependencies: - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" "@types/babel__core" "^7.1.7" babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.0.0" + babel-preset-jest "^26.3.0" chalk "^4.0.0" graceful-fs "^4.2.4" slash "^3.0.0" @@ -6141,13 +6153,14 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.0.0.tgz#fd1d35f95cf8849fc65cb01b5e58aedd710b34a8" - integrity sha512-+AuoehOrjt9irZL7DOt2+4ZaTM6dlu1s5TTS46JBa0/qem4dy7VNW3tMb96qeEqcIh20LD73TVNtmVEeymTG7w== +babel-plugin-jest-hoist@^26.2.0: + version "26.2.0" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.2.0.tgz#bdd0011df0d3d513e5e95f76bd53b51147aca2dd" + integrity sha512-B/hVMRv8Nh1sQ1a3EY8I0n4Y1Wty3NrR5ebOyVT302op+DOAau+xNEImGMsUWOC3++ZlMooCytKz+NgN8aKGbA== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.7.0: @@ -6313,14 +6326,15 @@ babel-plugin-transform-undefined-to-void@^6.9.4: resolved "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280" integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA= -babel-preset-current-node-syntax@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6" - integrity sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw== +babel-preset-current-node-syntax@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz#b4b547acddbf963cba555ba9f9cbbb70bfd044da" + integrity sha512-uyexu1sVwcdFnyq9o8UQYsXwXflIh8LvrF5+cKrYam93ned1CStffB3+BEcsxGSgagoA3GEyjDqO4a/58hyPYQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -6329,13 +6343,13 @@ babel-preset-current-node-syntax@^0.1.2: "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -babel-preset-jest@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.0.0.tgz#1eac82f513ad36c4db2e9263d7c485c825b1faa6" - integrity sha512-9ce+DatAa31DpR4Uir8g4Ahxs5K4W4L8refzt+qHWQANb6LhGcAEfIFgLUwk67oya2cCUd6t4eUMtO/z64ocNw== +babel-preset-jest@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.3.0.tgz#ed6344506225c065fd8a0b53e191986f74890776" + integrity sha512-5WPdf7nyYi2/eRxCbVrE1kKCWxgWY4RsPEbdJWFm7QsesFGqjdkyLeu1zRkwM1cxK6EPIlNd6d2AxLk7J+t4pw== dependencies: - babel-plugin-jest-hoist "^26.0.0" - babel-preset-current-node-syntax "^0.1.2" + babel-plugin-jest-hoist "^26.2.0" + babel-preset-current-node-syntax "^0.1.3" "babel-preset-minify@^0.5.0 || 0.6.0-alpha.5": version "0.5.1" @@ -8997,10 +9011,10 @@ diff-sequences@^25.2.6: resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== -diff-sequences@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6" - integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg== +diff-sequences@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.3.0.tgz#62a59b1b29ab7fd27cef2a33ae52abe73042d0a2" + integrity sha512-5j5vdRcw3CNctePNYN0Wy2e/JbWT6cAYnXv5OuqPhDpyCGc0uLu2TK0zOCJWNB9kOIfYMSpIulRaDgIi4HJ6Ig== diff@^4.0.1, diff@^4.0.2: version "4.0.2" @@ -9435,6 +9449,11 @@ emitter-component@^1.1.1: resolved "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6" integrity sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY= +emittery@^0.7.1: + version "0.7.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.7.1.tgz#c02375a927a40948c0345cc903072597f5270451" + integrity sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ== + "emoji-regex@>=6.0.0 <=6.1.1": version "6.1.1" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e" @@ -10163,16 +10182,16 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" -expect@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/expect/-/expect-26.0.1.tgz#18697b9611a7e2725e20ba3ceadda49bc9865421" - integrity sha512-QcCy4nygHeqmbw564YxNbHTJlXh47dVID2BUP52cZFpLU9zHViMFK6h07cC1wf7GYCTIigTdAXhVua8Yl1FkKg== +expect@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/expect/-/expect-26.4.2.tgz#36db120928a5a2d7d9736643032de32f24e1b2a1" + integrity sha512-IlJ3X52Z0lDHm7gjEp+m76uX46ldH5VpqmU0006vqDju/285twh7zaWMRhs67VpQhBwjjMchk+p5aA0VkERCAA== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" ansi-styles "^4.0.0" - jest-get-type "^26.0.0" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" jest-regex-util "^26.0.0" express-prom-bundle@^6.1.0: @@ -13173,6 +13192,13 @@ is-wsl@^2.1.1: resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + is-yarn-global@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" @@ -13249,6 +13275,16 @@ istanbul-lib-instrument@^4.0.0: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" +istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + istanbul-lib-report@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" @@ -13308,57 +13344,57 @@ jenkins@^0.28.0: dependencies: papi "^0.29.0" -jest-changed-files@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.0.1.tgz#1334630c6a1ad75784120f39c3aa9278e59f349f" - integrity sha512-q8LP9Sint17HaE2LjxQXL+oYWW/WeeXMPE2+Op9X3mY8IEGFVc14xRxFjUuXUbcPAlDLhtWdIEt59GdQbn76Hw== +jest-changed-files@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.3.0.tgz#68fb2a7eb125f50839dab1f5a17db3607fe195b1" + integrity sha512-1C4R4nijgPltX6fugKxM4oQ18zimS7LqQ+zTTY8lMCMFPrxqBFb7KJH0Z2fRQJvw2Slbaipsqq7s1mgX5Iot+g== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" execa "^4.0.0" throat "^5.0.0" -jest-cli@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-26.0.1.tgz#3a42399a4cbc96a519b99ad069a117d955570cac" - integrity sha512-pFLfSOBcbG9iOZWaMK4Een+tTxi/Wcm34geqZEqrst9cZDkTQ1LZ2CnBrTlHWuYAiTMFr0EQeK52ScyFU8wK+w== +jest-cli@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-26.4.2.tgz#24afc6e4dfc25cde4c7ec4226fb7db5f157c21da" + integrity sha512-zb+lGd/SfrPvoRSC/0LWdaWCnscXc1mGYW//NP4/tmBvRPT3VntZ2jtKUONsRi59zc5JqmsSajA9ewJKFYp8Cw== dependencies: - "@jest/core" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/core" "^26.4.2" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" is-ci "^2.0.0" - jest-config "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" + jest-config "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" prompts "^2.0.1" yargs "^15.3.1" -jest-config@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-config/-/jest-config-26.0.1.tgz#096a3d4150afadf719d1fab00e9a6fb2d6d67507" - integrity sha512-9mWKx2L1LFgOXlDsC4YSeavnblN6A4CPfXFiobq+YYLaBMymA/SczN7xYTSmLaEYHZOcB98UdoN4m5uNt6tztg== +jest-config@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-26.4.2.tgz#da0cbb7dc2c131ffe831f0f7f2a36256e6086558" + integrity sha512-QBf7YGLuToiM8PmTnJEdRxyYy3mHWLh24LJZKVdXZ2PNdizSe1B/E8bVm+HYcjbEzGuVXDv/di+EzdO/6Gq80A== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.0.1" - "@jest/types" "^26.0.1" - babel-jest "^26.0.1" + "@jest/test-sequencer" "^26.4.2" + "@jest/types" "^26.3.0" + babel-jest "^26.3.0" chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" - jest-environment-jsdom "^26.0.1" - jest-environment-node "^26.0.1" - jest-get-type "^26.0.0" - jest-jasmine2 "^26.0.1" + jest-environment-jsdom "^26.3.0" + jest-environment-node "^26.3.0" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.4.2" jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" + jest-resolve "^26.4.0" + jest-util "^26.3.0" + jest-validate "^26.4.2" micromatch "^4.0.2" - pretty-format "^26.0.1" + pretty-format "^26.4.2" jest-css-modules@^2.1.0: version "2.1.0" @@ -13377,15 +13413,15 @@ jest-diff@^25.1.0, jest-diff@^25.2.1: jest-get-type "^25.2.6" pretty-format "^25.5.0" -jest-diff@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.0.1.tgz#c44ab3cdd5977d466de69c46929e0e57f89aa1de" - integrity sha512-odTcHyl5X+U+QsczJmOjWw5tPvww+y9Yim5xzqxVl/R1j4z71+fHW4g8qu1ugMmKdFdxw+AtQgs5mupPnzcIBQ== +jest-diff@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.4.2.tgz#a1b7b303bcc534aabdb3bd4a7caf594ac059f5aa" + integrity sha512-6T1XQY8U28WH0Z5rGpQ+VqZSZz8EN8rZcBtfvXaOkbwxIEeRre6qnuZQlbY1AJ4MKDxQF8EkrCvK+hL/VkyYLQ== dependencies: chalk "^4.0.0" - diff-sequences "^26.0.0" - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + diff-sequences "^26.3.0" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" jest-docblock@^26.0.0: version "26.0.0" @@ -13394,39 +13430,41 @@ jest-docblock@^26.0.0: dependencies: detect-newline "^3.0.0" -jest-each@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-each/-/jest-each-26.0.1.tgz#633083061619302fc90dd8f58350f9d77d67be04" - integrity sha512-OTgJlwXCAR8NIWaXFL5DBbeS4QIYPuNASkzSwMCJO+ywo9BEa6TqkaSWsfR7VdbMLdgYJqSfQcIyjJCNwl5n4Q== +jest-each@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-26.4.2.tgz#bb14f7f4304f2bb2e2b81f783f989449b8b6ffae" + integrity sha512-p15rt8r8cUcRY0Mvo1fpkOGYm7iI8S6ySxgIdfh3oOIv+gHwrHTy5VWCGOecWUhDsit4Nz8avJWdT07WLpbwDA== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" chalk "^4.0.0" - jest-get-type "^26.0.0" - jest-util "^26.0.1" - pretty-format "^26.0.1" + jest-get-type "^26.3.0" + jest-util "^26.3.0" + pretty-format "^26.4.2" -jest-environment-jsdom@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.0.1.tgz#217690852e5bdd7c846a4e3b50c8ffd441dfd249" - integrity sha512-u88NJa3aptz2Xix2pFhihRBAatwZHWwSiRLBDBQE1cdJvDjPvv7ZGA0NQBxWwDDn7D0g1uHqxM8aGgfA9Bx49g== +jest-environment-jsdom@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.3.0.tgz#3b749ba0f3a78e92ba2c9ce519e16e5dd515220c" + integrity sha512-zra8He2btIMJkAzvLaiZ9QwEPGEetbxqmjEBQwhH3CA+Hhhu0jSiEJxnJMbX28TGUvPLxBt/zyaTLrOPF4yMJA== dependencies: - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" + jest-util "^26.3.0" jsdom "^16.2.2" -jest-environment-node@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.0.1.tgz#584a9ff623124ff6eeb49e0131b5f7612b310b13" - integrity sha512-4FRBWcSn5yVo0KtNav7+5NH5Z/tEgDLp7VRQVS5tCouWORxj+nI+1tOLutM07Zb2Qi7ja+HEDoOUkjBSWZg/IQ== +jest-environment-node@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.3.0.tgz#56c6cfb506d1597f94ee8d717072bda7228df849" + integrity sha512-c9BvYoo+FGcMj5FunbBgtBnbR5qk3uky8PKyRVpSfe2/8+LrNQMiXX53z6q2kY+j15SkjQCOSL/6LHnCPLVHNw== dependencies: - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" + jest-util "^26.3.0" jest-esm-transformer@^1.0.0: version "1.0.0" @@ -13449,61 +13487,63 @@ jest-get-type@^25.1.0, jest-get-type@^25.2.6: resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== -jest-get-type@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" - integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg== +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-haste-map@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.0.1.tgz#40dcc03c43ac94d25b8618075804d09cd5d49de7" - integrity sha512-J9kBl/EdjmDsvyv7CiyKY5+DsTvVOScenprz/fGqfLg/pm1gdjbwwQ98nW0t+OIt+f+5nAVaElvn/6wP5KO7KA== +jest-haste-map@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.3.0.tgz#c51a3b40100d53ab777bfdad382d2e7a00e5c726" + integrity sha512-DHWBpTJgJhLLGwE5Z1ZaqLTYqeODQIZpby0zMBsCU9iRFHYyhklYqP4EiG73j5dkbaAdSZhgB938mL51Q5LeZA== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" "@types/graceful-fs" "^4.1.2" + "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.4" - jest-serializer "^26.0.0" - jest-util "^26.0.1" - jest-worker "^26.0.0" + jest-regex-util "^26.0.0" + jest-serializer "^26.3.0" + jest-util "^26.3.0" + jest-worker "^26.3.0" micromatch "^4.0.2" sane "^4.0.3" walker "^1.0.7" - which "^2.0.2" optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.0.1.tgz#947c40ee816636ba23112af3206d6fa7b23c1c1c" - integrity sha512-ILaRyiWxiXOJ+RWTKupzQWwnPaeXPIoLS5uW41h18varJzd9/7I0QJGqg69fhTT1ev9JpSSo9QtalriUN0oqOg== +jest-jasmine2@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.4.2.tgz#18a9d5bec30904267ac5e9797570932aec1e2257" + integrity sha512-z7H4EpCldHN1J8fNgsja58QftxBSL+JcwZmaXIvV9WKIM+x49F4GLHu/+BQh2kzRKHAgaN/E82od+8rTOBPyPA== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.0.1" - "@jest/source-map" "^26.0.0" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/environment" "^26.3.0" + "@jest/source-map" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - expect "^26.0.1" + expect "^26.4.2" is-generator-fn "^2.0.0" - jest-each "^26.0.1" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" - jest-runtime "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - pretty-format "^26.0.1" + jest-each "^26.4.2" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" + jest-runtime "^26.4.2" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + pretty-format "^26.4.2" throat "^5.0.0" -jest-leak-detector@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.0.1.tgz#79b19ab3f41170e0a78eb8fa754a116d3447fb8c" - integrity sha512-93FR8tJhaYIWrWsbmVN1pQ9ZNlbgRpfvrnw5LmgLRX0ckOJ8ut/I35CL7awi2ecq6Ca4lL59bEK9hr7nqoHWPA== +jest-leak-detector@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.4.2.tgz#c73e2fa8757bf905f6f66fb9e0070b70fa0f573f" + integrity sha512-akzGcxwxtE+9ZJZRW+M2o+nTNnmQZxrHJxX/HjgDaU5+PLmY1qnQPnMjgADPGCRPhB+Yawe1iij0REe+k/aHoA== dependencies: - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" jest-matcher-utils@^25.1.0: version "25.1.0" @@ -13515,23 +13555,23 @@ jest-matcher-utils@^25.1.0: jest-get-type "^25.1.0" pretty-format "^25.1.0" -jest-matcher-utils@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.0.1.tgz#12e1fc386fe4f14678f4cc8dbd5ba75a58092911" - integrity sha512-PUMlsLth0Azen8Q2WFTwnSkGh2JZ8FYuwijC8NR47vXKpsrKmA1wWvgcj1CquuVfcYiDEdj985u5Wmg7COEARw== +jest-matcher-utils@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.4.2.tgz#fa81f3693f7cb67e5fc1537317525ef3b85f4b06" + integrity sha512-KcbNqWfWUG24R7tu9WcAOKKdiXiXCbMvQYT6iodZ9k1f7065k0keUOW6XpJMMvah+hTfqkhJhRXmA3r3zMAg0Q== dependencies: chalk "^4.0.0" - jest-diff "^26.0.1" - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + jest-diff "^26.4.2" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" -jest-message-util@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.0.1.tgz#07af1b42fc450b4cc8e90e4c9cef11b33ce9b0ac" - integrity sha512-CbK8uQREZ8umUfo8+zgIfEt+W7HAHjQCoRaNs4WxKGhAYBGwEyvxuK81FXa7VeB9pwDEXeeKOB2qcsNVCAvB7Q== +jest-message-util@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.3.0.tgz#3bdb538af27bb417f2d4d16557606fd082d5841a" + integrity sha512-xIavRYqr4/otGOiLxLZGj3ieMmjcNE73Ui+LdSW/Y790j5acqCsAdDiLIbzHCZMpN07JOENRWX5DcU+OQ+TjTA== dependencies: "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" "@types/stack-utils" "^1.0.1" chalk "^4.0.0" graceful-fs "^4.2.4" @@ -13539,164 +13579,169 @@ jest-message-util@^26.0.1: slash "^3.0.0" stack-utils "^2.0.2" -jest-mock@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-26.0.1.tgz#7fd1517ed4955397cf1620a771dc2d61fad8fd40" - integrity sha512-MpYTBqycuPYSY6xKJognV7Ja46/TeRbAZept987Zp+tuJvMN0YBWyyhG9mXyYQaU3SBI0TUlSaO5L3p49agw7Q== +jest-mock@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-26.3.0.tgz#ee62207c3c5ebe5f35b760e1267fee19a1cfdeba" + integrity sha512-PeaRrg8Dc6mnS35gOo/CbZovoDPKAeB1FICZiuagAgGvbWdNNyjQjkOaGUa/3N3JtpQ/Mh9P4A2D4Fv51NnP8Q== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" + "@types/node" "*" -jest-pnp-resolver@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" - integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== jest-regex-util@^26.0.0: version "26.0.0" resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-resolve-dependencies@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.0.1.tgz#607ba7ccc32151d185a477cff45bf33bce417f0b" - integrity sha512-9d5/RS/ft0vB/qy7jct/qAhzJsr6fRQJyGAFigK3XD4hf9kIbEH5gks4t4Z7kyMRhowU6HWm/o8ILqhaHdSqLw== +jest-resolve-dependencies@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.4.2.tgz#739bdb027c14befb2fe5aabbd03f7bab355f1dc5" + integrity sha512-ADHaOwqEcVc71uTfySzSowA/RdxUpCxhxa2FNLiin9vWLB1uLPad3we+JSSROq5+SrL9iYPdZZF8bdKM7XABTQ== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" jest-regex-util "^26.0.0" - jest-snapshot "^26.0.1" + jest-snapshot "^26.4.2" -jest-resolve@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.0.1.tgz#21d1ee06f9ea270a343a8893051aeed940cde736" - integrity sha512-6jWxk0IKZkPIVTvq6s72RH735P8f9eCJW3IM5CX/SJFeKq1p2cZx0U49wf/SdMlhaB/anann5J2nCJj6HrbezQ== +jest-resolve@^26.4.0: + version "26.4.0" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.4.0.tgz#6dc0af7fb93e65b73fec0368ca2b76f3eb59a6d7" + integrity sha512-bn/JoZTEXRSlEx3+SfgZcJAVuTMOksYq9xe9O6s4Ekg84aKBObEaVXKOEilULRqviSLAYJldnoWV9c07kwtiCg== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" chalk "^4.0.0" graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.1" - jest-util "^26.0.1" + jest-pnp-resolver "^1.2.2" + jest-util "^26.3.0" read-pkg-up "^7.0.1" resolve "^1.17.0" slash "^3.0.0" -jest-runner@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-26.0.1.tgz#ea03584b7ae4bacfb7e533d680a575a49ae35d50" - integrity sha512-CApm0g81b49Znm4cZekYQK67zY7kkB4umOlI2Dx5CwKAzdgw75EN+ozBHRvxBzwo1ZLYZ07TFxkaPm+1t4d8jA== +jest-runner@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-26.4.2.tgz#c3ec5482c8edd31973bd3935df5a449a45b5b853" + integrity sha512-FgjDHeVknDjw1gRAYaoUoShe1K3XUuFMkIaXbdhEys+1O4bEJS8Avmn4lBwoMfL8O5oFTdWYKcf3tEJyyYyk8g== dependencies: - "@jest/console" "^26.0.1" - "@jest/environment" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.3.0" + "@jest/environment" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" chalk "^4.0.0" + emittery "^0.7.1" exit "^0.1.2" graceful-fs "^4.2.4" - jest-config "^26.0.1" + jest-config "^26.4.2" jest-docblock "^26.0.0" - jest-haste-map "^26.0.1" - jest-jasmine2 "^26.0.1" - jest-leak-detector "^26.0.1" - jest-message-util "^26.0.1" - jest-resolve "^26.0.1" - jest-runtime "^26.0.1" - jest-util "^26.0.1" - jest-worker "^26.0.0" + jest-haste-map "^26.3.0" + jest-leak-detector "^26.4.2" + jest-message-util "^26.3.0" + jest-resolve "^26.4.0" + jest-runtime "^26.4.2" + jest-util "^26.3.0" + jest-worker "^26.3.0" source-map-support "^0.5.6" throat "^5.0.0" -jest-runtime@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.0.1.tgz#a121a6321235987d294168e282d52b364d7d3f89" - integrity sha512-Ci2QhYFmANg5qaXWf78T2Pfo6GtmIBn2rRaLnklRyEucmPccmCKvS9JPljcmtVamsdMmkyNkVFb9pBTD6si9Lw== +jest-runtime@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.4.2.tgz#94ce17890353c92e4206580c73a8f0c024c33c42" + integrity sha512-4Pe7Uk5a80FnbHwSOk7ojNCJvz3Ks2CNQWT5Z7MJo4tX0jb3V/LThKvD9tKPNVNyeMH98J/nzGlcwc00R2dSHQ== dependencies: - "@jest/console" "^26.0.1" - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/globals" "^26.0.1" - "@jest/source-map" "^26.0.0" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.3.0" + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/globals" "^26.4.2" + "@jest/source-map" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" "@types/yargs" "^15.0.0" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.2.4" - jest-config "^26.0.1" - jest-haste-map "^26.0.1" - jest-message-util "^26.0.1" - jest-mock "^26.0.1" + jest-config "^26.4.2" + jest-haste-map "^26.3.0" + jest-message-util "^26.3.0" + jest-mock "^26.3.0" jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" + jest-resolve "^26.4.0" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" slash "^3.0.0" strip-bom "^4.0.0" yargs "^15.3.1" -jest-serializer@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.0.0.tgz#f6c521ddb976943b93e662c0d4d79245abec72a3" - integrity sha512-sQGXLdEGWFAE4wIJ2ZaIDb+ikETlUirEOBsLXdoBbeLhTHkZUJwgk3+M8eyFizhM6le43PDCCKPA1hzkSDo4cQ== +jest-serializer@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.3.0.tgz#1c9d5e1b74d6e5f7e7f9627080fa205d976c33ef" + integrity sha512-IDRBQBLPlKa4flg77fqg0n/pH87tcRKwe8zxOVTWISxGpPHYkRZ1dXKyh04JOja7gppc60+soKVZ791mruVdow== dependencies: + "@types/node" "*" graceful-fs "^4.2.4" -jest-snapshot@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.0.1.tgz#1baa942bd83d47b837a84af7fcf5fd4a236da399" - integrity sha512-jxd+cF7+LL+a80qh6TAnTLUZHyQoWwEHSUFJjkw35u3Gx+BZUNuXhYvDqHXr62UQPnWo2P6fvQlLjsU93UKyxA== +jest-snapshot@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.4.2.tgz#87d3ac2f2bd87ea8003602fbebd8fcb9e94104f6" + integrity sha512-N6Uub8FccKlf5SBFnL2Ri/xofbaA68Cc3MGjP/NuwgnsvWh+9hLIR/DhrxbSiKXMY9vUW5dI6EW1eHaDHqe9sg== dependencies: "@babel/types" "^7.0.0" - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" "@types/prettier" "^2.0.0" chalk "^4.0.0" - expect "^26.0.1" + expect "^26.4.2" graceful-fs "^4.2.4" - jest-diff "^26.0.1" - jest-get-type "^26.0.0" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" - jest-resolve "^26.0.1" - make-dir "^3.0.0" + jest-diff "^26.4.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.3.0" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" + jest-resolve "^26.4.0" natural-compare "^1.4.0" - pretty-format "^26.0.1" + pretty-format "^26.4.2" semver "^7.3.2" -jest-util@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.0.1.tgz#72c4c51177b695fdd795ca072a6f94e3d7cef00a" - integrity sha512-byQ3n7ad1BO/WyFkYvlWQHTsomB6GIewBh8tlGtusiylAlaxQ1UpS0XYH0ngOyhZuHVLN79Qvl6/pMiDMSSG1g== +jest-util@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.3.0.tgz#a8974b191df30e2bf523ebbfdbaeb8efca535b3e" + integrity sha512-4zpn6bwV0+AMFN0IYhH/wnzIQzRaYVrz1A8sYnRnj4UXDXbOVtWmlaZkO9mipFqZ13okIfN87aDoJWB7VH6hcw== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" + "@types/node" "*" chalk "^4.0.0" graceful-fs "^4.2.4" is-ci "^2.0.0" - make-dir "^3.0.0" + micromatch "^4.0.2" -jest-validate@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-26.0.1.tgz#a62987e1da5b7f724130f904725e22f4e5b2e23c" - integrity sha512-u0xRc+rbmov/VqXnX3DlkxD74rHI/CfS5xaV2VpeaVySjbb1JioNVOyly5b56q2l9ZKe7bVG5qWmjfctkQb0bA== +jest-validate@^26.4.2: + version "26.4.2" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-26.4.2.tgz#e871b0dfe97747133014dcf6445ee8018398f39c" + integrity sha512-blft+xDX7XXghfhY0mrsBCYhX365n8K5wNDC4XAcNKqqjEzsRUSXP44m6PL0QJEW2crxQFLLztVnJ4j7oPlQrQ== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.3.0" camelcase "^6.0.0" chalk "^4.0.0" - jest-get-type "^26.0.0" + jest-get-type "^26.3.0" leven "^3.1.0" - pretty-format "^26.0.1" + pretty-format "^26.4.2" -jest-watcher@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.0.1.tgz#5b5e3ebbdf10c240e22a98af66d645631afda770" - integrity sha512-pdZPydsS8475f89kGswaNsN3rhP6lnC3/QDCppP7bg1L9JQz7oU9Mb/5xPETk1RHDCWeqmVC47M4K5RR7ejxFw== +jest-watcher@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.3.0.tgz#f8ef3068ddb8af160ef868400318dc4a898eed08" + integrity sha512-XnLdKmyCGJ3VoF6G/p5ohbJ04q/vv5aH9ENI+i6BL0uu9WWB6Z7Z2lhQQk0d2AVZcRGp1yW+/TsoToMhBFPRdQ== dependencies: - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^26.0.1" + jest-util "^26.3.0" string-length "^4.0.1" jest-worker@^25.1.0: @@ -13707,22 +13752,23 @@ jest-worker@^25.1.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^26.0.0: - version "26.0.0" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.0.0.tgz#4920c7714f0a96c6412464718d0c58a3df3fb066" - integrity sha512-pPaYa2+JnwmiZjK9x7p9BoZht+47ecFCDFA/CJxspHzeDvQcfVBLWzCiWyo+EGrSiQMWZtCFo9iSvMZnAAo8vw== +jest-worker@^26.3.0: + version "26.3.0" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz#7c8a97e4f4364b4f05ed8bca8ca0c24de091871f" + integrity sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw== dependencies: + "@types/node" "*" merge-stream "^2.0.0" supports-color "^7.0.0" jest@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/jest/-/jest-26.0.1.tgz#5c51a2e58dff7525b65f169721767173bf832694" - integrity sha512-29Q54kn5Bm7ZGKIuH2JRmnKl85YRigp0o0asTc6Sb6l2ch1DCXIeZTLLFy9ultJvhkTqbswF5DEx4+RlkmCxWg== + version "26.4.2" + resolved "https://registry.npmjs.org/jest/-/jest-26.4.2.tgz#7e8bfb348ec33f5459adeaffc1a25d5752d9d312" + integrity sha512-LLCjPrUh98Ik8CzW8LLVnSCfLaiY+wbK53U7VxnFSX7Q+kWC4noVeDvGWIFw0Amfq1lq2VfGm7YHWSLBV62MJw== dependencies: - "@jest/core" "^26.0.1" + "@jest/core" "^26.4.2" import-local "^3.0.2" - jest-cli "^26.0.1" + jest-cli "^26.4.2" jose@^1.27.1: version "1.27.1" @@ -15839,16 +15885,16 @@ node-modules-regexp@^1.0.0: resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-notifier@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-7.0.0.tgz#513bc42f2aa3a49fce1980a7ff375957c71f718a" - integrity sha512-y8ThJESxsHcak81PGpzWwQKxzk+5YtP3IxR8AYdpXQ1IB6FmcVzFdZXrkPin49F/DKUCfeeiziB8ptY9npzGuA== +node-notifier@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" + integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== dependencies: growly "^1.3.0" - is-wsl "^2.1.1" - semver "^7.2.1" + is-wsl "^2.2.0" + semver "^7.3.2" shellwords "^0.1.1" - uuid "^7.0.3" + uuid "^8.3.0" which "^2.0.2" node-pre-gyp@^0.11.0: @@ -17817,16 +17863,6 @@ pretty-format@^25.1.0, pretty-format@^25.2.1, pretty-format@^25.5.0: ansi-styles "^4.0.0" react-is "^16.12.0" -pretty-format@^26.0.1: - version "26.0.1" - resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.0.1.tgz#a4fe54fe428ad2fd3413ca6bbd1ec8c2e277e197" - integrity sha512-SWxz6MbupT3ZSlL0Po4WF/KujhQaVehijR2blyRDCzk9e45EaYMVhMBn49fnRuHxtkSpXTes1GxNpVmH86Bxfw== - dependencies: - "@jest/types" "^26.0.1" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" - pretty-format@^26.4.2: version "26.4.2" resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz#d081d032b398e801e2012af2df1214ef75a81237" @@ -22312,7 +22348,7 @@ uuid@^7.0.3: resolved "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== -uuid@^8.0.0, uuid@^8.2.0: +uuid@^8.0.0, uuid@^8.2.0, uuid@^8.3.0: version "8.3.0" resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== @@ -22322,10 +22358,10 @@ v8-compile-cache@^2.0.3: resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== -v8-to-istanbul@^4.1.3: - version "4.1.4" - resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" - integrity sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ== +v8-to-istanbul@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-5.0.1.tgz#0608f5b49a481458625edb058488607f25498ba5" + integrity sha512-mbDNjuDajqYe3TXFk5qxcQy8L1msXNE37WTlLoqqpBfRsimbNcrlhQlDPntmECEcUvdC+AQ8CyMMf6EUx1r74Q== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" From a7e922250aa1a63798a07a1798896b02793461ad Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Tue, 1 Sep 2020 14:21:05 +0200 Subject: [PATCH 47/56] Add instructions on how to refresh existing release PR --- docs/plugins/publishing.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/plugins/publishing.md b/docs/plugins/publishing.md index 1d16ebb047..6fee4f9b1d 100644 --- a/docs/plugins/publishing.md +++ b/docs/plugins/publishing.md @@ -39,4 +39,18 @@ $ git push origin -u new-release And then create a PR. Once the PR is approved and merged into master, the master build will publish new versions of all bumped packages. +### Include new changes in existing release PR + +If you want to include some last minute changes to an existing release PR, +follow these instructions: + +```sh +$ git checkout master +$ git pull +$ git checkout new-release +$ git reset --hard master +$ yarn release +$ git push --force +``` + [Back to Docs](../README.md) From 9f59ee821a98ad66d7193d88dca22894100006e7 Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Wed, 2 Sep 2020 11:07:33 +0200 Subject: [PATCH 48/56] Add new log format --- packages/backend-common/package.json | 3 +- .../backend-common/src/logging/formats.ts | 35 +++++++++++++++++++ .../backend-common/src/logging/rootLogger.ts | 7 ++-- 3 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 packages/backend-common/src/logging/formats.ts diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 92d301d7e3..248e638ead 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -46,7 +46,8 @@ "prom-client": "^12.0.0", "selfsigned": "^1.10.7", "stoppable": "^1.1.0", - "winston": "^3.2.1" + "winston": "^3.2.1", + "logform": "^2.1.1" }, "peerDependencies": { "pg-connection-string": "^2.3.0" diff --git a/packages/backend-common/src/logging/formats.ts b/packages/backend-common/src/logging/formats.ts new file mode 100644 index 0000000000..5f00448744 --- /dev/null +++ b/packages/backend-common/src/logging/formats.ts @@ -0,0 +1,35 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as winston from 'winston'; +import { TransformableInfo } from 'logform'; + +const coloredTemplate = (info: TransformableInfo) => { + const { timestamp, level, message, plugin, service } = info; + const colorizer = winston.format.colorize(); + const prefix = plugin || service; + const timestampColor = colorizer.colorize('timestamp', timestamp); + const prefixColor = colorizer.colorize('prefix', prefix); + + return `${timestampColor} ${prefixColor} ${level} ${message}`; +}; + +export const coloredFormat = winston.format.combine( + winston.format.timestamp(), + winston.format.colorize({ + colors: { timestamp: 'dim', prefix: 'blue' }, + }), + winston.format.printf(coloredTemplate), +); diff --git a/packages/backend-common/src/logging/rootLogger.ts b/packages/backend-common/src/logging/rootLogger.ts index fd2f3a1c8b..306ed23444 100644 --- a/packages/backend-common/src/logging/rootLogger.ts +++ b/packages/backend-common/src/logging/rootLogger.ts @@ -14,17 +14,14 @@ * limitations under the License. */ import * as winston from 'winston'; +import { coloredFormat } from './formats'; let rootLogger: winston.Logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: process.env.NODE_ENV === 'production' ? winston.format.json() - : winston.format.combine( - winston.format.colorize(), - winston.format.timestamp(), - winston.format.simple(), - ), + : coloredFormat, defaultMeta: { service: 'backstage' }, transports: [ new winston.transports.Console({ From 7d8058a1ef0fab41a6801e8f3ecbf616098a2faf Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Wed, 2 Sep 2020 11:08:40 +0200 Subject: [PATCH 49/56] Make http-proxy-middleware log to supplied logger --- plugins/proxy-backend/src/service/router.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/plugins/proxy-backend/src/service/router.ts b/plugins/proxy-backend/src/service/router.ts index 5273b2c806..5c5e17b872 100644 --- a/plugins/proxy-backend/src/service/router.ts +++ b/plugins/proxy-backend/src/service/router.ts @@ -34,6 +34,7 @@ export interface RouterOptions { // given config. function buildMiddleware( pathPrefix: string, + logger: Logger, route: string, config: string | ProxyConfig, ): Proxy { @@ -54,6 +55,9 @@ function buildMiddleware( fullConfig.changeOrigin = true; } + // Attach the logger to the proxy config + fullConfig.logProvider = () => logger; + return createProxyMiddleware(fullConfig); } @@ -66,7 +70,12 @@ export async function createRouter( Object.entries(proxyConfig).forEach(([route, proxyRouteConfig]) => { router.use( route, - buildMiddleware(options.pathPrefix, route, proxyRouteConfig), + buildMiddleware( + options.pathPrefix, + options.logger, + route, + proxyRouteConfig, + ), ); }); From dac617b436090565a89a0f5f55b0a7471e3284f3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Sep 2020 11:39:59 +0200 Subject: [PATCH 50/56] create-app: remove duplicate techdocs plugin from app package --- .../templates/default-app/packages/app/package.json.hbs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index 57ec119ed5..c432f27a3a 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -17,7 +17,6 @@ "@backstage/plugin-lighthouse": "^{{version}}", "@backstage/plugin-tech-radar": "^{{version}}", "@backstage/plugin-github-actions": "^{{version}}", - "@backstage/plugin-techdocs": "^{{version}}", "@backstage/plugin-sentry": "^{{version}}", "@backstage/test-utils": "^{{version}}", "@backstage/theme": "^{{version}}", From 992dfd545212f82cdeb83e2fc48921a4faa45e99 Mon Sep 17 00:00:00 2001 From: "althaf.hameez" Date: Wed, 2 Sep 2020 18:13:25 +0800 Subject: [PATCH 51/56] rebase --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index dc02ad3b85..0ba3e3196b 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -12,3 +12,4 @@ | [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. | | [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D | | [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling | +| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling | From 0af1ce25caf544271e186f74f9429eecc99e1cd6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Sep 2020 13:01:27 +0200 Subject: [PATCH 52/56] techdocs-backend: use resolvePackagePath instead of __dirname --- plugins/techdocs-backend/src/service/router.ts | 12 +++++++----- .../src/techdocs/stages/publish/local.ts | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/plugins/techdocs-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index f93d182edc..bb26ea19b8 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -19,7 +19,6 @@ import express from 'express'; import Knex from 'knex'; import fetch from 'node-fetch'; import { Config } from '@backstage/config'; -import path from 'path'; import Docker from 'dockerode'; import { GeneratorBuilder, @@ -27,6 +26,7 @@ import { PublisherBase, LocalPublish, } from '../techdocs'; +import { resolvePackagePath } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; type RouterOptions = { @@ -39,6 +39,11 @@ type RouterOptions = { dockerClient: Docker; }; +const staticDocsDir = resolvePackagePath( + '@backstage/plugin-techdocs-backend', + 'static/docs', +); + export async function createRouter({ preparers, generators, @@ -102,10 +107,7 @@ export async function createRouter({ }); if (publisher instanceof LocalPublish) { - router.use( - '/static/docs/', - express.static(path.resolve(__dirname, `../../static/docs`)), - ); + router.use('/static/docs/', express.static(staticDocsDir)); router.use( '/static/docs/:kind/:namespace/:name', async (req, res, next) => { diff --git a/plugins/techdocs-backend/src/techdocs/stages/publish/local.ts b/plugins/techdocs-backend/src/techdocs/stages/publish/local.ts index be9e1876d8..e33c6fa17d 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/publish/local.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/publish/local.ts @@ -14,10 +14,10 @@ * limitations under the License. */ import fs from 'fs-extra'; -import path from 'path'; import { Logger } from 'winston'; import { Entity } from '@backstage/catalog-model'; import { PublisherBase } from './types'; +import { resolvePackagePath } from '@backstage/backend-common'; export class LocalPublish implements PublisherBase { private readonly logger: Logger; @@ -39,9 +39,9 @@ export class LocalPublish implements PublisherBase { | { remoteUrl: string } { const entityNamespace = entity.metadata.namespace ?? 'default'; - const publishDir = path.resolve( - __dirname, - '../../../../static/docs/', + const publishDir = resolvePackagePath( + '@backstage/plugin-techdocs-backend', + 'static/docs', entity.kind, entityNamespace, entity.metadata.name, From 8ac23713029bfbab7d36261f62de8468a5ef1f9b Mon Sep 17 00:00:00 2001 From: Marcus Eide Date: Wed, 2 Sep 2020 14:03:35 +0200 Subject: [PATCH 53/56] Remove sentry from create-app --- .../templates/default-app/app-config.yaml.hbs | 3 --- .../default-app/packages/app/package.json.hbs | 1 - .../default-app/packages/app/src/plugins.ts | 1 - .../packages/backend/package.json.hbs | 1 - .../default-app/packages/backend/src/index.ts | 3 --- .../packages/backend/src/plugins/sentry.ts | 22 ------------------- 6 files changed, 31 deletions(-) delete mode 100644 packages/create-app/templates/default-app/packages/backend/src/plugins/sentry.ts diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index 64185e43d3..d5a8e9b200 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -44,9 +44,6 @@ proxy: techdocs: storageUrl: http://localhost:7000/techdocs/static/docs -sentry: - organization: spotify - lighthouse: baseUrl: http://localhost:3003 diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index c432f27a3a..9d4993c4dc 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -17,7 +17,6 @@ "@backstage/plugin-lighthouse": "^{{version}}", "@backstage/plugin-tech-radar": "^{{version}}", "@backstage/plugin-github-actions": "^{{version}}", - "@backstage/plugin-sentry": "^{{version}}", "@backstage/test-utils": "^{{version}}", "@backstage/theme": "^{{version}}", "history": "^5.0.0", diff --git a/packages/create-app/templates/default-app/packages/app/src/plugins.ts b/packages/create-app/templates/default-app/packages/app/src/plugins.ts index 0d54c55649..c787ac2166 100644 --- a/packages/create-app/templates/default-app/packages/app/src/plugins.ts +++ b/packages/create-app/templates/default-app/packages/app/src/plugins.ts @@ -7,4 +7,3 @@ export { plugin as Circleci } from '@backstage/plugin-circleci'; export { plugin as LighthousePlugin } from '@backstage/plugin-lighthouse'; export { plugin as TechRadar } from '@backstage/plugin-tech-radar'; export { plugin as GithubActions } from '@backstage/plugin-github-actions'; -export { plugin as Sentry } from '@backstage/plugin-sentry'; diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index a978349b02..53bfd6d990 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -26,7 +26,6 @@ "@backstage/plugin-proxy-backend": "^{{version}}", "@backstage/plugin-rollbar-backend": "^{{version}}", "@backstage/plugin-scaffolder-backend": "^{{version}}", - "@backstage/plugin-sentry-backend": "^{{version}}", "@backstage/plugin-techdocs-backend": "^{{version}}", "@octokit/rest": "^18.0.0", "dockerode": "^3.2.0", diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 6ba6c4dc8e..6a014727e9 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -20,7 +20,6 @@ import identity from './plugins/identity'; import scaffolder from './plugins/scaffolder'; import proxy from './plugins/proxy'; import techdocs from './plugins/techdocs'; -import sentry from './plugins/sentry'; import { PluginEnvironment } from './types'; function makeCreateEnv(loadedConfigs: AppConfig[]) { @@ -51,13 +50,11 @@ async function main() { const identityEnv = useHotMemoize(module, () => createEnv('identity')); const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); - const sentryEnv = useHotMemoize(module, () => createEnv('sentry')); const service = createServiceBuilder(module) .loadConfig(configReader) .addRouter('/catalog', await catalog(catalogEnv)) .addRouter('/scaffolder', await scaffolder(scaffolderEnv)) - .addRouter('/sentry', await sentry(sentryEnv)) .addRouter('/auth', await auth(authEnv)) .addRouter('/identity', await identity(identityEnv)) .addRouter('/techdocs', await techdocs(techdocsEnv)) diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/sentry.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/sentry.ts deleted file mode 100644 index 5cd0e55761..0000000000 --- a/packages/create-app/templates/default-app/packages/backend/src/plugins/sentry.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { createRouter } from '@backstage/plugin-sentry-backend'; -import type { PluginEnvironment } from '../types'; - -export default async function createPlugin({ logger }: PluginEnvironment) { - return await createRouter(logger); -} From c08a83260e7da58b4458965e4e6022756f1ba6f6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Sep 2020 14:21:58 +0200 Subject: [PATCH 54/56] auth-backend: use correct interface in factory return type --- plugins/auth-backend/src/providers/types.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 80b8899d94..b3b7e518cc 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -18,8 +18,6 @@ import express from 'express'; import { Logger } from 'winston'; import { TokenIssuer } from '../identity'; import { Config } from '@backstage/config'; -import { OAuthProvider } from '../lib/OAuthProvider'; -import { SamlAuthProvider } from './saml/provider'; export type OAuthProviderOptions = { /** @@ -174,7 +172,7 @@ export type AuthProviderFactory = ( envConfig: Config, logger: Logger, issuer: TokenIssuer, -) => OAuthProvider | SamlAuthProvider | undefined; +) => AuthProviderRouteHandlers | undefined; export type AuthResponse = { providerInfo: ProviderInfo; From 07c9a9474a111f8e8dcd1787734135dd52f19b29 Mon Sep 17 00:00:00 2001 From: Sebastian Qvarfordt Date: Wed, 2 Sep 2020 15:30:35 +0200 Subject: [PATCH 55/56] Get branchname from repo instance instead of location url (#2242) --- .../techdocs-backend/src/techdocs/stages/prepare/helpers.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/helpers.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/helpers.ts index b2f04bbbbf..27e746590a 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/helpers.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/helpers.ts @@ -79,9 +79,10 @@ export const checkoutGitRepository = async ( if (fs.existsSync(repositoryTmpPath)) { const repository = await Repository.open(repositoryTmpPath); + const currentBranchName = (await repository.getCurrentBranch()).shorthand(); await repository.mergeBranches( - parsedGitLocation.ref, - `origin/${parsedGitLocation.ref}`, + currentBranchName, + `origin/${currentBranchName}`, ); return repositoryTmpPath; } From 27113c53647ae2bb77a515e49968cda11e9ca879 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 2 Sep 2020 15:57:55 +0200 Subject: [PATCH 56/56] catalog: remove sentry widget --- plugins/catalog/package.json | 1 - .../components/EntityPageOverview/EntityPageOverview.tsx | 7 ------- 2 files changed, 8 deletions(-) diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 0f82add554..40865d488e 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -27,7 +27,6 @@ "@backstage/plugin-github-actions": "^0.1.1-alpha.20", "@backstage/plugin-jenkins": "^0.1.1-alpha.20", "@backstage/plugin-scaffolder": "^0.1.1-alpha.20", - "@backstage/plugin-sentry": "^0.1.1-alpha.20", "@backstage/plugin-techdocs": "^0.1.1-alpha.20", "@backstage/theme": "^0.1.1-alpha.20", "@material-ui/core": "^4.9.1", diff --git a/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx b/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx index 4067fef29a..ec697e7c06 100644 --- a/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx +++ b/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx @@ -16,7 +16,6 @@ import { Entity } from '@backstage/catalog-model'; import { Content } from '@backstage/core'; -import { SentryIssuesWidget } from '@backstage/plugin-sentry'; import { Widget as GithubActionsWidget } from '@backstage/plugin-github-actions'; import { JenkinsBuildsWidget, @@ -52,12 +51,6 @@ export const EntityPageOverview: FC<{ entity: Entity }> = ({ entity }) => { )} - - - );