diff --git a/.changeset/angry-eels-watch.md b/.changeset/angry-eels-watch.md deleted file mode 100644 index cd252d5558..0000000000 --- a/.changeset/angry-eels-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-rollbar-backend': patch ---- - -Moved `@backstage/test-utils` to `devDependencies`. diff --git a/.changeset/beige-wolves-kneel.md b/.changeset/beige-wolves-kneel.md deleted file mode 100644 index 2c768a3f03..0000000000 --- a/.changeset/beige-wolves-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Lazy-load `testcontainers` module in order to avoid side-effects. diff --git a/.changeset/chatty-gifts-fry.md b/.changeset/chatty-gifts-fry.md deleted file mode 100644 index 25f0a70bd9..0000000000 --- a/.changeset/chatty-gifts-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Replaces the usage of `got` with `node-fetch` in the `getUserPhoto` method of the Microsoft provider diff --git a/.changeset/chatty-wombats-buy.md b/.changeset/chatty-wombats-buy.md deleted file mode 100644 index aa743a6a71..0000000000 --- a/.changeset/chatty-wombats-buy.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -removed inline and internal CSS from index.html - -To make this change to an existing app, apply the following changes to the `packages/app/public/index.html` file: - -Remove internal style - -```diff -- -``` - -Remove inline style from the body tag - -```diff -- -+ -``` diff --git a/.changeset/curly-bugs-stare.md b/.changeset/curly-bugs-stare.md deleted file mode 100644 index 88e1d86e84..0000000000 --- a/.changeset/curly-bugs-stare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -Fixed an accidental re-export of `@backstage/test-utils` that broke this plugin in the most recent release. diff --git a/.changeset/curly-pillows-provide.md b/.changeset/curly-pillows-provide.md deleted file mode 100644 index e6a218233b..0000000000 --- a/.changeset/curly-pillows-provide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/test-utils': patch ---- - -JSON serialize and freeze values stored by the `MockStorageApi`. diff --git a/.changeset/cyan-goats-confess.md b/.changeset/cyan-goats-confess.md deleted file mode 100644 index 0ba500dc7f..0000000000 --- a/.changeset/cyan-goats-confess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/techdocs-common': patch ---- - -Bump `@azure/identity` from `^1.5.0` to `^2.0.1`. diff --git a/.changeset/dar-jag-gar.md b/.changeset/dar-jag-gar.md deleted file mode 100644 index 5989614101..0000000000 --- a/.changeset/dar-jag-gar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -In-memory cache clients instantiated from the same cache manager now share the same memory space. diff --git a/.changeset/eight-worms-report.md b/.changeset/eight-worms-report.md deleted file mode 100644 index 1dc12db0e4..0000000000 --- a/.changeset/eight-worms-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Use the default CSP policy provided by `helmet` directly rather than a copy. diff --git a/.changeset/eighty-dancers-heal.md b/.changeset/eighty-dancers-heal.md deleted file mode 100644 index 9286e75d2c..0000000000 --- a/.changeset/eighty-dancers-heal.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Update `auth0` and `onelogin` providers to allow for `authHandler` and `signIn.resolver` configuration. diff --git a/.changeset/eleven-pianos-fail.md b/.changeset/eleven-pianos-fail.md deleted file mode 100644 index 5b0aa76ae9..0000000000 --- a/.changeset/eleven-pianos-fail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Fixed bug on refresh token on Okta provider, now it gets the refresh token and it sends it into providerInfo diff --git a/.changeset/fluffy-toys-tease.md b/.changeset/fluffy-toys-tease.md deleted file mode 100644 index f20eaebb2c..0000000000 --- a/.changeset/fluffy-toys-tease.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights': minor ---- - -fixes api auth in tech-insights plugin diff --git a/.changeset/four-phones-shave.md b/.changeset/four-phones-shave.md deleted file mode 100644 index 1ef58bdadb..0000000000 --- a/.changeset/four-phones-shave.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@backstage/plugin-auth-backend': minor ---- - -Avoid ever returning OAuth refresh tokens back to the client, and always exchange refresh tokens for a new one when available for all providers. - -This comes with a breaking change to the TypeScript API for custom auth providers. The `refresh` method of `OAuthHandlers` implementation must now return a `{ response, refreshToken }` object rather than a direct response. Existing `refresh` implementations are typically migrated by changing an existing return expression that looks like this: - -```ts -return await this.handleResult({ - fullProfile, - params, - accessToken, - refreshToken, -}); -``` - -Into the following: - -```ts -return { - response: await this.handleResult({ - fullProfile, - params, - accessToken, - }), - refreshToken, -}; -``` diff --git a/.changeset/four-waves-tan.md b/.changeset/four-waves-tan.md deleted file mode 100644 index 444891d31b..0000000000 --- a/.changeset/four-waves-tan.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Internal cleanup of the exports structure diff --git a/.changeset/great-mayflies-travel.md b/.changeset/great-mayflies-travel.md new file mode 100644 index 0000000000..6927cc2a5e --- /dev/null +++ b/.changeset/great-mayflies-travel.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': patch +--- + +Fix missing search context issue with `HomePageSearchBar` diff --git a/.changeset/happy-moose-worry.md b/.changeset/happy-moose-worry.md deleted file mode 100644 index 66f0728f7d..0000000000 --- a/.changeset/happy-moose-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Removed unused templating asset. diff --git a/.changeset/honest-chefs-mate.md b/.changeset/honest-chefs-mate.md deleted file mode 100644 index dfc1ff16fb..0000000000 --- a/.changeset/honest-chefs-mate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-app-backend': patch ---- - -Set `X-Frame-Options: deny` rather than the default `sameorigin` for all content served by the `app-backend`.` diff --git a/.changeset/light-singers-double.md b/.changeset/light-singers-double.md deleted file mode 100644 index e21017373d..0000000000 --- a/.changeset/light-singers-double.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fix issue with plugin:serve for Plugins not using Lerna monorepo. diff --git a/.changeset/long-waves-hear.md b/.changeset/long-waves-hear.md deleted file mode 100644 index 8decec294b..0000000000 --- a/.changeset/long-waves-hear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -remove inline CSS from serve_index.html diff --git a/.changeset/lucky-bats-reflect.md b/.changeset/lucky-bats-reflect.md deleted file mode 100644 index ad3171382e..0000000000 --- a/.changeset/lucky-bats-reflect.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-scaffolder-backend': patch ---- - -Uptake changes to the GitHub Credentials Provider interface. diff --git a/.changeset/modern-buses-protect.md b/.changeset/modern-buses-protect.md deleted file mode 100644 index 2aed52eca0..0000000000 --- a/.changeset/modern-buses-protect.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -When a user has zero owned entities when viewing an entity kind in the catalog -page, it will be automatically redirected to see all the entities. Furthermore, -for the kind User and Group there are no longer the owned selector. diff --git a/.changeset/modern-waves-lay.md b/.changeset/modern-waves-lay.md deleted file mode 100644 index c0d9804379..0000000000 --- a/.changeset/modern-waves-lay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Add a comment to the default backend about the fallback 404 handler. diff --git a/.changeset/neat-insects-ring.md b/.changeset/neat-insects-ring.md deleted file mode 100644 index a46b6d44e3..0000000000 --- a/.changeset/neat-insects-ring.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Add the techdocs.sanitizer.allowedIframeHosts config. -This config allows all iframes which have the host of the attribute src in the 'allowedIframehosts' list to be displayed in the documentation. diff --git a/.changeset/new-tips-shop.md b/.changeset/new-tips-shop.md deleted file mode 100644 index 3ab4e817d0..0000000000 --- a/.changeset/new-tips-shop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@techdocs/cli': patch ---- - -remove internal and inline CSS from index.html diff --git a/.changeset/plenty-flies-repair.md b/.changeset/plenty-flies-repair.md deleted file mode 100644 index 7e9690a7f3..0000000000 --- a/.changeset/plenty-flies-repair.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-rollbar-backend': patch ---- - -Replace the usage of `axios` with `node-fetch` in the Rollbar API diff --git a/.changeset/poor-zoos-invent.md b/.changeset/poor-zoos-invent.md deleted file mode 100644 index a1c87bd3ad..0000000000 --- a/.changeset/poor-zoos-invent.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/plugin-scaffolder-common': patch ---- - -Support navigating back to pre-filled templates to update inputs of scaffolder tasks for resubmission diff --git a/.changeset/purple-trains-matter.md b/.changeset/purple-trains-matter.md new file mode 100644 index 0000000000..39531e4680 --- /dev/null +++ b/.changeset/purple-trains-matter.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Add Override Components for Components in @backstage/plugin-catalog-react diff --git a/.changeset/search-en-jul-hemma.md b/.changeset/search-en-jul-hemma.md deleted file mode 100644 index 9fae9fcaa5..0000000000 --- a/.changeset/search-en-jul-hemma.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Introduces a `` variant, which operates on the same part of a search query as the existing ``, but in a more opinionated way (as a single-select control surface suitable for faceted search UIs). - -Check the [search plugin storybook](https://backstage.io/storybook/?path=/story/plugins-search-searchtype--accordion) to see how it can be used. diff --git a/.changeset/search-odd-starfishes-raise.md b/.changeset/search-odd-starfishes-raise.md deleted file mode 100644 index 73627cf457..0000000000 --- a/.changeset/search-odd-starfishes-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Captures the search term entered in the SearchBarBase as a `search` event. diff --git a/.changeset/search-over-tysta-skogor.md b/.changeset/search-over-tysta-skogor.md deleted file mode 100644 index 5398ae7f5f..0000000000 --- a/.changeset/search-over-tysta-skogor.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -The `` filter in the composed `SearchPage.tsx` was replaced with the `` variant. - -This is an entirely optional change; if you wish to display a control surface for search `types` as a single-select accordion (as opposed to the current multi-select of checkboxes), you can make the following (or similar) changes to your search page layout: - -```diff ---- a/packages/app/src/components/search/SearchPage.tsx -+++ b/packages/app/src/components/search/SearchPage.tsx -@@ -11,7 +11,7 @@ import { - SearchType, - DefaultResultListItem, - } from '@backstage/plugin-search'; --import { Content, Header, Page } from '@backstage/core-components'; -+import { CatalogIcon, Content, DocsIcon, Header, Page } from '@backstage/core-components'; - - const useStyles = makeStyles((theme: Theme) => ({ - bar: { -@@ -19,6 +19,7 @@ const useStyles = makeStyles((theme: Theme) => ({ - }, - filters: { - padding: theme.spacing(2), -+ marginTop: theme.spacing(2), - }, - filter: { - '& + &': { -@@ -41,12 +42,23 @@ const SearchPage = () => { - - - -+ , -+ }, -+ { -+ value: 'techdocs', -+ name: 'Documentation', -+ icon: , -+ }, -+ ]} -+ /> - -- - { - // ... -+ const scheduler = taskScheduler.forPlugin(plugin); - return { -+ scheduler, - // ... -``` diff --git a/.changeset/slimy-socks-pump.md b/.changeset/slimy-socks-pump.md deleted file mode 100644 index f7252340f1..0000000000 --- a/.changeset/slimy-socks-pump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights': patch ---- - -Export `techInsightsApiRef` and associated types. diff --git a/.changeset/small-monkeys-live.md b/.changeset/small-monkeys-live.md new file mode 100644 index 0000000000..2e5a8ff719 --- /dev/null +++ b/.changeset/small-monkeys-live.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-insights': patch +--- + +remove unnecessary http request when running all checks diff --git a/.changeset/small-points-allow.md b/.changeset/small-points-allow.md deleted file mode 100644 index 2228fc8883..0000000000 --- a/.changeset/small-points-allow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -Bump `typescript-json-schema` from `^0.51.0` to `^0.52.0`. diff --git a/.changeset/spicy-moons-poke.md b/.changeset/spicy-moons-poke.md deleted file mode 100644 index cc39d629bf..0000000000 --- a/.changeset/spicy-moons-poke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-tech-insights-backend-module-jsonfc': patch ---- - -ability to add custom operators diff --git a/.changeset/tame-ways-prove.md b/.changeset/tame-ways-prove.md deleted file mode 100644 index 4f625d0a05..0000000000 --- a/.changeset/tame-ways-prove.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Add option to build command for minifying the generated code diff --git a/.changeset/tender-ducks-tie.md b/.changeset/tender-ducks-tie.md new file mode 100644 index 0000000000..ada9f2bf37 --- /dev/null +++ b/.changeset/tender-ducks-tie.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-api-docs': patch +'@backstage/plugin-catalog': patch +--- + +Support customizing index page layouts via outlets diff --git a/.changeset/twenty-hornets-train.md b/.changeset/twenty-hornets-train.md deleted file mode 100644 index 957bfd00da..0000000000 --- a/.changeset/twenty-hornets-train.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Enforce cookie SSL protection when in production for auth-backend sessions diff --git a/.changeset/two-rice-pull.md b/.changeset/two-rice-pull.md new file mode 100644 index 0000000000..3c6138094d --- /dev/null +++ b/.changeset/two-rice-pull.md @@ -0,0 +1,9 @@ +--- +'@backstage/backend-tasks': patch +--- + +Updated README to clarify the following: + +- Dashes cannot be used in the `id`, changed to an underscore in the example +- The `timeout` is required, this was also added to the example +- Added a note about tasks not running as expected for local development using persistent database diff --git a/.changeset/wet-chefs-exercise.md b/.changeset/wet-chefs-exercise.md deleted file mode 100644 index cf8a2e538e..0000000000 --- a/.changeset/wet-chefs-exercise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Display entity title on `ApiDefinitionCard` if defined diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7222edef08..109f90eff6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,6 +124,9 @@ jobs: - name: check api reports and generate API reference run: yarn build:api-reports:only --ci --docs + - name: verify changesets + run: node scripts/verify-changesets.js + - name: verify doc links run: node scripts/verify-links.js diff --git a/ADOPTERS.md b/ADOPTERS.md index 32dff321ca..95f7812636 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -78,3 +78,4 @@ | [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 | | [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. | | [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding | +| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. | diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 32ab830322..492cd86022 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -39,6 +39,7 @@ kubernetes: region: 'europe-west1' skipTLSVerify: true skipMetricsLookup: true + exposeDashboard: true ``` ### `serviceLocatorMethod` @@ -113,9 +114,13 @@ kubectl -n get secret $(kubectl -n get sa Note: The catalog index page is designed to have a minimal code footprint to > support easy customization, but creating a copy does introduce a possibility @@ -21,12 +20,11 @@ the catalog - you can replace the routing in `App.tsx` to point to your own For example, suppose that I want to allow filtering by a custom annotation added to entities, `company.com/security-tier`. To start, I'll copy the code for the -default catalog page and create a component in a -[new plugin](../../plugins/create-a-plugin.md): +default catalog page and create a component. ```tsx // imports, etc omitted for brevity. for full source see: -// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx +// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx export const CustomCatalogPage = ({ columns, actions, @@ -167,21 +165,7 @@ export const CustomCatalogPage = ({ }; ``` -This page itself can be exported as a routable extension in the plugin: - -```ts -export const CustomCatalogIndexPage = myPlugin.provide( - createRoutableExtension({ - name: 'CustomCatalogIndexPage', - component: () => - import('./components/CustomCatalogPage').then(m => m.CustomCatalogPage), - mountPoint: catalogRouteRef, - }), -); -``` - -Finally, we can replace the catalog route in the Backstage application with our -new `CustomCatalogIndexPage`. +Finally, we can apply our new `CustomCatalogPage`. ```diff # packages/app/src/App.tsx @@ -189,7 +173,9 @@ const routes = ( - } /> -+ } /> ++ }> ++ ++ ``` The same method can be used to customize the _default_ filters with a different diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index a4ca0771df..b9b74f92dd 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -53,8 +53,10 @@ To add a custom theme to your Backstage app, you pass it as configuration to For example, adding the theme that we created in the previous section can be done like this: -```ts +```tsx import { createApp } from '@backstage/app-defaults'; +import { ThemeProvider } from '@material-ui/core/styles'; +import CssBaseline from '@material-ui/core/CssBaseline'; const app = createApp({ apis: ..., @@ -63,7 +65,11 @@ const app = createApp({ id: 'my-theme', title: 'My Custom Theme', variant: 'light', - theme: myTheme, + Provider: ({ children }) => ( + + {children} + + ), }] }) ``` @@ -76,60 +82,67 @@ want to use the default themes, they are exported as `lightTheme` and ## Example of a custom theme ```ts -const themeOptions = createThemeOptions({ +import { + createTheme, + genPageTheme, + lightTheme, + shapes, +} from '@backstage/theme'; + +const myTheme = createTheme({ palette: { ...lightTheme.palette, primary: { - main: '#123456', + main: '#343b58', }, secondary: { - main: '#123456', + main: '#565a6e', }, error: { - main: '#123456', + main: '#8c4351', }, warning: { - main: '#123456', + main: '#8f5e15', }, info: { - main: '#123456', + main: '#34548a', }, success: { - main: '#123456', + main: '#485e30', }, background: { - default: '#123456', - paper: '#123456', + default: '#d5d6db', + paper: '#d5d6db', }, banner: { - info: '#123456', - error: '#123456', - text: '#123456', - link: '#123456', + info: '#34548a', + error: '#8c4351', + text: '#343b58', + link: '#565a6e', }, - errorBackground: '#123456', - warningBackground: '#123456', - infoBackground: '#123456', + errorBackground: '#8c4351', + warningBackground: '#8f5e15', + infoBackground: '#343b58', navigation: { - background: '#123456', - indicator: '#123456', - color: '#123456', - selectedColor: '#123456', + background: '#343b58', + indicator: '#8f5e15', + color: '#d5d6db', + selectedColor: '#ffffff', }, }, defaultPageTheme: 'home', - fontFamily: 'Comic Sans', + fontFamily: 'Comic Sans MS', /* below drives the header colors */ pageTheme: { - home: genPageTheme(['#123456', '#123456'], shapes.wave), - documentation: genPageTheme(['#123456', '#123456'], shapes.wave2), - tool: genPageTheme(['#123456', '#123456'], shapes.round), - service: genPageTheme(['#123456', '#123456'], shapes.wave), - website: genPageTheme(['#123456', '#123456'], shapes.wave), - library: genPageTheme(['#123456', '#123456'], shapes.wave), - other: genPageTheme(['#123456', '#123456'], shapes.wave), - app: genPageTheme(['#123456', '#123456'], shapes.wave), - apis: genPageTheme(['#123456', '#123456'], shapes.wave), + home: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + documentation: genPageTheme(['#8c4351', '#343b58'], shapes.wave2), + tool: genPageTheme(['#8c4351', '#343b58'], shapes.round), + service: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + website: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + library: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + other: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + app: genPageTheme(['#8c4351', '#343b58'], shapes.wave), + apis: genPageTheme(['#8c4351', '#343b58'], shapes.wave), }, }); ``` @@ -162,7 +175,7 @@ wouldn't be enough to alter the `box-shadow` property or to add css rules that aren't already defined like a margin. For these cases you should also create an override. -```ts +```tsx import { createApp } from '@backstage/core-app-api'; import { BackstageTheme, lightTheme } from '@backstage/theme'; /** @@ -187,6 +200,16 @@ export const createCustomThemeOverrides = ( }; }; +const customTheme: BackstageTheme = { + ...lightTheme, + overrides: { + // These are the overrides that Backstage applies to `material-ui` components + ...lightTheme.overrides, + // These are your custom overrides, either to `material-ui` or Backstage components. + ...createCustomThemeOverrides(lightTheme), + }, +}; + const app = createApp({ apis: ..., plugins: ..., @@ -194,15 +217,11 @@ const app = createApp({ id: 'my-theme', title: 'My Custom Theme', variant: 'light', - theme: { - ...lightTheme, - overrides: { - // These are the overrides that Backstage applies to `material-ui` components - ...lightTheme.overrides, - // These are your custom overrides, either to `material-ui` or Backstage components. - ...createCustomThemeOverrides(lightTheme), - }, - }, + Provider: ({ children }) => ( + + {children} + + ), }] }); ``` diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 0f7b64ad5e..11c1cf7777 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/backend-common +## 0.10.1 + +### Patch Changes + +- 94cdf5d1bd: In-memory cache clients instantiated from the same cache manager now share the same memory space. +- 916b2f1f3e: Use the default CSP policy provided by `helmet` directly rather than a copy. +- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface. +- 995e4c7d9d: Added support for non-"amazonaws.com" hosts (for example when testing with LocalStack) in AwsS3UrlReader. +- Updated dependencies + - @backstage/integration@0.7.0 + - @backstage/config-loader@0.9.1 + ## 0.10.0 ### Minor Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index cde1a7f67f..3aa368f963 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.10.0", + "version": "0.10.1", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -31,9 +31,9 @@ "dependencies": { "@backstage/cli-common": "^0.1.6", "@backstage/config": "^0.1.11", - "@backstage/config-loader": "^0.9.0", + "@backstage/config-loader": "^0.9.1", "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@backstage/types": "^0.1.1", "@google-cloud/storage": "^5.8.0", "@lerna/project": "^4.0.0", @@ -81,8 +81,8 @@ } }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.10.4", + "@backstage/test-utils": "^0.2.1", "@types/archiver": "^5.1.0", "@types/compression": "^1.7.0", "@types/concat-stream": "^1.6.0", diff --git a/packages/backend-common/src/reading/AwsS3UrlReader.test.ts b/packages/backend-common/src/reading/AwsS3UrlReader.test.ts index a3ae8b647f..2911699a5d 100644 --- a/packages/backend-common/src/reading/AwsS3UrlReader.test.ts +++ b/packages/backend-common/src/reading/AwsS3UrlReader.test.ts @@ -178,7 +178,7 @@ describe('AwsS3UrlReader', () => { ), ).rejects.toThrow( Error( - `Could not retrieve file from S3; caused by Error: not a valid AWS S3 URL: https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`, + `Could not retrieve file from S3; caused by Error: invalid AWS S3 URL, cannot parse region from host in https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`, ), ); }); @@ -234,7 +234,7 @@ describe('AwsS3UrlReader', () => { ), ).rejects.toThrow( Error( - `Could not retrieve file from S3; caused by Error: not a valid AWS S3 URL: https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`, + `Could not retrieve file from S3; caused by Error: invalid AWS S3 URL, cannot parse region from host in https://test-bucket.s3.us-east-2.NOTamazonaws.com/file.yaml`, ), ); }); @@ -332,4 +332,47 @@ describe('AwsS3UrlReader', () => { expect(body.toString().trim()).toBe('site_name: Test'); }); }); + + describe('readNonAwsHost', () => { + let awsS3UrlReader: AwsS3UrlReader; + + beforeAll(() => { + AWSMock.setSDKInstance(aws); + AWSMock.mock( + 'S3', + 'getObject', + Buffer.from( + require('fs').readFileSync( + path.resolve( + __dirname, + '__fixtures__/awsS3/awsS3-mock-object.yaml', + ), + ), + ), + ); + + const s3 = new aws.S3(); + awsS3UrlReader = new AwsS3UrlReader( + new AwsS3Integration( + readAwsS3IntegrationConfig( + new ConfigReader({ + host: 'localhost:4566', + accessKeyId: 'fake-access-key', + secretAccessKey: 'fake-secret-key', + endpoint: 'http://localhost:4566', + s3ForcePathStyle: true, + }), + ), + ), + { s3, treeResponseFactory }, + ); + }); + + it('returns contents of an object in a bucket', async () => { + const response = await awsS3UrlReader.read( + 'http://localhost:4566/test-bucket/awsS3-mock-object.yaml', + ); + expect(response.toString().trim()).toBe('site_name: Test'); + }); + }); }); diff --git a/packages/backend-common/src/reading/AwsS3UrlReader.ts b/packages/backend-common/src/reading/AwsS3UrlReader.ts index 0d806fcfaa..1fca72e91c 100644 --- a/packages/backend-common/src/reading/AwsS3UrlReader.ts +++ b/packages/backend-common/src/reading/AwsS3UrlReader.ts @@ -27,12 +27,17 @@ import { UrlReader, } from './types'; import getRawBody from 'raw-body'; -import { AwsS3Integration, ScmIntegrations } from '@backstage/integration'; +import { + AwsS3Integration, + ScmIntegrations, + AwsS3IntegrationConfig, +} from '@backstage/integration'; import { ForwardedError, NotModifiedError } from '@backstage/errors'; import { ListObjectsV2Output, ObjectList } from 'aws-sdk/clients/s3'; const parseURL = ( url: string, + config: AwsS3IntegrationConfig, ): { path: string; bucket: string; region: string } => { let { host, pathname } = new URL(url); @@ -42,20 +47,45 @@ const parseURL = ( */ pathname = pathname.substr(1); + let bucket; + let region; + /** - * Checks that the given URL is a valid S3 object url. - * Format of a Valid S3 URL: https://bucket-name.s3.Region.amazonaws.com/keyname + * Path style URLs: https://s3.Region.amazonaws.com/bucket-name/key-name + * Virtual hosted style URLs: https://bucket-name.s3.Region.amazonaws.com/key-name + * See https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access */ - const validHost = new RegExp( - /^[a-z\d][a-z\d\.-]{1,61}[a-z\d]\.s3\.[a-z\d-]+\.amazonaws.com$/, - ); - if (!validHost.test(host)) { - throw new Error(`not a valid AWS S3 URL: ${url}`); + if (config.s3ForcePathStyle) { + if (pathname.indexOf('/') < 0) { + throw new Error( + `invalid path-style AWS S3 URL, ${url} does not contain bucket in the path`, + ); + } + [bucket] = pathname.split('/'); + pathname = pathname.substr(bucket.length + 1); + } else { + if (host.indexOf('.') < 0) { + throw new Error( + `invalid virtual hosted-style AWS S3 URL, ${url} does not contain bucket prefix in the host`, + ); + } + [bucket] = host.split('.'); + host = host.substr(bucket.length + 1); } - const [bucket] = host.split(/\.s3\.[a-z\d-]+\.amazonaws.com/); - host = host.substring(bucket.length); - const [, , region, ,] = host.split('.'); + // Only extract region from *.amazonaws.com hosts + if (config.host === 'amazonaws.com') { + // At this point bucket prefix is removed from host for virtual hosted URLs + const match = host.match(/^s3\.([a-z\d-]+)\.amazonaws\.com$/); + if (!match) { + throw new Error( + `invalid AWS S3 URL, cannot parse region from host in ${url}`, + ); + } + region = match[1]; + } else { + region = ''; + } return { path: pathname, @@ -70,9 +100,12 @@ export class AwsS3UrlReader implements UrlReader { return integrations.awsS3.list().map(integration => { const creds = AwsS3UrlReader.buildCredentials(integration); + const s3 = new S3({ apiVersion: '2006-03-01', credentials: creds, + endpoint: integration.config.endpoint, + s3ForcePathStyle: integration.config.s3ForcePathStyle, }); const reader = new AwsS3UrlReader(integration, { s3, @@ -138,7 +171,7 @@ export class AwsS3UrlReader implements UrlReader { options?: ReadUrlOptions, ): Promise { try { - const { path, bucket, region } = parseURL(url); + const { path, bucket, region } = parseURL(url, this.integration.config); aws.config.update({ region: region }); let params; @@ -178,7 +211,7 @@ export class AwsS3UrlReader implements UrlReader { options?: ReadTreeOptions, ): Promise { try { - const { path, bucket, region } = parseURL(url); + const { path, bucket, region } = parseURL(url, this.integration.config); const allObjects: ObjectList = []; const responses = []; let continuationToken: string | undefined; diff --git a/packages/backend-tasks/README.md b/packages/backend-tasks/README.md index d3c361c02c..fe55f37afd 100644 --- a/packages/backend-tasks/README.md +++ b/packages/backend-tasks/README.md @@ -21,14 +21,19 @@ import { Duration } from 'luxon'; const scheduler = TaskScheduler.fromConfig(rootConfig).forPlugin('my-plugin'); await scheduler.scheduleTask({ - id: 'refresh-things', + id: 'refresh_things', frequency: Duration.fromObject({ minutes: 10 }), + timeout: Duration.fromObject({ minutes: 15 }), fn: async () => { await entityProvider.run(); }, }); ``` +## Local Development + +When working with the `@backstage/backend-tasks` library you may run into your task not running immediately at startup as expected if you are using a persistent database. This is by design - the library respects the previous state and does not run the task sooner than the specified frequency. If you want to get around this, there is a table called `backstage_backend_tasks__tasks` in the applicable plugin's database which will contain a record with the next run date and time. You can delete this record to get things back to what you expect. + ## Documentation - [Backstage Readme](https://github.com/backstage/backstage/blob/master/README.md) diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index b10dadb21c..f484a0fb8f 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-test-utils +## 0.1.12 + +### Patch Changes + +- 130b7aadf2: Lazy-load `testcontainers` module in order to avoid side-effects. +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/cli@0.10.4 + ## 0.1.11 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 218965c79f..e52398f0ef 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.1.11", + "version": "0.1.12", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -30,8 +30,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/cli": "^0.10.3", + "@backstage/backend-common": "^0.10.1", + "@backstage/cli": "^0.10.4", "@backstage/config": "^0.1.9", "knex": "^0.95.1", "mysql2": "^2.2.5", @@ -41,7 +41,7 @@ "uuid": "^8.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "jest": "^26.0.1" }, "files": [ diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 89283122f2..f3c2d4f861 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,25 @@ # example-backend +## 0.2.59 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-rollbar-backend@0.1.18 + - @backstage/plugin-auth-backend@0.6.0 + - @backstage/backend-common@0.10.1 + - @backstage/plugin-app-backend@0.3.21 + - @backstage/plugin-catalog-backend@0.19.4 + - @backstage/plugin-scaffolder-backend@0.15.19 + - @backstage/integration@0.7.0 + - @backstage/plugin-techdocs-backend@0.12.2 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.4 + - @backstage/plugin-permission-backend@0.2.3 + - @backstage/plugin-permission-node@0.2.3 + - @backstage/plugin-code-coverage-backend@0.1.18 + - @backstage/plugin-scaffolder-backend-module-rails@0.2.2 + - @backstage/plugin-todo-backend@0.1.17 + ## 0.2.58 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 4bdcad58f7..f204659789 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.58", + "version": "0.2.59", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,38 +24,38 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/backend-tasks": "^0.1.0", "@backstage/catalog-client": "^0.5.3", "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.10", - "@backstage/integration": "^0.6.10", - "@backstage/plugin-app-backend": "^0.3.20", - "@backstage/plugin-auth-backend": "^0.5.2", + "@backstage/integration": "^0.7.0", + "@backstage/plugin-app-backend": "^0.3.21", + "@backstage/plugin-auth-backend": "^0.6.0", "@backstage/plugin-azure-devops-backend": "^0.2.6", "@backstage/plugin-badges-backend": "^0.1.14", - "@backstage/plugin-catalog-backend": "^0.19.3", - "@backstage/plugin-code-coverage-backend": "^0.1.17", + "@backstage/plugin-catalog-backend": "^0.19.4", + "@backstage/plugin-code-coverage-backend": "^0.1.18", "@backstage/plugin-graphql-backend": "^0.1.10", "@backstage/plugin-jenkins-backend": "^0.1.10", "@backstage/plugin-kubernetes-backend": "^0.4.1", "@backstage/plugin-kafka-backend": "^0.2.13", - "@backstage/plugin-permission-backend": "^0.2.2", + "@backstage/plugin-permission-backend": "^0.2.3", "@backstage/plugin-permission-common": "^0.3.0", - "@backstage/plugin-permission-node": "^0.2.2", + "@backstage/plugin-permission-node": "^0.2.3", "@backstage/plugin-proxy-backend": "^0.2.15", - "@backstage/plugin-rollbar-backend": "^0.1.17", - "@backstage/plugin-scaffolder-backend": "^0.15.18", - "@backstage/plugin-scaffolder-backend-module-rails": "^0.2.1", + "@backstage/plugin-rollbar-backend": "^0.1.18", + "@backstage/plugin-scaffolder-backend": "^0.15.19", + "@backstage/plugin-scaffolder-backend-module-rails": "^0.2.2", "@backstage/plugin-search-backend": "^0.3.0", "@backstage/plugin-search-backend-node": "^0.4.2", "@backstage/plugin-search-backend-module-elasticsearch": "^0.0.7", "@backstage/plugin-search-backend-module-pg": "^0.2.3", - "@backstage/plugin-techdocs-backend": "^0.12.1", + "@backstage/plugin-techdocs-backend": "^0.12.2", "@backstage/plugin-tech-insights-backend": "^0.1.4", "@backstage/plugin-tech-insights-node": "^0.1.2", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.3", - "@backstage/plugin-todo-backend": "^0.1.16", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "^0.1.4", + "@backstage/plugin-todo-backend": "^0.1.17", "@gitbeaker/node": "^34.6.0", "@octokit/rest": "^18.5.3", "azure-devops-node-api": "^11.0.1", @@ -72,7 +72,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/dockerode": "^3.3.0", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 73e49693c2..8847545348 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/cli +## 0.10.4 + +### Patch Changes + +- 1d26017090: Fix issue with plugin:serve for Plugins not using Lerna monorepo. +- 9c3aaf3512: Bump `@typescript-eslint/eslint-plugin` to `4.33.0` +- 808828e4fa: remove inline CSS from serve_index.html +- 6e4080d31b: Add option to build command for minifying the generated code +- Updated dependencies + - @backstage/config-loader@0.9.1 + ## 0.10.3 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 42a33da0db..21ba9b00b1 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.10.3", + "version": "0.10.4", "private": false, "publishConfig": { "access": "public" @@ -30,7 +30,7 @@ "dependencies": { "@backstage/cli-common": "^0.1.6", "@backstage/config": "^0.1.11", - "@backstage/config-loader": "^0.9.0", + "@backstage/config-loader": "^0.9.1", "@backstage/errors": "^0.1.5", "@backstage/types": "^0.1.1", "@hot-loader/react-dom": "^16.13.0", @@ -51,7 +51,7 @@ "@svgr/rollup": "5.5.x", "@svgr/webpack": "5.5.x", "@types/webpack-env": "^1.15.2", - "@typescript-eslint/eslint-plugin": "^v4.30.0", + "@typescript-eslint/eslint-plugin": "^v4.33.0", "@typescript-eslint/parser": "^v4.28.3", "@yarnpkg/lockfile": "^1.1.0", "bfj": "^7.0.2", @@ -114,13 +114,13 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/config": "^0.1.11", "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@backstage/theme": "^0.2.14", "@types/diff": "^5.0.0", "@types/express": "^4.17.6", diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index cadd31555b..36aae32e8b 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/config-loader +## 0.9.1 + +### Patch Changes + +- 84663d59a3: Bump `typescript-json-schema` from `^0.51.0` to `^0.52.0`. + ## 0.9.0 ### Minor Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 07fab1fd82..d909cde58c 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.9.0", + "version": "0.9.1", "private": false, "publishConfig": { "access": "public", diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 9d71eadeb0..969b9da42b 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,125 @@ # @backstage/create-app +## 0.4.10 + +### Patch Changes + +- 79b342bd36: removed inline and internal CSS from index.html + + To make this change to an existing app, apply the following changes to the `packages/app/public/index.html` file: + + Remove internal style + + ```diff + - + ``` + + Remove inline style from the body tag + + ```diff + - + + + ``` + +- d33b65dc52: Removed unused templating asset. +- 613ad12960: Add a comment to the default backend about the fallback 404 handler. +- 20af5a701f: The `` filter in the composed `SearchPage.tsx` was replaced with the `` variant. + + This is an entirely optional change; if you wish to display a control surface for search `types` as a single-select accordion (as opposed to the current multi-select of checkboxes), you can make the following (or similar) changes to your search page layout: + + ```diff + --- a/packages/app/src/components/search/SearchPage.tsx + +++ b/packages/app/src/components/search/SearchPage.tsx + @@ -11,7 +11,7 @@ import { + SearchType, + DefaultResultListItem, + } from '@backstage/plugin-search'; + -import { Content, Header, Page } from '@backstage/core-components'; + +import { CatalogIcon, Content, DocsIcon, Header, Page } from '@backstage/core-components'; + + const useStyles = makeStyles((theme: Theme) => ({ + bar: { + @@ -19,6 +19,7 @@ const useStyles = makeStyles((theme: Theme) => ({ + }, + filters: { + padding: theme.spacing(2), + + marginTop: theme.spacing(2), + }, + filter: { + '& + &': { + @@ -41,12 +42,23 @@ const SearchPage = () => { + + + + + , + + }, + + { + + value: 'techdocs', + + name: 'Documentation', + + icon: , + + }, + + ]} + + /> + + - + { + // ... + + const scheduler = taskScheduler.forPlugin(plugin); + return { + + scheduler, + // ... + ``` + ## 0.4.9 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 810df43f47..af1d20b215 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.9", + "version": "0.4.10", "private": false, "publishConfig": { "access": "public" diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index 680ffc4847..121b778143 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/integration-react +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@0.7.0 + ## 0.1.16 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index 97d8ebea1a..62f9e8d593 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-react", "description": "Frontend package for managing integrations towards external systems", - "version": "0.1.16", + "version": "0.1.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,7 +24,7 @@ "@backstage/config": "^0.1.11", "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -35,9 +35,9 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index e3380082f7..359d2dd11e 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/integration +## 0.7.0 + +### Minor Changes + +- 7d4b4e937c: Create an interface for the GitHub credentials provider in order to support providing implementations. + + We have changed the name of the `GithubCredentialsProvider` to `SingleInstanceGithubCredentialsProvider`. + + `GithubCredentialsProvider` is now an interface that maybe implemented to provide a custom mechanism to retrieve GitHub credentials. + + In a later release we will support configuring URL readers, scaffolder tasks, and processors with customer GitHub credentials providers. + + If you want to uptake this release, you will need to replace all references to `GithubCredentialsProvider.create` with `SingleInstanceGithubCredentialsProvider.create`. + +### Patch Changes + +- cf2e20a792: Added `endpoint` and `s3ForcePathStyle` as optional configuration for AWS S3 integrations. + ## 0.6.10 ### Patch Changes diff --git a/packages/integration/api-report.md b/packages/integration/api-report.md index 00623dc917..8e74470973 100644 --- a/packages/integration/api-report.md +++ b/packages/integration/api-report.md @@ -30,6 +30,8 @@ export class AwsS3Integration implements ScmIntegration { // @public export type AwsS3IntegrationConfig = { host: string; + endpoint?: string; + s3ForcePathStyle?: boolean; accessKeyId?: string; secretAccessKey?: string; roleArn?: string; diff --git a/packages/integration/config.d.ts b/packages/integration/config.d.ts index 90cc10f77b..8873f0f220 100644 --- a/packages/integration/config.d.ts +++ b/packages/integration/config.d.ts @@ -167,10 +167,23 @@ export interface Config { /** Integration configuration for AWS S3 Service */ awsS3?: Array<{ /** - * The host of the target that this matches on, e.g. "amazonaws.com". + * AWS Endpoint. + * The endpoint URI to send requests to. The default endpoint is built from the configured region. + * @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property + * + * Supports non-AWS providers, e.g. for LocalStack, endpoint may look like http://localhost:4566 * @visibility frontend */ - host: string; + endpoint?: string; + + /** + * Whether to use path style URLs when communicating with S3. + * Defaults to false. + * This allows providers like LocalStack, Minio and Wasabi (and possibly others) to be used. + * @visibility frontend + */ + s3ForcePathStyle?: boolean; + /** * Account access key used to authenticate requests. * @visibility backend diff --git a/packages/integration/package.json b/packages/integration/package.json index ccf005ccec..ae674d2cf1 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "0.6.10", + "version": "0.7.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,9 +39,9 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/config-loader": "^0.9.0", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.10.4", + "@backstage/config-loader": "^0.9.1", + "@backstage/test-utils": "^0.2.1", "@types/jest": "^26.0.7", "@types/luxon": "^2.0.4", "msw": "^0.35.0" diff --git a/packages/integration/src/awsS3/AwsS3Integration.test.ts b/packages/integration/src/awsS3/AwsS3Integration.test.ts index 481f3c1951..2987f46a8a 100644 --- a/packages/integration/src/awsS3/AwsS3Integration.test.ts +++ b/packages/integration/src/awsS3/AwsS3Integration.test.ts @@ -24,7 +24,7 @@ describe('AwsS3Integration', () => { integrations: { awsS3: [ { - host: 'a.com', + endpoint: 'https://a.com', accessKeyId: 'access key', secretAccessKey: 'secret key', }, diff --git a/packages/integration/src/awsS3/config.test.ts b/packages/integration/src/awsS3/config.test.ts index 1c7d7d1647..4885a41a2a 100644 --- a/packages/integration/src/awsS3/config.test.ts +++ b/packages/integration/src/awsS3/config.test.ts @@ -26,16 +26,33 @@ describe('readAwsS3IntegrationConfig', () => { return new ConfigReader(data); } - it('reads all values', () => { + it('reads all values (default)', () => { const output = readAwsS3IntegrationConfig( buildConfig({ - host: 'amazonaws.com', accessKeyId: 'fake-key', secretAccessKey: 'fake-secret-key', }), ); expect(output).toEqual({ host: 'amazonaws.com', + s3ForcePathStyle: false, + accessKeyId: 'fake-key', + secretAccessKey: 'fake-secret-key', + }); + }); + it('reads all values (endpoint)', () => { + const output = readAwsS3IntegrationConfig( + buildConfig({ + endpoint: 'http://localhost:4566', + s3ForcePathStyle: true, + accessKeyId: 'fake-key', + secretAccessKey: 'fake-secret-key', + }), + ); + expect(output).toEqual({ + host: 'localhost:4566', + endpoint: 'http://localhost:4566', + s3ForcePathStyle: true, accessKeyId: 'fake-key', secretAccessKey: 'fake-secret-key', }); @@ -59,6 +76,7 @@ describe('readAwsS3IntegrationConfigs', () => { ); expect(output).toContainEqual({ host: 'amazonaws.com', + s3ForcePathStyle: false, accessKeyId: 'key', secretAccessKey: 'secret', }); diff --git a/packages/integration/src/awsS3/config.ts b/packages/integration/src/awsS3/config.ts index 6b5a23c85c..45cbdbe210 100644 --- a/packages/integration/src/awsS3/config.ts +++ b/packages/integration/src/awsS3/config.ts @@ -15,7 +15,6 @@ */ import { Config } from '@backstage/config'; -import { isValidHost } from '../helpers'; const AMAZON_AWS_HOST = 'amazonaws.com'; @@ -26,24 +25,38 @@ const AMAZON_AWS_HOST = 'amazonaws.com'; */ export type AwsS3IntegrationConfig = { /** - * The host of the target that this matches on, e.g. "amazonaws.com" - * - * Currently only "amazonaws.com" is supported. + * Host, derived from endpoint, and defaults to amazonaws.com */ host: string; /** - * accessKeyId + * (Optional) AWS Endpoint. + * The endpoint URI to send requests to. The default endpoint is built from the configured region. + * @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property + * + * Supports non-AWS providers, e.g. for LocalStack, endpoint may look like http://localhost:4566 + */ + endpoint?: string; + + /** + * (Optional) Whether to use path style URLs when communicating with S3. + * Defaults to false. + * This allows providers like LocalStack, Minio and Wasabi (and possibly others) to be used. + */ + s3ForcePathStyle?: boolean; + + /** + * (Optional) User access key id */ accessKeyId?: string; /** - * secretAccessKey + * (Optional) User secret access key */ secretAccessKey?: string; /** - * roleArn + * (Optional) ARN of role to be assumed */ roleArn?: string; }; @@ -58,18 +71,42 @@ export type AwsS3IntegrationConfig = { export function readAwsS3IntegrationConfig( config: Config, ): AwsS3IntegrationConfig { - const host = config.getOptionalString('host') ?? AMAZON_AWS_HOST; + const endpoint = config.getOptionalString('endpoint'); + const s3ForcePathStyle = + config.getOptionalBoolean('s3ForcePathStyle') ?? false; + let host; + let pathname; + if (endpoint) { + try { + const url = new URL(endpoint); + host = url.host; + pathname = url.pathname; + } catch { + throw new Error( + `invalid awsS3 integration config, endpoint '${endpoint}' is not a valid URL`, + ); + } + if (pathname !== '/') { + throw new Error( + `invalid awsS3 integration config, endpoints cannot contain path, got '${endpoint}'`, + ); + } + } else { + host = AMAZON_AWS_HOST; + } + const accessKeyId = config.getOptionalString('accessKeyId'); const secretAccessKey = config.getOptionalString('secretAccessKey'); const roleArn = config.getOptionalString('roleArn'); - if (!isValidHost(host)) { - throw new Error( - `Invalid awsS3 integration config, '${host}' is not a valid host`, - ); - } - - return { host, accessKeyId, secretAccessKey, roleArn }; + return { + host, + endpoint, + s3ForcePathStyle, + accessKeyId, + secretAccessKey, + roleArn, + }; } /** diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index d283c34b43..1690b9131c 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,14 @@ # @techdocs/cli +## 0.8.10 + +### Patch Changes + +- 8fbc988bfc: remove internal and inline CSS from index.html +- Updated dependencies + - @backstage/techdocs-common@0.11.2 + - @backstage/backend-common@0.10.1 + ## 0.8.9 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index be7c9f6b6a..b4c4ade6a3 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "0.8.9", + "version": "0.8.10", "private": false, "publishConfig": { "access": "public" @@ -32,7 +32,7 @@ "techdocs-cli": "bin/techdocs-cli" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/commander": "^2.12.2", "@types/fs-extra": "^9.0.6", "@types/http-proxy": "^1.17.4", @@ -56,10 +56,10 @@ "ext": "ts" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", - "@backstage/techdocs-common": "^0.11.1", + "@backstage/techdocs-common": "^0.11.2", "@types/dockerode": "^3.3.0", "commander": "^6.1.0", "dockerode": "^3.3.1", diff --git a/packages/techdocs-common/CHANGELOG.md b/packages/techdocs-common/CHANGELOG.md index ed5539752f..96281958b6 100644 --- a/packages/techdocs-common/CHANGELOG.md +++ b/packages/techdocs-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/techdocs-common +## 0.11.2 + +### Patch Changes + +- c2c8768771: Bump `@azure/identity` from `^1.5.0` to `^2.0.1`. +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/integration@0.7.0 + ## 0.11.1 ### Patch Changes diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index 7d50a2bcba..f3e0f2d0d4 100644 --- a/packages/techdocs-common/package.json +++ b/packages/techdocs-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/techdocs-common", "description": "Common functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", - "version": "0.11.1", + "version": "0.11.2", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -38,12 +38,12 @@ "dependencies": { "@azure/identity": "^2.0.1", "@azure/storage-blob": "^12.5.0", - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", "@backstage/search-common": "^0.2.1", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@google-cloud/storage": "^5.6.0", "@trendyol-js/openstack-swift-sdk": "^0.0.5", "@types/express": "^4.17.6", @@ -60,7 +60,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/fs-extra": "^9.0.5", "@types/js-yaml": "^4.0.0", "@types/mime-types": "^2.1.0", diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 144c0ad257..fa747f84d1 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/test-utils +## 0.2.1 + +### Patch Changes + +- c36b7794f7: JSON serialize and freeze values stored by the `MockStorageApi`. + ## 0.2.0 ### Minor Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index c125885d88..acfe03bf99 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.2.0", + "version": "0.2.1", "private": false, "publishConfig": { "access": "public", @@ -47,7 +47,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/jest": "^26.0.7", "@types/node": "^14.14.32" }, diff --git a/plugins/allure/package.json b/plugins/allure/package.json index bfffe95d6d..6c6908dbc1 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -37,10 +37,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 00fe5b6651..52a72e7cce 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -35,10 +35,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index 0c25b8a174..2ddcbd26a8 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -33,10 +33,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 5baf5ac05a..989f4d33ba 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-api-docs +## 0.6.20 + +### Patch Changes + +- de81b7455e: Display entity title on `ApiDefinitionCard` if defined +- Updated dependencies + - @backstage/plugin-catalog@0.7.6 + - @backstage/plugin-catalog-react@0.6.9 + ## 0.6.19 ### Patch Changes diff --git a/plugins/api-docs/api-report.md b/plugins/api-docs/api-report.md index 111660ae07..f0e8c06aab 100644 --- a/plugins/api-docs/api-report.md +++ b/plugins/api-docs/api-report.md @@ -5,7 +5,6 @@ ```ts /// -import { Action } from '@material-table/core'; import { ApiEntity } from '@backstage/catalog-model'; import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; @@ -15,6 +14,7 @@ import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { default as React_2 } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; import { TableColumn } from '@backstage/core-components'; +import { TableProps } from '@backstage/core-components'; import { UserListFilterKind } from '@backstage/plugin-catalog-react'; // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts @@ -53,27 +53,17 @@ const apiDocsPlugin: BackstagePlugin< export { apiDocsPlugin }; export { apiDocsPlugin as plugin }; +// @public +export const ApiExplorerIndexPage: ( + props: DefaultApiExplorerPageProps, +) => JSX.Element; + // Warning: (ae-missing-release-tag) "ApiExplorerPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const ApiExplorerPage: ({ - initiallySelectedFilter, - columns, - actions, -}: { - initiallySelectedFilter?: UserListFilterKind | undefined; - columns?: TableColumn[] | undefined; - actions?: - | ( - | Action - | { - action: (rowData: CatalogTableRow) => Action; - position: string; - } - | ((rowData: CatalogTableRow) => Action) - )[] - | undefined; -}) => JSX.Element; +export const ApiExplorerPage: ( + props: DefaultApiExplorerPageProps, +) => JSX.Element; // Warning: (ae-missing-release-tag) "ApiTypeTitle" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -110,6 +100,20 @@ export const ConsumedApisCard: ({ variant }: Props_2) => JSX.Element; // @public (undocumented) export const ConsumingComponentsCard: ({ variant }: Props_5) => JSX.Element; +// @public +export const DefaultApiExplorerPage: ({ + initiallySelectedFilter, + columns, + actions, +}: DefaultApiExplorerPageProps) => JSX.Element; + +// @public +export type DefaultApiExplorerPageProps = { + initiallySelectedFilter?: UserListFilterKind; + columns?: TableColumn[]; + actions?: TableProps['actions']; +}; + // Warning: (ae-missing-release-tag) "defaultDefinitionWidgets" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index b361d991cb..d1ba6080e5 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.6.19", + "version": "0.6.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,8 +34,8 @@ "@backstage/catalog-model": "^0.9.7", "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", - "@backstage/plugin-catalog": "^0.7.5", - "@backstage/plugin-catalog-react": "^0.6.8", + "@backstage/plugin-catalog": "^0.7.6", + "@backstage/plugin-catalog-react": "^0.6.9", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -54,10 +54,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx index 3629110d47..760d1ab59d 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.test.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2021 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,185 +14,31 @@ * limitations under the License. */ -import { Entity, RELATION_MEMBER_OF } from '@backstage/catalog-model'; -import { ConfigReader } from '@backstage/core-app-api'; -import { TableColumn, TableProps } from '@backstage/core-components'; -import { - ConfigApi, - configApiRef, - storageApiRef, -} from '@backstage/core-plugin-api'; -import { CatalogTableRow } from '@backstage/plugin-catalog'; -import { - CatalogApi, - catalogApiRef, - DefaultStarredEntitiesApi, - entityRouteRef, - starredEntitiesApiRef, -} from '@backstage/plugin-catalog-react'; -import { - MockStorageApi, - TestApiProvider, - wrapInTestApp, -} from '@backstage/test-utils'; -import DashboardIcon from '@material-ui/icons/Dashboard'; -import { render } from '@testing-library/react'; import React from 'react'; -import { apiDocsConfigRef } from '../../config'; +import { renderInTestApp } from '@backstage/test-utils'; +import { useOutlet } from 'react-router'; import { ApiExplorerPage } from './ApiExplorerPage'; -describe('ApiCatalogPage', () => { - const catalogApi: Partial = { - getEntities: () => - Promise.resolve({ - items: [ - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'API', - metadata: { - name: 'Entity1', - }, - spec: { type: 'openapi' }, - }, - ] as Entity[], - }), - getLocationByEntity: () => - Promise.resolve({ id: 'id', type: 'github', target: 'url' }), - getEntityByName: async entityName => { - return { - apiVersion: 'backstage.io/v1alpha1', - kind: 'User', - metadata: { name: entityName.name }, - relations: [ - { - type: RELATION_MEMBER_OF, - target: { namespace: 'default', kind: 'Group', name: 'tools' }, - }, - ], - }; - }, - }; +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + useOutlet: jest.fn().mockReturnValue('Route Children'), +})); - const configApi: ConfigApi = new ConfigReader({ - organization: { - name: 'My Company', - }, +jest.mock('./DefaultApiExplorerPage', () => ({ + DefaultApiExplorerPage: jest.fn().mockReturnValue('DefaultApiExplorerPage'), +})); + +describe('ApiExplorerPage', () => { + it('renders provided router element', async () => { + const { getByText } = await renderInTestApp(); + + expect(getByText('Route Children')).toBeInTheDocument(); }); - const apiDocsConfig = { - getApiDefinitionWidget: () => undefined, - }; + it('renders DefaultApiExplorerPage home when no router children are provided', async () => { + (useOutlet as jest.Mock).mockReturnValueOnce(null); + const { getByText } = await renderInTestApp(); - const storageApi = MockStorageApi.create(); - - const renderWrapped = (children: React.ReactNode) => - render( - wrapInTestApp( - - {children} - , - { - mountedRoutes: { - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, - }, - ), - ); - - // this test right now causes some red lines in the log output when running tests - // related to some theme issues in mui-table - // https://github.com/mbrn/material-table/issues/1293 - it('should render', async () => { - const { findByText } = renderWrapped(); - expect(await findByText(/My Company API Explorer/)).toBeInTheDocument(); - }); - - it('should render the default column of the grid', async () => { - const { getAllByRole } = renderWrapped(); - - const columnHeader = getAllByRole('button').filter( - c => c.tagName === 'SPAN', - ); - const columnHeaderLabels = columnHeader.map(c => c.textContent); - - expect(columnHeaderLabels).toEqual([ - 'Name', - 'System', - 'Owner', - 'Type', - 'Lifecycle', - 'Description', - 'Tags', - 'Actions', - ]); - }); - - it('should render the custom column passed as prop', async () => { - const columns: TableColumn[] = [ - { title: 'Foo', field: 'entity.foo' }, - { title: 'Bar', field: 'entity.bar' }, - { title: 'Baz', field: 'entity.spec.lifecycle' }, - ]; - const { getAllByRole } = renderWrapped( - , - ); - - const columnHeader = getAllByRole('button').filter( - c => c.tagName === 'SPAN', - ); - const columnHeaderLabels = columnHeader.map(c => c.textContent); - - expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']); - }); - - it('should render the default actions of an item in the grid', async () => { - const { findByTitle, findByText } = await renderWrapped( - , - ); - expect(await findByText(/All \(1\)/)).toBeInTheDocument(); - expect(await findByTitle(/View/)).toBeInTheDocument(); - expect(await findByTitle(/View/)).toBeInTheDocument(); - expect(await findByTitle(/Edit/)).toBeInTheDocument(); - expect(await findByTitle(/Add to favorites/)).toBeInTheDocument(); - }); - - it('should render the custom actions of an item passed as prop', async () => { - const actions: TableProps['actions'] = [ - () => { - return { - icon: () => , - tooltip: 'Foo Action', - disabled: false, - onClick: () => jest.fn(), - }; - }, - () => { - return { - icon: () => , - tooltip: 'Bar Action', - disabled: true, - onClick: () => jest.fn(), - }; - }, - ]; - - const { findByTitle, findByText } = await renderWrapped( - , - ); - expect(await findByText(/All \(1\)/)).toBeInTheDocument(); - expect(await findByTitle(/Foo Action/)).toBeInTheDocument(); - expect(await findByTitle(/Bar Action/)).toBeInTheDocument(); - expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled(); + expect(getByText('DefaultApiExplorerPage')).toBeInTheDocument(); }); }); diff --git a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.tsx b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.tsx index f28574145e..68ab0a1647 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.tsx +++ b/plugins/api-docs/src/components/ApiExplorerPage/ApiExplorerPage.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2021 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,97 +14,19 @@ * limitations under the License. */ -import { - Content, - ContentHeader, - CreateButton, - PageWithHeader, - SupportButton, - TableColumn, - TableProps, -} from '@backstage/core-components'; -import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; -import { - CatalogTable, - CatalogTableRow, - FilteredEntityLayout, - EntityListContainer, - FilterContainer, -} from '@backstage/plugin-catalog'; -import { - EntityKindPicker, - EntityLifecyclePicker, - EntityListProvider, - EntityOwnerPicker, - EntityTagPicker, - EntityTypePicker, - UserListFilterKind, - UserListPicker, -} from '@backstage/plugin-catalog-react'; import React from 'react'; -import { createComponentRouteRef } from '../../routes'; +import { useOutlet } from 'react-router'; +import { + DefaultApiExplorerPage, + DefaultApiExplorerPageProps, +} from './DefaultApiExplorerPage'; -const defaultColumns: TableColumn[] = [ - CatalogTable.columns.createNameColumn({ defaultKind: 'API' }), - CatalogTable.columns.createSystemColumn(), - CatalogTable.columns.createOwnerColumn(), - CatalogTable.columns.createSpecTypeColumn(), - CatalogTable.columns.createSpecLifecycleColumn(), - CatalogTable.columns.createMetadataDescriptionColumn(), - CatalogTable.columns.createTagsColumn(), -]; +/** + * ApiExplorerPage + * @public + */ +export const ApiExplorerPage = (props: DefaultApiExplorerPageProps) => { + const outlet = useOutlet(); -type ApiExplorerPageProps = { - initiallySelectedFilter?: UserListFilterKind; - columns?: TableColumn[]; - actions?: TableProps['actions']; -}; - -export const ApiExplorerPage = ({ - initiallySelectedFilter = 'all', - columns, - actions, -}: ApiExplorerPageProps) => { - const configApi = useApi(configApiRef); - const generatedSubtitle = `${ - configApi.getOptionalString('organization.name') ?? 'Backstage' - } API Explorer`; - const createComponentLink = useRouteRef(createComponentRouteRef); - - return ( - - - - - All your APIs - - - - - - - - - - - - - ); + return outlet || ; }; diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx new file mode 100644 index 0000000000..9e4c861e24 --- /dev/null +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.test.tsx @@ -0,0 +1,198 @@ +/* + * Copyright 2021 The Backstage 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. + */ + +import { Entity, RELATION_MEMBER_OF } from '@backstage/catalog-model'; +import { ConfigReader } from '@backstage/core-app-api'; +import { TableColumn, TableProps } from '@backstage/core-components'; +import { + ConfigApi, + configApiRef, + storageApiRef, +} from '@backstage/core-plugin-api'; +import { CatalogTableRow } from '@backstage/plugin-catalog'; +import { + CatalogApi, + catalogApiRef, + DefaultStarredEntitiesApi, + entityRouteRef, + starredEntitiesApiRef, +} from '@backstage/plugin-catalog-react'; +import { + MockStorageApi, + TestApiProvider, + wrapInTestApp, +} from '@backstage/test-utils'; +import DashboardIcon from '@material-ui/icons/Dashboard'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { apiDocsConfigRef } from '../../config'; +import { DefaultApiExplorerPage } from './DefaultApiExplorerPage'; + +describe('DefaultApiExplorerPage', () => { + const catalogApi: Partial = { + getEntities: () => + Promise.resolve({ + items: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'Entity1', + }, + spec: { type: 'openapi' }, + }, + ] as Entity[], + }), + getLocationByEntity: () => + Promise.resolve({ id: 'id', type: 'github', target: 'url' }), + getEntityByName: async entityName => { + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { name: entityName.name }, + relations: [ + { + type: RELATION_MEMBER_OF, + target: { namespace: 'default', kind: 'Group', name: 'tools' }, + }, + ], + }; + }, + }; + + const configApi: ConfigApi = new ConfigReader({ + organization: { + name: 'My Company', + }, + }); + + const apiDocsConfig = { + getApiDefinitionWidget: () => undefined, + }; + + const storageApi = MockStorageApi.create(); + + const renderWrapped = (children: React.ReactNode) => + render( + wrapInTestApp( + + {children} + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ), + ); + + // this test right now causes some red lines in the log output when running tests + // related to some theme issues in mui-table + // https://github.com/mbrn/material-table/issues/1293 + it('should render', async () => { + const { findByText } = renderWrapped(); + expect(await findByText(/My Company API Explorer/)).toBeInTheDocument(); + }); + + it('should render the default column of the grid', async () => { + const { getAllByRole } = renderWrapped(); + + const columnHeader = getAllByRole('button').filter( + c => c.tagName === 'SPAN', + ); + const columnHeaderLabels = columnHeader.map(c => c.textContent); + + expect(columnHeaderLabels).toEqual([ + 'Name', + 'System', + 'Owner', + 'Type', + 'Lifecycle', + 'Description', + 'Tags', + 'Actions', + ]); + }); + + it('should render the custom column passed as prop', async () => { + const columns: TableColumn[] = [ + { title: 'Foo', field: 'entity.foo' }, + { title: 'Bar', field: 'entity.bar' }, + { title: 'Baz', field: 'entity.spec.lifecycle' }, + ]; + const { getAllByRole } = renderWrapped( + , + ); + + const columnHeader = getAllByRole('button').filter( + c => c.tagName === 'SPAN', + ); + const columnHeaderLabels = columnHeader.map(c => c.textContent); + + expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']); + }); + + it('should render the default actions of an item in the grid', async () => { + const { findByTitle, findByText } = await renderWrapped( + , + ); + expect(await findByText(/All \(1\)/)).toBeInTheDocument(); + expect(await findByTitle(/View/)).toBeInTheDocument(); + expect(await findByTitle(/View/)).toBeInTheDocument(); + expect(await findByTitle(/Edit/)).toBeInTheDocument(); + expect(await findByTitle(/Add to favorites/)).toBeInTheDocument(); + }); + + it('should render the custom actions of an item passed as prop', async () => { + const actions: TableProps['actions'] = [ + () => { + return { + icon: () => , + tooltip: 'Foo Action', + disabled: false, + onClick: () => jest.fn(), + }; + }, + () => { + return { + icon: () => , + tooltip: 'Bar Action', + disabled: true, + onClick: () => jest.fn(), + }; + }, + ]; + + const { findByTitle, findByText } = await renderWrapped( + , + ); + expect(await findByText(/All \(1\)/)).toBeInTheDocument(); + expect(await findByTitle(/Foo Action/)).toBeInTheDocument(); + expect(await findByTitle(/Bar Action/)).toBeInTheDocument(); + expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled(); + }); +}); diff --git a/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx new file mode 100644 index 0000000000..5ddda96daa --- /dev/null +++ b/plugins/api-docs/src/components/ApiExplorerPage/DefaultApiExplorerPage.tsx @@ -0,0 +1,118 @@ +/* + * Copyright 2021 The Backstage 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. + */ + +import { + Content, + ContentHeader, + CreateButton, + PageWithHeader, + SupportButton, + TableColumn, + TableProps, +} from '@backstage/core-components'; +import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { + CatalogTable, + CatalogTableRow, + FilteredEntityLayout, + EntityListContainer, + FilterContainer, +} from '@backstage/plugin-catalog'; +import { + EntityKindPicker, + EntityLifecyclePicker, + EntityListProvider, + EntityOwnerPicker, + EntityTagPicker, + EntityTypePicker, + UserListFilterKind, + UserListPicker, +} from '@backstage/plugin-catalog-react'; +import React from 'react'; +import { createComponentRouteRef } from '../../routes'; + +const defaultColumns: TableColumn[] = [ + CatalogTable.columns.createNameColumn({ defaultKind: 'API' }), + CatalogTable.columns.createSystemColumn(), + CatalogTable.columns.createOwnerColumn(), + CatalogTable.columns.createSpecTypeColumn(), + CatalogTable.columns.createSpecLifecycleColumn(), + CatalogTable.columns.createMetadataDescriptionColumn(), + CatalogTable.columns.createTagsColumn(), +]; + +/** + * DefaultApiExplorerPageProps + * @public + */ +export type DefaultApiExplorerPageProps = { + initiallySelectedFilter?: UserListFilterKind; + columns?: TableColumn[]; + actions?: TableProps['actions']; +}; + +/** + * DefaultApiExplorerPage + * @public + */ +export const DefaultApiExplorerPage = ({ + initiallySelectedFilter = 'all', + columns, + actions, +}: DefaultApiExplorerPageProps) => { + const configApi = useApi(configApiRef); + const generatedSubtitle = `${ + configApi.getOptionalString('organization.name') ?? 'Backstage' + } API Explorer`; + const createComponentLink = useRouteRef(createComponentRouteRef); + + return ( + + + + + All your APIs + + + + + + + + + + + + + ); +}; diff --git a/plugins/api-docs/src/components/ApiExplorerPage/index.ts b/plugins/api-docs/src/components/ApiExplorerPage/index.ts index 3d170260ad..813ca90229 100644 --- a/plugins/api-docs/src/components/ApiExplorerPage/index.ts +++ b/plugins/api-docs/src/components/ApiExplorerPage/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2021 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,4 +14,6 @@ * limitations under the License. */ -export { ApiExplorerPage } from './ApiExplorerPage'; +export { ApiExplorerPage as ApiExplorerIndexPage } from './ApiExplorerPage'; +export { DefaultApiExplorerPage } from './DefaultApiExplorerPage'; +export type { DefaultApiExplorerPageProps } from './DefaultApiExplorerPage'; diff --git a/plugins/api-docs/src/components/index.ts b/plugins/api-docs/src/components/index.ts index c0af59dc52..f4d8034b56 100644 --- a/plugins/api-docs/src/components/index.ts +++ b/plugins/api-docs/src/components/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export * from './ApiExplorerPage'; export * from './ApiDefinitionCard'; export * from './ApisCards'; export * from './AsyncApiDefinitionWidget'; diff --git a/plugins/api-docs/src/plugin.ts b/plugins/api-docs/src/plugin.ts index f400be9c7c..61695b4a7a 100644 --- a/plugins/api-docs/src/plugin.ts +++ b/plugins/api-docs/src/plugin.ts @@ -53,7 +53,7 @@ export const ApiExplorerPage = apiDocsPlugin.provide( createRoutableExtension({ name: 'ApiExplorerPage', component: () => - import('./components/ApiExplorerPage').then(m => m.ApiExplorerPage), + import('./components/ApiExplorerPage').then(m => m.ApiExplorerIndexPage), mountPoint: rootRoute, }), ); diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 892deeed88..1ae02be713 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-app-backend +## 0.3.21 + +### Patch Changes + +- 9d9cfc1b8a: Set `X-Frame-Options: deny` rather than the default `sameorigin` for all content served by the `app-backend`.` +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/config-loader@0.9.1 + ## 0.3.20 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index 58469b27fe..b1a01a8345 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-backend", "description": "A Backstage backend plugin that serves the Backstage frontend app", - "version": "0.3.20", + "version": "0.3.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/config-loader": "^0.9.0", + "@backstage/backend-common": "^0.10.1", + "@backstage/config-loader": "^0.9.1", "@backstage/config": "^0.1.11", "@backstage/types": "^0.1.1", "@types/express": "^4.17.6", @@ -43,7 +43,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/types": "^0.1.1", "@types/supertest": "^2.0.8", "msw": "^0.35.0", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 86d3c2a30d..c130b58dc8 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-auth-backend +## 0.6.0 + +### Minor Changes + +- c88cdacc1a: Avoid ever returning OAuth refresh tokens back to the client, and always exchange refresh tokens for a new one when available for all providers. + + This comes with a breaking change to the TypeScript API for custom auth providers. The `refresh` method of `OAuthHandlers` implementation must now return a `{ response, refreshToken }` object rather than a direct response. Existing `refresh` implementations are typically migrated by changing an existing return expression that looks like this: + + ```ts + return await this.handleResult({ + fullProfile, + params, + accessToken, + refreshToken, + }); + ``` + + Into the following: + + ```ts + return { + response: await this.handleResult({ + fullProfile, + params, + accessToken, + }), + refreshToken, + }; + ``` + +### Patch Changes + +- f0f81f6cc7: Replaces the usage of `got` with `node-fetch` in the `getUserPhoto` method of the Microsoft provider +- 2f26120a36: Update `auth0` and `onelogin` providers to allow for `authHandler` and `signIn.resolver` configuration. +- a9abafa9df: Fixed bug on refresh token on Okta provider, now it gets the refresh token and it sends it into providerInfo +- eb48e78886: Enforce cookie SSL protection when in production for auth-backend sessions +- Updated dependencies + - @backstage/test-utils@0.2.1 + - @backstage/backend-common@0.10.1 + ## 0.5.2 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 1f3d47a346..620c8b397a 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.5.2", + "version": "0.6.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/catalog-client": "^0.5.3", "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@google-cloud/firestore": "^4.15.1", "@types/express": "^4.17.6", "@types/passport": "^1.0.3", @@ -72,7 +72,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index 86b26af501..3c1f5dd351 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -46,10 +46,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 2f9f109752..663d6f0824 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -43,10 +43,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index c36a529d1c..9bf4f22afe 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -43,7 +43,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/dev-utils": "^0.2.15", "@testing-library/jest-dom": "^5.10.1", "cross-fetch": "^3.0.6" diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 36d2f3006d..3ef3fc1722 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 43138d734f..e53bb50e1a 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-backend +## 0.19.4 + +### Patch Changes + +- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface. +- 3a63491c5f: Filter out projects with missing `default_branch` from GitLab Discovery. +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/integration@0.7.0 + ## 0.19.3 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 3f8f20dc1f..01e79314c5 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "0.19.3", + "version": "0.19.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,12 +30,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/catalog-client": "^0.5.3", "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@backstage/search-common": "^0.2.1", "@backstage/types": "^0.1.1", "@octokit/graphql": "^4.5.8", @@ -62,9 +62,9 @@ "yup": "^0.32.9" }, "devDependencies": { - "@backstage/backend-test-utils": "^0.1.11", - "@backstage/cli": "^0.10.3", - "@backstage/test-utils": "^0.2.0", + "@backstage/backend-test-utils": "^0.1.12", + "@backstage/cli": "^0.10.4", + "@backstage/test-utils": "^0.2.1", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", "@types/lodash": "^4.14.151", diff --git a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.test.ts index 311de05673..8d85d7375f 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.test.ts @@ -184,6 +184,13 @@ describe('GitlabDiscoveryProcessor', () => { last_activity_at: '2021-08-05T11:03:05.774Z', web_url: 'https://gitlab.fake/3', }, + { + id: 4, + archived: false, + default_branch: undefined, // MISSING DEFAULT BRANCH + last_activity_at: '2021-08-05T11:03:05.774Z', + web_url: 'https://gitlab.fake/4', + }, ], }; default: diff --git a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts index 70ccd44793..fabf3a1136 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts @@ -94,9 +94,16 @@ export class GitLabDiscoveryProcessor implements CatalogProcessor { }; for await (const project of projects) { result.scanned++; - if (!project.archived) { - result.matches.push(project); + + if (project.archived) { + continue; } + + if (branch === '*' && project.default_branch === undefined) { + continue; + } + + result.matches.push(project); } for (const project of result.matches) { diff --git a/plugins/catalog-backend/src/ingestion/processors/gitlab/types.ts b/plugins/catalog-backend/src/ingestion/processors/gitlab/types.ts index a66411ddc8..d41ed73aac 100644 --- a/plugins/catalog-backend/src/ingestion/processors/gitlab/types.ts +++ b/plugins/catalog-backend/src/ingestion/processors/gitlab/types.ts @@ -16,7 +16,7 @@ export type GitLabProject = { id: number; - default_branch: string; + default_branch?: string; archived: boolean; last_activity_at: string; web_url: string; diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 09278edba2..c294ba8e24 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -42,10 +42,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 9257c7b0f5..d575f64ab7 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-import +## 0.7.7 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@0.6.9 + - @backstage/integration@0.7.0 + - @backstage/integration-react@0.1.17 + ## 0.7.6 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 94fe6a573f..3f6570dca2 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.7.6", + "version": "0.7.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,9 +36,9 @@ "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/errors": "^0.1.3", - "@backstage/integration": "^0.6.10", - "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-catalog-react": "^0.6.8", + "@backstage/integration": "^0.7.0", + "@backstage/integration-react": "^0.1.17", + "@backstage/plugin-catalog-react": "^0.6.9", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -56,10 +56,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index b8a4128919..8db0fd7573 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-react +## 0.6.9 + +### Patch Changes + +- c6fdddec77: When a user has zero owned entities when viewing an entity kind in the catalog + page, it will be automatically redirected to see all the entities. Furthermore, + for the kind User and Group there are no longer the owned selector. +- Updated dependencies + - @backstage/integration@0.7.0 + ## 0.6.8 ### Patch Changes diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index d5cf06107c..673d9256f1 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -19,12 +19,14 @@ import { IconButton } from '@material-ui/core'; import { IdentityApi } from '@backstage/core-plugin-api'; import { LinkProps } from '@backstage/core-components'; import { Observable } from '@backstage/types'; +import { Overrides } from '@material-ui/core/styles/overrides'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { StorageApi } from '@backstage/core-plugin-api'; +import { StyleRules } from '@material-ui/core/styles/withStyles'; import { SystemEntity } from '@backstage/catalog-model'; import { TableColumn } from '@backstage/core-components'; import { UserEntity } from '@backstage/catalog-model'; @@ -52,6 +54,13 @@ export interface AsyncEntityProviderProps { refresh?: VoidFunction; } +// @public (undocumented) +export type BackstageOverrides = Overrides & { + [Name in keyof CatalogReactComponentsNameToClassKey]?: Partial< + StyleRules + >; +}; + export { CATALOG_FILTER_EXISTS }; export { CatalogApi }; @@ -61,6 +70,35 @@ export { CatalogApi }; // @public (undocumented) export const catalogApiRef: ApiRef; +// @public (undocumented) +export type CatalogReactComponentsNameToClassKey = { + CatalogReactUserListPicker: CatalogReactUserListPickerClassKey; + CatalogReactEntityLifecyclePicker: CatalogReactEntityLifecyclePickerClassKey; + CatalogReactEntitySearchBar: CatalogReactEntitySearchBarClassKey; + CatalogReactEntityTagPicker: CatalogReactEntityTagPickerClassKey; + CatalogReactEntityOwnerPicker: CatalogReactEntityOwnerPickerClassKey; +}; + +// @public (undocumented) +export type CatalogReactEntityLifecyclePickerClassKey = 'input'; + +// @public (undocumented) +export type CatalogReactEntityOwnerPickerClassKey = 'input'; + +// @public (undocumented) +export type CatalogReactEntitySearchBarClassKey = 'searchToolbar' | 'input'; + +// @public (undocumented) +export type CatalogReactEntityTagPickerClassKey = 'input'; + +// @public (undocumented) +export type CatalogReactUserListPickerClassKey = + | 'root' + | 'title' + | 'listIcon' + | 'menuItem' + | 'groupWrapper'; + // Warning: (ae-missing-release-tag) "catalogRouteRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 1283d45612..912ef5f653 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "0.6.8", + "version": "0.6.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -34,7 +34,7 @@ "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/errors": "^0.1.4", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@backstage/types": "^0.1.1", "@backstage/version-bridge": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -52,9 +52,9 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx b/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx index 750692ed2e..630b1700a0 100644 --- a/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx +++ b/plugins/catalog-react/src/components/EntityLifecyclePicker/EntityLifecyclePicker.tsx @@ -31,6 +31,9 @@ import React, { useEffect, useMemo, useState } from 'react'; import { useEntityListProvider } from '../../hooks/useEntityListProvider'; import { EntityLifecycleFilter } from '../../filters'; +/** @public */ +export type CatalogReactEntityLifecyclePickerClassKey = 'input'; + const useStyles = makeStyles( { input: {}, diff --git a/plugins/catalog-react/src/components/EntityLifecyclePicker/index.ts b/plugins/catalog-react/src/components/EntityLifecyclePicker/index.ts index 4b8cfb282d..def25eabf4 100644 --- a/plugins/catalog-react/src/components/EntityLifecyclePicker/index.ts +++ b/plugins/catalog-react/src/components/EntityLifecyclePicker/index.ts @@ -15,3 +15,4 @@ */ export { EntityLifecyclePicker } from './EntityLifecyclePicker'; +export type { CatalogReactEntityLifecyclePickerClassKey } from './EntityLifecyclePicker'; diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx index dbf6a33164..ae88858666 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx @@ -33,6 +33,9 @@ import { EntityOwnerFilter } from '../../filters'; import { getEntityRelations } from '../../utils'; import { formatEntityRefTitle } from '../EntityRefLink'; +/** @public */ +export type CatalogReactEntityOwnerPickerClassKey = 'input'; + const useStyles = makeStyles( { input: {}, diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/index.ts b/plugins/catalog-react/src/components/EntityOwnerPicker/index.ts index f30928718b..c20db945f7 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/index.ts +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/index.ts @@ -15,3 +15,4 @@ */ export { EntityOwnerPicker } from './EntityOwnerPicker'; +export type { CatalogReactEntityOwnerPickerClassKey } from './EntityOwnerPicker'; diff --git a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx index 3a848591a3..57c7f58413 100644 --- a/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx +++ b/plugins/catalog-react/src/components/EntitySearchBar/EntitySearchBar.tsx @@ -29,6 +29,9 @@ import { useDebounce } from 'react-use'; import { useEntityListProvider } from '../../hooks/useEntityListProvider'; import { EntityTextFilter } from '../../filters'; +/** @public */ +export type CatalogReactEntitySearchBarClassKey = 'searchToolbar' | 'input'; + const useStyles = makeStyles( _theme => ({ searchToolbar: { diff --git a/plugins/catalog-react/src/components/EntitySearchBar/index.ts b/plugins/catalog-react/src/components/EntitySearchBar/index.ts index 044b8ee416..e82c06d94e 100644 --- a/plugins/catalog-react/src/components/EntitySearchBar/index.ts +++ b/plugins/catalog-react/src/components/EntitySearchBar/index.ts @@ -15,3 +15,4 @@ */ export { EntitySearchBar } from './EntitySearchBar'; +export type { CatalogReactEntitySearchBarClassKey } from './EntitySearchBar'; diff --git a/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx b/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx index 9e00f7e7b0..a25c50c0a9 100644 --- a/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx +++ b/plugins/catalog-react/src/components/EntityTagPicker/EntityTagPicker.tsx @@ -31,6 +31,9 @@ import React, { useEffect, useMemo, useState } from 'react'; import { useEntityListProvider } from '../../hooks/useEntityListProvider'; import { EntityTagFilter } from '../../filters'; +/** @public */ +export type CatalogReactEntityTagPickerClassKey = 'input'; + const useStyles = makeStyles( { input: {}, diff --git a/plugins/catalog-react/src/components/EntityTagPicker/index.ts b/plugins/catalog-react/src/components/EntityTagPicker/index.ts index cb8d418a41..c982d33df0 100644 --- a/plugins/catalog-react/src/components/EntityTagPicker/index.ts +++ b/plugins/catalog-react/src/components/EntityTagPicker/index.ts @@ -15,3 +15,4 @@ */ export { EntityTagPicker } from './EntityTagPicker'; +export type { CatalogReactEntityTagPickerClassKey } from './EntityTagPicker'; diff --git a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx index 9aafdf1437..8746752b08 100644 --- a/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx +++ b/plugins/catalog-react/src/components/UserListPicker/UserListPicker.tsx @@ -43,6 +43,14 @@ import { import { UserListFilterKind } from '../../types'; import { reduceEntityFilters } from '../../utils'; +/** @public */ +export type CatalogReactUserListPickerClassKey = + | 'root' + | 'title' + | 'listIcon' + | 'menuItem' + | 'groupWrapper'; + const useStyles = makeStyles( theme => ({ root: { diff --git a/plugins/catalog-react/src/components/UserListPicker/index.ts b/plugins/catalog-react/src/components/UserListPicker/index.ts index 0bacaee8ca..45cb471197 100644 --- a/plugins/catalog-react/src/components/UserListPicker/index.ts +++ b/plugins/catalog-react/src/components/UserListPicker/index.ts @@ -15,3 +15,4 @@ */ export { UserListPicker } from './UserListPicker'; +export type { CatalogReactUserListPickerClassKey } from './UserListPicker'; diff --git a/plugins/catalog-react/src/index.ts b/plugins/catalog-react/src/index.ts index cf7a679f7a..7bf1bd1221 100644 --- a/plugins/catalog-react/src/index.ts +++ b/plugins/catalog-react/src/index.ts @@ -37,3 +37,4 @@ export { export * from './testUtils'; export * from './types'; export * from './utils'; +export * from './overridableComponents'; diff --git a/plugins/catalog-react/src/overridableComponents.ts b/plugins/catalog-react/src/overridableComponents.ts new file mode 100644 index 0000000000..1e654988e4 --- /dev/null +++ b/plugins/catalog-react/src/overridableComponents.ts @@ -0,0 +1,41 @@ +/* + * Copyright 2021 The Backstage 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. + */ +import { Overrides } from '@material-ui/core/styles/overrides'; +import { StyleRules } from '@material-ui/core/styles/withStyles'; + +import { + CatalogReactUserListPickerClassKey, + CatalogReactEntityLifecyclePickerClassKey, + CatalogReactEntitySearchBarClassKey, + CatalogReactEntityTagPickerClassKey, + CatalogReactEntityOwnerPickerClassKey, +} from './components'; + +/** @public */ +export type CatalogReactComponentsNameToClassKey = { + CatalogReactUserListPicker: CatalogReactUserListPickerClassKey; + CatalogReactEntityLifecyclePicker: CatalogReactEntityLifecyclePickerClassKey; + CatalogReactEntitySearchBar: CatalogReactEntitySearchBarClassKey; + CatalogReactEntityTagPicker: CatalogReactEntityTagPickerClassKey; + CatalogReactEntityOwnerPicker: CatalogReactEntityOwnerPickerClassKey; +}; + +/** @public */ +export type BackstageOverrides = Overrides & { + [Name in keyof CatalogReactComponentsNameToClassKey]?: Partial< + StyleRules + >; +}; diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index cb2dcfc079..2e626caf20 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog +## 0.7.6 + +### Patch Changes + +- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface. +- Updated dependencies + - @backstage/plugin-catalog-react@0.6.9 + - @backstage/integration-react@0.1.17 + ## 0.7.5 ### Patch Changes diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index 80271c89af..c046e031de 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -126,15 +126,10 @@ export class CatalogClientWrapper implements CatalogApi { // @public (undocumented) export const CatalogEntityPage: () => JSX.Element; -// Warning: (ae-forgotten-export) The symbol "CatalogPageProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "CatalogIndexPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const CatalogIndexPage: ({ - columns, - actions, - initiallySelectedFilter, -}: CatalogPageProps) => JSX.Element; +export const CatalogIndexPage: (props: DefaultCatalogPageProps) => JSX.Element; // Warning: (ae-forgotten-export) The symbol "CatalogKindHeaderProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "CatalogKindHeader" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -236,6 +231,13 @@ export function createSystemColumn(): TableColumn; // @public (undocumented) export function createTagsColumn(): TableColumn; +// @public +export type DefaultCatalogPageProps = { + initiallySelectedFilter?: UserListFilterKind; + columns?: TableColumn[]; + actions?: TableProps['actions']; +}; + // Warning: (ae-missing-release-tag) "EntityAboutCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 92003dca88..83720b9a90 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "0.7.5", + "version": "0.7.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,8 +36,8 @@ "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/errors": "^0.1.3", - "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-catalog-react": "^0.6.8", + "@backstage/integration-react": "^0.1.17", + "@backstage/plugin-catalog-react": "^0.6.9", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -53,10 +53,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/catalog/src/components/CatalogPage/CatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/CatalogPage.test.tsx index effd9f5bc6..6fbdcf40a2 100644 --- a/plugins/catalog/src/components/CatalogPage/CatalogPage.test.tsx +++ b/plugins/catalog/src/components/CatalogPage/CatalogPage.test.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2021 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,272 +14,31 @@ * limitations under the License. */ -import { CatalogApi } from '@backstage/catalog-client'; -import { - Entity, - RELATION_MEMBER_OF, - RELATION_OWNED_BY, -} from '@backstage/catalog-model'; -import { TableColumn, TableProps } from '@backstage/core-components'; -import { - IdentityApi, - identityApiRef, - ProfileInfo, - storageApiRef, -} from '@backstage/core-plugin-api'; -import { - catalogApiRef, - DefaultStarredEntitiesApi, - entityRouteRef, - starredEntitiesApiRef, -} from '@backstage/plugin-catalog-react'; -import { - mockBreakpoint, - MockStorageApi, - renderWithEffects, - TestApiProvider, - wrapInTestApp, -} from '@backstage/test-utils'; -import DashboardIcon from '@material-ui/icons/Dashboard'; -import { fireEvent, screen } from '@testing-library/react'; import React from 'react'; -import { createComponentRouteRef } from '../../routes'; -import { EntityRow } from '../CatalogTable'; +import { renderInTestApp } from '@backstage/test-utils'; +import { useOutlet } from 'react-router'; import { CatalogPage } from './CatalogPage'; +jest.mock('react-router', () => ({ + ...jest.requireActual('react-router'), + useOutlet: jest.fn().mockReturnValue('Route Children'), +})); + +jest.mock('./DefaultCatalogPage', () => ({ + DefaultCatalogPage: jest.fn().mockReturnValue('DefaultCatalogPage'), +})); + describe('CatalogPage', () => { - const origReplaceState = window.history.replaceState; - beforeEach(() => { - window.history.replaceState = jest.fn(); - }); - afterEach(() => { - window.history.replaceState = origReplaceState; + it('renders provided router element', async () => { + const { getByText } = await renderInTestApp(); + + expect(getByText('Route Children')).toBeInTheDocument(); }); - const catalogApi: Partial = { - getEntities: () => - Promise.resolve({ - items: [ - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Component', - metadata: { - name: 'Entity1', - }, - spec: { - owner: 'tools', - type: 'service', - }, - relations: [ - { - type: RELATION_OWNED_BY, - target: { kind: 'Group', name: 'tools', namespace: 'default' }, - }, - ], - }, - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Component', - metadata: { - name: 'Entity2', - }, - spec: { - owner: 'not-tools', - type: 'service', - }, - relations: [ - { - type: RELATION_OWNED_BY, - target: { - kind: 'Group', - name: 'not-tools', - namespace: 'default', - }, - }, - ], - }, - ] as Entity[], - }), - getLocationByEntity: () => - Promise.resolve({ id: 'id', type: 'github', target: 'url' }), - getEntityByName: async entityName => { - return { - apiVersion: 'backstage.io/v1alpha1', - kind: 'User', - metadata: { name: entityName.name }, - relations: [ - { - type: RELATION_MEMBER_OF, - target: { namespace: 'default', kind: 'Group', name: 'tools' }, - }, - ], - }; - }, - }; - const testProfile: Partial = { - displayName: 'Display Name', - }; - const identityApi: Partial = { - getUserId: () => 'tools', - getIdToken: async () => undefined, - getProfile: () => testProfile, - }; - const storageApi = MockStorageApi.create(); + it('renders DefaultCatalogPage home when no router children are provided', async () => { + (useOutlet as jest.Mock).mockReturnValueOnce(null); + const { getByText } = await renderInTestApp(); - const renderWrapped = (children: React.ReactNode) => - renderWithEffects( - wrapInTestApp( - - {children} - , - { - mountedRoutes: { - '/create': createComponentRouteRef, - '/catalog/:namespace/:kind/:name': entityRouteRef, - }, - }, - ), - ); - - // TODO(freben): The test timeouts are bumped in this file, because it seems - // page and table rerenders accumulate to occasionally go over the default - // limit. We should investigate why these timeouts happen. - - it('should render the default column of the grid', async () => { - const { getAllByRole } = await renderWrapped(); - - const columnHeader = getAllByRole('button').filter( - c => c.tagName === 'SPAN', - ); - const columnHeaderLabels = columnHeader.map(c => c.textContent); - - expect(columnHeaderLabels).toEqual([ - 'Name', - 'System', - 'Owner', - 'Type', - 'Lifecycle', - 'Description', - 'Tags', - 'Actions', - ]); - }, 20_000); - - it('should render the custom column passed as prop', async () => { - const columns: TableColumn[] = [ - { title: 'Foo', field: 'entity.foo' }, - { title: 'Bar', field: 'entity.bar' }, - { title: 'Baz', field: 'entity.spec.lifecycle' }, - ]; - const { getAllByRole } = await renderWrapped( - , - ); - - const columnHeader = getAllByRole('button').filter( - c => c.tagName === 'SPAN', - ); - const columnHeaderLabels = columnHeader.map(c => c.textContent); - expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']); - }, 20_000); - - it('should render the default actions of an item in the grid', async () => { - const { getByTestId, findByTitle, findByText } = await renderWrapped( - , - ); - fireEvent.click(getByTestId('user-picker-owned')); - expect(await findByText(/Owned \(1\)/)).toBeInTheDocument(); - expect(await findByTitle(/View/)).toBeInTheDocument(); - expect(await findByTitle(/Edit/)).toBeInTheDocument(); - expect(await findByTitle(/Add to favorites/)).toBeInTheDocument(); - }, 20_000); - - it('should render the custom actions of an item passed as prop', async () => { - const actions: TableProps['actions'] = [ - () => { - return { - icon: () => , - tooltip: 'Foo Action', - disabled: false, - onClick: () => jest.fn(), - }; - }, - () => { - return { - icon: () => , - tooltip: 'Bar Action', - disabled: true, - onClick: () => jest.fn(), - }; - }, - ]; - - const { getByTestId, findByTitle, findByText } = await renderWrapped( - , - ); - fireEvent.click(getByTestId('user-picker-owned')); - expect(await findByText(/Owned \(1\)/)).toBeInTheDocument(); - expect(await findByTitle(/Foo Action/)).toBeInTheDocument(); - expect(await findByTitle(/Bar Action/)).toBeInTheDocument(); - expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled(); - }, 20_000); - - // this test right now causes some red lines in the log output when running tests - // related to some theme issues in mui-table - // https://github.com/mbrn/material-table/issues/1293 - it('should render', async () => { - const { findByText, getByTestId } = await renderWrapped(); - fireEvent.click(getByTestId('user-picker-owned')); - await expect(findByText(/Owned \(1\)/)).resolves.toBeInTheDocument(); - fireEvent.click(getByTestId('user-picker-all')); - await expect(findByText(/All \(2\)/)).resolves.toBeInTheDocument(); - }, 20_000); - - it('should set initial filter correctly', async () => { - const { findByText } = await renderWrapped( - , - ); - await expect(findByText(/All \(2\)/)).resolves.toBeInTheDocument(); - }, 20_000); - - // this test is for fixing the bug after favoriting an entity, the matching - // entities defaulting to "owned" filter and not based on the selected filter - it('should render the correct entities filtered on the selected filter', async () => { - const { getByTestId } = await renderWrapped(); - fireEvent.click(getByTestId('user-picker-owned')); - await expect(screen.findByText(/Owned \(1\)/)).resolves.toBeInTheDocument(); - fireEvent.click(screen.getByTestId('user-picker-starred')); - await expect( - screen.findByText(/Starred \(0\)/), - ).resolves.toBeInTheDocument(); - fireEvent.click(screen.getByTestId('user-picker-all')); - await expect(screen.findByText(/All \(2\)/)).resolves.toBeInTheDocument(); - - const starredIcons = await screen.findAllByTitle('Add to favorites'); - fireEvent.click(starredIcons[0]); - await expect(screen.findByText(/All \(2\)/)).resolves.toBeInTheDocument(); - - fireEvent.click(screen.getByTestId('user-picker-starred')); - await expect( - screen.findByText(/Starred \(1\)/), - ).resolves.toBeInTheDocument(); - }, 20_000); - - it('should wrap filter in drawer on smaller screens', async () => { - mockBreakpoint({ matches: true }); - const { getByRole } = await renderWrapped(); - const button = getByRole('button', { name: 'Filters' }); - expect(getByRole('presentation', { hidden: true })).toBeInTheDocument(); - fireEvent.click(button); - expect(getByRole('presentation')).toBeVisible(); - }, 20_000); + expect(getByText('DefaultCatalogPage')).toBeInTheDocument(); + }); }); diff --git a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx index ec29d3839b..cf49cff244 100644 --- a/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Backstage Authors + * Copyright 2021 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,76 +14,15 @@ * limitations under the License. */ -import { - Content, - ContentHeader, - CreateButton, - PageWithHeader, - SupportButton, - TableColumn, - TableProps, -} from '@backstage/core-components'; -import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; -import { - EntityLifecyclePicker, - EntityListProvider, - EntityOwnerPicker, - EntityTagPicker, - EntityTypePicker, - UserListFilterKind, - UserListPicker, -} from '@backstage/plugin-catalog-react'; import React from 'react'; -import { createComponentRouteRef } from '../../routes'; -import { CatalogTable } from '../CatalogTable'; -import { EntityRow } from '../CatalogTable/types'; +import { useOutlet } from 'react-router'; import { - FilteredEntityLayout, - EntityListContainer, - FilterContainer, -} from '../FilteredEntityLayout'; -import { CatalogKindHeader } from '../CatalogKindHeader'; + DefaultCatalogPage, + DefaultCatalogPageProps, +} from './DefaultCatalogPage'; -export type CatalogPageProps = { - initiallySelectedFilter?: UserListFilterKind; - columns?: TableColumn[]; - actions?: TableProps['actions']; -}; - -export const CatalogPage = ({ - columns, - actions, - initiallySelectedFilter = 'owned', -}: CatalogPageProps) => { - const orgName = - useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; - const createComponentLink = useRouteRef(createComponentRouteRef); - - return ( - - - - }> - - All your software catalog entities - - - - - - - - - - - - - - - - - ); +export const CatalogPage = (props: DefaultCatalogPageProps) => { + const outlet = useOutlet(); + + return outlet || ; }; diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx new file mode 100644 index 0000000000..5f21ba364b --- /dev/null +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.test.tsx @@ -0,0 +1,287 @@ +/* + * Copyright 2021 The Backstage 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. + */ + +import { CatalogApi } from '@backstage/catalog-client'; +import { + Entity, + RELATION_MEMBER_OF, + RELATION_OWNED_BY, +} from '@backstage/catalog-model'; +import { TableColumn, TableProps } from '@backstage/core-components'; +import { + IdentityApi, + identityApiRef, + ProfileInfo, + storageApiRef, +} from '@backstage/core-plugin-api'; +import { + catalogApiRef, + DefaultStarredEntitiesApi, + entityRouteRef, + starredEntitiesApiRef, +} from '@backstage/plugin-catalog-react'; +import { + mockBreakpoint, + MockStorageApi, + renderWithEffects, + TestApiProvider, + wrapInTestApp, +} from '@backstage/test-utils'; +import DashboardIcon from '@material-ui/icons/Dashboard'; +import { fireEvent, screen } from '@testing-library/react'; +import React from 'react'; +import { createComponentRouteRef } from '../../routes'; +import { EntityRow } from '../CatalogTable'; +import { DefaultCatalogPage } from './DefaultCatalogPage'; + +describe('DefaultCatalogPage', () => { + const origReplaceState = window.history.replaceState; + beforeEach(() => { + window.history.replaceState = jest.fn(); + }); + afterEach(() => { + window.history.replaceState = origReplaceState; + }); + + const catalogApi: Partial = { + getEntities: () => + Promise.resolve({ + items: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'Entity1', + }, + spec: { + owner: 'tools', + type: 'service', + }, + relations: [ + { + type: RELATION_OWNED_BY, + target: { kind: 'Group', name: 'tools', namespace: 'default' }, + }, + ], + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'Entity2', + }, + spec: { + owner: 'not-tools', + type: 'service', + }, + relations: [ + { + type: RELATION_OWNED_BY, + target: { + kind: 'Group', + name: 'not-tools', + namespace: 'default', + }, + }, + ], + }, + ] as Entity[], + }), + getLocationByEntity: () => + Promise.resolve({ id: 'id', type: 'github', target: 'url' }), + getEntityByName: async entityName => { + return { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { name: entityName.name }, + relations: [ + { + type: RELATION_MEMBER_OF, + target: { namespace: 'default', kind: 'Group', name: 'tools' }, + }, + ], + }; + }, + }; + const testProfile: Partial = { + displayName: 'Display Name', + }; + const identityApi: Partial = { + getUserId: () => 'tools', + getIdToken: async () => undefined, + getProfile: () => testProfile, + }; + const storageApi = MockStorageApi.create(); + + const renderWrapped = (children: React.ReactNode) => + renderWithEffects( + wrapInTestApp( + + {children} + , + { + mountedRoutes: { + '/create': createComponentRouteRef, + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ), + ); + + // TODO(freben): The test timeouts are bumped in this file, because it seems + // page and table rerenders accumulate to occasionally go over the default + // limit. We should investigate why these timeouts happen. + + it('should render the default column of the grid', async () => { + const { getAllByRole } = await renderWrapped(); + + const columnHeader = getAllByRole('button').filter( + c => c.tagName === 'SPAN', + ); + const columnHeaderLabels = columnHeader.map(c => c.textContent); + + expect(columnHeaderLabels).toEqual([ + 'Name', + 'System', + 'Owner', + 'Type', + 'Lifecycle', + 'Description', + 'Tags', + 'Actions', + ]); + }, 20_000); + + it('should render the custom column passed as prop', async () => { + const columns: TableColumn[] = [ + { title: 'Foo', field: 'entity.foo' }, + { title: 'Bar', field: 'entity.bar' }, + { title: 'Baz', field: 'entity.spec.lifecycle' }, + ]; + const { getAllByRole } = await renderWrapped( + , + ); + + const columnHeader = getAllByRole('button').filter( + c => c.tagName === 'SPAN', + ); + const columnHeaderLabels = columnHeader.map(c => c.textContent); + expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']); + }, 20_000); + + it('should render the default actions of an item in the grid', async () => { + const { getByTestId, findByTitle, findByText } = await renderWrapped( + , + ); + fireEvent.click(getByTestId('user-picker-owned')); + expect(await findByText(/Owned \(1\)/)).toBeInTheDocument(); + expect(await findByTitle(/View/)).toBeInTheDocument(); + expect(await findByTitle(/Edit/)).toBeInTheDocument(); + expect(await findByTitle(/Add to favorites/)).toBeInTheDocument(); + }, 20_000); + + it('should render the custom actions of an item passed as prop', async () => { + const actions: TableProps['actions'] = [ + () => { + return { + icon: () => , + tooltip: 'Foo Action', + disabled: false, + onClick: () => jest.fn(), + }; + }, + () => { + return { + icon: () => , + tooltip: 'Bar Action', + disabled: true, + onClick: () => jest.fn(), + }; + }, + ]; + + const { getByTestId, findByTitle, findByText } = await renderWrapped( + , + ); + fireEvent.click(getByTestId('user-picker-owned')); + expect(await findByText(/Owned \(1\)/)).toBeInTheDocument(); + expect(await findByTitle(/Foo Action/)).toBeInTheDocument(); + expect(await findByTitle(/Bar Action/)).toBeInTheDocument(); + expect((await findByTitle(/Bar Action/)).firstChild).toBeDisabled(); + }, 20_000); + + // this test right now causes some red lines in the log output when running tests + // related to some theme issues in mui-table + // https://github.com/mbrn/material-table/issues/1293 + it('should render', async () => { + const { findByText, getByTestId } = await renderWrapped( + , + ); + fireEvent.click(getByTestId('user-picker-owned')); + await expect(findByText(/Owned \(1\)/)).resolves.toBeInTheDocument(); + fireEvent.click(getByTestId('user-picker-all')); + await expect(findByText(/All \(2\)/)).resolves.toBeInTheDocument(); + }, 20_000); + + it('should set initial filter correctly', async () => { + const { findByText } = await renderWrapped( + , + ); + await expect(findByText(/All \(2\)/)).resolves.toBeInTheDocument(); + }, 20_000); + + // this test is for fixing the bug after favoriting an entity, the matching + // entities defaulting to "owned" filter and not based on the selected filter + it('should render the correct entities filtered on the selected filter', async () => { + const { getByTestId } = await renderWrapped(); + fireEvent.click(getByTestId('user-picker-owned')); + await expect(screen.findByText(/Owned \(1\)/)).resolves.toBeInTheDocument(); + fireEvent.click(screen.getByTestId('user-picker-starred')); + await expect( + screen.findByText(/Starred \(0\)/), + ).resolves.toBeInTheDocument(); + fireEvent.click(screen.getByTestId('user-picker-all')); + await expect(screen.findByText(/All \(2\)/)).resolves.toBeInTheDocument(); + + const starredIcons = await screen.findAllByTitle('Add to favorites'); + fireEvent.click(starredIcons[0]); + await expect(screen.findByText(/All \(2\)/)).resolves.toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('user-picker-starred')); + await expect( + screen.findByText(/Starred \(1\)/), + ).resolves.toBeInTheDocument(); + }, 20_000); + + it('should wrap filter in drawer on smaller screens', async () => { + mockBreakpoint({ matches: true }); + const { getByRole } = await renderWrapped(); + const button = getByRole('button', { name: 'Filters' }); + expect(getByRole('presentation', { hidden: true })).toBeInTheDocument(); + fireEvent.click(button); + expect(getByRole('presentation')).toBeVisible(); + }, 20_000); +}); diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx new file mode 100644 index 0000000000..1453a39bbc --- /dev/null +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -0,0 +1,93 @@ +/* + * Copyright 2021 The Backstage 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. + */ + +import { + Content, + ContentHeader, + CreateButton, + PageWithHeader, + SupportButton, + TableColumn, + TableProps, +} from '@backstage/core-components'; +import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { + EntityLifecyclePicker, + EntityListProvider, + EntityOwnerPicker, + EntityTagPicker, + EntityTypePicker, + UserListFilterKind, + UserListPicker, +} from '@backstage/plugin-catalog-react'; +import React from 'react'; +import { createComponentRouteRef } from '../../routes'; +import { CatalogTable } from '../CatalogTable'; +import { EntityRow } from '../CatalogTable/types'; +import { + FilteredEntityLayout, + EntityListContainer, + FilterContainer, +} from '../FilteredEntityLayout'; +import { CatalogKindHeader } from '../CatalogKindHeader'; + +/** + * DefaultCatalogPageProps + * @public + */ +export type DefaultCatalogPageProps = { + initiallySelectedFilter?: UserListFilterKind; + columns?: TableColumn[]; + actions?: TableProps['actions']; +}; + +export const DefaultCatalogPage = ({ + columns, + actions, + initiallySelectedFilter = 'owned', +}: DefaultCatalogPageProps) => { + const orgName = + useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage'; + const createComponentLink = useRouteRef(createComponentRouteRef); + + return ( + + + + }> + + All your software catalog entities + + + + + + + + + + + + + + + + + ); +}; diff --git a/plugins/catalog/src/components/CatalogPage/index.ts b/plugins/catalog/src/components/CatalogPage/index.ts index dc7ed68229..ca6a13c034 100644 --- a/plugins/catalog/src/components/CatalogPage/index.ts +++ b/plugins/catalog/src/components/CatalogPage/index.ts @@ -14,3 +14,5 @@ * limitations under the License. */ export { CatalogPage } from './CatalogPage'; +export { DefaultCatalogPage } from './DefaultCatalogPage'; +export type { DefaultCatalogPageProps } from './DefaultCatalogPage'; diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts index d804bbaf83..56cae80b6a 100644 --- a/plugins/catalog/src/index.ts +++ b/plugins/catalog/src/index.ts @@ -54,3 +54,4 @@ export { export type { EntityLinksEmptyStateClassKey } from './components/EntityLinksCard'; export type { SystemDiagramCardClassKey } from './components/SystemDiagramCard'; +export type { DefaultCatalogPageProps } from './components/CatalogPage'; diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 5e88164b3c..7a6fda44e5 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -52,10 +52,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index e3834572fc..9c6c5586f7 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 4d7b7cc379..1fd78b862b 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-code-coverage-backend +## 0.1.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/integration@0.7.0 + ## 0.1.17 ### Patch Changes diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 009eb38906..4a24cada7c 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage-backend", "description": "A Backstage backend plugin that helps you keep track of your code coverage", - "version": "0.1.17", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,12 +20,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/catalog-client": "^0.5.3", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -36,7 +36,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/express-xml-bodyparser": "^0.3.2", "@types/supertest": "^2.0.8", "msw": "^0.35.0", diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index f7127cd824..1fb00c7ba4 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -43,10 +43,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 0725070a9b..03891b498c 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -38,10 +38,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index c2f0c3bbb9..2e47db3bb8 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-cost-insights +## 0.11.15 + +### Patch Changes + +- 7858c2abdc: Fixed an accidental re-export of `@backstage/test-utils` that broke this plugin in the most recent release. + ## 0.11.14 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 8323d12dcf..e1995f2e49 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.11.14", + "version": "0.11.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -56,10 +56,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 4bf38ddb99..943fe915f7 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 4e36033f00..5db5ce7018 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -36,10 +36,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 464388be50..80cc98a32a 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index f608614e18..05b2976efb 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -44,10 +44,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 468120a36b..1f7dc43cbd 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-git-release-manager +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@0.7.0 + ## 0.3.5 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 89ed787c5a..32fb6bba1e 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-git-release-manager", "description": "A Backstage plugin that helps you manage releases in git", - "version": "0.3.5", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -23,7 +23,7 @@ "dependencies": { "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 5f932693d5..4c65a93a43 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-github-actions +## 0.4.29 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@0.6.9 + - @backstage/integration@0.7.0 + ## 0.4.28 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 85e1ed04c3..7c3c475a0a 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.4.28", + "version": "0.4.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,8 +36,8 @@ "@backstage/catalog-model": "^0.9.8", "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", - "@backstage/integration": "^0.6.10", - "@backstage/plugin-catalog-react": "^0.6.8", + "@backstage/integration": "^0.7.0", + "@backstage/plugin-catalog-react": "^0.6.9", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -52,10 +52,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 6cda495e58..3d456e56d5 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-github-deployments +## 0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@0.6.9 + - @backstage/integration@0.7.0 + - @backstage/integration-react@0.1.17 + ## 0.1.23 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 5147e2dc9c..8e023e6cd2 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-deployments", "description": "A Backstage plugin that integrates towards GitHub Deployments", - "version": "0.1.23", + "version": "0.1.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,9 +25,9 @@ "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/errors": "^0.1.3", - "@backstage/integration": "^0.6.10", - "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-catalog-react": "^0.6.8", + "@backstage/integration": "^0.7.0", + "@backstage/integration-react": "^0.1.17", + "@backstage/plugin-catalog-react": "^0.6.9", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 064a170522..1defa61667 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -45,10 +45,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 25dfa0b2da..510e06a3a4 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -45,10 +45,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/home/package.json b/plugins/home/package.json index adb26e76d0..ea924d2aa1 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -36,10 +36,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 145a91ba75..de904d9a3e 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -40,10 +40,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index ea3df7b719..eba8b8405b 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 149979752e..6ba86a62a1 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -36,10 +36,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index 7d3adac1c4..9b181c8514 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -6,6 +6,7 @@ import { Config } from '@backstage/config'; import express from 'express'; import type { FetchResponse } from '@backstage/plugin-kubernetes-common'; +import type { JsonObject } from '@backstage/types'; import type { KubernetesFetchError } from '@backstage/plugin-kubernetes-common'; import type { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { Logger as Logger_2 } from 'winston'; @@ -31,6 +32,7 @@ export interface ClusterDetails { // (undocumented) caData?: string | undefined; dashboardApp?: string; + dashboardParameters?: JsonObject; dashboardUrl?: string; name: string; // (undocumented) diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts index f5d6b56893..6ece380f28 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts @@ -176,4 +176,76 @@ describe('ConfigClusterLocator', () => { }, ]); }); + + it('one cluster with dashboardParameters', async () => { + const config: Config = new ConfigReader({ + clusters: [ + { + name: 'cluster1', + url: 'http://localhost:8080', + authProvider: 'serviceAccount', + dashboardApp: 'gke', + dashboardParameters: { + projectId: 'some-project', + region: 'some-region', + clusterName: 'cluster1', + }, + }, + ], + }); + + const sut = ConfigClusterLocator.fromConfig(config); + + const result = await sut.getClusters(); + + expect(result).toStrictEqual([ + { + name: 'cluster1', + serviceAccountToken: undefined, + url: 'http://localhost:8080', + authProvider: 'serviceAccount', + skipMetricsLookup: false, + skipTLSVerify: false, + caData: undefined, + dashboardApp: 'gke', + dashboardParameters: { + projectId: 'some-project', + region: 'some-region', + clusterName: 'cluster1', + }, + }, + ]); + }); + + it('one cluster with dashboardUrl', async () => { + const config: Config = new ConfigReader({ + clusters: [ + { + name: 'cluster1', + url: 'http://localhost:8080', + authProvider: 'serviceAccount', + dashboardApp: 'standard', + dashboardUrl: 'http://someurl', + }, + ], + }); + + const sut = ConfigClusterLocator.fromConfig(config); + + const result = await sut.getClusters(); + + expect(result).toStrictEqual([ + { + name: 'cluster1', + serviceAccountToken: undefined, + url: 'http://localhost:8080', + authProvider: 'serviceAccount', + skipMetricsLookup: false, + skipTLSVerify: false, + caData: undefined, + dashboardApp: 'standard', + dashboardUrl: 'http://someurl', + }, + ]); + }); }); diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts index 36b5f58f2c..d8436b6c24 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts @@ -47,6 +47,9 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier { if (dashboardApp) { clusterDetails.dashboardApp = dashboardApp; } + if (c.has('dashboardParameters')) { + clusterDetails.dashboardParameters = c.get('dashboardParameters'); + } switch (authProvider) { case 'google': { diff --git a/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.test.ts index bd342f566b..6bef8e0009 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.test.ts @@ -226,5 +226,51 @@ describe('GkeClusterLocator', () => { parent: 'projects/some-project/locations/some-region', }); }); + it('expose GKE dashboard', async () => { + mockedListClusters.mockReturnValueOnce([ + { + clusters: [ + { + name: 'some-cluster', + endpoint: '1.2.3.4', + }, + ], + }, + ]); + + const config: Config = new ConfigReader({ + type: 'gke', + projectId: 'some-project', + region: 'some-region', + skipMetricsLookup: true, + exposeDashboard: true, + }); + + const sut = GkeClusterLocator.fromConfigWithClient(config, { + listClusters: mockedListClusters, + } as any); + + const result = await sut.getClusters(); + + expect(result).toStrictEqual([ + { + authProvider: 'google', + name: 'some-cluster', + url: 'https://1.2.3.4', + skipTLSVerify: false, + skipMetricsLookup: true, + dashboardApp: 'gke', + dashboardParameters: { + clusterName: 'some-cluster', + projectId: 'some-project', + region: 'some-region', + }, + }, + ]); + expect(mockedListClusters).toBeCalledTimes(1); + expect(mockedListClusters).toHaveBeenCalledWith({ + parent: 'projects/some-project/locations/some-region', + }); + }); }); }); diff --git a/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.ts b/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.ts index d7f5050399..8b70db40eb 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/GkeClusterLocator.ts @@ -24,6 +24,7 @@ type GkeClusterLocatorOptions = { region?: string; skipTLSVerify?: boolean; skipMetricsLookup?: boolean; + exposeDashboard?: boolean; }; export class GkeClusterLocator implements KubernetesClustersSupplier { @@ -42,6 +43,7 @@ export class GkeClusterLocator implements KubernetesClustersSupplier { skipTLSVerify: config.getOptionalBoolean('skipTLSVerify') ?? false, skipMetricsLookup: config.getOptionalBoolean('skipMetricsLookup') ?? false, + exposeDashboard: config.getOptionalBoolean('exposeDashboard') ?? false, }; return new GkeClusterLocator(options, client); } @@ -55,8 +57,13 @@ export class GkeClusterLocator implements KubernetesClustersSupplier { // TODO pass caData into the object async getClusters(): Promise { - const { projectId, region, skipTLSVerify, skipMetricsLookup } = - this.options; + const { + projectId, + region, + skipTLSVerify, + skipMetricsLookup, + exposeDashboard, + } = this.options; const request = { parent: `projects/${projectId}/locations/${region}`, }; @@ -70,6 +77,16 @@ export class GkeClusterLocator implements KubernetesClustersSupplier { authProvider: 'google', skipTLSVerify, skipMetricsLookup, + ...(exposeDashboard + ? { + dashboardApp: 'gke', + dashboardParameters: { + projectId, + region, + clusterName: r.name, + }, + } + : {}), })); } catch (e) { throw new ForwardedError( diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts index a25c220b80..b15ec1386e 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts @@ -255,6 +255,10 @@ export class KubernetesFanOutHandler { if (clusterDetailsItem.dashboardApp) { objects.cluster.dashboardApp = clusterDetailsItem.dashboardApp; } + if (clusterDetailsItem.dashboardParameters) { + objects.cluster.dashboardParameters = + clusterDetailsItem.dashboardParameters; + } return objects; }); }), diff --git a/plugins/kubernetes-backend/src/types/types.ts b/plugins/kubernetes-backend/src/types/types.ts index a0ec0832c1..4f25805063 100644 --- a/plugins/kubernetes-backend/src/types/types.ts +++ b/plugins/kubernetes-backend/src/types/types.ts @@ -15,6 +15,7 @@ */ import { Logger } from 'winston'; +import type { JsonObject } from '@backstage/types'; import type { FetchResponse, KubernetesFetchError, @@ -111,6 +112,7 @@ export interface ClusterDetails { * using the dashboardApp property, in order to properly format * links to kubernetes resources, otherwise it will assume that you're running the standard one. * @see dashboardApp + * @see dashboardParameters */ dashboardUrl?: string; /** @@ -129,6 +131,12 @@ export interface ClusterDetails { * ``` */ dashboardApp?: string; + /** + * Specifies specific parameters used by some dashboard URL formatters. + * This is used by the GKE formatter which requires the project, region and cluster name. + * @see dashboardApp + */ + dashboardParameters?: JsonObject; } export interface GKEClusterDetails extends ClusterDetails {} diff --git a/plugins/kubernetes-common/api-report.md b/plugins/kubernetes-common/api-report.md index f3500aa271..15019d71c3 100644 --- a/plugins/kubernetes-common/api-report.md +++ b/plugins/kubernetes-common/api-report.md @@ -4,6 +4,7 @@ ```ts import { Entity } from '@backstage/catalog-model'; +import type { JsonObject } from '@backstage/types'; import { V1ConfigMap } from '@kubernetes/client-node'; import { V1CronJob } from '@kubernetes/client-node'; import { V1Deployment } from '@kubernetes/client-node'; @@ -62,6 +63,7 @@ export interface ClientPodStatus { // @public (undocumented) export interface ClusterAttributes { dashboardApp?: string; + dashboardParameters?: JsonObject; dashboardUrl?: string; name: string; } diff --git a/plugins/kubernetes-common/src/types.ts b/plugins/kubernetes-common/src/types.ts index 0c5af00a97..afda9b5299 100644 --- a/plugins/kubernetes-common/src/types.ts +++ b/plugins/kubernetes-common/src/types.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import type { JsonObject } from '@backstage/types'; import { V1ConfigMap, V1CronJob, @@ -45,6 +46,7 @@ export interface ClusterAttributes { * Note that you should specify the app used for the dashboard * using the dashboardApp property, in order to properly format * links to kubernetes resources, otherwise it will assume that you're running the standard one. + * Also, for cloud clusters such as GKE, you should provide addititonal parameters using dashboardParameters. * @see dashboardApp */ dashboardUrl?: string; @@ -64,6 +66,11 @@ export interface ClusterAttributes { * ``` */ dashboardApp?: string; + /** + * Specifies specific parameters used by some dashboard URL formatters. + * This is used by the GKE formatter which requires the project, region and cluster name. + */ + dashboardParameters?: JsonObject; } export interface ClusterObjects { diff --git a/plugins/kubernetes/api-report.md b/plugins/kubernetes/api-report.md index 33ac98fb76..8dc0114738 100644 --- a/plugins/kubernetes/api-report.md +++ b/plugins/kubernetes/api-report.md @@ -10,6 +10,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; import { IdentityApi } from '@backstage/core-plugin-api'; +import type { JsonObject } from '@backstage/types'; import { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; import { OAuthApi } from '@backstage/core-plugin-api'; import { ObjectsByEntityResponse } from '@backstage/plugin-kubernetes-common'; diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 1a39042316..111a444f0d 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -53,10 +53,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/kubernetes/src/components/KubernetesDrawer/KubernetesDrawer.tsx b/plugins/kubernetes/src/components/KubernetesDrawer/KubernetesDrawer.tsx index b4ea31dc8d..8a177cf6dd 100644 --- a/plugins/kubernetes/src/components/KubernetesDrawer/KubernetesDrawer.tsx +++ b/plugins/kubernetes/src/components/KubernetesDrawer/KubernetesDrawer.tsx @@ -155,6 +155,7 @@ const KubernetesDrawerContent = ({ const { clusterLink, errorMessage } = tryFormatClusterLink({ dashboardUrl: cluster.dashboardUrl, dashboardApp: cluster.dashboardApp, + dashboardParameters: cluster.dashboardParameters, object, kind, }); diff --git a/plugins/kubernetes/src/types/types.ts b/plugins/kubernetes/src/types/types.ts index d6ef8fa784..1bdfa181d9 100644 --- a/plugins/kubernetes/src/types/types.ts +++ b/plugins/kubernetes/src/types/types.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import type { JsonObject } from '@backstage/types'; import { V1Deployment, V1Pod, @@ -43,7 +44,8 @@ export interface GroupedResponses extends DeploymentResources { } export interface ClusterLinksFormatterOptions { - dashboardUrl: URL; + dashboardUrl?: URL; + dashboardParameters?: JsonObject; object: any; kind: string; } diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.test.ts b/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.test.ts index 31e07a0f14..b767d496a2 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.test.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.test.ts @@ -114,5 +114,47 @@ describe('clusterLinks', () => { ); }); }); + describe('GKE app', () => { + it('should return an url on the deployment', () => { + const url = formatClusterLink({ + dashboardApp: 'gke', + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }); + expect(url).toBe( + 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', + ); + }); + it('should return an url on the service', () => { + const url = formatClusterLink({ + dashboardApp: 'gke', + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Service', + }); + expect(url).toBe( + 'https://console.cloud.google.com/kubernetes/service/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', + ); + }); + }); }); }); diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.ts b/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.ts index a8f83a9c76..6a998bbce2 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatClusterLink.ts @@ -14,20 +14,22 @@ * limitations under the License. */ +import type { JsonObject } from '@backstage/types'; import { defaultFormatterName, clusterLinksFormatters } from './formatters'; export type FormatClusterLinkOptions = { dashboardUrl?: string; dashboardApp?: string; + dashboardParameters?: JsonObject; object: any; kind: string; }; export function formatClusterLink(options: FormatClusterLinkOptions) { - if (!options.dashboardUrl) { + if (!options.dashboardUrl && !options.dashboardParameters) { return undefined; } - if (!options.object) { + if (options.dashboardUrl && !options.object) { return options.dashboardUrl; } const app = options.dashboardApp || defaultFormatterName; @@ -36,7 +38,10 @@ export function formatClusterLink(options: FormatClusterLinkOptions) { throw new Error(`Could not find Kubernetes dashboard app named '${app}'`); } const url = formatter({ - dashboardUrl: new URL(options.dashboardUrl), + dashboardUrl: options.dashboardUrl + ? new URL(options.dashboardUrl) + : undefined, + dashboardParameters: options.dashboardParameters, object: options.object, kind: options.kind, }); diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.test.ts b/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.test.ts index e566404daf..20541f216d 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.test.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.test.ts @@ -16,10 +16,9 @@ import { gkeFormatter } from './gke'; describe('clusterLinks - GKE formatter', () => { - it('should return an url on the workloads when there is a namespace only', () => { + it('should provide a dashboardParameters in the options', () => { expect(() => gkeFormatter({ - dashboardUrl: new URL('https://k8s.foo.com'), object: { metadata: { name: 'foobar', @@ -28,6 +27,196 @@ describe('clusterLinks - GKE formatter', () => { }, kind: 'Deployment', }), - ).toThrowError('GKE formatter is not yet implemented. Please, contribute!'); + ).toThrowError('GKE dashboard requires a dashboardParameters option'); + }); + it('should provide a projectId in the dashboardParameters options', () => { + expect(() => + gkeFormatter({ + dashboardParameters: { + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).toThrowError( + 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', + ); + }); + it('should provide a region in the dashboardParameters options', () => { + expect(() => + gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).toThrowError( + 'GKE dashboard requires a "region" of type string in the dashboardParameters option', + ); + }); + it('should provide a clusterName in the dashboardParameters options', () => { + expect(() => + gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).toThrowError( + 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', + ); + }); + it('should return an url on the cluster when there is a namespace only', () => { + const url = gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + namespace: 'bar', + }, + }, + kind: 'foo', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/clusters/details/us-east1-c/cluster-1/details?project=foobar-333614', + ); + }); + it('should return an url on the cluster when the kind is not recognizeed', () => { + const url = gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'UnknownKind', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/clusters/details/us-east1-c/cluster-1/details?project=foobar-333614', + ); + }); + it('should return an url on the deployment', () => { + const url = gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', + ); + }); + + it('should return an url on the service', () => { + const url = gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Service', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/service/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', + ); + }); + it('should return an url on the pod', () => { + const url = gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Pod', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/pod/us-east1-c/cluster-1/bar/foobar/details?project=foobar-333614', + ); + }); + it('should return an url on the ingress', () => { + const url = gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Ingress', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/ingress/us-east1-c/cluster-1/bar/foobar/details?project=foobar-333614', + ); + }); + it('should return an url on the deployment for a hpa', () => { + const url = gkeFormatter({ + dashboardParameters: { + projectId: 'foobar-333614', + region: 'us-east1-c', + clusterName: 'cluster-1', + }, + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'HorizontalPodAutoscaler', + }); + expect(url.href).toBe( + 'https://console.cloud.google.com/kubernetes/deployment/us-east1-c/cluster-1/bar/foobar/overview?project=foobar-333614', + ); }); }); diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.ts b/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.ts index 30e7fa3123..957032e6e2 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatters/gke.ts @@ -15,6 +15,53 @@ */ import { ClusterLinksFormatterOptions } from '../../../types/types'; -export function gkeFormatter(_options: ClusterLinksFormatterOptions): URL { - throw new Error('GKE formatter is not yet implemented. Please, contribute!'); +const kindMappings: Record = { + deployment: 'deployment', + pod: 'pod', + ingress: 'ingress', + service: 'service', + horizontalpodautoscaler: 'deployment', +}; + +export function gkeFormatter(options: ClusterLinksFormatterOptions): URL { + if (!options.dashboardParameters) { + throw new Error('GKE dashboard requires a dashboardParameters option'); + } + const args = options.dashboardParameters; + if (typeof args.projectId !== 'string') { + throw new Error( + 'GKE dashboard requires a "projectId" of type string in the dashboardParameters option', + ); + } + if (typeof args.region !== 'string') { + throw new Error( + 'GKE dashboard requires a "region" of type string in the dashboardParameters option', + ); + } + if (typeof args.clusterName !== 'string') { + throw new Error( + 'GKE dashboard requires a "clusterName" of type string in the dashboardParameters option', + ); + } + const basePath = new URL('https://console.cloud.google.com/'); + const region = encodeURIComponent(args.region); + const clusterName = encodeURIComponent(args.clusterName); + const name = encodeURIComponent(options.object.metadata?.name ?? ''); + const namespace = encodeURIComponent( + options.object.metadata?.namespace ?? '', + ); + const validKind = kindMappings[options.kind.toLocaleLowerCase('en-US')]; + let path = ''; + if (namespace && name && validKind) { + const kindsWithDetails = ['ingress', 'pod']; + const landingPage = kindsWithDetails.includes(validKind) + ? 'details' + : 'overview'; + path = `kubernetes/${validKind}/${region}/${clusterName}/${namespace}/${name}/${landingPage}`; + } else { + path = `kubernetes/clusters/details/${region}/${clusterName}/details`; + } + const result = new URL(path, basePath); + result.searchParams.set('project', args.projectId); + return result; } diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.test.ts b/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.test.ts index f0b85cad49..2380d3e2d5 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.test.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.test.ts @@ -16,6 +16,19 @@ import { openshiftFormatter } from './openshift'; describe('clusterLinks - OpenShift formatter', () => { + it('should provide a dashboardUrl in the options', () => { + expect(() => + openshiftFormatter({ + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).toThrowError('OpenShift dashboard requires a dashboardUrl option'); + }); it('should return an url on the workloads when there is a namespace only', () => { const url = openshiftFormatter({ dashboardUrl: new URL('https://k8s.foo.com'), diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.ts b/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.ts index 6c20cd4720..c5b7313061 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatters/openshift.ts @@ -24,6 +24,9 @@ const kindMappings: Record = { }; export function openshiftFormatter(options: ClusterLinksFormatterOptions): URL { + if (!options.dashboardUrl) { + throw new Error('OpenShift dashboard requires a dashboardUrl option'); + } const basePath = new URL(options.dashboardUrl.href); const name = encodeURIComponent(options.object.metadata?.name ?? ''); const namespace = encodeURIComponent( diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.test.ts b/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.test.ts index cb200387a3..45983deab0 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.test.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.test.ts @@ -16,6 +16,19 @@ import { rancherFormatter } from './rancher'; describe('clusterLinks - rancher formatter', () => { + it('should provide a dashboardUrl in the options', () => { + expect(() => + rancherFormatter({ + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).toThrowError('Rancher dashboard requires a dashboardUrl option'); + }); it('should return a url on the workloads when there is a namespace only', () => { const url = rancherFormatter({ dashboardUrl: new URL('https://k8s.foo.com'), diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.ts b/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.ts index 1ace39ec59..6c72730181 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatters/rancher.ts @@ -23,6 +23,9 @@ const kindMappings: Record = { }; export function rancherFormatter(options: ClusterLinksFormatterOptions): URL { + if (!options.dashboardUrl) { + throw new Error('Rancher dashboard requires a dashboardUrl option'); + } const basePath = new URL(options.dashboardUrl.href); const name = encodeURIComponent(options.object.metadata?.name ?? ''); const namespace = encodeURIComponent( diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.test.ts b/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.test.ts index 0b3c21a627..c0ee3f534d 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.test.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.test.ts @@ -23,6 +23,19 @@ function formatUrl(url: URL) { } describe('clusterLinks - standard formatter', () => { + it('should provide a dashboardUrl in the options', () => { + expect(() => + standardFormatter({ + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Deployment', + }), + ).toThrowError('standard dashboard requires a dashboardUrl option'); + }); it('should return an url on the workloads when there is a namespace only', () => { const url = standardFormatter({ dashboardUrl: new URL('https://k8s.foo.com'), @@ -67,6 +80,21 @@ describe('clusterLinks - standard formatter', () => { 'https://k8s.foo.com/#/deployment/bar/foobar?namespace=bar', ); }); + it('should return an url on the pod', () => { + const url = standardFormatter({ + dashboardUrl: new URL('https://k8s.foo.com/'), + object: { + metadata: { + name: 'foobar', + namespace: 'bar', + }, + }, + kind: 'Pod', + }); + expect(formatUrl(url)).toBe( + 'https://k8s.foo.com/#/pod/bar/foobar?namespace=bar', + ); + }); it('should return an url on the deployment with a prefix 1', () => { const url = standardFormatter({ dashboardUrl: new URL('https://k8s.foo.com/some/prefix'), diff --git a/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.ts b/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.ts index e28c9fae2b..a7428a8722 100644 --- a/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.ts +++ b/plugins/kubernetes/src/utils/clusterLinks/formatters/standard.ts @@ -17,12 +17,16 @@ import { ClusterLinksFormatterOptions } from '../../../types/types'; const kindMappings: Record = { deployment: 'deployment', + pod: 'pod', ingress: 'ingress', service: 'service', horizontalpodautoscaler: 'deployment', }; export function standardFormatter(options: ClusterLinksFormatterOptions) { + if (!options.dashboardUrl) { + throw new Error('standard dashboard requires a dashboardUrl option'); + } const result = new URL(options.dashboardUrl.href); const name = encodeURIComponent(options.object.metadata?.name ?? ''); const namespace = encodeURIComponent( diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index a9b1e679d0..51970e16c5 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -48,10 +48,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index 0502d130cf..2a81be3b99 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -31,7 +31,7 @@ "react-use": "^17.2.4" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/dev-utils": "^0.2.15", "@testing-library/jest-dom": "^5.10.1", "@types/react": "^16.13.1 || ^17.0.0", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 42b1a832fa..135e03e495 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -44,10 +44,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/org/package.json b/plugins/org/package.json index 2b17df45b2..1a952dfe2f 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -39,11 +39,11 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/core-app-api": "^0.3.0", "@backstage/catalog-client": "^0.5.3", + "@backstage/cli": "^0.10.4", + "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 3656ae682d..458180841e 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index 15474c8348..76ee47ab32 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-permission-backend +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.6.0 + - @backstage/backend-common@0.10.1 + - @backstage/plugin-permission-node@0.2.3 + ## 0.2.2 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index a06e22a9b7..890495f646 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -19,11 +19,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/config": "^0.1.11", - "@backstage/plugin-auth-backend": "^0.5.2", + "@backstage/plugin-auth-backend": "^0.6.0", "@backstage/plugin-permission-common": "^0.3.0", - "@backstage/plugin-permission-node": "^0.2.2", + "@backstage/plugin-permission-node": "^0.2.3", "@types/express": "*", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -33,7 +33,7 @@ "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/supertest": "^2.0.8", "supertest": "^6.1.6", "msw": "^0.35.0" diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index e49dfdc228..377b48f45e 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-permission-node +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.6.0 + - @backstage/backend-common@0.10.1 + ## 0.2.2 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 9100500f1f..55f955110e 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.2.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,16 +29,16 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/config": "^0.1.11", - "@backstage/plugin-auth-backend": "^0.5.2", + "@backstage/plugin-auth-backend": "^0.6.0", "@backstage/plugin-permission-common": "^0.3.0", "@types/express": "^4.17.6", "express": "^4.17.1", "zod": "^3.11.6" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/supertest": "^2.0.8", "msw": "^0.35.0", "supertest": "^6.1.3" diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index 49de959e2b..2d568b8be1 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-rollbar-backend +## 0.1.18 + +### Patch Changes + +- 152bd9ba2b: Moved `@backstage/test-utils` to `devDependencies`. +- c5e175cde9: Replace the usage of `axios` with `node-fetch` in the Rollbar API +- Updated dependencies + - @backstage/backend-common@0.10.1 + ## 0.1.17 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index def1514909..5257402661 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar-backend", "description": "A Backstage backend plugin that integrates towards Rollbar", - "version": "0.1.17", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/config": "^0.1.10", "@types/express": "^4.17.6", "camelcase-keys": "^6.2.2", @@ -48,8 +48,8 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.10.4", + "@backstage/test-utils": "^0.2.1", "@types/supertest": "^2.0.8", "msw": "^0.36.3", "supertest": "^6.1.3" diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 67dbebb80d..df5305b851 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 38f336e5cc..52a82025c9 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.1.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/plugin-scaffolder-backend@0.15.19 + - @backstage/integration@0.7.0 + ## 0.1.6 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 68f5bc9a54..349cda084e 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", - "version": "0.1.6", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,10 +20,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/errors": "^0.1.4", - "@backstage/integration": "^0.6.10", - "@backstage/plugin-scaffolder-backend": "^0.15.18", + "@backstage/integration": "^0.7.0", + "@backstage/plugin-scaffolder-backend": "^0.15.19", "@backstage/config": "^0.1.11", "@backstage/types": "^0.1.1", "command-exists": "^1.2.9", @@ -32,7 +32,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/fs-extra": "^9.0.1", "@types/mock-fs": "^4.13.0", "@types/jest": "^26.0.7", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 1abf510af4..70c35ba33e 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/plugin-scaffolder-backend@0.15.19 + - @backstage/integration@0.7.0 + ## 0.2.1 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 7021ce9c0b..42a910e624 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", "description": "A module for the scaffolder backend that lets you template projects using Rails", - "version": "0.2.1", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,17 +21,17 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/plugin-scaffolder-backend": "^0.15.18", + "@backstage/backend-common": "^0.10.1", + "@backstage/plugin-scaffolder-backend": "^0.15.19", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.4", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@backstage/types": "^0.1.1", "command-exists": "^1.2.9", "fs-extra": "^9.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", "@types/command-exists": "^1.2.0", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 8af6b497cc..1a138a16e0 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-scaffolder-backend +## 0.15.19 + +### Patch Changes + +- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface. +- d078377f67: Support navigating back to pre-filled templates to update inputs of scaffolder tasks for resubmission +- 5f8ceba1b1: Support custom file name for `catalog:write` action +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/plugin-catalog-backend@0.19.4 + - @backstage/plugin-scaffolder-common@0.1.2 + - @backstage/integration@0.7.0 + - @backstage/plugin-scaffolder-backend-module-cookiecutter@0.1.7 + ## 0.15.18 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index ba5dceb699..8fb5bdcdab 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "0.15.18", + "version": "0.15.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,15 +31,15 @@ "build:assets": "node scripts/build-nunjucks.js" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/catalog-client": "^0.5.3", "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.6.10", - "@backstage/plugin-catalog-backend": "^0.19.3", - "@backstage/plugin-scaffolder-common": "^0.1.1", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "^0.1.6", + "@backstage/integration": "^0.7.0", + "@backstage/plugin-catalog-backend": "^0.19.4", + "@backstage/plugin-scaffolder-common": "^0.1.2", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "^0.1.7", "@backstage/types": "^0.1.1", "@gitbeaker/core": "^34.6.0", "@gitbeaker/node": "^34.6.0", @@ -73,8 +73,8 @@ "vm2": "^3.9.5" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.10.4", + "@backstage/test-utils": "^0.2.1", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts index 48c44f090a..8b1be0c187 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.test.ts @@ -69,4 +69,33 @@ describe('catalog:write', () => { yaml.stringify(entity), ); }); + + it('should support a custom filename', async () => { + const entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'n', + namespace: 'ns', + annotations: { + [ORIGIN_LOCATION_ANNOTATION]: 'url:https://example.com', + }, + }, + spec: {}, + }; + + await action.handler({ + ...mockContext, + input: { + filePath: 'some-dir/entity-info.yaml', + entity, + }, + }); + + expect(fsMock.writeFile).toHaveBeenCalledTimes(1); + expect(fsMock.writeFile).toHaveBeenCalledWith( + resolvePath(mockContext.workspacePath, 'some-dir/entity-info.yaml'), + yaml.stringify(entity), + ); + }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts index b813244020..46220358c7 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/catalog/write.ts @@ -21,13 +21,18 @@ import { Entity } from '@backstage/catalog-model'; import { resolveSafeChildPath } from '@backstage/backend-common'; export function createCatalogWriteAction() { - return createTemplateAction<{ name?: string; entity: Entity }>({ + return createTemplateAction<{ filePath?: string; entity: Entity }>({ id: 'catalog:write', description: 'Writes the catalog-info.yaml for your template', schema: { input: { type: 'object', properties: { + filePath: { + title: 'Catalog file path', + description: 'Defaults to catalog-info.yaml', + type: 'string', + }, entity: { title: 'Entity info to write catalog-info.yaml', description: @@ -39,10 +44,11 @@ export function createCatalogWriteAction() { }, async handler(ctx) { ctx.logStream.write(`Writing catalog-info.yaml`); - const { entity } = ctx.input; + const { filePath, entity } = ctx.input; + const path = filePath ?? 'catalog-info.yaml'; await fs.writeFile( - resolveSafeChildPath(ctx.workspacePath, 'catalog-info.yaml'), + resolveSafeChildPath(ctx.workspacePath, path), yaml.stringify(entity), ); }, diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index db139b2782..f2d9ea26b3 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-scaffolder-common +## 0.1.2 + +### Patch Changes + +- d078377f67: Support navigating back to pre-filled templates to update inputs of scaffolder tasks for resubmission + ## 0.1.1 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 9099eda99d..80644a6739 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-common", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", - "version": "0.1.1", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -40,6 +40,6 @@ "@backstage/types": "^0.1.1" }, "devDependencies": { - "@backstage/cli": "^0.10.0" + "@backstage/cli": "^0.10.4" } } diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 29a8437066..78870ae5ab 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder +## 0.11.16 + +### Patch Changes + +- 9c25894892: Implement a `EntityTagsPicker` field extension +- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface. +- d078377f67: Support navigating back to pre-filled templates to update inputs of scaffolder tasks for resubmission +- Updated dependencies + - @backstage/plugin-catalog-react@0.6.9 + - @backstage/plugin-scaffolder-common@0.1.2 + - @backstage/integration@0.7.0 + - @backstage/integration-react@0.1.17 + ## 0.11.15 ### Patch Changes diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 4f6928e72d..5252e08299 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -80,6 +80,16 @@ export const EntityPicker: ({ // @public (undocumented) export const EntityPickerFieldExtension: () => null; +// @public +export const EntityTagsPicker: ({ + formData, + onChange, + uiSchema, +}: FieldProps) => JSX.Element; + +// @public +export const EntityTagsPickerFieldExtension: () => null; + // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "FavouriteTemplate" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 2c9112a77a..ec33430b02 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "0.11.15", + "version": "0.11.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,10 +37,10 @@ "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.6.10", - "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-catalog-react": "^0.6.8", - "@backstage/plugin-scaffolder-common": "^0.1.1", + "@backstage/integration": "^0.7.0", + "@backstage/integration-react": "^0.1.17", + "@backstage/plugin-catalog-react": "^0.6.9", + "@backstage/plugin-scaffolder-common": "^0.1.2", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -67,11 +67,11 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/plugin-catalog": "^0.7.5", - "@backstage/test-utils": "^0.2.0", + "@backstage/plugin-catalog": "^0.7.6", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx b/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx new file mode 100644 index 0000000000..b21398a3f4 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx @@ -0,0 +1,107 @@ +/* + * Copyright 2021 The Backstage 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. + */ +import React, { useState } from 'react'; +import { useAsync, useEffectOnce } from 'react-use'; +import { CatalogEntitiesRequest } from '@backstage/catalog-client'; +import { Entity, makeValidator } from '@backstage/catalog-model'; +import { useApi } from '@backstage/core-plugin-api'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { FormControl, TextField } from '@material-ui/core'; +import { Autocomplete } from '@material-ui/lab'; +import { FieldProps } from '@rjsf/core'; + +/** + * EntityTagsPicker + * @public + */ +export const EntityTagsPicker = ({ + formData, + onChange, + uiSchema, +}: FieldProps) => { + const catalogApi = useApi(catalogApiRef); + const [inputValue, setInputValue] = useState(''); + const [inputError, setInputError] = useState(false); + const tagValidator = makeValidator().isValidTag; + const kinds = uiSchema['ui:options']?.kinds as string[]; + + const { loading, value: existingTags } = useAsync(async () => { + const tagsRequest: CatalogEntitiesRequest = { fields: ['metadata.tags'] }; + if (kinds) { + tagsRequest.filter = { kind: kinds }; + } + + const entities = await catalogApi.getEntities(tagsRequest); + + return [ + ...new Set( + entities.items + .flatMap((e: Entity) => e.metadata?.tags) + .filter(Boolean) as string[], + ), + ].sort(); + }); + + const setTags = (_: React.ChangeEvent<{}>, values: string[] | null) => { + // Reset error state in case all tags were removed + let hasError = false; + let addDuplicate = false; + const currentTags = formData || []; + + // If adding a new tag + if (values?.length && currentTags.length < values.length) { + const newTag = (values[values.length - 1] = values[values.length - 1] + .toLocaleLowerCase('en-US') + .trim()); + hasError = !tagValidator(newTag); + addDuplicate = currentTags.indexOf(newTag) !== -1; + } + + setInputError(hasError); + setInputValue(!hasError ? '' : inputValue); + if (!hasError && !addDuplicate) { + onChange(values || []); + } + }; + + // Initialize field to always return an array + useEffectOnce(() => onChange(formData || [])); + + return ( + + ( + setInputValue(e.target.value)} + error={inputError} + helperText="Add any relevant tags, hit 'Enter' to add new tags. Valid format: [a-z0-9+#] separated by [-], at most 63 characters" + /> + )} + /> + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts b/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts new file mode 100644 index 0000000000..09f4d5c519 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/EntityTagsPicker/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2021 The Backstage 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. + */ +export { EntityTagsPicker } from './EntityTagsPicker'; diff --git a/plugins/scaffolder/src/components/fields/index.ts b/plugins/scaffolder/src/components/fields/index.ts index 299470e220..ecde218029 100644 --- a/plugins/scaffolder/src/components/fields/index.ts +++ b/plugins/scaffolder/src/components/fields/index.ts @@ -19,3 +19,4 @@ export * from './OwnerPicker'; export * from './RepoUrlPicker'; export * from './TextValuePicker'; export * from './OwnedEntityPicker'; +export * from './EntityTagsPicker'; diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index 12a29809e0..820cc0e6d3 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -18,6 +18,7 @@ import { EntityNamePicker, entityNamePickerValidation, } from '../components/fields/EntityNamePicker'; +import { EntityTagsPicker } from '../components/fields/EntityTagsPicker'; import { OwnerPicker } from '../components/fields/OwnerPicker'; import { repoPickerValidation, @@ -36,6 +37,10 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = [ name: 'EntityNamePicker', validation: entityNamePickerValidation, }, + { + component: EntityTagsPicker, + name: 'EntityTagsPicker', + }, { component: RepoUrlPicker, name: 'RepoUrlPicker', diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index dfbd2af296..3851b2151b 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -30,6 +30,7 @@ export type { CustomFieldValidator, FieldExtensionOptions } from './extensions'; export { EntityPickerFieldExtension, EntityNamePickerFieldExtension, + EntityTagsPickerFieldExtension, OwnerPickerFieldExtension, OwnedEntityPickerFieldExtension, RepoUrlPickerFieldExtension, @@ -40,6 +41,7 @@ export { export { EntityNamePicker, EntityPicker, + EntityTagsPicker, OwnerPicker, RepoUrlPicker, TextValuePicker, diff --git a/plugins/scaffolder/src/plugin.ts b/plugins/scaffolder/src/plugin.ts index 95cad50eba..02b36c4bb6 100644 --- a/plugins/scaffolder/src/plugin.ts +++ b/plugins/scaffolder/src/plugin.ts @@ -36,6 +36,7 @@ import { identityApiRef, } from '@backstage/core-plugin-api'; import { OwnedEntityPicker } from './components/fields/OwnedEntityPicker'; +import { EntityTagsPicker } from './components/fields/EntityTagsPicker'; export const scaffolderPlugin = createPlugin({ id: 'scaffolder', @@ -103,3 +104,14 @@ export const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide( name: 'OwnedEntityPicker', }), ); + +/** + * EntityTagsPickerFieldExtension + * @public + */ +export const EntityTagsPickerFieldExtension = scaffolderPlugin.provide( + createScaffolderFieldExtension({ + component: EntityTagsPicker, + name: 'EntityTagsPicker', + }), +); diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 4ff92cfb76..376a02b5fb 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search +## 0.5.3 + +### Patch Changes + +- 6d8e3a9651: Internal cleanup of the exports structure +- 8b532a6c02: Introduces a `` variant, which operates on the same part of a search query as the existing ``, but in a more opinionated way (as a single-select control surface suitable for faceted search UIs). + + Check the [search plugin storybook](https://backstage.io/storybook/?path=/story/plugins-search-searchtype--accordion) to see how it can be used. + +- af4980fb5d: Captures the search term entered in the SearchBarBase as a `search` event. +- Updated dependencies + - @backstage/plugin-catalog-react@0.6.9 + ## 0.5.2 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index a308fc0a22..c9e7d0aba1 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "0.5.2", + "version": "0.5.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,7 +35,7 @@ "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/errors": "^0.1.4", - "@backstage/plugin-catalog-react": "^0.6.8", + "@backstage/plugin-catalog-react": "^0.6.9", "@backstage/search-common": "^0.2.1", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", @@ -52,10 +52,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/search/src/components/SearchBar/SearchBar.tsx b/plugins/search/src/components/SearchBar/SearchBar.tsx index aa4b1e728a..188341cd6c 100644 --- a/plugins/search/src/components/SearchBar/SearchBar.tsx +++ b/plugins/search/src/components/SearchBar/SearchBar.tsx @@ -20,6 +20,7 @@ import React, { useState, useEffect, useCallback, + useContext, } from 'react'; import { useDebounce } from 'react-use'; import { configApiRef, useApi } from '@backstage/core-plugin-api'; @@ -32,7 +33,11 @@ import { import SearchIcon from '@material-ui/icons/Search'; import ClearButton from '@material-ui/icons/Clear'; -import { useSearch } from '../SearchContext'; +import { + SearchContext, + SearchContextProvider, + useSearch, +} from '../SearchContext'; import { TrackSearch } from '../SearchTracker'; /** @@ -48,6 +53,11 @@ export type SearchBarBaseProps = Omit & { onChange: (value: string) => void; }; +const useSearchContextCheck = () => { + const context = useContext(SearchContext); + return context !== undefined; +}; + /** * All search boxes exported by the search plugin are based on the , * and this one is based on the component from Material UI. @@ -69,6 +79,7 @@ export const SearchBarBase = ({ }: SearchBarBaseProps) => { const configApi = useApi(configApiRef); const [value, setValue] = useState(defaultValue as string); + const hasSearchContext = useSearchContextCheck(); useEffect(() => { setValue(prevValue => @@ -119,7 +130,7 @@ export const SearchBarBase = ({ ); - return ( + const searchBar = ( ); + + return hasSearchContext ? ( + searchBar + ) : ( + {searchBar} + ); }; /** diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index c1eadc5646..3b810b7bfc 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -49,10 +49,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index 17c9328a92..1770fea044 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -39,10 +39,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 71ec7e7f29..9eba8bcfb1 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -50,10 +50,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index e6ffc43402..7277db6355 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -48,10 +48,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index a6bd7824c9..544bfc3c2b 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.4 + +### Patch Changes + +- 8d00dc427c: ability to add custom operators +- Updated dependencies + - @backstage/backend-common@0.10.1 + ## 0.1.3 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index d7ee1bfb58..30f00f4210 100644 --- a/plugins/tech-insights-backend-module-jsonfc/package.json +++ b/plugins/tech-insights-backend-module-jsonfc/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend-module-jsonfc", - "version": "0.1.3", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,7 +31,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/config": "^0.1.8", "@backstage/errors": "^0.1.5", "@backstage/plugin-tech-insights-common": "^0.2.0", @@ -43,7 +43,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/node-cron": "^2.0.4" }, "files": [ diff --git a/plugins/tech-insights/CHANGELOG.md b/plugins/tech-insights/CHANGELOG.md index d353cecba0..e761faab97 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-tech-insights +## 0.1.3 + +### Patch Changes + +- a86f5c1701: Fixed API auth in tech-insights plugin +- d83079fc11: Export `techInsightsApiRef` and associated types. +- Updated dependencies + - @backstage/plugin-catalog-react@0.6.9 + ## 0.1.2 ### Patch Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index f8382984de..d661f5846c 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights", - "version": "0.1.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,7 +24,7 @@ "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/errors": "^0.1.4", - "@backstage/plugin-catalog-react": "^0.6.8", + "@backstage/plugin-catalog-react": "^0.6.9", "@backstage/plugin-tech-insights-common": "^0.2.0", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", @@ -39,10 +39,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/tech-insights/src/api/TechInsightsClient.ts b/plugins/tech-insights/src/api/TechInsightsClient.ts index 43979e60b0..2298f463f5 100644 --- a/plugins/tech-insights/src/api/TechInsightsClient.ts +++ b/plugins/tech-insights/src/api/TechInsightsClient.ts @@ -66,20 +66,20 @@ export class TechInsightsClient implements TechInsightsApi { async runChecks( entityParams: EntityName, - checks: Check[], + checks?: Check[], ): Promise { const url = await this.discoveryApi.getBaseUrl('tech-insights'); const token = await this.identityApi.getIdToken(); const { namespace, kind, name } = entityParams; - const allChecks = checks ? checks : await this.getAllChecks(); - const checkIds = allChecks.map((check: Check) => check.id); + const checkIds = checks ? checks.map(check => check.id) : []; + const requestBody = { checks: checkIds.length > 0 ? checkIds : undefined }; const response = await fetch( `${url}/checks/run/${encodeURIComponent(namespace)}/${encodeURIComponent( kind, )}/${encodeURIComponent(name)}`, { method: 'POST', - body: JSON.stringify({ checks: checkIds }), + body: JSON.stringify(requestBody), headers: { 'Content-Type': 'application/json', ...(token && { Authorization: `Bearer ${token}` }), diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index b9154db76e..50968a6a2f 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -46,10 +46,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index dee69523ef..256a402a24 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-techdocs-backend +## 0.12.2 + +### Patch Changes + +- da676a49ab: Add support for API auth in DefaultTechDocsCollator +- Updated dependencies + - @backstage/techdocs-common@0.11.2 + - @backstage/backend-common@0.10.1 + - @backstage/integration@0.7.0 + ## 0.12.1 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 89dcda5968..0d5a86ffc7 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-backend", "description": "The Backstage backend plugin that renders technical documentation for your components", - "version": "0.12.1", + "version": "0.12.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,14 +31,14 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/catalog-client": "^0.5.3", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@backstage/search-common": "^0.2.1", - "@backstage/techdocs-common": "^0.11.1", + "@backstage/techdocs-common": "^0.11.2", "@types/express": "^4.17.6", "cross-fetch": "^3.0.6", "dockerode": "^3.3.1", @@ -52,8 +52,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.3", - "@backstage/test-utils": "^0.2.0", + "@backstage/cli": "^0.10.4", + "@backstage/test-utils": "^0.2.1", "@types/dockerode": "^3.3.0", "msw": "^0.35.0", "supertest": "^6.1.3" diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 2883181f13..2cfa8064e9 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-techdocs +## 0.12.12 + +### Patch Changes + +- aa8f764a3e: Add the techdocs.sanitizer.allowedIframeHosts config. + This config allows all iframes which have the host of the attribute src in the 'allowedIframehosts' list to be displayed in the documentation. +- Updated dependencies + - @backstage/plugin-search@0.5.3 + - @backstage/plugin-catalog@0.7.6 + - @backstage/plugin-catalog-react@0.6.9 + - @backstage/integration@0.7.0 + - @backstage/integration-react@0.1.17 + ## 0.12.11 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index b702b45073..f45be5b4b7 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "0.12.11", + "version": "0.12.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,11 +37,11 @@ "@backstage/core-components": "^0.8.2", "@backstage/core-plugin-api": "^0.4.0", "@backstage/errors": "^0.1.5", - "@backstage/integration": "^0.6.10", - "@backstage/integration-react": "^0.1.16", - "@backstage/plugin-catalog": "^0.7.5", - "@backstage/plugin-catalog-react": "^0.6.8", - "@backstage/plugin-search": "^0.5.2", + "@backstage/integration": "^0.7.0", + "@backstage/integration-react": "^0.1.17", + "@backstage/plugin-catalog": "^0.7.6", + "@backstage/plugin-catalog-react": "^0.6.9", + "@backstage/plugin-search": "^0.5.3", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -62,10 +62,10 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/react-hooks": "^7.0.2", diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index 2c854a2beb..41ffd3e79d 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-todo-backend +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.10.1 + - @backstage/integration@0.7.0 + ## 0.1.16 ### Patch Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index f8578cd544..7368f69fd8 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo-backend", "description": "A Backstage backend plugin that lets you browse TODO comments in your source code", - "version": "0.1.16", + "version": "0.1.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -25,12 +25,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", + "@backstage/backend-common": "^0.10.1", "@backstage/catalog-client": "^0.5.3", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", "@backstage/errors": "^0.1.3", - "@backstage/integration": "^0.6.10", + "@backstage/integration": "^0.7.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -39,7 +39,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@types/supertest": "^2.0.8", "msw": "^0.35.0", "supertest": "^6.1.3" diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 6f86c47db9..a2a94d11b1 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -42,10 +42,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index cd7225ac72..f43fc36e17 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -44,10 +44,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 64a19fc0f2..88001a68db 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -37,10 +37,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.3", + "@backstage/cli": "^0.10.4", "@backstage/core-app-api": "^0.3.0", "@backstage/dev-utils": "^0.2.15", - "@backstage/test-utils": "^0.2.0", + "@backstage/test-utils": "^0.2.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", "@testing-library/user-event": "^13.1.8", diff --git a/scripts/verify-changesets.js b/scripts/verify-changesets.js new file mode 100755 index 0000000000..8d828ee058 --- /dev/null +++ b/scripts/verify-changesets.js @@ -0,0 +1,88 @@ +#!/usr/bin/env node +/* + * Copyright 2020 The Backstage 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. + */ + +/* eslint-disable import/no-extraneous-dependencies */ + +const { resolve: resolvePath } = require('path'); +const fs = require('fs-extra'); +const { default: parseChangeset } = require('@changesets/parse'); + +const privatePackages = new Set([ + 'example-app', + 'example-backend', + 'e2e-test', + 'storybook', + 'embedded-techdocs-app', +]); + +async function main() { + process.chdir(resolvePath(__dirname, '../.changeset')); + + const fileNames = await fs.readdir('.'); + const changesetNames = fileNames.filter( + name => name.endsWith('.md') && name !== 'README.md', + ); + + const changesets = await Promise.all( + changesetNames.map(async name => { + const content = await fs.readFile(name, 'utf8'); + return { name, ...parseChangeset(content) }; + }), + ); + + const errors = []; + for (const changeset of changesets) { + const privateReleases = changeset.releases.filter(release => + privatePackages.has(release.name), + ); + if (privateReleases.length > 0) { + const names = privateReleases + .map(release => `'${release.name}'`) + .join(', '); + errors.push({ + name: changeset.name, + messages: [ + `Should not contain releases of the following packages since they are not published: ${names}`, + ], + }); + } + } + + if (errors.length) { + console.log(); + console.log('***********************************************************'); + console.log('* Changeset verification failed! *'); + console.log('***********************************************************'); + console.log(); + for (const error of errors) { + console.error(`Changeset '${error.name}' is invalid:`); + console.log(); + for (const message of error.messages) { + console.error(` ${message}`); + } + } + console.log(); + console.log('***********************************************************'); + console.log(); + process.exit(1); + } +} + +main().catch(error => { + console.error(error.stack); + process.exit(1); +}); diff --git a/yarn.lock b/yarn.lock index 4ddb332fb3..1730c6f376 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2498,6 +2498,19 @@ react-use "^17.2.4" zen-observable "^0.8.15" +"@backstage/integration@^0.6.4", "@backstage/integration@^0.6.7": + version "0.6.10" + resolved "https://registry.npmjs.org/@backstage/integration/-/integration-0.6.10.tgz#e55a26f5124445de74e46944f63c263c9b985995" + integrity sha512-qGAZ7rflWdZdjUgxzLWmkrR1zPC5ep62d0fqtwg77MZsGwBNrbNOI2qJbk+IRPmOgym2Adg2C95O2UV7Hyde7g== + dependencies: + "@backstage/config" "^0.1.11" + "@octokit/auth-app" "^3.4.0" + "@octokit/rest" "^18.5.3" + cross-fetch "^3.0.6" + git-url-parse "^11.6.0" + lodash "^4.17.21" + luxon "^2.0.2" + "@backstage/plugin-catalog-react@^0.4.0": version "0.4.6" resolved "https://registry.npmjs.org/@backstage/plugin-catalog-react/-/plugin-catalog-react-0.4.6.tgz#f33f3cd734f110d3c547f7eae4e25d14806ec796" @@ -7821,9 +7834,9 @@ integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA== "@types/jscodeshift@^0.11.0": - version "0.11.0" - resolved "https://registry.npmjs.org/@types/jscodeshift/-/jscodeshift-0.11.0.tgz#7224cf1a4d0383b4fb2694ffed52f57b45c3325b" - integrity sha512-OcJgr5GznWCEx2Oeg4eMUZYwssTHFj/tU8grrNCKdFQtAEAa0ezDiPHbCdSkyWrRSurXrYbNbHdhxbbB76pXNg== + version "0.11.3" + resolved "https://registry.npmjs.org/@types/jscodeshift/-/jscodeshift-0.11.3.tgz#8dcab24ced39dcab1c8ff3461b3d171aafee3d48" + integrity sha512-pM0JD9kWVDH9DQp5Y6td16924V3MwZHei8P3cTeuFhXpzpk0K+iWraBZz8wF61QkFs9fZeAQNX0q8SG0+TFm2w== dependencies: ast-types "^0.14.1" recast "^0.20.3" @@ -8764,28 +8777,29 @@ resolved "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71" integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg== -"@typescript-eslint/eslint-plugin@^v4.30.0": - version "4.30.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.30.0.tgz#4a0c1ae96b953f4e67435e20248d812bfa55e4fb" - integrity sha512-NgAnqk55RQ/SD+tZFD9aPwNSeHmDHHe5rtUyhIq0ZeCWZEvo4DK9rYz7v9HDuQZFvn320Ot+AikaCKMFKLlD0g== +"@typescript-eslint/eslint-plugin@^v4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== dependencies: - "@typescript-eslint/experimental-utils" "4.30.0" - "@typescript-eslint/scope-manager" "4.30.0" + "@typescript-eslint/experimental-utils" "4.33.0" + "@typescript-eslint/scope-manager" "4.33.0" debug "^4.3.1" functional-red-black-tree "^1.0.1" + ignore "^5.1.8" regexpp "^3.1.0" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.30.0", "@typescript-eslint/experimental-utils@^4.0.1": - version "4.30.0" - resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.30.0.tgz#9e49704fef568432ae16fc0d6685c13d67db0fd5" - integrity sha512-K8RNIX9GnBsv5v4TjtwkKtqMSzYpjqAQg/oSphtxf3xxdt6T0owqnpojztjjTcatSteH3hLj3t/kklKx87NPqw== +"@typescript-eslint/experimental-utils@4.33.0", "@typescript-eslint/experimental-utils@^4.0.1": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.30.0" - "@typescript-eslint/types" "4.30.0" - "@typescript-eslint/typescript-estree" "4.30.0" + "@typescript-eslint/scope-manager" "4.33.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/typescript-estree" "4.33.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -8807,23 +8821,23 @@ "@typescript-eslint/types" "4.28.3" "@typescript-eslint/visitor-keys" "4.28.3" -"@typescript-eslint/scope-manager@4.30.0": - version "4.30.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.30.0.tgz#1a3ffbb385b1a06be85cd5165a22324f069a85ee" - integrity sha512-VJ/jAXovxNh7rIXCQbYhkyV2Y3Ac/0cVHP/FruTJSAUUm4Oacmn/nkN5zfWmWFEanN4ggP0vJSHOeajtHq3f8A== +"@typescript-eslint/scope-manager@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== dependencies: - "@typescript-eslint/types" "4.30.0" - "@typescript-eslint/visitor-keys" "4.30.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" "@typescript-eslint/types@4.28.3": version "4.28.3" resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.3.tgz#8fffd436a3bada422c2c1da56060a0566a9506c7" integrity sha512-kQFaEsQBQVtA9VGVyciyTbIg7S3WoKHNuOp/UF5RG40900KtGqfoiETWD/v0lzRXc+euVE9NXmfer9dLkUJrkA== -"@typescript-eslint/types@4.30.0": - version "4.30.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.30.0.tgz#fb9d9b0358426f18687fba82eb0b0f869780204f" - integrity sha512-YKldqbNU9K4WpTNwBqtAerQKLLW/X2A/j4yw92e3ZJYLx+BpKLeheyzoPfzIXHfM8BXfoleTdiYwpsvVPvHrDw== +"@typescript-eslint/types@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== "@typescript-eslint/typescript-estree@4.28.3": version "4.28.3" @@ -8838,13 +8852,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@4.30.0": - version "4.30.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.30.0.tgz#ae57833da72a753f4846cd3053758c771670c2ac" - integrity sha512-6WN7UFYvykr/U0Qgy4kz48iGPWILvYL34xXJxvDQeiRE018B7POspNRVtAZscWntEPZpFCx4hcz/XBT+erenfg== +"@typescript-eslint/typescript-estree@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== dependencies: - "@typescript-eslint/types" "4.30.0" - "@typescript-eslint/visitor-keys" "4.30.0" + "@typescript-eslint/types" "4.33.0" + "@typescript-eslint/visitor-keys" "4.33.0" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" @@ -8859,12 +8873,12 @@ "@typescript-eslint/types" "4.28.3" eslint-visitor-keys "^2.0.0" -"@typescript-eslint/visitor-keys@4.30.0": - version "4.30.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.30.0.tgz#a47c6272fc71b0c627d1691f68eaecf4ad71445e" - integrity sha512-pNaaxDt/Ol/+JZwzP7MqWc8PJQTUhZwoee/PVlQ+iYoYhagccvoHnC9e4l+C/krQYYkENxznhVSDwClIbZVxRw== +"@typescript-eslint/visitor-keys@4.33.0": + version "4.33.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== dependencies: - "@typescript-eslint/types" "4.30.0" + "@typescript-eslint/types" "4.33.0" eslint-visitor-keys "^2.0.0" "@webassemblyjs/ast@1.11.1": @@ -14841,9 +14855,9 @@ express-prom-bundle@^6.3.6: url-value-parser "^2.0.0" express-promise-router@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/express-promise-router/-/express-promise-router-4.1.0.tgz#79160e145c27610ba411bceb0552a36f11dbab4f" - integrity sha512-nvg0X1Rj8oajPPC+fG3t4e740aNmQZRZY6dRLbiiM56Dvd8213RJ4kaxhZVTdQLut+l4DZdfeJkyx2VENPMBdw== + version "4.1.1" + resolved "https://registry.npmjs.org/express-promise-router/-/express-promise-router-4.1.1.tgz#8fac102060b9bcc868f84d34fbb12fd8fa494291" + integrity sha512-Lkvcy/ZGrBhzkl3y7uYBHLMtLI4D6XQ2kiFg9dq7fbktBch5gjqJ0+KovX0cvCAvTJw92raWunRLM/OM+5l4fA== dependencies: is-promise "^4.0.0" lodash.flattendeep "^4.0.0" @@ -17194,10 +17208,10 @@ ignore@^4.0.3, ignore@^4.0.6: resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4: - version "5.1.4" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" - integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== +ignore@^5.1.4, ignore@^5.1.8: + version "5.2.0" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== immer@8.0.1: version "8.0.1"