diff --git a/.changeset/afraid-teachers-cross.md b/.changeset/afraid-teachers-cross.md new file mode 100644 index 0000000000..8fc376441f --- /dev/null +++ b/.changeset/afraid-teachers-cross.md @@ -0,0 +1,29 @@ +--- +'@backstage/create-app': patch +--- + +Pass on plugin database management instance that is now required by the scaffolder plugin. + +To apply this change to an existing application, add the following to `src/plugins/scaffolder.ts`: + +```diff +export default async function createPlugin({ + logger, + config, ++ database, +}: PluginEnvironment) { + +// ...omitted... + + return await createRouter({ + preparers, + templaters, + publishers, + logger, + config, + dockerClient, + entityClient, ++ database, + }); +} +``` diff --git a/.changeset/catalog-import-export-api-snow-fight.md b/.changeset/catalog-import-export-api-snow-fight.md deleted file mode 100644 index dce9811f10..0000000000 --- a/.changeset/catalog-import-export-api-snow-fight.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Export _api_ (Client, API, ref) from the catalog import plugin. diff --git a/.changeset/chilled-toys-raise.md b/.changeset/chilled-toys-raise.md deleted file mode 100644 index 282d5492ec..0000000000 --- a/.changeset/chilled-toys-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Migrated to new composability API, exporting the plugin as `scaffolderPlugin`. The template list page (`/create`) is exported as the `TemplateIndexPage` extension, and the templating page itself is exported as `TemplatePage`. diff --git a/.changeset/chilly-dodos-drop.md b/.changeset/chilly-dodos-drop.md deleted file mode 100644 index 2af5255e70..0000000000 --- a/.changeset/chilly-dodos-drop.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/techdocs-common': patch -'@backstage/plugin-techdocs-backend': patch ---- - -1. Added option to use Azure Blob Storage as a choice to store the static generated files for TechDocs. diff --git a/.changeset/cost-insights-tidy-geese-play.md b/.changeset/cost-insights-tidy-geese-play.md new file mode 100644 index 0000000000..f8aa503ca6 --- /dev/null +++ b/.changeset/cost-insights-tidy-geese-play.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +Fix snooze quarter option diff --git a/.changeset/cost-insights-tricky-moles-grin.md b/.changeset/cost-insights-tricky-moles-grin.md deleted file mode 100644 index c35769e03c..0000000000 --- a/.changeset/cost-insights-tricky-moles-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': minor ---- - -add alert hooks diff --git a/.changeset/cost-insights-wise-moons-crash.md b/.changeset/cost-insights-wise-moons-crash.md deleted file mode 100644 index 1277911059..0000000000 --- a/.changeset/cost-insights-wise-moons-crash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-cost-insights': patch ---- - -Fixed date calculations incorrectly converting to UTC in some cases. This should be a transparent change. diff --git a/.changeset/curly-crabs-compete.md b/.changeset/curly-crabs-compete.md new file mode 100644 index 0000000000..552a41a9f1 --- /dev/null +++ b/.changeset/curly-crabs-compete.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-circleci': patch +--- + +Migrated to new composability API, exporting the plugin instance as `circleCIPlugin`, the entity page content as `EntityCircleCIContent`, and entity conditional as `isCircleCIAvailable`. diff --git a/.changeset/curly-ghosts-laugh.md b/.changeset/curly-ghosts-laugh.md deleted file mode 100644 index 8c55e93cfc..0000000000 --- a/.changeset/curly-ghosts-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Remove techdocs.requestUrl and techdocs.storageUrl from app-config.yaml diff --git a/.changeset/cyan-kiwis-suffer.md b/.changeset/cyan-kiwis-suffer.md deleted file mode 100644 index b59b0e9a32..0000000000 --- a/.changeset/cyan-kiwis-suffer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Update `create-plugin` template to use the new composability API, by switching to exporting a single routable extension component. diff --git a/.changeset/cyan-lies-flow.md b/.changeset/cyan-lies-flow.md new file mode 100644 index 0000000000..e7da9fab0a --- /dev/null +++ b/.changeset/cyan-lies-flow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search': minor +--- + +Migrated to new composability API, exporting the plugin instance as `searchPlugin`, and page as `SearchPage`. Due to the old router component also being called `SearchPage`, this is a breaking change. The old page component is now exported as `Router`, which can be used to maintain the old behavior. diff --git a/.changeset/cyan-lions-float.md b/.changeset/cyan-lions-float.md deleted file mode 100644 index f5fa064b71..0000000000 --- a/.changeset/cyan-lions-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-graphiql': patch ---- - -Finalized composability API migration, now exporting the plugin as `graphiqlPlugin`. diff --git a/.changeset/dirty-carrots-invent.md b/.changeset/dirty-carrots-invent.md deleted file mode 100644 index ceb4e4d2bb..0000000000 --- a/.changeset/dirty-carrots-invent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core': patch ---- - -Add className to the SidebarItem diff --git a/.changeset/dry-kings-hear.md b/.changeset/dry-kings-hear.md deleted file mode 100644 index c877785329..0000000000 --- a/.changeset/dry-kings-hear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Fix gitlab handling of paths with spaces diff --git a/.changeset/early-hotels-mate.md b/.changeset/early-hotels-mate.md new file mode 100644 index 0000000000..2cda0344bf --- /dev/null +++ b/.changeset/early-hotels-mate.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +use child logger, if provided, to log single location refresh diff --git a/.changeset/eight-carrots-talk.md b/.changeset/eight-carrots-talk.md deleted file mode 100644 index 01e38b845d..0000000000 --- a/.changeset/eight-carrots-talk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core': patch ---- - -Update `WarningPanel` component to use accordion-style expansion diff --git a/.changeset/empty-hairs-fetch.md b/.changeset/empty-hairs-fetch.md deleted file mode 100644 index aedeb8a853..0000000000 --- a/.changeset/empty-hairs-fetch.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-org': patch ---- - -Display owner and system as entity page links in the tables of the `api-docs` -plugin. - -Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to -`@backstage/plugin-catalog-react` and export it from there to use it by other -plugins. diff --git a/.changeset/fair-kids-laugh.md b/.changeset/fair-kids-laugh.md deleted file mode 100644 index d478508ed9..0000000000 --- a/.changeset/fair-kids-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/theme': patch ---- - -Updates warning text color to align to updated `WarningPanel` styling diff --git a/.changeset/fast-dots-camp.md b/.changeset/fast-dots-camp.md deleted file mode 100644 index 7a1f510f47..0000000000 --- a/.changeset/fast-dots-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Migrated to new composability API, exporting the plugin instance as `catalogImportPlugin`, and the page as `CatalogImportPage`. diff --git a/.changeset/fifty-dolls-doubt.md b/.changeset/fifty-dolls-doubt.md deleted file mode 100644 index 1abd7a16b9..0000000000 --- a/.changeset/fifty-dolls-doubt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-lighthouse': patch ---- - -Migrate to new composability API, exporting the plugin instance as `lighthousePlugin`, the top-level page as `LighthousePage`, the entity card as `EntityLastLighthouseAuditCard`, and the entity content as `EntityLighthouseContent`. diff --git a/.changeset/fluffy-hats-hug.md b/.changeset/fluffy-hats-hug.md new file mode 100644 index 0000000000..b3d06337fd --- /dev/null +++ b/.changeset/fluffy-hats-hug.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Don't respond to a request twice if an entity has not been found. diff --git a/.changeset/fluffy-nails-sort.md b/.changeset/fluffy-nails-sort.md deleted file mode 100644 index 0aa87b532f..0000000000 --- a/.changeset/fluffy-nails-sort.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Updated the `rootLogger` in `@backstage/backend-common` to support custom logging options. This is useful when you want to make some changes without re-implementing the entire logger and calling `setRootLogger` or `logger.configure`. For example you can add additional `defaultMeta` tags to each log entry. The following changes are included: - -- Added `createRootLogger` which accepts winston `LoggerOptions`. These options allow overriding the default keys. - -Example Usage: - -```ts -// Create the logger -const logger = createRootLogger({ - defaultMeta: { appName: 'backstage', appEnv: 'prod' }, -}); - -// Add a custom logger transport -logger.add(new MyCustomTransport()); - -const config = await loadBackendConfig({ - argv: process.argv, - logger: getRootLogger(), // already set to new logger instance -}); -``` diff --git a/.changeset/four-paws-pull.md b/.changeset/four-paws-pull.md deleted file mode 100644 index 183b3dc5d7..0000000000 --- a/.changeset/four-paws-pull.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Make use of the `resolveUrl` facility of the `integration` package. - -Also rename the `LocationRefProcessor` to `LocationEntityProcessor`, to match the file name. This constitutes an interface change since the class is exported, but it is unlikely to be consumed outside of the package since it sits comfortably with the other default processors inside the catalog builder. diff --git a/.changeset/four-rings-push.md b/.changeset/four-rings-push.md new file mode 100644 index 0000000000..500dd0e812 --- /dev/null +++ b/.changeset/four-rings-push.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cloudbuild': patch +--- + +Migrate to new composability API, exporting the plugin instance as `cloudbuildPlugin`, the entity content as `EntityCloudbuildContent`, the entity conditional as `isCloudbuildAvailable`, and entity cards as `EntityLatestCloudbuildRunCard` and `EntityLatestCloudbuildsForBranchCard`. diff --git a/.changeset/four-shrimps-flash.md b/.changeset/four-shrimps-flash.md deleted file mode 100644 index fb155bafd7..0000000000 --- a/.changeset/four-shrimps-flash.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/core': patch -'@backstage/plugin-techdocs': patch ---- - -Add `href` in addition to `onClick` to `ItemCard`. Ensure that the height of a -`ItemCard` with and without tags is equal. diff --git a/.changeset/fresh-eels-compare.md b/.changeset/fresh-eels-compare.md deleted file mode 100644 index 5d17556f7f..0000000000 --- a/.changeset/fresh-eels-compare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings': patch ---- - -Migrate to new composability API, exporting the plugin as `userSettingsPlugin` and the page as `UserSettingsPage`. diff --git a/.changeset/funny-students-shout.md b/.changeset/funny-students-shout.md new file mode 100644 index 0000000000..97b273c687 --- /dev/null +++ b/.changeset/funny-students-shout.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-register-component': patch +--- + +Migrated to new composability API, exporting the plugin instance as `registerComponentPlugin`, and page as `RegisterComponentPage`. diff --git a/.changeset/fuzzy-pumpkins-tie.md b/.changeset/fuzzy-pumpkins-tie.md deleted file mode 100644 index 1e87972ce1..0000000000 --- a/.changeset/fuzzy-pumpkins-tie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-model': patch ---- - -Adds a new optional `links` metadata field to the Entity class within the `catalog-model` package (as discussed in [[RFC] Entity Links](https://github.com/backstage/backstage/issues/3787)). This PR adds support for the entity links only. Follow up PR's will introduce the UI component to display them. diff --git a/.changeset/gentle-scissors-compare.md b/.changeset/gentle-scissors-compare.md deleted file mode 100644 index bb615987b2..0000000000 --- a/.changeset/gentle-scissors-compare.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/techdocs-common': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-techdocs-backend': patch ---- - -`techdocs.requestUrl` and `techdocs.storageUrl` are now optional configs and the discovery API will be used to get the URL where techdocs plugin is hosted. diff --git a/.changeset/hot-rules-shout.md b/.changeset/hot-rules-shout.md deleted file mode 100644 index c88f4b01dc..0000000000 --- a/.changeset/hot-rules-shout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Add `children` option to `addPage`, which will be rendered as the children of the `Route`. diff --git a/.changeset/large-terms-invite.md b/.changeset/large-terms-invite.md new file mode 100644 index 0000000000..6653ac8e1e --- /dev/null +++ b/.changeset/large-terms-invite.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Introduced `v2` Scaffolder REST API, which uses an implementation that is database backed, making the scaffolder instances stateless. The `createRouter` function now requires a `PluginDatabaseManager` instance to be passed in, commonly available as `database` in the plugin environment in the backend. + +This API should be considered unstable until used by the scaffolder frontend. diff --git a/.changeset/late-crews-train.md b/.changeset/late-crews-train.md deleted file mode 100644 index 00f8f8b6ee..0000000000 --- a/.changeset/late-crews-train.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'example-app': patch -'@backstage/plugin-rollbar': patch ---- - -Migrated to new composability API, exporting the plugin instance as `rollbarPlugin`, the entity page content as `EntityRollbarContent`, and entity conditional as `isRollbarAvailable`. Updated the `EntityPage` for the `example-app` to include a composite `ErrorsSwitcher` component that works with both `Sentry` & `Rollbar`. Also removed the unused and undocumented `RollbarHome` related components. diff --git a/.changeset/little-cherries-hug.md b/.changeset/little-cherries-hug.md deleted file mode 100644 index 5fb42cbdad..0000000000 --- a/.changeset/little-cherries-hug.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Attempt to fix windows test errors in master diff --git a/.changeset/little-pets-cross.md b/.changeset/little-pets-cross.md deleted file mode 100644 index 0f4e2605cd..0000000000 --- a/.changeset/little-pets-cross.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-model': patch ---- - -Replace `yup` with `ajv`, for validation of catalog entities. diff --git a/.changeset/loud-walls-collect.md b/.changeset/loud-walls-collect.md deleted file mode 100644 index 78356eef38..0000000000 --- a/.changeset/loud-walls-collect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed module resolution of external libraries during backend development. Modules used to be resolved relative to the backend entrypoint, but are now resolved relative to each individual module. diff --git a/.changeset/lovely-panthers-peel.md b/.changeset/lovely-panthers-peel.md deleted file mode 100644 index 512f0ebd3f..0000000000 --- a/.changeset/lovely-panthers-peel.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/core': minor ---- - -Closes #3556 -The scroll bar of collapsed sidebar is now hidden without full screen. - -![image](https://user-images.githubusercontent.com/46953622/105390193-0bfd0080-5c19-11eb-8e86-2161bbe6e8d9.png) diff --git a/.changeset/metal-insects-compete.md b/.changeset/metal-insects-compete.md deleted file mode 100644 index ead779d6a9..0000000000 --- a/.changeset/metal-insects-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -Migrate to new composability API, exporting the plugin instance as `orgPlugin`, and the entity cards as `EntityGroupProfileCard`, `EntityMembersListCard`, `EntityOwnershipCard`, and `EntityUserProfileCard`. diff --git a/.changeset/metal-pans-leave.md b/.changeset/metal-pans-leave.md deleted file mode 100644 index 16d5478e43..0000000000 --- a/.changeset/metal-pans-leave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -Bump `config-loader` to `ajv` 7, to enable v7 feature use elsewhere diff --git a/.changeset/moody-apricots-warn.md b/.changeset/moody-apricots-warn.md deleted file mode 100644 index c4d9be0ba3..0000000000 --- a/.changeset/moody-apricots-warn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/dev-utils': patch ---- - -Added `path` option to `addPage` that can be used to set a specific path for the page rather than a generated one. Also omit sidebar item altogether if `title` option is not set. diff --git a/.changeset/moody-buckets-visit.md b/.changeset/moody-buckets-visit.md deleted file mode 100644 index 07a960620b..0000000000 --- a/.changeset/moody-buckets-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Properly forward errors that occur when looking up GitLab project IDs. diff --git a/.changeset/neat-brooms-allow.md b/.changeset/neat-brooms-allow.md deleted file mode 100644 index a4c69b0945..0000000000 --- a/.changeset/neat-brooms-allow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/config-loader': patch ---- - -Each piece of the configuration schema is now validated upfront, in order to produce more informative errors. diff --git a/.changeset/nice-bottles-battle.md b/.changeset/nice-bottles-battle.md deleted file mode 100644 index a688241caa..0000000000 --- a/.changeset/nice-bottles-battle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-app-backend': patch ---- - -Failures to load the frontend configuration schema now throws an error that includes more context and instructions for how to fix the issue. diff --git a/.changeset/ninety-houses-shout.md b/.changeset/ninety-houses-shout.md new file mode 100644 index 0000000000..845decc74c --- /dev/null +++ b/.changeset/ninety-houses-shout.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Migrated to new composability API, exporting the plugin instance as `techdocsPlugin`, the top-level page as `TechdocsPage`, and the entity content as `EntityTechdocsContent`. diff --git a/.changeset/ninety-keys-serve.md b/.changeset/ninety-keys-serve.md deleted file mode 100644 index d15884b1c4..0000000000 --- a/.changeset/ninety-keys-serve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core': patch ---- - -Add a `prop` union for `SignInPage` that allows it to be used for just a single provider, with inline errors, and optionally with automatic sign-in. diff --git a/.changeset/odd-buckets-compare.md b/.changeset/odd-buckets-compare.md new file mode 100644 index 0000000000..faf68fb4a0 --- /dev/null +++ b/.changeset/odd-buckets-compare.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Set explicit content-type in error handler responses. diff --git a/.changeset/old-tools-exist.md b/.changeset/old-tools-exist.md new file mode 100644 index 0000000000..a9365cb784 --- /dev/null +++ b/.changeset/old-tools-exist.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Slight refactoring in support of a future search implementation in `UrlReader`. Mostly moving code around. diff --git a/.changeset/orange-pets-whisper.md b/.changeset/orange-pets-whisper.md deleted file mode 100644 index e96c210e43..0000000000 --- a/.changeset/orange-pets-whisper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Add check for outdated/duplicate packages to yarn start diff --git a/.changeset/perfect-ladybugs-listen.md b/.changeset/perfect-ladybugs-listen.md new file mode 100644 index 0000000000..2f9e65c1d9 --- /dev/null +++ b/.changeset/perfect-ladybugs-listen.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-pagerduty': patch +--- + +Migrated to new composability API, exporting the plugin instance as `pagerDutyPlugin`, entity card as `EntityPagerDutyCard`, and entity conditional as `isPagerDutyAvailable`. diff --git a/.changeset/plenty-steaks-confess.md b/.changeset/plenty-steaks-confess.md deleted file mode 100644 index f9ffe0f539..0000000000 --- a/.changeset/plenty-steaks-confess.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-gcp-projects': patch ---- - -Migrate to new composability API, exporting the plugin as `gcpProjectsPlugin` and page as `GcpProjectsPage`. diff --git a/.changeset/poor-ligers-flow.md b/.changeset/poor-ligers-flow.md deleted file mode 100644 index 1c3a8a742b..0000000000 --- a/.changeset/poor-ligers-flow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Throw `NotAllowedError` when registering locations with entities of disallowed kinds diff --git a/.changeset/poor-sheep-give.md b/.changeset/poor-sheep-give.md new file mode 100644 index 0000000000..4c52594b35 --- /dev/null +++ b/.changeset/poor-sheep-give.md @@ -0,0 +1,5 @@ +--- +'@backstage/test-utils': patch +--- + +Added `mountedRoutes` option to `wrapInTestApp`, allowing routes to be associated to concrete paths to make `useRouteRef` usable in tested components. diff --git a/.changeset/popular-cars-eat.md b/.changeset/popular-cars-eat.md new file mode 100644 index 0000000000..6d3bcdfab2 --- /dev/null +++ b/.changeset/popular-cars-eat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-jenkins': patch +--- + +Migrate to new composability API, exporting the plugin instance as `jenkinsPlugin`, the entity content as `EntityJenkinsContent`, the entity conditional as `isJenkinsAvailable`, and the entity card as `EntityLatestJenkinsRunCard`. diff --git a/.changeset/pretty-melons-prove.md b/.changeset/pretty-melons-prove.md deleted file mode 100644 index 7048757e5a..0000000000 --- a/.changeset/pretty-melons-prove.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-fossa': minor ---- - -Port FOSSA plugin to new extension model. - -If you are using the FOSSA plugin adjust the plugin import from `plugin` to -`fossaPlugin` and replace `` with ``. diff --git a/.changeset/quick-apes-shop.md b/.changeset/quick-apes-shop.md deleted file mode 100644 index 4c87b9253d..0000000000 --- a/.changeset/quick-apes-shop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Migrate to new composability API, exporting the plugin as `apiDocsPlugin`, index page as `ApiExplorerPage`, and entity page cards as `EntityApiDefinitionCard`, `EntityConsumedApisCard`, `EntityConsumingComponentsCard`, `EntityProvidedApisCard`, and `EntityProvidingComponentsCard`. diff --git a/.changeset/selfish-kids-know.md b/.changeset/selfish-kids-know.md deleted file mode 100644 index f434559135..0000000000 --- a/.changeset/selfish-kids-know.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Finalize migration to new composability API, with the plugin instance now exported `catalogPlugin`. diff --git a/.changeset/selfish-years-pump.md b/.changeset/selfish-years-pump.md new file mode 100644 index 0000000000..e5cc5f3bc3 --- /dev/null +++ b/.changeset/selfish-years-pump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-github-actions': patch +--- + +Migrate to new composability API, exporting the plugin instance as `githubActionsPlugin`, the entity content as `EntityGithubActionsContent`, entity conditional as `isGithubActionsAvailable`, and entity cards as `EntityLatestGithubActionRunCard`, `EntityLatestGithubActionsForBranchCard`, and `EntityRecentGithubActionsRunsCard`. diff --git a/.changeset/shaggy-dingos-suffer.md b/.changeset/shaggy-dingos-suffer.md deleted file mode 100644 index c1e200b701..0000000000 --- a/.changeset/shaggy-dingos-suffer.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-tech-radar': patch ---- - -Fix mapping RadarEntry and Entry for moved and url attributes -Fix clicking of links in the radar legend diff --git a/.changeset/shiny-falcons-marry.md b/.changeset/shiny-falcons-marry.md new file mode 100644 index 0000000000..4dda68d693 --- /dev/null +++ b/.changeset/shiny-falcons-marry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-newrelic': patch +--- + +Migrate to new composability API, exporting the plugin instance as `newRelicPlugin`, and the root page as `NewRelicPage`. diff --git a/.changeset/shiny-rabbits-unite.md b/.changeset/shiny-rabbits-unite.md deleted file mode 100644 index dca9ee0dd9..0000000000 --- a/.changeset/shiny-rabbits-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core': patch ---- - -Fix check that determines whether popup was closed or the messaging was misconfigured. diff --git a/.changeset/shy-maps-guess.md b/.changeset/shy-maps-guess.md new file mode 100644 index 0000000000..2a50d3d461 --- /dev/null +++ b/.changeset/shy-maps-guess.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes': patch +--- + +Migrate to new composability API, exporting the plugin instance as `kubernetesPlugin` and entity content as `EntityKubernetesContent`. diff --git a/.changeset/silent-readers-worry.md b/.changeset/silent-readers-worry.md deleted file mode 100644 index 866485ecc0..0000000000 --- a/.changeset/silent-readers-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-sonarqube': patch ---- - -Migrate to new composability API, exporting the plugin as `sonarQubePlugin` and card as `EntitySonarQubeCard`. diff --git a/.changeset/six-ravens-heal.md b/.changeset/six-ravens-heal.md deleted file mode 100644 index 960c482be9..0000000000 --- a/.changeset/six-ravens-heal.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-model': patch ---- - -Introduce json schema variants of the `yup` validation schemas diff --git a/.changeset/sixty-lemons-agree.md b/.changeset/sixty-lemons-agree.md new file mode 100644 index 0000000000..7fc438b433 --- /dev/null +++ b/.changeset/sixty-lemons-agree.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kafka': patch +--- + +Migrate to new composability API, exporting the plugin instance as `kafkaPlugin`, entity content as `EntityKafkaContent`, and entity conditional as `isKafkaAvailable`. diff --git a/.changeset/sour-gorillas-fail.md b/.changeset/sour-gorillas-fail.md deleted file mode 100644 index c6394ed76e..0000000000 --- a/.changeset/sour-gorillas-fail.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -# Repo visibility for GitLab and BitBucket repos - -**NOTE: This changes default repo visibility from `private` to `public` for GitLab and BitBucket** which -is consistent with the GitHub default. If you were counting on `private` visibility, you'll need to update -your scaffolder config to use `private`. - -This adds repo visibility feature parity with GitHub for GitLab and BitBucket. - -To configure the repo visibility, set scaffolder._type_.visibility as in this example: - -```yaml -scaffolder: - github: - visibility: private # 'public' or 'internal' or 'private' (default is 'public') - gitlab: - visibility: public # 'public' or 'internal' or 'private' (default is 'public') - bitbucket: - visibility: public # 'public' or 'private' (default is 'public') -``` diff --git a/.changeset/stale-zebras-warn.md b/.changeset/stale-zebras-warn.md deleted file mode 100644 index 33b53d3f75..0000000000 --- a/.changeset/stale-zebras-warn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-welcome': patch ---- - -Migrated to new composability API, exporting the plugin as `welcomePlugin` and the page as `WelcomePage`. diff --git a/.changeset/strange-cobras-unite.md b/.changeset/strange-cobras-unite.md new file mode 100644 index 0000000000..d53a324dab --- /dev/null +++ b/.changeset/strange-cobras-unite.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Refactored route response handling to use more explicit types and throw errors. diff --git a/.changeset/tame-points-search.md b/.changeset/tame-points-search.md deleted file mode 100644 index 7fffafc1cf..0000000000 --- a/.changeset/tame-points-search.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/integration': patch ---- - -Add a `resolveUrl` method to integrations, that works like the two-argument URL -constructor. The reason for using this is that Azure have their paths in a -query parameter, rather than the pathname of the URL. - -The implementation is optional (when not present, the URL constructor is used), -so this does not imply a breaking change. diff --git a/.changeset/techdocs-chilly-steaks-brush.md b/.changeset/techdocs-chilly-steaks-brush.md deleted file mode 100644 index 7fd4763c63..0000000000 --- a/.changeset/techdocs-chilly-steaks-brush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/techdocs-common': patch ---- - -dir preparer will use URL Reader in its implementation. diff --git a/.changeset/techdocs-green-rabbits-burn.md b/.changeset/techdocs-green-rabbits-burn.md new file mode 100644 index 0000000000..5af68c2000 --- /dev/null +++ b/.changeset/techdocs-green-rabbits-burn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Enhance API calls to support trapping 500 errors from techdocs-backend diff --git a/.changeset/thirty-cobras-tickle.md b/.changeset/thirty-cobras-tickle.md deleted file mode 100644 index cf43318658..0000000000 --- a/.changeset/thirty-cobras-tickle.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@backstage/core': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-explore': patch ---- - -Introduce `TabbedLayout` for creating tabs that are routed. - -```typescript - - -
This is rendered under /example/anything-here route
-
-
-``` diff --git a/.changeset/tidy-news-perform.md b/.changeset/tidy-news-perform.md deleted file mode 100644 index 055f051da7..0000000000 --- a/.changeset/tidy-news-perform.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings': patch ---- - -Keep the Pin Sidebar setting visible on small screens. diff --git a/.changeset/tricky-dancers-rush.md b/.changeset/tricky-dancers-rush.md new file mode 100644 index 0000000000..301b23d98e --- /dev/null +++ b/.changeset/tricky-dancers-rush.md @@ -0,0 +1,5 @@ +--- +'@backstage/core': patch +--- + +Fixed type inference of `createRouteRef`. diff --git a/.changeset/two-dogs-search.md b/.changeset/two-dogs-search.md new file mode 100644 index 0000000000..5f673c0cfb --- /dev/null +++ b/.changeset/two-dogs-search.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-gitops-profiles': patch +--- + +Migrated to new composability API, exporting the plugin instance as `gitopsProfilesPlugin` and pages as `GitopsProfilesClusterListPage`, `GitopsProfilesClusterPage`, and `GitopsProfilesCreatePage`. diff --git a/.changeset/two-foxes-exercise.md b/.changeset/two-foxes-exercise.md deleted file mode 100644 index 953eb83138..0000000000 --- a/.changeset/two-foxes-exercise.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-explore': patch ---- - -Rework the explore plugin to allow the user to explore things in the ecosystem, -including tools and domains. diff --git a/.changeset/wet-suits-live.md b/.changeset/wet-suits-live.md deleted file mode 100644 index 27b8df8a84..0000000000 --- a/.changeset/wet-suits-live.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch -'@backstage/plugin-catalog-import': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-org': patch -'@backstage/plugin-register-component': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-techdocs': patch -'@backstage/dev-utils': patch ---- - -Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. diff --git a/.changeset/wicked-beds-buy.md b/.changeset/wicked-beds-buy.md deleted file mode 100644 index ddcf4f880e..0000000000 --- a/.changeset/wicked-beds-buy.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -The scaffolder is updated to generate a unique workspace directory inside the temp folder. This directory is cleaned up by the job processor after each run. - -The prepare/template/publish steps have been refactored to operate on known directories, `template/` and `result/`, inside the temporary workspace path. - -Updated preparers to accept the template url instead of the entire template. This is done primarily to allow for backwards compatibility between v1 and v2 scaffolder templates. - -Fixes broken GitHub actions templating in the Create React App template. - -#### For those with **custom** preparers, templates, or publishers - -The preparer interface has changed, the prepare method now only takes a single argument, and doesn't return anything. As part of this change the preparers were refactored to accept a URL pointing to the target directory, rather than computing that from the template entity. - -The `workingDirectory` option was also removed, and replaced with a `workspacePath` option. The difference between the two is that `workingDirectory` was a place for the preparer to create temporary directories, while the `workspacePath` is the specific folder were the entire templating process for a single template job takes place. Instead of returning a path to the folder were the prepared contents were placed, the contents are put at the `/template` path. - -```diff -type PreparerOptions = { -- workingDirectory?: string; -+ /** -+ * Full URL to the directory containg template data -+ */ -+ url: string; -+ /** -+ * The workspace path that will eventually be the the root of the new repo -+ */ -+ workspacePath: string; - logger: Logger; -}; - --prepare(template: TemplateEntityV1alpha1, opts?: PreparerOptions): Promise -+prepare(opts: PreparerOptions): Promise; -``` - -Instead of returning a path to the folder were the templaters contents were placed, the contents are put at the `/result` path. All templaters now also expect the source template to be present in the `template` directory within the `workspacePath`. - -```diff -export type TemplaterRunOptions = { -- directory: string; -+ workspacePath: string; - values: TemplaterValues; - logStream?: Writable; - dockerClient: Docker; -}; - --public async run(options: TemplaterRunOptions): Promise -+public async run(options: TemplaterRunOptions): Promise -``` - -Just like the preparer and templaters, the publishers have also switched to using `workspacePath`. The root of the new repo is expected to be located at `/result`. - -```diff -export type PublisherOptions = { - values: TemplaterValues; -- directory: string; -+ workspacePath: string; - logger: Logger; -}; -``` diff --git a/.changeset/wicked-boxes-taste.md b/.changeset/wicked-boxes-taste.md deleted file mode 100644 index 3eef04825c..0000000000 --- a/.changeset/wicked-boxes-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration': major ---- - -#4322 Bitbucket own hosted v5.11.1 branchUrl fix and enabled error tracing… #4347 diff --git a/.changeset/wild-cows-exercise.md b/.changeset/wild-cows-exercise.md deleted file mode 100644 index cbc347888f..0000000000 --- a/.changeset/wild-cows-exercise.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog': minor -'@backstage/create-app': minor ---- - -`@backstage/plugin-catalog` stopped exporting hooks and helpers for other -plugins. They are migrated to `@backstage/plugin-catalog-react`. -Change both your dependencies and imports to the new package. diff --git a/.changeset/wise-lies-listen.md b/.changeset/wise-lies-listen.md deleted file mode 100644 index 53f1edea02..0000000000 --- a/.changeset/wise-lies-listen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-model': patch ---- - -Implement matchEntityWithRef for client side filtering of entities by ref matching diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 62be0a6cea..0fe1642394 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -3,6 +3,7 @@ name: E2E Test Linux on: pull_request: paths-ignore: + - '.changeset/**' - 'contrib/**' - 'docs/**' - 'microsite/**' diff --git a/docs/features/techdocs/creating-and-publishing.md b/docs/features/techdocs/creating-and-publishing.md index c15dc1fe69..b9340330a8 100644 --- a/docs/features/techdocs/creating-and-publishing.md +++ b/docs/features/techdocs/creating-and-publishing.md @@ -80,6 +80,10 @@ Create a `/docs` folder in the root of the project with at least an `index.md` file. _(If you add more markdown files, make sure to update the nav in the mkdocs.yml file to get a proper navigation for your documentation.)_ +> Note - Although `docs` is a popular directory name for storing documentation, +> it can be renamed to something else and can be configured by `mkdocs.yml`. See +> https://www.mkdocs.org/user-guide/configuration/#docs_dir + The `docs/index.md` can for example have the following content: ```md diff --git a/docs/getting-started/deployment-other.md b/docs/getting-started/deployment-other.md index 418a6b3dd3..e92b54d08b 100644 --- a/docs/getting-started/deployment-other.md +++ b/docs/getting-started/deployment-other.md @@ -90,7 +90,7 @@ $ docker build -t example-deployment . To run the image locally you can run: ```sh -$ docker run -p -it 7000:7000 example-deployment +$ docker run -it -p 7000:7000 example-deployment ``` You should then start to get logs in your terminal, and then you can open your diff --git a/package.json b/package.json index fd130fcbbd..ad0ce2cd57 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ }, "resolutions": { "**/@roadiehq/**/@backstage/core": "*", + "**/@roadiehq/**/@backstage/plugin-catalog": "*", "**/@roadiehq/**/@backstage/catalog-model": "*" }, "version": "1.0.0", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index d39f705546..fcd9b795a4 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,81 @@ # example-app +## 0.2.14 + +### Patch Changes + +- 9d6ef14bc: Migrated to new composability API, exporting the plugin instance as `rollbarPlugin`, the entity page content as `EntityRollbarContent`, and entity conditional as `isRollbarAvailable`. Updated the `EntityPage` for the `example-app` to include a composite `ErrorsSwitcher` component that works with both `Sentry` & `Rollbar`. Also removed the unused and undocumented `RollbarHome` related components. +- Updated dependencies [ceef4dd89] +- Updated dependencies [720149854] +- Updated dependencies [19172f5a9] +- Updated dependencies [4c6a6dddd] +- Updated dependencies [398e1f83e] +- Updated dependencies [87b189d00] +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [b712841d6] +- Updated dependencies [a5628df40] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [bc5082a00] +- Updated dependencies [6e612ce25] +- Updated dependencies [e44925723] +- Updated dependencies [b37501a3d] +- Updated dependencies [9d6ef14bc] +- Updated dependencies [025e122c3] +- Updated dependencies [e9aab60c7] +- Updated dependencies [21e624ba9] +- Updated dependencies [0269f4fd9] +- Updated dependencies [19fe61c27] +- Updated dependencies [da9f53c60] +- Updated dependencies [a08c4b0b0] +- Updated dependencies [bc5082a00] +- Updated dependencies [bc5082a00] +- Updated dependencies [b37501a3d] +- Updated dependencies [90c8f20b9] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [8dfdec613] +- Updated dependencies [54c7d02f7] +- Updated dependencies [de98c32ed] +- Updated dependencies [806929fe2] +- Updated dependencies [019fe39a0] +- Updated dependencies [019fe39a0] +- Updated dependencies [11cb5ef94] + - @backstage/plugin-catalog-import@0.3.7 + - @backstage/plugin-scaffolder@0.4.2 + - @backstage/plugin-cost-insights@0.8.0 + - @backstage/cli@0.6.0 + - @backstage/plugin-graphiql@0.2.7 + - @backstage/core@0.6.0 + - @backstage/plugin-api-docs@0.4.4 + - @backstage/plugin-catalog@0.3.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/plugin-org@0.3.5 + - @backstage/theme@0.2.3 + - @backstage/plugin-lighthouse@0.2.9 + - @backstage/plugin-techdocs@0.5.5 + - @backstage/plugin-user-settings@0.2.5 + - @backstage/catalog-model@0.7.1 + - @backstage/plugin-rollbar@0.2.9 + - @backstage/plugin-gcp-projects@0.2.4 + - @backstage/plugin-tech-radar@0.3.4 + - @backstage/plugin-welcome@0.2.5 + - @backstage/plugin-explore@0.2.4 + - @backstage/plugin-circleci@0.2.7 + - @backstage/plugin-cloudbuild@0.2.8 + - @backstage/plugin-github-actions@0.3.1 + - @backstage/plugin-jenkins@0.3.8 + - @backstage/plugin-kafka@0.2.1 + - @backstage/plugin-register-component@0.2.8 + - @backstage/plugin-search@0.2.7 + - @backstage/plugin-sentry@0.3.4 + - @backstage/plugin-gitops-profiles@0.2.4 + - @backstage/plugin-kubernetes@0.3.8 + - @backstage/plugin-newrelic@0.2.4 + - @backstage/plugin-pagerduty@0.2.7 + ## 0.2.13 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 949146833e..47be270e29 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,41 +1,41 @@ { "name": "example-app", - "version": "0.2.13", + "version": "0.2.14", "private": true, "bundled": true, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/cli": "^0.5.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-api-docs": "^0.4.3", - "@backstage/plugin-catalog": "^0.2.14", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/plugin-catalog-import": "^0.3.6", - "@backstage/plugin-circleci": "^0.2.6", - "@backstage/plugin-cloudbuild": "^0.2.7", - "@backstage/plugin-cost-insights": "^0.7.0", - "@backstage/plugin-explore": "^0.2.3", - "@backstage/plugin-gcp-projects": "^0.2.3", - "@backstage/plugin-github-actions": "^0.3.0", - "@backstage/plugin-gitops-profiles": "^0.2.3", - "@backstage/plugin-graphiql": "^0.2.6", - "@backstage/plugin-org": "^0.3.4", - "@backstage/plugin-jenkins": "^0.3.6", - "@backstage/plugin-kafka": "^0.2.0", - "@backstage/plugin-kubernetes": "^0.3.7", - "@backstage/plugin-lighthouse": "^0.2.8", - "@backstage/plugin-newrelic": "^0.2.3", - "@backstage/plugin-pagerduty": "0.2.6", - "@backstage/plugin-register-component": "^0.2.7", - "@backstage/plugin-rollbar": "^0.2.8", - "@backstage/plugin-scaffolder": "^0.4.1", - "@backstage/plugin-sentry": "^0.3.3", - "@backstage/plugin-search": "^0.2.6", - "@backstage/plugin-tech-radar": "^0.3.3", - "@backstage/plugin-techdocs": "^0.5.4", - "@backstage/plugin-user-settings": "^0.2.4", - "@backstage/plugin-welcome": "^0.2.4", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/cli": "^0.6.0", + "@backstage/core": "^0.6.0", + "@backstage/plugin-api-docs": "^0.4.4", + "@backstage/plugin-catalog": "^0.3.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/plugin-catalog-import": "^0.3.7", + "@backstage/plugin-circleci": "^0.2.7", + "@backstage/plugin-cloudbuild": "^0.2.8", + "@backstage/plugin-cost-insights": "^0.8.0", + "@backstage/plugin-explore": "^0.2.4", + "@backstage/plugin-gcp-projects": "^0.2.4", + "@backstage/plugin-github-actions": "^0.3.1", + "@backstage/plugin-gitops-profiles": "^0.2.4", + "@backstage/plugin-graphiql": "^0.2.7", + "@backstage/plugin-org": "^0.3.5", + "@backstage/plugin-jenkins": "^0.3.8", + "@backstage/plugin-kafka": "^0.2.1", + "@backstage/plugin-kubernetes": "^0.3.8", + "@backstage/plugin-lighthouse": "^0.2.9", + "@backstage/plugin-newrelic": "^0.2.4", + "@backstage/plugin-pagerduty": "0.2.7", + "@backstage/plugin-register-component": "^0.2.8", + "@backstage/plugin-rollbar": "^0.2.9", + "@backstage/plugin-scaffolder": "^0.4.2", + "@backstage/plugin-sentry": "^0.3.4", + "@backstage/plugin-search": "^0.2.7", + "@backstage/plugin-tech-radar": "^0.3.4", + "@backstage/plugin-techdocs": "^0.5.5", + "@backstage/plugin-user-settings": "^0.2.5", + "@backstage/plugin-welcome": "^0.2.5", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@octokit/rest": "^18.0.12", diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index 3cb57f9056..cc33a7e81b 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/backend-common +## 0.5.2 + +### Patch Changes + +- 2430ee7c2: Updated the `rootLogger` in `@backstage/backend-common` to support custom logging options. This is useful when you want to make some changes without re-implementing the entire logger and calling `setRootLogger` or `logger.configure`. For example you can add additional `defaultMeta` tags to each log entry. The following changes are included: + + - Added `createRootLogger` which accepts winston `LoggerOptions`. These options allow overriding the default keys. + + Example Usage: + + ```ts + // Create the logger + const logger = createRootLogger({ + defaultMeta: { appName: 'backstage', appEnv: 'prod' }, + }); + + // Add a custom logger transport + logger.add(new MyCustomTransport()); + + const config = await loadBackendConfig({ + argv: process.argv, + logger: getRootLogger(), // already set to new logger instance + }); + ``` + +- Updated dependencies [c4abcdb60] +- Updated dependencies [062df71db] +- Updated dependencies [064c513e1] +- Updated dependencies [e9aab60c7] +- Updated dependencies [3149bfe63] +- Updated dependencies [2e62aea6f] + - @backstage/integration@0.3.2 + - @backstage/config-loader@0.5.1 + ## 0.5.1 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 78077c2ce7..faec36dab4 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.5.1", + "version": "0.5.2", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -31,8 +31,9 @@ "dependencies": { "@backstage/cli-common": "^0.1.1", "@backstage/config": "^0.1.2", - "@backstage/config-loader": "^0.5.0", - "@backstage/integration": "^0.3.1", + "@backstage/config-loader": "^0.5.1", + "@backstage/integration": "^0.3.2", + "@octokit/rest": "^18.0.12", "@types/cors": "^2.8.6", "@types/express": "^4.17.6", "archiver": "^5.0.2", @@ -66,7 +67,7 @@ } }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@backstage/test-utils": "^0.1.5", "@types/archiver": "^5.1.0", "@types/compression": "^1.7.0", diff --git a/packages/backend-common/src/middleware/errorHandler.ts b/packages/backend-common/src/middleware/errorHandler.ts index a08849813d..2f3b904d38 100644 --- a/packages/backend-common/src/middleware/errorHandler.ts +++ b/packages/backend-common/src/middleware/errorHandler.ts @@ -63,10 +63,10 @@ export function errorHandler( return ( error: Error, _request: Request, - response: Response, + res: Response, next: NextFunction, ) => { - if (response.headersSent) { + if (res.headersSent) { // If the headers have already been sent, do not send the response again // as this will throw an error in the backend. next(error); @@ -80,7 +80,9 @@ export function errorHandler( logger.error(error); } - response.status(status).send(message); + res.status(status); + res.setHeader('content-type', 'text/plain'); + res.send(message); }; } diff --git a/packages/backend-common/src/reading/GithubUrlReader.ts b/packages/backend-common/src/reading/GithubUrlReader.ts index 4f1aa7c07b..99d641f2dd 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.ts @@ -15,11 +15,12 @@ */ import { - GitHubIntegrationConfig, - readGitHubIntegrationConfigs, getGitHubFileFetchUrl, GithubCredentialsProvider, + GitHubIntegrationConfig, + readGitHubIntegrationConfigs, } from '@backstage/integration'; +import { RestEndpointMethodTypes } from '@octokit/rest'; import fetch from 'cross-fetch'; import parseGitUrl from 'git-url-parse'; import { Readable } from 'stream'; @@ -98,74 +99,26 @@ export class GithubUrlReader implements UrlReader { url: string, options?: ReadTreeOptions, ): Promise { - const { ref, filepath, full_name } = parseGitUrl(url); - // Caveat: The ref will totally be incorrect if the branch name includes a / - // Thus, readTree can not work on url containing branch name that has a / - - const { headers } = await this.deps.credentialsProvider.getCredentials({ - url, - }); - - // Get GitHub API urls for the repository - const repoGitHubResponse = await fetch( - new URL(`${this.config.apiBaseUrl}/repos/${full_name}`).toString(), - { - headers, - }, - ); - if (!repoGitHubResponse.ok) { - const message = `Failed to read tree (repository) from ${url}, ${repoGitHubResponse.status} ${repoGitHubResponse.statusText}`; - if (repoGitHubResponse.status === 404) { - throw new NotFoundError(message); - } - throw new Error(message); - } - - const repoResponseJson = await repoGitHubResponse.json(); - - // ref is an empty string if no branch is set in provided url to readTree. - // Use GitHub API to get the default branch of the repository. - const branch = ref || repoResponseJson.default_branch; - const branchesApiUrl = repoResponseJson.branches_url; - const archiveApiUrl = repoResponseJson.archive_url; - - // Fetch the latest commit in the provided or default branch to compare against - // the provided sha. - const branchGitHubResponse = await fetch( - // branchesApiUrl looks like "https://api.github.com/repos/owner/repo/branches{/branch}" - branchesApiUrl.replace('{/branch}', `/${branch}`), - { - headers, - }, - ); - if (!branchGitHubResponse.ok) { - const message = `Failed to read tree (branch) from ${url}, ${branchGitHubResponse.status} ${branchGitHubResponse.statusText}`; - if (branchGitHubResponse.status === 404) { - throw new NotFoundError(message); - } - throw new Error(message); - } - const commitSha = (await branchGitHubResponse.json()).commit.sha; + const repoDetails = await this.getRepoDetails(url); + const commitSha = repoDetails.branch.commit.sha!; if (options?.etag && options.etag === commitSha) { throw new NotModifiedError(); } - const archive = await fetch( - // archiveApiUrl looks like "https://api.github.com/repos/owner/repo/{archive_format}{/ref}" - archiveApiUrl + const { headers } = await this.deps.credentialsProvider.getCredentials({ + url, + }); + + // archive_url looks like "https://api.github.com/repos/owner/repo/{archive_format}{/ref}" + const archive = await this.fetchResponse( + repoDetails.repo.archive_url .replace('{archive_format}', 'tarball') .replace('{/ref}', `/${commitSha}`), { headers }, ); - if (!archive.ok) { - const message = `Failed to read tree (archive) from ${url}, ${archive.status} ${archive.statusText}`; - if (archive.status === 404) { - throw new NotFoundError(message); - } - throw new Error(message); - } + const { filepath } = parseGitUrl(url); return await this.deps.treeResponseFactory.fromTarArchive({ // TODO(Rugvip): Underlying implementation of fetch will be node-fetch, we probably want // to stick to using that in exclusively backend code. @@ -180,4 +133,59 @@ export class GithubUrlReader implements UrlReader { const { host, token } = this.config; return `github{host=${host},authed=${Boolean(token)}}`; } + + private async getRepoDetails( + url: string, + ): Promise<{ + repo: RestEndpointMethodTypes['repos']['get']['response']['data']; + branch: RestEndpointMethodTypes['repos']['getBranch']['response']['data']; + }> { + const parsed = parseGitUrl(url); + const { ref, full_name } = parsed; + + // Caveat: The ref will totally be incorrect if the branch name includes a + // slash. Thus, some operations can not work on URLs containing branch + // names that have a slash in them. + + const { headers } = await this.deps.credentialsProvider.getCredentials({ + url, + }); + + const repo: RestEndpointMethodTypes['repos']['get']['response']['data'] = await this.fetchJson( + `${this.config.apiBaseUrl}/repos/${full_name}`, + { headers }, + ); + + // branches_url looks like "https://api.github.com/repos/owner/repo/branches{/branch}" + const branch: RestEndpointMethodTypes['repos']['getBranch']['response']['data'] = await this.fetchJson( + repo.branches_url.replace('{/branch}', `/${ref || repo.default_branch}`), + { headers }, + ); + + return { repo, branch }; + } + + private async fetchResponse( + url: string | URL, + init: RequestInit, + ): Promise { + const urlAsString = url.toString(); + + const response = await fetch(urlAsString, init); + + if (!response.ok) { + const message = `Request failed for ${urlAsString}, ${response.status} ${response.statusText}`; + if (response.status === 404) { + throw new NotFoundError(message); + } + throw new Error(message); + } + + return response; + } + + private async fetchJson(url: string | URL, init: RequestInit): Promise { + const response = await this.fetchResponse(url, init); + return await response.json(); + } } diff --git a/packages/backend-common/src/reading/integration.test.ts b/packages/backend-common/src/reading/integration.test.ts index 18f87636a5..16fdf3ff58 100644 --- a/packages/backend-common/src/reading/integration.test.ts +++ b/packages/backend-common/src/reading/integration.test.ts @@ -71,7 +71,11 @@ function withRetries(count: number, fn: () => Promise) { error = err; } } - throw error; + if (!error.message.match(/rate limit|Too Many Requests/)) { + throw error; + } else { + console.warn('Request was rate limited', error); + } }; } diff --git a/packages/backend-common/src/reading/tree/TarArchiveResponse.ts b/packages/backend-common/src/reading/tree/TarArchiveResponse.ts index 24bfa3f1a8..d22529293f 100644 --- a/packages/backend-common/src/reading/tree/TarArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/TarArchiveResponse.ts @@ -14,16 +14,16 @@ * limitations under the License. */ -import tar, { Parse, ParseStream, ReadEntry } from 'tar'; -import platformPath from 'path'; -import fs from 'fs-extra'; -import { Readable, pipeline as pipelineCb } from 'stream'; -import { promisify } from 'util'; import concatStream from 'concat-stream'; +import fs from 'fs-extra'; +import platformPath from 'path'; +import { pipeline as pipelineCb, Readable } from 'stream'; +import tar, { Parse, ParseStream, ReadEntry } from 'tar'; +import { promisify } from 'util'; import { ReadTreeResponse, - ReadTreeResponseFile, ReadTreeResponseDirOptions, + ReadTreeResponseFile, } from '../types'; // Tar types for `Parse` is not a proper constructor, but it should be diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts index 323f7b4778..2547c7b0e4 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts @@ -14,15 +14,15 @@ * limitations under the License. */ -import platformPath from 'path'; -import fs from 'fs-extra'; -import unzipper, { Entry } from 'unzipper'; import archiver from 'archiver'; +import fs from 'fs-extra'; +import platformPath from 'path'; import { Readable } from 'stream'; +import unzipper, { Entry } from 'unzipper'; import { ReadTreeResponse, - ReadTreeResponseFile, ReadTreeResponseDirOptions, + ReadTreeResponseFile, } from '../types'; // Matches a directory name + one `/` at the start of any string, diff --git a/packages/backend-common/src/reading/types.ts b/packages/backend-common/src/reading/types.ts index f9dfbe9aff..be788fc6e2 100644 --- a/packages/backend-common/src/reading/types.ts +++ b/packages/backend-common/src/reading/types.ts @@ -18,6 +18,32 @@ import { Logger } from 'winston'; import { Config } from '@backstage/config'; import { ReadTreeResponseFactory } from './tree'; +/** + * A generic interface for fetching plain data from URLs. + */ +export type UrlReader = { + read(url: string): Promise; + readTree(url: string, options?: ReadTreeOptions): Promise; +}; + +export type UrlReaderPredicateTuple = { + predicate: (url: URL) => boolean; + reader: UrlReader; +}; + +/** + * A factory function that can read config to construct zero or more + * UrlReaders along with a predicate for when it should be used. + */ +export type ReaderFactory = (options: { + config: Config; + logger: Logger; + treeResponseFactory: ReadTreeResponseFactory; +}) => UrlReaderPredicateTuple[]; + +/** + * An options object for readTree operations. + */ export type ReadTreeOptions = { /** * A filter that can be used to select which files should be included. @@ -47,39 +73,6 @@ export type ReadTreeOptions = { etag?: string; }; -/** - * A generic interface for fetching plain data from URLs. - */ -export type UrlReader = { - read(url: string): Promise; - readTree(url: string, options?: ReadTreeOptions): Promise; -}; - -export type UrlReaderPredicateTuple = { - predicate: (url: URL) => boolean; - reader: UrlReader; -}; - -/** - * A factory function that can read config to construct zero or more - * UrlReaders along with a predicate for when it should be used. - */ -export type ReaderFactory = (options: { - config: Config; - logger: Logger; - treeResponseFactory: ReadTreeResponseFactory; -}) => UrlReaderPredicateTuple[]; - -export type ReadTreeResponseFile = { - path: string; - content(): Promise; -}; - -export type ReadTreeResponseDirOptions = { - /** The directory to write files to. Defaults to the OS tmpdir or `backend.workingDirectory` if set in config */ - targetDir?: string; -}; - export type ReadTreeResponse = { /** * files() returns an array of all the files inside the tree and corresponding functions to read their content. @@ -97,3 +90,16 @@ export type ReadTreeResponse = { */ etag: string; }; + +export type ReadTreeResponseDirOptions = { + /** The directory to write files to. Defaults to the OS tmpdir or `backend.workingDirectory` if set in config */ + targetDir?: string; +}; + +/** + * Represents a single file in a readTree response. + */ +export type ReadTreeResponseFile = { + path: string; + content(): Promise; +}; diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 215e4e7296..f85c22784d 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,31 @@ # example-backend +## 0.2.14 + +### Patch Changes + +- Updated dependencies [c777df180] +- Updated dependencies [2430ee7c2] +- Updated dependencies [3149bfe63] +- Updated dependencies [6e612ce25] +- Updated dependencies [e44925723] +- Updated dependencies [9d6ef14bc] +- Updated dependencies [a26668913] +- Updated dependencies [025e122c3] +- Updated dependencies [e9aab60c7] +- Updated dependencies [24e47ef1e] +- Updated dependencies [7881f2117] +- Updated dependencies [529d16d27] +- Updated dependencies [cdea0baf1] +- Updated dependencies [11cb5ef94] + - @backstage/plugin-techdocs-backend@0.5.5 + - @backstage/backend-common@0.5.2 + - @backstage/plugin-catalog-backend@0.6.0 + - @backstage/catalog-model@0.7.1 + - example-app@0.2.14 + - @backstage/plugin-scaffolder-backend@0.6.0 + - @backstage/plugin-app-backend@0.3.6 + ## 0.2.13 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index aa00407952..544bb976fe 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.13", + "version": "0.2.14", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,24 +27,24 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", - "@backstage/plugin-app-backend": "^0.3.5", + "@backstage/plugin-app-backend": "^0.3.6", "@backstage/plugin-auth-backend": "^0.2.12", - "@backstage/plugin-catalog-backend": "^0.5.5", + "@backstage/plugin-catalog-backend": "^0.6.0", "@backstage/plugin-graphql-backend": "^0.1.5", "@backstage/plugin-kubernetes-backend": "^0.2.6", "@backstage/plugin-kafka-backend": "^0.2.0", "@backstage/plugin-proxy-backend": "^0.2.4", "@backstage/plugin-rollbar-backend": "^0.1.7", - "@backstage/plugin-scaffolder-backend": "^0.5.2", - "@backstage/plugin-techdocs-backend": "^0.5.4", + "@backstage/plugin-scaffolder-backend": "^0.6.0", + "@backstage/plugin-techdocs-backend": "^0.5.5", "@gitbeaker/node": "^28.0.2", "@octokit/rest": "^18.0.12", "azure-devops-node-api": "^10.1.1", "dockerode": "^3.2.1", - "example-app": "^0.2.13", + "example-app": "^0.2.14", "express": "^4.17.1", "express-promise-router": "^3.0.3", "knex": "^0.21.6", @@ -54,7 +54,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/dockerode": "^3.2.1", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5" diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index 4e2257a46c..723165ff82 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -30,6 +30,7 @@ import Docker from 'dockerode'; export default async function createPlugin({ logger, config, + database, }: PluginEnvironment) { const cookiecutterTemplater = new CookieCutter(); const craTemplater = new CreateReactAppTemplater(); @@ -54,5 +55,6 @@ export default async function createPlugin({ config, dockerClient, entityClient, + database, }); } diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index c1cbd6157f..00b05e37bf 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -29,12 +29,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", "cross-fetch": "^3.0.6" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/jest": "^26.0.7", "msw": "^0.21.2" }, diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index 6a081c3336..8d581dcb0c 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/catalog-model +## 0.7.1 + +### Patch Changes + +- 6e612ce25: Adds a new optional `links` metadata field to the Entity class within the `catalog-model` package (as discussed in [[RFC] Entity Links](https://github.com/backstage/backstage/issues/3787)). This PR adds support for the entity links only. Follow up PR's will introduce the UI component to display them. +- 025e122c3: Replace `yup` with `ajv`, for validation of catalog entities. +- 7881f2117: Introduce json schema variants of the `yup` validation schemas +- 11cb5ef94: Implement matchEntityWithRef for client side filtering of entities by ref matching + ## 0.7.0 ### Minor Changes diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index e81bc3a9b6..af74b78a08 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-model", - "version": "0.7.0", + "version": "0.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -39,7 +39,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/express": "^4.17.6", "@types/jest": "^26.0.7", "@types/lodash": "^4.14.151", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 29cce97ae9..c40f7605eb 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/cli +## 0.6.0 + +### Minor Changes + +- 19fe61c27: We have updated the default `eslint` rules in the `@backstage/cli` package. + + ```diff + -'@typescript-eslint/no-shadow': 'off', + -'@typescript-eslint/no-redeclare': 'off', + +'no-shadow': 'off', + +'no-redeclare': 'off', + +'@typescript-eslint/no-shadow': 'error', + +'@typescript-eslint/no-redeclare': 'error', + ``` + + The rules are documented [here](https://eslint.org/docs/rules/no-shadow) and [here](https://eslint.org/docs/rules/no-redeclare). + + This involved a large number of small changes to the code base. When you compile your own code using the CLI, you may also be + affected. We consider these rules important, and the primary recommendation is to try to update your code according to the + documentation above. But those that prefer to not enable the rules, or need time to perform the updates, may update their + local `.eslintrc.js` file(s) in the repo root and/or in individual plugins as they see fit: + + ```js + module.exports = { + // ... other declarations + rules: { + '@typescript-eslint/no-shadow': 'off', + '@typescript-eslint/no-redeclare': 'off', + }, + }; + ``` + + Because of the nature of this change, we're unable to provide a grace period for the update :( + +### Patch Changes + +- 398e1f83e: Update `create-plugin` template to use the new composability API, by switching to exporting a single routable extension component. +- e9aab60c7: Fixed module resolution of external libraries during backend development. Modules used to be resolved relative to the backend entrypoint, but are now resolved relative to each individual module. +- a08c4b0b0: Add check for outdated/duplicate packages to yarn start +- Updated dependencies [062df71db] +- Updated dependencies [e9aab60c7] + - @backstage/config-loader@0.5.1 + ## 0.5.0 ### Minor Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index ed373f6058..9aaeb00459 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.5.0", + "version": "0.6.0", "private": false, "publishConfig": { "access": "public" @@ -30,7 +30,7 @@ "dependencies": { "@backstage/cli-common": "^0.1.1", "@backstage/config": "^0.1.2", - "@backstage/config-loader": "^0.5.0", + "@backstage/config-loader": "^0.5.1", "@hot-loader/react-dom": "^16.13.0", "@lerna/package-graph": "^3.18.5", "@lerna/project": "^3.18.0", @@ -93,7 +93,7 @@ "rollup-plugin-esbuild": "2.6.x", "rollup-plugin-peer-deps-external": "^2.2.2", "rollup-plugin-postcss": "^3.1.1", - "rollup-plugin-typescript2": "^0.27.3", + "rollup-plugin-typescript2": "^0.29.0", "rollup-pluginutils": "^2.8.2", "semver": "^7.3.2", "start-server-webpack-plugin": "^2.2.5", @@ -113,12 +113,12 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-common": "^0.5.1", + "@backstage/backend-common": "^0.5.2", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/core": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", - "@backstage/theme": "^0.2.2", + "@backstage/theme": "^0.2.3", "@types/diff": "^4.0.2", "@types/express": "^4.17.6", "@types/fs-extra": "^9.0.1", diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 2079c85096..cbc6473286 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/config-loader +## 0.5.1 + +### Patch Changes + +- 062df71db: Bump `config-loader` to `ajv` 7, to enable v7 feature use elsewhere +- e9aab60c7: Each piece of the configuration schema is now validated upfront, in order to produce more informative errors. + ## 0.5.0 ### Minor Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 3387477231..0b024b2c84 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.5.0", + "version": "0.5.1", "private": false, "publishConfig": { "access": "public", diff --git a/packages/core-api/package.json b/packages/core-api/package.json index bbea58e846..927eca3490 100644 --- a/packages/core-api/package.json +++ b/packages/core-api/package.json @@ -30,7 +30,7 @@ }, "dependencies": { "@backstage/config": "^0.1.2", - "@backstage/theme": "^0.2.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@types/react": "^16.9", @@ -42,7 +42,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@backstage/test-utils": "^0.1.6", "@backstage/test-utils-core": "^0.1.1", "@testing-library/jest-dom": "^5.10.1", diff --git a/packages/core-api/src/routing/RouteRef.ts b/packages/core-api/src/routing/RouteRef.ts index 4c2da34098..0a3df49b58 100644 --- a/packages/core-api/src/routing/RouteRef.ts +++ b/packages/core-api/src/routing/RouteRef.ts @@ -14,7 +14,16 @@ * limitations under the License. */ -import { RouteRefConfig, RouteRef } from './types'; +import { RouteRef } from './types'; +import { IconComponent } from '../icons'; + +export type RouteRefConfig = { + params?: Array; + /** @deprecated Route refs no longer decide their own path */ + path?: string; + icon?: IconComponent; + title: string; +}; export class AbsoluteRouteRef { constructor(private readonly config: RouteRefConfig) {} @@ -38,9 +47,20 @@ export class AbsoluteRouteRef { } export function createRouteRef< - ParamKeys extends string, - Params extends { [param in string]: string } = { [name in ParamKeys]: string } ->(config: RouteRefConfig): RouteRef { + // Params is the type that we care about and the one to be embedded in the route ref. + // For example, given the params ['name', 'kind'], Params will be {name: string, kind: string} + Params extends { [param in ParamKey]: string }, + // ParamKey is here to make sure the Params type properly has its keys narrowed down + // to only the elements of params. Defaulting to never makes sure we end up with + // Param = {} if the params array is empty. + ParamKey extends string = never +>(config: { + params?: ParamKey[]; + /** @deprecated Route refs no longer decide their own path */ + path?: string; + icon?: IconComponent; + title: string; +}): RouteRef { return new AbsoluteRouteRef(config); } diff --git a/packages/core-api/src/routing/hooks.test.tsx b/packages/core-api/src/routing/hooks.test.tsx index 3dbeaf8e3e..84a8314807 100644 --- a/packages/core-api/src/routing/hooks.test.tsx +++ b/packages/core-api/src/routing/hooks.test.tsx @@ -39,8 +39,9 @@ import { createRouteRef, createExternalRouteRef, ExternalRouteRef, + RouteRefConfig, } from './RouteRef'; -import { RouteRef, RouteRefConfig } from './types'; +import { RouteRef } from './types'; const mockConfig = (extra?: Partial>) => ({ path: '/unused', diff --git a/packages/core-api/src/routing/index.ts b/packages/core-api/src/routing/index.ts index 9564b3b225..af71e0c3e9 100644 --- a/packages/core-api/src/routing/index.ts +++ b/packages/core-api/src/routing/index.ts @@ -16,11 +16,11 @@ export type { RouteRef, - RouteRefConfig, AbsoluteRouteRef, ConcreteRoute, MutableRouteRef, } from './types'; export { FlatRoutes } from './FlatRoutes'; export { createRouteRef } from './RouteRef'; +export type { RouteRefConfig } from './RouteRef'; export { useRouteRef } from './hooks'; diff --git a/packages/core-api/src/routing/types.ts b/packages/core-api/src/routing/types.ts index 99a20c31e9..5f9376c1d2 100644 --- a/packages/core-api/src/routing/types.ts +++ b/packages/core-api/src/routing/types.ts @@ -45,14 +45,6 @@ export type AbsoluteRouteRef = RouteRef<{}>; */ export type MutableRouteRef = RouteRef<{}>; -export type RouteRefConfig = { - params?: Array; - /** @deprecated Route refs no longer decide their own path */ - path?: string; - icon?: IconComponent; - title: string; -}; - // A duplicate of the react-router RouteObject, but with routeRef added export interface BackstageRouteObject { caseSensitive: boolean; diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 0fea08e539..60a6e43654 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/core +## 0.6.0 + +### Minor Changes + +- 21e624ba9: Closes #3556 + The scroll bar of collapsed sidebar is now hidden without full screen. + + ![image](https://user-images.githubusercontent.com/46953622/105390193-0bfd0080-5c19-11eb-8e86-2161bbe6e8d9.png) + +### Patch Changes + +- 12ece98cd: Add className to the SidebarItem +- d82246867: Update `WarningPanel` component to use accordion-style expansion +- 5fa3bdb55: Add `href` in addition to `onClick` to `ItemCard`. Ensure that the height of a + `ItemCard` with and without tags is equal. +- da9f53c60: Add a `prop` union for `SignInPage` that allows it to be used for just a single provider, with inline errors, and optionally with automatic sign-in. +- 32c95605f: Fix check that determines whether popup was closed or the messaging was misconfigured. +- 54c7d02f7: Introduce `TabbedLayout` for creating tabs that are routed. + + ```typescript + + +
This is rendered under /example/anything-here route
+
+
+ ``` + +- Updated dependencies [c810082ae] + - @backstage/theme@0.2.3 + ## 0.5.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index 49090e1362..41dbc8ef14 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core", "description": "Core API used by Backstage plugins and apps", - "version": "0.5.0", + "version": "0.6.0", "private": false, "publishConfig": { "access": "public", @@ -31,7 +31,7 @@ "dependencies": { "@backstage/config": "^0.1.2", "@backstage/core-api": "^0.2.8", - "@backstage/theme": "^0.2.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -66,7 +66,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 6c449b33b5..13b854972a 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,78 @@ # @backstage/create-app +## 0.3.8 + +### Patch Changes + +- 019fe39a0: **BREAKING CHANGE**: The `useEntity` hook has been moved from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. + To apply this change to an existing app, add `@backstage/plugin-catalog-react` to your dependencies in `packages/app/package.json`, and update + the import inside `packages/app/src/components/catalog/EntityPage.tsx` as well as any other places you were using `useEntity` or any other functions that were moved to `@backstage/plugin-catalog-react`. +- 436ca3f62: Remove techdocs.requestUrl and techdocs.storageUrl from app-config.yaml +- Updated dependencies [ceef4dd89] +- Updated dependencies [720149854] +- Updated dependencies [c777df180] +- Updated dependencies [398e1f83e] +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [b712841d6] +- Updated dependencies [a5628df40] +- Updated dependencies [2430ee7c2] +- Updated dependencies [3149bfe63] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [bc5082a00] +- Updated dependencies [6e612ce25] +- Updated dependencies [e44925723] +- Updated dependencies [b37501a3d] +- Updated dependencies [a26668913] +- Updated dependencies [025e122c3] +- Updated dependencies [e9aab60c7] +- Updated dependencies [21e624ba9] +- Updated dependencies [19fe61c27] +- Updated dependencies [e9aab60c7] +- Updated dependencies [da9f53c60] +- Updated dependencies [a08c4b0b0] +- Updated dependencies [24e47ef1e] +- Updated dependencies [bc5082a00] +- Updated dependencies [b37501a3d] +- Updated dependencies [90c8f20b9] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [529d16d27] +- Updated dependencies [54c7d02f7] +- Updated dependencies [de98c32ed] +- Updated dependencies [806929fe2] +- Updated dependencies [019fe39a0] +- Updated dependencies [cdea0baf1] +- Updated dependencies [019fe39a0] +- Updated dependencies [11cb5ef94] + - @backstage/plugin-catalog-import@0.3.7 + - @backstage/plugin-scaffolder@0.4.2 + - @backstage/plugin-techdocs-backend@0.5.5 + - @backstage/cli@0.6.0 + - @backstage/core@0.6.0 + - @backstage/plugin-api-docs@0.4.4 + - @backstage/plugin-catalog@0.3.0 + - @backstage/theme@0.2.3 + - @backstage/plugin-lighthouse@0.2.9 + - @backstage/backend-common@0.5.2 + - @backstage/plugin-catalog-backend@0.6.0 + - @backstage/plugin-techdocs@0.5.5 + - @backstage/plugin-user-settings@0.2.5 + - @backstage/catalog-model@0.7.1 + - @backstage/plugin-scaffolder-backend@0.6.0 + - @backstage/plugin-app-backend@0.3.6 + - @backstage/plugin-tech-radar@0.3.4 + - @backstage/plugin-explore@0.2.4 + - @backstage/plugin-circleci@0.2.7 + - @backstage/plugin-github-actions@0.3.1 + - @backstage/plugin-search@0.2.7 + - @backstage/test-utils@0.1.6 + - @backstage/plugin-auth-backend@0.2.12 + - @backstage/plugin-proxy-backend@0.2.4 + - @backstage/plugin-rollbar-backend@0.1.7 + ## 0.3.7 ### Patch Changes @@ -52,7 +125,7 @@ - @backstage/plugin-catalog@0.2.13 - @backstage/plugin-scaffolder-backend@0.5.1 -## 1.0.0 +## 0.3.6 ### Minor Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 475b61dde8..5f32a5d13d 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "Create app package for Backstage", - "version": "0.3.7", + "version": "0.3.8", "private": false, "publishConfig": { "access": "public" @@ -44,32 +44,32 @@ "ts-node": "^8.6.2" }, "peerDependencies": { - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", - "@backstage/cli": "^0.5.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/cli": "^0.6.0", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.5.0", - "@backstage/plugin-api-docs": "^0.4.3", - "@backstage/plugin-app-backend": "^0.3.5", + "@backstage/core": "^0.6.0", + "@backstage/plugin-api-docs": "^0.4.4", + "@backstage/plugin-app-backend": "^0.3.6", "@backstage/plugin-auth-backend": "^0.2.12", - "@backstage/plugin-catalog": "^0.2.14", - "@backstage/plugin-catalog-backend": "^0.5.5", - "@backstage/plugin-catalog-import": "^0.3.6", - "@backstage/plugin-circleci": "^0.2.6", - "@backstage/plugin-explore": "^0.2.3", - "@backstage/plugin-github-actions": "^0.3.0", - "@backstage/plugin-lighthouse": "^0.2.8", + "@backstage/plugin-catalog": "^0.3.0", + "@backstage/plugin-catalog-backend": "^0.6.0", + "@backstage/plugin-catalog-import": "^0.3.7", + "@backstage/plugin-circleci": "^0.2.7", + "@backstage/plugin-explore": "^0.2.4", + "@backstage/plugin-github-actions": "^0.3.1", + "@backstage/plugin-lighthouse": "^0.2.9", "@backstage/plugin-proxy-backend": "^0.2.4", "@backstage/plugin-rollbar-backend": "^0.1.7", - "@backstage/plugin-scaffolder": "^0.4.1", - "@backstage/plugin-search": "^0.2.6", - "@backstage/plugin-scaffolder-backend": "^0.5.2", - "@backstage/plugin-tech-radar": "^0.3.3", - "@backstage/plugin-techdocs": "^0.5.4", - "@backstage/plugin-techdocs-backend": "^0.5.4", - "@backstage/plugin-user-settings": "^0.2.4", + "@backstage/plugin-scaffolder": "^0.4.2", + "@backstage/plugin-search": "^0.2.7", + "@backstage/plugin-scaffolder-backend": "^0.6.0", + "@backstage/plugin-tech-radar": "^0.3.4", + "@backstage/plugin-techdocs": "^0.5.5", + "@backstage/plugin-techdocs-backend": "^0.5.5", + "@backstage/plugin-user-settings": "^0.2.5", "@backstage/test-utils": "^0.1.6", - "@backstage/theme": "^0.2.2" + "@backstage/theme": "^0.2.3" }, "nodemonConfig": { "watch": "./src", diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts index c8bd3e5012..d68f90ce08 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts @@ -14,6 +14,7 @@ import Docker from 'dockerode'; export default async function createPlugin({ logger, config, + database, }: PluginEnvironment) { const cookiecutterTemplater = new CookieCutter(); const craTemplater = new CreateReactAppTemplater(); @@ -38,5 +39,6 @@ export default async function createPlugin({ config, dockerClient, entityClient, + database, }); } diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index c6c740bf39..251a4db7ee 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/dev-utils +## 0.1.9 + +### Patch Changes + +- 720149854: Added `path` option to `addPage` that can be used to set a specific path for the page rather than a generated one. Also omit sidebar item altogether if `title` option is not set. +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.1.8 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index eff2d6e218..3a01306b46 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "0.1.8", + "version": "0.1.9", "private": false, "publishConfig": { "access": "public", @@ -29,11 +29,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/catalog-model": "^0.7.0", - "@backstage/plugin-catalog-react": "^0.0.1", + "@backstage/core": "^0.6.0", + "@backstage/catalog-model": "^0.7.1", + "@backstage/plugin-catalog-react": "^0.0.2", "@backstage/test-utils": "^0.1.5", - "@backstage/theme": "^0.2.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@testing-library/jest-dom": "^5.10.1", @@ -47,7 +47,7 @@ "react-router-dom": "6.0.0-beta.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/jest": "^26.0.7", "@types/node": "^12.0.0" }, diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 11eb164535..11839d733b 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/integration +## 0.3.2 + +### Patch Changes + +- c4abcdb60: Fix GitLab handling of paths with spaces +- 064c513e1: Properly forward errors that occur when looking up GitLab project IDs. +- 3149bfe63: Add a `resolveUrl` method to integrations, that works like the two-argument URL + constructor. The reason for using this is that Azure have their paths in a + query parameter, rather than the pathname of the URL. + + The implementation is optional (when not present, the URL constructor is used), + so this does not imply a breaking change. + +- 2e62aea6f: #4322 Bitbucket own hosted v5.11.1 branchUrl fix and enabled error tracing… #4347 + ## 0.3.1 ### Patch Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index 06a83ea883..f82472ca97 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "0.3.1", + "version": "0.3.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -37,7 +37,7 @@ "luxon": "^1.25.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@backstage/test-utils": "^0.1.5", "@types/jest": "^26.0.7", "@types/luxon": "^1.25.0", diff --git a/packages/integration/src/github/GithubCredentialsProvider.ts b/packages/integration/src/github/GithubCredentialsProvider.ts index a22c69909b..0bf217c824 100644 --- a/packages/integration/src/github/GithubCredentialsProvider.ts +++ b/packages/integration/src/github/GithubCredentialsProvider.ts @@ -53,7 +53,7 @@ class Cache { /** * This accept header is required when calling App APIs in GitHub Enterprise. - * It has no effect on calls to github.com and can probably be removed entierly + * It has no effect on calls to github.com and can probably be removed entirely * once GitHub Apps is out of preview. */ const HEADERS = { diff --git a/packages/techdocs-common/CHANGELOG.md b/packages/techdocs-common/CHANGELOG.md index 568df3157c..baf7a380a2 100644 --- a/packages/techdocs-common/CHANGELOG.md +++ b/packages/techdocs-common/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/techdocs-common +## 0.3.7 + +### Patch Changes + +- c777df180: 1. Added option to use Azure Blob Storage as a choice to store the static generated files for TechDocs. +- e44925723: `techdocs.requestUrl` and `techdocs.storageUrl` are now optional configs and the discovery API will be used to get the URL where techdocs plugin is hosted. +- f0320190d: dir preparer will use URL Reader in its implementation. +- Updated dependencies [c4abcdb60] +- Updated dependencies [2430ee7c2] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [064c513e1] +- Updated dependencies [7881f2117] +- Updated dependencies [3149bfe63] +- Updated dependencies [2e62aea6f] +- Updated dependencies [11cb5ef94] + - @backstage/integration@0.3.2 + - @backstage/backend-common@0.5.2 + - @backstage/catalog-model@0.7.1 + ## 0.3.6 ### Patch Changes diff --git a/packages/techdocs-common/package.json b/packages/techdocs-common/package.json index 2a065600a1..9b0f7fbf9f 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.3.6", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -39,10 +39,10 @@ "@aws-sdk/client-s3": "^3.1.0", "@azure/identity": "^1.2.2", "@azure/storage-blob": "^12.4.0", - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", - "@backstage/integration": "^0.3.1", + "@backstage/integration": "^0.3.2", "@google-cloud/storage": "^5.6.0", "@types/dockerode": "^3.2.1", "@types/express": "^4.17.6", @@ -61,7 +61,7 @@ }, "devDependencies": { "@aws-sdk/types": "3.1.0", - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/fs-extra": "^9.0.5", "@types/git-url-parse": "^9.0.0", "@types/js-yaml": "^3.12.5", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 10f0e89c14..5cea83fa03 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -31,7 +31,7 @@ "dependencies": { "@backstage/core-api": "^0.2.7", "@backstage/test-utils-core": "^0.1.1", - "@backstage/theme": "^0.2.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", @@ -45,7 +45,7 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/jest": "^26.0.7", "@types/node": "^12.0.0" }, diff --git a/packages/test-utils/src/testUtils/appWrappers.test.tsx b/packages/test-utils/src/testUtils/appWrappers.test.tsx index 29f8d97793..4899f07061 100644 --- a/packages/test-utils/src/testUtils/appWrappers.test.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.test.tsx @@ -21,9 +21,11 @@ import { Route, Routes } from 'react-router'; import { withLogCollector } from '@backstage/test-utils-core'; import { useApi, + useRouteRef, errorApiRef, ApiProvider, ApiRegistry, + createRouteRef, } from '@backstage/core-api'; import { MockErrorApi } from './apis'; @@ -113,4 +115,29 @@ describe('wrapInTestApp', () => { expect(rendered.getByText('foo')).toBeInTheDocument(); expect(mockErrorApi.getErrors()).toEqual([{ error: new Error('NOPE') }]); }); + + it('should allow route refs to be mounted on specific paths', async () => { + const aRouteRef = createRouteRef({ title: 'A' }); + const bRouteRef = createRouteRef({ title: 'B', params: ['name'] }); + + const MyComponent = () => { + const a = useRouteRef(aRouteRef); + const b = useRouteRef(bRouteRef); + return ( +
+
Link A: {a()}
+
Link B: {b({ name: 'x' })}
+
+ ); + }; + + const rendered = await renderInTestApp(, { + mountedRoutes: { + '/my-a-path': aRouteRef, + '/my-b-path/:name': bRouteRef, + }, + }); + expect(rendered.getByText('Link A: /my-a-path')).toBeInTheDocument(); + expect(rendered.getByText('Link B: /my-b-path/x')).toBeInTheDocument(); + }); }); diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index 1f6c7622b8..cc67a5b707 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -21,6 +21,9 @@ import { lightTheme } from '@backstage/theme'; import privateExports, { defaultSystemIcons, BootErrorPageProps, + RouteRef, + createPlugin, + createRoutableExtension, } from '@backstage/core-api'; import { RenderResult } from '@testing-library/react'; import { renderWithEffects } from '@backstage/test-utils-core'; @@ -44,6 +47,22 @@ type TestAppOptions = { * Initial route entries to pass along as `initialEntries` to the router. */ routeEntries?: string[]; + + /** + * An object of paths to mount route ref on, with the key being the path and the value + * being the RouteRef that the path will be bound to. This allows the route refs to be + * used by `useRouteRef` in the rendered elements. + * + * @example + * wrapInTestApp(, { + * mountedRoutes: { + * '/my-path': myRouteRef, + * } + * }) + * // ... + * const link = useRouteRef(myRouteRef) + */ + mountedRoutes?: { [path: string]: RouteRef }; }; /** @@ -90,12 +109,27 @@ export function wrapInTestApp( Wrapper = () => Component as React.ReactElement; } + const routePlugin = createPlugin({ id: 'mock-route-plugin' }); + const routeElements = Object.entries(options.mountedRoutes ?? {}).map( + ([path, routeRef]) => { + const PageComponent = () =>
Mounted at {path}
; + const Page = routePlugin.provide( + createRoutableExtension({ + component: async () => PageComponent, + mountPoint: routeRef, + }), + ); + return } />; + }, + ); + const AppProvider = app.getProvider(); const AppRouter = app.getRouter(); return ( + {routeElements} {/* The path of * here is needed to be set as a catch all, so it will render the wrapper element * and work with nested routes if they exist too */} } /> diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md index 13d95ab856..4ee58b2201 100644 --- a/packages/theme/CHANGELOG.md +++ b/packages/theme/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/theme +## 0.2.3 + +### Patch Changes + +- c810082ae: Updates warning text color to align to updated `WarningPanel` styling + ## 0.2.2 ### Patch Changes diff --git a/packages/theme/package.json b/packages/theme/package.json index 24edf81bb6..31abd9acff 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/theme", "description": "material-ui theme for use with Backstage.", - "version": "0.2.2", + "version": "0.2.3", "private": false, "publishConfig": { "access": "public", @@ -31,7 +31,7 @@ "@material-ui/core": "^4.11.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0" + "@backstage/cli": "^0.6.0" }, "files": [ "dist" diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 01e34d8e1d..4735beb150 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-api-docs +## 0.4.4 + +### Patch Changes + +- 7fc89bae2: Display owner and system as entity page links in the tables of the `api-docs` + plugin. + + Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to + `@backstage/plugin-catalog-react` and export it from there to use it by other + plugins. + +- bc5082a00: Migrate to new composability API, exporting the plugin as `apiDocsPlugin`, index page as `ApiExplorerPage`, and entity page cards as `EntityApiDefinitionCard`, `EntityConsumedApisCard`, `EntityConsumingComponentsCard`, `EntityProvidedApisCard`, and `EntityProvidingComponentsCard`. +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.4.3 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 4bd7bd1727..175b831ada 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.4.3", + "version": "0.4.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,10 +30,10 @@ }, "dependencies": { "@asyncapi/react-component": "^0.18.2", - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-icons/font": "^1.0.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -49,8 +49,8 @@ "swagger-ui-react": "^3.37.2" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 514e32633a..b57e0d25fb 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-app-backend +## 0.3.6 + +### Patch Changes + +- e9aab60c7: Failures to load the frontend configuration schema now throws an error that includes more context and instructions for how to fix the issue. +- Updated dependencies [2430ee7c2] +- Updated dependencies [062df71db] +- Updated dependencies [e9aab60c7] + - @backstage/backend-common@0.5.2 + - @backstage/config-loader@0.5.1 + ## 0.3.5 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index f397ea1475..cca36a51f8 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.3.5", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,8 +29,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", - "@backstage/config-loader": "^0.5.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/config-loader": "^0.5.1", "@backstage/config": "^0.1.2", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -40,7 +40,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/supertest": "^2.0.8", "msw": "^0.20.5", "supertest": "^4.0.2" diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index b2198165a5..e87c2b4a90 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", + "@backstage/backend-common": "^0.5.2", "@backstage/catalog-client": "^0.3.5", - "@backstage/catalog-model": "^0.7.0", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", "@types/express": "^4.17.6", "compression": "^1.7.4", @@ -65,7 +65,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 0e446bf0f7..eb256d2c08 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-backend +## 0.6.0 + +### Minor Changes + +- 3149bfe63: Make use of the `resolveUrl` facility of the `integration` package. + + Also rename the `LocationRefProcessor` to `LocationEntityProcessor`, to match the file name. This constitutes an interface change since the class is exported, but it is unlikely to be consumed outside of the package since it sits comfortably with the other default processors inside the catalog builder. + +### Patch Changes + +- 24e47ef1e: Throw `NotAllowedError` when registering locations with entities of disallowed kinds +- Updated dependencies [c4abcdb60] +- Updated dependencies [2430ee7c2] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [064c513e1] +- Updated dependencies [7881f2117] +- Updated dependencies [3149bfe63] +- Updated dependencies [2e62aea6f] +- Updated dependencies [11cb5ef94] + - @backstage/integration@0.3.2 + - @backstage/backend-common@0.5.2 + - @backstage/catalog-model@0.7.1 + ## 0.5.5 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index cc0a9e412a..bb76441f3f 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "0.5.5", + "version": "0.6.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "dependencies": { "@aws-sdk/client-organizations": "^3.2.0", "@azure/msal-node": "^1.0.0-beta.3", - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", - "@backstage/integration": "^0.3.1", + "@backstage/integration": "^0.3.2", "@octokit/graphql": "^4.5.8", "@types/express": "^4.17.6", "@types/ldapjs": "^1.0.9", @@ -58,7 +58,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@backstage/test-utils": "^0.1.6", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts b/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts index ba97232810..467c0eb2e8 100644 --- a/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts +++ b/plugins/catalog-backend/src/ingestion/HigherOrderOperations.ts @@ -130,7 +130,7 @@ export class HigherOrderOperations implements HigherOrderOperation { `Locations Refresh: Refreshing location ${location.type}:${location.target}`, ); try { - await this.refreshSingleLocation(location); + await this.refreshSingleLocation(location, logger); await this.locationsCatalog.logUpdateSuccess(location.id, undefined); } catch (e) { logger.warn( @@ -148,8 +148,12 @@ export class HigherOrderOperations implements HigherOrderOperation { } // Performs a full refresh of a single location - private async refreshSingleLocation(location: Location) { + private async refreshSingleLocation( + location: Location, + optionalLogger?: Logger, + ) { let startTimestamp = process.hrtime(); + const logger = optionalLogger || this.logger; const readerOutput = await this.locationReader.read({ type: location.type, @@ -157,12 +161,12 @@ export class HigherOrderOperations implements HigherOrderOperation { }); for (const item of readerOutput.errors) { - this.logger.warn( + logger.warn( `Failed item in location ${item.location.type}:${item.location.target}, ${item.error.stack}`, ); } - this.logger.info( + logger.info( `Read ${readerOutput.entities.length} entities from location ${ location.type }:${location.target} in ${durationText(startTimestamp)}`, @@ -186,14 +190,14 @@ export class HigherOrderOperations implements HigherOrderOperation { throw e; } - this.logger.debug(`Posting update success markers`); + logger.debug(`Posting update success markers`); await this.locationsCatalog.logUpdateSuccess( location.id, readerOutput.entities.map(e => e.entity.metadata.name), ); - this.logger.info( + logger.info( `Wrote ${readerOutput.entities.length} entities from location ${ location.type }:${location.target} in ${durationText(startTimestamp)}`, diff --git a/plugins/catalog-backend/src/service/router.ts b/plugins/catalog-backend/src/service/router.ts index 43c2967233..17cfc77d8b 100644 --- a/plugins/catalog-backend/src/service/router.ts +++ b/plugins/catalog-backend/src/service/router.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { errorHandler } from '@backstage/backend-common'; +import { errorHandler, NotFoundError } from '@backstage/backend-common'; import { locationSpecSchema, analyzeLocationSchema, @@ -57,7 +57,7 @@ export async function createRouter( const filter = EntityFilters.ofQuery(req.query); const fieldMapper = translateQueryToFieldMapper(req.query); const entities = await entitiesCatalog.entities(filter); - res.status(200).send(entities.map(fieldMapper)); + res.status(200).json(entities.map(fieldMapper)); }) .post('/entities', async (req, res) => { const body = await requireRequestBody(req); @@ -67,7 +67,7 @@ export async function createRouter( const [entity] = await entitiesCatalog.entities( EntityFilters.ofMatchers({ 'metadata.uid': result.entityId }), ); - res.status(200).send(entity); + res.status(200).json(entity); }) .get('/entities/by-uid/:uid', async (req, res) => { const { uid } = req.params; @@ -75,14 +75,14 @@ export async function createRouter( EntityFilters.ofMatchers({ 'metadata.uid': uid }), ); if (!entities.length) { - res.status(404).send(`No entity with uid ${uid}`); + throw new NotFoundError(`No entity with uid ${uid}`); } - res.status(200).send(entities[0]); + res.status(200).json(entities[0]); }) .delete('/entities/by-uid/:uid', async (req, res) => { const { uid } = req.params; await entitiesCatalog.removeEntityByUid(uid); - res.status(204).send(); + res.status(204).end(); }) .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => { const { kind, namespace, name } = req.params; @@ -94,13 +94,11 @@ export async function createRouter( }), ); if (!entities.length) { - res - .status(404) - .send( - `No entity with kind ${kind} namespace ${namespace} name ${name}`, - ); + throw new NotFoundError( + `No entity with kind ${kind} namespace ${namespace} name ${name}`, + ); } - res.status(200).send(entities[0]); + res.status(200).json(entities[0]); }); } @@ -109,7 +107,7 @@ export async function createRouter( const input = await validateRequestBody(req, locationSpecSchema); const dryRun = yn(req.query.dryRun, { default: false }); const output = await higherOrderOperation.addLocation(input, { dryRun }); - res.status(201).send(output); + res.status(201).json(output); }); } @@ -117,22 +115,22 @@ export async function createRouter( router .get('/locations', async (_req, res) => { const output = await locationsCatalog.locations(); - res.status(200).send(output); + res.status(200).json(output); }) .get('/locations/:id/history', async (req, res) => { const { id } = req.params; const output = await locationsCatalog.locationHistory(id); - res.status(200).send(output); + res.status(200).json(output); }) .get('/locations/:id', async (req, res) => { const { id } = req.params; const output = await locationsCatalog.location(id); - res.status(200).send(output); + res.status(200).json(output); }) .delete('/locations/:id', async (req, res) => { const { id } = req.params; await locationsCatalog.removeLocation(id); - res.status(204).send(); + res.status(204).end(); }); } @@ -140,7 +138,7 @@ export async function createRouter( router.post('/analyze-location', async (req, res) => { const input = await validateRequestBody(req, analyzeLocationSchema); const output = await locationAnalyzer.analyzeLocation(input); - res.status(200).send(output); + res.status(200).json(output); }); } diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index c81c29fc3e..9d76545909 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -30,8 +30,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", "@graphql-modules/core": "^0.7.17", "apollo-server": "^2.16.1", @@ -42,7 +42,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@backstage/test-utils": "^0.1.5", "@graphql-codegen/cli": "^1.17.7", "@graphql-codegen/typescript": "^1.17.7", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index c6e4995c70..0311d865a9 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-catalog-import +## 0.3.7 + +### Patch Changes + +- ceef4dd89: Export _api_ (Client, API, ref) from the catalog import plugin. +- b712841d6: Migrated to new composability API, exporting the plugin instance as `catalogImportPlugin`, and the page as `CatalogImportPage`. +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [c4abcdb60] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [064c513e1] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [3149bfe63] +- Updated dependencies [54c7d02f7] +- Updated dependencies [2e62aea6f] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/integration@0.3.2 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.3.6 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 7f3cc3d1e3..2b2b016716 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.3.6", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,11 +30,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/integration": "^0.3.1", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/integration": "^0.3.2", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -50,8 +50,8 @@ }, "devDependencies": { "@backstage/catalog-client": "^0.3.5", - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md new file mode 100644 index 0000000000..90b7c80caf --- /dev/null +++ b/plugins/catalog-react/CHANGELOG.md @@ -0,0 +1,26 @@ +# @backstage/plugin-catalog-react + +## 0.0.2 + +### Patch Changes + +- 7fc89bae2: Display owner and system as entity page links in the tables of the `api-docs` + plugin. + + Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to + `@backstage/plugin-catalog-react` and export it from there to use it by other + plugins. + +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/catalog-model@0.7.1 diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 94dc835d14..64307f6846 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "0.0.1", + "version": "0.0.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,8 +29,8 @@ }, "dependencies": { "@backstage/catalog-client": "^0.3.5", - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", "@material-ui/core": "^4.11.0", "@types/react": "^16.9", "react": "^16.13.1", @@ -39,8 +39,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 3920d8696d..eb4c9a30d7 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-catalog +## 0.3.0 + +### Minor Changes + +- 019fe39a0: `@backstage/plugin-catalog` stopped exporting hooks and helpers for other + plugins. They are migrated to `@backstage/plugin-catalog-react`. + Change both your dependencies and imports to the new package. + +### Patch Changes + +- 7fc89bae2: Display owner and system as entity page links in the tables of the `api-docs` + plugin. + + Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to + `@backstage/plugin-catalog-react` and export it from there to use it by other + plugins. + +- b37501a3d: Add `children` option to `addPage`, which will be rendered as the children of the `Route`. +- b37501a3d: Finalize migration to new composability API, with the plugin instance now exported `catalogPlugin`. +- 54c7d02f7: Introduce `TabbedLayout` for creating tabs that are routed. + + ```typescript + + +
This is rendered under /example/anything-here route
+
+
+ ``` + +- Updated dependencies [720149854] +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [019fe39a0] +- Updated dependencies [11cb5ef94] + - @backstage/plugin-scaffolder@0.4.2 + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.14 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index bf30e28571..c806c58e67 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "0.2.14", + "version": "0.3.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ }, "dependencies": { "@backstage/catalog-client": "^0.3.5", - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/plugin-scaffolder": "^0.4.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/plugin-scaffolder": "^0.4.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -52,8 +52,8 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@microsoft/microsoft-graph-types": "^1.25.0", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 45025a94e3..99715821a6 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-circleci +## 0.2.7 + +### Patch Changes + +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.6 ### Patch Changes diff --git a/plugins/circleci/dev/index.tsx b/plugins/circleci/dev/index.tsx index 812a5585d4..19a32c0d04 100644 --- a/plugins/circleci/dev/index.tsx +++ b/plugins/circleci/dev/index.tsx @@ -15,6 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { circleCIPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(circleCIPlugin).render(); diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index f128540784..37e4425b23 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-circleci", - "version": "0.2.6", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -50,8 +50,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/circleci/src/components/Router.tsx b/plugins/circleci/src/components/Router.tsx index 5fe9a20eff..d18b6c1e61 100644 --- a/plugins/circleci/src/components/Router.tsx +++ b/plugins/circleci/src/components/Router.tsx @@ -21,15 +21,25 @@ import { BuildWithStepsPage } from './BuildWithStepsPage/'; import { BuildsPage } from './BuildsPage'; import { CIRCLECI_ANNOTATION } from '../constants'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { MissingAnnotationEmptyState } from '@backstage/core'; -export const isPluginApplicableToEntity = (entity: Entity) => +export const isCircleCIAvailable = (entity: Entity) => Boolean(entity.metadata.annotations?.[CIRCLECI_ANNOTATION]); -export const Router = ({ entity }: { entity: Entity }) => - !isPluginApplicableToEntity(entity) ? ( - - ) : ( +type Props = { + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}; + +export const Router = (_props: Props) => { + const { entity } = useEntity(); + + if (!isCircleCIAvailable(entity)) { + return ; + } + + return ( } /> /> ); +}; diff --git a/plugins/circleci/src/index.ts b/plugins/circleci/src/index.ts index c6cb140208..2a37cbdee0 100644 --- a/plugins/circleci/src/index.ts +++ b/plugins/circleci/src/index.ts @@ -14,8 +14,16 @@ * limitations under the License. */ -export { plugin } from './plugin'; +export { + circleCIPlugin, + circleCIPlugin as plugin, + EntityCircleCIContent, +} from './plugin'; export * from './api'; export * from './route-refs'; -export { Router, isPluginApplicableToEntity } from './components/Router'; +export { + Router, + isCircleCIAvailable, + isCircleCIAvailable as isPluginApplicableToEntity, +} from './components/Router'; export { CIRCLECI_ANNOTATION } from './constants'; diff --git a/plugins/circleci/src/plugin.test.ts b/plugins/circleci/src/plugin.test.ts index 821a503257..bdd637027c 100644 --- a/plugins/circleci/src/plugin.test.ts +++ b/plugins/circleci/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { circleCIPlugin } from './plugin'; describe('circleci', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(circleCIPlugin).toBeDefined(); }); }); diff --git a/plugins/circleci/src/plugin.ts b/plugins/circleci/src/plugin.ts index c5bb122ed3..4e0d485726 100644 --- a/plugins/circleci/src/plugin.ts +++ b/plugins/circleci/src/plugin.ts @@ -18,10 +18,12 @@ import { createPlugin, createApiFactory, discoveryApiRef, + createRoutableExtension, } from '@backstage/core'; import { circleCIApiRef, CircleCIApi } from './api'; +import { circleCIRouteRef } from './route-refs'; -export const plugin = createPlugin({ +export const circleCIPlugin = createPlugin({ id: 'circleci', apis: [ createApiFactory({ @@ -31,3 +33,10 @@ export const plugin = createPlugin({ }), ], }); + +export const EntityCircleCIContent = circleCIPlugin.provide( + createRoutableExtension({ + component: () => import('./components/Router').then(m => m.Router), + mountPoint: circleCIRouteRef, + }), +); diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index d174677f51..ae3f8faada 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-cloudbuild +## 0.2.8 + +### Patch Changes + +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.7 ### Patch Changes diff --git a/plugins/cloudbuild/dev/index.tsx b/plugins/cloudbuild/dev/index.tsx index 264d6f801f..26fb65d151 100644 --- a/plugins/cloudbuild/dev/index.tsx +++ b/plugins/cloudbuild/dev/index.tsx @@ -14,6 +14,6 @@ * limitations under the License. */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { cloudbuildPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(cloudbuildPlugin).render(); diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 3e5bbef3a9..cbad4928b7 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cloudbuild", - "version": "0.2.7", + "version": "0.2.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,9 +30,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -46,8 +47,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/cloudbuild/src/components/Cards/Cards.tsx b/plugins/cloudbuild/src/components/Cards/Cards.tsx index bbfb0b59c3..75ae33027e 100644 --- a/plugins/cloudbuild/src/components/Cards/Cards.tsx +++ b/plugins/cloudbuild/src/components/Cards/Cards.tsx @@ -17,6 +17,7 @@ import React, { useEffect } from 'react'; import { useWorkflowRuns } from '../useWorkflowRuns'; import { WorkflowRun, WorkflowRunsTable } from '../WorkflowRunsTable'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; import { Link, Theme, makeStyles, LinearProgress } from '@material-ui/core'; import { @@ -72,12 +73,13 @@ const WidgetContent = ({ }; export const LatestWorkflowRunCard = ({ - entity, branch = 'master', }: { - entity: Entity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; branch: string; }) => { + const { entity } = useEntity(); const errorApi = useApi(errorApiRef); const projectId = entity?.metadata.annotations?.[CLOUDBUILD_ANNOTATION] || ''; @@ -104,13 +106,17 @@ export const LatestWorkflowRunCard = ({ }; export const LatestWorkflowsForBranchCard = ({ - entity, branch = 'master', }: { - entity: Entity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; branch: string; -}) => ( - - - -); +}) => { + const { entity } = useEntity(); + + return ( + + + + ); +}; diff --git a/plugins/cloudbuild/src/components/Router.tsx b/plugins/cloudbuild/src/components/Router.tsx index af4959f4be..0f71efcf86 100644 --- a/plugins/cloudbuild/src/components/Router.tsx +++ b/plugins/cloudbuild/src/components/Router.tsx @@ -15,6 +15,7 @@ */ import React from 'react'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { Routes, Route } from 'react-router'; import { rootRouteRef, buildRouteRef } from '../plugin'; import { WorkflowRunDetails } from './WorkflowRunDetails'; @@ -22,14 +23,22 @@ import { WorkflowRunsTable } from './WorkflowRunsTable'; import { CLOUDBUILD_ANNOTATION } from './useProjectName'; import { MissingAnnotationEmptyState } from '@backstage/core'; -export const isPluginApplicableToEntity = (entity: Entity) => +export const isCloudbuildAvailable = (entity: Entity) => Boolean(entity.metadata.annotations?.[CLOUDBUILD_ANNOTATION]); -export const Router = ({ entity }: { entity: Entity }) => - // TODO(shmidt-i): move warning to a separate standardized component - !isPluginApplicableToEntity(entity) ? ( - - ) : ( +type Props = { + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}; + +export const Router = (_props: Props) => { + const { entity } = useEntity(); + + if (!isCloudbuildAvailable(entity)) { + // TODO(shmidt-i): move warning to a separate standardized component + return ; + } + return ( ) ); +}; diff --git a/plugins/cloudbuild/src/index.ts b/plugins/cloudbuild/src/index.ts index 616bb6b4e7..b7cd6c29d5 100644 --- a/plugins/cloudbuild/src/index.ts +++ b/plugins/cloudbuild/src/index.ts @@ -13,8 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { plugin } from './plugin'; +export { + cloudbuildPlugin, + cloudbuildPlugin as plugin, + EntityCloudbuildContent, + EntityLatestCloudbuildRunCard, + EntityLatestCloudbuildsForBranchCard, +} from './plugin'; export * from './api'; -export { Router, isPluginApplicableToEntity } from './components/Router'; +export { + Router, + isCloudbuildAvailable, + isCloudbuildAvailable as isPluginApplicableToEntity, +} from './components/Router'; export * from './components/Cards'; export { CLOUDBUILD_ANNOTATION } from './components/useProjectName'; diff --git a/plugins/cloudbuild/src/plugin.test.ts b/plugins/cloudbuild/src/plugin.test.ts index dae16f1d1b..ea042a901a 100644 --- a/plugins/cloudbuild/src/plugin.test.ts +++ b/plugins/cloudbuild/src/plugin.test.ts @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { plugin } from './plugin'; +import { cloudbuildPlugin } from './plugin'; describe('cloudbuild', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(cloudbuildPlugin).toBeDefined(); }); }); diff --git a/plugins/cloudbuild/src/plugin.ts b/plugins/cloudbuild/src/plugin.ts index ee997cc7ec..f5aaf4696a 100644 --- a/plugins/cloudbuild/src/plugin.ts +++ b/plugins/cloudbuild/src/plugin.ts @@ -18,6 +18,8 @@ import { createRouteRef, createApiFactory, googleAuthApiRef, + createRoutableExtension, + createComponentExtension, } from '@backstage/core'; import { cloudbuildApiRef, CloudbuildClient } from './api'; @@ -31,7 +33,7 @@ export const buildRouteRef = createRouteRef({ title: 'Cloudbuild Run', }); -export const plugin = createPlugin({ +export const cloudbuildPlugin = createPlugin({ id: 'cloudbuild', apis: [ createApiFactory({ @@ -42,4 +44,32 @@ export const plugin = createPlugin({ }, }), ], + routes: { + entityContent: rootRouteRef, + }, }); + +export const EntityCloudbuildContent = cloudbuildPlugin.provide( + createRoutableExtension({ + component: () => import('./components/Router').then(m => m.Router), + mountPoint: rootRouteRef, + }), +); + +export const EntityLatestCloudbuildRunCard = cloudbuildPlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/Cards').then(m => m.LatestWorkflowRunCard), + }, + }), +); + +export const EntityLatestCloudbuildsForBranchCard = cloudbuildPlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/Cards').then(m => m.LatestWorkflowsForBranchCard), + }, + }), +); diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 78d4c69da4..87bfd3af07 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-cost-insights +## 0.8.0 + +### Minor Changes + +- 19172f5a9: add alert hooks + +### Patch Changes + +- 4c6a6dddd: Fixed date calculations incorrectly converting to UTC in some cases. This should be a transparent change. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + ## 0.7.0 ### Minor Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 022e778150..0184d50517 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cost-insights", - "version": "0.7.0", + "version": "0.8.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ }, "dependencies": { "@backstage/config": "^0.1.2", - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -55,8 +55,8 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/cost-insights/src/types/Alert.ts b/plugins/cost-insights/src/types/Alert.ts index eb8919b71a..84c37a7c15 100644 --- a/plugins/cost-insights/src/types/Alert.ts +++ b/plugins/cost-insights/src/types/Alert.ts @@ -149,7 +149,7 @@ export const AlertSnoozeOptions: AlertSnoozeOption[] = [ label: '1 Month', }, { - duration: Duration.P3M, + duration: Duration.P90D, label: '1 Quarter', }, ]; diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md new file mode 100644 index 0000000000..1b58da0f04 --- /dev/null +++ b/plugins/explore-react/CHANGELOG.md @@ -0,0 +1,14 @@ +# @backstage/plugin-explore-react + +## 0.0.2 + +### Patch Changes + +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 80d3d9d21e..924c723a67 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore-react", - "version": "0.0.1", + "version": "0.0.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -28,11 +28,11 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/core": "^0.5.0" + "@backstage/core": "^0.6.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index 75a0471ce7..0d2daf37b5 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,40 @@ # @backstage/plugin-explore +## 0.2.4 + +### Patch Changes + +- 54c7d02f7: Introduce `TabbedLayout` for creating tabs that are routed. + + ```typescript + + +
This is rendered under /example/anything-here route
+
+
+ ``` + +- 806929fe2: Rework the explore plugin to allow the user to explore things in the ecosystem, + including tools and domains. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + - @backstage/plugin-explore-react@0.0.2 + ## 0.2.3 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 2afa686355..e9d21cc221 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore", - "version": "0.2.3", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,11 +30,11 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/plugin-explore-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/plugin-explore-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -45,8 +45,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index 6fa8584017..de1e2fda06 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-fossa +## 0.2.0 + +### Minor Changes + +- 5ac9df899: Port FOSSA plugin to new extension model. + + If you are using the FOSSA plugin adjust the plugin import from `plugin` to + `fossaPlugin` and replace `` with ``. + +### Patch Changes + +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.1.2 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 879f12c6f6..74f04e3fd0 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-fossa", - "version": "0.1.2", + "version": "0.2.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -44,8 +44,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index 3b4a168644..92f1da463e 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-gcp-projects +## 0.2.4 + +### Patch Changes + +- bc5082a00: Migrate to new composability API, exporting the plugin as `gcpProjectsPlugin` and page as `GcpProjectsPage`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + ## 0.2.3 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index d48295e204..fced060d99 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcp-projects", - "version": "0.2.3", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -41,8 +41,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 1bd0481610..a9bbf67a9a 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-github-actions +## 0.3.1 + +### Patch Changes + +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [c4abcdb60] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [064c513e1] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [3149bfe63] +- Updated dependencies [54c7d02f7] +- Updated dependencies [2e62aea6f] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/integration@0.3.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.3.0 ### Minor Changes diff --git a/plugins/github-actions/dev/index.tsx b/plugins/github-actions/dev/index.tsx index 812a5585d4..9156224202 100644 --- a/plugins/github-actions/dev/index.tsx +++ b/plugins/github-actions/dev/index.tsx @@ -15,6 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { githubActionsPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(githubActionsPlugin).render(); diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index beb35b3cb0..7d05395b42 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-actions", - "version": "0.3.0", + "version": "0.3.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/integration": "^0.3.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/core": "^0.6.0", + "@backstage/integration": "^0.3.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -49,8 +50,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/github-actions/src/components/Cards/Cards.tsx b/plugins/github-actions/src/components/Cards/Cards.tsx index f1c27cb666..202bf5aa92 100644 --- a/plugins/github-actions/src/components/Cards/Cards.tsx +++ b/plugins/github-actions/src/components/Cards/Cards.tsx @@ -17,6 +17,7 @@ import React, { useEffect } from 'react'; import { useWorkflowRuns } from '../useWorkflowRuns'; import { WorkflowRun, WorkflowRunsTable } from '../WorkflowRunsTable'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { readGitHubIntegrationConfigs } from '@backstage/integration'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; import { @@ -81,11 +82,11 @@ const WidgetContent = ({ }; export const LatestWorkflowRunCard = ({ - entity, branch = 'master', // Display the card full height suitable for variant, }: Props) => { + const { entity } = useEntity(); const config = useApi(configApiRef); const errorApi = useApi(errorApiRef); // TODO: Get github hostname from metadata annotation @@ -121,17 +122,21 @@ export const LatestWorkflowRunCard = ({ }; type Props = { - entity: Entity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; branch: string; variant?: string; }; export const LatestWorkflowsForBranchCard = ({ - entity, branch = 'master', variant, -}: Props) => ( - - - -); +}: Props) => { + const { entity } = useEntity(); + + return ( + + + + ); +}; diff --git a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx index 0deb4ae39d..18cc59439b 100644 --- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx +++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.test.tsx @@ -22,6 +22,7 @@ import { ConfigApi, ConfigReader, } from '@backstage/core'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; import { lightTheme } from '@backstage/theme'; import { ThemeProvider } from '@material-ui/core'; import { render } from '@testing-library/react'; @@ -84,7 +85,9 @@ describe('', () => { configApi, )} > - + + + , diff --git a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx index aa30423c3e..4425bc8364 100644 --- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx +++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx @@ -23,6 +23,7 @@ import { useApi, } from '@backstage/core'; import { readGitHubIntegrationConfigs } from '@backstage/integration'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { Button, Link } from '@material-ui/core'; import React, { useEffect } from 'react'; import { generatePath, Link as RouterLink } from 'react-router-dom'; @@ -33,7 +34,8 @@ import { WorkflowRunStatus } from '../WorkflowRunStatus'; const firstLine = (message: string): string => message.split('\n')[0]; export type Props = { - entity: Entity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; branch?: string; dense?: boolean; limit?: number; @@ -41,12 +43,12 @@ export type Props = { }; export const RecentWorkflowRunsCard = ({ - entity, branch, dense = false, limit = 5, variant, }: Props) => { + const { entity } = useEntity(); const config = useApi(configApiRef); const errorApi = useApi(errorApiRef); // TODO: Get github hostname from metadata annotation diff --git a/plugins/github-actions/src/components/Router.tsx b/plugins/github-actions/src/components/Router.tsx index e7430d40ed..834fcae43c 100644 --- a/plugins/github-actions/src/components/Router.tsx +++ b/plugins/github-actions/src/components/Router.tsx @@ -15,6 +15,7 @@ */ import React from 'react'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { Routes, Route } from 'react-router'; import { rootRouteRef, buildRouteRef } from '../plugin'; import { WorkflowRunDetails } from './WorkflowRunDetails'; @@ -22,13 +23,23 @@ import { WorkflowRunsTable } from './WorkflowRunsTable'; import { GITHUB_ACTIONS_ANNOTATION } from './useProjectName'; import { MissingAnnotationEmptyState } from '@backstage/core'; -export const isPluginApplicableToEntity = (entity: Entity) => +export const isGithubActionsAvailable = (entity: Entity) => Boolean(entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION]); -export const Router = ({ entity }: { entity: Entity }) => - !isPluginApplicableToEntity(entity) ? ( - - ) : ( +type Props = { + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}; + +export const Router = (_props: Props) => { + const { entity } = useEntity(); + + if (!isGithubActionsAvailable(entity)) { + return ( + + ); + } + return ( ) ); +}; diff --git a/plugins/github-actions/src/index.ts b/plugins/github-actions/src/index.ts index 24fe6fc90d..b4179a9d92 100644 --- a/plugins/github-actions/src/index.ts +++ b/plugins/github-actions/src/index.ts @@ -14,8 +14,19 @@ * limitations under the License. */ -export { plugin } from './plugin'; +export { + githubActionsPlugin, + githubActionsPlugin as plugin, + EntityGithubActionsContent, + EntityLatestGithubActionRunCard, + EntityLatestGithubActionsForBranchCard, + EntityRecentGithubActionsRunsCard, +} from './plugin'; export * from './api'; -export { Router, isPluginApplicableToEntity } from './components/Router'; +export { + Router, + isGithubActionsAvailable, + isGithubActionsAvailable as isPluginApplicableToEntity, +} from './components/Router'; export * from './components/Cards'; export { GITHUB_ACTIONS_ANNOTATION } from './components/useProjectName'; diff --git a/plugins/github-actions/src/plugin.test.ts b/plugins/github-actions/src/plugin.test.ts index fa1075cbc8..53bc96c77a 100644 --- a/plugins/github-actions/src/plugin.test.ts +++ b/plugins/github-actions/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { githubActionsPlugin } from './plugin'; describe('github-actions', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(githubActionsPlugin).toBeDefined(); }); }); diff --git a/plugins/github-actions/src/plugin.ts b/plugins/github-actions/src/plugin.ts index 39ffc468b1..d296b4ad30 100644 --- a/plugins/github-actions/src/plugin.ts +++ b/plugins/github-actions/src/plugin.ts @@ -20,6 +20,8 @@ import { createRouteRef, createApiFactory, githubAuthApiRef, + createRoutableExtension, + createComponentExtension, } from '@backstage/core'; import { githubActionsApiRef, GithubActionsClient } from './api'; @@ -34,7 +36,7 @@ export const buildRouteRef = createRouteRef({ title: 'GitHub Actions Workflow Run', }); -export const plugin = createPlugin({ +export const githubActionsPlugin = createPlugin({ id: 'github-actions', apis: [ createApiFactory({ @@ -44,4 +46,41 @@ export const plugin = createPlugin({ new GithubActionsClient({ configApi, githubAuthApi }), }), ], + routes: { + entityContent: rootRouteRef, + }, }); + +export const EntityGithubActionsContent = githubActionsPlugin.provide( + createRoutableExtension({ + component: () => import('./components/Router').then(m => m.Router), + mountPoint: rootRouteRef, + }), +); + +export const EntityLatestGithubActionRunCard = githubActionsPlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/Cards').then(m => m.LatestWorkflowRunCard), + }, + }), +); + +export const EntityLatestGithubActionsForBranchCard = githubActionsPlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/Cards').then(m => m.LatestWorkflowsForBranchCard), + }, + }), +); + +export const EntityRecentGithubActionsRunsCard = githubActionsPlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/Cards').then(m => m.RecentWorkflowRunsCard), + }, + }), +); diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index 5aa38c65e5..0fa9fa24a2 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-gitops-profiles +## 0.2.4 + +### Patch Changes + +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + ## 0.2.3 ### Patch Changes diff --git a/plugins/gitops-profiles/dev/index.tsx b/plugins/gitops-profiles/dev/index.tsx index 812a5585d4..c164e4005d 100644 --- a/plugins/gitops-profiles/dev/index.tsx +++ b/plugins/gitops-profiles/dev/index.tsx @@ -15,6 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { gitopsProfilesPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(gitopsProfilesPlugin).render(); diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 447c3cbb81..c25628fa62 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gitops-profiles", - "version": "0.2.3", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -42,8 +42,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/gitops-profiles/src/index.ts b/plugins/gitops-profiles/src/index.ts index d67bc6a864..876c7c3263 100644 --- a/plugins/gitops-profiles/src/index.ts +++ b/plugins/gitops-profiles/src/index.ts @@ -14,5 +14,11 @@ * limitations under the License. */ -export { plugin } from './plugin'; +export { + gitopsProfilesPlugin, + gitopsProfilesPlugin as plugin, + GitopsProfilesClusterListPage, + GitopsProfilesClusterPage, + GitopsProfilesCreatePage, +} from './plugin'; export * from './api'; diff --git a/plugins/gitops-profiles/src/plugin.test.ts b/plugins/gitops-profiles/src/plugin.test.ts index 19bc49eba7..fa26902f2b 100644 --- a/plugins/gitops-profiles/src/plugin.test.ts +++ b/plugins/gitops-profiles/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { gitopsProfilesPlugin } from './plugin'; describe('gitops-profiles', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(gitopsProfilesPlugin).toBeDefined(); }); }); diff --git a/plugins/gitops-profiles/src/plugin.ts b/plugins/gitops-profiles/src/plugin.ts index 45820644f7..98a0067969 100644 --- a/plugins/gitops-profiles/src/plugin.ts +++ b/plugins/gitops-profiles/src/plugin.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { createPlugin, createApiFactory } from '@backstage/core'; +import { + createPlugin, + createApiFactory, + createRoutableExtension, +} from '@backstage/core'; import ProfileCatalog from './components/ProfileCatalog'; import ClusterPage from './components/ClusterPage'; import ClusterList from './components/ClusterList'; @@ -25,7 +29,7 @@ import { } from './routes'; import { gitOpsApiRef, GitOpsRestApi } from './api'; -export const plugin = createPlugin({ +export const gitopsProfilesPlugin = createPlugin({ id: 'gitops-profiles', apis: [ createApiFactory(gitOpsApiRef, new GitOpsRestApi('http://localhost:3008')), @@ -35,4 +39,30 @@ export const plugin = createPlugin({ router.addRoute(gitOpsClusterDetailsRoute, ClusterPage); router.addRoute(gitOpsClusterCreateRoute, ProfileCatalog); }, + routes: { + listPage: gitOpsClusterListRoute, + detailsPage: gitOpsClusterDetailsRoute, + createPage: gitOpsClusterCreateRoute, + }, }); + +export const GitopsProfilesClusterListPage = gitopsProfilesPlugin.provide( + createRoutableExtension({ + component: () => import('./components/ClusterList').then(m => m.default), + mountPoint: gitOpsClusterListRoute, + }), +); + +export const GitopsProfilesClusterPage = gitopsProfilesPlugin.provide( + createRoutableExtension({ + component: () => import('./components/ClusterPage').then(m => m.default), + mountPoint: gitOpsClusterDetailsRoute, + }), +); + +export const GitopsProfilesCreatePage = gitopsProfilesPlugin.provide( + createRoutableExtension({ + component: () => import('./components/ProfileCatalog').then(m => m.default), + mountPoint: gitOpsClusterCreateRoute, + }), +); diff --git a/plugins/gitops-profiles/src/routes.ts b/plugins/gitops-profiles/src/routes.ts index f9bdefa806..28be85bd38 100644 --- a/plugins/gitops-profiles/src/routes.ts +++ b/plugins/gitops-profiles/src/routes.ts @@ -28,6 +28,7 @@ export const gitOpsClusterDetailsRoute = createRouteRef({ icon: NoIcon, path: '/gitops-cluster/:owner/:repo', title: 'GitOps Cluster details', + params: ['owner', 'repo'], }); export const gitOpsClusterCreateRoute = createRouteRef({ diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index 88e6cc63e5..d6f4864a2f 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-graphiql +## 0.2.7 + +### Patch Changes + +- 87b189d00: Finalized composability API migration, now exporting the plugin as `graphiqlPlugin`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + ## 0.2.6 ### Patch Changes diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 850b29108e..9293a07dd7 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.2.6", + "version": "0.2.7", "private": false, "publishConfig": { "access": "public", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -43,8 +43,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/graphql/package.json b/plugins/graphql/package.json index 99d369b1a7..ab12ee5278 100644 --- a/plugins/graphql/package.json +++ b/plugins/graphql/package.json @@ -29,7 +29,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", + "@backstage/backend-common": "^0.5.2", "@backstage/config": "^0.1.2", "@backstage/plugin-catalog-graphql": "^0.2.6", "@graphql-modules/core": "^0.7.17", @@ -45,7 +45,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/supertest": "^2.0.8", "eslint-plugin-graphql": "^4.0.0", "msw": "^0.20.5", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index c49857c7a5..2199c58949 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-jenkins +## 0.3.8 + +### Patch Changes + +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.3.7 ### Patch Changes diff --git a/plugins/jenkins/dev/index.tsx b/plugins/jenkins/dev/index.tsx index 812a5585d4..8beb6eabc1 100644 --- a/plugins/jenkins/dev/index.tsx +++ b/plugins/jenkins/dev/index.tsx @@ -15,6 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { jenkinsPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(jenkinsPlugin).render(); diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index 7456d4be53..5d59d2e5ab 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins", - "version": "0.3.7", + "version": "0.3.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -47,8 +47,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/jenkins/src/components/Router.tsx b/plugins/jenkins/src/components/Router.tsx index 91bcde2a8b..85f06bb0e1 100644 --- a/plugins/jenkins/src/components/Router.tsx +++ b/plugins/jenkins/src/components/Router.tsx @@ -15,6 +15,7 @@ */ import React from 'react'; import { Route, Routes } from 'react-router'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { buildRouteRef, rootRouteRef } from '../plugin'; import { DetailedViewPage } from './BuildWithStepsPage/'; import { JENKINS_ANNOTATION } from '../constants'; @@ -22,13 +23,22 @@ import { Entity } from '@backstage/catalog-model'; import { MissingAnnotationEmptyState } from '@backstage/core'; import { CITable } from './BuildsPage/lib/CITable'; -export const isPluginApplicableToEntity = (entity: Entity) => +export const isJenkinsAvailable = (entity: Entity) => Boolean(entity.metadata.annotations?.[JENKINS_ANNOTATION]); -export const Router = ({ entity }: { entity: Entity }) => { - return !isPluginApplicableToEntity(entity) ? ( - - ) : ( +type Props = { + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}; + +export const Router = (_props: Props) => { + const { entity } = useEntity(); + + if (!isJenkinsAvailable(entity)) { + return ; + } + + return ( } /> } /> diff --git a/plugins/jenkins/src/index.ts b/plugins/jenkins/src/index.ts index 30fa0c70a5..e434e959e8 100644 --- a/plugins/jenkins/src/index.ts +++ b/plugins/jenkins/src/index.ts @@ -14,8 +14,17 @@ * limitations under the License. */ -export { plugin } from './plugin'; +export { + jenkinsPlugin, + jenkinsPlugin as plugin, + EntityJenkinsContent, + EntityLatestJenkinsRunCard, +} from './plugin'; export { LatestRunCard } from './components/Cards'; -export { Router, isPluginApplicableToEntity } from './components/Router'; +export { + Router, + isJenkinsAvailable, + isJenkinsAvailable as isPluginApplicableToEntity, +} from './components/Router'; export { JENKINS_ANNOTATION } from './constants'; export * from './api'; diff --git a/plugins/jenkins/src/plugin.test.ts b/plugins/jenkins/src/plugin.test.ts index 8c3f057ecb..0498b80b90 100644 --- a/plugins/jenkins/src/plugin.test.ts +++ b/plugins/jenkins/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { jenkinsPlugin } from './plugin'; describe('jenkins', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(jenkinsPlugin).toBeDefined(); }); }); diff --git a/plugins/jenkins/src/plugin.ts b/plugins/jenkins/src/plugin.ts index 23c54743a3..85001d9bbc 100644 --- a/plugins/jenkins/src/plugin.ts +++ b/plugins/jenkins/src/plugin.ts @@ -19,6 +19,8 @@ import { createRouteRef, createApiFactory, discoveryApiRef, + createRoutableExtension, + createComponentExtension, } from '@backstage/core'; import { jenkinsApiRef, JenkinsApi } from './api'; @@ -32,7 +34,7 @@ export const buildRouteRef = createRouteRef({ title: 'Jenkins run', }); -export const plugin = createPlugin({ +export const jenkinsPlugin = createPlugin({ id: 'jenkins', apis: [ createApiFactory({ @@ -41,4 +43,21 @@ export const plugin = createPlugin({ factory: ({ discoveryApi }) => new JenkinsApi({ discoveryApi }), }), ], + routes: { + entityContent: rootRouteRef, + }, }); + +export const EntityJenkinsContent = jenkinsPlugin.provide( + createRoutableExtension({ + component: () => import('./components/Router').then(m => m.Router), + mountPoint: rootRouteRef, + }), +); +export const EntityLatestJenkinsRunCard = jenkinsPlugin.provide( + createComponentExtension({ + component: { + lazy: () => import('./components/Cards').then(m => m.LatestRunCard), + }, + }), +); diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index 311464b47d..1eaa1d8316 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -42,7 +42,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/jest-when": "^2.7.2", "@types/lodash": "^4.14.151", "jest-when": "^3.1.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index 92f49a1d35..2895288b56 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-kafka +## 0.2.1 + +### Patch Changes + +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.0 ### Minor Changes diff --git a/plugins/kafka/dev/index.tsx b/plugins/kafka/dev/index.tsx index 264d6f801f..5506d47026 100644 --- a/plugins/kafka/dev/index.tsx +++ b/plugins/kafka/dev/index.tsx @@ -14,6 +14,6 @@ * limitations under the License. */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { kafkaPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(kafkaPlugin).render(); diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 546d20bc67..5d6454ed60 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kafka", - "version": "0.2.0", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,10 +20,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -33,8 +33,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/kafka/src/Router.tsx b/plugins/kafka/src/Router.tsx index b445f8f408..13503fefe8 100644 --- a/plugins/kafka/src/Router.tsx +++ b/plugins/kafka/src/Router.tsx @@ -17,7 +17,7 @@ import { Entity } from '@backstage/catalog-model'; import React from 'react'; import { Route, Routes } from 'react-router'; - +import { useEntity } from '@backstage/plugin-catalog-react'; import { rootCatalogKafkaRouteRef } from './plugin'; import { KAFKA_CONSUMER_GROUP_ANNOTATION } from './constants'; import { KafkaTopicsForConsumer } from './components/ConsumerGroupOffsets/ConsumerGroupOffsets'; @@ -26,10 +26,23 @@ import { MissingAnnotationEmptyState } from '@backstage/core'; export const isPluginApplicableToEntity = (entity: Entity) => Boolean(entity.metadata.annotations?.[KAFKA_CONSUMER_GROUP_ANNOTATION]); -export const Router = ({ entity }: { entity: Entity }) => { - return !isPluginApplicableToEntity(entity) ? ( - - ) : ( +type Props = { + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}; + +export const Router = (_props: Props) => { + const { entity } = useEntity(); + + if (!isPluginApplicableToEntity(entity)) { + return ( + + ); + } + + return ( { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(kafkaPlugin).toBeDefined(); }); }); diff --git a/plugins/kafka/src/plugin.ts b/plugins/kafka/src/plugin.ts index 878a7f56e9..832099a30c 100644 --- a/plugins/kafka/src/plugin.ts +++ b/plugins/kafka/src/plugin.ts @@ -16,6 +16,7 @@ import { createApiFactory, createPlugin, + createRoutableExtension, createRouteRef, discoveryApiRef, } from '@backstage/core'; @@ -27,7 +28,7 @@ export const rootCatalogKafkaRouteRef = createRouteRef({ title: 'Kafka', }); -export const plugin = createPlugin({ +export const kafkaPlugin = createPlugin({ id: 'kafka', apis: [ createApiFactory({ @@ -36,4 +37,14 @@ export const plugin = createPlugin({ factory: ({ discoveryApi }) => new KafkaBackendClient({ discoveryApi }), }), ], + routes: { + entityContent: rootCatalogKafkaRouteRef, + }, }); + +export const EntityKafkaContent = kafkaPlugin.provide( + createRoutableExtension({ + component: () => import('./Router').then(m => m.Router), + mountPoint: rootCatalogKafkaRouteRef, + }), +); diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index e69a82b738..3823ee1899 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -32,8 +32,8 @@ }, "dependencies": { "@aws-sdk/credential-provider-node": "^3.3.0", - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", "@kubernetes/client-node": "^0.13.2", "@types/express": "^4.17.6", @@ -51,7 +51,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/aws4": "^1.5.1", "supertest": "^4.0.2" }, diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index f16728e1fe..311bd5edaa 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes +## 0.3.8 + +### Patch Changes + +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.3.7 ### Patch Changes diff --git a/plugins/kubernetes/dev/index.tsx b/plugins/kubernetes/dev/index.tsx index f352fb9c34..de93d21348 100644 --- a/plugins/kubernetes/dev/index.tsx +++ b/plugins/kubernetes/dev/index.tsx @@ -14,6 +14,6 @@ * limitations under the License. */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src'; +import { kubernetesPlugin } from '../src'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(kubernetesPlugin).render(); diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 1d985c0d10..9013fa9395 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.3.7", + "version": "0.3.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", + "@backstage/catalog-model": "^0.7.1", + "@backstage/plugin-catalog-react": "^0.0.2", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.5.0", + "@backstage/core": "^0.6.0", "@backstage/plugin-kubernetes-backend": "^0.2.6", - "@backstage/theme": "^0.2.2", + "@backstage/theme": "^0.2.3", "@kubernetes/client-node": "^0.13.2", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -47,8 +48,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/kubernetes/src/Router.tsx b/plugins/kubernetes/src/Router.tsx index 20a4c04285..36851b3c46 100644 --- a/plugins/kubernetes/src/Router.tsx +++ b/plugins/kubernetes/src/Router.tsx @@ -16,15 +16,22 @@ import React from 'react'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { Route, Routes } from 'react-router-dom'; - import { rootCatalogKubernetesRouteRef } from './plugin'; import { KubernetesContent } from './components/KubernetesContent'; import { MissingAnnotationEmptyState } from '@backstage/core'; const KUBERNETES_ANNOTATION = 'backstage.io/kubernetes-id'; -export const Router = ({ entity }: { entity: Entity }) => { +type Props = { + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}; + +export const Router = (_props: Props) => { + const { entity } = useEntity(); + const kubernetesAnnotationValue = entity.metadata.annotations?.[KUBERNETES_ANNOTATION]; diff --git a/plugins/kubernetes/src/index.ts b/plugins/kubernetes/src/index.ts index 8b5969666c..eca6b068f1 100644 --- a/plugins/kubernetes/src/index.ts +++ b/plugins/kubernetes/src/index.ts @@ -13,5 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { plugin } from './plugin'; +export { + kubernetesPlugin, + kubernetesPlugin as plugin, + EntityKubernetesContent, +} from './plugin'; export { Router } from './Router'; diff --git a/plugins/kubernetes/src/plugin.test.ts b/plugins/kubernetes/src/plugin.test.ts index 20c50a813a..f176b7f451 100644 --- a/plugins/kubernetes/src/plugin.test.ts +++ b/plugins/kubernetes/src/plugin.test.ts @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { plugin } from './plugin'; +import { kubernetesPlugin } from './plugin'; describe('kubernetes', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(kubernetesPlugin).toBeDefined(); }); }); diff --git a/plugins/kubernetes/src/plugin.ts b/plugins/kubernetes/src/plugin.ts index cff9e1468b..af29df3dcc 100644 --- a/plugins/kubernetes/src/plugin.ts +++ b/plugins/kubernetes/src/plugin.ts @@ -19,6 +19,7 @@ import { createRouteRef, discoveryApiRef, googleAuthApiRef, + createRoutableExtension, } from '@backstage/core'; import { KubernetesBackendClient } from './api/KubernetesBackendClient'; import { kubernetesApiRef } from './api/types'; @@ -30,7 +31,7 @@ export const rootCatalogKubernetesRouteRef = createRouteRef({ title: 'Kubernetes', }); -export const plugin = createPlugin({ +export const kubernetesPlugin = createPlugin({ id: 'kubernetes', apis: [ createApiFactory({ @@ -47,4 +48,14 @@ export const plugin = createPlugin({ }, }), ], + routes: { + entityContent: rootCatalogKubernetesRouteRef, + }, }); + +export const EntityKubernetesContent = kubernetesPlugin.provide( + createRoutableExtension({ + component: () => import('./Router').then(m => m.Router), + mountPoint: rootCatalogKubernetesRouteRef, + }), +); diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 301a9b4fed..8fec8887c3 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-lighthouse +## 0.2.9 + +### Patch Changes + +- a5628df40: Migrate to new composability API, exporting the plugin instance as `lighthousePlugin`, the top-level page as `LighthousePage`, the entity card as `EntityLastLighthouseAuditCard`, and the entity content as `EntityLighthouseContent`. +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.8 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 5b45bfa48b..07e1ad8475 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-lighthouse", - "version": "0.2.8", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -46,8 +46,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/lighthouse/src/Router.tsx b/plugins/lighthouse/src/Router.tsx index 0634a0aaa0..643d30cdc2 100644 --- a/plugins/lighthouse/src/Router.tsx +++ b/plugins/lighthouse/src/Router.tsx @@ -16,6 +16,7 @@ import React from 'react'; import { Route, Routes } from 'react-router-dom'; +import { useEntity } from '@backstage/plugin-catalog-react'; import AuditList from './components/AuditList'; import AuditView, { AuditViewContent } from './components/AuditView'; import CreateAudit, { CreateAuditContent } from './components/CreateAudit'; @@ -35,15 +36,27 @@ export const Router = () => ( ); -export const EmbeddedRouter = ({ entity }: { entity: Entity }) => - !isLighthouseAvailable(entity) ? ( - - ) : ( +type Props = { + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}; + +export const EmbeddedRouter = (_props: Props) => { + const { entity } = useEntity(); + + if (!isLighthouseAvailable(entity)) { + return ( + + ); + } + + return ( } /> } /> } /> ); +}; diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index d7806c4081..6eae73bc86 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-newrelic +## 0.2.4 + +### Patch Changes + +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + ## 0.2.3 ### Patch Changes diff --git a/plugins/newrelic/dev/index.tsx b/plugins/newrelic/dev/index.tsx index 812a5585d4..9ca421f94a 100644 --- a/plugins/newrelic/dev/index.tsx +++ b/plugins/newrelic/dev/index.tsx @@ -15,6 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { newRelicPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(newRelicPlugin).render(); diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 2f43c9cbeb..ccd43c42c8 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic", - "version": "0.2.3", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -41,8 +41,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/newrelic/src/index.ts b/plugins/newrelic/src/index.ts index 3a0a0fe2d3..aa4e990d6c 100644 --- a/plugins/newrelic/src/index.ts +++ b/plugins/newrelic/src/index.ts @@ -14,4 +14,8 @@ * limitations under the License. */ -export { plugin } from './plugin'; +export { + newRelicPlugin, + newRelicPlugin as plugin, + NewRelicPage, +} from './plugin'; diff --git a/plugins/newrelic/src/plugin.test.ts b/plugins/newrelic/src/plugin.test.ts index 17429a95e0..f2e8fde924 100644 --- a/plugins/newrelic/src/plugin.test.ts +++ b/plugins/newrelic/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { newRelicPlugin } from './plugin'; describe('newrelic', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(newRelicPlugin).toBeDefined(); }); }); diff --git a/plugins/newrelic/src/plugin.ts b/plugins/newrelic/src/plugin.ts index 5f5ba88617..d89aa813e9 100644 --- a/plugins/newrelic/src/plugin.ts +++ b/plugins/newrelic/src/plugin.ts @@ -19,6 +19,7 @@ import { createPlugin, createRouteRef, discoveryApiRef, + createRoutableExtension, } from '@backstage/core'; import { NewRelicClient, newRelicApiRef } from './api'; import NewRelicComponent from './components/NewRelicComponent'; @@ -28,7 +29,7 @@ export const rootRouteRef = createRouteRef({ title: 'newrelic', }); -export const plugin = createPlugin({ +export const newRelicPlugin = createPlugin({ id: 'newrelic', apis: [ createApiFactory({ @@ -40,4 +41,15 @@ export const plugin = createPlugin({ register({ router }) { router.addRoute(rootRouteRef, NewRelicComponent); }, + routes: { + root: rootRouteRef, + }, }); + +export const NewRelicPage = newRelicPlugin.provide( + createRoutableExtension({ + component: () => + import('./components/NewRelicComponent').then(m => m.default), + mountPoint: rootRouteRef, + }), +); diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 17dd37266f..6101685e1d 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,36 @@ # @backstage/plugin-org +## 0.3.5 + +### Patch Changes + +- 7fc89bae2: Display owner and system as entity page links in the tables of the `api-docs` + plugin. + + Move `isOwnerOf` and `getEntityRelations` from `@backstage/plugin-catalog` to + `@backstage/plugin-catalog-react` and export it from there to use it by other + plugins. + +- 0269f4fd9: Migrate to new composability API, exporting the plugin instance as `orgPlugin`, and the entity cards as `EntityGroupProfileCard`, `EntityMembersListCard`, `EntityOwnershipCard`, and `EntityUserProfileCard`. +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.3.4 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index e376dea5bc..0491554f77 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.3.4", + "version": "0.3.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,10 +20,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -33,8 +33,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx index 506a98d012..2f0f1e2e16 100644 --- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx +++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx @@ -21,7 +21,7 @@ import { RELATION_PARENT_OF, } from '@backstage/catalog-model'; import { Avatar, InfoCard } from '@backstage/core'; -import { entityRouteParams } from '@backstage/plugin-catalog-react'; +import { useEntity, entityRouteParams } from '@backstage/plugin-catalog-react'; import { Box, Grid, Link, Tooltip, Typography } from '@material-ui/core'; import AccountTreeIcon from '@material-ui/icons/AccountTree'; import EmailIcon from '@material-ui/icons/Email'; @@ -33,26 +33,29 @@ import { generatePath, Link as RouterLink } from 'react-router-dom'; const GroupLink = ({ groupName, index = 0, - entity, }: { groupName: string; index?: number; - entity: Entity; -}) => ( - <> - {index >= 1 ? ', ' : ''} - - [{groupName}] - - -); + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}) => { + const { entity } = useEntity(); + return ( + <> + {index >= 1 ? ', ' : ''} + + [{groupName}] + + + ); +}; const CardTitle = ({ title }: { title: string }) => ( @@ -61,12 +64,13 @@ const CardTitle = ({ title }: { title: string }) => ( ); export const GroupProfileCard = ({ - entity: group, variant, }: { - entity: GroupEntity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: GroupEntity; variant: string; }) => { + const group = useEntity().entity as GroupEntity; const { metadata: { name, description }, spec: { profile }, diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx index 6815fd0e55..28c55b376b 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx @@ -16,7 +16,11 @@ import { Entity, GroupEntity } from '@backstage/catalog-model'; import { ApiProvider, ApiRegistry } from '@backstage/core'; -import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { + CatalogApi, + catalogApiRef, + EntityProvider, +} from '@backstage/plugin-catalog-react'; import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; import React from 'react'; import { MembersListCard } from './MembersListCard'; @@ -78,7 +82,10 @@ describe('MemberTab Test', () => { const rendered = await renderWithEffects( wrapInTestApp( - + + + + , , ), ); diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index f644e7db7e..7f8ede2eb7 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -21,6 +21,7 @@ import { } from '@backstage/catalog-model'; import { Avatar, InfoCard, Progress, useApi } from '@backstage/core'; import { + useEntity, catalogApiRef, entityRouteParams, } from '@backstage/plugin-catalog-react'; @@ -105,11 +106,11 @@ const MemberComponent = ({ ); }; -export const MembersListCard = ({ - entity: groupEntity, -}: { - entity: GroupEntity; +export const MembersListCard = (_props: { + /** @deprecated The entity is now grabbed from context instead */ + entity?: GroupEntity; }) => { + const groupEntity = useEntity().entity as GroupEntity; const { metadata: { name: groupName }, spec: { profile }, diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 60f06bd53a..80e80bddcc 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -16,7 +16,11 @@ import { Entity } from '@backstage/catalog-model'; import { InfoCard, Progress, useApi } from '@backstage/core'; -import { catalogApiRef, isOwnerOf } from '@backstage/plugin-catalog-react'; +import { + catalogApiRef, + isOwnerOf, + useEntity, +} from '@backstage/plugin-catalog-react'; import { pageTheme } from '@backstage/theme'; import { Box, @@ -113,12 +117,13 @@ const EntityCountTile = ({ }; export const OwnershipCard = ({ - entity, variant, }: { - entity: Entity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; variant: string; }) => { + const { entity } = useEntity(); const catalogApi = useApi(catalogApiRef); const { loading, diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx index 77708e6f27..7c7d26c228 100644 --- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx +++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.test.tsx @@ -15,6 +15,7 @@ */ import { UserEntity } from '@backstage/catalog-model'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; import React from 'react'; import { UserProfileCard } from './UserProfileCard'; @@ -48,7 +49,11 @@ describe('UserSummary Test', () => { it('Display Profile Card', async () => { const rendered = await renderWithEffects( - wrapInTestApp(), + wrapInTestApp( + + + , + ), ); expect(rendered.getByText('calum-leavy@example.com')).toBeInTheDocument(); diff --git a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx index bdd0cd15f6..1cf7c968b3 100644 --- a/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx +++ b/plugins/org/src/components/Cards/User/UserProfileCard/UserProfileCard.tsx @@ -19,7 +19,7 @@ import { UserEntity, } from '@backstage/catalog-model'; import { Avatar, InfoCard } from '@backstage/core'; -import { entityRouteParams } from '@backstage/plugin-catalog-react'; +import { useEntity, entityRouteParams } from '@backstage/plugin-catalog-react'; import { Box, Grid, Link, Tooltip, Typography } from '@material-ui/core'; import EmailIcon from '@material-ui/icons/Email'; import GroupIcon from '@material-ui/icons/Group'; @@ -60,12 +60,13 @@ const CardTitle = ({ title }: { title?: string }) => ) : null; export const UserProfileCard = ({ - entity: user, variant, }: { - entity: UserEntity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: UserEntity; variant: string; }) => { + const user = useEntity().entity as UserEntity; const { metadata: { name: metaName }, spec: { profile }, diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index d27becfa47..eb00ce36be 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-pagerduty +## 0.2.7 + +### Patch Changes + +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.6 ### Patch Changes diff --git a/plugins/pagerduty/dev/index.tsx b/plugins/pagerduty/dev/index.tsx index 264d6f801f..ad46c0ca9e 100644 --- a/plugins/pagerduty/dev/index.tsx +++ b/plugins/pagerduty/dev/index.tsx @@ -14,6 +14,6 @@ * limitations under the License. */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { pagerDutyPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(pagerDutyPlugin).render(); diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 0e87bdc2d7..afd41dcc46 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-pagerduty", - "version": "0.2.6", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,9 +30,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -44,8 +45,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/pagerduty/src/components/PagerDutyCard.test.tsx b/plugins/pagerduty/src/components/PagerDutyCard.test.tsx index a6615aee82..a719a27f86 100644 --- a/plugins/pagerduty/src/components/PagerDutyCard.test.tsx +++ b/plugins/pagerduty/src/components/PagerDutyCard.test.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { render, waitFor, fireEvent, act } from '@testing-library/react'; import { PagerDutyCard } from './PagerDutyCard'; import { Entity } from '@backstage/catalog-model'; +import { EntityProvider } from '@backstage/plugin-catalog-react'; import { wrapInTestApp } from '@backstage/test-utils'; import { alertApiRef, @@ -80,7 +81,9 @@ describe('PageDutyCard', () => { const { getByText, queryByTestId } = render( wrapInTestApp( - + + + , ), ); @@ -99,7 +102,9 @@ describe('PageDutyCard', () => { const { getByText, queryByTestId } = render( wrapInTestApp( - + + + , ), ); @@ -114,7 +119,9 @@ describe('PageDutyCard', () => { const { getByText, queryByTestId } = render( wrapInTestApp( - + + + , ), ); @@ -134,7 +141,9 @@ describe('PageDutyCard', () => { const { getByText, queryByTestId, getByTestId, getByRole } = render( wrapInTestApp( - + + + , ), ); diff --git a/plugins/pagerduty/src/components/PagerDutyCard.tsx b/plugins/pagerduty/src/components/PagerDutyCard.tsx index 5fb2cd7f4a..e03fb0fdbe 100644 --- a/plugins/pagerduty/src/components/PagerDutyCard.tsx +++ b/plugins/pagerduty/src/components/PagerDutyCard.tsx @@ -16,6 +16,7 @@ import React, { useState, useCallback } from 'react'; import { useApi, Progress, HeaderIconLinkRow } from '@backstage/core'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { Button, makeStyles, @@ -56,11 +57,13 @@ export const isPluginApplicableToEntity = (entity: Entity) => Boolean(entity.metadata.annotations?.[PAGERDUTY_INTEGRATION_KEY]); type Props = { - entity: Entity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; }; -export const PagerDutyCard = ({ entity }: Props) => { +export const PagerDutyCard = (_props: Props) => { const classes = useStyles(); + const { entity } = useEntity(); const api = useApi(pagerDutyApiRef); const [showDialog, setShowDialog] = useState(false); const [refreshIncidents, setRefreshIncidents] = useState(false); diff --git a/plugins/pagerduty/src/index.ts b/plugins/pagerduty/src/index.ts index 4ecd4edcc6..2dfedab164 100644 --- a/plugins/pagerduty/src/index.ts +++ b/plugins/pagerduty/src/index.ts @@ -13,9 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { plugin } from './plugin'; +export { + pagerDutyPlugin, + pagerDutyPlugin as plugin, + EntityPagerDutyCard, +} from './plugin'; export { isPluginApplicableToEntity, + isPluginApplicableToEntity as isPagerDutyAvailable, PagerDutyCard, } from './components/PagerDutyCard'; export { diff --git a/plugins/pagerduty/src/plugin.test.ts b/plugins/pagerduty/src/plugin.test.ts index 8d4545ac12..c1175ab384 100644 --- a/plugins/pagerduty/src/plugin.test.ts +++ b/plugins/pagerduty/src/plugin.test.ts @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { plugin } from './plugin'; +import { pagerDutyPlugin } from './plugin'; describe('pagerduty', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(pagerDutyPlugin).toBeDefined(); }); }); diff --git a/plugins/pagerduty/src/plugin.ts b/plugins/pagerduty/src/plugin.ts index 34796f491e..fbe827b90d 100644 --- a/plugins/pagerduty/src/plugin.ts +++ b/plugins/pagerduty/src/plugin.ts @@ -19,6 +19,7 @@ import { createRouteRef, discoveryApiRef, configApiRef, + createComponentExtension, } from '@backstage/core'; import { pagerDutyApiRef, PagerDutyClient } from './api'; @@ -27,7 +28,7 @@ export const rootRouteRef = createRouteRef({ title: 'pagerduty', }); -export const plugin = createPlugin({ +export const pagerDutyPlugin = createPlugin({ id: 'pagerduty', apis: [ createApiFactory({ @@ -38,3 +39,12 @@ export const plugin = createPlugin({ }), ], }); + +export const EntityPagerDutyCard = pagerDutyPlugin.provide( + createComponentExtension({ + component: { + lazy: () => + import('./components/PagerDutyCard').then(m => m.PagerDutyCard), + }, + }), +); diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index ae828cb2ec..51ccf98f8b 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -28,7 +28,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", + "@backstage/backend-common": "^0.5.2", "@backstage/config": "^0.1.2", "@types/express": "^4.17.6", "express": "^4.17.1", @@ -42,7 +42,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/register-component/CHANGELOG.md b/plugins/register-component/CHANGELOG.md index abc2fdbd58..901c556052 100644 --- a/plugins/register-component/CHANGELOG.md +++ b/plugins/register-component/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-register-component +## 0.2.8 + +### Patch Changes + +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.7 ### Patch Changes diff --git a/plugins/register-component/dev/index.tsx b/plugins/register-component/dev/index.tsx index 812a5585d4..3304d0874f 100644 --- a/plugins/register-component/dev/index.tsx +++ b/plugins/register-component/dev/index.tsx @@ -15,6 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { registerComponentPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(registerComponentPlugin).render(); diff --git a/plugins/register-component/package.json b/plugins/register-component/package.json index 39c431b3cd..9e0f045cd4 100644 --- a/plugins/register-component/package.json +++ b/plugins/register-component/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-register-component", - "version": "0.2.7", + "version": "0.2.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,10 +30,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -45,8 +45,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/register-component/src/index.ts b/plugins/register-component/src/index.ts index ff7857cacd..56bcd06fde 100644 --- a/plugins/register-component/src/index.ts +++ b/plugins/register-component/src/index.ts @@ -14,5 +14,9 @@ * limitations under the License. */ -export { plugin } from './plugin'; +export { + registerComponentPlugin, + registerComponentPlugin as plugin, + RegisterComponentPage, +} from './plugin'; export { Router } from './components/Router'; diff --git a/plugins/register-component/src/plugin.test.ts b/plugins/register-component/src/plugin.test.ts index 1e61060202..2b6ad48bcf 100644 --- a/plugins/register-component/src/plugin.test.ts +++ b/plugins/register-component/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { registerComponentPlugin } from './plugin'; describe('register-component', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(registerComponentPlugin).toBeDefined(); }); }); diff --git a/plugins/register-component/src/plugin.ts b/plugins/register-component/src/plugin.ts index 17f99917c8..d3727158e5 100644 --- a/plugins/register-component/src/plugin.ts +++ b/plugins/register-component/src/plugin.ts @@ -14,8 +14,29 @@ * limitations under the License. */ -import { createPlugin } from '@backstage/core'; +import { + createPlugin, + createRoutableExtension, + createRouteRef, +} from '@backstage/core'; -export const plugin = createPlugin({ - id: 'register-component', +const rootRouteRef = createRouteRef({ + title: 'Register Component', }); + +export const registerComponentPlugin = createPlugin({ + id: 'register-component', + routes: { + root: rootRouteRef, + }, +}); + +export const RegisterComponentPage = registerComponentPlugin.provide( + createRoutableExtension({ + component: () => + import('./components/RegisterComponentPage').then( + m => m.RegisterComponentPage, + ), + mountPoint: rootRouteRef, + }), +); diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 522f5a3b4c..ff7a4f06f5 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", + "@backstage/backend-common": "^0.5.2", "@backstage/config": "^0.1.2", "@types/express": "^4.17.6", "axios": "^0.21.1", @@ -47,7 +47,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@types/supertest": "^2.0.8", "supertest": "^4.0.2" }, diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index d317640948..e49c843116 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-rollbar +## 0.2.9 + +### Patch Changes + +- 9d6ef14bc: Migrated to new composability API, exporting the plugin instance as `rollbarPlugin`, the entity page content as `EntityRollbarContent`, and entity conditional as `isRollbarAvailable`. Updated the `EntityPage` for the `example-app` to include a composite `ErrorsSwitcher` component that works with both `Sentry` & `Rollbar`. Also removed the unused and undocumented `RollbarHome` related components. +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.8 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 7ba72dad0d..44d8583bfa 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-rollbar", - "version": "0.2.8", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -47,8 +47,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 353e2321cf..e8526e0b56 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,103 @@ # @backstage/plugin-scaffolder-backend +## 0.6.0 + +### Minor Changes + +- cdea0baf1: The scaffolder is updated to generate a unique workspace directory inside the temp folder. This directory is cleaned up by the job processor after each run. + + The prepare/template/publish steps have been refactored to operate on known directories, `template/` and `result/`, inside the temporary workspace path. + + Updated preparers to accept the template url instead of the entire template. This is done primarily to allow for backwards compatibility between v1 and v2 scaffolder templates. + + Fixes broken GitHub actions templating in the Create React App template. + + #### For those with **custom** preparers, templates, or publishers + + The preparer interface has changed, the prepare method now only takes a single argument, and doesn't return anything. As part of this change the preparers were refactored to accept a URL pointing to the target directory, rather than computing that from the template entity. + + The `workingDirectory` option was also removed, and replaced with a `workspacePath` option. The difference between the two is that `workingDirectory` was a place for the preparer to create temporary directories, while the `workspacePath` is the specific folder were the entire templating process for a single template job takes place. Instead of returning a path to the folder were the prepared contents were placed, the contents are put at the `/template` path. + + ```diff + type PreparerOptions = { + - workingDirectory?: string; + + /** + + * Full URL to the directory containg template data + + */ + + url: string; + + /** + + * The workspace path that will eventually be the the root of the new repo + + */ + + workspacePath: string; + logger: Logger; + }; + + -prepare(template: TemplateEntityV1alpha1, opts?: PreparerOptions): Promise + +prepare(opts: PreparerOptions): Promise; + ``` + + Instead of returning a path to the folder were the templaters contents were placed, the contents are put at the `/result` path. All templaters now also expect the source template to be present in the `template` directory within the `workspacePath`. + + ```diff + export type TemplaterRunOptions = { + - directory: string; + + workspacePath: string; + values: TemplaterValues; + logStream?: Writable; + dockerClient: Docker; + }; + + -public async run(options: TemplaterRunOptions): Promise + +public async run(options: TemplaterRunOptions): Promise + ``` + + Just like the preparer and templaters, the publishers have also switched to using `workspacePath`. The root of the new repo is expected to be located at `/result`. + + ```diff + export type PublisherOptions = { + values: TemplaterValues; + - directory: string; + + workspacePath: string; + logger: Logger; + }; + ``` + +### Patch Changes + +- a26668913: Attempt to fix windows test errors in master +- 529d16d27: # Repo visibility for GitLab and BitBucket repos + + **NOTE: This changes default repo visibility from `private` to `public` for GitLab and BitBucket** which + is consistent with the GitHub default. If you were counting on `private` visibility, you'll need to update + your scaffolder config to use `private`. + + This adds repo visibility feature parity with GitHub for GitLab and BitBucket. + + To configure the repo visibility, set scaffolder._type_.visibility as in this example: + + ```yaml + scaffolder: + github: + visibility: private # 'public' or 'internal' or 'private' (default is 'public') + gitlab: + visibility: public # 'public' or 'internal' or 'private' (default is 'public') + bitbucket: + visibility: public # 'public' or 'private' (default is 'public') + ``` + +- Updated dependencies [c4abcdb60] +- Updated dependencies [2430ee7c2] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [064c513e1] +- Updated dependencies [7881f2117] +- Updated dependencies [3149bfe63] +- Updated dependencies [2e62aea6f] +- Updated dependencies [11cb5ef94] + - @backstage/integration@0.3.2 + - @backstage/backend-common@0.5.2 + - @backstage/catalog-model@0.7.1 + ## 0.5.2 ### Patch Changes diff --git a/plugins/scaffolder-backend/migrations/20210120143715_init.js b/plugins/scaffolder-backend/migrations/20210120143715_init.js new file mode 100644 index 0000000000..256ec7d423 --- /dev/null +++ b/plugins/scaffolder-backend/migrations/20210120143715_init.js @@ -0,0 +1,85 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// @ts-check + +/** + * @param {import('knex')} knex + */ +exports.up = async function up(knex) { + await knex.schema.createTable('tasks', table => { + table.comment('The table of scaffolder tasks'); + table.uuid('id').primary().notNullable().comment('The ID of the task'); + table + .text('spec') + .notNullable() + .comment('A JSON encoded task specification'); + table + .text('status') + .notNullable() + .comment('The current status of the task'); + table + .dateTime('created_at') + .defaultTo(knex.fn.now()) + .notNullable() + .comment('The timestamp when this task was created'); + table + .dateTime('last_heartbeat_at') + .nullable() + .comment('The last timestamp when a heartbeat was received'); + }); + + await knex.schema.createTable('task_events', table => { + table.comment('The event stream a given task'); + table + .bigIncrements('id') + .primary() + .notNullable() + .comment('The ID of the event'); + table + .uuid('task_id') + .references('id') + .inTable('tasks') + .notNullable() + .onDelete('CASCADE') + .comment('The task that generated the event'); + table + .text('body') + .notNullable() + .comment('The JSON encoded body of the event'); + table.text('event_type').notNullable().comment('The type of event'); + table + .timestamp('created_at') + .defaultTo(knex.fn.now()) + .notNullable() + .comment('The timestamp when this event was generated'); + + table.index(['task_id'], 'task_events_task_id_idx'); + }); +}; + +/** + * @param {import('knex')} knex + */ +exports.down = async function down(knex) { + if (knex.client.config.client !== 'sqlite3') { + await knex.schema.alterTable('task_events', table => { + table.dropIndex([], 'ctask_events_task_id_idx'); + }); + } + await knex.schema.dropTable('task_events'); + await knex.schema.dropTable('tasks'); +}; diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 7af9f567e3..ecce161c8e 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "0.5.2", + "version": "0.6.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", - "@backstage/integration": "^0.3.1", + "@backstage/integration": "^0.3.2", "@gitbeaker/core": "^28.0.2", "@gitbeaker/node": "^28.0.2", "@octokit/rest": "^18.0.12", @@ -53,13 +53,14 @@ "helmet": "^4.0.0", "isomorphic-git": "^1.8.0", "jsonschema": "^1.2.6", + "knex": "^0.21.6", "morgan": "^1.10.0", "uuid": "^8.2.0", "winston": "^3.2.1", "yaml": "^1.10.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "@backstage/test-utils": "^0.1.5", "@types/fs-extra": "^9.0.1", "@types/mock-fs": "^4.13.0", @@ -71,6 +72,7 @@ }, "files": [ "dist", + "migrations", "config.d.ts" ], "configSchema": "config.d.ts" diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts b/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts new file mode 100644 index 0000000000..f151780ba9 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/stages/legacy.ts @@ -0,0 +1,110 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TemplateActionRegistry } from '../tasks/TemplateConverter'; +import { FilePreparer, PreparerBuilder } from './prepare'; +import Docker from 'dockerode'; +import { TemplaterBuilder, TemplaterValues } from './templater'; +import { PublisherBuilder } from './publish'; + +type Options = { + dockerClient: Docker; + preparers: PreparerBuilder; + templaters: TemplaterBuilder; + publishers: PublisherBuilder; +}; + +export function registerLegacyActions( + registry: TemplateActionRegistry, + options: Options, +) { + const { dockerClient, preparers, templaters, publishers } = options; + + registry.register({ + id: 'legacy:prepare', + async handler(ctx) { + const { protocol, url } = ctx.parameters; + const preparer = + protocol === 'file' ? new FilePreparer() : preparers.get(url as string); + + ctx.logger.info('Prepare the skeleton'); + await preparer.prepare({ + url: url as string, + logger: ctx.logger, + workspacePath: ctx.workspacePath, + }); + }, + }); + + registry.register({ + id: 'legacy:template', + async handler(ctx) { + const { logger } = ctx; + + const templater = templaters.get(ctx.parameters.templater as string); + + logger.info('Run the templater'); + await templater.run({ + workspacePath: ctx.workspacePath, + dockerClient, + logStream: ctx.logStream, + values: ctx.parameters.values as TemplaterValues, + }); + }, + }); + + registry.register({ + id: 'legacy:publish', + async handler(ctx) { + const { values } = ctx.parameters; + if ( + typeof values !== 'object' || + values === null || + Array.isArray(values) + ) { + throw new Error( + `Invalid values passed to publish, got ${typeof values}`, + ); + } + const storePath = values.storePath as unknown; + if (typeof storePath !== 'string') { + throw new Error( + `Invalid store path passed to publish, got ${typeof storePath}`, + ); + } + const owner = values.owner as unknown; + if (typeof owner !== 'string') { + throw new Error(`Invalid owner passed to publish, got ${typeof owner}`); + } + + const publisher = publishers.get(storePath); + ctx.logger.info('Will now store the template'); + const { remoteUrl, catalogInfoUrl } = await publisher.publish({ + values: { + ...values, + owner, + storePath, + }, + workspacePath: ctx.workspacePath, + logger: ctx.logger, + }); + ctx.output('remoteUrl', remoteUrl); + if (catalogInfoUrl) { + ctx.output('catalogInfoUrl', catalogInfoUrl); + } + }, + }); +} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts new file mode 100644 index 0000000000..5717f3c8c1 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -0,0 +1,272 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { JsonObject } from '@backstage/config'; +import { + ConflictError, + NotFoundError, + resolvePackagePath, +} from '@backstage/backend-common'; +import Knex from 'knex'; +import { v4 as uuid } from 'uuid'; +import { + DbTaskEventRow, + DbTaskRow, + Status, + TaskEventType, + TaskSpec, + TaskStore, + TaskStoreEmitOptions, + TaskStoreGetEventsOptions, +} from './types'; + +const migrationsDir = resolvePackagePath( + '@backstage/plugin-scaffolder-backend', + 'migrations', +); + +export type RawDbTaskRow = { + id: string; + spec: string; + status: Status; + last_heartbeat_at?: string; + created_at: string; +}; + +export type RawDbTaskEventRow = { + id: number; + task_id: string; + body: string; + event_type: TaskEventType; + created_at: string; +}; + +export class DatabaseTaskStore implements TaskStore { + static async create(knex: Knex): Promise { + await knex.migrate.latest({ + directory: migrationsDir, + }); + return new DatabaseTaskStore(knex); + } + + constructor(private readonly db: Knex) {} + + async get(taskId: string): Promise { + const [result] = await this.db('tasks') + .where({ id: taskId }) + .select(); + if (!result) { + throw new NotFoundError(`No task with id '${taskId}' found`); + } + try { + const spec = JSON.parse(result.spec); + return { + id: result.id, + spec, + status: result.status, + lastHeartbeatAt: result.last_heartbeat_at, + createdAt: result.created_at, + }; + } catch (error) { + throw new Error(`Failed to parse spec of task '${taskId}', ${error}`); + } + } + + async createTask(spec: TaskSpec): Promise<{ taskId: string }> { + const taskId = uuid(); + await this.db('tasks').insert({ + id: taskId, + spec: JSON.stringify(spec), + status: 'open', + }); + return { taskId }; + } + + async claimTask(): Promise { + return this.db.transaction(async tx => { + const [task] = await tx('tasks') + .where({ + status: 'open', + }) + .limit(1) + .select(); + + if (!task) { + return undefined; + } + + const updateCount = await tx('tasks') + .where({ id: task.id, status: 'open' }) + .update({ + status: 'processing', + last_heartbeat_at: this.db.fn.now(), + }); + + if (updateCount < 1) { + return undefined; + } + + try { + const spec = JSON.parse(task.spec); + return { + id: task.id, + spec, + status: 'processing', + lastHeartbeatAt: task.last_heartbeat_at, + createdAt: task.created_at, + }; + } catch (error) { + throw new Error(`Failed to parse spec of task '${task.id}', ${error}`); + } + }); + } + + async heartbeatTask(taskId: string): Promise { + const updateCount = await this.db('tasks') + .where({ id: taskId, status: 'processing' }) + .update({ + last_heartbeat_at: this.db.fn.now(), + }); + if (updateCount === 0) { + throw new ConflictError(`No running task with taskId ${taskId} found`); + } + } + + async listStaleTasks({ + timeoutS, + }: { + timeoutS: number; + }): Promise<{ + tasks: { taskId: string }[]; + }> { + const rawRows = await this.db('tasks') + .where('status', 'processing') + .andWhere( + 'last_heartbeat_at', + '<=', + this.db.client.config.client === 'sqlite3' + ? this.db.raw(`datetime('now', ?)`, [`-${timeoutS} seconds`]) + : this.db.raw(`dateadd('second', ?, ?)`, [ + `-${timeoutS}`, + this.db.fn.now(), + ]), + ); + const tasks = rawRows.map(row => ({ + taskId: row.id, + })); + return { tasks }; + } + + async completeTask({ + taskId, + status, + eventBody, + }: { + taskId: string; + status: Status; + eventBody: JsonObject; + }): Promise { + let oldStatus: string; + if (status === 'failed' || status === 'completed') { + oldStatus = 'processing'; + } else { + throw new Error( + `Invalid status update of run '${taskId}' to status '${status}'`, + ); + } + await this.db.transaction(async tx => { + const [task] = await tx('tasks') + .where({ + id: taskId, + }) + .limit(1) + .select(); + + if (!task) { + throw new Error(`No task with taskId ${taskId} found`); + } + if (task.status !== oldStatus) { + throw new ConflictError( + `Refusing to update status of run '${taskId}' to status '${status}' ` + + `as it is currently '${task.status}', expected '${oldStatus}'`, + ); + } + const updateCount = await tx('tasks') + .where({ + id: taskId, + status: oldStatus, + }) + .update({ + status, + }); + if (updateCount !== 1) { + throw new ConflictError( + `Failed to update status to '${status}' for taskId ${taskId}`, + ); + } + + await tx('task_events').insert({ + task_id: taskId, + event_type: 'completion', + body: JSON.stringify(eventBody), + }); + }); + } + + async emitLogEvent({ taskId, body }: TaskStoreEmitOptions): Promise { + const serliazedBody = JSON.stringify(body); + await this.db('task_events').insert({ + task_id: taskId, + event_type: 'log', + body: serliazedBody, + }); + } + + async listEvents({ + taskId, + after, + }: TaskStoreGetEventsOptions): Promise<{ events: DbTaskEventRow[] }> { + const rawEvents = await this.db('task_events') + .where({ + task_id: taskId, + }) + .andWhere(builder => { + if (typeof after === 'number') { + builder.where('id', '>', after).orWhere('event_type', 'completion'); + } + }) + .orderBy('id') + .select(); + + const events = rawEvents.map(event => { + try { + const body = JSON.parse(event.body) as JsonObject; + return { + id: event.id, + taskId, + body, + type: event.event_type, + createdAt: event.created_at, + }; + } catch (error) { + throw new Error( + `Failed to parse event body from event taskId=${taskId} id=${event.id}, ${error}`, + ); + } + }); + return { events }; + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts new file mode 100644 index 0000000000..c45fa46335 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.test.ts @@ -0,0 +1,183 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + getVoidLogger, + SingleConnectionDatabaseManager, +} from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { DatabaseTaskStore } from './DatabaseTaskStore'; +import { StorageTaskBroker, TaskAgent } from './StorageTaskBroker'; +import { TaskSpec, DbTaskEventRow } from './types'; + +async function createStore(): Promise { + const manager = SingleConnectionDatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'sqlite3', + connection: ':memory:', + }, + }, + }), + ).forPlugin('scaffolder'); + return await DatabaseTaskStore.create(await manager.getClient()); +} + +describe('StorageTaskBroker', () => { + let storage: DatabaseTaskStore; + + beforeAll(async () => { + storage = await createStore(); + }); + + const logger = getVoidLogger(); + it('should claim a dispatched work item', async () => { + const broker = new StorageTaskBroker(storage, logger); + await broker.dispatch({ steps: [] }); + await expect(broker.claim()).resolves.toEqual(expect.any(TaskAgent)); + }); + + it('should wait for a dispatched work item', async () => { + const broker = new StorageTaskBroker(storage, logger); + const promise = broker.claim(); + + await expect(Promise.race([promise, 'waiting'])).resolves.toBe('waiting'); + + await broker.dispatch({ steps: [] }); + await expect(promise).resolves.toEqual(expect.any(TaskAgent)); + }); + + it('should dispatch multiple items and claim them in order', async () => { + const broker = new StorageTaskBroker(storage, logger); + await broker.dispatch({ steps: [{ id: 'a' }] } as TaskSpec); + await broker.dispatch({ steps: [{ id: 'b' }] } as TaskSpec); + await broker.dispatch({ steps: [{ id: 'c' }] } as TaskSpec); + + const taskA = await broker.claim(); + const taskB = await broker.claim(); + const taskC = await broker.claim(); + await expect(taskA).toEqual(expect.any(TaskAgent)); + await expect(taskB).toEqual(expect.any(TaskAgent)); + await expect(taskC).toEqual(expect.any(TaskAgent)); + await expect(taskA.spec.steps[0].id).toBe('a'); + await expect(taskB.spec.steps[0].id).toBe('b'); + await expect(taskC.spec.steps[0].id).toBe('c'); + }); + + it('should complete a task', async () => { + const broker = new StorageTaskBroker(storage, logger); + const dispatchResult = await broker.dispatch({ steps: [] }); + const task = await broker.claim(); + await task.complete('completed'); + const taskRow = await storage.get(dispatchResult.taskId); + expect(taskRow.status).toBe('completed'); + }, 10000); + + it('should fail a task', async () => { + const broker = new StorageTaskBroker(storage, logger); + const dispatchResult = await broker.dispatch({ steps: [] }); + const task = await broker.claim(); + await task.complete('failed'); + const taskRow = await storage.get(dispatchResult.taskId); + expect(taskRow.status).toBe('failed'); + }); + + it('multiple brokers should be able to observe a single task', async () => { + const broker1 = new StorageTaskBroker(storage, logger); + const broker2 = new StorageTaskBroker(storage, logger); + + const { taskId } = await broker1.dispatch({ steps: [] }); + + const logPromise = new Promise(resolve => { + const observedEvents = new Array(); + + broker2.observe({ taskId, after: undefined }, (_err, { events }) => { + observedEvents.push(...events); + if (events.some(e => e.type === 'completion')) { + resolve(observedEvents); + } + }); + }); + const task = await broker1.claim(); + await task.emitLog('log 1'); + await task.emitLog('log 2'); + await task.emitLog('log 3'); + await task.complete('completed'); + + const logs = await logPromise; + expect(logs.map(l => l.body.message, logger)).toEqual([ + 'log 1', + 'log 2', + 'log 3', + 'Run completed with status: completed', + ]); + + const afterLogs = await new Promise(resolve => { + broker2.observe({ taskId, after: logs[1].id }, (_err, { events }) => + resolve(events.map(e => e.body.message as string)), + ); + }); + expect(afterLogs).toEqual([ + 'log 3', + 'Run completed with status: completed', + ]); + }); + + it('should heartbeat', async () => { + const broker = new StorageTaskBroker(storage, logger); + const { taskId } = await broker.dispatch({ steps: [] }); + const task = await broker.claim(); + + const initialTask = await storage.get(taskId); + + for (;;) { + const maybeTask = await storage.get(taskId); + if (maybeTask.lastHeartbeatAt !== initialTask.lastHeartbeatAt) { + break; + } + await new Promise(resolve => setTimeout(resolve, 50)); + } + await task.complete('completed'); + expect.assertions(0); + }); + + it('should be update the status to failed if heartbeat fails', async () => { + const broker = new StorageTaskBroker(storage, logger); + const { taskId } = await broker.dispatch({ steps: [] }); + const task = await broker.claim(); + + jest + .spyOn((task as any).storage, 'heartbeatTask') + .mockRejectedValue(new Error('nah m8')); + + const intervalId = setInterval(() => { + broker.vacuumTasks({ timeoutS: 2 }).catch(fail); + }, 500); + + for (;;) { + const maybeTask = await storage.get(taskId); + if (maybeTask.status === 'failed') { + break; + } + await new Promise(resolve => setTimeout(resolve, 50)); + } + + clearInterval(intervalId); + + expect(task.done).toBe(true); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts new file mode 100644 index 0000000000..48c0d5e5ba --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts @@ -0,0 +1,205 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Logger } from 'winston'; +import { + CompletedTaskState, + Task, + TaskSpec, + TaskStore, + TaskBroker, + DispatchResult, + DbTaskEventRow, +} from './types'; + +export class TaskAgent implements Task { + private isDone = false; + + private heartbeatTimeoutId?: ReturnType; + + static create(state: TaskState, storage: TaskStore, logger: Logger) { + const agent = new TaskAgent(state, storage, logger); + agent.startTimeout(); + return agent; + } + + // Runs heartbeat internally + private constructor( + private readonly state: TaskState, + private readonly storage: TaskStore, + private readonly logger: Logger, + ) {} + + get spec() { + return this.state.spec; + } + + async getWorkspaceName() { + return this.state.taskId; + } + + get done() { + return this.isDone; + } + + async emitLog(message: string): Promise { + await this.storage.emitLogEvent({ + taskId: this.state.taskId, + body: { message }, + }); + } + + async complete(result: CompletedTaskState): Promise { + await this.storage.completeTask({ + taskId: this.state.taskId, + status: result === 'failed' ? 'failed' : 'completed', + eventBody: { message: `Run completed with status: ${result}` }, + }); + this.isDone = true; + if (this.heartbeatTimeoutId) { + clearTimeout(this.heartbeatTimeoutId); + } + } + + private startTimeout() { + this.heartbeatTimeoutId = setTimeout(async () => { + try { + await this.storage.heartbeatTask(this.state.taskId); + this.startTimeout(); + } catch (error) { + this.isDone = true; + + this.logger.error( + `Heartbeat for task ${this.state.taskId} failed`, + error, + ); + } + }, 1000); + } +} + +interface TaskState { + spec: TaskSpec; + taskId: string; +} + +function defer() { + let resolve = () => {}; + const promise = new Promise(_resolve => { + resolve = _resolve; + }); + return { promise, resolve }; +} + +export class StorageTaskBroker implements TaskBroker { + constructor( + private readonly storage: TaskStore, + private readonly logger: Logger, + ) {} + private deferredDispatch = defer(); + + async claim(): Promise { + for (;;) { + const pendingTask = await this.storage.claimTask(); + if (pendingTask) { + return TaskAgent.create( + { + taskId: pendingTask.id, + spec: pendingTask.spec, + }, + this.storage, + this.logger, + ); + } + + await this.waitForDispatch(); + } + } + + async dispatch(spec: TaskSpec): Promise { + const taskRow = await this.storage.createTask(spec); + this.signalDispatch(); + return { + taskId: taskRow.taskId, + }; + } + + observe( + options: { + taskId: string; + after: number | undefined; + }, + callback: ( + error: Error | undefined, + result: { events: DbTaskEventRow[] }, + ) => void, + ): () => void { + const { taskId } = options; + + let cancelled = false; + const unsubscribe = () => { + cancelled = true; + }; + + (async () => { + let after = options.after; + while (!cancelled) { + const result = await this.storage.listEvents({ taskId, after: after }); + const { events } = result; + if (events.length) { + after = events[events.length - 1].id; + try { + callback(undefined, result); + } catch (error) { + callback(error, { events: [] }); + } + } + + await new Promise(resolve => setTimeout(resolve, 1000)); + } + })(); + + return unsubscribe; + } + + async vacuumTasks(timeoutS: { timeoutS: number }): Promise { + const { tasks } = await this.storage.listStaleTasks(timeoutS); + await Promise.all( + tasks.map(async task => { + try { + await this.storage.completeTask({ + taskId: task.taskId, + status: 'failed', + eventBody: { + message: + 'The task was cancelled because the task worker lost connection to the task broker', + }, + }); + } catch (error) { + this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`); + } + }), + ); + } + + private waitForDispatch() { + return this.deferredDispatch.promise; + } + + private signalDispatch() { + this.deferredDispatch.resolve(); + this.deferredDispatch = defer(); + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts new file mode 100644 index 0000000000..c62495ca4c --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts @@ -0,0 +1,110 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PassThrough } from 'stream'; +import { Logger } from 'winston'; +import * as winston from 'winston'; +import { JsonValue } from '@backstage/config'; +import { TaskBroker, Task } from './types'; +import fs from 'fs-extra'; +import path from 'path'; +import { TemplateActionRegistry } from './TemplateConverter'; + +type Options = { + logger: Logger; + taskBroker: TaskBroker; + workingDirectory: string; + actionRegistry: TemplateActionRegistry; +}; + +export class TaskWorker { + constructor(private readonly options: Options) {} + + start() { + (async () => { + for (;;) { + const task = await this.options.taskBroker.claim(); + await this.runOneTask(task); + } + })(); + } + + async runOneTask(task: Task) { + try { + const { actionRegistry, logger } = this.options; + + const workspacePath = path.join( + this.options.workingDirectory, + await task.getWorkspaceName(), + ); + await fs.ensureDir(workspacePath); + + const taskLogger = winston.createLogger({ + level: process.env.LOG_LEVEL || 'info', + format: winston.format.combine( + winston.format.colorize(), + winston.format.timestamp(), + winston.format.simple(), + ), + defaultMeta: {}, + }); + + const stream = new PassThrough(); + stream.on('data', data => { + const message = data.toString().trim(); + if (message?.length > 1) task.emitLog(message); + }); + + taskLogger.add(new winston.transports.Stream({ stream })); + + // Give us some time to curl observe + task.emitLog('Task claimed, waiting ...'); + await new Promise(resolve => setTimeout(resolve, 5000)); + task.emitLog(`Starting up work with ${task.spec.steps.length} steps`); + + const outputs: { [name: string]: JsonValue } = {}; + + for (const step of task.spec.steps) { + task.emitLog(`Beginning step ${step.name}`); + + const action = actionRegistry.get(step.action); + if (!action) { + throw new Error(`Action '${step.action}' does not exist`); + } + + // TODO: substitute any placeholders with output from previous steps + const parameters = step.parameters!; + + await action.handler({ + logger, + logStream: stream, + parameters, + workspacePath, + output(name: string, value: JsonValue) { + outputs[name] = value; + }, + }); + + task.emitLog(`Finished step ${step.name}`); + } + + await task.complete('completed'); + } catch (error) { + task.emitLog(String(error.stack)); + await task.complete('failed'); + } + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts new file mode 100644 index 0000000000..69788238cc --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TemplateConverter.ts @@ -0,0 +1,117 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { resolve as resolvePath } from 'path'; +import { JsonValue } from '@backstage/config'; +import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; +import { Logger } from 'winston'; +import type { Writable } from 'stream'; + +import { TaskSpec } from './types'; +import { ConflictError, NotFoundError } from '@backstage/backend-common'; +import { + getTemplaterKey, + joinGitUrlPath, + parseLocationAnnotation, + TemplaterValues, +} from '../stages'; + +export function templateEntityToSpec( + template: TemplateEntityV1alpha1, + values: TemplaterValues, +): TaskSpec { + const steps: TaskSpec['steps'] = []; + + const { protocol, location } = parseLocationAnnotation(template); + + let url: string; + if (protocol === 'file') { + const path = resolvePath(location, template.spec.path || '.'); + + url = `file://${path}`; + } else { + url = joinGitUrlPath(location, template.spec.path); + } + const templater = getTemplaterKey(template); + + steps.push({ + id: 'prepare', + name: 'Prepare', + action: 'legacy:prepare', + parameters: { + protocol, + url, + }, + }); + + steps.push({ + id: 'template', + name: 'Template', + action: 'legacy:template', + parameters: { + templater, + values, + }, + }); + + steps.push({ + id: 'publish', + name: 'Publishing', + action: 'legacy:publish', + parameters: { + values, + }, + }); + + return { steps }; +} + +type ActionContext = { + logger: Logger; + logStream: Writable; + + workspacePath: string; + parameters: { [name: string]: JsonValue }; + output(name: string, value: JsonValue): void; +}; + +type TemplateAction = { + id: string; + handler: (ctx: ActionContext) => Promise; +}; + +export class TemplateActionRegistry { + private readonly actions = new Map(); + + register(action: TemplateAction) { + if (this.actions.has(action.id)) { + throw new ConflictError( + `Template action with ID '${action.id}' has already been registered`, + ); + } + this.actions.set(action.id, action); + } + + get(actionId: string): TemplateAction { + const action = this.actions.get(actionId); + if (!action) { + throw new NotFoundError( + `Template action with ID '${actionId}' is not registered.`, + ); + } + return action; + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/index.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/index.ts new file mode 100644 index 0000000000..c85135426e --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { DatabaseTaskStore } from './DatabaseTaskStore'; +export { StorageTaskBroker } from './StorageTaskBroker'; +export { TaskWorker } from './TaskWorker'; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts new file mode 100644 index 0000000000..0c2592109b --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts @@ -0,0 +1,111 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { JsonValue, JsonObject } from '@backstage/config'; + +export type Status = + | 'open' + | 'processing' + | 'failed' + | 'cancelled' + | 'completed'; + +export type CompletedTaskState = 'failed' | 'completed'; + +export type DbTaskRow = { + id: string; + spec: TaskSpec; + status: Status; + createdAt: string; + lastHeartbeatAt?: string; +}; + +export type TaskEventType = 'completion' | 'log'; +export type DbTaskEventRow = { + id: number; + taskId: string; + body: JsonObject; + type: TaskEventType; + createdAt: string; +}; + +export type TaskSpec = { + steps: Array<{ + id: string; + name: string; + action: string; + parameters?: { [name: string]: JsonValue }; + }>; +}; + +export type DispatchResult = { + taskId: string; +}; + +export interface Task { + spec: TaskSpec; + done: boolean; + emitLog(message: string): Promise; + complete(result: CompletedTaskState): Promise; + getWorkspaceName(): Promise; +} + +export interface TaskBroker { + claim(): Promise; + dispatch(spec: TaskSpec): Promise; + vacuumTasks(timeoutS: { timeoutS: number }): Promise; + observe( + options: { + taskId: string; + after: number | undefined; + }, + callback: ( + error: Error | undefined, + result: { events: DbTaskEventRow[] }, + ) => void, + ): () => void; +} + +export type TaskStoreEmitOptions = { + taskId: string; + body: JsonObject; +}; + +export type TaskStoreGetEventsOptions = { + taskId: string; + after?: number | undefined; +}; +export interface TaskStore { + createTask(task: TaskSpec): Promise<{ taskId: string }>; + claimTask(): Promise; + completeTask(options: { + taskId: string; + status: Status; + eventBody: JsonObject; + }): Promise; + heartbeatTask(taskId: string): Promise; + listStaleTasks(options: { + timeoutS: number; + }): Promise<{ + tasks: { taskId: string }[]; + }>; + + emitLogEvent({ taskId, body }: TaskStoreEmitOptions): Promise; + listEvents({ + taskId, + after, + }: TaskStoreGetEventsOptions): Promise<{ events: DbTaskEventRow[] }>; +} diff --git a/plugins/scaffolder-backend/src/service/helpers.ts b/plugins/scaffolder-backend/src/service/helpers.ts new file mode 100644 index 0000000000..dd3d43c6d1 --- /dev/null +++ b/plugins/scaffolder-backend/src/service/helpers.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import os from 'os'; +import fs from 'fs-extra'; +import { Logger } from 'winston'; +import { Config } from '@backstage/config'; + +export async function getWorkingDirectory( + config: Config, + logger: Logger, +): Promise { + if (!config.has('backend.workingDirectory')) { + return os.tmpdir(); + } + + const workingDirectory = config.getString('backend.workingDirectory'); + try { + // Check if working directory exists and is writable + await fs.access(workingDirectory, fs.constants.F_OK | fs.constants.W_OK); + logger.info(`using working directory: ${workingDirectory}`); + } catch (err) { + logger.error( + `working directory ${workingDirectory} ${ + err.code === 'ENOENT' ? 'does not exist' : 'is not writable' + }`, + ); + throw err; + } + return workingDirectory; +} diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 31f62febd2..8a0fa6cba6 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -16,6 +16,7 @@ const mockAccess = jest.fn(); jest.doMock('fs-extra', () => ({ + access: mockAccess, promises: { access: mockAccess, }, @@ -27,7 +28,11 @@ jest.doMock('fs-extra', () => ({ remove: jest.fn(), })); -import { getVoidLogger } from '@backstage/backend-common'; +import { + SingleConnectionDatabaseManager, + PluginDatabaseManager, + getVoidLogger, +} from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import express from 'express'; import request from 'supertest'; @@ -41,6 +46,19 @@ const generateEntityClient: any = (template: any) => ({ findTemplate: () => Promise.resolve(template), }); +function createDatabase(): PluginDatabaseManager { + return SingleConnectionDatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'sqlite3', + connection: ':memory:', + }, + }, + }), + ).forPlugin('scaffolder'); +} + describe('createRouter - working directory', () => { const mockPrepare = jest.fn(); const mockPreparers = new Preparers(); @@ -78,7 +96,6 @@ describe('createRouter - working directory', () => { }; const mockedEntityClient = generateEntityClient(template); - it('should throw an error when working directory does not exist or is not writable', async () => { mockAccess.mockImplementation(() => { throw new Error('access error'); @@ -93,6 +110,7 @@ describe('createRouter - working directory', () => { config: new ConfigReader(workDirConfig('/path')), dockerClient: new Docker(), entityClient: mockedEntityClient, + database: createDatabase(), }), ).rejects.toThrow('access error'); }); @@ -106,6 +124,7 @@ describe('createRouter - working directory', () => { config: new ConfigReader(workDirConfig('/path')), dockerClient: new Docker(), entityClient: mockedEntityClient, + database: createDatabase(), }); const app = express().use(router); @@ -134,6 +153,7 @@ describe('createRouter - working directory', () => { config: new ConfigReader({}), dockerClient: new Docker(), entityClient: mockedEntityClient, + database: createDatabase(), }); const app = express().use(router); @@ -203,6 +223,7 @@ describe('createRouter', () => { config: new ConfigReader({}), dockerClient: new Docker(), entityClient: generateEntityClient(template), + database: createDatabase(), }); app = express().use(router); }); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 9098e5d05e..5821edfe8c 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -33,6 +33,18 @@ import { import { CatalogEntityClient } from '../lib/catalog'; import { validate, ValidatorResult } from 'jsonschema'; import parseGitUrl from 'git-url-parse'; +import { + DatabaseTaskStore, + StorageTaskBroker, + TaskWorker, +} from '../scaffolder/tasks'; +import { + TemplateActionRegistry, + templateEntityToSpec, +} from '../scaffolder/tasks/TemplateConverter'; +import { registerLegacyActions } from '../scaffolder/stages/legacy'; +import { getWorkingDirectory } from './helpers'; +import { PluginDatabaseManager } from '@backstage/backend-common'; export interface RouterOptions { preparers: PreparerBuilder; @@ -43,6 +55,7 @@ export interface RouterOptions { config: Config; dockerClient: Docker; entityClient: CatalogEntityClient; + database: PluginDatabaseManager; } export async function createRouter( @@ -59,11 +72,34 @@ export async function createRouter( config, dockerClient, entityClient, + database, } = options; const logger = parentLogger.child({ plugin: 'scaffolder' }); + const workingDirectory = await getWorkingDirectory(config, logger); const jobProcessor = await JobProcessor.fromConfig({ config, logger }); + const databaseTaskStore = await DatabaseTaskStore.create( + await database.getClient(), + ); + const taskBroker = new StorageTaskBroker(databaseTaskStore, logger); + const actionRegistry = new TemplateActionRegistry(); + const worker = new TaskWorker({ + logger, + taskBroker, + actionRegistry, + workingDirectory, + }); + + registerLegacyActions(actionRegistry, { + dockerClient, + preparers, + publishers, + templaters, + }); + + worker.start(); + router .get('/v1/job/:jobId', ({ params }, res) => { const job = jobProcessor.get(params.jobId); @@ -184,6 +220,75 @@ export async function createRouter( res.status(201).json({ id: job.id }); }); + // NOTE: The v2 API is unstable + router + .post('/v2/tasks', async (req, res) => { + const templateName: string = req.body.templateName; + const values: TemplaterValues = { + ...req.body.values, + destination: { + git: parseGitUrl(req.body.values.storePath), + }, + }; + const template = await entityClient.findTemplate(templateName); + + const validationResult: ValidatorResult = validate( + values, + template.spec.schema, + ); + + if (!validationResult.valid) { + res.status(400).json({ errors: validationResult.errors }); + return; + } + const taskSpec = templateEntityToSpec(template, values); + const result = await taskBroker.dispatch(taskSpec); + + res.status(201).json({ id: result.taskId }); + }) + .get('/v2/tasks/:taskId/eventstream', async (req, res) => { + const { taskId } = req.params; + const after = Number(req.query.after) || undefined; + logger.debug(`Event stream observing taskId '${taskId}' opened`); + + // Mandatory headers and http status to keep connection open + res.writeHead(200, { + Connection: 'keep-alive', + 'Cache-Control': 'no-cache', + 'Content-Type': 'text/event-stream', + }); + + // After client opens connection send all events as string + const unsubscribe = taskBroker.observe( + { taskId, after }, + (error, { events }) => { + if (error) { + logger.error( + `Received error from event stream when observing taskId '${taskId}', ${error}`, + ); + } + + for (const event of events) { + res.write( + `event: ${event.type}\ndata: ${JSON.stringify(event)}\n\n`, + ); + if (event.type === 'completion') { + unsubscribe(); + // Closing the event stream here would cause the frontend + // to automatically reconnect because it lost connection. + } + } + res.flush(); + }, + ); + // When client closes connection we update the clients list + // avoiding the disconnected one + req.on('close', () => { + unsubscribe(); + logger.debug(`Event stream observing taskId '${taskId}' closed`); + }); + }); + const app = express(); app.set('logger', logger); app.use('/', router); diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 11a9cfb75c..cd7c8fe685 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-scaffolder +## 0.4.2 + +### Patch Changes + +- 720149854: Migrated to new composability API, exporting the plugin as `scaffolderPlugin`. The template list page (`/create`) is exported as the `TemplateIndexPage` extension, and the templating page itself is exported as `TemplatePage`. +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.4.1 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 69021953a2..56beb7b10b 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "0.4.1", + "version": "0.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,10 +30,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -51,8 +51,8 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@backstage/catalog-client": "^0.3.5", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index 35590bc2d7..383cb3c484 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-search +## 0.2.7 + +### Patch Changes + +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.2.6 ### Patch Changes diff --git a/plugins/search/dev/index.tsx b/plugins/search/dev/index.tsx index 264d6f801f..e6e97ead6d 100644 --- a/plugins/search/dev/index.tsx +++ b/plugins/search/dev/index.tsx @@ -14,6 +14,6 @@ * limitations under the License. */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { searchPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(searchPlugin).render(); diff --git a/plugins/search/package.json b/plugins/search/package.json index 28627b88ea..6142e65dd3 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "0.2.6", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/catalog-model": "^0.7.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/catalog-model": "^0.7.1", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -43,8 +43,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/search/src/index.ts b/plugins/search/src/index.ts index 77ad7f9266..572d75bea5 100644 --- a/plugins/search/src/index.ts +++ b/plugins/search/src/index.ts @@ -13,5 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { plugin } from './plugin'; -export * from './components'; +export { searchPlugin, searchPlugin as plugin, SearchPage } from './plugin'; +export { + Filters, + FiltersButton, + SearchBar, + SearchPage as Router, + SearchResult, + SidebarSearch, +} from './components'; +export type { FiltersState } from './components'; diff --git a/plugins/search/src/plugin.test.ts b/plugins/search/src/plugin.test.ts index 92b8d5bcbf..902faeaf9e 100644 --- a/plugins/search/src/plugin.test.ts +++ b/plugins/search/src/plugin.test.ts @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { plugin } from './plugin'; +import { searchPlugin } from './plugin'; describe('search', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(searchPlugin).toBeDefined(); }); }); diff --git a/plugins/search/src/plugin.ts b/plugins/search/src/plugin.ts index 44c7bcb042..37503b7751 100644 --- a/plugins/search/src/plugin.ts +++ b/plugins/search/src/plugin.ts @@ -13,17 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createPlugin, createRouteRef } from '@backstage/core'; -import { SearchPage } from './components/SearchPage'; +import { + createPlugin, + createRouteRef, + createRoutableExtension, +} from '@backstage/core'; +import { SearchPage as SearchPageComponent } from './components/SearchPage'; export const rootRouteRef = createRouteRef({ path: '/search', title: 'search', }); -export const plugin = createPlugin({ +export const searchPlugin = createPlugin({ id: 'search', register({ router }) { - router.addRoute(rootRouteRef, SearchPage); + router.addRoute(rootRouteRef, SearchPageComponent); + }, + routes: { + root: rootRouteRef, }, }); + +export const SearchPage = searchPlugin.provide( + createRoutableExtension({ + component: () => import('./components/SearchPage').then(m => m.SearchPage), + mountPoint: rootRouteRef, + }), +); diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index 92d88ece8a..698f72020c 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-sentry +## 0.3.4 + +### Patch Changes + +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.3.3 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 38e1c55ed0..06b538289b 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sentry", - "version": "0.3.3", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,10 +31,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -46,8 +46,8 @@ "timeago.js": "^4.0.2" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index c3be5e7415..c422f9d72e 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-sonarqube +## 0.1.10 + +### Patch Changes + +- 8dfdec613: Migrate to new composability API, exporting the plugin as `sonarQubePlugin` and card as `EntitySonarQubeCard`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.1.9 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index c286dd9dac..a31ee320f2 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube", - "version": "0.1.9", + "version": "0.1.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,10 +32,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/plugin-catalog-react": "^0.0.1", - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/catalog-model": "^0.7.1", + "@backstage/plugin-catalog-react": "^0.0.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -47,8 +47,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index 9325827eb9..49a5f8bfcd 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-tech-radar +## 0.3.4 + +### Patch Changes + +- 90c8f20b9: Fix mapping RadarEntry and Entry for moved and url attributes + Fix clicking of links in the radar legend +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + ## 0.3.3 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 9014d52931..a5c9f7bb53 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-radar", - "version": "0.3.3", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -43,8 +43,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index fab57f2a00..28ba4e032c 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-techdocs-backend +## 0.5.5 + +### Patch Changes + +- c777df180: 1. Added option to use Azure Blob Storage as a choice to store the static generated files for TechDocs. +- e44925723: `techdocs.requestUrl` and `techdocs.storageUrl` are now optional configs and the discovery API will be used to get the URL where techdocs plugin is hosted. +- Updated dependencies [c777df180] +- Updated dependencies [2430ee7c2] +- Updated dependencies [6e612ce25] +- Updated dependencies [e44925723] +- Updated dependencies [025e122c3] +- Updated dependencies [7881f2117] +- Updated dependencies [f0320190d] +- Updated dependencies [11cb5ef94] + - @backstage/techdocs-common@0.3.7 + - @backstage/backend-common@0.5.2 + - @backstage/catalog-model@0.7.1 + ## 0.5.4 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index e6af442d20..36e5bd3bcd 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "0.5.4", + "version": "0.5.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,10 +30,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.5.1", - "@backstage/catalog-model": "^0.7.0", + "@backstage/backend-common": "^0.5.2", + "@backstage/catalog-model": "^0.7.1", "@backstage/config": "^0.1.2", - "@backstage/techdocs-common": "^0.3.6", + "@backstage/techdocs-common": "^0.3.7", "@types/dockerode": "^3.2.1", "@types/express": "^4.17.6", "cross-fetch": "^3.0.6", @@ -45,7 +45,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.5.0", + "@backstage/cli": "^0.6.0", "supertest": "^4.0.2" }, "files": [ diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 5d2d04aaee..69fe41dd32 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,35 @@ # @backstage/plugin-techdocs +## 0.5.5 + +### Patch Changes + +- 5fa3bdb55: Add `href` in addition to `onClick` to `ItemCard`. Ensure that the height of a + `ItemCard` with and without tags is equal. +- e44925723: `techdocs.requestUrl` and `techdocs.storageUrl` are now optional configs and the discovery API will be used to get the URL where techdocs plugin is hosted. +- 019fe39a0: Switch dependency from `@backstage/plugin-catalog` to `@backstage/plugin-catalog-react`. +- Updated dependencies [c777df180] +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [7fc89bae2] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [6e612ce25] +- Updated dependencies [e44925723] +- Updated dependencies [025e122c3] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [7881f2117] +- Updated dependencies [f0320190d] +- Updated dependencies [54c7d02f7] +- Updated dependencies [11cb5ef94] + - @backstage/techdocs-common@0.3.7 + - @backstage/core@0.6.0 + - @backstage/plugin-catalog-react@0.0.2 + - @backstage/theme@0.2.3 + - @backstage/catalog-model@0.7.1 + ## 0.5.4 ### Patch Changes diff --git a/plugins/techdocs/dev/index.tsx b/plugins/techdocs/dev/index.tsx index 42fa9a9ec4..4cf74c9622 100644 --- a/plugins/techdocs/dev/index.tsx +++ b/plugins/techdocs/dev/index.tsx @@ -16,7 +16,7 @@ import { configApiRef, discoveryApiRef } from '@backstage/core'; import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { techdocsPlugin } from '../src/plugin'; import { TechDocsDevStorageApi } from './api'; import { techdocsStorageApiRef } from '../src'; @@ -30,5 +30,5 @@ createDevApp() discoveryApi, }), }) - .registerPlugin(plugin) + .registerPlugin(techdocsPlugin) .render(); diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 20e294c661..ad9e1f7bef 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "0.5.4", + "version": "0.5.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,12 +32,12 @@ }, "dependencies": { "@backstage/config": "^0.1.2", - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", + "@backstage/catalog-model": "^0.7.1", + "@backstage/core": "^0.6.0", + "@backstage/plugin-catalog-react": "^0.0.2", "@backstage/test-utils": "^0.1.6", - "@backstage/theme": "^0.2.2", - "@backstage/techdocs-common": "^0.3.6", + "@backstage/theme": "^0.2.3", + "@backstage/techdocs-common": "^0.3.7", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -50,8 +50,8 @@ "sanitize-html": "^1.27.0" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/techdocs/src/Router.tsx b/plugins/techdocs/src/Router.tsx index 262f542ee6..b220912174 100644 --- a/plugins/techdocs/src/Router.tsx +++ b/plugins/techdocs/src/Router.tsx @@ -16,6 +16,7 @@ import React from 'react'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; import { Route, Routes } from 'react-router-dom'; import { MissingAnnotationEmptyState } from '@backstage/core'; import { @@ -38,7 +39,14 @@ export const Router = () => { ); }; -export const EmbeddedDocsRouter = ({ entity }: { entity: Entity }) => { +type Props = { + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; +}; + +export const EmbeddedDocsRouter = (_props: Props) => { + const { entity } = useEntity(); + const projectId = entity.metadata.annotations?.[TECHDOCS_ANNOTATION]; if (!projectId) { diff --git a/plugins/techdocs/src/api.ts b/plugins/techdocs/src/api.ts index a8b1f1e34f..7f77be44e2 100644 --- a/plugins/techdocs/src/api.ts +++ b/plugins/techdocs/src/api.ts @@ -157,14 +157,23 @@ export class TechDocsStorageApi implements TechDocsStorage { `${url.endsWith('/') ? url : `${url}/`}index.html`, ); - if (request.status === 404) { - let errorMessage = 'Page not found. '; - // path is empty for the home page of an entity's docs site - if (!path) { - errorMessage += - 'This could be because there is no index.md file in the root of the docs directory of this repository.'; - } - throw new Error(errorMessage); + let errorMessage = ''; + switch (request.status) { + case 404: + errorMessage = 'Page not found. '; + // path is empty for the home page of an entity's docs site + if (!path) { + errorMessage += + 'This could be because there is no index.md file in the root of the docs directory of this repository.'; + } + throw new Error(errorMessage); + case 500: + errorMessage = + 'Could not generate documentation or an error in the TechDocs backend. '; + throw new Error(errorMessage); + default: + // Do nothing + break; } return request.text(); diff --git a/plugins/techdocs/src/index.ts b/plugins/techdocs/src/index.ts index 1726e0daf3..30c143e31f 100644 --- a/plugins/techdocs/src/index.ts +++ b/plugins/techdocs/src/index.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -export { plugin } from './plugin'; +export { + techdocsPlugin, + techdocsPlugin as plugin, + TechdocsPage, + EntityTechdocsContent, +} from './plugin'; export { Router, EmbeddedDocsRouter } from './Router'; export * from './reader'; export * from './api'; diff --git a/plugins/techdocs/src/plugin.test.ts b/plugins/techdocs/src/plugin.test.ts index e750be9ac3..52f072627c 100644 --- a/plugins/techdocs/src/plugin.test.ts +++ b/plugins/techdocs/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { techdocsPlugin } from './plugin'; describe('techdocs', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(techdocsPlugin).toBeDefined(); }); }); diff --git a/plugins/techdocs/src/plugin.ts b/plugins/techdocs/src/plugin.ts index 982b749f2c..0b4063c237 100644 --- a/plugins/techdocs/src/plugin.ts +++ b/plugins/techdocs/src/plugin.ts @@ -35,6 +35,7 @@ import { createApiFactory, configApiRef, discoveryApiRef, + createRoutableExtension, } from '@backstage/core'; import { techdocsStorageApiRef, @@ -58,7 +59,7 @@ export const rootCatalogDocsRouteRef = createRouteRef({ title: 'Docs', }); -export const plugin = createPlugin({ +export const techdocsPlugin = createPlugin({ id: 'techdocs', apis: [ createApiFactory({ @@ -80,4 +81,22 @@ export const plugin = createPlugin({ }), }), ], + routes: { + root: rootRouteRef, + entityContent: rootCatalogDocsRouteRef, + }, }); + +export const TechdocsPage = techdocsPlugin.provide( + createRoutableExtension({ + component: () => import('./Router').then(m => m.Router), + mountPoint: rootRouteRef, + }), +); + +export const EntityTechdocsContent = techdocsPlugin.provide( + createRoutableExtension({ + component: () => import('./Router').then(m => m.EmbeddedDocsRouter), + mountPoint: rootCatalogDocsRouteRef, + }), +); diff --git a/plugins/techdocs/src/reader/components/Reader.tsx b/plugins/techdocs/src/reader/components/Reader.tsx index 50990911a1..c651f1ec13 100644 --- a/plugins/techdocs/src/reader/components/Reader.tsx +++ b/plugins/techdocs/src/reader/components/Reader.tsx @@ -155,7 +155,9 @@ export const Reader = ({ entityId, onReady }: Props) => { ]); if (error) { - return ; + // TODO Enhance API call to return customize error objects so we can identify which we ran into + // For now this defaults to display error code 404 + return ; } return ( diff --git a/plugins/techdocs/src/reader/components/TechDocsNotFound.test.tsx b/plugins/techdocs/src/reader/components/TechDocsNotFound.test.tsx index d3c98fec78..c6562ec8ad 100644 --- a/plugins/techdocs/src/reader/components/TechDocsNotFound.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsNotFound.test.tsx @@ -41,3 +41,20 @@ describe('', ( expect(rendered.getByTestId('go-back-link')).toBeDefined(); }); }); + +describe('', () => { + it('should render with a custom status code, custom error message and go back link', () => { + const rendered = render( + wrapInTestApp( + , + ), + ); + rendered.getByText(/This is a custom error message/i); + rendered.getByText(/500/i); + rendered.getByText(/Looks like someone dropped the mic!/i); + expect(rendered.getByTestId('go-back-link')).toBeDefined(); + }); +}); diff --git a/plugins/techdocs/src/reader/components/TechDocsNotFound.tsx b/plugins/techdocs/src/reader/components/TechDocsNotFound.tsx index cdacc1cb7e..04f2106161 100644 --- a/plugins/techdocs/src/reader/components/TechDocsNotFound.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsNotFound.tsx @@ -19,9 +19,10 @@ import { ErrorPage, useApi, configApiRef } from '@backstage/core'; type Props = { errorMessage?: string; + statusCode?: number; }; -export const TechDocsNotFound = ({ errorMessage }: Props) => { +export const TechDocsNotFound = ({ errorMessage, statusCode }: Props) => { const techdocsBuilder = useApi(configApiRef).getOptionalString( 'techdocs.builder', ); @@ -37,7 +38,7 @@ export const TechDocsNotFound = ({ errorMessage }: Props) => { return ( diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index c9abbf2747..467f207754 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-user-settings +## 0.2.5 + +### Patch Changes + +- bc5082a00: Migrate to new composability API, exporting the plugin as `userSettingsPlugin` and the page as `UserSettingsPage`. +- de98c32ed: Keep the Pin Sidebar setting visible on small screens. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + ## 0.2.4 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 78790a891e..88453e8efb 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -41,8 +41,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/plugins/welcome/CHANGELOG.md b/plugins/welcome/CHANGELOG.md index a1eaf43dc4..594d30226a 100644 --- a/plugins/welcome/CHANGELOG.md +++ b/plugins/welcome/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-welcome +## 0.2.5 + +### Patch Changes + +- 8dfdec613: Migrated to new composability API, exporting the plugin as `welcomePlugin` and the page as `WelcomePage`. +- Updated dependencies [12ece98cd] +- Updated dependencies [d82246867] +- Updated dependencies [c810082ae] +- Updated dependencies [5fa3bdb55] +- Updated dependencies [21e624ba9] +- Updated dependencies [da9f53c60] +- Updated dependencies [32c95605f] +- Updated dependencies [54c7d02f7] + - @backstage/core@0.6.0 + - @backstage/theme@0.2.3 + ## 0.2.4 ### Patch Changes diff --git a/plugins/welcome/package.json b/plugins/welcome/package.json index 9482e34743..f3d50dc675 100644 --- a/plugins/welcome/package.json +++ b/plugins/welcome/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-welcome", - "version": "0.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -30,8 +30,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@backstage/theme": "^0.2.2", + "@backstage/core": "^0.6.0", + "@backstage/theme": "^0.2.3", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -41,8 +41,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.5.0", - "@backstage/dev-utils": "^0.1.8", + "@backstage/cli": "^0.6.0", + "@backstage/dev-utils": "^0.1.9", "@backstage/test-utils": "^0.1.6", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/yarn.lock b/yarn.lock index 060205f11e..a16fc49a9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2583,7 +2583,7 @@ to-fast-properties "^2.0.0" "@backstage/catalog-model@^0.2.0": - version "0.7.0" + version "0.7.1" dependencies: "@backstage/config" "^0.1.2" "@types/json-schema" "^7.0.5" @@ -2595,7 +2595,7 @@ yup "^0.29.3" "@backstage/catalog-model@^0.3.0": - version "0.7.0" + version "0.7.1" dependencies: "@backstage/config" "^0.1.2" "@types/json-schema" "^7.0.5" @@ -2607,11 +2607,11 @@ yup "^0.29.3" "@backstage/core@^0.3.0": - version "0.5.0" + version "0.6.0" dependencies: "@backstage/config" "^0.1.2" "@backstage/core-api" "^0.2.8" - "@backstage/theme" "^0.2.2" + "@backstage/theme" "^0.2.3" "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.45" @@ -2645,6 +2645,54 @@ remark-gfm "^1.0.0" zen-observable "^0.8.15" +"@backstage/plugin-catalog@^0.2.0": + version "0.3.0" + dependencies: + "@backstage/catalog-client" "^0.3.5" + "@backstage/catalog-model" "^0.7.1" + "@backstage/core" "^0.6.0" + "@backstage/plugin-catalog-react" "^0.0.2" + "@backstage/plugin-scaffolder" "^0.4.2" + "@backstage/theme" "^0.2.3" + "@material-ui/core" "^4.11.0" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.45" + "@types/react" "^16.9" + classnames "^2.2.6" + git-url-parse "^11.4.4" + moment "^2.26.0" + react "^16.13.1" + react-dom "^16.13.1" + react-helmet "6.1.0" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-use "^15.3.3" + swr "^0.3.0" + +"@backstage/plugin-catalog@^0.2.1": + version "0.3.0" + dependencies: + "@backstage/catalog-client" "^0.3.5" + "@backstage/catalog-model" "^0.7.1" + "@backstage/core" "^0.6.0" + "@backstage/plugin-catalog-react" "^0.0.2" + "@backstage/plugin-scaffolder" "^0.4.2" + "@backstage/theme" "^0.2.3" + "@material-ui/core" "^4.11.0" + "@material-ui/icons" "^4.9.1" + "@material-ui/lab" "4.0.0-alpha.45" + "@types/react" "^16.9" + classnames "^2.2.6" + git-url-parse "^11.4.4" + moment "^2.26.0" + react "^16.13.1" + react-dom "^16.13.1" + react-helmet "6.1.0" + react-router "6.0.0-beta.0" + react-router-dom "6.0.0-beta.0" + react-use "^15.3.3" + swr "^0.3.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -2674,19 +2722,7 @@ resolve-from "^5.0.0" semver "^5.4.1" -"@changesets/assemble-release-plan@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-4.0.0.tgz#60c2392c0e2c99f24778ab3a5c8e8c80ddaaaa59" - integrity sha512-3Kv21FNvysTQvZs3fHr6aZeDibhZHtgI1++fMZplzVtwNVmpjow3zv9lcZmJP26LthbpVH3I8+nqlU7M43lfWA== - dependencies: - "@babel/runtime" "^7.10.4" - "@changesets/errors" "^0.1.4" - "@changesets/get-dependents-graph" "^1.1.3" - "@changesets/types" "^3.1.0" - "@manypkg/get-packages" "^1.0.1" - semver "^5.4.1" - -"@changesets/assemble-release-plan@^4.1.0": +"@changesets/assemble-release-plan@^4.0.0", "@changesets/assemble-release-plan@^4.1.0": version "4.1.0" resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-4.1.0.tgz#091e5e768dfe51835937e71d1ebaca1c9d6de55b" integrity sha512-dMqe2L5Pn4UGTW89kOuuCuZD3pQFZj1Sxv92ZW4S98sXGsxcb2PdW+PeHbQ7tawkCYCOvzhXxAlN4OdF2DlDKQ== @@ -2734,20 +2770,7 @@ term-size "^2.1.0" tty-table "^2.8.10" -"@changesets/config@^1.2.0": - version "1.4.0" - resolved "https://registry.npmjs.org/@changesets/config/-/config-1.4.0.tgz#c157a4121f198b749f2bbc2e9015b6e976ece7d6" - integrity sha512-eoTOcJ6py7jBDY8rUXwEGxR5UtvUX+p//0NhkVpPGcnvIeITHq+DOIsuWyGzWcb+1FaYkof3CCr32/komZTu4Q== - dependencies: - "@changesets/errors" "^0.1.4" - "@changesets/get-dependents-graph" "^1.1.3" - "@changesets/logger" "^0.0.5" - "@changesets/types" "^3.2.0" - "@manypkg/get-packages" "^1.0.1" - fs-extra "^7.0.1" - micromatch "^4.0.2" - -"@changesets/config@^1.5.0": +"@changesets/config@^1.2.0", "@changesets/config@^1.5.0": version "1.5.0" resolved "https://registry.npmjs.org/@changesets/config/-/config-1.5.0.tgz#6d58b01e45916318d3f39e9cde86a5d69dc58ed8" integrity sha512-Bl9nLVYcwFCpd9jpzcOsExZk1NuTYX20D2YWHCdS1xll3W0yOdSUlWLUCCfugN1l3+yTR6iDW6q9o6vpCevWvA== @@ -2767,17 +2790,6 @@ dependencies: extendable-error "^0.1.5" -"@changesets/get-dependents-graph@^1.1.3": - version "1.1.3" - resolved "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.1.3.tgz#da959c43ce98f3a990a6b8d9c1f894bcc1b629c7" - integrity sha512-cTbySXwSv9yWp4Pp5R/b5Qv23wJgFaFCqUbsI3IJ2pyPl0vMaODAZS8NI1nNK2XSxGIg1tw+dWNSR4PlrKBSVQ== - dependencies: - "@changesets/types" "^3.0.0" - "@manypkg/get-packages" "^1.0.1" - chalk "^2.1.0" - fs-extra "^7.0.1" - semver "^5.4.1" - "@changesets/get-dependents-graph@^1.2.0": version "1.2.0" resolved "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.2.0.tgz#6986927a5fec60bc6fcc76f966efae2ac30c05ed" @@ -2807,19 +2819,7 @@ resolved "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz#8131a99035edd11aa7a44c341cbb05e668618c67" integrity sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg== -"@changesets/git@^1.0.5": - version "1.0.6" - resolved "https://registry.npmjs.org/@changesets/git/-/git-1.0.6.tgz#057e627e5d3fcb74bf6c18d7284e130ba5a7632e" - integrity sha512-e0M06XuME3W5lGhz+CO0vLc60u+hLk/pYjOx/6GXEWuQrwtGgeycFIfRgRt8qTs664o1oKtVHBbd7ItpoWgFfA== - dependencies: - "@babel/runtime" "^7.10.4" - "@changesets/errors" "^0.1.4" - "@changesets/types" "^3.1.1" - "@manypkg/get-packages" "^1.0.1" - is-subdir "^1.1.1" - spawndamnit "^2.0.0" - -"@changesets/git@^1.1.0": +"@changesets/git@^1.0.5", "@changesets/git@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@changesets/git/-/git-1.1.0.tgz#ecaa8058ac87b450c09da0e74b68e6854cd0742c" integrity sha512-f/2rQynT+JiAL/V0V/GQdXhLkcb86ELg3UwH3fQO4wVdfUbE9NHIHq9ohJdH1Ymh0Lv48F/b38aWZ5v2sKiF3w== @@ -2839,9 +2839,9 @@ chalk "^2.1.0" "@changesets/parse@^0.3.6": - version "0.3.6" - resolved "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.6.tgz#8c2c8480fc07d2db2c37469d4a8df10906a989c6" - integrity sha512-0XPd/es9CfogI7XIqDr7I2mWzm++xX2s9GZsij3GajPYd7ouEsgJyNatPooxNtqj6ZepkiD6uqlqbeBUyj/A0Q== + version "0.3.7" + resolved "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.7.tgz#1368136e2b83d5cff11b4d383a3032723530db99" + integrity sha512-8yqKulslq/7V2VRBsJqPgjnZMoehYqhJm5lEOXJPZ2rcuSdyj8+p/2vq2vRDBJT2m0rP+C9G8DujsGYQIFZezw== dependencies: "@changesets/types" "^3.0.0" js-yaml "^3.13.1" @@ -2871,12 +2871,7 @@ fs-extra "^7.0.1" p-filter "^2.1.0" -"@changesets/types@^3.0.0", "@changesets/types@^3.1.0", "@changesets/types@^3.1.1", "@changesets/types@^3.2.0": - version "3.2.0" - resolved "https://registry.npmjs.org/@changesets/types/-/types-3.2.0.tgz#d8306d7219c3b19b6d860ddeb9d7374e2dd6b035" - integrity sha512-rAmPtOyXpisEEE25CchKNUAf2ApyAeuZ/h78YDoqKZaCk5tUD0lgYZGPIRV9WTPoqNjJULIym37ogc6pkax5jg== - -"@changesets/types@^3.3.0": +"@changesets/types@^3.0.0", "@changesets/types@^3.1.0", "@changesets/types@^3.1.1", "@changesets/types@^3.3.0": version "3.3.0" resolved "https://registry.npmjs.org/@changesets/types/-/types-3.3.0.tgz#04cd8184b2d2da760667bd89bf9b930938dbd96e" integrity sha512-rJamRo+OD/MQekImfIk07JZwYSB18iU6fYL8xOg0gfAiTh1a1+OlR1fPIxm55I7RsWw812is2YcPPwXdIewrhA== @@ -13841,12 +13836,12 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-versions@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" - integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== +find-versions@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" + integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== dependencies: - semver-regex "^2.0.0" + semver-regex "^3.1.2" find-yarn-workspace-root2@1.2.16: version "1.2.16" @@ -15452,17 +15447,17 @@ humanize-ms@^1.2.1: ms "^2.0.0" husky@^4.2.3: - version "4.3.6" - resolved "https://registry.npmjs.org/husky/-/husky-4.3.6.tgz#ebd9dd8b9324aa851f1587318db4cccb7665a13c" - integrity sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag== + version "4.3.8" + resolved "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" + integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== dependencies: chalk "^4.0.0" ci-info "^2.0.0" compare-versions "^3.6.0" cosmiconfig "^7.0.0" - find-versions "^3.2.0" + find-versions "^4.0.0" opencollective-postinstall "^2.0.2" - pkg-dir "^4.2.0" + pkg-dir "^5.0.0" please-upgrade-node "^3.2.0" slash "^3.0.0" which-pm-runs "^1.0.0" @@ -20784,6 +20779,13 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== + dependencies: + find-up "^5.0.0" + pkg-up@3.1.0, pkg-up@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" @@ -23193,10 +23195,10 @@ rollup-plugin-postcss@^3.1.1: safe-identifier "^0.4.1" style-inject "^0.3.0" -rollup-plugin-typescript2@^0.27.3: - version "0.27.3" - resolved "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.27.3.tgz#cd9455ac026d325b20c5728d2cc54a08a771b68b" - integrity sha512-gmYPIFmALj9D3Ga1ZbTZAKTXq1JKlTQBtj299DXhqYz9cL3g/AQfUvbb2UhH+Nf++cCq941W2Mv7UcrcgLzJJg== +rollup-plugin-typescript2@^0.29.0: + version "0.29.0" + resolved "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.29.0.tgz#b7ad83f5241dbc5bdf1e98d9c3fca005ffe39e1a" + integrity sha512-YytahBSZCIjn/elFugEGQR5qTsVhxhUwGZIsA9TmrSsC88qroGo65O5HZP/TTArH2dm0vUmYWhKchhwi2wL9bw== dependencies: "@rollup/pluginutils" "^3.1.0" find-cache-dir "^3.3.1" @@ -23405,10 +23407,10 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -semver-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" - integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== +semver-regex@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz#34b4c0d361eef262e07199dbef316d0f2ab11807" + integrity sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA== "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1"