From 0bdeeb20cfc689949762cf623603c5ec744eb741 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 25 Nov 2020 11:40:36 +0100 Subject: [PATCH 01/45] core-api: add internal attachNodeData and getComponentData helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: blam --- .../core-api/src/lib/componentData.test.tsx | 62 +++++++++++++++++ packages/core-api/src/lib/componentData.tsx | 69 +++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 packages/core-api/src/lib/componentData.test.tsx create mode 100644 packages/core-api/src/lib/componentData.tsx diff --git a/packages/core-api/src/lib/componentData.test.tsx b/packages/core-api/src/lib/componentData.test.tsx new file mode 100644 index 0000000000..6c4abda40f --- /dev/null +++ b/packages/core-api/src/lib/componentData.test.tsx @@ -0,0 +1,62 @@ +/* + * 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 { attachComponentData, getComponentData } from './componentData'; + +describe('elementData', () => { + it('should attach a single piece of data', () => { + const data = { foo: 'bar' }; + const Component = () => null; + attachComponentData(Component, 'my-data', data); + + const element = ; + expect(getComponentData(element, 'my-data')).toBe(data); + }); + + it('should attach several distinct pieces of data', () => { + const data1 = { foo: 'bar' }; + const data2 = { test: 'value' }; + const Component = () => null; + attachComponentData(Component, 'my-data', data1); + attachComponentData(Component, 'second', data2); + + const element = ; + expect(getComponentData(element, 'my-data')).toBe(data1); + expect(getComponentData(element, 'second')).toBe(data2); + }); + + it('returns undefined for missing data', () => { + const data = { foo: 'bar' }; + const Component1 = () => null; + const Component2 = () => null; + attachComponentData(Component2, 'my-data', data); + + const element1 = ; + const element2 = ; + expect(getComponentData(element1, 'missing')).toBeUndefined(); + expect(getComponentData(element2, 'missing')).toBeUndefined(); + }); + + it('should throw when attempting to overwrite data', () => { + const data = { foo: 'bar' }; + const MyComponent = () => null; + attachComponentData(MyComponent, 'my-data', data); + expect(() => attachComponentData(MyComponent, 'my-data', data)).toThrow( + 'Attempted to attach duplicate data "my-data" to component "MyComponent"', + ); + }); +}); diff --git a/packages/core-api/src/lib/componentData.tsx b/packages/core-api/src/lib/componentData.tsx new file mode 100644 index 0000000000..1f88356a48 --- /dev/null +++ b/packages/core-api/src/lib/componentData.tsx @@ -0,0 +1,69 @@ +/* + * 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 { ComponentType, ReactNode } from 'react'; + +const DATA_KEY = Symbol('backstage-component-data'); + +type DataContainer = { + map: Map; +}; + +type ComponentWithData

= ComponentType

& { + [DATA_KEY]?: DataContainer; +}; + +type ReactNodeWithData = ReactNode & { + type?: { [DATA_KEY]?: DataContainer }; +}; + +export function attachComponentData

( + component: ComponentType

, + type: string, + data: unknown, +) { + const dataComponent = component as ComponentWithData

; + + let container = dataComponent[DATA_KEY]; + if (!container) { + container = dataComponent[DATA_KEY] = { map: new Map() }; + } + + if (container.map.has(type)) { + const name = component.displayName || component.name; + throw new Error( + `Attempted to attach duplicate data "${type}" to component "${name}"`, + ); + } + + container.map.set(type, data); +} + +export function getComponentData( + node: ReactNode, + type: string, +): T | undefined { + if (!node) { + return undefined; + } + + const container = (node as ReactNodeWithData).type?.[DATA_KEY]; + if (!container) { + return undefined; + } + + return container.map.get(type) as T | undefined; +} From 18821642ead8e5c0ca29692af6954426069a1770 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 25 Nov 2020 17:37:47 +0100 Subject: [PATCH 02/45] core-api: add plugin.provide and extensions + core extension functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: blam --- packages/core-api/src/lib/extensions.test.tsx | 72 +++++++++++++++++++ packages/core-api/src/lib/extensions.tsx | 59 +++++++++++++++ packages/core-api/src/plugin/Plugin.tsx | 13 +++- packages/core-api/src/plugin/types.ts | 5 ++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 packages/core-api/src/lib/extensions.test.tsx create mode 100644 packages/core-api/src/lib/extensions.tsx diff --git a/packages/core-api/src/lib/extensions.test.tsx b/packages/core-api/src/lib/extensions.test.tsx new file mode 100644 index 0000000000..92fcecebc4 --- /dev/null +++ b/packages/core-api/src/lib/extensions.test.tsx @@ -0,0 +1,72 @@ +/* + * 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 { createPlugin } from '../plugin'; +import { createRouteRef } from '../routing'; +import { getComponentData } from './componentData'; +import { + createComponentExtension, + createReactExtension, + createRoutableExtension, +} from './extensions'; + +const plugin = createPlugin({ + id: 'my-plugin', +}); + +describe('extensions', () => { + it('should create a react extension with component data', () => { + const Component = () => null; + + const extension = createReactExtension({ + component: Component, + data: { + myData: { foo: 'bar' }, + }, + }); + + const ExtensionComponent = plugin.provide(extension); + const element = ; + + expect(getComponentData(element, 'core.plugin')).toBe(plugin); + expect(getComponentData(element, 'myData')).toEqual({ foo: 'bar' }); + }); + + it('should create react extensions of different types', () => { + const Component = () => null; + const routeRef = createRouteRef({ path: '/foo', title: 'Foo' }); + + const extension1 = createComponentExtension({ + component: Component, + }); + + const extension2 = createRoutableExtension({ + component: Component, + mountPoint: routeRef, + }); + + const ExtensionComponent1 = plugin.provide(extension1); + const ExtensionComponent2 = plugin.provide(extension2); + + const element1 = ; + const element2 = ; + + expect(getComponentData(element1, 'core.plugin')).toBe(plugin); + expect(getComponentData(element2, 'core.plugin')).toBe(plugin); + expect(getComponentData(element2, 'core.mountPoint')).toBe(routeRef); + }); +}); diff --git a/packages/core-api/src/lib/extensions.tsx b/packages/core-api/src/lib/extensions.tsx new file mode 100644 index 0000000000..c0a71a2a90 --- /dev/null +++ b/packages/core-api/src/lib/extensions.tsx @@ -0,0 +1,59 @@ +/* + * 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, { ExoticComponent, ComponentType } from 'react'; +import { RouteRef } from '../routing'; +import { attachComponentData } from './componentData'; +import { Extension, BackstagePlugin } from '../plugin/types'; + +export function createRoutableExtension(options: { + component: ComponentType; + mountPoint: RouteRef; +}): Extension> { + const { component, mountPoint } = options; + return createReactExtension({ + component, + data: { + 'core.mountPoint': mountPoint, + }, + }); +} + +export function createComponentExtension(options: { + component: ComponentType; +}): Extension> { + const { component } = options; + return createReactExtension({ component }); +} + +export function createReactExtension(options: { + component: ComponentType; + data?: Record; +}): Extension> { + const { component: Component, data = {} } = options; + return { + expose(plugin: BackstagePlugin): ExoticComponent { + const Result = (props: Props) => ; + + attachComponentData(Result, 'core.plugin', plugin); + for (const [key, value] of Object.entries(data)) { + attachComponentData(Result, key, value); + } + + return Result as ExoticComponent; + }, + }; +} diff --git a/packages/core-api/src/plugin/Plugin.tsx b/packages/core-api/src/plugin/Plugin.tsx index d69bb7e721..f477674f4d 100644 --- a/packages/core-api/src/plugin/Plugin.tsx +++ b/packages/core-api/src/plugin/Plugin.tsx @@ -14,10 +14,15 @@ * limitations under the License. */ -import { PluginConfig, PluginOutput, BackstagePlugin } from './types'; +import { + PluginConfig, + PluginOutput, + BackstagePlugin, + Extension, +} from './types'; import { AnyApiFactory } from '../apis'; -export class PluginImpl { +export class PluginImpl implements BackstagePlugin { private storedOutput?: PluginOutput[]; constructor(private readonly config: PluginConfig) {} @@ -65,6 +70,10 @@ export class PluginImpl { return this.storedOutput; } + provide(extension: Extension): T { + return extension.expose(this); + } + toString() { return `plugin{${this.config.id}}`; } diff --git a/packages/core-api/src/plugin/types.ts b/packages/core-api/src/plugin/types.ts index 855264c5f4..dd19948a0a 100644 --- a/packages/core-api/src/plugin/types.ts +++ b/packages/core-api/src/plugin/types.ts @@ -66,10 +66,15 @@ export type PluginOutput = | RedirectRouteOutput | FeatureFlagOutput; +export type Extension = { + expose(plugin: BackstagePlugin): T; +}; + export type BackstagePlugin = { getId(): string; output(): PluginOutput[]; getApis(): Iterable; + provide(extension: Extension): T; }; export type PluginConfig = { From 632e1986166916e09d4bd8f2d88f2d7b6b14ac06 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 26 Nov 2020 15:36:22 +0100 Subject: [PATCH 03/45] core-api: add mount point collection + extension tweaks Co-authored-by: blam --- packages/core-api/src/lib/extensions.tsx | 25 ++- .../core-api/src/routing/discovery.test.tsx | 145 ++++++++++++++++++ packages/core-api/src/routing/discovery.tsx | 75 +++++++++ 3 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 packages/core-api/src/routing/discovery.test.tsx create mode 100644 packages/core-api/src/routing/discovery.tsx diff --git a/packages/core-api/src/lib/extensions.tsx b/packages/core-api/src/lib/extensions.tsx index c0a71a2a90..4087d5f963 100644 --- a/packages/core-api/src/lib/extensions.tsx +++ b/packages/core-api/src/lib/extensions.tsx @@ -14,7 +14,11 @@ * limitations under the License. */ -import React, { ExoticComponent, ComponentType } from 'react'; +import React, { + NamedExoticComponent, + ComponentType, + PropsWithChildren, +} from 'react'; import { RouteRef } from '../routing'; import { attachComponentData } from './componentData'; import { Extension, BackstagePlugin } from '../plugin/types'; @@ -22,7 +26,12 @@ import { Extension, BackstagePlugin } from '../plugin/types'; export function createRoutableExtension(options: { component: ComponentType; mountPoint: RouteRef; -}): Extension> { + // TODO(Rugvip): We want to carry forward the exact props type from the inner component, with + // or without children. ComponentType stops us from doing that though, as it always + // adds children to the props internally. We may want to work around this with custom types. +}): Extension< + NamedExoticComponent> +> { const { component, mountPoint } = options; return createReactExtension({ component, @@ -34,7 +43,7 @@ export function createRoutableExtension(options: { export function createComponentExtension(options: { component: ComponentType; -}): Extension> { +}): Extension> { const { component } = options; return createReactExtension({ component }); } @@ -42,10 +51,10 @@ export function createComponentExtension(options: { export function createReactExtension(options: { component: ComponentType; data?: Record; -}): Extension> { +}): Extension> { const { component: Component, data = {} } = options; return { - expose(plugin: BackstagePlugin): ExoticComponent { + expose(plugin: BackstagePlugin): NamedExoticComponent { const Result = (props: Props) => ; attachComponentData(Result, 'core.plugin', plugin); @@ -53,7 +62,11 @@ export function createReactExtension(options: { attachComponentData(Result, key, value); } - return Result as ExoticComponent; + const name = Component.displayName || Component.name || 'Component'; + if (name) { + Result.displayName = `Extension(${name})`; + } + return Result as NamedExoticComponent; }, }; } diff --git a/packages/core-api/src/routing/discovery.test.tsx b/packages/core-api/src/routing/discovery.test.tsx new file mode 100644 index 0000000000..c894c8ac6d --- /dev/null +++ b/packages/core-api/src/routing/discovery.test.tsx @@ -0,0 +1,145 @@ +/* + * 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, { PropsWithChildren } from 'react'; +import { collectRoutes } from './discovery'; +import { createRouteRef } from './RouteRef'; +import { createPlugin } from '../plugin'; +import { createRoutableExtension } from '../lib/extensions'; +import { MemoryRouter, Routes, Route } from 'react-router-dom'; + +const mockConfig = () => ({ path: '/foo', title: 'Foo' }); +const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}; + +const plugin = createPlugin({ id: 'my-plugin' }); + +const ref1 = createRouteRef(mockConfig()); +const ref2 = createRouteRef(mockConfig()); +const ref3 = createRouteRef(mockConfig()); +const ref4 = createRouteRef(mockConfig()); +const ref5 = createRouteRef(mockConfig()); + +const Extension1 = plugin.provide( + createRoutableExtension({ component: MockComponent, mountPoint: ref1 }), +); +const Extension2 = plugin.provide( + createRoutableExtension({ component: MockComponent, mountPoint: ref2 }), +); +const Extension3 = plugin.provide( + createRoutableExtension({ component: MockComponent, mountPoint: ref3 }), +); +const Extension4 = plugin.provide( + createRoutableExtension({ component: MockComponent, mountPoint: ref4 }), +); +const Extension5 = plugin.provide( + createRoutableExtension({ component: MockComponent, mountPoint: ref5 }), +); + +describe('discovery', () => { + it('should collect routes', () => { + const list = [ +

, +
, +
+ +
, + ]; + + const routes = collectRoutes( + + + +
+ +
+
+ Some text here shouldn't be a problem +
+ {null} +
+ +
+ + {false} + {list} + {true} + {0} +
+ +
+ } /> +
+ + , + ); + + expect(routes).toEqual( + new Map([ + [ref1, '/foo'], + [ref2, '/bar/:id'], + [ref3, '/baz'], + [ref4, '/divsoup'], + [ref5, '/blop'], + ]), + ); + }); + + it('should handle all react router Route patterns', () => { + const routes = collectRoutes( + + + + + + + + } + /> + }> + } /> + + + + , + ); + + expect(routes).toEqual( + new Map([ + [ref1, '/foo'], + [ref2, '/bar/:id'], + [ref3, '/baz'], + [ref4, '/divsoup'], + [ref5, '/blop'], + ]), + ); + }); + + it('should not visit the same element twice', () => { + const element = ; + + expect(() => + collectRoutes( + + {element} + {element} + , + ), + ).toThrow(`Visited element Extension(MockComponent) twice`); + }); +}); diff --git a/packages/core-api/src/routing/discovery.tsx b/packages/core-api/src/routing/discovery.tsx new file mode 100644 index 0000000000..61e5df9136 --- /dev/null +++ b/packages/core-api/src/routing/discovery.tsx @@ -0,0 +1,75 @@ +/* + * 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, { isValidElement, ReactNode } from 'react'; +import { RouteRef } from './types'; +import { getComponentData } from '../lib/componentData'; + +export const collectRoutes = (tree: ReactNode) => { + const treeMap = new Map(); + + const visited = new Set(); + const nodes = [tree]; + + while (nodes.length !== 0) { + const node = nodes.shift(); + if (!isIterableElement(node)) { + continue; + } + if (visited.has(node)) { + const anyType = node?.type as + | { displayName?: string; name?: string } + | undefined; + const name = anyType?.displayName || anyType?.name || String(anyType); + throw new Error(`Visited element ${name} twice`); + } + visited.add(node); + + React.Children.forEach(node, child => { + if (!isIterableElement(child)) { + return; + } + + const { path, element, children } = child.props as { + path?: string; + element?: ReactNode; + children?: ReactNode; + }; + if (path) { + const routeRef = getComponentData(child, 'core.mountPoint'); + if (routeRef) { + treeMap.set(routeRef, path); + } else if (isIterableElement(element)) { + const elementRouteRef = getComponentData( + element, + 'core.mountPoint', + ); + if (elementRouteRef) { + treeMap.set(elementRouteRef, path); + } + nodes.push(element.props?.children); + } + } + nodes.push(children); + }); + } + + return treeMap; +}; + +function isIterableElement(node: ReactNode): node is JSX.Element { + return isValidElement(node) || Array.isArray(node); +} From 2009082476983189b9cfe29a7b93b1de21b9d3b9 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 26 Nov 2020 16:07:03 +0100 Subject: [PATCH 04/45] core-api: add mount point parent discovery Co-authored-by: blam --- .../core-api/src/routing/discovery.test.tsx | 33 +++++++++--- packages/core-api/src/routing/discovery.tsx | 54 +++++++++++++++++++ 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/packages/core-api/src/routing/discovery.test.tsx b/packages/core-api/src/routing/discovery.test.tsx index c894c8ac6d..02c80297c0 100644 --- a/packages/core-api/src/routing/discovery.test.tsx +++ b/packages/core-api/src/routing/discovery.test.tsx @@ -15,7 +15,7 @@ */ import React, { PropsWithChildren } from 'react'; -import { collectRoutes } from './discovery'; +import { collectRoutes, collectRouteParents } from './discovery'; import { createRouteRef } from './RouteRef'; import { createPlugin } from '../plugin'; import { createRoutableExtension } from '../lib/extensions'; @@ -58,7 +58,7 @@ describe('discovery', () => {
, ]; - const routes = collectRoutes( + const root = ( @@ -83,10 +83,10 @@ describe('discovery', () => { } />
- , + ); - expect(routes).toEqual( + expect(collectRoutes(root)).toEqual( new Map([ [ref1, '/foo'], [ref2, '/bar/:id'], @@ -95,10 +95,20 @@ describe('discovery', () => { [ref5, '/blop'], ]), ); + + expect(collectRouteParents(root)).toEqual( + new Map([ + [ref1, undefined], + [ref2, ref1], + [ref3, ref2], + [ref4, undefined], + [ref5, ref1], + ]), + ); }); it('should handle all react router Route patterns', () => { - const routes = collectRoutes( + const root = ( { - , + ); - expect(routes).toEqual( + expect(collectRoutes(root)).toEqual( new Map([ [ref1, '/foo'], [ref2, '/bar/:id'], @@ -128,6 +138,15 @@ describe('discovery', () => { [ref5, '/blop'], ]), ); + expect(collectRouteParents(root)).toEqual( + new Map([ + [ref1, undefined], + [ref2, ref1], + [ref3, undefined], + [ref4, ref3], + [ref5, ref3], + ]), + ); }); it('should not visit the same element twice', () => { diff --git a/packages/core-api/src/routing/discovery.tsx b/packages/core-api/src/routing/discovery.tsx index 61e5df9136..96946e1ca3 100644 --- a/packages/core-api/src/routing/discovery.tsx +++ b/packages/core-api/src/routing/discovery.tsx @@ -70,6 +70,60 @@ export const collectRoutes = (tree: ReactNode) => { return treeMap; }; +export const collectRouteParents = (tree: ReactNode) => { + const treeMap = new Map(); + + const nodes = [{ node: tree, parent: undefined as RouteRef | undefined }]; + + while (nodes.length !== 0) { + const { parent, node } = nodes.shift()!; + if (!isIterableElement(node)) { + continue; + } + + React.Children.forEach(node, child => { + if (!isIterableElement(child)) { + return; + } + + const { path, element, children } = child.props as { + path?: string; + element?: ReactNode; + children?: ReactNode; + }; + + let nextParent = parent; + + if (path) { + const routeRef = getComponentData(child, 'core.mountPoint'); + if (routeRef) { + treeMap.set(routeRef, parent); + nextParent = routeRef; + } else if (isIterableElement(element)) { + const elementRouteRef = getComponentData( + element, + 'core.mountPoint', + ); + if (elementRouteRef) { + treeMap.set(elementRouteRef, parent); + + nextParent = elementRouteRef; + nodes.push({ + parent: elementRouteRef, + node: element.props?.children, + }); + } else { + nodes.push({ parent, node: element.props?.children }); + } + } + } + nodes.push({ parent: nextParent, node: children }); + }); + } + + return treeMap; +}; + function isIterableElement(node: ReactNode): node is JSX.Element { return isValidElement(node) || Array.isArray(node); } From e7bf831061532baa8d06f9776c1eaa4a67427e7c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 26 Nov 2020 16:48:50 +0100 Subject: [PATCH 05/45] core-api: add plugin instance collection utility Co-authored-by: blam --- .../core-api/src/plugin/collection.test.tsx | 85 +++++++++++++++++++ packages/core-api/src/plugin/collection.ts | 72 ++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 packages/core-api/src/plugin/collection.test.tsx create mode 100644 packages/core-api/src/plugin/collection.ts diff --git a/packages/core-api/src/plugin/collection.test.tsx b/packages/core-api/src/plugin/collection.test.tsx new file mode 100644 index 0000000000..cb123cd2b1 --- /dev/null +++ b/packages/core-api/src/plugin/collection.test.tsx @@ -0,0 +1,85 @@ +/* + * 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, { PropsWithChildren } from 'react'; +import { createRouteRef } from '../routing'; +import { createPlugin } from '../plugin'; +import { + createRoutableExtension, + createComponentExtension, +} from '../lib/extensions'; +import { MemoryRouter, Routes, Route } from 'react-router-dom'; +import { collectPlugins } from './collection'; + +const mockConfig = () => ({ path: '/foo', title: 'Foo' }); +const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}; + +const pluginA = createPlugin({ id: 'my-plugin-a' }); +const pluginB = createPlugin({ id: 'my-plugin-b' }); +const pluginC = createPlugin({ id: 'my-plugin-c' }); + +const ref1 = createRouteRef(mockConfig()); +const ref2 = createRouteRef(mockConfig()); + +const Extension1 = pluginA.provide( + createRoutableExtension({ component: MockComponent, mountPoint: ref1 }), +); +const Extension2 = pluginB.provide( + createRoutableExtension({ component: MockComponent, mountPoint: ref2 }), +); +const Extension3 = pluginA.provide( + createComponentExtension({ component: MockComponent }), +); +const Extension4 = pluginB.provide( + createComponentExtension({ component: MockComponent }), +); +const Extension5 = pluginC.provide( + createComponentExtension({ component: MockComponent }), +); + +describe('collection', () => { + it('should collect the plugins', () => { + const root = ( + + + +
+ +
+
+ {[]} + Some text here shouldn't be a problem +
+ {null} +
+ +
+ + {false} + {true} + {0} +
+ +
+ } /> +
+ + + ); + + expect(collectPlugins(root)).toEqual(new Set([pluginA, pluginB, pluginC])); + }); +}); diff --git a/packages/core-api/src/plugin/collection.ts b/packages/core-api/src/plugin/collection.ts new file mode 100644 index 0000000000..23139deac4 --- /dev/null +++ b/packages/core-api/src/plugin/collection.ts @@ -0,0 +1,72 @@ +/* + * 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. + */ +/* + * 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, { isValidElement, ReactNode } from 'react'; +import { BackstagePlugin } from './types'; +import { getComponentData } from '../lib/componentData'; + +export const collectPlugins = (tree: ReactNode) => { + const plugins = new Set(); + + const nodes = [tree]; + + while (nodes.length !== 0) { + const node = nodes.shift(); + if (!isIterableElement(node)) { + continue; + } + + React.Children.forEach(node, child => { + if (!isIterableElement(child)) { + return; + } + + const { element, children } = child.props as { + element?: ReactNode; + children?: ReactNode; + }; + const plugin = getComponentData(child, 'core.plugin'); + if (plugin) { + plugins.add(plugin); + } + if (isIterableElement(element)) { + nodes.push(element); + } + nodes.push(children); + }); + } + + return plugins; +}; + +function isIterableElement(node: ReactNode): node is JSX.Element { + return isValidElement(node) || Array.isArray(node); +} From 9cf15f6baa62bf08a506f2eaf91e8995b1f910d6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 26 Nov 2020 16:54:36 +0100 Subject: [PATCH 06/45] core-api: move extension and component data utils into extensions/ Co-authored-by: blam --- .../componentData.test.tsx | 0 .../src/{lib => extensions}/componentData.tsx | 0 .../{lib => extensions}/extensions.test.tsx | 0 .../src/{lib => extensions}/extensions.tsx | 0 packages/core-api/src/extensions/index.ts | 22 +++++++++++++++++++ .../core-api/src/plugin/collection.test.tsx | 2 +- packages/core-api/src/plugin/collection.ts | 2 +- .../core-api/src/routing/discovery.test.tsx | 2 +- packages/core-api/src/routing/discovery.tsx | 2 +- 9 files changed, 26 insertions(+), 4 deletions(-) rename packages/core-api/src/{lib => extensions}/componentData.test.tsx (100%) rename packages/core-api/src/{lib => extensions}/componentData.tsx (100%) rename packages/core-api/src/{lib => extensions}/extensions.test.tsx (100%) rename packages/core-api/src/{lib => extensions}/extensions.tsx (100%) create mode 100644 packages/core-api/src/extensions/index.ts diff --git a/packages/core-api/src/lib/componentData.test.tsx b/packages/core-api/src/extensions/componentData.test.tsx similarity index 100% rename from packages/core-api/src/lib/componentData.test.tsx rename to packages/core-api/src/extensions/componentData.test.tsx diff --git a/packages/core-api/src/lib/componentData.tsx b/packages/core-api/src/extensions/componentData.tsx similarity index 100% rename from packages/core-api/src/lib/componentData.tsx rename to packages/core-api/src/extensions/componentData.tsx diff --git a/packages/core-api/src/lib/extensions.test.tsx b/packages/core-api/src/extensions/extensions.test.tsx similarity index 100% rename from packages/core-api/src/lib/extensions.test.tsx rename to packages/core-api/src/extensions/extensions.test.tsx diff --git a/packages/core-api/src/lib/extensions.tsx b/packages/core-api/src/extensions/extensions.tsx similarity index 100% rename from packages/core-api/src/lib/extensions.tsx rename to packages/core-api/src/extensions/extensions.tsx diff --git a/packages/core-api/src/extensions/index.ts b/packages/core-api/src/extensions/index.ts new file mode 100644 index 0000000000..26a0c597b1 --- /dev/null +++ b/packages/core-api/src/extensions/index.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. + */ + +export { attachComponentData, getComponentData } from './componentData'; +export { + createReactExtension, + createRoutableExtension, + createComponentExtension, +} from './extensions'; diff --git a/packages/core-api/src/plugin/collection.test.tsx b/packages/core-api/src/plugin/collection.test.tsx index cb123cd2b1..fd94303ef4 100644 --- a/packages/core-api/src/plugin/collection.test.tsx +++ b/packages/core-api/src/plugin/collection.test.tsx @@ -20,7 +20,7 @@ import { createPlugin } from '../plugin'; import { createRoutableExtension, createComponentExtension, -} from '../lib/extensions'; +} from '../extensions'; import { MemoryRouter, Routes, Route } from 'react-router-dom'; import { collectPlugins } from './collection'; diff --git a/packages/core-api/src/plugin/collection.ts b/packages/core-api/src/plugin/collection.ts index 23139deac4..0811f66445 100644 --- a/packages/core-api/src/plugin/collection.ts +++ b/packages/core-api/src/plugin/collection.ts @@ -31,7 +31,7 @@ import React, { isValidElement, ReactNode } from 'react'; import { BackstagePlugin } from './types'; -import { getComponentData } from '../lib/componentData'; +import { getComponentData } from '../extensions'; export const collectPlugins = (tree: ReactNode) => { const plugins = new Set(); diff --git a/packages/core-api/src/routing/discovery.test.tsx b/packages/core-api/src/routing/discovery.test.tsx index 02c80297c0..be553d9ce5 100644 --- a/packages/core-api/src/routing/discovery.test.tsx +++ b/packages/core-api/src/routing/discovery.test.tsx @@ -18,7 +18,7 @@ import React, { PropsWithChildren } from 'react'; import { collectRoutes, collectRouteParents } from './discovery'; import { createRouteRef } from './RouteRef'; import { createPlugin } from '../plugin'; -import { createRoutableExtension } from '../lib/extensions'; +import { createRoutableExtension } from '../extensions'; import { MemoryRouter, Routes, Route } from 'react-router-dom'; const mockConfig = () => ({ path: '/foo', title: 'Foo' }); diff --git a/packages/core-api/src/routing/discovery.tsx b/packages/core-api/src/routing/discovery.tsx index 96946e1ca3..973c96e420 100644 --- a/packages/core-api/src/routing/discovery.tsx +++ b/packages/core-api/src/routing/discovery.tsx @@ -16,7 +16,7 @@ import React, { isValidElement, ReactNode } from 'react'; import { RouteRef } from './types'; -import { getComponentData } from '../lib/componentData'; +import { getComponentData } from '../extensions'; export const collectRoutes = (tree: ReactNode) => { const treeMap = new Map(); From 3bc19b75e8783f0c07bf58a20ae7a2ea795834b3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 26 Nov 2020 17:48:32 +0100 Subject: [PATCH 07/45] core-api: refactor route discovery to use common traversal function Co-authored-by: blam --- packages/core-api/src/routing/discovery.tsx | 166 ++++++++++---------- 1 file changed, 87 insertions(+), 79 deletions(-) diff --git a/packages/core-api/src/routing/discovery.tsx b/packages/core-api/src/routing/discovery.tsx index 973c96e420..65983a8a77 100644 --- a/packages/core-api/src/routing/discovery.tsx +++ b/packages/core-api/src/routing/discovery.tsx @@ -18,54 +18,75 @@ import React, { isValidElement, ReactNode } from 'react'; import { RouteRef } from './types'; import { getComponentData } from '../extensions'; -export const collectRoutes = (tree: ReactNode) => { - const treeMap = new Map(); +type TraverseFunc = ( + node: JSX.Element, + context: Context, +) => Generator< + Context extends undefined + ? { children: JSX.Element; context?: Context } + : { children: JSX.Element; context: Context }, + void, + void +>; +function traverse( + root: ReactNode, + initialContext: Context, + traverseFunc: TraverseFunc, +): void { const visited = new Set(); - const nodes = [tree]; + const nodes = [{ children: root, context: initialContext }]; while (nodes.length !== 0) { - const node = nodes.shift(); - if (!isIterableElement(node)) { - continue; - } - if (visited.has(node)) { - const anyType = node?.type as - | { displayName?: string; name?: string } - | undefined; - const name = anyType?.displayName || anyType?.name || String(anyType); - throw new Error(`Visited element ${name} twice`); - } - visited.add(node); + const { children, context } = nodes.shift()!; - React.Children.forEach(node, child => { + React.Children.forEach(children, child => { if (!isIterableElement(child)) { return; } - - const { path, element, children } = child.props as { - path?: string; - element?: ReactNode; - children?: ReactNode; - }; - if (path) { - const routeRef = getComponentData(child, 'core.mountPoint'); - if (routeRef) { - treeMap.set(routeRef, path); - } else if (isIterableElement(element)) { - const elementRouteRef = getComponentData( - element, - 'core.mountPoint', - ); - if (elementRouteRef) { - treeMap.set(elementRouteRef, path); - } - nodes.push(element.props?.children); - } + if (visited.has(child)) { + const anyType = child?.type as + | { displayName?: string; name?: string } + | undefined; + const name = anyType?.displayName || anyType?.name || String(anyType); + throw new Error(`Visited element ${name} twice`); + } + visited.add(child); + + for (const next of traverseFunc(child, context)) { + nodes.push(next as { children: JSX.Element; context: Context }); } - nodes.push(children); }); } +} + +export const collectRoutes = (tree: ReactNode) => { + const treeMap = new Map(); + + traverse(tree, undefined, function* traverseFunc(node) { + const { path, element, children } = node.props as { + path?: string; + element?: ReactNode; + children?: ReactNode; + }; + if (path) { + const routeRef = getComponentData(node, 'core.mountPoint'); + if (routeRef) { + treeMap.set(routeRef, path); + } else if (isIterableElement(element)) { + const elementRouteRef = getComponentData( + element, + 'core.mountPoint', + ); + if (elementRouteRef) { + treeMap.set(elementRouteRef, path); + } + yield { children: element.props?.children }; + } + } + + yield { children }; + }); return treeMap; }; @@ -73,53 +94,40 @@ export const collectRoutes = (tree: ReactNode) => { export const collectRouteParents = (tree: ReactNode) => { const treeMap = new Map(); - const nodes = [{ node: tree, parent: undefined as RouteRef | undefined }]; + traverse(tree, undefined, function* traverseFunc( + node, + parent, + ) { + const { path, element, children } = node.props as { + path?: string; + element?: ReactNode; + children?: ReactNode; + }; - while (nodes.length !== 0) { - const { parent, node } = nodes.shift()!; - if (!isIterableElement(node)) { - continue; - } + let nextParent = parent; - React.Children.forEach(node, child => { - if (!isIterableElement(child)) { - return; - } + if (path) { + const routeRef = getComponentData(node, 'core.mountPoint'); + if (routeRef) { + treeMap.set(routeRef, parent); + nextParent = routeRef; + } else if (isIterableElement(element)) { + const elementRouteRef = getComponentData( + element, + 'core.mountPoint', + ); - const { path, element, children } = child.props as { - path?: string; - element?: ReactNode; - children?: ReactNode; - }; - - let nextParent = parent; - - if (path) { - const routeRef = getComponentData(child, 'core.mountPoint'); - if (routeRef) { - treeMap.set(routeRef, parent); - nextParent = routeRef; - } else if (isIterableElement(element)) { - const elementRouteRef = getComponentData( - element, - 'core.mountPoint', - ); - if (elementRouteRef) { - treeMap.set(elementRouteRef, parent); - - nextParent = elementRouteRef; - nodes.push({ - parent: elementRouteRef, - node: element.props?.children, - }); - } else { - nodes.push({ parent, node: element.props?.children }); - } + if (elementRouteRef) { + treeMap.set(elementRouteRef, parent); + nextParent = elementRouteRef; + yield { children: element.props?.children, context: elementRouteRef }; + } else { + yield { children: element.props?.children, context: parent }; } } - nodes.push({ parent: nextParent, node: children }); - }); - } + } + yield { children, context: nextParent }; + }); return treeMap; }; From 9cced997b22930df77521d586979d227a462b856 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 26 Nov 2020 18:12:02 +0100 Subject: [PATCH 08/45] core-api: refactor routing element traversal to not skip over elements Co-authored-by: blam --- packages/core-api/src/routing/discovery.tsx | 123 +++++++++++--------- 1 file changed, 71 insertions(+), 52 deletions(-) diff --git a/packages/core-api/src/routing/discovery.tsx b/packages/core-api/src/routing/discovery.tsx index 65983a8a77..b925c8349d 100644 --- a/packages/core-api/src/routing/discovery.tsx +++ b/packages/core-api/src/routing/discovery.tsx @@ -14,34 +14,44 @@ * limitations under the License. */ -import React, { isValidElement, ReactNode } from 'react'; +import { isValidElement, ReactNode, ReactElement, Children } from 'react'; import { RouteRef } from './types'; import { getComponentData } from '../extensions'; type TraverseFunc = ( - node: JSX.Element, + node: ReactElement, + parent: ReactElement, context: Context, ) => Generator< Context extends undefined - ? { children: JSX.Element; context?: Context } - : { children: JSX.Element; context: Context }, + ? { children: ReactNode; context?: Context } + : { children: ReactNode; context: Context }, void, void >; -function traverse( - root: ReactNode, - initialContext: Context, +function traverse( + options: { root: ReactElement; initialContext?: Context }, traverseFunc: TraverseFunc, ): void { const visited = new Set(); - const nodes = [{ children: root, context: initialContext }]; + const nodes: Array<{ + children: ReactNode; + parent: ReactElement; + context: Context; + }> = [ + { + children: Children.toArray(options.root), + parent: options.root, + context: options.initialContext!, + }, + ]; while (nodes.length !== 0) { - const { children, context } = nodes.shift()!; + const { children, parent, context } = nodes.shift()!; - React.Children.forEach(children, child => { - if (!isIterableElement(child)) { + Children.forEach(children, child => { + if (!isValidElement(child)) { return; } if (visited.has(child)) { @@ -53,36 +63,48 @@ function traverse( } visited.add(child); - for (const next of traverseFunc(child, context)) { - nodes.push(next as { children: JSX.Element; context: Context }); + for (const next of traverseFunc(child, parent, context)) { + nodes.push({ + children: next.children, + context: next.context!, + parent: child, + }); } }); } } -export const collectRoutes = (tree: ReactNode) => { +export const collectRoutes = (root: ReactElement) => { const treeMap = new Map(); - traverse(tree, undefined, function* traverseFunc(node) { + traverse({ root }, function* traverseFunc(node, parent: ReactElement) { const { path, element, children } = node.props as { path?: string; element?: ReactNode; children?: ReactNode; }; - if (path) { - const routeRef = getComponentData(node, 'core.mountPoint'); - if (routeRef) { - treeMap.set(routeRef, path); - } else if (isIterableElement(element)) { - const elementRouteRef = getComponentData( - element, - 'core.mountPoint', - ); - if (elementRouteRef) { - treeMap.set(elementRouteRef, path); - } - yield { children: element.props?.children }; + if (parent.props.element === node) { + yield { children }; + return; + } + const routeRef = getComponentData(node, 'core.mountPoint'); + if (routeRef) { + if (!path) { + throw new Error('Mounted routable extension must have a path'); } + treeMap.set(routeRef, path); + } else if (isValidElement(element)) { + const elementRouteRef = getComponentData( + element, + 'core.mountPoint', + ); + if (elementRouteRef) { + if (!path) { + throw new Error('Route element must have a path'); + } + treeMap.set(elementRouteRef, path); + } + yield { children: element }; } yield { children }; @@ -91,47 +113,44 @@ export const collectRoutes = (tree: ReactNode) => { return treeMap; }; -export const collectRouteParents = (tree: ReactNode) => { +export const collectRouteParents = (root: ReactElement) => { const treeMap = new Map(); - traverse(tree, undefined, function* traverseFunc( - node, - parent, - ) { - const { path, element, children } = node.props as { - path?: string; - element?: ReactNode; - children?: ReactNode; - }; + traverse( + { root, initialContext: undefined }, + function* traverseFunc(node, parent, parentRouteRef) { + const { element, children } = node.props as { + element?: ReactNode; + children?: ReactNode; + }; + if (parent.props.element === node) { + yield { children }; + return; + } - let nextParent = parent; + let nextParent = parentRouteRef; - if (path) { const routeRef = getComponentData(node, 'core.mountPoint'); if (routeRef) { - treeMap.set(routeRef, parent); + treeMap.set(routeRef, parentRouteRef); nextParent = routeRef; - } else if (isIterableElement(element)) { + } else if (isValidElement(element)) { const elementRouteRef = getComponentData( element, 'core.mountPoint', ); if (elementRouteRef) { - treeMap.set(elementRouteRef, parent); + treeMap.set(elementRouteRef, parentRouteRef); nextParent = elementRouteRef; - yield { children: element.props?.children, context: elementRouteRef }; + yield { children: element, context: elementRouteRef }; } else { - yield { children: element.props?.children, context: parent }; + yield { children: element, context: parentRouteRef }; } } - } - yield { children, context: nextParent }; - }); + yield { children, context: nextParent }; + }, + ); return treeMap; }; - -function isIterableElement(node: ReactNode): node is JSX.Element { - return isValidElement(node) || Array.isArray(node); -} From bcc211a0816cef546a25501e210e12bebb996920 Mon Sep 17 00:00:00 2001 From: Moustafa Baiou Date: Tue, 1 Dec 2020 00:31:13 -0500 Subject: [PATCH 09/45] refactor(k8s-plugin): update to use annotation based label selector add changeset --- .changeset/strange-stingrays-enjoy.md | 7 +++ .../src/kinds/ComponentEntityV1alpha1.ts | 16 ------ .../examples/dice-roller/README.md | 2 +- .../src/cluster-locator/index.test.ts | 2 +- .../src/cluster-locator/index.ts | 2 +- ...ubernetesObjectsByServiceIdHandler.test.ts | 57 +++++++++++-------- .../getKubernetesObjectsForServiceHandler.ts | 18 ++---- plugins/kubernetes-backend/src/types/types.ts | 4 +- plugins/kubernetes/README.md | 29 ++++------ .../KubernetesContent/KubernetesContent.tsx | 4 +- 10 files changed, 64 insertions(+), 77 deletions(-) create mode 100644 .changeset/strange-stingrays-enjoy.md diff --git a/.changeset/strange-stingrays-enjoy.md b/.changeset/strange-stingrays-enjoy.md new file mode 100644 index 0000000000..26b42a5611 --- /dev/null +++ b/.changeset/strange-stingrays-enjoy.md @@ -0,0 +1,7 @@ +--- +'@backstage/catalog-model': minor +'@backstage/plugin-kubernetes': patch +'@backstage/plugin-kubernetes-backend': patch +--- + +k8s-plugin: refactor approach to use annotation based label-selector diff --git a/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.ts b/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.ts index 5fd4f88537..680674f16e 100644 --- a/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.ts +++ b/packages/catalog-model/src/kinds/ComponentEntityV1alpha1.ts @@ -32,15 +32,6 @@ const schema = yup.object>({ implementsApis: yup.array(yup.string().required()).notRequired(), providesApis: yup.array(yup.string().required()).notRequired(), consumesApis: yup.array(yup.string().required()).notRequired(), - kubernetes: yup - .object({ - selector: yup - .object({ - matchLabels: yup.object().required(), - }) - .required(), - }) - .notRequired(), }) .required(), }); @@ -60,13 +51,6 @@ export interface ComponentEntityV1alpha1 extends Entity { implementsApis?: string[]; providesApis?: string[]; consumesApis?: string[]; - kubernetes?: { - selector: { - matchLabels: { - [key: string]: string; - }; - }; - }; }; } diff --git a/plugins/kubernetes-backend/examples/dice-roller/README.md b/plugins/kubernetes-backend/examples/dice-roller/README.md index bf3e7d261a..5f541bb61d 100644 --- a/plugins/kubernetes-backend/examples/dice-roller/README.md +++ b/plugins/kubernetes-backend/examples/dice-roller/README.md @@ -42,7 +42,7 @@ kubernetes: Mac copy to clipboard: ``` -kubectl get secret $(kubectl get sa dice-roller -o=json | jq -r .secrets[0].name) -o=json | jq -r '.data["token"]' | base64 --decode | pbcopy +kubectl get secret $(kubectl get sa dice-roller -o=json | jq -r '.secrets[0].name') -o=json | jq -r '.data["token"]' | base64 --decode | pbcopy ``` Paste into `app-config.local.yaml` `kubernetes.clusters[0].serviceAccountToken` diff --git a/plugins/kubernetes-backend/src/cluster-locator/index.test.ts b/plugins/kubernetes-backend/src/cluster-locator/index.test.ts index 32a09cb496..5677fa2d0d 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/index.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/index.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Config, ConfigReader } from '../../../../packages/config/src'; +import { Config, ConfigReader } from '@backstage/config'; import { getCombinedClusterDetails } from './index'; describe('getCombinedClusterDetails', () => { diff --git a/plugins/kubernetes-backend/src/cluster-locator/index.ts b/plugins/kubernetes-backend/src/cluster-locator/index.ts index ea418768b4..9e6558510c 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/index.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/index.ts @@ -15,7 +15,7 @@ */ import { ClusterDetails, ClusterLocatorMethod } from '..'; -import { Config } from '../../../../packages/config/src'; +import { Config } from '@backstage/config'; import { ConfigClusterLocator } from './ConfigClusterLocator'; export { ConfigClusterLocator } from './ConfigClusterLocator'; diff --git a/plugins/kubernetes-backend/src/service/getKubernetesObjectsByServiceIdHandler.test.ts b/plugins/kubernetes-backend/src/service/getKubernetesObjectsByServiceIdHandler.test.ts index adebebe1c5..5c6513e57c 100644 --- a/plugins/kubernetes-backend/src/service/getKubernetesObjectsByServiceIdHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/getKubernetesObjectsByServiceIdHandler.test.ts @@ -16,7 +16,6 @@ import { handleGetKubernetesObjectsForService } from './getKubernetesObjectsForServiceHandler'; import { getVoidLogger } from '@backstage/backend-common'; -import { ComponentEntityV1alpha1 } from '@backstage/catalog-model'; import { ObjectFetchParams } from '..'; const TEST_SERVICE_ID = 'my-service'; @@ -25,26 +24,6 @@ const fetchObjectsForService = jest.fn(); const getClustersByServiceId = jest.fn(); -const goodEntity: ComponentEntityV1alpha1 = { - apiVersion: 'backstage.io/v1beta1', - kind: 'Component', - metadata: { - name: 'test-component', - }, - spec: { - type: 'service', - lifecycle: 'production', - owner: 'joe', - kubernetes: { - selector: { - matchLabels: { - 'backstage.io/test-label': 'test-component', - }, - }, - }, - }, -}; - const mockFetch = (mock: jest.Mock) => { mock.mockImplementation((params: ObjectFetchParams) => Promise.resolve({ @@ -111,7 +90,24 @@ describe('handleGetKubernetesObjectsForService', () => { getClustersByServiceId, }, getVoidLogger(), - { entity: goodEntity }, + { + entity: { + apiVersion: 'backstage.io/v1beta1', + kind: 'Component', + metadata: { + name: 'test-component', + annotations: { + 'backstage.io/kubernetes-labels-selector': + 'backstage.io/test-label=test-component', + }, + }, + spec: { + type: 'service', + lifecycle: 'production', + owner: 'joe', + }, + }, + }, ); expect(getClustersByServiceId.mock.calls.length).toBe(1); @@ -186,10 +182,25 @@ describe('handleGetKubernetesObjectsForService', () => { }, getVoidLogger(), { - entity: goodEntity, auth: { google: 'google_token_123', }, + entity: { + apiVersion: 'backstage.io/v1beta1', + kind: 'Component', + metadata: { + name: 'test-component', + annotations: { + 'backstage.io/kubernetes-labels-selector': + 'backstage.io/test-label=test-component', + }, + }, + spec: { + type: 'service', + lifecycle: 'production', + owner: 'joe', + }, + }, }, ); diff --git a/plugins/kubernetes-backend/src/service/getKubernetesObjectsForServiceHandler.ts b/plugins/kubernetes-backend/src/service/getKubernetesObjectsForServiceHandler.ts index 82220f5d6c..2dd1e32b96 100644 --- a/plugins/kubernetes-backend/src/service/getKubernetesObjectsForServiceHandler.ts +++ b/plugins/kubernetes-backend/src/service/getKubernetesObjectsForServiceHandler.ts @@ -15,7 +15,6 @@ */ import { Logger } from 'winston'; -import { ComponentEntityV1alpha1 } from '@backstage/catalog-model'; import { KubernetesRequestBody, ClusterDetails, @@ -47,18 +46,6 @@ const DEFAULT_OBJECTS = new Set([ 'ingresses', ]); -function parseLabelSelector(entity: ComponentEntityV1alpha1): string { - const matchLabels = entity?.spec?.kubernetes?.selector?.matchLabels; - if (matchLabels) { - // TODO: figure out how to convert the selector to the full query param from the yaml - // (as shown here https://github.com/kubernetes/apimachinery/blob/master/pkg/labels/selector.go) - return Object.keys(matchLabels) - .map(key => `${key}=${matchLabels[key.toString()]}`) - .join(','); - } - return ''; -} - // Fans out the request to all clusters that the service lives in, aggregates their responses together export const handleGetKubernetesObjectsForService: GetKubernetesObjectsForServiceHandler = async ( serviceId, @@ -92,7 +79,10 @@ export const handleGetKubernetesObjectsForService: GetKubernetesObjectsForServic .join(', ')}]`, ); - const labelSelector = parseLabelSelector(requestBody.entity); + const labelSelector: string = + requestBody.entity?.metadata?.annotations?.[ + 'backstage.io/kubernetes-label-selector' + ] || `backstage.io/kubernetes-id=${requestBody.entity.metadata.name}`; return Promise.all( clusterDetailsDecoratedForAuth.map(clusterDetails => { diff --git a/plugins/kubernetes-backend/src/types/types.ts b/plugins/kubernetes-backend/src/types/types.ts index b2a5ef432c..9f0b90c032 100644 --- a/plugins/kubernetes-backend/src/types/types.ts +++ b/plugins/kubernetes-backend/src/types/types.ts @@ -23,7 +23,7 @@ import { V1ReplicaSet, V1Service, } from '@kubernetes/client-node'; -import { ComponentEntityV1alpha1 } from '@backstage/catalog-model'; +import { Entity } from '@backstage/catalog-model'; export interface ClusterDetails { name: string; @@ -36,7 +36,7 @@ export interface KubernetesRequestBody { auth?: { google?: string; }; - entity: ComponentEntityV1alpha1; + entity: Entity; } export interface ClusterObjects { diff --git a/plugins/kubernetes/README.md b/plugins/kubernetes/README.md index 8f3542a46e..a343764b70 100644 --- a/plugins/kubernetes/README.md +++ b/plugins/kubernetes/README.md @@ -17,23 +17,7 @@ It is only meant for local development, and the setup for it can be found inside There are two ways to surface your kubernetes components as part of an entity. The label selector takes precedence over the annotation/service id. -### Full label selector - -#### Adding the entity label selector to the spec - -In order for Backstage to detect that an entity has kubernetes components the `kubernetes.selector` must have a valid selector. (Currently only matchLabels is supported) - -```yaml -spec: - kubernetes: - selector: - matchLabels: - someKey: someValue - other-key: other-value - app.kubernetes.io/name: dice-roller -``` - -### Common `backstage.io/kubernetes-id` label on objects +### Common `backstage.io/kubernetes-id` label #### Adding the entity annotation @@ -53,3 +37,14 @@ as a part of an entity, Kubernetes components must be labeled with the following ```yaml 'backstage.io/kubernetes-id': ``` + +### label selector query annotation + +#### Adding a label selector query annotation + +You can write your own custom label selector query that backstage will use to lookup the objects (similar to `kubectl --selector="your query here"`) +review the documentation [here](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) for more info + +```yaml +'backstage.io/kubernetes-label-selector': 'app=my-app,component=front-end' +``` diff --git a/plugins/kubernetes/src/components/KubernetesContent/KubernetesContent.tsx b/plugins/kubernetes/src/components/KubernetesContent/KubernetesContent.tsx index 14cda3b5f7..65c1102d47 100644 --- a/plugins/kubernetes/src/components/KubernetesContent/KubernetesContent.tsx +++ b/plugins/kubernetes/src/components/KubernetesContent/KubernetesContent.tsx @@ -26,7 +26,7 @@ import { TabbedCard, useApi, } from '@backstage/core'; -import { ComponentEntityV1alpha1, Entity } from '@backstage/catalog-model'; +import { Entity } from '@backstage/catalog-model'; import { kubernetesApiRef } from '../../api/types'; import { KubernetesRequestBody, @@ -121,7 +121,7 @@ export const KubernetesContent = ({ entity }: KubernetesContentProps) => { (async () => { // For each auth type, invoke decorateRequestBodyForAuth on corresponding KubernetesAuthProvider let requestBody: KubernetesRequestBody = { - entity: entity as ComponentEntityV1alpha1, + entity, }; for (const authProviderStr of authProviders) { // Multiple asyncs done sequentially instead of all at once to prevent same requestBody from being modified simultaneously From da42f58fae727c6457ce42d133ac8b3325a6239a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 1 Dec 2020 14:27:16 +0100 Subject: [PATCH 10/45] catalog-model: update ownership of data --- .../catalog-model/examples/acme/team-a-group.yaml | 14 ++++++++++++++ .../examples/apis/hello-world-api.yaml | 2 +- .../catalog-model/examples/apis/petstore-api.yaml | 2 +- .../catalog-model/examples/apis/spotify-api.yaml | 2 +- .../examples/apis/streetlights-api.yaml | 2 +- .../catalog-model/examples/apis/swapi-graphql.yaml | 2 +- .../components/artist-lookup-component.yaml | 2 +- .../examples/components/petstore-component.yaml | 2 +- .../components/playback-lib-component.yaml | 2 +- .../components/playback-order-component.yaml | 2 +- .../examples/components/podcast-api-component.yaml | 2 +- .../examples/components/queue-proxy-component.yaml | 2 +- .../examples/components/searcher-component.yaml | 2 +- .../examples/components/shuffle-api-component.yaml | 2 +- .../examples/components/www-artist-component.yaml | 2 +- plugins/catalog/src/components/useOwnUser.ts | 9 +++++---- 16 files changed, 33 insertions(+), 18 deletions(-) diff --git a/packages/catalog-model/examples/acme/team-a-group.yaml b/packages/catalog-model/examples/acme/team-a-group.yaml index dacc4c6c3c..8dbf0bb839 100644 --- a/packages/catalog-model/examples/acme/team-a-group.yaml +++ b/packages/catalog-model/examples/acme/team-a-group.yaml @@ -42,3 +42,17 @@ spec: email: nigel-manning@example.com picture: https://example.com/staff/nigel.jpeg memberOf: [team-a] +--- +# This user is added as an example, to make it more easy for the "Guest" +# sign-in option to demonstrate some entities being owned. In a regular org, +# a guest user would probably not be registered like this. +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: guest +spec: + profile: + displayName: Guest User + email: guest@example.com + picture: https://example.com/staff/the-ceos-dog.jpeg + memberOf: [team-a] diff --git a/packages/catalog-model/examples/apis/hello-world-api.yaml b/packages/catalog-model/examples/apis/hello-world-api.yaml index 659c48adfb..0f9786329f 100644 --- a/packages/catalog-model/examples/apis/hello-world-api.yaml +++ b/packages/catalog-model/examples/apis/hello-world-api.yaml @@ -6,7 +6,7 @@ metadata: spec: type: grpc lifecycle: deprecated - owner: grpc@example.com + owner: team-c definition: | // Copyright 2015 gRPC authors. // diff --git a/packages/catalog-model/examples/apis/petstore-api.yaml b/packages/catalog-model/examples/apis/petstore-api.yaml index c8ce576cce..a314b4e255 100644 --- a/packages/catalog-model/examples/apis/petstore-api.yaml +++ b/packages/catalog-model/examples/apis/petstore-api.yaml @@ -9,7 +9,7 @@ metadata: spec: type: openapi lifecycle: experimental - owner: pets@example.com + owner: team-c definition: | openapi: "3.0.0" info: diff --git a/packages/catalog-model/examples/apis/spotify-api.yaml b/packages/catalog-model/examples/apis/spotify-api.yaml index 14deb17abe..0b8e80b86e 100644 --- a/packages/catalog-model/examples/apis/spotify-api.yaml +++ b/packages/catalog-model/examples/apis/spotify-api.yaml @@ -12,6 +12,6 @@ metadata: spec: type: openapi lifecycle: production - owner: spotify@example.com + owner: team-a definition: $text: https://github.com/APIs-guru/openapi-directory/blob/master/APIs/spotify.com/v1/swagger.yaml diff --git a/packages/catalog-model/examples/apis/streetlights-api.yaml b/packages/catalog-model/examples/apis/streetlights-api.yaml index d53b05fc2d..725811d0cc 100644 --- a/packages/catalog-model/examples/apis/streetlights-api.yaml +++ b/packages/catalog-model/examples/apis/streetlights-api.yaml @@ -8,7 +8,7 @@ metadata: spec: type: asyncapi lifecycle: production - owner: streetlights@example.com + owner: team-c definition: | asyncapi: 2.0.0 info: diff --git a/packages/catalog-model/examples/apis/swapi-graphql.yaml b/packages/catalog-model/examples/apis/swapi-graphql.yaml index bc5e8e60ac..0c1f7af5a4 100644 --- a/packages/catalog-model/examples/apis/swapi-graphql.yaml +++ b/packages/catalog-model/examples/apis/swapi-graphql.yaml @@ -6,7 +6,7 @@ metadata: spec: type: graphql lifecycle: production - owner: yoda@dagobah.space + owner: team-b definition: | schema { query: Root diff --git a/packages/catalog-model/examples/components/artist-lookup-component.yaml b/packages/catalog-model/examples/components/artist-lookup-component.yaml index 79dd3bccf6..257344be3d 100644 --- a/packages/catalog-model/examples/components/artist-lookup-component.yaml +++ b/packages/catalog-model/examples/components/artist-lookup-component.yaml @@ -9,4 +9,4 @@ metadata: spec: type: service lifecycle: experimental - owner: artists@example.com + owner: team-a diff --git a/packages/catalog-model/examples/components/petstore-component.yaml b/packages/catalog-model/examples/components/petstore-component.yaml index 7e2093ad09..e6dd56c274 100644 --- a/packages/catalog-model/examples/components/petstore-component.yaml +++ b/packages/catalog-model/examples/components/petstore-component.yaml @@ -6,7 +6,7 @@ metadata: spec: type: service lifecycle: experimental - owner: pets@example.com + owner: team-c implementsApis: - petstore - streetlights diff --git a/packages/catalog-model/examples/components/playback-lib-component.yaml b/packages/catalog-model/examples/components/playback-lib-component.yaml index c32332d4d2..f7d7670b5d 100644 --- a/packages/catalog-model/examples/components/playback-lib-component.yaml +++ b/packages/catalog-model/examples/components/playback-lib-component.yaml @@ -6,4 +6,4 @@ metadata: spec: type: library lifecycle: experimental - owner: players@example.com + owner: team-c diff --git a/packages/catalog-model/examples/components/playback-order-component.yaml b/packages/catalog-model/examples/components/playback-order-component.yaml index 3e46953928..c4f41b2b58 100644 --- a/packages/catalog-model/examples/components/playback-order-component.yaml +++ b/packages/catalog-model/examples/components/playback-order-component.yaml @@ -9,4 +9,4 @@ metadata: spec: type: service lifecycle: production - owner: guest + owner: user:guest diff --git a/packages/catalog-model/examples/components/podcast-api-component.yaml b/packages/catalog-model/examples/components/podcast-api-component.yaml index c1b1c9281c..b89ff48c48 100644 --- a/packages/catalog-model/examples/components/podcast-api-component.yaml +++ b/packages/catalog-model/examples/components/podcast-api-component.yaml @@ -8,4 +8,4 @@ metadata: spec: type: service lifecycle: experimental - owner: players@example.com + owner: team-b diff --git a/packages/catalog-model/examples/components/queue-proxy-component.yaml b/packages/catalog-model/examples/components/queue-proxy-component.yaml index c9b130db52..7f7fcbd527 100644 --- a/packages/catalog-model/examples/components/queue-proxy-component.yaml +++ b/packages/catalog-model/examples/components/queue-proxy-component.yaml @@ -9,4 +9,4 @@ metadata: spec: type: website lifecycle: production - owner: tools@example.com + owner: team-b diff --git a/packages/catalog-model/examples/components/searcher-component.yaml b/packages/catalog-model/examples/components/searcher-component.yaml index 042fcb24a9..77150c96f0 100644 --- a/packages/catalog-model/examples/components/searcher-component.yaml +++ b/packages/catalog-model/examples/components/searcher-component.yaml @@ -8,4 +8,4 @@ metadata: spec: type: service lifecycle: production - owner: guest + owner: user:guest diff --git a/packages/catalog-model/examples/components/shuffle-api-component.yaml b/packages/catalog-model/examples/components/shuffle-api-component.yaml index 1f9de46d4e..1c2da03511 100644 --- a/packages/catalog-model/examples/components/shuffle-api-component.yaml +++ b/packages/catalog-model/examples/components/shuffle-api-component.yaml @@ -8,4 +8,4 @@ metadata: spec: type: service lifecycle: production - owner: guest + owner: user:guest diff --git a/packages/catalog-model/examples/components/www-artist-component.yaml b/packages/catalog-model/examples/components/www-artist-component.yaml index 84379c93fc..c333eb8c09 100644 --- a/packages/catalog-model/examples/components/www-artist-component.yaml +++ b/packages/catalog-model/examples/components/www-artist-component.yaml @@ -6,4 +6,4 @@ metadata: spec: type: website lifecycle: production - owner: artists@example.com + owner: team-a diff --git a/plugins/catalog/src/components/useOwnUser.ts b/plugins/catalog/src/components/useOwnUser.ts index a74b60481e..9aa4bda99c 100644 --- a/plugins/catalog/src/components/useOwnUser.ts +++ b/plugins/catalog/src/components/useOwnUser.ts @@ -21,20 +21,21 @@ import { identityApiRef, useApi } from '@backstage/core'; import { catalogApiRef } from '../plugin'; /** - * Get the group memberships of the logged-in user. + * Get the catalog User entity (if any) that matches the logged-in user. */ -export function useOwnUser(): AsyncState { +export function useOwnUser(): AsyncState { const catalogApi = useApi(catalogApiRef); const identityApi = useApi(identityApiRef); - // TODO: get the full entity (or at least the full entity name) from the identityApi + // TODO: get the full entity (or at least the full entity name) from the + // identityApi return useAsync( () => catalogApi.getEntityByName({ kind: 'User', namespace: 'default', name: identityApi.getUserId(), - }) as Promise, + }) as Promise, [catalogApi, identityApi], ); } From 706868141eafb9d5e5626ad29595b6d5e5ba979e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 26 Nov 2020 19:22:59 +0100 Subject: [PATCH 11/45] core-api: refactor route discovery to do a single pluggable sweep --- .../core-api/src/routing/discovery.test.tsx | 51 +++- packages/core-api/src/routing/discovery.tsx | 224 +++++++++++------- 2 files changed, 175 insertions(+), 100 deletions(-) diff --git a/packages/core-api/src/routing/discovery.test.tsx b/packages/core-api/src/routing/discovery.test.tsx index be553d9ce5..c702811529 100644 --- a/packages/core-api/src/routing/discovery.test.tsx +++ b/packages/core-api/src/routing/discovery.test.tsx @@ -15,7 +15,13 @@ */ import React, { PropsWithChildren } from 'react'; -import { collectRoutes, collectRouteParents } from './discovery'; +import { + traverseElementTree, + childDiscoverer, + routeElementDiscoverer, + routeCollector, + routeParentCollector, +} from './discovery'; import { createRouteRef } from './RouteRef'; import { createPlugin } from '../plugin'; import { createRoutableExtension } from '../extensions'; @@ -86,7 +92,15 @@ describe('discovery', () => { ); - expect(collectRoutes(root)).toEqual( + const { routes, routeParents } = traverseElementTree({ + root, + discoverers: [childDiscoverer, routeElementDiscoverer], + collectors: { + routes: routeCollector, + routeParents: routeParentCollector, + }, + }); + expect(routes).toEqual( new Map([ [ref1, '/foo'], [ref2, '/bar/:id'], @@ -96,7 +110,7 @@ describe('discovery', () => { ]), ); - expect(collectRouteParents(root)).toEqual( + expect(routeParents).toEqual( new Map([ [ref1, undefined], [ref2, ref1], @@ -129,7 +143,15 @@ describe('discovery', () => { ); - expect(collectRoutes(root)).toEqual( + const { routes, routeParents } = traverseElementTree({ + root, + discoverers: [childDiscoverer, routeElementDiscoverer], + collectors: { + routes: routeCollector, + routeParents: routeParentCollector, + }, + }); + expect(routes).toEqual( new Map([ [ref1, '/foo'], [ref2, '/bar/:id'], @@ -138,7 +160,7 @@ describe('discovery', () => { [ref5, '/blop'], ]), ); - expect(collectRouteParents(root)).toEqual( + expect(routeParents).toEqual( new Map([ [ref1, undefined], [ref2, ref1], @@ -153,12 +175,19 @@ describe('discovery', () => { const element = ; expect(() => - collectRoutes( - - {element} - {element} - , - ), + traverseElementTree({ + root: ( + + {element} + {element} + + ), + discoverers: [childDiscoverer, routeElementDiscoverer], + collectors: { + routes: routeCollector, + routeParents: routeParentCollector, + }, + }), ).toThrow(`Visited element Extension(MockComponent) twice`); }); }); diff --git a/packages/core-api/src/routing/discovery.tsx b/packages/core-api/src/routing/discovery.tsx index b925c8349d..0189ae3a4e 100644 --- a/packages/core-api/src/routing/discovery.tsx +++ b/packages/core-api/src/routing/discovery.tsx @@ -18,81 +18,143 @@ import { isValidElement, ReactNode, ReactElement, Children } from 'react'; import { RouteRef } from './types'; import { getComponentData } from '../extensions'; -type TraverseFunc = ( - node: ReactElement, - parent: ReactElement, - context: Context, -) => Generator< - Context extends undefined - ? { children: ReactNode; context?: Context } - : { children: ReactNode; context: Context }, - void, - void ->; +type Discoverer = (element: ReactElement) => ReactNode; -function traverse( - options: { root: ReactElement; initialContext?: Context }, - traverseFunc: TraverseFunc, -): void { +type Collector = () => { + accumulator: Result; + visit( + accumulator: Result, + element: ReactElement, + parent: ReactElement, + context: Context, + ): Context; +}; + +/** + * A function that allows you to traverse a tree of React elements using + * varying methods to discover child nodes and collect data along the way. + */ +export function traverseElementTree(options: { + root: ReactElement; + discoverers: Discoverer[]; + collectors: { [name in keyof Results]: Collector }; +}): Results { const visited = new Set(); - const nodes: Array<{ - children: ReactNode; + const collectors: { + [name in string]: ReturnType>; + } = {}; + + // Bootstrap all collectors, initializing the accumulators and providing the visitor function + for (const name in options.collectors) { + if (options.collectors.hasOwnProperty(name)) { + collectors[name] = options.collectors[name](); + } + } + + // Internal representation of an element in the tree that we're iterating over + type QueueItem = { + node: ReactNode; parent: ReactElement; - context: Context; - }> = [ + contexts: { [name in string]: unknown }; + }; + + const queue = [ { - children: Children.toArray(options.root), + node: Children.toArray(options.root), parent: options.root, - context: options.initialContext!, - }, + contexts: {}, + } as QueueItem, ]; - while (nodes.length !== 0) { - const { children, parent, context } = nodes.shift()!; + while (queue.length !== 0) { + const { node, parent, contexts } = queue.shift()!; - Children.forEach(children, child => { - if (!isValidElement(child)) { + // While the parent and the element we pass on to collectors and discoverers + // have been validated and are known to be React elements, the child nodes + // emitted by the discoverers are not. + Children.forEach(node, element => { + if (!isValidElement(element)) { return; } - if (visited.has(child)) { - const anyType = child?.type as + if (visited.has(element)) { + const anyType = element?.type as | { displayName?: string; name?: string } | undefined; const name = anyType?.displayName || anyType?.name || String(anyType); throw new Error(`Visited element ${name} twice`); } - visited.add(child); + visited.add(element); - for (const next of traverseFunc(child, parent, context)) { - nodes.push({ - children: next.children, - context: next.context!, - parent: child, - }); + const nextContexts: QueueItem['contexts'] = {}; + + // Collectors populate their result data using the current node, and compute + // context for the next iteration + for (const name in collectors) { + if (collectors.hasOwnProperty(name)) { + const collector = collectors[name]; + + nextContexts[name] = collector.visit( + collector.accumulator, + element, + parent, + contexts[name], + ); + } + } + + // Discoverers provide ways to continue the traversal from the current element + for (const discoverer of options.discoverers) { + const children = discoverer(element); + if (children) { + queue.push({ + node: children, + parent: element, + contexts: nextContexts, + }); + } } }); } + + return Object.fromEntries( + Object.entries(collectors).map(([name, c]) => [name, c.accumulator]), + ) as Results; } -export const collectRoutes = (root: ReactElement) => { - const treeMap = new Map(); +export function childDiscoverer(element: ReactElement): ReactNode { + return element.props?.children; +} - traverse({ root }, function* traverseFunc(node, parent: ReactElement) { - const { path, element, children } = node.props as { - path?: string; - element?: ReactNode; - children?: ReactNode; - }; +export function routeElementDiscoverer(element: ReactElement): ReactNode { + if (element.props?.path && element.props?.element) { + return element.props?.element; + } + return undefined; +} + +function createCollector( + initialResult: Result, + visit: ReturnType>['visit'], +): Collector { + return () => ({ accumulator: initialResult, visit }); +} + +export const routeCollector = createCollector( + new Map(), + (acc, node, parent) => { if (parent.props.element === node) { - yield { children }; return; } + + const path: string | undefined = node.props?.path; + const element: ReactNode = node.props?.element; + const routeRef = getComponentData(node, 'core.mountPoint'); if (routeRef) { if (!path) { throw new Error('Mounted routable extension must have a path'); } - treeMap.set(routeRef, path); + acc.set(routeRef, path); } else if (isValidElement(element)) { const elementRouteRef = getComponentData( element, @@ -102,55 +164,39 @@ export const collectRoutes = (root: ReactElement) => { if (!path) { throw new Error('Route element must have a path'); } - treeMap.set(elementRouteRef, path); + acc.set(elementRouteRef, path); } - yield { children: element }; + } + }, +); + +export const routeParentCollector = createCollector( + new Map(), + (acc, node, parent, parentRouteRef?: RouteRef) => { + if (parent.props.element === node) { + return parentRouteRef; } - yield { children }; - }); + const element: ReactNode = node.props?.element; - return treeMap; -}; + let nextParent = parentRouteRef; -export const collectRouteParents = (root: ReactElement) => { - const treeMap = new Map(); + const routeRef = getComponentData(node, 'core.mountPoint'); + if (routeRef) { + acc.set(routeRef, parentRouteRef); + nextParent = routeRef; + } else if (isValidElement(element)) { + const elementRouteRef = getComponentData( + element, + 'core.mountPoint', + ); - traverse( - { root, initialContext: undefined }, - function* traverseFunc(node, parent, parentRouteRef) { - const { element, children } = node.props as { - element?: ReactNode; - children?: ReactNode; - }; - if (parent.props.element === node) { - yield { children }; - return; + if (elementRouteRef) { + acc.set(elementRouteRef, parentRouteRef); + nextParent = elementRouteRef; } + } - let nextParent = parentRouteRef; - - const routeRef = getComponentData(node, 'core.mountPoint'); - if (routeRef) { - treeMap.set(routeRef, parentRouteRef); - nextParent = routeRef; - } else if (isValidElement(element)) { - const elementRouteRef = getComponentData( - element, - 'core.mountPoint', - ); - - if (elementRouteRef) { - treeMap.set(elementRouteRef, parentRouteRef); - nextParent = elementRouteRef; - yield { children: element, context: elementRouteRef }; - } else { - yield { children: element, context: parentRouteRef }; - } - } - yield { children, context: nextParent }; - }, - ); - - return treeMap; -}; + return nextParent; + }, +); From 26ed08c1679de2ccc8205f417a83889a90002133 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 27 Nov 2020 11:41:59 +0100 Subject: [PATCH 12/45] core-api: refactor all element data collection to use the same traversal facilities Co-authored-by: blam --- .../src/extensions/traversal.test.tsx | 98 +++++++++++++++++++ .../discovery.tsx => extensions/traversal.ts} | 82 ++-------------- ...ollection.test.tsx => collectors.test.tsx} | 19 +++- .../plugin/{collection.ts => collectors.ts} | 46 ++------- ...discovery.test.tsx => collectors.test.tsx} | 6 +- packages/core-api/src/routing/collectors.tsx | 82 ++++++++++++++++ 6 files changed, 217 insertions(+), 116 deletions(-) create mode 100644 packages/core-api/src/extensions/traversal.test.tsx rename packages/core-api/src/{routing/discovery.tsx => extensions/traversal.ts} (68%) rename packages/core-api/src/plugin/{collection.test.tsx => collectors.test.tsx} (84%) rename packages/core-api/src/plugin/{collection.ts => collectors.ts} (58%) rename packages/core-api/src/routing/{discovery.test.tsx => collectors.test.tsx} (98%) create mode 100644 packages/core-api/src/routing/collectors.tsx diff --git a/packages/core-api/src/extensions/traversal.test.tsx b/packages/core-api/src/extensions/traversal.test.tsx new file mode 100644 index 0000000000..a69ee9de77 --- /dev/null +++ b/packages/core-api/src/extensions/traversal.test.tsx @@ -0,0 +1,98 @@ +/* + * 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, { Children, isValidElement } from 'react'; +import { + childDiscoverer, + createCollector, + traverseElementTree, +} from './traversal'; + +describe('discovery', () => { + it('should collect element names', () => { + const root = ( +
+
+

Title

+

Text

+
+
+
+

Title

+ Text +
+
+ ); + + const { names } = traverseElementTree({ + root, + discoverers: [childDiscoverer], + collectors: { + names: createCollector(Array(), (acc, el) => { + if (typeof el.type === 'string') { + acc.push(el.type); + } + }), + }, + }); + + expect(names).toEqual([ + 'main', + 'div', + 'hr', + 'div', + 'h1', + 'p', + 'h2', + 'span', + ]); + }); + + it('should collect element names while skipping one level of children', () => { + const root = ( +
+
+

Title

+

Text

+
+
+
+

Title

+ Text +
+
+ ); + + const { names } = traverseElementTree({ + root, + discoverers: [ + el => + Children.toArray(el.props.children).flatMap(child => + isValidElement(child) ? child?.props?.children : [], + ), + ], + collectors: { + names: createCollector(Array(), (acc, el) => { + if (typeof el.type === 'string') { + acc.push(el.type); + } + }), + }, + }); + + expect(names).toEqual(['main', 'h1', 'p', 'h2', 'span']); + }); +}); diff --git a/packages/core-api/src/routing/discovery.tsx b/packages/core-api/src/extensions/traversal.ts similarity index 68% rename from packages/core-api/src/routing/discovery.tsx rename to packages/core-api/src/extensions/traversal.ts index 0189ae3a4e..a1fbdab25a 100644 --- a/packages/core-api/src/routing/discovery.tsx +++ b/packages/core-api/src/extensions/traversal.ts @@ -15,12 +15,10 @@ */ import { isValidElement, ReactNode, ReactElement, Children } from 'react'; -import { RouteRef } from './types'; -import { getComponentData } from '../extensions'; -type Discoverer = (element: ReactElement) => ReactNode; +export type Discoverer = (element: ReactElement) => ReactNode; -type Collector = () => { +export type Collector = () => { accumulator: Result; visit( accumulator: Result, @@ -121,6 +119,13 @@ export function traverseElementTree(options: { ) as Results; } +export function createCollector( + initialResult: Result, + visit: ReturnType>['visit'], +): Collector { + return () => ({ accumulator: initialResult, visit }); +} + export function childDiscoverer(element: ReactElement): ReactNode { return element.props?.children; } @@ -131,72 +136,3 @@ export function routeElementDiscoverer(element: ReactElement): ReactNode { } return undefined; } - -function createCollector( - initialResult: Result, - visit: ReturnType>['visit'], -): Collector { - return () => ({ accumulator: initialResult, visit }); -} - -export const routeCollector = createCollector( - new Map(), - (acc, node, parent) => { - if (parent.props.element === node) { - return; - } - - const path: string | undefined = node.props?.path; - const element: ReactNode = node.props?.element; - - const routeRef = getComponentData(node, 'core.mountPoint'); - if (routeRef) { - if (!path) { - throw new Error('Mounted routable extension must have a path'); - } - acc.set(routeRef, path); - } else if (isValidElement(element)) { - const elementRouteRef = getComponentData( - element, - 'core.mountPoint', - ); - if (elementRouteRef) { - if (!path) { - throw new Error('Route element must have a path'); - } - acc.set(elementRouteRef, path); - } - } - }, -); - -export const routeParentCollector = createCollector( - new Map(), - (acc, node, parent, parentRouteRef?: RouteRef) => { - if (parent.props.element === node) { - return parentRouteRef; - } - - const element: ReactNode = node.props?.element; - - let nextParent = parentRouteRef; - - const routeRef = getComponentData(node, 'core.mountPoint'); - if (routeRef) { - acc.set(routeRef, parentRouteRef); - nextParent = routeRef; - } else if (isValidElement(element)) { - const elementRouteRef = getComponentData( - element, - 'core.mountPoint', - ); - - if (elementRouteRef) { - acc.set(elementRouteRef, parentRouteRef); - nextParent = elementRouteRef; - } - } - - return nextParent; - }, -); diff --git a/packages/core-api/src/plugin/collection.test.tsx b/packages/core-api/src/plugin/collectors.test.tsx similarity index 84% rename from packages/core-api/src/plugin/collection.test.tsx rename to packages/core-api/src/plugin/collectors.test.tsx index fd94303ef4..f040cfd433 100644 --- a/packages/core-api/src/plugin/collection.test.tsx +++ b/packages/core-api/src/plugin/collectors.test.tsx @@ -16,13 +16,18 @@ import React, { PropsWithChildren } from 'react'; import { createRouteRef } from '../routing'; -import { createPlugin } from '../plugin'; +import { createPlugin } from './Plugin'; import { createRoutableExtension, createComponentExtension, } from '../extensions'; import { MemoryRouter, Routes, Route } from 'react-router-dom'; -import { collectPlugins } from './collection'; +import { + traverseElementTree, + childDiscoverer, + routeElementDiscoverer, +} from '../extensions/traversal'; +import { pluginCollector } from './collectors'; const mockConfig = () => ({ path: '/foo', title: 'Foo' }); const MockComponent = ({ children }: PropsWithChildren<{}>) => <>{children}; @@ -80,6 +85,14 @@ describe('collection', () => { ); - expect(collectPlugins(root)).toEqual(new Set([pluginA, pluginB, pluginC])); + const { plugins } = traverseElementTree({ + root, + discoverers: [childDiscoverer, routeElementDiscoverer], + collectors: { + plugins: pluginCollector, + }, + }); + + expect(plugins).toEqual(new Set([pluginA, pluginB, pluginC])); }); }); diff --git a/packages/core-api/src/plugin/collection.ts b/packages/core-api/src/plugin/collectors.ts similarity index 58% rename from packages/core-api/src/plugin/collection.ts rename to packages/core-api/src/plugin/collectors.ts index 0811f66445..a222746f9e 100644 --- a/packages/core-api/src/plugin/collection.ts +++ b/packages/core-api/src/plugin/collectors.ts @@ -29,44 +29,16 @@ * limitations under the License. */ -import React, { isValidElement, ReactNode } from 'react'; import { BackstagePlugin } from './types'; import { getComponentData } from '../extensions'; +import { createCollector } from '../extensions/traversal'; -export const collectPlugins = (tree: ReactNode) => { - const plugins = new Set(); - - const nodes = [tree]; - - while (nodes.length !== 0) { - const node = nodes.shift(); - if (!isIterableElement(node)) { - continue; +export const pluginCollector = createCollector( + new Set(), + (acc, node) => { + const plugin = getComponentData(node, 'core.plugin'); + if (plugin) { + acc.add(plugin); } - - React.Children.forEach(node, child => { - if (!isIterableElement(child)) { - return; - } - - const { element, children } = child.props as { - element?: ReactNode; - children?: ReactNode; - }; - const plugin = getComponentData(child, 'core.plugin'); - if (plugin) { - plugins.add(plugin); - } - if (isIterableElement(element)) { - nodes.push(element); - } - nodes.push(children); - }); - } - - return plugins; -}; - -function isIterableElement(node: ReactNode): node is JSX.Element { - return isValidElement(node) || Array.isArray(node); -} + }, +); diff --git a/packages/core-api/src/routing/discovery.test.tsx b/packages/core-api/src/routing/collectors.test.tsx similarity index 98% rename from packages/core-api/src/routing/discovery.test.tsx rename to packages/core-api/src/routing/collectors.test.tsx index c702811529..c2eefa7e82 100644 --- a/packages/core-api/src/routing/discovery.test.tsx +++ b/packages/core-api/src/routing/collectors.test.tsx @@ -15,13 +15,13 @@ */ import React, { PropsWithChildren } from 'react'; +import { routeCollector, routeParentCollector } from './collectors'; + import { traverseElementTree, childDiscoverer, routeElementDiscoverer, - routeCollector, - routeParentCollector, -} from './discovery'; +} from '../extensions/traversal'; import { createRouteRef } from './RouteRef'; import { createPlugin } from '../plugin'; import { createRoutableExtension } from '../extensions'; diff --git a/packages/core-api/src/routing/collectors.tsx b/packages/core-api/src/routing/collectors.tsx new file mode 100644 index 0000000000..fab0cbe112 --- /dev/null +++ b/packages/core-api/src/routing/collectors.tsx @@ -0,0 +1,82 @@ +/* + * 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 { isValidElement, ReactNode } from 'react'; +import { RouteRef } from '../routing/types'; +import { getComponentData } from '../extensions'; +import { createCollector } from '../extensions/traversal'; + +export const routeCollector = createCollector( + new Map(), + (acc, node, parent) => { + if (parent.props.element === node) { + return; + } + + const path: string | undefined = node.props?.path; + const element: ReactNode = node.props?.element; + + const routeRef = getComponentData(node, 'core.mountPoint'); + if (routeRef) { + if (!path) { + throw new Error('Mounted routable extension must have a path'); + } + acc.set(routeRef, path); + } else if (isValidElement(element)) { + const elementRouteRef = getComponentData( + element, + 'core.mountPoint', + ); + if (elementRouteRef) { + if (!path) { + throw new Error('Route element must have a path'); + } + acc.set(elementRouteRef, path); + } + } + }, +); + +export const routeParentCollector = createCollector( + new Map(), + (acc, node, parent, parentRouteRef?: RouteRef) => { + if (parent.props.element === node) { + return parentRouteRef; + } + + const element: ReactNode = node.props?.element; + + let nextParent = parentRouteRef; + + const routeRef = getComponentData(node, 'core.mountPoint'); + if (routeRef) { + acc.set(routeRef, parentRouteRef); + nextParent = routeRef; + } else if (isValidElement(element)) { + const elementRouteRef = getComponentData( + element, + 'core.mountPoint', + ); + + if (elementRouteRef) { + acc.set(elementRouteRef, parentRouteRef); + nextParent = elementRouteRef; + } + } + + return nextParent; + }, +); From c9544afa010a7d36fe9db8e0d1604aab69244e12 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 1 Dec 2020 20:23:02 +0100 Subject: [PATCH 13/45] scripts/verify-links: forbid relative links out of docs --- docs/auth/index.md | 2 +- scripts/verify-links.js | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/auth/index.md b/docs/auth/index.md index 3f95efaf61..cf468c7bb7 100644 --- a/docs/auth/index.md +++ b/docs/auth/index.md @@ -93,6 +93,6 @@ sign-in methods. More details are provided in dedicated sections of the documentation. - [OAuth](./oauth.md): Description of the generic OAuth flow implemented by the - [auth-backend](../../plugins/auth-backend). + [auth-backend](https://github.com/backstage/backstage/tree/master/plugins/auth-backend). - [Glossary](./glossary.md): Glossary of some common terms related to the auth flows. diff --git a/scripts/verify-links.js b/scripts/verify-links.js index 0422352d4e..ac2941c1fd 100755 --- a/scripts/verify-links.js +++ b/scripts/verify-links.js @@ -74,6 +74,14 @@ async function verifyUrl(basePath, absUrl, docPages) { path = resolvePath(dirname(resolvePath(projectRoot, basePath)), url); } + if ( + absUrl === url && + basePath.match(/^(?:docs)\//) && + !path.startsWith(resolvePath(projectRoot, 'docs')) + ) { + return { url, basePath, problem: 'out-of-docs' }; + } + const exists = await fs.pathExists(path); if (!exists) { return { url, basePath, problem: 'missing' }; @@ -148,6 +156,18 @@ async function main() { console.error( `Unable to reach ${url} from root or microsite/static/, linked from ${basePath}`, ); + } else if (problem === 'out-of-docs') { + console.error( + 'Links in docks must use absolute URLs for targets outside of docs', + ); + console.error(` From: ${basePath}`); + console.error(` To: ${url}`); + console.error( + ` Likely replace with: https://github.com/backstage/backstage/blob/master/${url.replace( + /^[./]+/, + '', + )}`, + ); } else if (problem === 'doc-missing') { const suggestion = docPages.get(url) || From a7f944880b0e50de9a03cb173c02aaa5acfc1257 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Tue, 1 Dec 2020 14:55:15 -0500 Subject: [PATCH 14/45] Refactor to support ADR004 module exporting --- plugins/circleci/src/api/CircleCI.ts | 95 +++++++++++ plugins/circleci/src/api/index.ts | 80 +-------- plugins/jenkins/src/api/JenkinsApi.ts | 233 ++++++++++++++++++++++++++ plugins/jenkins/src/api/index.ts | 218 +----------------------- 4 files changed, 330 insertions(+), 296 deletions(-) create mode 100644 plugins/circleci/src/api/CircleCI.ts create mode 100644 plugins/jenkins/src/api/JenkinsApi.ts diff --git a/plugins/circleci/src/api/CircleCI.ts b/plugins/circleci/src/api/CircleCI.ts new file mode 100644 index 0000000000..c71be6b781 --- /dev/null +++ b/plugins/circleci/src/api/CircleCI.ts @@ -0,0 +1,95 @@ +/* + * 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 { + CircleCIOptions, + getMe, + getBuildSummaries, + getFullBuild, + postBuildActions, + BuildAction, + BuildWithSteps, + BuildStepAction, + BuildSummary, + GitType, +} from 'circleci-api'; +import { createApiRef, DiscoveryApi } from '@backstage/core'; + +export { GitType }; +export type { BuildWithSteps, BuildStepAction, BuildSummary }; + +export const circleCIApiRef = createApiRef({ + id: 'plugin.circleci.service', + description: 'Used by the CircleCI plugin to make requests', +}); + +const DEFAULT_PROXY_PATH = '/circleci/api'; + +type Options = { + discoveryApi: DiscoveryApi; + /** + * Path to use for requests via the proxy, defaults to /circleci/api + */ + proxyPath?: string; +}; + +export class CircleCIApi { + private readonly discoveryApi: DiscoveryApi; + private readonly proxyPath: string; + + constructor(options: Options) { + this.discoveryApi = options.discoveryApi; + this.proxyPath = options.proxyPath ?? DEFAULT_PROXY_PATH; + } + + async retry(buildNumber: number, options: Partial) { + return postBuildActions('', buildNumber, BuildAction.RETRY, { + circleHost: await this.getApiUrl(), + ...options.vcs, + }); + } + + async getBuilds( + { limit = 10, offset = 0 }: { limit: number; offset: number }, + options: Partial, + ) { + return getBuildSummaries('', { + options: { + limit, + offset, + }, + vcs: {}, + circleHost: await this.getApiUrl(), + ...options, + }); + } + + async getUser(options: Partial) { + return getMe('', { circleHost: await this.getApiUrl(), ...options }); + } + + async getBuild(buildNumber: number, options: Partial) { + return getFullBuild('', buildNumber, { + circleHost: await this.getApiUrl(), + ...options.vcs, + }); + } + + private async getApiUrl() { + const proxyUrl = await this.discoveryApi.getBaseUrl('proxy'); + return proxyUrl + this.proxyPath; + } +} diff --git a/plugins/circleci/src/api/index.ts b/plugins/circleci/src/api/index.ts index c71be6b781..cf7319ec06 100644 --- a/plugins/circleci/src/api/index.ts +++ b/plugins/circleci/src/api/index.ts @@ -14,82 +14,4 @@ * limitations under the License. */ -import { - CircleCIOptions, - getMe, - getBuildSummaries, - getFullBuild, - postBuildActions, - BuildAction, - BuildWithSteps, - BuildStepAction, - BuildSummary, - GitType, -} from 'circleci-api'; -import { createApiRef, DiscoveryApi } from '@backstage/core'; - -export { GitType }; -export type { BuildWithSteps, BuildStepAction, BuildSummary }; - -export const circleCIApiRef = createApiRef({ - id: 'plugin.circleci.service', - description: 'Used by the CircleCI plugin to make requests', -}); - -const DEFAULT_PROXY_PATH = '/circleci/api'; - -type Options = { - discoveryApi: DiscoveryApi; - /** - * Path to use for requests via the proxy, defaults to /circleci/api - */ - proxyPath?: string; -}; - -export class CircleCIApi { - private readonly discoveryApi: DiscoveryApi; - private readonly proxyPath: string; - - constructor(options: Options) { - this.discoveryApi = options.discoveryApi; - this.proxyPath = options.proxyPath ?? DEFAULT_PROXY_PATH; - } - - async retry(buildNumber: number, options: Partial) { - return postBuildActions('', buildNumber, BuildAction.RETRY, { - circleHost: await this.getApiUrl(), - ...options.vcs, - }); - } - - async getBuilds( - { limit = 10, offset = 0 }: { limit: number; offset: number }, - options: Partial, - ) { - return getBuildSummaries('', { - options: { - limit, - offset, - }, - vcs: {}, - circleHost: await this.getApiUrl(), - ...options, - }); - } - - async getUser(options: Partial) { - return getMe('', { circleHost: await this.getApiUrl(), ...options }); - } - - async getBuild(buildNumber: number, options: Partial) { - return getFullBuild('', buildNumber, { - circleHost: await this.getApiUrl(), - ...options.vcs, - }); - } - - private async getApiUrl() { - const proxyUrl = await this.discoveryApi.getBaseUrl('proxy'); - return proxyUrl + this.proxyPath; - } -} +export * from './CircleCI'; diff --git a/plugins/jenkins/src/api/JenkinsApi.ts b/plugins/jenkins/src/api/JenkinsApi.ts new file mode 100644 index 0000000000..0fa48a1d17 --- /dev/null +++ b/plugins/jenkins/src/api/JenkinsApi.ts @@ -0,0 +1,233 @@ +/* + * 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 { createApiRef, DiscoveryApi } from '@backstage/core'; +import { CITableBuildInfo } from '../components/BuildsPage/lib/CITable'; + +const jenkins = require('jenkins'); + +export const jenkinsApiRef = createApiRef({ + id: 'plugin.jenkins.service', + description: 'Used by the Jenkins plugin to make requests', +}); + +const DEFAULT_PROXY_PATH = '/jenkins/api'; + +type Options = { + discoveryApi: DiscoveryApi; + /** + * Path to use for requests via the proxy, defaults to /jenkins/api + */ + proxyPath?: string; +}; + +export class JenkinsApi { + private readonly discoveryApi: DiscoveryApi; + private readonly proxyPath: string; + + constructor(options: Options) { + this.discoveryApi = options.discoveryApi; + this.proxyPath = options.proxyPath ?? DEFAULT_PROXY_PATH; + } + + private async getClient() { + const proxyUrl = await this.discoveryApi.getBaseUrl('proxy'); + return jenkins({ baseUrl: proxyUrl + this.proxyPath, promisify: true }); + } + + async retry(buildName: string) { + const client = await this.getClient(); + // looks like the current SDK only supports triggering a new build + // can't see any support for replay (re-running the specific build with the same SCM info) + return await client.job.build(buildName); + } + + async getLastBuild(jobName: string) { + const client = await this.getClient(); + const job = await client.job.get(jobName); + + const lastBuild = await client.build.get(jobName, job.lastBuild.number); + return lastBuild; + } + + extractScmDetailsFromJob(jobDetails: any): any { + const scmInfo = jobDetails.actions + .filter( + (action: any) => + action._class === 'jenkins.scm.api.metadata.ObjectMetadataAction', + ) + .map((action: any) => { + return { + url: action?.objectUrl, + // https://javadoc.jenkins.io/plugin/scm-api/jenkins/scm/api/metadata/ObjectMetadataAction.html + // branch name for regular builds, pull request title on pull requests + displayName: action?.objectDisplayName, + }; + }) + .pop(); + + const author = jobDetails.actions + .filter( + (action: any) => + action._class === + 'jenkins.scm.api.metadata.ContributorMetadataAction', + ) + .map((action: any) => { + return action.contributorDisplayName; + }) + .pop(); + + if (author) { + scmInfo.author = author; + } + + return scmInfo; + } + + async getJob(jobName: string) { + const client = await this.getClient(); + return client.job.get({ + name: jobName, + depth: 1, + }); + } + + async getFolder(folderName: string) { + const client = await this.getClient(); + const folder = await client.job.get(folderName); + const results = []; + for (const jobSummary of folder.jobs) { + const jobDetails = await client.job.get({ + name: `${folderName}/${jobSummary.name}`, + depth: 1, + }); + + const jobScmInfo = this.extractScmDetailsFromJob(jobDetails); + if (jobDetails.jobs) { + // skipping folders inside folders for now + } else { + for (const buildDetails of jobDetails.builds) { + const build = await client.build.get({ + name: `${folderName}/${jobSummary.name}`, + number: buildDetails.number, + depth: 1, + }); + + const ciTable = this.mapJenkinsBuildToCITable(build, jobScmInfo); + results.push(ciTable); + } + } + } + return results; + } + + private getTestReport( + jenkinsResult: any, + ): { + total: number; + passed: number; + skipped: number; + failed: number; + testUrl: string; + } { + return jenkinsResult.actions + .filter( + (action: any) => + action._class === 'hudson.tasks.junit.TestResultAction', + ) + .map((action: any) => { + return { + total: action.totalCount, + passed: action.totalCount - action.failCount - action.skipCount, + skipped: action.skipCount, + failed: action.failCount, + testUrl: `${jenkinsResult.url}${action.urlName}/`, + }; + }) + .pop(); + } + + mapJenkinsBuildToCITable( + jenkinsResult: any, + jobScmInfo?: any, + ): CITableBuildInfo { + const source = + jenkinsResult.actions + .filter( + (action: any) => + action._class === 'hudson.plugins.git.util.BuildData', + ) + .map((action: any) => { + const [first]: any = Object.values(action.buildsByBranchName); + const branch = first.revision.branch[0]; + return { + branchName: branch.name, + commit: { + hash: branch.SHA1.substring(0, 8), + }, + }; + }) + .pop() || {}; + + if (jobScmInfo) { + source.url = jobScmInfo?.url; + source.displayName = jobScmInfo?.displayName; + source.author = jobScmInfo?.author; + } + + const path = new URL(jenkinsResult.url).pathname; + + return { + id: path, + buildNumber: jenkinsResult.number, + buildUrl: jenkinsResult.url, + buildName: jenkinsResult.fullDisplayName, + status: jenkinsResult.building ? 'running' : jenkinsResult.result, + onRestartClick: () => { + // TODO: this won't handle non root context path, need a better way to get the job name + const { jobName } = this.extractJobDetailsFromBuildName(path); + return this.retry(jobName); + }, + source: source, + tests: this.getTestReport(jenkinsResult), + }; + } + + async getBuild(buildName: string) { + const client = await this.getClient(); + const { jobName, buildNumber } = this.extractJobDetailsFromBuildName( + buildName, + ); + const buildResult = await client.build.get(jobName, buildNumber); + return buildResult; + } + + extractJobDetailsFromBuildName(buildName: string) { + const trimmedBuild = buildName.replace(/\/job/g, '').replace(/\/$/, ''); + + const split = trimmedBuild.split('/'); + const buildNumber = parseInt(split[split.length - 1], 10); + const jobName = trimmedBuild.slice( + 0, + trimmedBuild.length - buildNumber.toString(10).length - 1, + ); + + return { + jobName, + buildNumber, + }; + } +} diff --git a/plugins/jenkins/src/api/index.ts b/plugins/jenkins/src/api/index.ts index 0fa48a1d17..5c0b073eb8 100644 --- a/plugins/jenkins/src/api/index.ts +++ b/plugins/jenkins/src/api/index.ts @@ -14,220 +14,4 @@ * limitations under the License. */ -import { createApiRef, DiscoveryApi } from '@backstage/core'; -import { CITableBuildInfo } from '../components/BuildsPage/lib/CITable'; - -const jenkins = require('jenkins'); - -export const jenkinsApiRef = createApiRef({ - id: 'plugin.jenkins.service', - description: 'Used by the Jenkins plugin to make requests', -}); - -const DEFAULT_PROXY_PATH = '/jenkins/api'; - -type Options = { - discoveryApi: DiscoveryApi; - /** - * Path to use for requests via the proxy, defaults to /jenkins/api - */ - proxyPath?: string; -}; - -export class JenkinsApi { - private readonly discoveryApi: DiscoveryApi; - private readonly proxyPath: string; - - constructor(options: Options) { - this.discoveryApi = options.discoveryApi; - this.proxyPath = options.proxyPath ?? DEFAULT_PROXY_PATH; - } - - private async getClient() { - const proxyUrl = await this.discoveryApi.getBaseUrl('proxy'); - return jenkins({ baseUrl: proxyUrl + this.proxyPath, promisify: true }); - } - - async retry(buildName: string) { - const client = await this.getClient(); - // looks like the current SDK only supports triggering a new build - // can't see any support for replay (re-running the specific build with the same SCM info) - return await client.job.build(buildName); - } - - async getLastBuild(jobName: string) { - const client = await this.getClient(); - const job = await client.job.get(jobName); - - const lastBuild = await client.build.get(jobName, job.lastBuild.number); - return lastBuild; - } - - extractScmDetailsFromJob(jobDetails: any): any { - const scmInfo = jobDetails.actions - .filter( - (action: any) => - action._class === 'jenkins.scm.api.metadata.ObjectMetadataAction', - ) - .map((action: any) => { - return { - url: action?.objectUrl, - // https://javadoc.jenkins.io/plugin/scm-api/jenkins/scm/api/metadata/ObjectMetadataAction.html - // branch name for regular builds, pull request title on pull requests - displayName: action?.objectDisplayName, - }; - }) - .pop(); - - const author = jobDetails.actions - .filter( - (action: any) => - action._class === - 'jenkins.scm.api.metadata.ContributorMetadataAction', - ) - .map((action: any) => { - return action.contributorDisplayName; - }) - .pop(); - - if (author) { - scmInfo.author = author; - } - - return scmInfo; - } - - async getJob(jobName: string) { - const client = await this.getClient(); - return client.job.get({ - name: jobName, - depth: 1, - }); - } - - async getFolder(folderName: string) { - const client = await this.getClient(); - const folder = await client.job.get(folderName); - const results = []; - for (const jobSummary of folder.jobs) { - const jobDetails = await client.job.get({ - name: `${folderName}/${jobSummary.name}`, - depth: 1, - }); - - const jobScmInfo = this.extractScmDetailsFromJob(jobDetails); - if (jobDetails.jobs) { - // skipping folders inside folders for now - } else { - for (const buildDetails of jobDetails.builds) { - const build = await client.build.get({ - name: `${folderName}/${jobSummary.name}`, - number: buildDetails.number, - depth: 1, - }); - - const ciTable = this.mapJenkinsBuildToCITable(build, jobScmInfo); - results.push(ciTable); - } - } - } - return results; - } - - private getTestReport( - jenkinsResult: any, - ): { - total: number; - passed: number; - skipped: number; - failed: number; - testUrl: string; - } { - return jenkinsResult.actions - .filter( - (action: any) => - action._class === 'hudson.tasks.junit.TestResultAction', - ) - .map((action: any) => { - return { - total: action.totalCount, - passed: action.totalCount - action.failCount - action.skipCount, - skipped: action.skipCount, - failed: action.failCount, - testUrl: `${jenkinsResult.url}${action.urlName}/`, - }; - }) - .pop(); - } - - mapJenkinsBuildToCITable( - jenkinsResult: any, - jobScmInfo?: any, - ): CITableBuildInfo { - const source = - jenkinsResult.actions - .filter( - (action: any) => - action._class === 'hudson.plugins.git.util.BuildData', - ) - .map((action: any) => { - const [first]: any = Object.values(action.buildsByBranchName); - const branch = first.revision.branch[0]; - return { - branchName: branch.name, - commit: { - hash: branch.SHA1.substring(0, 8), - }, - }; - }) - .pop() || {}; - - if (jobScmInfo) { - source.url = jobScmInfo?.url; - source.displayName = jobScmInfo?.displayName; - source.author = jobScmInfo?.author; - } - - const path = new URL(jenkinsResult.url).pathname; - - return { - id: path, - buildNumber: jenkinsResult.number, - buildUrl: jenkinsResult.url, - buildName: jenkinsResult.fullDisplayName, - status: jenkinsResult.building ? 'running' : jenkinsResult.result, - onRestartClick: () => { - // TODO: this won't handle non root context path, need a better way to get the job name - const { jobName } = this.extractJobDetailsFromBuildName(path); - return this.retry(jobName); - }, - source: source, - tests: this.getTestReport(jenkinsResult), - }; - } - - async getBuild(buildName: string) { - const client = await this.getClient(); - const { jobName, buildNumber } = this.extractJobDetailsFromBuildName( - buildName, - ); - const buildResult = await client.build.get(jobName, buildNumber); - return buildResult; - } - - extractJobDetailsFromBuildName(buildName: string) { - const trimmedBuild = buildName.replace(/\/job/g, '').replace(/\/$/, ''); - - const split = trimmedBuild.split('/'); - const buildNumber = parseInt(split[split.length - 1], 10); - const jobName = trimmedBuild.slice( - 0, - trimmedBuild.length - buildNumber.toString(10).length - 1, - ); - - return { - jobName, - buildNumber, - }; - } -} +export * from './JenkinsApi'; From 04efbbdd2e58ce95f0173f414389630d201b6cba Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Tue, 1 Dec 2020 14:56:27 -0500 Subject: [PATCH 15/45] Add changeset --- .changeset/five-lies-smile.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/five-lies-smile.md diff --git a/.changeset/five-lies-smile.md b/.changeset/five-lies-smile.md new file mode 100644 index 0000000000..a35a2ca528 --- /dev/null +++ b/.changeset/five-lies-smile.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-circleci': patch +'@backstage/plugin-jenkins': patch +--- + +Refactor to support ADR004 module exporting. + +For more information, see https://backstage.io/docs/architecture-decisions/adrs-adr004. From 40c5b968ab1a548a65faf19efc7b098de25faad8 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Tue, 1 Dec 2020 15:06:42 -0500 Subject: [PATCH 16/45] Change package name --- plugins/circleci/src/api/{CircleCI.ts => CircleCIApi.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/circleci/src/api/{CircleCI.ts => CircleCIApi.ts} (100%) diff --git a/plugins/circleci/src/api/CircleCI.ts b/plugins/circleci/src/api/CircleCIApi.ts similarity index 100% rename from plugins/circleci/src/api/CircleCI.ts rename to plugins/circleci/src/api/CircleCIApi.ts From fe7257ff0700ffac9956435ae99da4986b61e6b1 Mon Sep 17 00:00:00 2001 From: Ryan Vazquez Date: Tue, 1 Dec 2020 15:06:59 -0500 Subject: [PATCH 17/45] enable sku breakdowns for unlabeled entities --- .changeset/cost-insights-calm-bikes-prove.md | 5 ++ .../ProductEntityDialog.tsx | 2 +- .../ProductInsightsChart.tsx | 68 +++++++------------ plugins/cost-insights/src/utils/assert.ts | 10 ++- plugins/cost-insights/src/utils/graphs.ts | 8 ++- plugins/cost-insights/src/utils/mockData.ts | 21 +++++- 6 files changed, 64 insertions(+), 50 deletions(-) create mode 100644 .changeset/cost-insights-calm-bikes-prove.md diff --git a/.changeset/cost-insights-calm-bikes-prove.md b/.changeset/cost-insights-calm-bikes-prove.md new file mode 100644 index 0000000000..179350fcd9 --- /dev/null +++ b/.changeset/cost-insights-calm-bikes-prove.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +enable SKU breakdown for unlabeled entities diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx index 4cccd638cb..c01ab67ecc 100644 --- a/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx +++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx @@ -176,7 +176,7 @@ export const ProductEntityDialog = ({ { const classes = useStyles(); const layoutClasses = useLayoutStyles(); - const [isOpen, setOpen] = useState(false); - const [isClickable, setClickable] = useState(true); - const [selectLabel, setSelected] = useState>(null); - const [activeLabel, setActive] = useState>(null); + const [activeLabel, setActive] = useState>(); + const [selectLabel, setSelected] = useState>(); + const isSelected = useMemo(() => !isUndefined(selectLabel), [selectLabel]); + const isClickable = useMemo(() => { + const skus = + entity.entities.find(e => e.id === activeLabel)?.entities ?? []; + return skus.length > 0; + }, [entity, activeLabel]); const legendTitle = `Cost ${entity.change.ratio <= 0 ? 'Savings' : 'Growth'}`; const costStart = entity.aggregation[0]; @@ -76,52 +81,25 @@ export const ProductInsightsChart = ({ currentName: formatPeriod(duration, billingDate, true), }; - useEffect(() => { - function toggleModal() { - if (selectLabel) { - setOpen(true); - } else { - setOpen(false); - } - } - - toggleModal(); - }, [selectLabel]); - - useEffect(() => { - // disable click if an entity is unlabeled or if it does not have any skus - function toggleClickableEntity() { - if (activeLabel) { - const hasSkus = entity.entities.find(e => e.id === activeLabel) - ?.entities.length; - if (hasSkus) { - setClickable(true); - } else { - setClickable(false); - } - } else { - setClickable(false); - } - } - - toggleClickableEntity(); - }, [activeLabel, entity]); - const onMouseMove: RechartsFunction = ( data: Record<'activeLabel', string | undefined>, ) => { - if (isActiveLabel(data)) { + if (isLabeled(data)) { setActive(data.activeLabel!); - } else { + } else if (isUnlabeled(data)) { setActive(null); + } else { + setActive(undefined); } }; const onClick: RechartsFunction = (data: Record<'activeLabel', string>) => { - if (isActiveLabel(data)) { + if (isLabeled(data)) { setSelected(data.activeLabel); - } else { + } else if (isUnlabeled(data)) { setSelected(null); + } else { + setSelected(undefined); } }; @@ -213,10 +191,10 @@ export const ProductInsightsChart = ({ options={options} {...barChartProps} /> - {selectLabel && entity.entities.length && ( + {isSelected && entity.entities.length && ( setSelected(null)} + open={isSelected} + onClose={() => setSelected(undefined)} entity={entity.entities.find(e => e.id === selectLabel)} options={options} /> diff --git a/plugins/cost-insights/src/utils/assert.ts b/plugins/cost-insights/src/utils/assert.ts index 8f7caef0fa..19ddabe574 100644 --- a/plugins/cost-insights/src/utils/assert.ts +++ b/plugins/cost-insights/src/utils/assert.ts @@ -17,7 +17,15 @@ export function notEmpty( value: TValue | null | undefined, ): value is TValue { - return value !== null && value !== undefined; + return !isNull(value) && !isUndefined(value); +} + +export function isUndefined(value: any): boolean { + return value === undefined; +} + +export function isNull(value: any): boolean { + return value === null; } // Utility for exhaustiveness checking in switch statements diff --git a/plugins/cost-insights/src/utils/graphs.ts b/plugins/cost-insights/src/utils/graphs.ts index ac06e20587..bc82b63f89 100644 --- a/plugins/cost-insights/src/utils/graphs.ts +++ b/plugins/cost-insights/src/utils/graphs.ts @@ -72,8 +72,12 @@ export const isInvalid = ({ label, payload }: TooltipProps) => { return label === undefined || !payload || !payload.length; }; -export const isActiveLabel = ( +export const isLabeled = (data?: Record<'activeLabel', string | undefined>) => { + return data?.activeLabel && data?.activeLabel !== ''; +}; + +export const isUnlabeled = ( data?: Record<'activeLabel', string | undefined>, ) => { - return data?.activeLabel && data.activeLabel !== ''; + return data?.activeLabel === ''; }; diff --git a/plugins/cost-insights/src/utils/mockData.ts b/plugins/cost-insights/src/utils/mockData.ts index f188bd7a57..98eab19b41 100644 --- a/plugins/cost-insights/src/utils/mockData.ts +++ b/plugins/cost-insights/src/utils/mockData.ts @@ -563,7 +563,26 @@ export const SampleCloudDataflowInsights: Entity = { ratio: 0.2, amount: 2_000, }, - entities: [], + entities: [ + { + id: 'Sample SKU A', + aggregation: [3_000, 4_000], + change: { + ratio: 0.333333, + amount: 1_000, + }, + entities: [], + }, + { + id: 'Sample SKU B', + aggregation: [7_000, 8_000], + change: { + ratio: 0.14285714, + amount: 1_000, + }, + entities: [], + }, + ], }, { id: 'entity-a', From 353b51b93831aa0c6d0f8582d2196ebb7ea82ed3 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Tue, 1 Dec 2020 15:14:26 -0500 Subject: [PATCH 18/45] Be explicit about Jenkins exports --- plugins/jenkins/src/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/jenkins/src/api/index.ts b/plugins/jenkins/src/api/index.ts index 5c0b073eb8..41e0985be2 100644 --- a/plugins/jenkins/src/api/index.ts +++ b/plugins/jenkins/src/api/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export * from './JenkinsApi'; +export { JenkinsApi, jenkinsApiRef } from './JenkinsApi'; From 92ccf4f6176f289c5611f67b2d06731ebc93aba0 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Tue, 1 Dec 2020 15:14:41 -0500 Subject: [PATCH 19/45] Fix export name --- plugins/circleci/src/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/circleci/src/api/index.ts b/plugins/circleci/src/api/index.ts index cf7319ec06..4c957c040a 100644 --- a/plugins/circleci/src/api/index.ts +++ b/plugins/circleci/src/api/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export * from './CircleCI'; +export * from './CircleCIApi'; From c5bd448c4dc51af3c5a82446816853577b5be339 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Tue, 1 Dec 2020 15:19:07 -0500 Subject: [PATCH 20/45] Update exports/imports --- plugins/circleci/src/state/useBuildWithSteps.ts | 2 +- plugins/circleci/src/state/useBuilds.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/circleci/src/state/useBuildWithSteps.ts b/plugins/circleci/src/state/useBuildWithSteps.ts index c169b8fe63..dff5927044 100644 --- a/plugins/circleci/src/state/useBuildWithSteps.ts +++ b/plugins/circleci/src/state/useBuildWithSteps.ts @@ -16,7 +16,7 @@ import { errorApiRef, useApi } from '@backstage/core'; import { useCallback, useMemo } from 'react'; import { useAsyncRetry } from 'react-use'; -import { circleCIApiRef } from '../api/index'; +import { circleCIApiRef } from '../api'; import { useAsyncPolling } from './useAsyncPolling'; import { useProjectSlugFromEntity, mapVcsType } from './useBuilds'; diff --git a/plugins/circleci/src/state/useBuilds.ts b/plugins/circleci/src/state/useBuilds.ts index 35bd2a2986..c172a88985 100644 --- a/plugins/circleci/src/state/useBuilds.ts +++ b/plugins/circleci/src/state/useBuilds.ts @@ -18,7 +18,7 @@ import { errorApiRef, useApi } from '@backstage/core'; import { BuildSummary, GitType } from 'circleci-api'; import { useCallback, useEffect, useState } from 'react'; import { useAsyncRetry } from 'react-use'; -import { circleCIApiRef } from '../api/index'; +import { circleCIApiRef } from '../api'; import type { CITableBuildInfo } from '../components/BuildsPage/lib/CITable'; import { useEntity } from '@backstage/plugin-catalog'; import { CIRCLECI_ANNOTATION } from '../constants'; From 2de30dd01947034b230421e589790fa535f5f308 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Tue, 1 Dec 2020 21:10:08 -0500 Subject: [PATCH 21/45] Explicit exports --- plugins/circleci/src/api/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/circleci/src/api/index.ts b/plugins/circleci/src/api/index.ts index 4c957c040a..1853008099 100644 --- a/plugins/circleci/src/api/index.ts +++ b/plugins/circleci/src/api/index.ts @@ -14,4 +14,9 @@ * limitations under the License. */ -export * from './CircleCIApi'; +export { CircleCIApi, circleCIApiRef, GitType } from './CircleCIApi'; +export type { + BuildWithSteps, + BuildStepAction, + BuildSummary, +} from './CircleCIApi'; From 08835a61d982ce20a36a562583f534da19c3961b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 1 Dec 2020 15:29:03 +0100 Subject: [PATCH 22/45] catalog: add support for relative targets and implicit types in Location entities --- .changeset/olive-parrots-retire.md | 6 ++ .../software-catalog/descriptor-format.md | 56 +++++++++++++++++++ .../catalog-model/examples/acme-corp.yaml | 3 +- packages/catalog-model/examples/acme/org.yaml | 15 +++-- packages/catalog-model/examples/all-apis.yaml | 11 ++-- .../examples/all-components.yaml | 19 +++---- .../src/kinds/LocationEntityV1alpha1.test.ts | 4 +- .../src/kinds/LocationEntityV1alpha1.ts | 4 +- .../LocationEntityProcessor.test.ts | 44 +++++++++++++++ .../processors/LocationEntityProcessor.ts | 45 +++++++++++---- 10 files changed, 167 insertions(+), 40 deletions(-) create mode 100644 .changeset/olive-parrots-retire.md create mode 100644 plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.test.ts diff --git a/.changeset/olive-parrots-retire.md b/.changeset/olive-parrots-retire.md new file mode 100644 index 0000000000..8e4ae1a7d4 --- /dev/null +++ b/.changeset/olive-parrots-retire.md @@ -0,0 +1,6 @@ +--- +'@backstage/catalog-model': minor +'@backstage/plugin-catalog-backend': patch +--- + +Add support for relative targets and implicit types in Location entities. diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 438f874990..19c5c74f68 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -31,6 +31,7 @@ we recommend that you name them `catalog-info.yaml`. - [Kind: Resource](#kind-resource) - [Kind: System](#kind-system) - [Kind: Domain](#kind-domain) +- [Kind: Location](#kind-location) ## Overall Shape Of An Entity @@ -884,3 +885,58 @@ This kind is not yet defined, but is reserved [for future use](system-model.md). ## Kind: Domain This kind is not yet defined, but is reserved [for future use](system-model.md). + +## Kind: Location + +Describes the following entity kind: + +| Field | Value | +| ------------ | ----------------------- | +| `apiVersion` | `backstage.io/v1alpha1` | +| `kind` | `Location` | + +A location is a marker that references other places to look for catalog data. + +Descriptor files for this kind may look as follows. + +```yaml +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: org-data +spec: + type: url + targets: + - http://github.com/myorg/myproject/org-data-dump/catalog-info-staff.yaml + - http://github.com/myorg/myproject/org-data-dump/catalog-info-consultants.yaml +``` + +In addition to the [common envelope metadata](#common-to-all-kinds-the-metadata) +shape, this kind has the following structure. + +### `apiVersion` and `kind` [required] + +Exactly equal to `backstage.io/v1alpha1` and `Location`, respectively. + +### `spec.type` [optional] + +The single location type, that's common to the targets specified in the spec. If +it is left out, it is inherited from the location type that originally read the +entity data. For example, if you have a `url` type location, that when read +results in a `Location` kind entity with no `spec.type`, then the referenced +targets in the entity will implicitly also be of `url` type. This is useful +because you can define a hierarchy of things in a directory structure using +relative target paths (see below), and it will work out no matter if it's +consumed locally on disk from a `file` location, or as uploaded on a VCS. + +### `spec.target` [optional] + +A single target as a string. Can be either an absolute path/URL (depending on +the type), or a relative path such as `./details/catalog-info.yaml` which is +resolved relative to the location of this Location entity itself. + +### `spec.targets` [optional] + +A list of targets as strings. They can all be either absolute paths/URLs +(depending on the type), or relative paths such as `./details/catalog-info.yaml` +which are resolved relative to the location of this Location entity itself. diff --git a/packages/catalog-model/examples/acme-corp.yaml b/packages/catalog-model/examples/acme-corp.yaml index e8047fc143..6449d548e0 100644 --- a/packages/catalog-model/examples/acme-corp.yaml +++ b/packages/catalog-model/examples/acme-corp.yaml @@ -4,6 +4,5 @@ metadata: name: acme-corp description: A collection of all Backstage example Groups spec: - type: github targets: - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/org.yaml + - ./acme/org.yaml diff --git a/packages/catalog-model/examples/acme/org.yaml b/packages/catalog-model/examples/acme/org.yaml index 8c562aaf89..fe368962b1 100644 --- a/packages/catalog-model/examples/acme/org.yaml +++ b/packages/catalog-model/examples/acme/org.yaml @@ -16,12 +16,11 @@ metadata: name: example-groups description: A collection of all Backstage example Groups spec: - type: github targets: - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/infrastructure-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/boxoffice-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/backstage-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-a-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-b-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-c-group.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-d-group.yaml + - ./infrastructure-group.yaml + - ./boxoffice-group.yaml + - ./backstage-group.yaml + - ./team-a-group.yaml + - ./team-b-group.yaml + - ./team-c-group.yaml + - ./team-d-group.yaml diff --git a/packages/catalog-model/examples/all-apis.yaml b/packages/catalog-model/examples/all-apis.yaml index 0278fc3078..20752faf97 100644 --- a/packages/catalog-model/examples/all-apis.yaml +++ b/packages/catalog-model/examples/all-apis.yaml @@ -4,10 +4,9 @@ metadata: name: example-apis description: A collection of all Backstage example APIs spec: - type: github targets: - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/hello-world-api.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/petstore-api.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/spotify-api.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/streetlights-api.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/swapi-graphql.yaml + - ./apis/hello-world-api.yaml + - ./apis/petstore-api.yaml + - ./apis/spotify-api.yaml + - ./apis/streetlights-api.yaml + - ./apis/swapi-graphql.yaml diff --git a/packages/catalog-model/examples/all-components.yaml b/packages/catalog-model/examples/all-components.yaml index 06c44b59d7..f29a7378a0 100644 --- a/packages/catalog-model/examples/all-components.yaml +++ b/packages/catalog-model/examples/all-components.yaml @@ -4,14 +4,13 @@ metadata: name: example-components description: A collection of all Backstage example components spec: - type: github targets: - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/artist-lookup-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/petstore-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/playback-order-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/podcast-api-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/queue-proxy-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/searcher-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/playback-lib-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/www-artist-component.yaml - - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/shuffle-api-component.yaml + - ./components/artist-lookup-component.yaml + - ./components/petstore-component.yaml + - ./components/playback-order-component.yaml + - ./components/podcast-api-component.yaml + - ./components/queue-proxy-component.yaml + - ./components/searcher-component.yaml + - ./components/playback-lib-component.yaml + - ./components/www-artist-component.yaml + - ./components/shuffle-api-component.yaml diff --git a/packages/catalog-model/src/kinds/LocationEntityV1alpha1.test.ts b/packages/catalog-model/src/kinds/LocationEntityV1alpha1.test.ts index d9c1e9185f..2451df8e64 100644 --- a/packages/catalog-model/src/kinds/LocationEntityV1alpha1.test.ts +++ b/packages/catalog-model/src/kinds/LocationEntityV1alpha1.test.ts @@ -54,9 +54,9 @@ describe('LocationV1alpha1Validator', () => { await expect(validator.check(entity)).resolves.toBe(false); }); - it('rejects missing type', async () => { + it('accepts missing type', async () => { delete (entity as any).spec.type; - await expect(validator.check(entity)).rejects.toThrow(/type/); + await expect(validator.check(entity)).resolves.toBe(true); }); it('rejects wrong type', async () => { diff --git a/packages/catalog-model/src/kinds/LocationEntityV1alpha1.ts b/packages/catalog-model/src/kinds/LocationEntityV1alpha1.ts index e536be7922..9cd767de94 100644 --- a/packages/catalog-model/src/kinds/LocationEntityV1alpha1.ts +++ b/packages/catalog-model/src/kinds/LocationEntityV1alpha1.ts @@ -26,7 +26,7 @@ const schema = yup.object>({ kind: yup.string().required().equals([KIND]), spec: yup .object({ - type: yup.string().required().min(1), + type: yup.string().notRequired().min(1), target: yup.string().notRequired().min(1), targets: yup.array(yup.string().required()).notRequired(), }) @@ -37,7 +37,7 @@ export interface LocationEntityV1alpha1 extends Entity { apiVersion: typeof API_VERSION[number]; kind: typeof KIND; spec: { - type: string; + type?: string; target?: string; targets?: string[]; }; diff --git a/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.test.ts new file mode 100644 index 0000000000..998dfb62a2 --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.test.ts @@ -0,0 +1,44 @@ +/* + * 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 } from '@backstage/catalog-model'; +import { toAbsoluteUrl } from './LocationEntityProcessor'; +import path from 'path'; + +describe('LocationEntityProcessor', () => { + describe('toAbsoluteUrl', () => { + it('handles files', () => { + const base: LocationSpec = { + type: 'file', + target: `some${path.sep}path${path.sep}catalog-info.yaml`, + }; + expect(toAbsoluteUrl(base, `.${path.sep}c`)).toBe( + `some${path.sep}path${path.sep}c`, + ); + expect(toAbsoluteUrl(base, `${path.sep}c`)).toBe(`${path.sep}c`); + }); + + it('handles urls', () => { + const base: LocationSpec = { + type: 'url', + target: 'http://a.com/b/catalog-info.yaml', + }; + expect(toAbsoluteUrl(base, './c/d')).toBe('http://a.com/b/c/d'); + expect(toAbsoluteUrl(base, 'c/d')).toBe('http://a.com/b/c/d'); + expect(toAbsoluteUrl(base, 'http://b.com/z')).toBe('http://b.com/z'); + }); + }); +}); diff --git a/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.ts index 86e17f07f2..1c7e13f1c4 100644 --- a/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.ts @@ -17,27 +17,52 @@ import { Entity, LocationEntity, LocationSpec } from '@backstage/catalog-model'; import * as result from './results'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; +import path from 'path'; + +export function toAbsoluteUrl(base: LocationSpec, target: string): string { + try { + if (base.type === 'file') { + if (target.startsWith('.')) { + return path.join(path.dirname(base.target), target); + } + return target; + } + return new URL(target, base.target).toString(); + } catch (e) { + return target; + } +} export class LocationRefProcessor implements CatalogProcessor { async postProcessEntity( entity: Entity, - _location: LocationSpec, + location: LocationSpec, emit: CatalogProcessorEmit, ): Promise { if (entity.kind === 'Location') { - const location = entity as LocationEntity; - if (location.spec.target) { + const locationEntity = entity as LocationEntity; + + const type = locationEntity.spec.type || location.type; + if (type === 'file' && location.target.endsWith(path.sep)) { emit( - result.location( - { type: location.spec.type, target: location.spec.target }, - false, + result.inputError( + location, + `LocationRefProcessor cannot handle ${type} type location with target ${location.target} that ends with a path separator`, ), ); } - if (location.spec.targets) { - for (const target of location.spec.targets) { - emit(result.location({ type: location.spec.type, target }, false)); - } + + const targets = new Array(); + if (locationEntity.spec.target) { + targets.push(locationEntity.spec.target); + } + if (locationEntity.spec.targets) { + targets.push(...locationEntity.spec.targets); + } + + for (const maybeRelativeTarget of targets) { + const target = toAbsoluteUrl(location, maybeRelativeTarget); + emit(result.location({ type, target }, false)); } } From a9fdf8c294286130610f765dfdfa69d86fc58a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 2 Dec 2020 07:40:57 +0100 Subject: [PATCH 23/45] keep the old examples, add new variant as sibling dir --- .changeset/olive-parrots-retire.md | 2 +- .../catalog-model/examples-relative/README.md | 10 + .../examples-relative/acme-corp.yaml | 8 + .../acme/backstage-group.yaml | 11 + .../acme/boxoffice-group.yaml | 11 + .../acme/infrastructure-group.yaml | 11 + .../examples-relative/acme/org.yaml | 26 + .../examples-relative/acme/team-a-group.yaml | 58 + .../examples-relative/acme/team-b-group.yaml | 66 + .../examples-relative/acme/team-c-group.yaml | 66 + .../examples-relative/acme/team-d-group.yaml | 33 + .../examples-relative/all-apis.yaml | 12 + .../examples-relative/all-components.yaml | 16 + .../apis/hello-world-api.yaml | 48 + .../examples-relative/apis/petstore-api.yaml | 124 ++ .../examples-relative/apis/spotify-api.yaml | 17 + .../apis/streetlights-api.yaml | 221 ++++ .../examples-relative/apis/swapi-graphql.yaml | 1176 +++++++++++++++++ .../components/artist-lookup-component.yaml | 12 + .../components/petstore-component.yaml | 13 + .../components/playback-lib-component.yaml | 9 + .../components/playback-order-component.yaml | 12 + .../components/podcast-api-component.yaml | 11 + .../components/queue-proxy-component.yaml | 12 + .../components/searcher-component.yaml | 11 + .../components/shuffle-api-component.yaml | 11 + .../components/www-artist-component.yaml | 9 + packages/catalog-model/examples/README.md | 7 + .../catalog-model/examples/acme-corp.yaml | 3 +- packages/catalog-model/examples/acme/org.yaml | 15 +- packages/catalog-model/examples/all-apis.yaml | 11 +- .../examples/all-components.yaml | 19 +- 32 files changed, 2048 insertions(+), 23 deletions(-) create mode 100644 packages/catalog-model/examples-relative/README.md create mode 100644 packages/catalog-model/examples-relative/acme-corp.yaml create mode 100644 packages/catalog-model/examples-relative/acme/backstage-group.yaml create mode 100644 packages/catalog-model/examples-relative/acme/boxoffice-group.yaml create mode 100644 packages/catalog-model/examples-relative/acme/infrastructure-group.yaml create mode 100644 packages/catalog-model/examples-relative/acme/org.yaml create mode 100644 packages/catalog-model/examples-relative/acme/team-a-group.yaml create mode 100644 packages/catalog-model/examples-relative/acme/team-b-group.yaml create mode 100644 packages/catalog-model/examples-relative/acme/team-c-group.yaml create mode 100644 packages/catalog-model/examples-relative/acme/team-d-group.yaml create mode 100644 packages/catalog-model/examples-relative/all-apis.yaml create mode 100644 packages/catalog-model/examples-relative/all-components.yaml create mode 100644 packages/catalog-model/examples-relative/apis/hello-world-api.yaml create mode 100644 packages/catalog-model/examples-relative/apis/petstore-api.yaml create mode 100644 packages/catalog-model/examples-relative/apis/spotify-api.yaml create mode 100644 packages/catalog-model/examples-relative/apis/streetlights-api.yaml create mode 100644 packages/catalog-model/examples-relative/apis/swapi-graphql.yaml create mode 100644 packages/catalog-model/examples-relative/components/artist-lookup-component.yaml create mode 100644 packages/catalog-model/examples-relative/components/petstore-component.yaml create mode 100644 packages/catalog-model/examples-relative/components/playback-lib-component.yaml create mode 100644 packages/catalog-model/examples-relative/components/playback-order-component.yaml create mode 100644 packages/catalog-model/examples-relative/components/podcast-api-component.yaml create mode 100644 packages/catalog-model/examples-relative/components/queue-proxy-component.yaml create mode 100644 packages/catalog-model/examples-relative/components/searcher-component.yaml create mode 100644 packages/catalog-model/examples-relative/components/shuffle-api-component.yaml create mode 100644 packages/catalog-model/examples-relative/components/www-artist-component.yaml create mode 100644 packages/catalog-model/examples/README.md diff --git a/.changeset/olive-parrots-retire.md b/.changeset/olive-parrots-retire.md index 8e4ae1a7d4..8337a34b70 100644 --- a/.changeset/olive-parrots-retire.md +++ b/.changeset/olive-parrots-retire.md @@ -1,5 +1,5 @@ --- -'@backstage/catalog-model': minor +'@backstage/catalog-model': patch '@backstage/plugin-catalog-backend': patch --- diff --git a/packages/catalog-model/examples-relative/README.md b/packages/catalog-model/examples-relative/README.md new file mode 100644 index 0000000000..3ed63a0e00 --- /dev/null +++ b/packages/catalog-model/examples-relative/README.md @@ -0,0 +1,10 @@ +# Examples with relative paths + +These examples use Location entities with relative paths +[see #3513](https://github.com/backstage/backstage/pull/3513). + +The `examples` sibling directory will be replaced with these contents no sooner +than December 16 2020, to give consumers time to adopt the above change. + +The contents of this directory is here for consumers who are on the edge and +want to use the new facility before December 16. diff --git a/packages/catalog-model/examples-relative/acme-corp.yaml b/packages/catalog-model/examples-relative/acme-corp.yaml new file mode 100644 index 0000000000..6449d548e0 --- /dev/null +++ b/packages/catalog-model/examples-relative/acme-corp.yaml @@ -0,0 +1,8 @@ +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: acme-corp + description: A collection of all Backstage example Groups +spec: + targets: + - ./acme/org.yaml diff --git a/packages/catalog-model/examples-relative/acme/backstage-group.yaml b/packages/catalog-model/examples-relative/acme/backstage-group.yaml new file mode 100644 index 0000000000..f992d155bc --- /dev/null +++ b/packages/catalog-model/examples-relative/acme/backstage-group.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: backstage + description: The backstage sub-department +spec: + type: sub-department + parent: infrastructure + ancestors: [infrastructure, acme-corp] + children: [team-a, team-b] + descendants: [team-a, team-b] diff --git a/packages/catalog-model/examples-relative/acme/boxoffice-group.yaml b/packages/catalog-model/examples-relative/acme/boxoffice-group.yaml new file mode 100644 index 0000000000..0be1fe58cb --- /dev/null +++ b/packages/catalog-model/examples-relative/acme/boxoffice-group.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: boxoffice + description: The boxoffice sub-department +spec: + type: sub-department + parent: infrastructure + ancestors: [infrastructure, acme-corp] + children: [team-c, team-d] + descendants: [team-c, team-d] diff --git a/packages/catalog-model/examples-relative/acme/infrastructure-group.yaml b/packages/catalog-model/examples-relative/acme/infrastructure-group.yaml new file mode 100644 index 0000000000..2341782944 --- /dev/null +++ b/packages/catalog-model/examples-relative/acme/infrastructure-group.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: infrastructure + description: The infra department +spec: + type: department + parent: acme-corp + ancestors: [acme-corp] + children: [backstage, boxoffice] + descendants: [backstage, boxoffice, team-a, team-b, team-c, team-d] diff --git a/packages/catalog-model/examples-relative/acme/org.yaml b/packages/catalog-model/examples-relative/acme/org.yaml new file mode 100644 index 0000000000..fe368962b1 --- /dev/null +++ b/packages/catalog-model/examples-relative/acme/org.yaml @@ -0,0 +1,26 @@ +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: acme-corp + description: The acme-corp organization +spec: + type: organization + ancestors: [] + children: [infrastructure] + descendants: + [infrastructure, backstage, boxoffice, team-a, team-b, team-c, team-d] +--- +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: example-groups + description: A collection of all Backstage example Groups +spec: + targets: + - ./infrastructure-group.yaml + - ./boxoffice-group.yaml + - ./backstage-group.yaml + - ./team-a-group.yaml + - ./team-b-group.yaml + - ./team-c-group.yaml + - ./team-d-group.yaml diff --git a/packages/catalog-model/examples-relative/acme/team-a-group.yaml b/packages/catalog-model/examples-relative/acme/team-a-group.yaml new file mode 100644 index 0000000000..8dbf0bb839 --- /dev/null +++ b/packages/catalog-model/examples-relative/acme/team-a-group.yaml @@ -0,0 +1,58 @@ +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: team-a + description: Team A +spec: + type: team + parent: backstage + ancestors: [backstage, infrastructure, acme-corp] + children: [] + descendants: [] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: breanna.davison +spec: + profile: + displayName: Breanna Davison + email: breanna-davison@example.com + picture: https://example.com/staff/breanna.jpeg + memberOf: [team-a] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: janelle.dawe +spec: + profile: + displayName: Janelle Dawe + email: janelle-dawe@example.com + picture: https://example.com/staff/janelle.jpeg + memberOf: [team-a] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: nigel.manning +spec: + profile: + displayName: Nigel Manning + email: nigel-manning@example.com + picture: https://example.com/staff/nigel.jpeg + memberOf: [team-a] +--- +# This user is added as an example, to make it more easy for the "Guest" +# sign-in option to demonstrate some entities being owned. In a regular org, +# a guest user would probably not be registered like this. +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: guest +spec: + profile: + displayName: Guest User + email: guest@example.com + picture: https://example.com/staff/the-ceos-dog.jpeg + memberOf: [team-a] diff --git a/packages/catalog-model/examples-relative/acme/team-b-group.yaml b/packages/catalog-model/examples-relative/acme/team-b-group.yaml new file mode 100644 index 0000000000..00e9e41d80 --- /dev/null +++ b/packages/catalog-model/examples-relative/acme/team-b-group.yaml @@ -0,0 +1,66 @@ +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: team-b + description: Team B +spec: + type: team + parent: backstage + ancestors: [backstage, infrastructure, acme-corp] + children: [] + descendants: [] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: amelia.park +spec: + profile: + displayName: Amelia Park + email: amelia-park@example.com + picture: https://example.com/staff/amelia.jpeg + memberOf: [team-b] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: colette.brock +spec: + profile: + displayName: Colette Brock + email: colette-brock@example.com + picture: https://example.com/staff/colette.jpeg + memberOf: [team-b] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: jenny.doe +spec: + profile: + displayName: Jenny Doe + email: jenny-doe@example.com + picture: https://example.com/staff/jenny.jpeg + memberOf: [team-b] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: jonathon.page +spec: + profile: + displayName: Jonathon Page + email: jonathon-page@example.com + picture: https://example.com/staff/jonathon.jpeg + memberOf: [team-b] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: justine.barrow +spec: + profile: + displayName: Justine Barrow + email: justine-barrow@example.com + picture: https://example.com/staff/justine.jpeg + memberOf: [team-b] diff --git a/packages/catalog-model/examples-relative/acme/team-c-group.yaml b/packages/catalog-model/examples-relative/acme/team-c-group.yaml new file mode 100644 index 0000000000..0f97f69cb3 --- /dev/null +++ b/packages/catalog-model/examples-relative/acme/team-c-group.yaml @@ -0,0 +1,66 @@ +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: team-c + description: Team C +spec: + type: team + parent: boxoffice + ancestors: [boxoffice, infrastructure, acme-corp] + children: [] + descendants: [] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: calum.leavy +spec: + profile: + displayName: Calum Leavy + email: calum-leavy@example.com + picture: https://example.com/staff/calum.jpeg + memberOf: [team-c] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: frank.tiernan +spec: + profile: + displayName: Frank Tiernan + email: frank-tiernan@example.com + picture: https://example.com/staff/frank.jpeg + memberOf: [team-c] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: peadar.macmahon +spec: + profile: + displayName: Peadar MacMahon + email: peadar-macmahon@example.com + picture: https://example.com/staff/peadar.jpeg + memberOf: [team-c] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: sarah.gilroy +spec: + profile: + displayName: Sarah Gilroy + email: sarah-gilroy@example.com + picture: https://example.com/staff/sarah.jpeg + memberOf: [team-c] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: tara.macgovern +spec: + profile: + displayName: Tara MacGovern + email: tara-macgovern@example.com + picture: https://example.com/staff/tara.jpeg + memberOf: [team-c] diff --git a/packages/catalog-model/examples-relative/acme/team-d-group.yaml b/packages/catalog-model/examples-relative/acme/team-d-group.yaml new file mode 100644 index 0000000000..5a1a53a2e6 --- /dev/null +++ b/packages/catalog-model/examples-relative/acme/team-d-group.yaml @@ -0,0 +1,33 @@ +apiVersion: backstage.io/v1alpha1 +kind: Group +metadata: + name: team-d + description: Team D +spec: + type: team + parent: boxoffice + ancestors: [boxoffice, infrastructure, acme-corp] + children: [] + descendants: [] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: eva.macdowell +spec: + profile: + displayName: Eva MacDowell + email: eva-macdowell@example.com + picture: https://example.com/staff/eva.jpeg + memberOf: [team-d] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: lucy.sheehan +spec: + profile: + displayName: Lucy Sheehan + email: lucy-sheehan@example.com + picture: https://example.com/staff/lucy.jpeg + memberOf: [team-d] diff --git a/packages/catalog-model/examples-relative/all-apis.yaml b/packages/catalog-model/examples-relative/all-apis.yaml new file mode 100644 index 0000000000..20752faf97 --- /dev/null +++ b/packages/catalog-model/examples-relative/all-apis.yaml @@ -0,0 +1,12 @@ +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: example-apis + description: A collection of all Backstage example APIs +spec: + targets: + - ./apis/hello-world-api.yaml + - ./apis/petstore-api.yaml + - ./apis/spotify-api.yaml + - ./apis/streetlights-api.yaml + - ./apis/swapi-graphql.yaml diff --git a/packages/catalog-model/examples-relative/all-components.yaml b/packages/catalog-model/examples-relative/all-components.yaml new file mode 100644 index 0000000000..f29a7378a0 --- /dev/null +++ b/packages/catalog-model/examples-relative/all-components.yaml @@ -0,0 +1,16 @@ +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: example-components + description: A collection of all Backstage example components +spec: + targets: + - ./components/artist-lookup-component.yaml + - ./components/petstore-component.yaml + - ./components/playback-order-component.yaml + - ./components/podcast-api-component.yaml + - ./components/queue-proxy-component.yaml + - ./components/searcher-component.yaml + - ./components/playback-lib-component.yaml + - ./components/www-artist-component.yaml + - ./components/shuffle-api-component.yaml diff --git a/packages/catalog-model/examples-relative/apis/hello-world-api.yaml b/packages/catalog-model/examples-relative/apis/hello-world-api.yaml new file mode 100644 index 0000000000..0f9786329f --- /dev/null +++ b/packages/catalog-model/examples-relative/apis/hello-world-api.yaml @@ -0,0 +1,48 @@ +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: hello-world + description: Hello World example for gRPC +spec: + type: grpc + lifecycle: deprecated + owner: team-c + definition: | + // Copyright 2015 gRPC authors. + // + // 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. + + syntax = "proto3"; + + option java_multiple_files = true; + option java_package = "io.grpc.examples.helloworld"; + option java_outer_classname = "HelloWorldProto"; + option objc_class_prefix = "HLW"; + + package helloworld; + + // The greeting service definition. + service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} + } + + // The request message containing the user's name. + message HelloRequest { + string name = 1; + } + + // The response message containing the greetings + message HelloReply { + string message = 1; + } diff --git a/packages/catalog-model/examples-relative/apis/petstore-api.yaml b/packages/catalog-model/examples-relative/apis/petstore-api.yaml new file mode 100644 index 0000000000..a314b4e255 --- /dev/null +++ b/packages/catalog-model/examples-relative/apis/petstore-api.yaml @@ -0,0 +1,124 @@ +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: petstore + description: The petstore API + tags: + - store + - rest +spec: + type: openapi + lifecycle: experimental + owner: team-c + definition: | + openapi: "3.0.0" + info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT + servers: + - url: http://petstore.swagger.io/v1 + paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string diff --git a/packages/catalog-model/examples-relative/apis/spotify-api.yaml b/packages/catalog-model/examples-relative/apis/spotify-api.yaml new file mode 100644 index 0000000000..0b8e80b86e --- /dev/null +++ b/packages/catalog-model/examples-relative/apis/spotify-api.yaml @@ -0,0 +1,17 @@ +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: spotify + description: The Spotify web API + tags: + - spotify + - rest + annotations: + # The annotation is deprecated, we use placeholders (see below) instead, remove it later. + backstage.io/definition-at-location: 'url:https://raw.githubusercontent.com/APIs-guru/openapi-directory/master/APIs/spotify.com/v1/swagger.yaml' +spec: + type: openapi + lifecycle: production + owner: team-a + definition: + $text: https://github.com/APIs-guru/openapi-directory/blob/master/APIs/spotify.com/v1/swagger.yaml diff --git a/packages/catalog-model/examples-relative/apis/streetlights-api.yaml b/packages/catalog-model/examples-relative/apis/streetlights-api.yaml new file mode 100644 index 0000000000..725811d0cc --- /dev/null +++ b/packages/catalog-model/examples-relative/apis/streetlights-api.yaml @@ -0,0 +1,221 @@ +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: streetlights + description: The Smartylighting Streetlights API allows you to remotely manage the city lights. + tags: + - mqtt +spec: + type: asyncapi + lifecycle: production + owner: team-c + definition: | + asyncapi: 2.0.0 + info: + title: Streetlights API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you to remotely manage the city lights. + + ### Check out its awesome features: + + * Turn a specific streetlight on/off 🌃 + * Dim a specific streetlight 😎 + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + + servers: + production: + url: api.streetlights.smartylighting.com:{port} + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + security: + - apiKey: [] + - supportedOauthFlows: + - streetlights:on + - streetlights:off + - streetlights:dim + - openIdConnectWellKnown: [] + + defaultContentType: application/json + + channels: + smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured: + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + summary: Receive information about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting/streetlights/1/0/action/{streetlightId}/turn/on: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + operationId: turnOn + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting/streetlights/1/0/action/{streetlightId}/turn/off: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + operationId: turnOff + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting/streetlights/1/0/action/{streetlightId}/dim: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + operationId: dimLight + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/dimLight' + + components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions for a particular streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/turnOnOffPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - on + - off + description: Whether to turn on or off the light. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + securitySchemes: + apiKey: + type: apiKey + in: user + description: Provide your API key as the user and leave the password empty. + supportedOauthFlows: + type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: 'https://authserver.example/auth' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + password: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + clientCredentials: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + authorizationCode: + authorizationUrl: 'https://authserver.example/auth' + tokenUrl: 'https://authserver.example/token' + refreshUrl: 'https://authserver.example/refresh' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + openIdConnectWellKnown: + type: openIdConnect + openIdConnectUrl: 'https://authserver.example/.well-known' + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + + operationTraits: + kafka: + bindings: + kafka: + clientId: my-app-id diff --git a/packages/catalog-model/examples-relative/apis/swapi-graphql.yaml b/packages/catalog-model/examples-relative/apis/swapi-graphql.yaml new file mode 100644 index 0000000000..0c1f7af5a4 --- /dev/null +++ b/packages/catalog-model/examples-relative/apis/swapi-graphql.yaml @@ -0,0 +1,1176 @@ +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: starwars-graphql + description: SWAPI GraphQL Schema +spec: + type: graphql + lifecycle: production + owner: team-b + definition: | + schema { + query: Root + } + + """A single film.""" + type Film implements Node { + """The title of this film.""" + title: String + + """The episode number of this film.""" + episodeID: Int + + """The opening paragraphs at the beginning of this film.""" + openingCrawl: String + + """The name of the director of this film.""" + director: String + + """The name(s) of the producer(s) of this film.""" + producers: [String] + + """The ISO 8601 date format of film release at original creator country.""" + releaseDate: String + speciesConnection(after: String, first: Int, before: String, last: Int): FilmSpeciesConnection + starshipConnection(after: String, first: Int, before: String, last: Int): FilmStarshipsConnection + vehicleConnection(after: String, first: Int, before: String, last: Int): FilmVehiclesConnection + characterConnection(after: String, first: Int, before: String, last: Int): FilmCharactersConnection + planetConnection(after: String, first: Int, before: String, last: Int): FilmPlanetsConnection + + """The ISO 8601 date format of the time that this resource was created.""" + created: String + + """The ISO 8601 date format of the time that this resource was edited.""" + edited: String + + """The ID of an object""" + id: ID! + } + + """A connection to a list of items.""" + type FilmCharactersConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [FilmCharactersEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + characters: [Person] + } + + """An edge in a connection.""" + type FilmCharactersEdge { + """The item at the end of the edge""" + node: Person + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type FilmPlanetsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [FilmPlanetsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + planets: [Planet] + } + + """An edge in a connection.""" + type FilmPlanetsEdge { + """The item at the end of the edge""" + node: Planet + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type FilmsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [FilmsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + films: [Film] + } + + """An edge in a connection.""" + type FilmsEdge { + """The item at the end of the edge""" + node: Film + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type FilmSpeciesConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [FilmSpeciesEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + species: [Species] + } + + """An edge in a connection.""" + type FilmSpeciesEdge { + """The item at the end of the edge""" + node: Species + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type FilmStarshipsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [FilmStarshipsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + starships: [Starship] + } + + """An edge in a connection.""" + type FilmStarshipsEdge { + """The item at the end of the edge""" + node: Starship + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type FilmVehiclesConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [FilmVehiclesEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + vehicles: [Vehicle] + } + + """An edge in a connection.""" + type FilmVehiclesEdge { + """The item at the end of the edge""" + node: Vehicle + + """A cursor for use in pagination""" + cursor: String! + } + + """An object with an ID""" + interface Node { + """The id of the object.""" + id: ID! + } + + """Information about pagination in a connection.""" + type PageInfo { + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! + + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! + + """When paginating backwards, the cursor to continue.""" + startCursor: String + + """When paginating forwards, the cursor to continue.""" + endCursor: String + } + + """A connection to a list of items.""" + type PeopleConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [PeopleEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + people: [Person] + } + + """An edge in a connection.""" + type PeopleEdge { + """The item at the end of the edge""" + node: Person + + """A cursor for use in pagination""" + cursor: String! + } + + """An individual person or character within the Star Wars universe.""" + type Person implements Node { + """The name of this person.""" + name: String + + """ + The birth year of the person, using the in-universe standard of BBY or ABY - + Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is + a battle that occurs at the end of Star Wars episode IV: A New Hope. + """ + birthYear: String + + """ + The eye color of this person. Will be "unknown" if not known or "n/a" if the + person does not have an eye. + """ + eyeColor: String + + """ + The gender of this person. Either "Male", "Female" or "unknown", + "n/a" if the person does not have a gender. + """ + gender: String + + """ + The hair color of this person. Will be "unknown" if not known or "n/a" if the + person does not have hair. + """ + hairColor: String + + """The height of the person in centimeters.""" + height: Int + + """The mass of the person in kilograms.""" + mass: Float + + """The skin color of this person.""" + skinColor: String + + """A planet that this person was born on or inhabits.""" + homeworld: Planet + filmConnection(after: String, first: Int, before: String, last: Int): PersonFilmsConnection + + """The species that this person belongs to, or null if unknown.""" + species: Species + starshipConnection(after: String, first: Int, before: String, last: Int): PersonStarshipsConnection + vehicleConnection(after: String, first: Int, before: String, last: Int): PersonVehiclesConnection + + """The ISO 8601 date format of the time that this resource was created.""" + created: String + + """The ISO 8601 date format of the time that this resource was edited.""" + edited: String + + """The ID of an object""" + id: ID! + } + + """A connection to a list of items.""" + type PersonFilmsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [PersonFilmsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + films: [Film] + } + + """An edge in a connection.""" + type PersonFilmsEdge { + """The item at the end of the edge""" + node: Film + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type PersonStarshipsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [PersonStarshipsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + starships: [Starship] + } + + """An edge in a connection.""" + type PersonStarshipsEdge { + """The item at the end of the edge""" + node: Starship + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type PersonVehiclesConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [PersonVehiclesEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + vehicles: [Vehicle] + } + + """An edge in a connection.""" + type PersonVehiclesEdge { + """The item at the end of the edge""" + node: Vehicle + + """A cursor for use in pagination""" + cursor: String! + } + + """ + A large mass, planet or planetoid in the Star Wars Universe, at the time of + 0 ABY. + """ + type Planet implements Node { + """The name of this planet.""" + name: String + + """The diameter of this planet in kilometers.""" + diameter: Int + + """ + The number of standard hours it takes for this planet to complete a single + rotation on its axis. + """ + rotationPeriod: Int + + """ + The number of standard days it takes for this planet to complete a single orbit + of its local star. + """ + orbitalPeriod: Int + + """ + A number denoting the gravity of this planet, where "1" is normal or 1 standard + G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. + """ + gravity: String + + """The average population of sentient beings inhabiting this planet.""" + population: Float + + """The climates of this planet.""" + climates: [String] + + """The terrains of this planet.""" + terrains: [String] + + """ + The percentage of the planet surface that is naturally occuring water or bodies + of water. + """ + surfaceWater: Float + residentConnection(after: String, first: Int, before: String, last: Int): PlanetResidentsConnection + filmConnection(after: String, first: Int, before: String, last: Int): PlanetFilmsConnection + + """The ISO 8601 date format of the time that this resource was created.""" + created: String + + """The ISO 8601 date format of the time that this resource was edited.""" + edited: String + + """The ID of an object""" + id: ID! + } + + """A connection to a list of items.""" + type PlanetFilmsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [PlanetFilmsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + films: [Film] + } + + """An edge in a connection.""" + type PlanetFilmsEdge { + """The item at the end of the edge""" + node: Film + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type PlanetResidentsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [PlanetResidentsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + residents: [Person] + } + + """An edge in a connection.""" + type PlanetResidentsEdge { + """The item at the end of the edge""" + node: Person + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type PlanetsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [PlanetsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + planets: [Planet] + } + + """An edge in a connection.""" + type PlanetsEdge { + """The item at the end of the edge""" + node: Planet + + """A cursor for use in pagination""" + cursor: String! + } + + type Root { + allFilms(after: String, first: Int, before: String, last: Int): FilmsConnection + film(id: ID, filmID: ID): Film + allPeople(after: String, first: Int, before: String, last: Int): PeopleConnection + person(id: ID, personID: ID): Person + allPlanets(after: String, first: Int, before: String, last: Int): PlanetsConnection + planet(id: ID, planetID: ID): Planet + allSpecies(after: String, first: Int, before: String, last: Int): SpeciesConnection + species(id: ID, speciesID: ID): Species + allStarships(after: String, first: Int, before: String, last: Int): StarshipsConnection + starship(id: ID, starshipID: ID): Starship + allVehicles(after: String, first: Int, before: String, last: Int): VehiclesConnection + vehicle(id: ID, vehicleID: ID): Vehicle + + """Fetches an object given its ID""" + node( + """The ID of an object""" + id: ID! + ): Node + } + + """A type of person or character within the Star Wars Universe.""" + type Species implements Node { + """The name of this species.""" + name: String + + """The classification of this species, such as "mammal" or "reptile".""" + classification: String + + """The designation of this species, such as "sentient".""" + designation: String + + """The average height of this species in centimeters.""" + averageHeight: Float + + """The average lifespan of this species in years, null if unknown.""" + averageLifespan: Int + + """ + Common eye colors for this species, null if this species does not typically + have eyes. + """ + eyeColors: [String] + + """ + Common hair colors for this species, null if this species does not typically + have hair. + """ + hairColors: [String] + + """ + Common skin colors for this species, null if this species does not typically + have skin. + """ + skinColors: [String] + + """The language commonly spoken by this species.""" + language: String + + """A planet that this species originates from.""" + homeworld: Planet + personConnection(after: String, first: Int, before: String, last: Int): SpeciesPeopleConnection + filmConnection(after: String, first: Int, before: String, last: Int): SpeciesFilmsConnection + + """The ISO 8601 date format of the time that this resource was created.""" + created: String + + """The ISO 8601 date format of the time that this resource was edited.""" + edited: String + + """The ID of an object""" + id: ID! + } + + """A connection to a list of items.""" + type SpeciesConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [SpeciesEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + species: [Species] + } + + """An edge in a connection.""" + type SpeciesEdge { + """The item at the end of the edge""" + node: Species + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type SpeciesFilmsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [SpeciesFilmsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + films: [Film] + } + + """An edge in a connection.""" + type SpeciesFilmsEdge { + """The item at the end of the edge""" + node: Film + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type SpeciesPeopleConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [SpeciesPeopleEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + people: [Person] + } + + """An edge in a connection.""" + type SpeciesPeopleEdge { + """The item at the end of the edge""" + node: Person + + """A cursor for use in pagination""" + cursor: String! + } + + """A single transport craft that has hyperdrive capability.""" + type Starship implements Node { + """The name of this starship. The common name, such as "Death Star".""" + name: String + + """ + The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 + Orbital Battle Station". + """ + model: String + + """ + The class of this starship, such as "Starfighter" or "Deep Space Mobile + Battlestation" + """ + starshipClass: String + + """The manufacturers of this starship.""" + manufacturers: [String] + + """The cost of this starship new, in galactic credits.""" + costInCredits: Float + + """The length of this starship in meters.""" + length: Float + + """The number of personnel needed to run or pilot this starship.""" + crew: String + + """The number of non-essential people this starship can transport.""" + passengers: String + + """ + The maximum speed of this starship in atmosphere. null if this starship is + incapable of atmosphering flight. + """ + maxAtmospheringSpeed: Int + + """The class of this starships hyperdrive.""" + hyperdriveRating: Float + + """ + The Maximum number of Megalights this starship can travel in a standard hour. + A "Megalight" is a standard unit of distance and has never been defined before + within the Star Wars universe. This figure is only really useful for measuring + the difference in speed of starships. We can assume it is similar to AU, the + distance between our Sun (Sol) and Earth. + """ + MGLT: Int + + """The maximum number of kilograms that this starship can transport.""" + cargoCapacity: Float + + """ + The maximum length of time that this starship can provide consumables for its + entire crew without having to resupply. + """ + consumables: String + pilotConnection(after: String, first: Int, before: String, last: Int): StarshipPilotsConnection + filmConnection(after: String, first: Int, before: String, last: Int): StarshipFilmsConnection + + """The ISO 8601 date format of the time that this resource was created.""" + created: String + + """The ISO 8601 date format of the time that this resource was edited.""" + edited: String + + """The ID of an object""" + id: ID! + } + + """A connection to a list of items.""" + type StarshipFilmsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [StarshipFilmsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + films: [Film] + } + + """An edge in a connection.""" + type StarshipFilmsEdge { + """The item at the end of the edge""" + node: Film + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type StarshipPilotsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [StarshipPilotsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + pilots: [Person] + } + + """An edge in a connection.""" + type StarshipPilotsEdge { + """The item at the end of the edge""" + node: Person + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type StarshipsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [StarshipsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + starships: [Starship] + } + + """An edge in a connection.""" + type StarshipsEdge { + """The item at the end of the edge""" + node: Starship + + """A cursor for use in pagination""" + cursor: String! + } + + """A single transport craft that does not have hyperdrive capability""" + type Vehicle implements Node { + """ + The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder + bike". + """ + name: String + + """ + The model or official name of this vehicle. Such as "All-Terrain Attack + Transport". + """ + model: String + + """The class of this vehicle, such as "Wheeled" or "Repulsorcraft".""" + vehicleClass: String + + """The manufacturers of this vehicle.""" + manufacturers: [String] + + """The cost of this vehicle new, in Galactic Credits.""" + costInCredits: Float + + """The length of this vehicle in meters.""" + length: Float + + """The number of personnel needed to run or pilot this vehicle.""" + crew: String + + """The number of non-essential people this vehicle can transport.""" + passengers: String + + """The maximum speed of this vehicle in atmosphere.""" + maxAtmospheringSpeed: Int + + """The maximum number of kilograms that this vehicle can transport.""" + cargoCapacity: Float + + """ + The maximum length of time that this vehicle can provide consumables for its + entire crew without having to resupply. + """ + consumables: String + pilotConnection(after: String, first: Int, before: String, last: Int): VehiclePilotsConnection + filmConnection(after: String, first: Int, before: String, last: Int): VehicleFilmsConnection + + """The ISO 8601 date format of the time that this resource was created.""" + created: String + + """The ISO 8601 date format of the time that this resource was edited.""" + edited: String + + """The ID of an object""" + id: ID! + } + + """A connection to a list of items.""" + type VehicleFilmsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [VehicleFilmsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + films: [Film] + } + + """An edge in a connection.""" + type VehicleFilmsEdge { + """The item at the end of the edge""" + node: Film + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type VehiclePilotsConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [VehiclePilotsEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + pilots: [Person] + } + + """An edge in a connection.""" + type VehiclePilotsEdge { + """The item at the end of the edge""" + node: Person + + """A cursor for use in pagination""" + cursor: String! + } + + """A connection to a list of items.""" + type VehiclesConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [VehiclesEdge] + + """ + A count of the total number of objects in this connection, ignoring pagination. + This allows a client to fetch the first five objects by passing "5" as the + argument to "first", then fetch the total count so it could display "5 of 83", + for example. + """ + totalCount: Int + + """ + A list of all of the objects returned in the connection. This is a convenience + field provided for quickly exploring the API; rather than querying for + "{ edges { node } }" when no edge data is needed, this field can be be used + instead. Note that when clients like Relay need to fetch the "cursor" field on + the edge to enable efficient pagination, this shortcut cannot be used, and the + full "{ edges { node } }" version should be used instead. + """ + vehicles: [Vehicle] + } + + """An edge in a connection.""" + type VehiclesEdge { + """The item at the end of the edge""" + node: Vehicle + + """A cursor for use in pagination""" + cursor: String! + } diff --git a/packages/catalog-model/examples-relative/components/artist-lookup-component.yaml b/packages/catalog-model/examples-relative/components/artist-lookup-component.yaml new file mode 100644 index 0000000000..257344be3d --- /dev/null +++ b/packages/catalog-model/examples-relative/components/artist-lookup-component.yaml @@ -0,0 +1,12 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: artist-lookup + description: Artist Lookup + tags: + - java + - data +spec: + type: service + lifecycle: experimental + owner: team-a diff --git a/packages/catalog-model/examples-relative/components/petstore-component.yaml b/packages/catalog-model/examples-relative/components/petstore-component.yaml new file mode 100644 index 0000000000..e6dd56c274 --- /dev/null +++ b/packages/catalog-model/examples-relative/components/petstore-component.yaml @@ -0,0 +1,13 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: petstore + description: Petstore +spec: + type: service + lifecycle: experimental + owner: team-c + implementsApis: + - petstore + - streetlights + - hello-world diff --git a/packages/catalog-model/examples-relative/components/playback-lib-component.yaml b/packages/catalog-model/examples-relative/components/playback-lib-component.yaml new file mode 100644 index 0000000000..f7d7670b5d --- /dev/null +++ b/packages/catalog-model/examples-relative/components/playback-lib-component.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: playback-sdk + description: Audio and video playback SDK +spec: + type: library + lifecycle: experimental + owner: team-c diff --git a/packages/catalog-model/examples-relative/components/playback-order-component.yaml b/packages/catalog-model/examples-relative/components/playback-order-component.yaml new file mode 100644 index 0000000000..c4f41b2b58 --- /dev/null +++ b/packages/catalog-model/examples-relative/components/playback-order-component.yaml @@ -0,0 +1,12 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: playback-order + description: Playback Order + tags: + - java + - playback +spec: + type: service + lifecycle: production + owner: user:guest diff --git a/packages/catalog-model/examples-relative/components/podcast-api-component.yaml b/packages/catalog-model/examples-relative/components/podcast-api-component.yaml new file mode 100644 index 0000000000..b89ff48c48 --- /dev/null +++ b/packages/catalog-model/examples-relative/components/podcast-api-component.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: podcast-api + description: Podcast API + tags: + - java +spec: + type: service + lifecycle: experimental + owner: team-b diff --git a/packages/catalog-model/examples-relative/components/queue-proxy-component.yaml b/packages/catalog-model/examples-relative/components/queue-proxy-component.yaml new file mode 100644 index 0000000000..7f7fcbd527 --- /dev/null +++ b/packages/catalog-model/examples-relative/components/queue-proxy-component.yaml @@ -0,0 +1,12 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: queue-proxy + description: Queue Proxy + tags: + - go + - website +spec: + type: website + lifecycle: production + owner: team-b diff --git a/packages/catalog-model/examples-relative/components/searcher-component.yaml b/packages/catalog-model/examples-relative/components/searcher-component.yaml new file mode 100644 index 0000000000..77150c96f0 --- /dev/null +++ b/packages/catalog-model/examples-relative/components/searcher-component.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: searcher + description: Searcher + tags: + - go +spec: + type: service + lifecycle: production + owner: user:guest diff --git a/packages/catalog-model/examples-relative/components/shuffle-api-component.yaml b/packages/catalog-model/examples-relative/components/shuffle-api-component.yaml new file mode 100644 index 0000000000..1c2da03511 --- /dev/null +++ b/packages/catalog-model/examples-relative/components/shuffle-api-component.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: shuffle-api + description: Shuffle API + tags: + - go +spec: + type: service + lifecycle: production + owner: user:guest diff --git a/packages/catalog-model/examples-relative/components/www-artist-component.yaml b/packages/catalog-model/examples-relative/components/www-artist-component.yaml new file mode 100644 index 0000000000..c333eb8c09 --- /dev/null +++ b/packages/catalog-model/examples-relative/components/www-artist-component.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: www-artist + description: Artist main website +spec: + type: website + lifecycle: production + owner: team-a diff --git a/packages/catalog-model/examples/README.md b/packages/catalog-model/examples/README.md new file mode 100644 index 0000000000..abf4934f3f --- /dev/null +++ b/packages/catalog-model/examples/README.md @@ -0,0 +1,7 @@ +# Example Entities + +NOTE: These are being replaced with the contents of the `examples-relative` +sibling directory, after December 16 2020. If you are using this example data +you will need to be using a released version of the catalog backend which +supports relative targets in Location entities +[see #3513](https://github.com/backstage/backstage/pull/3513) after that time. diff --git a/packages/catalog-model/examples/acme-corp.yaml b/packages/catalog-model/examples/acme-corp.yaml index 6449d548e0..e8047fc143 100644 --- a/packages/catalog-model/examples/acme-corp.yaml +++ b/packages/catalog-model/examples/acme-corp.yaml @@ -4,5 +4,6 @@ metadata: name: acme-corp description: A collection of all Backstage example Groups spec: + type: github targets: - - ./acme/org.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/org.yaml diff --git a/packages/catalog-model/examples/acme/org.yaml b/packages/catalog-model/examples/acme/org.yaml index fe368962b1..8c562aaf89 100644 --- a/packages/catalog-model/examples/acme/org.yaml +++ b/packages/catalog-model/examples/acme/org.yaml @@ -16,11 +16,12 @@ metadata: name: example-groups description: A collection of all Backstage example Groups spec: + type: github targets: - - ./infrastructure-group.yaml - - ./boxoffice-group.yaml - - ./backstage-group.yaml - - ./team-a-group.yaml - - ./team-b-group.yaml - - ./team-c-group.yaml - - ./team-d-group.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/infrastructure-group.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/boxoffice-group.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/backstage-group.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-a-group.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-b-group.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-c-group.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme/team-d-group.yaml diff --git a/packages/catalog-model/examples/all-apis.yaml b/packages/catalog-model/examples/all-apis.yaml index 20752faf97..0278fc3078 100644 --- a/packages/catalog-model/examples/all-apis.yaml +++ b/packages/catalog-model/examples/all-apis.yaml @@ -4,9 +4,10 @@ metadata: name: example-apis description: A collection of all Backstage example APIs spec: + type: github targets: - - ./apis/hello-world-api.yaml - - ./apis/petstore-api.yaml - - ./apis/spotify-api.yaml - - ./apis/streetlights-api.yaml - - ./apis/swapi-graphql.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/hello-world-api.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/petstore-api.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/spotify-api.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/streetlights-api.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/apis/swapi-graphql.yaml diff --git a/packages/catalog-model/examples/all-components.yaml b/packages/catalog-model/examples/all-components.yaml index f29a7378a0..06c44b59d7 100644 --- a/packages/catalog-model/examples/all-components.yaml +++ b/packages/catalog-model/examples/all-components.yaml @@ -4,13 +4,14 @@ metadata: name: example-components description: A collection of all Backstage example components spec: + type: github targets: - - ./components/artist-lookup-component.yaml - - ./components/petstore-component.yaml - - ./components/playback-order-component.yaml - - ./components/podcast-api-component.yaml - - ./components/queue-proxy-component.yaml - - ./components/searcher-component.yaml - - ./components/playback-lib-component.yaml - - ./components/www-artist-component.yaml - - ./components/shuffle-api-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/artist-lookup-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/petstore-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/playback-order-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/podcast-api-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/queue-proxy-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/searcher-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/playback-lib-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/www-artist-component.yaml + - https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/shuffle-api-component.yaml From 338e60a8260541c8aab36fa644e7814c9b872297 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Dec 2020 04:54:47 +0000 Subject: [PATCH 24/45] build(deps-dev): bump @types/jwt-decode from 2.2.1 to 3.1.0 Bumps [@types/jwt-decode](https://github.com/auth0/jwt-decode) from 2.2.1 to 3.1.0. - [Release notes](https://github.com/auth0/jwt-decode/releases) - [Changelog](https://github.com/auth0/jwt-decode/blob/master/CHANGELOG.md) - [Commits](https://github.com/auth0/jwt-decode/commits/v3.1.0) Signed-off-by: dependabot[bot] --- plugins/auth-backend/package.json | 4 ++-- yarn.lock | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 814c8c5258..a0e0e0f56f 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -36,7 +36,7 @@ "got": "^11.5.2", "helmet": "^4.0.0", "jose": "^1.27.1", - "jwt-decode": "2.2.0", + "jwt-decode": "^3.1.0", "knex": "^0.21.6", "moment": "^2.26.0", "morgan": "^1.10.0", @@ -59,7 +59,7 @@ "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", - "@types/jwt-decode": "2.2.1", + "@types/jwt-decode": "^3.1.0", "@types/nock": "^11.1.0", "@types/openid-client": "^3.7.0", "@types/passport": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index 6f27d7028a..e53d5098a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5466,10 +5466,12 @@ dependencies: "@types/node" "*" -"@types/jwt-decode@2.2.1": - version "2.2.1" - resolved "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-2.2.1.tgz#afdf5c527fcfccbd4009b5fd02d1e18241f2d2f2" - integrity sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A== +"@types/jwt-decode@^3.1.0": + version "3.1.0" + resolved "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-3.1.0.tgz#eb1b24f436962b8857beaf8addfd542de56670a2" + integrity sha512-tthwik7TKkou3mVnBnvVuHnHElbjtdbM63pdBCbZTirCt3WAdM73Y79mOri7+ljsS99ZVwUFZHLMxJuJnv/z1w== + dependencies: + jwt-decode "*" "@types/keygrip@*": version "1.0.2" @@ -15586,10 +15588,10 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" -jwt-decode@2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79" - integrity sha1-fYa9VmefWM5qhHBKZX3TkruoGnk= +jwt-decode@*, jwt-decode@^3.1.0: + version "3.1.2" + resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" + integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== keyv@^3.0.0: version "3.1.0" From 2ff323915474ad84bdab65eed9a7abd7e15b994a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Dec 2020 14:26:36 +0100 Subject: [PATCH 25/45] build(deps-dev): bump @types/codemirror from 0.0.97 to 0.0.100 (#3522) Bumps [@types/codemirror](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/codemirror) from 0.0.97 to 0.0.100. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/codemirror) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- plugins/graphiql/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index d3dc673c01..ccff3decf1 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -49,7 +49,7 @@ "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", - "@types/codemirror": "^0.0.97", + "@types/codemirror": "^0.0.100", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", "cross-fetch": "^3.0.6", diff --git a/yarn.lock b/yarn.lock index e53d5098a1..978b8a7fc1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4999,10 +4999,10 @@ dependencies: "@types/node" "*" -"@types/codemirror@^0.0.97": - version "0.0.97" - resolved "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.97.tgz#6f2d8266b7f1b34aacfe8c77221fafe324c3d081" - integrity sha512-n5d7o9nWhC49DjfhsxANP7naWSeTzrjXASkUDQh7626sM4zK9XP2EVcHp1IcCf/IPV6c7ORzDUDF3Bkt231VKg== +"@types/codemirror@^0.0.100": + version "0.0.100" + resolved "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.100.tgz#3ebdf1514208d73f38c25925d9cf9399a42a7471" + integrity sha512-4jGmu1T8vpQrJCe8cbe3KveiJmK2UAt3rZO2qE2sPoMhGLuwW0cMzFYJLyXebbRJg5G3RbuUXLip1IHPUESkFA== dependencies: "@types/tern" "*" From bad8990788ada0e12acaf1cb771637d74fb9af0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Dec 2020 04:45:02 +0000 Subject: [PATCH 26/45] build(deps): bump typescript-json-schema from 0.43.0 to 0.45.0 Bumps [typescript-json-schema](https://github.com/YousefED/typescript-json-schema) from 0.43.0 to 0.45.0. - [Release notes](https://github.com/YousefED/typescript-json-schema/releases) - [Commits](https://github.com/YousefED/typescript-json-schema/compare/v0.43.0...v0.45.0) Signed-off-by: dependabot[bot] --- packages/config-loader/package.json | 2 +- yarn.lock | 74 ++++++++++++++--------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 1584a61df5..24d7ba320a 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -36,7 +36,7 @@ "fs-extra": "^9.0.0", "json-schema": "^0.2.5", "json-schema-merge-allof": "^0.7.0", - "typescript-json-schema": "^0.43.0", + "typescript-json-schema": "^0.45.0", "yaml": "^1.9.2", "yup": "^0.29.3" }, diff --git a/yarn.lock b/yarn.lock index 978b8a7fc1..5c2a8253d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8862,10 +8862,10 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" -cliui@^7.0.0: - version "7.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.1.tgz#a4cb67aad45cd83d8d05128fc9f4d8fbb887e6b3" - integrity sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ== +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" @@ -11217,10 +11217,10 @@ escalade@^3.0.1: resolved "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4" integrity sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ== -escalade@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" - integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-goat@^2.0.0: version "2.1.1" @@ -12758,7 +12758,7 @@ glob-to-regexp@^0.3.0: resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.6: +glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -23615,21 +23615,21 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-json-schema@^0.43.0: - version "0.43.0" - resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.43.0.tgz#8bd9c832f1f15f006ff933907ce192222fdfd92f" - integrity sha512-4c9IMlIlHYJiQtzL1gh2nIPJEjBgJjDUs50gsnnc+GFyDSK1oFM3uQIBSVosiuA/4t6LSAXDS9vTdqbQC6EcgA== +typescript-json-schema@^0.45.0: + version "0.45.0" + resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.45.0.tgz#2f244e99518e589a442ee5f9c1d2c85a1ec7dc84" + integrity sha512-4MeX0HIODRd+K1/sIbkPryGXG43PVQ9cvIC8gDYml6yBgcsWLjvPMpTNr9VV+bQwpDLncB8Ie4qSenuKUwNZpg== dependencies: - "@types/json-schema" "^7.0.5" - glob "~7.1.6" + "@types/json-schema" "^7.0.6" + glob "^7.1.6" json-stable-stringify "^1.0.1" - typescript "~4.0.2" - yargs "^15.4.1" + typescript "^4.1.2" + yargs "^16.1.1" -typescript@^4.0.3, typescript@~4.0.2: - version "4.0.5" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389" - integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ== +typescript@^4.0.3, typescript@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9" + integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ== ua-parser-js@^0.7.18: version "0.7.21" @@ -24845,10 +24845,10 @@ y18n@^4.0.0: resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== -y18n@^5.0.1: - version "5.0.2" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.2.tgz#48218df5da2731b4403115c39a1af709c873f829" - integrity sha512-CkwaeZw6dQgqgPGeTWKMXCRmMcBgETFlTml1+ZOO+q7kGst8NREJ+eWwFNPVUQ4QGdAaklbqCZHH6Zuep1RjiA== +y18n@^5.0.5: + version "5.0.5" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" + integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== yaeti@^0.0.6: version "0.0.6" @@ -24916,10 +24916,10 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.0.0: - version "20.2.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.1.tgz#28f3773c546cdd8a69ddae68116b48a5da328e77" - integrity sha512-yYsjuSkjbLMBp16eaOt7/siKTjNVjMm3SoJnIg3sEh/JsvqVVDyjRKmaJV4cl+lNIgq6QEco2i3gDebJl7/vLA== +yargs-parser@^20.2.2: + version "20.2.4" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== yargs-parser@^3.2.0: version "3.2.0" @@ -24979,18 +24979,18 @@ yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.3: - version "16.0.3" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.0.3.tgz#7a919b9e43c90f80d4a142a89795e85399a7e54c" - integrity sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA== +yargs@^16.0.3, yargs@^16.1.1: + version "16.1.1" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.1.1.tgz#5a4a095bd1ca806b0a50d0c03611d38034d219a1" + integrity sha512-hAD1RcFP/wfgfxgMVswPE+z3tlPFtxG8/yWUrG2i17sTWGCGqWnxKcLTF4cUKDUK8fzokwsmO9H0TDkRbMHy8w== dependencies: - cliui "^7.0.0" - escalade "^3.0.2" + cliui "^7.0.2" + escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" string-width "^4.2.0" - y18n "^5.0.1" - yargs-parser "^20.0.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" yargs@^5.0.0: version "5.0.0" From b4488ddb0b87f9a75a1e45572e265c98e0437a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 2 Dec 2020 09:38:30 +0100 Subject: [PATCH 27/45] address typescript errors --- .changeset/itchy-hotels-brush.md | 9 ++ packages/cli/asset-types/asset-types.d.ts | 12 +++ .../OAuthRequestApi/OAuthPendingRequests.ts | 2 +- .../src/ingestion/processors/util/org.test.ts | 2 +- plugins/cost-insights/src/utils/styles.ts | 82 +++++++++---------- 5 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 .changeset/itchy-hotels-brush.md diff --git a/.changeset/itchy-hotels-brush.md b/.changeset/itchy-hotels-brush.md new file mode 100644 index 0000000000..7f1bb4ef14 --- /dev/null +++ b/.changeset/itchy-hotels-brush.md @@ -0,0 +1,9 @@ +--- +'@backstage/cli': patch +'@backstage/config-loader': patch +'@backstage/core-api': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-cost-insights': patch +--- + +Added a type alias for PositionError = GeolocationPositionError diff --git a/packages/cli/asset-types/asset-types.d.ts b/packages/cli/asset-types/asset-types.d.ts index 28c1fde9e3..9db4438fd4 100644 --- a/packages/cli/asset-types/asset-types.d.ts +++ b/packages/cli/asset-types/asset-types.d.ts @@ -97,3 +97,15 @@ declare module '*.module.sass' { const classes: { readonly [key: string]: string }; export default classes; } + +// NOTE(freben): Both the fix, and the placement of the fix, are not great. +// +// The fix is because the PositionError was renamed to +// GeolocationPositionError outside of our control, and react-use is dependent +// on the old name. +// +// The placement is because it's the one location we have at the moment, where +// a central .d.ts file is imported by the frontend and can be amended. +// +// After both TS and react-use are bumped high enough, this should be removed. +type PositionError = GeolocationPositionError; diff --git a/packages/core-api/src/apis/implementations/OAuthRequestApi/OAuthPendingRequests.ts b/packages/core-api/src/apis/implementations/OAuthRequestApi/OAuthPendingRequests.ts index 6287f35015..e616ece5ae 100644 --- a/packages/core-api/src/apis/implementations/OAuthRequestApi/OAuthPendingRequests.ts +++ b/packages/core-api/src/apis/implementations/OAuthRequestApi/OAuthPendingRequests.ts @@ -19,7 +19,7 @@ import { Observable } from '../../../types'; type RequestQueueEntry = { scopes: Set; - resolve: (value?: ResultType | PromiseLike | undefined) => void; + resolve: (value: ResultType | PromiseLike) => void; reject: (reason: Error) => void; }; diff --git a/plugins/catalog-backend/src/ingestion/processors/util/org.test.ts b/plugins/catalog-backend/src/ingestion/processors/util/org.test.ts index f7afd63101..7e5a2e9754 100644 --- a/plugins/catalog-backend/src/ingestion/processors/util/org.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/util/org.test.ts @@ -76,7 +76,7 @@ describe('buildMemberOf', () => { const u: UserEntity = { apiVersion: 'backstage.io/v1alpha1', kind: 'User', - metadata: { name }, + metadata: { name: 'n' }, spec: { profile: {}, memberOf: ['c'] }, }; diff --git a/plugins/cost-insights/src/utils/styles.ts b/plugins/cost-insights/src/utils/styles.ts index 5a42604311..c04ceba8e3 100644 --- a/plugins/cost-insights/src/utils/styles.ts +++ b/plugins/cost-insights/src/utils/styles.ts @@ -222,16 +222,13 @@ export const useBarChartLabelStyles = makeStyles(theme => }), ); -export const useCostInsightsStyles = makeStyles( - (theme: BackstageTheme) => - createStyles({ - h6Subtle: { - ...theme.typography.h6, - fontWeight: 'normal', - color: theme.palette.textSubtle, - }, - }), -); +export const useCostInsightsStyles = makeStyles(theme => ({ + h6Subtle: { + ...theme.typography.h6, + fontWeight: 'normal', + color: theme.palette.textSubtle, + }, +})); export const useCostInsightsTabsStyles = makeStyles( (theme: BackstageTheme) => ({ @@ -310,40 +307,37 @@ export const useCostGrowthStyles = makeStyles( }), ); -export const useCostGrowthLegendStyles = makeStyles( - (theme: BackstageTheme) => - createStyles({ - h5: { - ...theme.typography.h5, - fontWeight: 500, - padding: 0, - }, - marker: { - display: 'inherit', - marginRight: theme.spacing(1), - }, - helpIcon: { - display: 'inherit', - }, - title: { - ...theme.typography.overline, - fontWeight: 500, - lineHeight: 0, - marginRight: theme.spacing(1), - color: theme.palette.textSubtle, - }, - tooltip: { - display: 'block', - padding: theme.spacing(1), - backgroundColor: theme.palette.navigation.background, - }, - tooltipText: { - color: theme.palette.background.default, - fontSize: theme.typography.fontSize, - lineHeight: 1.5, - }, - }), -); +export const useCostGrowthLegendStyles = makeStyles(theme => ({ + h5: { + ...theme.typography.h5, + fontWeight: 500, + padding: 0, + }, + marker: { + display: 'inherit', + marginRight: theme.spacing(1), + }, + helpIcon: { + display: 'inherit', + }, + title: { + ...theme.typography.overline, + fontWeight: 500, + lineHeight: 0, + marginRight: theme.spacing(1), + color: theme.palette.textSubtle, + }, + tooltip: { + display: 'block', + padding: theme.spacing(1), + backgroundColor: theme.palette.navigation.background, + }, + tooltipText: { + color: theme.palette.background.default, + fontSize: theme.typography.fontSize, + lineHeight: 1.5, + }, +})); export const useBarChartStepperStyles = makeStyles( (theme: BackstageTheme) => From ff83308e489cf974fe477670d692a47695f8f858 Mon Sep 17 00:00:00 2001 From: Brenda Sukh Date: Wed, 2 Dec 2020 14:32:11 -0500 Subject: [PATCH 28/45] Generalize SKU specific verbiage --- .../ProductEntityDialog.tsx | 22 ++++++++++--------- .../ProductInsightsChart.tsx | 15 ++++++++----- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx index c01ab67ecc..df980fe16c 100644 --- a/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx +++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx @@ -29,7 +29,7 @@ function createRenderer(col: keyof RowData, classes: Record) { const row = rowData as RowData; const rowStyles = classnames(classes.row, { [classes.rowTotal]: row.id === 'total', - [classes.colFirst]: col === 'sku', + [classes.colFirst]: col === 'label', [classes.colLast]: col === 'ratio', }); @@ -50,7 +50,7 @@ function createRenderer(col: keyof RowData, classes: Record) { /> ); default: - return {row.sku}; + return {row.label}; } }; } @@ -63,7 +63,7 @@ function createSorter(field?: keyof Omit) { const b = data2 as RowData; if (a.id === 'total') return 1; if (b.id === 'total') return 1; - if (field === 'sku') return a.sku.localeCompare(b.sku); + if (field === 'label') return a.label.localeCompare(b.label); return field ? a[field] - b[field] @@ -80,7 +80,7 @@ const defaultEntity: Entity = { type RowData = { id: string; - sku: string; + label: string; previous: number; current: number; ratio: number; @@ -118,10 +118,12 @@ export const ProductEntityDialog = ({ const columns: TableColumn[] = [ { - field: 'sku', - title: SKU, - render: createRenderer('sku', classes), - customSort: createSorter('sku'), + field: 'label', + title: ( + {entitiesLabel} + ), + render: createRenderer('label', classes), + customSort: createSorter('label'), width: '33.33%', }, { @@ -154,14 +156,14 @@ export const ProductEntityDialog = ({ const rowData: RowData[] = entity.entities .map(e => ({ id: e.id || 'Unknown', - sku: e.id || 'Unknown', + label: e.id || 'Unknown', previous: e.aggregation[0], current: e.aggregation[1], ratio: e.change.ratio, })) .concat({ id: 'total', - sku: 'Total', + label: 'Total', previous: entity.aggregation[0], current: entity.aggregation[1], ratio: entity.change.ratio, diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsChart.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsChart.tsx index 221a99708b..69f49991ed 100644 --- a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsChart.tsx +++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsChart.tsx @@ -66,9 +66,9 @@ export const ProductInsightsChart = ({ const [selectLabel, setSelected] = useState>(); const isSelected = useMemo(() => !isUndefined(selectLabel), [selectLabel]); const isClickable = useMemo(() => { - const skus = + const breakdownEntities = entity.entities.find(e => e.id === activeLabel)?.entities ?? []; - return skus.length > 0; + return breakdownEntities.length > 0; }, [entity, activeLabel]); const legendTitle = `Cost ${entity.change.ratio <= 0 ? 'Savings' : 'Growth'}`; @@ -122,10 +122,13 @@ export const ProductInsightsChart = ({ const activeEntity = findAlways(entity.entities, e => e.id === id); const ratio = activeEntity.change.ratio; - const skus = activeEntity.entities; - const subtitle = `${skus.length} ${pluralOf(skus.length, 'SKU')}`; + const breakdownEntities = activeEntity.entities; + const subtitle = `${breakdownEntities.length} ${pluralOf( + breakdownEntities.length, + entity.entitiesLabel || 'SKU', + )}`; - if (skus.length) { + if (breakdownEntities.length) { return ( Date: Wed, 2 Dec 2020 14:32:40 -0500 Subject: [PATCH 29/45] Add additional events panel --- app-config.yaml | 3 + plugins/cost-insights/src/utils/mockData.ts | 90 ++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/app-config.yaml b/app-config.yaml index 3b476981e4..54d564de7d 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -290,6 +290,9 @@ costInsights: bigQuery: name: BigQuery icon: search + events: + name: Events + icon: data metrics: DAU: name: Daily Active Users diff --git a/plugins/cost-insights/src/utils/mockData.ts b/plugins/cost-insights/src/utils/mockData.ts index 98eab19b41..76bdf5f08f 100644 --- a/plugins/cost-insights/src/utils/mockData.ts +++ b/plugins/cost-insights/src/utils/mockData.ts @@ -812,7 +812,7 @@ export const SampleComputeEngineInsights: Entity = { id: 'Sample SKU A', aggregation: [1_000, 2_000], change: { - ratio: 0.5, + ratio: 1, amount: 1_000, }, entities: [], @@ -849,6 +849,92 @@ export const SampleComputeEngineInsights: Entity = { ], }; +export const SampleEventsInsights: Entity = { + id: 'events', + aggregation: [20_000, 10_000], + change: { + ratio: -0.5, + amount: -10_000, + }, + entitiesLabel: 'Product', + entities: [ + { + id: 'entity-a', + aggregation: [15_000, 7_000], + change: { + ratio: -0.53333333333, + amount: -8_000, + }, + entities: [ + { + id: 'Sample Product A', + aggregation: [5_000, 2_000], + change: { + ratio: -0.6, + amount: -3_000, + }, + entities: [], + }, + { + id: 'Sample Product B', + aggregation: [7_000, 2_500], + change: { + ratio: -0.64285714285, + amount: -4_500, + }, + entities: [], + }, + { + id: 'Sample Product C', + aggregation: [3_000, 2_500], + change: { + ratio: -0.16666666666, + amount: -500, + }, + entities: [], + }, + ], + }, + { + id: 'entity-b', + aggregation: [5_000, 3_000], + change: { + ratio: -0.4, + amount: -2_000, + }, + entities: [ + { + id: 'Sample Product A', + aggregation: [2_000, 1_000], + change: { + ratio: -0.5, + amount: -1_000, + }, + entities: [], + }, + { + id: 'Sample Product B', + aggregation: [1_000, 1_500], + change: { + ratio: 0.5, + amount: 500, + }, + entities: [], + }, + { + id: 'Sample Product C', + aggregation: [2_000, 500], + change: { + ratio: -0.75, + amount: -1_500, + }, + entities: [], + }, + ], + }, + ], +}; + export function entityOf(product: string): Entity { switch (product) { case 'computeEngine': @@ -859,6 +945,8 @@ export function entityOf(product: string): Entity { return SampleCloudStorageInsights; case 'bigQuery': return SampleBigQueryInsights; + case 'events': + return SampleEventsInsights; default: throw new Error( `Cannot get insights for ${product}. Make sure product matches product property in app-info.yaml`, From fc16895a930a8901e19f2aafa48e8a162b2d2f72 Mon Sep 17 00:00:00 2001 From: Brenda Sukh Date: Wed, 2 Dec 2020 15:07:50 -0500 Subject: [PATCH 30/45] Generalize breakdown label --- .../src/components/ProductInsightsCard/ProductEntityDialog.tsx | 2 ++ .../src/components/ProductInsightsCard/ProductInsightsChart.tsx | 1 + plugins/cost-insights/src/types/Entity.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx index df980fe16c..d617c0df35 100644 --- a/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx +++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductEntityDialog.tsx @@ -93,6 +93,7 @@ type ProductEntityDialogOptions = Partial< type ProductEntityDialogProps = { open: boolean; entity?: Entity; + entitiesLabel: string; options?: ProductEntityDialogOptions; onClose: () => void; }; @@ -100,6 +101,7 @@ type ProductEntityDialogProps = { export const ProductEntityDialog = ({ open, entity = defaultEntity, + entitiesLabel, options = {}, onClose, }: ProductEntityDialogProps) => { diff --git a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsChart.tsx b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsChart.tsx index 69f49991ed..2c26f62574 100644 --- a/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsChart.tsx +++ b/plugins/cost-insights/src/components/ProductInsightsCard/ProductInsightsChart.tsx @@ -200,6 +200,7 @@ export const ProductInsightsChart = ({ onClose={() => setSelected(undefined)} entity={entity.entities.find(e => e.id === selectLabel)} options={options} + entitiesLabel={entity.entitiesLabel || 'SKU'} /> )} diff --git a/plugins/cost-insights/src/types/Entity.ts b/plugins/cost-insights/src/types/Entity.ts index 83347f05c3..52f6271bb4 100644 --- a/plugins/cost-insights/src/types/Entity.ts +++ b/plugins/cost-insights/src/types/Entity.ts @@ -22,6 +22,7 @@ export interface Entity { aggregation: [number, number]; entities: Entity[]; change: ChangeStatistic; + entitiesLabel?: string; } /* From 69f38457f59d3b6672a2c855c85afa72ce3d6ea5 Mon Sep 17 00:00:00 2001 From: Brenda Sukh Date: Wed, 2 Dec 2020 15:18:32 -0500 Subject: [PATCH 31/45] Add changeset --- .changeset/cost-insights-hot-cheetahs-shout.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cost-insights-hot-cheetahs-shout.md diff --git a/.changeset/cost-insights-hot-cheetahs-shout.md b/.changeset/cost-insights-hot-cheetahs-shout.md new file mode 100644 index 0000000000..3d9fa31378 --- /dev/null +++ b/.changeset/cost-insights-hot-cheetahs-shout.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +Add support for non-SKU breakdowns for entities in the product panels. From bf3c161d72932a67753e9aabf15d982e3742d9f9 Mon Sep 17 00:00:00 2001 From: Ryan Vazquez Date: Wed, 2 Dec 2020 17:36:30 -0500 Subject: [PATCH 32/45] disable support button --- .../src/components/CostInsightsPage/CostInsightsPage.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/cost-insights/src/components/CostInsightsPage/CostInsightsPage.tsx b/plugins/cost-insights/src/components/CostInsightsPage/CostInsightsPage.tsx index e361a14322..9a38bf2955 100644 --- a/plugins/cost-insights/src/components/CostInsightsPage/CostInsightsPage.tsx +++ b/plugins/cost-insights/src/components/CostInsightsPage/CostInsightsPage.tsx @@ -32,7 +32,8 @@ import { import { CostInsightsNavigation } from '../CostInsightsNavigation'; import { CostOverviewCard } from '../CostOverviewCard'; import { ProductInsights } from '../ProductInsights'; -import { CostInsightsSupportButton } from '../CostInsightsSupportButton'; +/* https://github.com/backstage/backstage/issues/2574 */ +// import { CostInsightsSupportButton } from '../CostInsightsSupportButton'; import { useConfig, useCurrency, @@ -164,7 +165,7 @@ export const CostInsightsPage = () => { - + {/* */} @@ -239,7 +240,7 @@ export const CostInsightsPage = () => { mb={2} > - + {/* */} From bec334b33684a17c5c3e9ed0e2a9deff603bf8b6 Mon Sep 17 00:00:00 2001 From: Ryan Vazquez Date: Wed, 2 Dec 2020 17:38:06 -0500 Subject: [PATCH 33/45] changeset --- .changeset/cost-insights-hungry-oranges-enjoy.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cost-insights-hungry-oranges-enjoy.md diff --git a/.changeset/cost-insights-hungry-oranges-enjoy.md b/.changeset/cost-insights-hungry-oranges-enjoy.md new file mode 100644 index 0000000000..2a4a8bb566 --- /dev/null +++ b/.changeset/cost-insights-hungry-oranges-enjoy.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +disable support button From fe5c6a772723913bf1b91661fb1acfc95ddc7ea2 Mon Sep 17 00:00:00 2001 From: Fabian Chong Date: Thu, 26 Nov 2020 18:28:50 +0800 Subject: [PATCH 34/45] Optional .npmrc to support private NPM registry --- packages/cli/src/commands/backend/buildImage.ts | 4 ++++ packages/create-app/templates/default-app/package.json.hbs | 2 +- .../templates/default-app/packages/backend/Dockerfile | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/backend/buildImage.ts b/packages/cli/src/commands/backend/buildImage.ts index b6ae0dd579..6439b37ca1 100644 --- a/packages/cli/src/commands/backend/buildImage.ts +++ b/packages/cli/src/commands/backend/buildImage.ts @@ -34,11 +34,15 @@ export default async (cmd: Command) => { const pkgPath = paths.resolveTarget(PKG_PATH); const pkg = await fs.readJson(pkgPath); const appConfigs = await findAppConfigs(); + const npmrc = fs.existsSync(paths.resolveTargetRoot('.npmrc')) + ? ['.npmrc'] + : []; const tempDistWorkspace = await createDistWorkspace([pkg.name], { buildDependencies: Boolean(cmd.build), files: [ 'package.json', 'yarn.lock', + ...npmrc, ...appConfigs, { src: paths.resolveTarget('Dockerfile'), dest: 'Dockerfile' }, ], diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index 975a5a2ed2..e3d287c75c 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -8,7 +8,7 @@ "scripts": { "start": "yarn workspace app start", "build": "lerna run build", - "build-image": "yarn workspace backend build-image", + "build-image": "yarn workspace backend build-image --build-arg NPM_TOKEN", "tsc": "tsc", "tsc:full": "tsc --skipLibCheck false --incremental false", "clean": "backstage-cli clean && lerna run clean", diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index 50514713d3..b0c2d4a6e5 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -1,11 +1,12 @@ FROM node:12-buster +ARG NPM_TOKEN WORKDIR /usr/src/app # Copy repo skeleton first, to avoid unnecessary docker cache invalidation. # The skeleton contains the package.json of each package in the monorepo, # and along with yarn.lock and the root package.json, that's enough to run yarn install. -ADD yarn.lock package.json skeleton.tar ./ +ADD .npmrc* yarn.lock package.json skeleton.tar ./ RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" From 433aa52a1701a693b151982c6607526c9bcccbc4 Mon Sep 17 00:00:00 2001 From: Fabian Chong Date: Tue, 1 Dec 2020 14:27:37 +0800 Subject: [PATCH 35/45] Pass NPM_TOKEN through docker --secret --- packages/create-app/templates/default-app/package.json.hbs | 2 +- .../templates/default-app/packages/backend/Dockerfile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index e3d287c75c..8ee5666033 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -8,7 +8,7 @@ "scripts": { "start": "yarn workspace app start", "build": "lerna run build", - "build-image": "yarn workspace backend build-image --build-arg NPM_TOKEN", + "build-image": "DOCKER_BUILDKIT=1 yarn workspace backend build-image", "tsc": "tsc", "tsc:full": "tsc --skipLibCheck false --incremental false", "clean": "backstage-cli clean && lerna run clean", diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index b0c2d4a6e5..aeed5054f0 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -1,5 +1,5 @@ +# syntax = docker/dockerfile:1.0-experimental FROM node:12-buster -ARG NPM_TOKEN WORKDIR /usr/src/app @@ -8,7 +8,7 @@ WORKDIR /usr/src/app # and along with yarn.lock and the root package.json, that's enough to run yarn install. ADD .npmrc* yarn.lock package.json skeleton.tar ./ -RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" +RUN --mount=type=secret,id=NPM_TOKEN NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" # This will copy the contents of the dist-workspace when running the build-image command. # Do not use this Dockerfile outside of that command, as it will copy in the source code instead. From a42205b3e84c8986f5421f48c73f3c16d3f80266 Mon Sep 17 00:00:00 2001 From: Fabian Chong Date: Tue, 1 Dec 2020 14:35:20 +0800 Subject: [PATCH 36/45] Uses pathExists --- packages/cli/src/commands/backend/buildImage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/backend/buildImage.ts b/packages/cli/src/commands/backend/buildImage.ts index 6439b37ca1..654f51cd10 100644 --- a/packages/cli/src/commands/backend/buildImage.ts +++ b/packages/cli/src/commands/backend/buildImage.ts @@ -34,7 +34,7 @@ export default async (cmd: Command) => { const pkgPath = paths.resolveTarget(PKG_PATH); const pkg = await fs.readJson(pkgPath); const appConfigs = await findAppConfigs(); - const npmrc = fs.existsSync(paths.resolveTargetRoot('.npmrc')) + const npmrc = (await fs.pathExists(paths.resolveTargetRoot('.npmrc'))) ? ['.npmrc'] : []; const tempDistWorkspace = await createDistWorkspace([pkg.name], { From 8a16e8af82398bcda4fc55cb9718cada22caa57f Mon Sep 17 00:00:00 2001 From: Joel Low Date: Thu, 3 Dec 2020 10:06:15 +0800 Subject: [PATCH 37/45] Add missing changelog entry --- .changeset/spotty-paws-think.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/spotty-paws-think.md diff --git a/.changeset/spotty-paws-think.md b/.changeset/spotty-paws-think.md new file mode 100644 index 0000000000..7e59a0f641 --- /dev/null +++ b/.changeset/spotty-paws-think.md @@ -0,0 +1,6 @@ +--- +'@backstage/cli': patch +'@backstage/create-app': patch +--- + +Support `.npmrc` when building with private NPM registries From 6b7c44d32ded9ce33a3157023d52a60e42abcc25 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Thu, 3 Dec 2020 16:10:36 +0800 Subject: [PATCH 38/45] Add simple instructions to providing an NPM Token to backend:build-image --- packages/cli/src/commands/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 2b0e3e25b9..975df97f41 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -55,7 +55,9 @@ export function registerCommands(program: CommanderStatic) { .helpOption(', --backstage-cli-help') // Let docker handle --help .option('--build', 'Build packages before packing them into the image') .description( - 'Bundles the package into a docker image. All extra args are forwarded to docker image build', + 'Bundles the package into a docker image. All extra args are forwarded to ' + + '`docker image build`. For example, if a $NPM_TOKEN needs to be exposed, run ' + + '`backend:build-image --secret id=NPM_TOKEN,src=/NPM_TOKEN.txt`', ) .action(lazy(() => import('./backend/buildImage').then(m => m.default))); From a6e9708adabdddde4923fefa806af84849871e7b Mon Sep 17 00:00:00 2001 From: Joel Low Date: Thu, 3 Dec 2020 17:27:46 +0800 Subject: [PATCH 39/45] Revert changes to template app --- .changeset/spotty-paws-think.md | 1 - packages/create-app/templates/default-app/package.json.hbs | 2 +- .../templates/default-app/packages/backend/Dockerfile | 5 ++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.changeset/spotty-paws-think.md b/.changeset/spotty-paws-think.md index 7e59a0f641..552b65d7e6 100644 --- a/.changeset/spotty-paws-think.md +++ b/.changeset/spotty-paws-think.md @@ -1,6 +1,5 @@ --- '@backstage/cli': patch -'@backstage/create-app': patch --- Support `.npmrc` when building with private NPM registries diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index 8ee5666033..975a5a2ed2 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -8,7 +8,7 @@ "scripts": { "start": "yarn workspace app start", "build": "lerna run build", - "build-image": "DOCKER_BUILDKIT=1 yarn workspace backend build-image", + "build-image": "yarn workspace backend build-image", "tsc": "tsc", "tsc:full": "tsc --skipLibCheck false --incremental false", "clean": "backstage-cli clean && lerna run clean", diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index aeed5054f0..50514713d3 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -1,4 +1,3 @@ -# syntax = docker/dockerfile:1.0-experimental FROM node:12-buster WORKDIR /usr/src/app @@ -6,9 +5,9 @@ WORKDIR /usr/src/app # Copy repo skeleton first, to avoid unnecessary docker cache invalidation. # The skeleton contains the package.json of each package in the monorepo, # and along with yarn.lock and the root package.json, that's enough to run yarn install. -ADD .npmrc* yarn.lock package.json skeleton.tar ./ +ADD yarn.lock package.json skeleton.tar ./ -RUN --mount=type=secret,id=NPM_TOKEN NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" +RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" # This will copy the contents of the dist-workspace when running the build-image command. # Do not use this Dockerfile outside of that command, as it will copy in the source code instead. From e0cd3aa7aab35adfd75b906de989b7fda4919df1 Mon Sep 17 00:00:00 2001 From: Joel Low Date: Thu, 3 Dec 2020 17:47:22 +0800 Subject: [PATCH 40/45] Shorten help message for `backend:build-image` --- packages/cli/src/commands/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 975df97f41..db88c57fb1 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -55,9 +55,11 @@ export function registerCommands(program: CommanderStatic) { .helpOption(', --backstage-cli-help') // Let docker handle --help .option('--build', 'Build packages before packing them into the image') .description( + // TODO: Add example use cases in Backstage documentation. + // For example, if a $NPM_TOKEN needs to be exposed, run `backend:build-image --secret + // id=NPM_TOKEN,src=/NPM_TOKEN.txt`. 'Bundles the package into a docker image. All extra args are forwarded to ' + - '`docker image build`. For example, if a $NPM_TOKEN needs to be exposed, run ' + - '`backend:build-image --secret id=NPM_TOKEN,src=/NPM_TOKEN.txt`', + '`docker image build`.', ) .action(lazy(() => import('./backend/buildImage').then(m => m.default))); From 2f9ee534a2e44a87b37005fddf7be64169b16409 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 3 Dec 2020 12:00:06 +0100 Subject: [PATCH 41/45] cli: add missing --build flag to experimental bundle command --- packages/cli/src/commands/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index db88c57fb1..f773f279fc 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -47,6 +47,7 @@ export function registerCommands(program: CommanderStatic) { program .command('backend:__experimental__bundle__', { hidden: true }) .description('Bundle all backend packages into dist-workspace') + .option('--build', 'Build packages before packing them into the image') .action(lazy(() => import('./backend/bundle').then(m => m.default))); program From eeecfbf4a676abf8f210886f5f5142ba82e04483 Mon Sep 17 00:00:00 2001 From: Sebastian Qvarfordt Date: Thu, 3 Dec 2020 15:00:03 +0100 Subject: [PATCH 42/45] Cache techdocs build using UrlReader (#3551) * Better caching is coming when some backstage core features are in place. Currently let's just cache it for 30 minutes * Fixed prettier --- plugins/techdocs-backend/src/service/helpers.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/techdocs-backend/src/service/helpers.ts b/plugins/techdocs-backend/src/service/helpers.ts index 4a736f7388..012061dc0a 100644 --- a/plugins/techdocs-backend/src/service/helpers.ts +++ b/plugins/techdocs-backend/src/service/helpers.ts @@ -120,6 +120,16 @@ export class DocsBuilder { } } + // TODO: Better caching for URL. + if (type === 'url') { + const builtAt = buildMetadataStorage.getTimestamp(); + const now = Date.now(); + + if (builtAt > now - 1800000) { + return true; + } + } + this.logger.debug( `Docs for entity ${getEntityId(this.entity)} was outdated.`, ); From 34bc80d8b2ddea41eb980d97c9358ce1602de96d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 3 Dec 2020 15:07:37 +0100 Subject: [PATCH 43/45] Apply suggestions from code review --- scripts/verify-links.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/verify-links.js b/scripts/verify-links.js index ac2941c1fd..75e7a8c1d0 100755 --- a/scripts/verify-links.js +++ b/scripts/verify-links.js @@ -158,7 +158,7 @@ async function main() { ); } else if (problem === 'out-of-docs') { console.error( - 'Links in docks must use absolute URLs for targets outside of docs', + 'Links in docs must use absolute URLs for targets outside of docs', ); console.error(` From: ${basePath}`); console.error(` To: ${url}`); From b570f78e22072a788d3fef8f18babd8ac9e27478 Mon Sep 17 00:00:00 2001 From: Sebastian Qvarfordt Date: Thu, 3 Dec 2020 16:24:29 +0100 Subject: [PATCH 44/45] Use resource instead of source when building github repo tar url (#3552) * Use resource instead of source when building github repo tar url * Changed the right part of the url... * Added test to make sure we include subdomains in githubs readtree * Fixed wopsie --- .../src/reading/GithubUrlReader.test.ts | 34 +++++++++++++++++++ .../src/reading/GithubUrlReader.ts | 4 +-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/backend-common/src/reading/GithubUrlReader.test.ts b/packages/backend-common/src/reading/GithubUrlReader.test.ts index eb87d339ea..abe8b4f640 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.test.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.test.ts @@ -235,6 +235,40 @@ describe('GithubUrlReader', () => { expect(indexMarkdownFile.toString()).toBe('# Test\n'); }); + it('includes the subdomain in the github url', async () => { + worker.resetHandlers(); + worker.use( + rest.get( + 'https://ghe.github.com/backstage/mock/archive/repo.tar.gz', + (_, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/x-gzip'), + ctx.body(repoBuffer), + ), + ), + ); + + const processor = new GithubUrlReader( + { + host: 'ghe.github.com', + apiBaseUrl: 'https://api.github.com', + }, + { treeResponseFactory }, + ); + + const response = await processor.readTree( + 'https://ghe.github.com/backstage/mock/tree/repo/docs', + ); + + const files = await response.files(); + + expect(files.length).toBe(1); + const indexMarkdownFile = await files[0].content(); + + expect(indexMarkdownFile.toString()).toBe('# Test\n'); + }); + it('must specify a branch', async () => { const processor = new GithubUrlReader( { diff --git a/packages/backend-common/src/reading/GithubUrlReader.ts b/packages/backend-common/src/reading/GithubUrlReader.ts index 907f2ada7a..692a3c6dd8 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.ts @@ -179,7 +179,7 @@ export class GithubUrlReader implements UrlReader { name: repoName, ref, protocol, - source, + resource, full_name, filepath, } = parseGitUri(url); @@ -194,7 +194,7 @@ export class GithubUrlReader implements UrlReader { // TODO(Rugvip): use API to fetch URL instead const response = await fetch( new URL( - `${protocol}://${source}/${full_name}/archive/${ref}.tar.gz`, + `${protocol}://${resource}/${full_name}/archive/${ref}.tar.gz`, ).toString(), ); if (!response.ok) { From 01aa774d9a4c2e3b6b357cd32e155254ef8f2880 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 3 Dec 2020 15:28:22 +0000 Subject: [PATCH 45/45] Version Packages --- .changeset/beige-queens-crash.md | 13 ------ .changeset/chilly-chefs-protect.md | 5 --- .changeset/cost-insights-calm-bikes-prove.md | 5 --- .changeset/cost-insights-cyan-nails-film.md | 5 --- .../cost-insights-hot-cheetahs-shout.md | 5 --- .../cost-insights-hungry-oranges-enjoy.md | 5 --- .changeset/famous-items-travel.md | 5 --- .changeset/four-plants-happen.md | 6 --- .changeset/grumpy-crews-build.md | 9 ---- .changeset/itchy-hotels-brush.md | 9 ---- .changeset/light-bulldogs-guess.md | 5 --- .changeset/light-nails-crash.md | 5 --- .changeset/new-nails-thank.md | 7 ---- .changeset/olive-parrots-retire.md | 6 --- .changeset/perfect-dryers-sell.md | 13 ------ .changeset/slow-insects-fail.md | 5 --- .changeset/smart-turkeys-bathe.md | 28 ------------- .changeset/sour-eels-dream.md | 7 ---- .changeset/spotty-paws-think.md | 5 --- .changeset/strange-stingrays-enjoy.md | 7 ---- .changeset/stupid-taxis-sneeze.md | 7 ---- .changeset/tidy-actors-repair.md | 5 --- .changeset/twenty-trees-travel.md | 5 --- .changeset/weak-roses-search.md | 5 --- packages/app/CHANGELOG.md | 40 ++++++++++++++++++ packages/app/package.json | 42 +++++++++---------- packages/backend-common/CHANGELOG.md | 9 ++++ packages/backend-common/package.json | 8 ++-- packages/backend/CHANGELOG.md | 24 +++++++++++ packages/backend/package.json | 24 +++++------ packages/catalog-client/CHANGELOG.md | 9 ++++ packages/catalog-client/package.json | 6 +-- packages/catalog-model/CHANGELOG.md | 31 ++++++++++++++ packages/catalog-model/package.json | 4 +- packages/cli/CHANGELOG.md | 16 +++++++ packages/cli/package.json | 10 ++--- packages/config-loader/CHANGELOG.md | 14 +++++++ packages/config-loader/package.json | 2 +- packages/core-api/CHANGELOG.md | 7 ++++ packages/core-api/package.json | 6 +-- packages/core/package.json | 6 +-- packages/create-app/CHANGELOG.md | 26 ++++++++++++ packages/create-app/package.json | 38 ++++++++--------- packages/dev-utils/CHANGELOG.md | 11 +++++ packages/dev-utils/package.json | 6 +-- packages/integration/package.json | 2 +- packages/test-utils/CHANGELOG.md | 11 +++++ packages/test-utils/package.json | 6 +-- packages/theme/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 12 ++++++ plugins/api-docs/package.json | 12 +++--- plugins/app-backend/CHANGELOG.md | 10 +++++ plugins/app-backend/package.json | 8 ++-- plugins/auth-backend/CHANGELOG.md | 12 ++++++ plugins/auth-backend/package.json | 10 ++--- plugins/catalog-backend/CHANGELOG.md | 41 ++++++++++++++++++ plugins/catalog-backend/package.json | 10 ++--- plugins/catalog-graphql/CHANGELOG.md | 11 +++++ plugins/catalog-graphql/package.json | 10 ++--- plugins/catalog-import/CHANGELOG.md | 39 +++++++++++++++++ plugins/catalog-import/package.json | 14 +++---- plugins/catalog/CHANGELOG.md | 14 +++++++ plugins/catalog/package.json | 16 +++---- plugins/circleci/CHANGELOG.md | 11 +++++ plugins/circleci/package.json | 12 +++--- plugins/cloudbuild/CHANGELOG.md | 11 +++++ plugins/cloudbuild/package.json | 12 +++--- plugins/cost-insights/CHANGELOG.md | 13 ++++++ plugins/cost-insights/package.json | 10 ++--- plugins/explore/package.json | 6 +-- plugins/gcp-projects/package.json | 6 +-- plugins/github-actions/CHANGELOG.md | 13 ++++++ plugins/github-actions/package.json | 14 +++---- plugins/gitops-profiles/package.json | 6 +-- plugins/graphiql/package.json | 6 +-- plugins/graphql/package.json | 6 +-- plugins/jenkins/CHANGELOG.md | 11 +++++ plugins/jenkins/package.json | 12 +++--- plugins/kubernetes-backend/CHANGELOG.md | 12 ++++++ plugins/kubernetes-backend/package.json | 8 ++-- plugins/kubernetes/CHANGELOG.md | 11 +++++ plugins/kubernetes/package.json | 12 +++--- plugins/lighthouse/CHANGELOG.md | 13 ++++++ plugins/lighthouse/package.json | 14 +++---- plugins/newrelic/package.json | 6 +-- plugins/proxy-backend/CHANGELOG.md | 11 +++++ plugins/proxy-backend/package.json | 6 +-- plugins/register-component/CHANGELOG.md | 11 +++++ plugins/register-component/package.json | 12 +++--- plugins/rollbar-backend/package.json | 4 +- plugins/rollbar/CHANGELOG.md | 11 +++++ plugins/rollbar/package.json | 12 +++--- plugins/scaffolder-backend/CHANGELOG.md | 11 +++++ plugins/scaffolder-backend/package.json | 8 ++-- plugins/scaffolder/CHANGELOG.md | 33 +++++++++++++++ plugins/scaffolder/package.json | 12 +++--- plugins/search/CHANGELOG.md | 11 +++++ plugins/search/package.json | 12 +++--- plugins/sentry-backend/package.json | 4 +- plugins/sentry/CHANGELOG.md | 10 +++++ plugins/sentry/package.json | 10 ++--- plugins/sonarqube/CHANGELOG.md | 9 ++++ plugins/sonarqube/package.json | 10 ++--- plugins/tech-radar/package.json | 8 ++-- plugins/techdocs-backend/CHANGELOG.md | 12 ++++++ plugins/techdocs-backend/package.json | 8 ++-- plugins/techdocs/CHANGELOG.md | 15 +++++++ plugins/techdocs/package.json | 16 +++---- plugins/user-settings/package.json | 6 +-- plugins/welcome/CHANGELOG.md | 6 +++ plugins/welcome/package.json | 8 ++-- 111 files changed, 826 insertions(+), 431 deletions(-) delete mode 100644 .changeset/beige-queens-crash.md delete mode 100644 .changeset/chilly-chefs-protect.md delete mode 100644 .changeset/cost-insights-calm-bikes-prove.md delete mode 100644 .changeset/cost-insights-cyan-nails-film.md delete mode 100644 .changeset/cost-insights-hot-cheetahs-shout.md delete mode 100644 .changeset/cost-insights-hungry-oranges-enjoy.md delete mode 100644 .changeset/famous-items-travel.md delete mode 100644 .changeset/four-plants-happen.md delete mode 100644 .changeset/grumpy-crews-build.md delete mode 100644 .changeset/itchy-hotels-brush.md delete mode 100644 .changeset/light-bulldogs-guess.md delete mode 100644 .changeset/light-nails-crash.md delete mode 100644 .changeset/new-nails-thank.md delete mode 100644 .changeset/olive-parrots-retire.md delete mode 100644 .changeset/perfect-dryers-sell.md delete mode 100644 .changeset/slow-insects-fail.md delete mode 100644 .changeset/smart-turkeys-bathe.md delete mode 100644 .changeset/sour-eels-dream.md delete mode 100644 .changeset/spotty-paws-think.md delete mode 100644 .changeset/strange-stingrays-enjoy.md delete mode 100644 .changeset/stupid-taxis-sneeze.md delete mode 100644 .changeset/tidy-actors-repair.md delete mode 100644 .changeset/twenty-trees-travel.md delete mode 100644 .changeset/weak-roses-search.md create mode 100644 plugins/catalog-import/CHANGELOG.md diff --git a/.changeset/beige-queens-crash.md b/.changeset/beige-queens-crash.md deleted file mode 100644 index 6253717673..0000000000 --- a/.changeset/beige-queens-crash.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Optimized the `yarn install` step in the backend `Dockerfile`. - -To apply these changes to an existing app, make the following changes to `packages/backend/Dockerfile`: - -Replace the `RUN yarn install ...` line with the following: - -```bash -RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" -``` diff --git a/.changeset/chilly-chefs-protect.md b/.changeset/chilly-chefs-protect.md deleted file mode 100644 index 22e2ea9b7e..0000000000 --- a/.changeset/chilly-chefs-protect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Update swagger-ui-react to 3.37.2 diff --git a/.changeset/cost-insights-calm-bikes-prove.md b/.changeset/cost-insights-calm-bikes-prove.md deleted file mode 100644 index 179350fcd9..0000000000 --- a/.changeset/cost-insights-calm-bikes-prove.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -enable SKU breakdown for unlabeled entities diff --git a/.changeset/cost-insights-cyan-nails-film.md b/.changeset/cost-insights-cyan-nails-film.md deleted file mode 100644 index 69e21d87fe..0000000000 --- a/.changeset/cost-insights-cyan-nails-film.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -Add breakdown view to the Cost Overview panel diff --git a/.changeset/cost-insights-hot-cheetahs-shout.md b/.changeset/cost-insights-hot-cheetahs-shout.md deleted file mode 100644 index 3d9fa31378..0000000000 --- a/.changeset/cost-insights-hot-cheetahs-shout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -Add support for non-SKU breakdowns for entities in the product panels. diff --git a/.changeset/cost-insights-hungry-oranges-enjoy.md b/.changeset/cost-insights-hungry-oranges-enjoy.md deleted file mode 100644 index 2a4a8bb566..0000000000 --- a/.changeset/cost-insights-hungry-oranges-enjoy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -disable support button diff --git a/.changeset/famous-items-travel.md b/.changeset/famous-items-travel.md deleted file mode 100644 index a0aa02732d..0000000000 --- a/.changeset/famous-items-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs-backend': patch ---- - -Update URL auth format for Gitlab clone diff --git a/.changeset/four-plants-happen.md b/.changeset/four-plants-happen.md deleted file mode 100644 index b273d8ec41..0000000000 --- a/.changeset/four-plants-happen.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-sentry': patch -'@backstage/plugin-welcome': patch ---- - -Refactor route registration to remove deprecating code diff --git a/.changeset/grumpy-crews-build.md b/.changeset/grumpy-crews-build.md deleted file mode 100644 index 502210c257..0000000000 --- a/.changeset/grumpy-crews-build.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/config-loader': minor ---- - -Fix typo of "visibility" in config schema reference - -If you have defined a config element named `visiblity`, you -will need to fix the spelling to `visibility`. For more info, -see https://backstage.io/docs/conf/defining#visibility. diff --git a/.changeset/itchy-hotels-brush.md b/.changeset/itchy-hotels-brush.md deleted file mode 100644 index 7f1bb4ef14..0000000000 --- a/.changeset/itchy-hotels-brush.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/cli': patch -'@backstage/config-loader': patch -'@backstage/core-api': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-cost-insights': patch ---- - -Added a type alias for PositionError = GeolocationPositionError diff --git a/.changeset/light-bulldogs-guess.md b/.changeset/light-bulldogs-guess.md deleted file mode 100644 index d7b5a5aef5..0000000000 --- a/.changeset/light-bulldogs-guess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Allow the `backend.listen.port` config to be both a number or a string. diff --git a/.changeset/light-nails-crash.md b/.changeset/light-nails-crash.md deleted file mode 100644 index c7791d1027..0000000000 --- a/.changeset/light-nails-crash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Bump versions of `esbuild` and `rollup-plugin-esbuild` diff --git a/.changeset/new-nails-thank.md b/.changeset/new-nails-thank.md deleted file mode 100644 index 4fc7ccac68..0000000000 --- a/.changeset/new-nails-thank.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-proxy-backend': patch ---- - -Filter the headers that are sent from the proxied-targed back to the frontend to not forwarded unwanted authentication or -monitoring contexts from other origins (like `Set-Cookie` with e.g. a google analytics context). The implementation reuses -the `allowedHeaders` configuration that now controls both directions `frontend->target` and `target->frontend`. diff --git a/.changeset/olive-parrots-retire.md b/.changeset/olive-parrots-retire.md deleted file mode 100644 index 8337a34b70..0000000000 --- a/.changeset/olive-parrots-retire.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/catalog-model': patch -'@backstage/plugin-catalog-backend': patch ---- - -Add support for relative targets and implicit types in Location entities. diff --git a/.changeset/perfect-dryers-sell.md b/.changeset/perfect-dryers-sell.md deleted file mode 100644 index e1c5592162..0000000000 --- a/.changeset/perfect-dryers-sell.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Removed `"resolutions"` entry for `esbuild` in the root `package.json` in order to use the version specified by `@backstage/cli`. - -To apply this change to an existing app, remove the following from your root `package.json`: - -```json -"resolutions": { - "esbuild": "0.6.3" -}, -``` diff --git a/.changeset/slow-insects-fail.md b/.changeset/slow-insects-fail.md deleted file mode 100644 index a07e025f34..0000000000 --- a/.changeset/slow-insects-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Add [API docs plugin](https://github.com/backstage/backstage/tree/master/plugins/api-docs) to new apps being created through the CLI. diff --git a/.changeset/smart-turkeys-bathe.md b/.changeset/smart-turkeys-bathe.md deleted file mode 100644 index 5f429b5b37..0000000000 --- a/.changeset/smart-turkeys-bathe.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor -'@backstage/plugin-catalog-import': minor -'@backstage/catalog-model': patch -'@backstage/plugin-scaffolder': patch ---- - -Add Analyze location endpoint to catalog backend. Add catalog-import plugin and replace import-component with it. To start using Analyze location endpoint, you have add it to the `createRouter` function options in the `\backstage\packages\backend\src\plugins\catalog.ts` file: - -```ts -export default async function createPlugin(env: PluginEnvironment) { - const builder = new CatalogBuilder(env); - const { - entitiesCatalog, - locationsCatalog, - higherOrderOperation, - locationAnalyzer, //<-- - } = await builder.build(); - - return await createRouter({ - entitiesCatalog, - locationsCatalog, - higherOrderOperation, - locationAnalyzer, //<-- - logger: env.logger, - }); -} -``` diff --git a/.changeset/sour-eels-dream.md b/.changeset/sour-eels-dream.md deleted file mode 100644 index 75b9fb3c8d..0000000000 --- a/.changeset/sour-eels-dream.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Gracefully handle missing codeowners. - -The CodeOwnersProcessor now also takes a logger as a parameter. diff --git a/.changeset/spotty-paws-think.md b/.changeset/spotty-paws-think.md deleted file mode 100644 index 552b65d7e6..0000000000 --- a/.changeset/spotty-paws-think.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Support `.npmrc` when building with private NPM registries diff --git a/.changeset/strange-stingrays-enjoy.md b/.changeset/strange-stingrays-enjoy.md deleted file mode 100644 index 26b42a5611..0000000000 --- a/.changeset/strange-stingrays-enjoy.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/catalog-model': minor -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-kubernetes-backend': patch ---- - -k8s-plugin: refactor approach to use annotation based label-selector diff --git a/.changeset/stupid-taxis-sneeze.md b/.changeset/stupid-taxis-sneeze.md deleted file mode 100644 index d8e0fb130a..0000000000 --- a/.changeset/stupid-taxis-sneeze.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli': minor -'@backstage/plugin-cost-insights': patch ---- - -sort product panels and navigation menu by greatest cost -update tsconfig.json to use ES2020 api diff --git a/.changeset/tidy-actors-repair.md b/.changeset/tidy-actors-repair.md deleted file mode 100644 index 4869400556..0000000000 --- a/.changeset/tidy-actors-repair.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Use type EntityName from catalog-model for entities diff --git a/.changeset/twenty-trees-travel.md b/.changeset/twenty-trees-travel.md deleted file mode 100644 index 7f65084320..0000000000 --- a/.changeset/twenty-trees-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Use the OWNED_BY relation and compare it to the users MEMBER_OF relation. The user entity is searched by name, based on the userId of the identity. diff --git a/.changeset/weak-roses-search.md b/.changeset/weak-roses-search.md deleted file mode 100644 index 9f5074ce48..0000000000 --- a/.changeset/weak-roses-search.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-proxy-backend': patch ---- - -Add configuration schema for the commonly used properties diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index a6c8da7fd9..1b6e5cf1e0 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,45 @@ # example-app +## 0.2.5 + +### Patch Changes + +- Updated dependencies [7eb8bfe4a] +- Updated dependencies [fe7257ff0] +- Updated dependencies [a2cfa311a] +- Updated dependencies [69f38457f] +- Updated dependencies [bec334b33] +- Updated dependencies [303c5ea17] +- Updated dependencies [b4488ddb0] +- Updated dependencies [4a655c89d] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [8a16e8af8] +- Updated dependencies [bcc211a08] +- Updated dependencies [00670a96e] +- Updated dependencies [da2ad65cb] +- Updated dependencies [ebf37bbae] + - @backstage/plugin-api-docs@0.3.1 + - @backstage/plugin-cost-insights@0.4.2 + - @backstage/plugin-sentry@0.2.4 + - @backstage/plugin-welcome@0.2.2 + - @backstage/cli@0.4.0 + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog-import@0.3.0 + - @backstage/plugin-scaffolder@0.3.2 + - @backstage/plugin-kubernetes@0.3.1 + - @backstage/plugin-techdocs@0.3.1 + - @backstage/plugin-catalog@0.2.5 + - @backstage/test-utils@0.1.4 + - @backstage/plugin-circleci@0.2.3 + - @backstage/plugin-cloudbuild@0.2.3 + - @backstage/plugin-github-actions@0.2.3 + - @backstage/plugin-jenkins@0.3.2 + - @backstage/plugin-lighthouse@0.2.4 + - @backstage/plugin-register-component@0.2.3 + - @backstage/plugin-rollbar@0.2.5 + - @backstage/plugin-search@0.2.2 + ## 0.2.4 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index c176f74cf6..fd6667ac85 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,37 +1,37 @@ { "name": "example-app", - "version": "0.2.4", + "version": "0.2.5", "private": true, "bundled": true, "dependencies": { - "@backstage/catalog-model": "^0.3.1", - "@backstage/cli": "^0.3.2", + "@backstage/catalog-model": "^0.4.0", + "@backstage/cli": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-api-docs": "^0.3.0", - "@backstage/plugin-catalog": "^0.2.4", - "@backstage/plugin-catalog-import": "^0.2.0", - "@backstage/plugin-circleci": "^0.2.2", - "@backstage/plugin-cloudbuild": "^0.2.2", - "@backstage/plugin-cost-insights": "^0.4.1", + "@backstage/plugin-api-docs": "^0.3.1", + "@backstage/plugin-catalog": "^0.2.5", + "@backstage/plugin-catalog-import": "^0.3.0", + "@backstage/plugin-circleci": "^0.2.3", + "@backstage/plugin-cloudbuild": "^0.2.3", + "@backstage/plugin-cost-insights": "^0.4.2", "@backstage/plugin-explore": "^0.2.1", "@backstage/plugin-gcp-projects": "^0.2.1", - "@backstage/plugin-github-actions": "^0.2.2", + "@backstage/plugin-github-actions": "^0.2.3", "@backstage/plugin-gitops-profiles": "^0.2.1", "@backstage/plugin-graphiql": "^0.2.1", - "@backstage/plugin-jenkins": "^0.3.1", - "@backstage/plugin-kubernetes": "^0.3.0", - "@backstage/plugin-lighthouse": "^0.2.3", + "@backstage/plugin-jenkins": "^0.3.2", + "@backstage/plugin-kubernetes": "^0.3.1", + "@backstage/plugin-lighthouse": "^0.2.4", "@backstage/plugin-newrelic": "^0.2.1", - "@backstage/plugin-register-component": "^0.2.2", - "@backstage/plugin-rollbar": "^0.2.4", - "@backstage/plugin-scaffolder": "^0.3.1", - "@backstage/plugin-sentry": "^0.2.3", - "@backstage/plugin-search": "^0.2.1", + "@backstage/plugin-register-component": "^0.2.3", + "@backstage/plugin-rollbar": "^0.2.5", + "@backstage/plugin-scaffolder": "^0.3.2", + "@backstage/plugin-sentry": "^0.2.4", + "@backstage/plugin-search": "^0.2.2", "@backstage/plugin-tech-radar": "^0.3.0", - "@backstage/plugin-techdocs": "^0.3.0", + "@backstage/plugin-techdocs": "^0.3.1", "@backstage/plugin-user-settings": "^0.2.2", - "@backstage/plugin-welcome": "^0.2.1", - "@backstage/test-utils": "^0.1.3", + "@backstage/plugin-welcome": "^0.2.2", + "@backstage/test-utils": "^0.1.4", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index aec6c37a49..0c3741ec84 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-common +## 0.3.3 + +### Patch Changes + +- 612368274: Allow the `backend.listen.port` config to be both a number or a string. +- Updated dependencies [4e7091759] +- Updated dependencies [b4488ddb0] + - @backstage/config-loader@0.4.0 + ## 0.3.2 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index ca92f70e98..04e189abca 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.3.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -31,7 +31,7 @@ "dependencies": { "@backstage/cli-common": "^0.1.1", "@backstage/config": "^0.1.1", - "@backstage/config-loader": "^0.3.0", + "@backstage/config-loader": "^0.4.0", "@backstage/integration": "^0.1.2", "@types/cors": "^2.8.6", "@types/express": "^4.17.6", @@ -67,8 +67,8 @@ } }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/test-utils": "^0.1.4", "@types/archiver": "^3.1.1", "@types/compression": "^1.7.0", "@types/concat-stream": "^1.6.0", diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index d47e9003a5..838ca7d302 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,29 @@ # example-backend +## 0.2.5 + +### Patch Changes + +- Updated dependencies [ae95c7ff3] +- Updated dependencies [b4488ddb0] +- Updated dependencies [612368274] +- Updated dependencies [6a6c7c14e] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [e42402b47] +- Updated dependencies [bcc211a08] +- Updated dependencies [3619ea4c4] + - @backstage/plugin-techdocs-backend@0.3.1 + - @backstage/plugin-catalog-backend@0.3.0 + - @backstage/backend-common@0.3.3 + - @backstage/plugin-proxy-backend@0.2.2 + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-kubernetes-backend@0.2.1 + - @backstage/plugin-app-backend@0.3.2 + - example-app@0.2.5 + - @backstage/plugin-auth-backend@0.2.5 + - @backstage/plugin-scaffolder-backend@0.3.3 + ## 0.2.4 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index beb2567bd7..9e635902e9 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.4", + "version": "0.2.5", "main": "dist/index.cjs.js", "types": "src/index.ts", "private": true, @@ -18,24 +18,24 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.3.2", - "@backstage/catalog-model": "^0.3.1", + "@backstage/backend-common": "^0.3.3", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", - "@backstage/plugin-app-backend": "^0.3.1", - "@backstage/plugin-auth-backend": "^0.2.4", - "@backstage/plugin-catalog-backend": "^0.2.3", + "@backstage/plugin-app-backend": "^0.3.2", + "@backstage/plugin-auth-backend": "^0.2.5", + "@backstage/plugin-catalog-backend": "^0.3.0", "@backstage/plugin-graphql-backend": "^0.1.3", - "@backstage/plugin-kubernetes-backend": "^0.2.0", - "@backstage/plugin-proxy-backend": "^0.2.1", + "@backstage/plugin-kubernetes-backend": "^0.2.1", + "@backstage/plugin-proxy-backend": "^0.2.2", "@backstage/plugin-rollbar-backend": "^0.1.4", - "@backstage/plugin-scaffolder-backend": "^0.3.2", + "@backstage/plugin-scaffolder-backend": "^0.3.3", "@backstage/plugin-sentry-backend": "^0.1.3", - "@backstage/plugin-techdocs-backend": "^0.3.0", + "@backstage/plugin-techdocs-backend": "^0.3.1", "@gitbeaker/node": "^25.2.0", "@octokit/rest": "^18.0.0", "azure-devops-node-api": "^10.1.1", "dockerode": "^3.2.0", - "example-app": "^0.2.4", + "example-app": "^0.2.5", "express": "^4.17.1", "express-promise-router": "^3.0.3", "knex": "^0.21.6", @@ -45,7 +45,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.3.2", + "@backstage/cli": "^0.4.0", "@types/dockerode": "^2.5.32", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 3454a6c8e0..3ea3b496d7 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/catalog-client +## 0.3.2 + +### Patch Changes + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/catalog-model@0.4.0 + ## 0.3.1 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 4509b7d547..a343cae716 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-client", - "version": "0.3.1", + "version": "0.3.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,12 +20,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "cross-fetch": "^3.0.6" }, "devDependencies": { - "@backstage/cli": "^0.3.1", + "@backstage/cli": "^0.4.0", "@types/jest": "^26.0.7", "msw": "^0.21.2" }, diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index 630664e491..be8e4a1d70 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/catalog-model +## 0.4.0 + +### Minor Changes + +- bcc211a08: k8s-plugin: refactor approach to use annotation based label-selector + +### Patch Changes + +- 08835a61d: Add support for relative targets and implicit types in Location entities. +- a9fd599f7: Add Analyze location endpoint to catalog backend. Add catalog-import plugin and replace import-component with it. To start using Analyze location endpoint, you have add it to the `createRouter` function options in the `\backstage\packages\backend\src\plugins\catalog.ts` file: + + ```ts + export default async function createPlugin(env: PluginEnvironment) { + const builder = new CatalogBuilder(env); + const { + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + locationAnalyzer, //<-- + } = await builder.build(); + + return await createRouter({ + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + locationAnalyzer, //<-- + logger: env.logger, + }); + } + ``` + ## 0.3.1 ### Patch Changes diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 53f56c6600..25406c8eef 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-model", - "version": "0.3.1", + "version": "0.4.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", + "@backstage/cli": "^0.4.0", "@types/express": "^4.17.6", "@types/jest": "^26.0.7", "@types/lodash": "^4.14.151", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index d1770eaf1f..45214cd1e0 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/cli +## 0.4.0 + +### Minor Changes + +- 00670a96e: sort product panels and navigation menu by greatest cost + update tsconfig.json to use ES2020 api + +### Patch Changes + +- b4488ddb0: Added a type alias for PositionError = GeolocationPositionError +- 4a655c89d: Bump versions of `esbuild` and `rollup-plugin-esbuild` +- 8a16e8af8: Support `.npmrc` when building with private NPM registries +- Updated dependencies [4e7091759] +- Updated dependencies [b4488ddb0] + - @backstage/config-loader@0.4.0 + ## 0.3.2 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index eff546168e..fd02473453 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.3.2", + "version": "0.4.0", "private": false, "publishConfig": { "access": "public" @@ -30,7 +30,7 @@ "dependencies": { "@backstage/cli-common": "^0.1.1", "@backstage/config": "^0.1.1", - "@backstage/config-loader": "^0.3.0", + "@backstage/config-loader": "^0.4.0", "@hot-loader/react-dom": "^16.13.0", "@lerna/package-graph": "^3.18.5", "@lerna/project": "^3.18.0", @@ -111,11 +111,11 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-common": "^0.3.2", + "@backstage/backend-common": "^0.3.3", "@backstage/config": "^0.1.1", "@backstage/core": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@backstage/theme": "^0.2.1", "@types/diff": "^4.0.2", "@types/fs-extra": "^9.0.1", diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 729dc81206..30891c2dd9 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/config-loader +## 0.4.0 + +### Minor Changes + +- 4e7091759: Fix typo of "visibility" in config schema reference + + If you have defined a config element named `visiblity`, you + will need to fix the spelling to `visibility`. For more info, + see https://backstage.io/docs/conf/defining#visibility. + +### Patch Changes + +- b4488ddb0: Added a type alias for PositionError = GeolocationPositionError + ## 0.3.0 ### Minor Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 24d7ba320a..3e2c58c676 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "0.3.0", + "version": "0.4.0", "private": false, "publishConfig": { "access": "public", diff --git a/packages/core-api/CHANGELOG.md b/packages/core-api/CHANGELOG.md index 79bed2dfa3..ab333b998e 100644 --- a/packages/core-api/CHANGELOG.md +++ b/packages/core-api/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/core-api +## 0.2.4 + +### Patch Changes + +- b4488ddb0: Added a type alias for PositionError = GeolocationPositionError + - @backstage/test-utils@0.1.4 + ## 0.2.3 ### Patch Changes diff --git a/packages/core-api/package.json b/packages/core-api/package.json index fe56d11b9e..bfff89f27a 100644 --- a/packages/core-api/package.json +++ b/packages/core-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-api", "description": "Internal Core API used by Backstage plugins and apps", - "version": "0.2.3", + "version": "0.2.4", "private": false, "publishConfig": { "access": "public", @@ -30,7 +30,7 @@ }, "dependencies": { "@backstage/config": "^0.1.1", - "@backstage/test-utils": "^0.1.3", + "@backstage/test-utils": "^0.1.4", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -42,7 +42,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.3.2", + "@backstage/cli": "^0.4.0", "@backstage/test-utils-core": "^0.1.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/packages/core/package.json b/packages/core/package.json index f667ffe7be..dd48a5d4ce 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -30,7 +30,7 @@ }, "dependencies": { "@backstage/config": "^0.1.1", - "@backstage/core-api": "^0.2.1", + "@backstage/core-api": "^0.2.4", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -64,8 +64,8 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.3.1", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/test-utils": "^0.1.4", "@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/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 4526bd4733..e13e31f406 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/create-app +## 0.2.3 + +### Patch Changes + +- 68fdc3a9f: Optimized the `yarn install` step in the backend `Dockerfile`. + + To apply these changes to an existing app, make the following changes to `packages/backend/Dockerfile`: + + Replace the `RUN yarn install ...` line with the following: + + ```bash + RUN yarn install --frozen-lockfile --production --network-timeout 300000 && rm -rf "$(yarn cache dir)" + ``` + +- 4a655c89d: Removed `"resolutions"` entry for `esbuild` in the root `package.json` in order to use the version specified by `@backstage/cli`. + + To apply this change to an existing app, remove the following from your root `package.json`: + + ```json + "resolutions": { + "esbuild": "0.6.3" + }, + ``` + +- ea475893d: Add [API docs plugin](https://github.com/backstage/backstage/tree/master/plugins/api-docs) to new apps being created through the CLI. + ## 0.2.2 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index adb9d30465..384a6f11a2 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "Create app package for Backstage", - "version": "0.2.2", + "version": "0.2.3", "private": false, "publishConfig": { "access": "public" @@ -37,30 +37,30 @@ "recursive-readdir": "^2.2.2" }, "devDependencies": { - "@backstage/backend-common": "^0.3.2", - "@backstage/catalog-model": "^0.3.1", - "@backstage/cli": "^0.3.2", + "@backstage/backend-common": "^0.3.3", + "@backstage/catalog-model": "^0.4.0", + "@backstage/cli": "^0.4.0", "@backstage/config": "^0.1.1", "@backstage/core": "^0.3.2", - "@backstage/plugin-api-docs": "^0.3.0", - "@backstage/plugin-app-backend": "^0.3.1", - "@backstage/plugin-auth-backend": "^0.2.4", - "@backstage/plugin-catalog": "^0.2.4", - "@backstage/plugin-catalog-backend": "^0.2.3", - "@backstage/plugin-circleci": "^0.2.2", + "@backstage/plugin-api-docs": "^0.3.1", + "@backstage/plugin-app-backend": "^0.3.2", + "@backstage/plugin-auth-backend": "^0.2.5", + "@backstage/plugin-catalog": "^0.2.5", + "@backstage/plugin-catalog-backend": "^0.3.0", + "@backstage/plugin-circleci": "^0.2.3", "@backstage/plugin-explore": "^0.2.1", - "@backstage/plugin-github-actions": "^0.2.2", - "@backstage/plugin-lighthouse": "^0.2.3", - "@backstage/plugin-proxy-backend": "^0.2.1", - "@backstage/plugin-register-component": "^0.2.2", + "@backstage/plugin-github-actions": "^0.2.3", + "@backstage/plugin-lighthouse": "^0.2.4", + "@backstage/plugin-proxy-backend": "^0.2.2", + "@backstage/plugin-register-component": "^0.2.3", "@backstage/plugin-rollbar-backend": "^0.1.4", - "@backstage/plugin-scaffolder": "^0.3.1", - "@backstage/plugin-scaffolder-backend": "^0.3.2", + "@backstage/plugin-scaffolder": "^0.3.2", + "@backstage/plugin-scaffolder-backend": "^0.3.3", "@backstage/plugin-tech-radar": "^0.3.0", - "@backstage/plugin-techdocs": "^0.3.0", - "@backstage/plugin-techdocs-backend": "^0.3.0", + "@backstage/plugin-techdocs": "^0.3.1", + "@backstage/plugin-techdocs-backend": "^0.3.1", "@backstage/plugin-user-settings": "^0.2.2", - "@backstage/test-utils": "^0.1.3", + "@backstage/test-utils": "^0.1.4", "@backstage/theme": "^0.2.1", "@types/fs-extra": "^9.0.1", "@types/inquirer": "^7.3.1", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index fd8b11bada..9a1048aa3d 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/dev-utils +## 0.1.5 + +### Patch Changes + +- Updated dependencies [b4488ddb0] +- Updated dependencies [4a655c89d] +- Updated dependencies [8a16e8af8] +- Updated dependencies [00670a96e] + - @backstage/cli@0.4.0 + - @backstage/test-utils@0.1.4 + ## 0.1.4 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index bf2d230ba7..4ceb0cec5e 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "0.1.4", + "version": "0.1.5", "private": false, "publishConfig": { "access": "public", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/cli": "^0.3.0", + "@backstage/cli": "^0.4.0", "@backstage/core": "^0.3.1", - "@backstage/test-utils": "^0.1.3", + "@backstage/test-utils": "^0.1.4", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", diff --git a/packages/integration/package.json b/packages/integration/package.json index fd4bd0bd3a..342476c38f 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -24,7 +24,7 @@ "git-url-parse": "^11.4.0" }, "devDependencies": { - "@backstage/cli": "^0.3.2", + "@backstage/cli": "^0.4.0", "@types/jest": "^26.0.7" }, "files": [ diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index b4bc2bbe76..dbeb79ed78 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/test-utils +## 0.1.4 + +### Patch Changes + +- Updated dependencies [b4488ddb0] +- Updated dependencies [4a655c89d] +- Updated dependencies [8a16e8af8] +- Updated dependencies [00670a96e] + - @backstage/cli@0.4.0 + - @backstage/core-api@0.2.4 + ## 0.1.3 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index a8f5cd1661..86997a6767 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "0.1.3", + "version": "0.1.4", "private": false, "publishConfig": { "access": "public", @@ -29,8 +29,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/cli": "^0.3.0", - "@backstage/core-api": "^0.2.0", + "@backstage/cli": "^0.4.0", + "@backstage/core-api": "^0.2.4", "@backstage/test-utils-core": "^0.1.1", "@backstage/theme": "^0.2.0", "@material-ui/core": "^4.11.0", diff --git a/packages/theme/package.json b/packages/theme/package.json index 68c70c656a..18b75afff4 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -31,7 +31,7 @@ "@material-ui/core": "^4.11.0" }, "devDependencies": { - "@backstage/cli": "^0.3.0" + "@backstage/cli": "^0.4.0" }, "files": [ "dist" diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index efa94fb46f..3b9c1951d4 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-api-docs +## 0.3.1 + +### Patch Changes + +- 7eb8bfe4a: Update swagger-ui-react to 3.37.2 +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.3.0 ### Minor Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index f9719226ee..659ded8061 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.3.0", + "version": "0.3.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.1", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.4", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@kyma-project/asyncapi-react": "^0.14.2", "@material-icons/font": "^1.0.2", @@ -40,9 +40,9 @@ "swagger-ui-react": "^3.37.2" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 1f2b3f008a..e92b886f2d 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-app-backend +## 0.3.2 + +### Patch Changes + +- Updated dependencies [4e7091759] +- Updated dependencies [b4488ddb0] +- Updated dependencies [612368274] + - @backstage/config-loader@0.4.0 + - @backstage/backend-common@0.3.3 + ## 0.3.1 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index ac350a14b4..6d2fdcb67c 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.3.1", + "version": "0.3.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.2", - "@backstage/config-loader": "^0.3.0", + "@backstage/backend-common": "^0.3.3", + "@backstage/config-loader": "^0.4.0", "@backstage/config": "^0.1.1", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -31,7 +31,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.3.2", + "@backstage/cli": "^0.4.0", "@types/supertest": "^2.0.8", "msw": "^0.20.5", "supertest": "^4.0.2" diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 257c38a3e5..9bdd04783a 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-auth-backend +## 0.2.5 + +### Patch Changes + +- Updated dependencies [612368274] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/backend-common@0.3.3 + - @backstage/catalog-model@0.4.0 + - @backstage/catalog-client@0.3.2 + ## 0.2.4 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index a0e0e0f56f..ddca6a24b4 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.2", - "@backstage/catalog-client": "^0.3.1", - "@backstage/catalog-model": "^0.3.1", + "@backstage/backend-common": "^0.3.3", + "@backstage/catalog-client": "^0.3.2", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "@types/express": "^4.17.6", "compression": "^1.7.4", @@ -55,7 +55,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.3.2", + "@backstage/cli": "^0.4.0", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 64f1a7ba87..935d52f116 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-catalog-backend +## 0.3.0 + +### Minor Changes + +- a9fd599f7: Add Analyze location endpoint to catalog backend. Add catalog-import plugin and replace import-component with it. To start using Analyze location endpoint, you have add it to the `createRouter` function options in the `\backstage\packages\backend\src\plugins\catalog.ts` file: + + ```ts + export default async function createPlugin(env: PluginEnvironment) { + const builder = new CatalogBuilder(env); + const { + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + locationAnalyzer, //<-- + } = await builder.build(); + + return await createRouter({ + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + locationAnalyzer, //<-- + logger: env.logger, + }); + } + ``` + +### Patch Changes + +- b4488ddb0: Added a type alias for PositionError = GeolocationPositionError +- 08835a61d: Add support for relative targets and implicit types in Location entities. +- e42402b47: Gracefully handle missing codeowners. + + The CodeOwnersProcessor now also takes a logger as a parameter. + +- Updated dependencies [612368274] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/backend-common@0.3.3 + - @backstage/catalog-model@0.4.0 + ## 0.2.3 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 9a4933ea6e..69f260d020 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "0.2.3", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ }, "dependencies": { "@azure/msal-node": "^1.0.0-alpha.8", - "@backstage/backend-common": "^0.3.2", - "@backstage/catalog-model": "^0.3.1", + "@backstage/backend-common": "^0.3.3", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "@octokit/graphql": "^4.5.6", "@types/express": "^4.17.6", @@ -48,8 +48,8 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/test-utils": "^0.1.4", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", "@types/lodash": "^4.14.151", diff --git a/plugins/catalog-graphql/CHANGELOG.md b/plugins/catalog-graphql/CHANGELOG.md index 56911b9c45..2bb4d9ac54 100644 --- a/plugins/catalog-graphql/CHANGELOG.md +++ b/plugins/catalog-graphql/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-graphql +## 0.2.3 + +### Patch Changes + +- Updated dependencies [612368274] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/backend-common@0.3.3 + - @backstage/catalog-model@0.4.0 + ## 0.2.2 ### Patch Changes diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index a489d66e5b..9b12250ca0 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graphql", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.1", - "@backstage/catalog-model": "^0.3.0", + "@backstage/backend-common": "^0.3.3", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "@graphql-modules/core": "^0.7.17", "apollo-server": "^2.16.1", @@ -32,8 +32,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.3.1", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/test-utils": "^0.1.4", "@graphql-codegen/cli": "^1.17.7", "@graphql-codegen/typescript": "^1.17.7", "@graphql-codegen/typescript-resolvers": "^1.17.7", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md new file mode 100644 index 0000000000..bdbb8681de --- /dev/null +++ b/plugins/catalog-import/CHANGELOG.md @@ -0,0 +1,39 @@ +# @backstage/plugin-catalog-import + +## 0.3.0 + +### Minor Changes + +- a9fd599f7: Add Analyze location endpoint to catalog backend. Add catalog-import plugin and replace import-component with it. To start using Analyze location endpoint, you have add it to the `createRouter` function options in the `\backstage\packages\backend\src\plugins\catalog.ts` file: + + ```ts + export default async function createPlugin(env: PluginEnvironment) { + const builder = new CatalogBuilder(env); + const { + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + locationAnalyzer, //<-- + } = await builder.build(); + + return await createRouter({ + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + locationAnalyzer, //<-- + logger: env.logger, + }); + } + ``` + +### Patch Changes + +- Updated dependencies [b4488ddb0] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [e42402b47] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/plugin-catalog-backend@0.3.0 + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 11562b741e..74cb3635be 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.2.0", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.0", - "@backstage/plugin-catalog-backend": "^0.2.2", + "@backstage/plugin-catalog": "^0.2.5", + "@backstage/plugin-catalog-backend": "^0.3.0", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -40,9 +40,9 @@ "yaml": "^1.10.0" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index b1c3cefa51..7630bdb077 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog +## 0.2.5 + +### Patch Changes + +- ebf37bbae: Use the OWNED_BY relation and compare it to the users MEMBER_OF relation. The user entity is searched by name, based on the userId of the identity. +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [da2ad65cb] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-scaffolder@0.3.2 + - @backstage/plugin-techdocs@0.3.1 + - @backstage/catalog-client@0.3.2 + ## 0.2.4 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index f039749f64..6887f71b3b 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-client": "^0.3.1", - "@backstage/catalog-model": "^0.3.1", + "@backstage/catalog-client": "^0.3.2", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-scaffolder": "^0.3.1", - "@backstage/plugin-techdocs": "^0.3.0", + "@backstage/plugin-scaffolder": "^0.3.2", + "@backstage/plugin-techdocs": "^0.3.1", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -43,9 +43,9 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@microsoft/microsoft-graph-types": "^1.25.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index a81531e28d..7986cca2ec 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-circleci +## 0.2.3 + +### Patch Changes + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.2.2 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index fda28733af..c67696244c 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-circleci", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.3", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -40,9 +40,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 4cb2d01377..1f707ac777 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-cloudbuild +## 0.2.3 + +### Patch Changes + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.2.2 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index c36669ccb9..3e514a5eb8 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cloudbuild", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.3", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -39,9 +39,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index b7bdfa9d50..b545b2ec37 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-cost-insights +## 0.4.2 + +### Patch Changes + +- fe7257ff0: enable SKU breakdown for unlabeled entities +- a2cfa311a: Add breakdown view to the Cost Overview panel +- 69f38457f: Add support for non-SKU breakdowns for entities in the product panels. +- bec334b33: disable support button +- b4488ddb0: Added a type alias for PositionError = GeolocationPositionError +- 00670a96e: sort product panels and navigation menu by greatest cost + update tsconfig.json to use ES2020 api + - @backstage/test-utils@0.1.4 + ## 0.4.1 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index bc649e50ab..5a3ee38afe 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cost-insights", - "version": "0.4.1", + "version": "0.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,7 +23,7 @@ "dependencies": { "@backstage/config": "^0.1.1", "@backstage/core": "^0.3.2", - "@backstage/test-utils": "^0.1.3", + "@backstage/test-utils": "^0.1.4", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -46,9 +46,9 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 3c3619f2ce..45cbb310f8 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -33,9 +33,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index f07cd1b0e6..faa79ed647 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -31,9 +31,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 96f3876802..e43704f83a 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-github-actions +## 0.2.3 + +### Patch Changes + +- Updated dependencies [b4488ddb0] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/core-api@0.2.4 + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.2.2 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 83ba62be95..5822a0e608 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-actions", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/core-api": "^0.2.1", - "@backstage/plugin-catalog": "^0.2.3", + "@backstage/core-api": "^0.2.4", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -40,9 +40,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 78af131bac..3adf7291db 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -32,9 +32,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index ccff3decf1..38c1fb1894 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -43,9 +43,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/graphql/package.json b/plugins/graphql/package.json index 53af8d9154..f9121ebd9a 100644 --- a/plugins/graphql/package.json +++ b/plugins/graphql/package.json @@ -19,9 +19,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.0", + "@backstage/backend-common": "^0.3.3", "@backstage/config": "^0.1.1", - "@backstage/plugin-catalog-graphql": "^0.2.1", + "@backstage/plugin-catalog-graphql": "^0.2.3", "@graphql-modules/core": "^0.7.17", "@types/express": "^4.17.6", "apollo-server": "^2.16.1", @@ -35,7 +35,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.3.0", + "@backstage/cli": "^0.4.0", "@types/supertest": "^2.0.8", "eslint-plugin-graphql": "^4.0.0", "msw": "^0.20.5", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index aeeb069f19..ca4e0284b5 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-jenkins +## 0.3.2 + +### Patch Changes + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.3.1 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index e47ec9edda..64bb7dfb20 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins", - "version": "0.3.1", + "version": "0.3.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.3", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -36,9 +36,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 2877264e54..dc875669ef 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-kubernetes-backend +## 0.2.1 + +### Patch Changes + +- bcc211a08: k8s-plugin: refactor approach to use annotation based label-selector +- Updated dependencies [612368274] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/backend-common@0.3.3 + - @backstage/catalog-model@0.4.0 + ## 0.2.0 ### Minor Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 8fe2f4c58f..9d1ff2eed4 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.2.0", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.1", - "@backstage/catalog-model": "^0.3.0", + "@backstage/backend-common": "^0.3.3", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "@kubernetes/client-node": "^0.12.1", "@types/express": "^4.17.6", @@ -39,7 +39,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.3.1", + "@backstage/cli": "^0.4.0", "supertest": "^4.0.2" }, "files": [ diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 652fc394a2..9bc3004913 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kubernetes +## 0.3.1 + +### Patch Changes + +- bcc211a08: k8s-plugin: refactor approach to use annotation based label-selector +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-kubernetes-backend@0.2.1 + ## 0.3.0 ### Minor Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 75b9ee098c..6fa2f7e3ff 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.3.0", + "version": "0.3.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "@backstage/core": "^0.3.2", - "@backstage/plugin-kubernetes-backend": "^0.2.0", + "@backstage/plugin-kubernetes-backend": "^0.2.1", "@backstage/theme": "^0.2.1", "@kubernetes/client-node": "^0.12.1", "@material-ui/core": "^4.11.0", @@ -36,9 +36,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index e35f3dece0..2106111b5e 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-lighthouse +## 0.2.4 + +### Patch Changes + +- Updated dependencies [b4488ddb0] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/core-api@0.2.4 + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.2.3 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 29b5a81cb9..da824044a9 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-lighthouse", - "version": "0.2.3", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "@backstage/core": "^0.3.2", - "@backstage/core-api": "^0.2.1", - "@backstage/plugin-catalog": "^0.2.3", + "@backstage/core-api": "^0.2.4", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -38,9 +38,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 691b9ab862..9cfb810f4a 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -31,9 +31,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index b034d26c95..4f9d373fdc 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-proxy-backend +## 0.2.2 + +### Patch Changes + +- 6a6c7c14e: Filter the headers that are sent from the proxied-targed back to the frontend to not forwarded unwanted authentication or + monitoring contexts from other origins (like `Set-Cookie` with e.g. a google analytics context). The implementation reuses + the `allowedHeaders` configuration that now controls both directions `frontend->target` and `target->frontend`. +- 3619ea4c4: Add configuration schema for the commonly used properties +- Updated dependencies [612368274] + - @backstage/backend-common@0.3.3 + ## 0.2.1 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 1283f9d261..68c89169c5 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.2.1", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -19,7 +19,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.0", + "@backstage/backend-common": "^0.3.3", "@backstage/config": "^0.1.1", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -33,7 +33,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.3.0", + "@backstage/cli": "^0.4.0", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/register-component/CHANGELOG.md b/plugins/register-component/CHANGELOG.md index c569046855..56ece52c40 100644 --- a/plugins/register-component/CHANGELOG.md +++ b/plugins/register-component/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-register-component +## 0.2.3 + +### Patch Changes + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.2.2 ### Patch Changes diff --git a/plugins/register-component/package.json b/plugins/register-component/package.json index ad4432be83..18a97e36f7 100644 --- a/plugins/register-component/package.json +++ b/plugins/register-component/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-register-component", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.3", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -36,9 +36,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index c91bf0cb9e..edaaa3a9b5 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.2", + "@backstage/backend-common": "^0.3.3", "@backstage/config": "^0.1.1", "@types/express": "^4.17.6", "axios": "^0.20.0", @@ -37,7 +37,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.3.2", + "@backstage/cli": "^0.4.0", "@types/supertest": "^2.0.8", "supertest": "^4.0.2" }, diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 095f04104a..89c7a273af 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-rollbar +## 0.2.5 + +### Patch Changes + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.2.4 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 35b057c054..9cdd7895bf 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-rollbar", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.1", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.4", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -37,9 +37,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/react-hooks": "^3.3.0", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index ea7e5c85ee..1b22ee1f14 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend +## 0.3.3 + +### Patch Changes + +- Updated dependencies [612368274] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/backend-common@0.3.3 + - @backstage/catalog-model@0.4.0 + ## 0.3.2 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index a095167a08..f71d8bc36c 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "0.3.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.1", - "@backstage/catalog-model": "^0.3.0", + "@backstage/backend-common": "^0.3.3", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "@gitbeaker/core": "^25.2.0", "@gitbeaker/node": "^25.2.0", @@ -48,7 +48,7 @@ "cross-fetch": "^3.0.6" }, "devDependencies": { - "@backstage/cli": "^0.3.1", + "@backstage/cli": "^0.4.0", "@octokit/types": "^5.4.1", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index c78e05c3e0..197d54a9a4 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-scaffolder +## 0.3.2 + +### Patch Changes + +- a9fd599f7: Add Analyze location endpoint to catalog backend. Add catalog-import plugin and replace import-component with it. To start using Analyze location endpoint, you have add it to the `createRouter` function options in the `\backstage\packages\backend\src\plugins\catalog.ts` file: + + ```ts + export default async function createPlugin(env: PluginEnvironment) { + const builder = new CatalogBuilder(env); + const { + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + locationAnalyzer, //<-- + } = await builder.build(); + + return await createRouter({ + entitiesCatalog, + locationsCatalog, + higherOrderOperation, + locationAnalyzer, //<-- + logger: env.logger, + }); + } + ``` + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.3.1 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 5a6a970851..381f2bfdbf 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "0.3.1", + "version": "0.3.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.3", + "@backstage/plugin-catalog": "^0.2.5", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -41,9 +41,9 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 3545914e96..106499bad4 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search +## 0.2.2 + +### Patch Changes + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + ## 0.2.1 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index ddc7a2d687..490d5003ef 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "0.2.1", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ }, "dependencies": { "@backstage/core": "^0.3.2", - "@backstage/plugin-catalog": "^0.2.3", - "@backstage/catalog-model": "^0.3.0", + "@backstage/plugin-catalog": "^0.2.5", + "@backstage/catalog-model": "^0.4.0", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -34,9 +34,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/sentry-backend/package.json b/plugins/sentry-backend/package.json index 2b6b5fc60d..5f5eafd5c6 100644 --- a/plugins/sentry-backend/package.json +++ b/plugins/sentry-backend/package.json @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.0", + "@backstage/backend-common": "^0.3.3", "@types/express": "^4.17.6", "axios": "^0.20.0", "compression": "^1.7.4", @@ -34,7 +34,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.3.0" + "@backstage/cli": "^0.4.0" }, "files": [ "dist" diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index b388548d8e..026c0e80c7 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-sentry +## 0.2.4 + +### Patch Changes + +- 303c5ea17: Refactor route registration to remove deprecating code +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/catalog-model@0.4.0 + ## 0.2.3 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 4d8473c509..b952a81d51 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sentry", - "version": "0.2.3", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,7 +21,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", @@ -36,9 +36,9 @@ "timeago.js": "^4.0.2" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 9ebd73b812..69d94fa655 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-sonarqube +## 0.1.5 + +### Patch Changes + +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/catalog-model@0.4.0 + ## 0.1.4 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index d5635c2770..2dd52ab021 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube", - "version": "0.1.4", + "version": "0.1.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,7 +21,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.0", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", @@ -35,9 +35,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 532fc26e9c..269e0e0b4f 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -22,7 +22,7 @@ }, "dependencies": { "@backstage/core": "^0.3.2", - "@backstage/test-utils": "^0.1.3", + "@backstage/test-utils": "^0.1.4", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -35,9 +35,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 0a396efd41..6557dfe924 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-backend +## 0.3.1 + +### Patch Changes + +- ae95c7ff3: Update URL auth format for Gitlab clone +- Updated dependencies [612368274] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] + - @backstage/backend-common@0.3.3 + - @backstage/catalog-model@0.4.0 + ## 0.3.0 ### Minor Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index bf67108457..773b5a5d5c 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "0.3.0", + "version": "0.3.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.3.2", - "@backstage/catalog-model": "^0.3.1", + "@backstage/backend-common": "^0.3.3", + "@backstage/catalog-model": "^0.4.0", "@backstage/config": "^0.1.1", "@types/dockerode": "^2.5.34", "@types/express": "^4.17.6", @@ -39,7 +39,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.3.2", + "@backstage/cli": "^0.4.0", "supertest": "^4.0.2" }, "files": [ diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 5076362774..b3f1507f9f 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-techdocs +## 0.3.1 + +### Patch Changes + +- da2ad65cb: Use type EntityName from catalog-model for entities +- Updated dependencies [b4488ddb0] +- Updated dependencies [08835a61d] +- Updated dependencies [a9fd599f7] +- Updated dependencies [bcc211a08] +- Updated dependencies [ebf37bbae] + - @backstage/core-api@0.2.4 + - @backstage/catalog-model@0.4.0 + - @backstage/plugin-catalog@0.2.5 + - @backstage/test-utils@0.1.4 + ## 0.3.0 ### Minor Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index c8bca7d07e..d3cd6cdf64 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "0.3.0", + "version": "0.3.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.3.1", + "@backstage/catalog-model": "^0.4.0", "@backstage/core": "^0.3.2", - "@backstage/core-api": "^0.2.3", - "@backstage/plugin-catalog": "^0.2.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/core-api": "^0.2.4", + "@backstage/plugin-catalog": "^0.2.5", + "@backstage/test-utils": "^0.1.4", "@backstage/theme": "^0.2.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -39,9 +39,9 @@ "sanitize-html": "^1.27.0" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index da4c2cd1cd..e1b94e85d9 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -32,9 +32,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/welcome/CHANGELOG.md b/plugins/welcome/CHANGELOG.md index e6165ef4f9..b1111eb107 100644 --- a/plugins/welcome/CHANGELOG.md +++ b/plugins/welcome/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-welcome +## 0.2.2 + +### Patch Changes + +- 303c5ea17: Refactor route registration to remove deprecating code + ## 0.2.1 ### Patch Changes diff --git a/plugins/welcome/package.json b/plugins/welcome/package.json index 167bb07565..fe1d2e1604 100644 --- a/plugins/welcome/package.json +++ b/plugins/welcome/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-welcome", - "version": "0.2.1", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -32,9 +32,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.3.2", - "@backstage/dev-utils": "^0.1.4", - "@backstage/test-utils": "^0.1.3", + "@backstage/cli": "^0.4.0", + "@backstage/dev-utils": "^0.1.5", + "@backstage/test-utils": "^0.1.4", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7",