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-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/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-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/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-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/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/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/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/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-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/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/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/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/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-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/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/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/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/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/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/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/.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/app-config.yaml b/app-config.yaml index 763dd0c258..5240a050a8 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -74,8 +74,6 @@ organization: # Reference documentation http://backstage.io/docs/features/techdocs/configuration techdocs: - requestUrl: http://localhost:7000/api/techdocs - storageUrl: http://localhost:7000/api/techdocs/static/docs builder: 'local' # Alternatives - 'external' generators: techdocs: 'docker' # Alternatives - 'local' diff --git a/docs/features/techdocs/configuration.md b/docs/features/techdocs/configuration.md index bb44050dcf..20e436d8a4 100644 --- a/docs/features/techdocs/configuration.md +++ b/docs/features/techdocs/configuration.md @@ -13,15 +13,6 @@ configuration options for TechDocs. # File: app-config.yaml techdocs: - # TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc. - - requestUrl: http://localhost:7000/api/techdocs - - # Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware - # to serve files from either a local directory or an External storage provider. - - storageUrl: http://localhost:7000/api/techdocs/static/docs - # generators.techdocs can have two values: 'docker' or 'local'. This is to determine how to run the generator - whether to # spin up the techdocs-container docker image or to run mkdocs locally (assuming all the dependencies are taken care of). # You want to change this to 'local' if you are running Backstage using your own custom Docker setup and want to avoid running @@ -101,4 +92,15 @@ techdocs: # https://docs.microsoft.com/en-us/azure/storage/common/storage-auth?toc=/azure/storage/blobs/toc.json accountKey: $env: TECHDOCS_AZURE_BLOB_STORAGE_ACCOUNT_KEY + + # (Optional and Legacy) TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc. + # You don't have to specify this anymore. + + requestUrl: http://localhost:7000/api/techdocs + + # (Optional and Legacy) Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware + # to serve files from either a local directory or an External storage provider. + # You don't have to specify this anymore. + + storageUrl: http://localhost:7000/api/techdocs/static/docs ``` diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index 5147e17aaa..e0b323857d 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -150,26 +150,10 @@ app. Now let us tweak some configurations to suit your needs. **See [TechDocs Configuration Options](configuration.md) for complete configuration reference.** -### Setting TechDocs URLs - -```yaml -techdocs: - storageUrl: http://localhost:7000/api/techdocs/static/docs - requestUrl: http://localhost:7000/api/techdocs/ -``` - -`requestUrl` is used by TechDocs frontend plugin to discover `techdocs-backend` -endpoints, and the `storageUrl` is another endpoint in `techdocs-backend` which -acts as a middleware between TechDocs and the storage (where the static -generated docs site are stored). These default values should mostly work for -you. These options will soon be optional to set. - ### Should TechDocs Backend generate docs? ```yaml techdocs: - storageUrl: http://localhost:7000/api/techdocs/static/docs - requestUrl: http://localhost:7000/api/techdocs/ builder: 'local' ``` @@ -196,8 +180,6 @@ out Backstage for the first time. At a later time, review ```yaml techdocs: - storageUrl: http://localhost:7000/api/techdocs/static/docs - requestUrl: http://localhost:7000/api/techdocs/ builder: 'local' publisher: type: 'local' @@ -219,6 +201,9 @@ no config is provided. ```yaml techdocs: + builder: 'local' + publisher: + type: 'local' generators: techdocs: local ``` 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 758a8ba884..fd130fcbbd 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ }, "version": "1.0.0", "devDependencies": { - "@changesets/cli": "^2.11.0", + "@changesets/cli": "^2.14.0", "@octokit/openapi-types": "^2.2.0", "@spotify/eslint-config-oss": "^1.0.1", "@spotify/prettier-config": "^9.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 9de8299d93..9b82e0bb32 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/app/src/App.tsx b/packages/app/src/App.tsx index 1b76773979..00696736d1 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -15,30 +15,30 @@ */ import { - createApp, AlertDisplay, - OAuthRequestDialog, - SignInPage, + createApp, createRouteRef, FlatRoutes, + OAuthRequestDialog, + SignInPage, } from '@backstage/core'; -import React from 'react'; -import Root from './components/Root'; -import * as plugins from './plugins'; -import { apis } from './apis'; -import { hot } from 'react-hot-loader/root'; -import { providers } from './identityProviders'; import { Router as CatalogRouter } from '@backstage/plugin-catalog'; -import { Router as DocsRouter } from '@backstage/plugin-techdocs'; +import { Router as ImportComponentRouter } from '@backstage/plugin-catalog-import'; +import { ExplorePage } from '@backstage/plugin-explore'; import { Router as GraphiQLRouter } from '@backstage/plugin-graphiql'; -import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar'; import { Router as LighthouseRouter } from '@backstage/plugin-lighthouse'; import { Router as RegisterComponentRouter } from '@backstage/plugin-register-component'; +import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar'; +import { Router as DocsRouter } from '@backstage/plugin-techdocs'; import { Router as SettingsRouter } from '@backstage/plugin-user-settings'; -import { Router as ImportComponentRouter } from '@backstage/plugin-catalog-import'; -import { Route, Navigate } from 'react-router'; - +import React from 'react'; +import { hot } from 'react-hot-loader/root'; +import { Navigate, Route } from 'react-router'; +import { apis } from './apis'; import { EntityPage } from './components/catalog/EntityPage'; +import Root from './components/Root'; +import { providers } from './identityProviders'; +import * as plugins from './plugins'; const app = createApp({ apis, @@ -78,6 +78,7 @@ const routes = ( element={} /> } /> + } /> } diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 52dd397418..80706fe459 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -20,6 +20,7 @@ import HomeIcon from '@material-ui/icons/Home'; import ExtensionIcon from '@material-ui/icons/Extension'; import RuleIcon from '@material-ui/icons/AssignmentTurnedIn'; import MapIcon from '@material-ui/icons/MyLocation'; +import LayersIcon from '@material-ui/icons/Layers'; import LibraryBooks from '@material-ui/icons/LibraryBooks'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; import MoneyIcon from '@material-ui/icons/MonetizationOn'; @@ -82,6 +83,7 @@ const Root = ({ children }: PropsWithChildren<{}>) => ( + {/* End global nav */} diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 0372c8759c..5474afa72c 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { ApiEntity, Entity, @@ -64,6 +65,10 @@ import { isPluginApplicableToEntity as isPagerDutyAvailable, PagerDutyCard, } from '@backstage/plugin-pagerduty'; +import { + isRollbarAvailable, + Router as RollbarRouter, +} from '@backstage/plugin-rollbar'; import { Router as SentryRouter } from '@backstage/plugin-sentry'; import { EmbeddedDocsRouter as DocsRouter } from '@backstage/plugin-techdocs'; import { Button, Grid } from '@material-ui/core'; @@ -153,6 +158,15 @@ const RecentCICDRunsSwitcher = ({ entity }: { entity: Entity }) => { ); }; +export const ErrorsSwitcher = ({ entity }: { entity: Entity }) => { + switch (true) { + case isRollbarAvailable(entity): + return ; + default: + return ; + } +}; + const ComponentOverviewContent = ({ entity }: { entity: Entity }) => ( @@ -212,9 +226,9 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => ( element={} /> } + path="/errors/*" + title="Errors" + element={} /> ( element={} /> } + path="/errors/*" + title="Errors" + element={} /> Promise) { } describe('UrlReaders', () => { + jest.setTimeout(30_000); + it( 'should read data from azure', withRetries(3, async () => { diff --git a/packages/backend-common/src/reading/tree/TarArchiveResponse.ts b/packages/backend-common/src/reading/tree/TarArchiveResponse.ts index 96d3a5d495..24bfa3f1a8 100644 --- a/packages/backend-common/src/reading/tree/TarArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/TarArchiveResponse.ts @@ -15,7 +15,7 @@ */ import tar, { Parse, ParseStream, ReadEntry } from 'tar'; -import path from 'path'; +import platformPath from 'path'; import fs from 'fs-extra'; import { Readable, pipeline as pipelineCb } from 'stream'; import { promisify } from 'util'; @@ -147,7 +147,7 @@ export class TarArchiveResponse implements ReadTreeResponse { const dir = options?.targetDir ?? - (await fs.mkdtemp(path.join(this.workDir, 'backstage-'))); + (await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-'))); // Equivalent of tar --strip-components=N // When no subPath is given, remove just 1 top level directory diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts index 37ff32741f..323f7b4778 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import path from 'path'; +import platformPath from 'path'; import fs from 'fs-extra'; import unzipper, { Entry } from 'unzipper'; import archiver from 'archiver'; @@ -144,7 +144,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { const dir = options?.targetDir ?? - (await fs.mkdtemp(path.join(this.workDir, 'backstage-'))); + (await fs.mkdtemp(platformPath.join(this.workDir, 'backstage-'))); await this.stream .pipe(unzipper.Parse()) @@ -155,11 +155,11 @@ export class ZipArchiveResponse implements ReadTreeResponse { const entryPath = this.getInnerPath( this.stripTopDirectory(entry.path), ); - const dirname = path.dirname(entryPath); + const dirname = platformPath.dirname(entryPath); if (dirname) { - await fs.mkdirp(path.join(dir, dirname)); + await fs.mkdirp(platformPath.join(dir, dirname)); } - entry.pipe(fs.createWriteStream(path.join(dir, entryPath))); + entry.pipe(fs.createWriteStream(platformPath.join(dir, entryPath))); } else { entry.autodrain(); } 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/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/catalog-model/src/entity/index.ts b/packages/catalog-model/src/entity/index.ts index 4afb8f5c96..e80e14f7a4 100644 --- a/packages/catalog-model/src/entity/index.ts +++ b/packages/catalog-model/src/entity/index.ts @@ -27,6 +27,7 @@ export type { } from './Entity'; export * from './policies'; export { + compareEntityToRef, getEntityName, parseEntityName, parseEntityRef, diff --git a/packages/catalog-model/src/entity/ref.test.ts b/packages/catalog-model/src/entity/ref.test.ts index bd7cc9477d..5ca511ee03 100644 --- a/packages/catalog-model/src/entity/ref.test.ts +++ b/packages/catalog-model/src/entity/ref.test.ts @@ -16,7 +16,12 @@ import { ENTITY_DEFAULT_NAMESPACE } from './constants'; import { Entity } from './Entity'; -import { parseEntityName, parseEntityRef, serializeEntityRef } from './ref'; +import { + compareEntityToRef, + parseEntityName, + parseEntityRef, + serializeEntityRef, +} from './ref'; describe('ref', () => { describe('parseEntityName', () => { @@ -381,4 +386,320 @@ describe('ref', () => { ).toEqual({ kind: 'a', namespace: 'b', name: 'c/x' }); }); }); + + describe('compareEntityToRef', () => { + const entityWithNamespace: Entity = { + apiVersion: 'a', + kind: 'K', + metadata: { + name: 'n', + namespace: 'ns', + }, + }; + const entityWithoutNamespace: Entity = { + apiVersion: 'a', + kind: 'K', + metadata: { + name: 'n', + }, + }; + + it('handles matching string refs', () => { + expect(compareEntityToRef(entityWithNamespace, 'K:ns/n')).toBe(true); + expect(compareEntityToRef(entityWithNamespace, 'k:nS/N')).toBe(true); + expect( + compareEntityToRef(entityWithNamespace, 'K:n', { + defaultNamespace: 'ns', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithNamespace, 'K:n', { + defaultNamespace: 'Ns', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithNamespace, 'ns/n', { defaultKind: 'K' }), + ).toBe(true); + expect( + compareEntityToRef(entityWithNamespace, 'n', { + defaultKind: 'K', + defaultNamespace: 'ns', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithNamespace, 'N', { + defaultKind: 'k', + defaultNamespace: 'nS', + }), + ).toBe(true); + + expect(compareEntityToRef(entityWithoutNamespace, 'K:default/n')).toBe( + true, + ); + expect(compareEntityToRef(entityWithoutNamespace, 'K:deFault/n')).toBe( + true, + ); + expect( + compareEntityToRef(entityWithoutNamespace, 'K:n', { + defaultNamespace: 'default', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithoutNamespace, 'K:n', { + defaultNamespace: 'deFault', + }), + ).toBe(true); + expect(compareEntityToRef(entityWithoutNamespace, 'K:default/n')).toBe( + true, + ); + expect(compareEntityToRef(entityWithoutNamespace, 'K:n')).toBe(true); + expect( + compareEntityToRef(entityWithoutNamespace, 'default/n', { + defaultKind: 'K', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithoutNamespace, 'n', { + defaultKind: 'K', + defaultNamespace: 'default', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithoutNamespace, 'n', { + defaultKind: 'K', + }), + ).toBe(true); + }); + + it('handles mismatching string refs', () => { + expect(compareEntityToRef(entityWithNamespace, 'X:ns/n')).toBe(false); + expect( + compareEntityToRef(entityWithoutNamespace, 'ns/n', { + defaultKind: 'X', + }), + ).toBe(false); + + expect(compareEntityToRef(entityWithNamespace, 'K:xx/n')).toBe(false); + expect( + compareEntityToRef(entityWithoutNamespace, 'K:n', { + defaultNamespace: 'xx', + }), + ).toBe(false); + + expect(compareEntityToRef(entityWithNamespace, 'K:ns/x')).toBe(false); + expect( + compareEntityToRef(entityWithoutNamespace, 'x', { + defaultKind: 'K', + defaultNamespace: 'ns', + }), + ).toBe(false); + }); + + it('handles matching compound refs', () => { + expect( + compareEntityToRef(entityWithNamespace, { + kind: 'K', + namespace: 'ns', + name: 'n', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithNamespace, { + kind: 'k', + namespace: 'Ns', + name: 'N', + }), + ).toBe(true); + expect( + compareEntityToRef( + entityWithNamespace, + { kind: 'K', name: 'n' }, + { + defaultNamespace: 'ns', + }, + ), + ).toBe(true); + expect( + compareEntityToRef( + entityWithNamespace, + { namespace: 'ns', name: 'n' }, + { defaultKind: 'K' }, + ), + ).toBe(true); + expect( + compareEntityToRef(entityWithNamespace, 'n', { + defaultKind: 'K', + defaultNamespace: 'ns', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithNamespace, 'N', { + defaultKind: 'k', + defaultNamespace: 'nS', + }), + ).toBe(true); + + expect( + compareEntityToRef(entityWithoutNamespace, { + kind: 'K', + namespace: 'default', + name: 'n', + }), + ).toBe(true); + expect( + compareEntityToRef(entityWithoutNamespace, { + kind: 'k', + namespace: 'deFault', + name: 'N', + }), + ).toBe(true); + expect( + compareEntityToRef( + entityWithoutNamespace, + { kind: 'K', name: 'n' }, + { + defaultNamespace: 'default', + }, + ), + ).toBe(true); + expect( + compareEntityToRef(entityWithoutNamespace, { kind: 'K', name: 'n' }), + ).toBe(true); + expect( + compareEntityToRef( + entityWithoutNamespace, + { namespace: 'default', name: 'n' }, + { + defaultKind: 'K', + }, + ), + ).toBe(true); + expect( + compareEntityToRef( + entityWithoutNamespace, + { name: 'n' }, + { + defaultKind: 'K', + defaultNamespace: 'default', + }, + ), + ).toBe(true); + expect( + compareEntityToRef( + entityWithoutNamespace, + { name: 'N' }, + { + defaultKind: 'k', + defaultNamespace: 'defAult', + }, + ), + ).toBe(true); + expect( + compareEntityToRef( + entityWithoutNamespace, + { name: 'n' }, + { + defaultKind: 'K', + }, + ), + ).toBe(true); + }); + + it('handles mismatching compound refs', () => { + expect( + compareEntityToRef(entityWithNamespace, { + kind: 'X', + namespace: 'ns', + name: 'n', + }), + ).toBe(false); + expect( + compareEntityToRef( + entityWithNamespace, + { + namespace: 'ns', + name: 'n', + }, + { defaultKind: 'X' }, + ), + ).toBe(false); + expect( + compareEntityToRef(entityWithoutNamespace, { + kind: 'X', + namespace: 'default', + name: 'n', + }), + ).toBe(false); + expect( + compareEntityToRef( + entityWithoutNamespace, + { + namespace: 'default', + name: 'n', + }, + { defaultKind: 'X' }, + ), + ).toBe(false); + + expect( + compareEntityToRef(entityWithNamespace, { + kind: 'K', + namespace: 'xx', + name: 'n', + }), + ).toBe(false); + expect( + compareEntityToRef( + entityWithNamespace, + { + kind: 'K', + name: 'n', + }, + { defaultNamespace: 'xx' }, + ), + ).toBe(false); + expect( + compareEntityToRef(entityWithoutNamespace, { + kind: 'K', + namespace: 'xx', + name: 'n', + }), + ).toBe(false); + expect( + compareEntityToRef( + entityWithoutNamespace, + { + kind: 'K', + name: 'n', + }, + { defaultNamespace: 'xx' }, + ), + ).toBe(false); + + expect( + compareEntityToRef(entityWithNamespace, { + kind: 'K', + namespace: 'ns', + name: 'x', + }), + ).toBe(false); + expect( + compareEntityToRef(entityWithoutNamespace, { + kind: 'K', + namespace: 'default', + name: 'x', + }), + ).toBe(false); + expect( + compareEntityToRef( + entityWithoutNamespace, + { + kind: 'K', + name: 'x', + }, + { defaultNamespace: 'default' }, + ), + ).toBe(false); + }); + }); }); diff --git a/packages/catalog-model/src/entity/ref.ts b/packages/catalog-model/src/entity/ref.ts index 9f6f175d8d..bf34962d01 100644 --- a/packages/catalog-model/src/entity/ref.ts +++ b/packages/catalog-model/src/entity/ref.ts @@ -18,6 +18,27 @@ import { EntityName, EntityRef } from '../types'; import { ENTITY_DEFAULT_NAMESPACE } from './constants'; import { Entity } from './Entity'; +function parseRefString( + ref: string, +): { + kind?: string; + namespace?: string; + name: string; +} { + const match = /^([^:/]+:)?([^:/]+\/)?([^:/]+)$/.exec(ref.trim()); + if (!match) { + throw new TypeError( + `Entity reference "${ref}" was not on the form [:][/]`, + ); + } + + return { + kind: match[1]?.slice(0, -1), + namespace: match[2]?.slice(0, -1), + name: match[3], + }; +} + /** * Extracts the kind, namespace and name that form the name triplet of the * given entity. @@ -121,17 +142,11 @@ export function parseEntityRef( } if (typeof ref === 'string') { - const match = /^([^:/]+:)?([^:/]+\/)?([^:/]+)$/.exec(ref.trim()); - if (!match) { - throw new Error( - `Entity reference "${ref}" was not on the form [:][/]`, - ); - } - + const parsed = parseRefString(ref); return { - kind: match[1]?.slice(0, -1) ?? context.defaultKind, - namespace: match[2]?.slice(0, -1) ?? context.defaultNamespace, - name: match[3], + kind: parsed.kind ?? context.defaultKind, + namespace: parsed.namespace ?? context.defaultNamespace, + name: parsed.name, }; } @@ -196,3 +211,53 @@ export function serializeEntityRef( return `${kind ? `${kind}:` : ''}${namespace ? `${namespace}/` : ''}${name}`; } + +/** + * Compares an entity to either a string reference or a compound reference. + * + * The comparison is case insensitive, and all of kind, namespace, and name + * must match (after applying the optional context to the ref). + * + * @param entity The entity to match + * @param ref A string or compound entity ref + * @param context An optional context of default kind and namespace, that apply + * to the ref if given + * @returns True if matching, false otherwise + */ +export function compareEntityToRef( + entity: Entity, + ref: EntityRef | EntityName, + context?: EntityRefContext, +): boolean { + const entityKind = entity.kind; + const entityNamespace = entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE; + const entityName = entity.metadata.name; + + let refKind: string | undefined; + let refNamespace: string | undefined; + let refName: string; + if (typeof ref === 'string') { + const parsed = parseRefString(ref); + refKind = parsed.kind || context?.defaultKind; + refNamespace = + parsed.namespace || context?.defaultNamespace || ENTITY_DEFAULT_NAMESPACE; + refName = parsed.name; + } else { + refKind = ref.kind || context?.defaultKind; + refNamespace = + ref.namespace || context?.defaultNamespace || ENTITY_DEFAULT_NAMESPACE; + refName = ref.name; + } + + if (!refKind || !refNamespace) { + throw new Error( + `Entity reference or context did not contain kind and namespace`, + ); + } + + return ( + entityKind.toLowerCase() === refKind.toLowerCase() && + entityNamespace.toLowerCase() === refNamespace.toLowerCase() && + entityName.toLowerCase() === refName.toLowerCase() + ); +} 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/config/eslint.backend.js b/packages/cli/config/eslint.backend.js index 7acb538d38..e7fd4cb688 100644 --- a/packages/cli/config/eslint.backend.js +++ b/packages/cli/config/eslint.backend.js @@ -38,8 +38,10 @@ module.exports = { }, ignorePatterns: ['.eslintrc.js', '**/dist/**', '**/dist-types/**'], rules: { - '@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', 'no-console': 0, // Permitted in console programs 'new-cap': ['error', { capIsNew: false }], // Because Express constructs things e.g. like 'const r = express.Router()' diff --git a/packages/cli/config/eslint.js b/packages/cli/config/eslint.js index 044d737d15..37bd7bed94 100644 --- a/packages/cli/config/eslint.js +++ b/packages/cli/config/eslint.js @@ -45,8 +45,10 @@ module.exports = { }, ignorePatterns: ['.eslintrc.js', '**/dist/**', '**/dist-types/**'], rules: { - '@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', 'no-undef': 'off', 'import/newline-after-import': 'error', 'import/no-duplicates': 'warn', diff --git a/packages/cli/package.json b/packages/cli/package.json index ed373f6058..fb33a154a7 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", @@ -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/cli/src/commands/config/print.ts b/packages/cli/src/commands/config/print.ts index 56dcd3f753..930f2c98ca 100644 --- a/packages/cli/src/commands/config/print.ts +++ b/packages/cli/src/commands/config/print.ts @@ -63,8 +63,8 @@ function serializeConfigData( } const sanitizedConfigs = schema.process(appConfigs, { - valueTransform: (value, { visibility }) => - visibility === 'secret' ? '' : value, + valueTransform: (value, context) => + context.visibility === 'secret' ? '' : value, }); return ConfigReader.fromConfigs(sanitizedConfigs).get(); diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index 987d4f6f31..31803d4827 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -108,7 +108,7 @@ describe('bump', () => { paths.targetDir = '/'; jest .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...paths) => resolvePath('/', ...paths)); + .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'runPlain').mockImplementation(async (...[, , , name]) => JSON.stringify({ type: 'inspect', @@ -204,7 +204,7 @@ describe('bump', () => { paths.targetDir = '/'; jest .spyOn(paths, 'resolveTargetRoot') - .mockImplementation((...paths) => resolvePath('/', ...paths)); + .mockImplementation((...path) => resolvePath('/', ...path)); jest.spyOn(runObj, 'runPlain').mockImplementation(async () => ''); jest.spyOn(runObj, 'run').mockResolvedValue(undefined); diff --git a/packages/cli/src/lib/bundler/LinkedPackageResolvePlugin.ts b/packages/cli/src/lib/bundler/LinkedPackageResolvePlugin.ts index 0478337c61..fed8b39a19 100644 --- a/packages/cli/src/lib/bundler/LinkedPackageResolvePlugin.ts +++ b/packages/cli/src/lib/bundler/LinkedPackageResolvePlugin.ts @@ -41,7 +41,7 @@ export class LinkedPackageResolvePlugin implements ResolvePlugin { callback: () => void, ) => { const pkg = this.packages.find( - pkg => data.path && isChildPath(pkg.location, data.path), + pkge => data.path && isChildPath(pkge.location, data.path), ); if (!pkg) { callback(); diff --git a/packages/cli/src/lib/bundler/paths.ts b/packages/cli/src/lib/bundler/paths.ts index f38416ca4e..c8d48a7199 100644 --- a/packages/cli/src/lib/bundler/paths.ts +++ b/packages/cli/src/lib/bundler/paths.ts @@ -42,14 +42,14 @@ export type BundlingPathsOptions = { export function resolveBundlingPaths(options: BundlingPathsOptions) { const { entry } = options; - const resolveTargetModule = (path: string) => { + const resolveTargetModule = (pathString: string) => { for (const ext of ['mjs', 'js', 'ts', 'tsx', 'jsx']) { - const filePath = paths.resolveTarget(`${path}.${ext}`); + const filePath = paths.resolveTarget(`${pathString}.${ext}`); if (fs.pathExistsSync(filePath)) { return filePath; } } - return paths.resolveTarget(`${path}.js`); + return paths.resolveTarget(`${pathString}.js`); }; let targetPublic = undefined; 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/config-loader/src/lib/schema/collect.ts b/packages/config-loader/src/lib/schema/collect.ts index 0e53562875..611413931e 100644 --- a/packages/config-loader/src/lib/schema/collect.ts +++ b/packages/config-loader/src/lib/schema/collect.ts @@ -118,7 +118,9 @@ export async function collectConfigSchemas( } await Promise.all( - depNames.map(name => processItem({ name, parentPath: pkgPath })), + depNames.map(depName => + processItem({ name: depName, parentPath: pkgPath }), + ), ); } 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/lib/AuthConnector/DirectAuthConnector.ts b/packages/core-api/src/lib/AuthConnector/DirectAuthConnector.ts index 517bf82ae7..e7764fcbaa 100644 --- a/packages/core-api/src/lib/AuthConnector/DirectAuthConnector.ts +++ b/packages/core-api/src/lib/AuthConnector/DirectAuthConnector.ts @@ -13,12 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - AuthProvider, - ProfileInfo, - BackstageIdentity, - DiscoveryApi, -} from '../../apis/definitions'; +import { AuthProvider, DiscoveryApi } from '../../apis/definitions'; import { showLoginPopup } from '../loginPopup'; type Options = { @@ -26,13 +21,6 @@ type Options = { environment?: string; provider: AuthProvider & { id: string }; }; - -export type DirectAuthResponse = { - userId: string; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; - export class DirectAuthConnector { private readonly discoveryApi: DiscoveryApi; private readonly environment: string | undefined; diff --git a/packages/core-api/src/routing/FlatRoutes.tsx b/packages/core-api/src/routing/FlatRoutes.tsx index a6783964a7..cefb347290 100644 --- a/packages/core-api/src/routing/FlatRoutes.tsx +++ b/packages/core-api/src/routing/FlatRoutes.tsx @@ -25,8 +25,8 @@ type RouteObject = { // Similar to the same function from react-router, this collects routes from the // children, but only the first level of routes -function createRoutesFromChildren(children: ReactNode): RouteObject[] { - return Children.toArray(children) +function createRoutesFromChildren(childrenNode: ReactNode): RouteObject[] { + return Children.toArray(childrenNode) .flatMap(child => { if (!isValidElement(child)) { return []; 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/plugins/catalog/src/components/EntityLayout/TabbedLayout.test.tsx b/packages/core/src/components/TabbedLayout/RoutedTabs.test.tsx similarity index 92% rename from plugins/catalog/src/components/EntityLayout/TabbedLayout.test.tsx rename to packages/core/src/components/TabbedLayout/RoutedTabs.test.tsx index 065265cea4..549aa55eff 100644 --- a/plugins/catalog/src/components/EntityLayout/TabbedLayout.test.tsx +++ b/packages/core/src/components/TabbedLayout/RoutedTabs.test.tsx @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; -import { TabbedLayout } from './TabbedLayout'; import { renderInTestApp } from '@backstage/test-utils'; import { fireEvent } from '@testing-library/react'; +import React from 'react'; import { act } from 'react-dom/test-utils'; -import { Routes, Route } from 'react-router'; +import { Route, Routes } from 'react-router'; +import { RoutedTabs } from './RoutedTabs'; const testRoute1 = { path: '', @@ -31,10 +31,10 @@ const testRoute2 = { children:
tabbed-test-content-2
, }; -describe('TabbedLayout', () => { +describe('RoutedTabs', () => { it('renders simplest case', async () => { const rendered = await renderInTestApp( - , + , ); expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); @@ -46,7 +46,7 @@ describe('TabbedLayout', () => { } + element={} /> , ); @@ -70,7 +70,7 @@ describe('TabbedLayout', () => { { it('shows only one tab contents at a time', async () => { const rendered = await renderInTestApp( - , + , { routeEntries: ['/some-other-path'] }, ); @@ -135,7 +135,7 @@ describe('TabbedLayout', () => { it('redirects to the top level when no route is matching the url', async () => { const rendered = await renderInTestApp( - , + , { routeEntries: ['/non-existing-path'] }, ); diff --git a/plugins/catalog/src/components/EntityLayout/TabbedLayout.tsx b/packages/core/src/components/TabbedLayout/RoutedTabs.tsx similarity index 84% rename from plugins/catalog/src/components/EntityLayout/TabbedLayout.tsx rename to packages/core/src/components/TabbedLayout/RoutedTabs.tsx index a2209ba492..b17c8afb3b 100644 --- a/plugins/catalog/src/components/EntityLayout/TabbedLayout.tsx +++ b/packages/core/src/components/TabbedLayout/RoutedTabs.tsx @@ -14,9 +14,9 @@ * limitations under the License. */ import React, { useMemo } from 'react'; -import { useParams, useNavigate, matchRoutes, useRoutes } from 'react-router'; -import { HeaderTabs, Content as LayoutContent } from '@backstage/core'; import { Helmet } from 'react-helmet'; +import { matchRoutes, useNavigate, useParams, useRoutes } from 'react-router'; +import { Content, HeaderTabs } from '../../layout'; import { SubRoute } from './types'; export function useSelectedSubRoute( @@ -44,7 +44,7 @@ export function useSelectedSubRoute( }; } -export const TabbedLayout = ({ routes }: { routes: SubRoute[] }) => { +export const RoutedTabs = ({ routes }: { routes: SubRoute[] }) => { const navigate = useNavigate(); const { index, route, element } = useSelectedSubRoute(routes); const headerTabs = useMemo( @@ -52,12 +52,12 @@ export const TabbedLayout = ({ routes }: { routes: SubRoute[] }) => { [routes], ); - const onTabChange = (index: number) => + const onTabChange = (tabIndex: number) => // Remove trailing /* // And remove leading / for relative navigation // Note! route resolves relative to the position in the React tree, // not relative to current location - navigate(routes[index].path.replace(/\/\*$/, '').replace(/^\//, '')); + navigate(routes[tabIndex].path.replace(/\/\*$/, '').replace(/^\//, '')); return ( <> @@ -66,10 +66,10 @@ export const TabbedLayout = ({ routes }: { routes: SubRoute[] }) => { selectedIndex={index} onChange={onTabChange} /> - + {element} - + ); }; diff --git a/packages/core/src/components/TabbedLayout/TabbedLayout.stories.tsx b/packages/core/src/components/TabbedLayout/TabbedLayout.stories.tsx new file mode 100644 index 0000000000..bf6175a9a2 --- /dev/null +++ b/packages/core/src/components/TabbedLayout/TabbedLayout.stories.tsx @@ -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 React, { PropsWithChildren } from 'react'; +import { MemoryRouter, Route, Routes } from 'react-router'; +import { TabbedLayout } from './TabbedLayout'; + +export default { + title: 'Navigation/TabbedLayout', + component: TabbedLayout, +}; + +const Wrapper = ({ children }: PropsWithChildren<{}>) => ( + + + {children}} /> + + +); + +export const Default = () => ( + + + +
tabbed-test-content
+
+ +
tabbed-test-content-2
+
+
+
+); diff --git a/packages/core/src/components/TabbedLayout/TabbedLayout.test.tsx b/packages/core/src/components/TabbedLayout/TabbedLayout.test.tsx new file mode 100644 index 0000000000..77230ab6cd --- /dev/null +++ b/packages/core/src/components/TabbedLayout/TabbedLayout.test.tsx @@ -0,0 +1,94 @@ +/* + * 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 { renderInTestApp, withLogCollector } from '@backstage/test-utils'; +import { fireEvent } from '@testing-library/react'; +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { Route, Routes } from 'react-router'; +import { TabbedLayout } from './TabbedLayout'; + +describe('TabbedLayout', () => { + it('renders simplest case', async () => { + const { getByText } = await renderInTestApp( + + +
tabbed-test-content
+
+
, + ); + + expect(getByText('tabbed-test-title')).toBeInTheDocument(); + expect(getByText('tabbed-test-content')).toBeInTheDocument(); + }); + + it('throws if any other component is a child of TabbedLayout', async () => { + const { error } = await withLogCollector(async () => { + await expect( + renderInTestApp( + + +
tabbed-test-content
+
+
This will cause app to throw
+
, + ), + ).rejects.toThrow(/Child of TabbedLayout must be an TabbedLayout.Route/); + }); + + expect(error).toEqual([ + expect.stringMatching( + /Child of TabbedLayout must be an TabbedLayout.Route/, + ), + expect.stringMatching( + /The above error occurred in the component/, + ), + ]); + }); + + it('navigates when user clicks different tab', async () => { + const { getByText, queryByText, queryAllByRole } = await renderInTestApp( + + + +
tabbed-test-content
+
+ +
tabbed-test-content-2
+
+
+ } + /> + , + ); + + const secondTab = queryAllByRole('tab')[1]; + act(() => { + fireEvent.click(secondTab); + }); + + expect(getByText('tabbed-test-title')).toBeInTheDocument(); + expect(queryByText('tabbed-test-content')).not.toBeInTheDocument(); + + expect(getByText('tabbed-test-title-2')).toBeInTheDocument(); + expect(queryByText('tabbed-test-content-2')).toBeInTheDocument(); + }); +}); diff --git a/packages/core/src/components/TabbedLayout/TabbedLayout.tsx b/packages/core/src/components/TabbedLayout/TabbedLayout.tsx new file mode 100644 index 0000000000..f181ee5980 --- /dev/null +++ b/packages/core/src/components/TabbedLayout/TabbedLayout.tsx @@ -0,0 +1,89 @@ +/* + * 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 { attachComponentData } from '@backstage/core-api'; +import React, { + Children, + Fragment, + isValidElement, + PropsWithChildren, + ReactNode, +} from 'react'; +import { RoutedTabs } from './RoutedTabs'; + +type SubRoute = { + path: string; + title: string; + children: JSX.Element; +}; + +const Route: (props: SubRoute) => null = () => null; + +// This causes all mount points that are discovered within this route to use the path of the route itself +attachComponentData(Route, 'core.gatherMountPoints', true); + +export function createSubRoutesFromChildren( + childrenProps: ReactNode, +): SubRoute[] { + // Directly comparing child.type with Route will not work with in + // combination with react-hot-loader in storybook + // https://github.com/gaearon/react-hot-loader/issues/304 + const routeType = ( + +
+ + ).type; + + return Children.toArray(childrenProps).flatMap(child => { + if (!isValidElement(child)) { + return []; + } + + if (child.type === Fragment) { + return createSubRoutesFromChildren(child.props.children); + } + + if (child.type !== routeType) { + throw new Error('Child of TabbedLayout must be an TabbedLayout.Route'); + } + + const { path, title, children } = child.props; + return [{ path, title, children }]; + }); +} + +/** + * TabbedLayout is a compound component, which allows you to define a layout for + * pages using a sub-navigation mechanism. + * + * Consists of two parts: TabbedLayout and TabbedLayout.Route + * + * @example + * ```jsx + * + * + *
This is rendered under /example/anything-here route
+ *
+ *
+ * ``` + */ +export const TabbedLayout = ({ children }: PropsWithChildren<{}>) => { + const routes = createSubRoutesFromChildren(children); + + return ; +}; + +TabbedLayout.Route = Route; diff --git a/packages/core/src/components/TabbedLayout/index.ts b/packages/core/src/components/TabbedLayout/index.ts new file mode 100644 index 0000000000..744b56959e --- /dev/null +++ b/packages/core/src/components/TabbedLayout/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { TabbedLayout } from './TabbedLayout'; diff --git a/plugins/catalog/src/components/EntityLayout/types.ts b/packages/core/src/components/TabbedLayout/types.ts similarity index 100% rename from plugins/catalog/src/components/EntityLayout/types.ts rename to packages/core/src/components/TabbedLayout/types.ts diff --git a/packages/core/src/components/index.ts b/packages/core/src/components/index.ts index 85ebba7a58..77eba9759a 100644 --- a/packages/core/src/components/index.ts +++ b/packages/core/src/components/index.ts @@ -21,10 +21,13 @@ export * from './CodeSnippet'; export * from './CopyTextButton'; export * from './DependencyGraph'; export * from './DismissableBanner'; +export * from './EmptyState'; export * from './FeatureDiscovery'; +export * from './HeaderIconLinkRow'; export * from './HorizontalScrollGrid'; export * from './Lifecycle'; export * from './Link'; +export * from './MarkdownContent'; export * from './OAuthRequestDialog'; export * from './Progress'; export * from './ProgressBars'; @@ -32,10 +35,8 @@ export * from './SimpleStepper'; export * from './Status'; export * from './StructuredMetadataTable'; export * from './SupportButton'; +export * from './TabbedLayout'; export * from './Table'; export * from './Tabs'; export * from './TrendLine'; export * from './WarningPanel'; -export * from './EmptyState'; -export * from './MarkdownContent'; -export * from './HeaderIconLinkRow'; diff --git a/packages/core/src/layout/HeaderTabs/HeaderTabs.tsx b/packages/core/src/layout/HeaderTabs/HeaderTabs.tsx index a1b4e1a97f..718a103f00 100644 --- a/packages/core/src/layout/HeaderTabs/HeaderTabs.tsx +++ b/packages/core/src/layout/HeaderTabs/HeaderTabs.tsx @@ -18,7 +18,7 @@ // This is just a temporary solution to implementing tabs for now import React, { useState, useEffect } from 'react'; -import { makeStyles, Tabs, Tab } from '@material-ui/core'; +import { makeStyles, Tabs, Tab as TabUI } from '@material-ui/core'; const useStyles = makeStyles(theme => ({ tabsWrapper: { @@ -81,7 +81,7 @@ export const HeaderTabs = ({ value={selectedTab} > {tabs.map((tab, index) => ( - ( label="Button" /> + + + ); + +export const Link = () => ( + + + + + + + + + + +); diff --git a/packages/core/src/layout/ItemCard/ItemCard.tsx b/packages/core/src/layout/ItemCard/ItemCard.tsx index 991a05708f..4242cd6381 100644 --- a/packages/core/src/layout/ItemCard/ItemCard.tsx +++ b/packages/core/src/layout/ItemCard/ItemCard.tsx @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { Button, Card, Chip, makeStyles, Typography } from '@material-ui/core'; +import clsx from 'clsx'; import React from 'react'; -import { Button, Card, Chip, Typography, makeStyles } from '@material-ui/core'; +import { Link } from '../../components'; const useStyles = makeStyles(theme => ({ header: { @@ -30,6 +32,9 @@ const useStyles = makeStyles(theme => ({ overflow: 'hidden', textOverflow: 'ellipsis', }, + withTags: { + height: 'calc(175px - 32px - 8px)', + }, footer: { display: 'flex', flexDirection: 'row-reverse', @@ -43,7 +48,9 @@ type ItemCardProps = { type?: string; label: string; onClick?: () => void; + href?: string; }; + export const ItemCard = ({ description, tags, @@ -51,6 +58,7 @@ export const ItemCard = ({ type, label, onClick, + href, }: ItemCardProps) => { const classes = useStyles(); @@ -64,13 +72,27 @@ export const ItemCard = ({ {tags?.map((tag, i) => ( ))} - + 0 && classes.withTags, + )} + > {description}
- + {!href && ( + + )} + {href && ( + + )}
diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 6c449b33b5..01432ba150 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: `@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. +- 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/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index d253102f71..495b30dd6f 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -56,14 +56,13 @@ proxy: target: 'https://example.com' changeOrigin: true +# Reference documentation http://backstage.io/docs/features/techdocs/configuration techdocs: - requestUrl: http://localhost:7000/api/techdocs - storageUrl: http://localhost:7000/api/techdocs/static/docs - builder: 'local' + builder: 'local' # Alternatives - 'external' generators: - techdocs: 'docker' + techdocs: 'docker' # Alternatives - 'local' publisher: - type: 'local' + type: 'local' # Alternatives - 'googleGcs' or 'awsS3'. Read documentation for using alternatives. auth: # see https://backstage.io/docs/tutorials/quickstart-app-auth to know more about enabling auth providers 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/e2e-test/src/commands/run.ts b/packages/e2e-test/src/commands/run.ts index 2ddcc333d2..5f4894f9e9 100644 --- a/packages/e2e-test/src/commands/run.ts +++ b/packages/e2e-test/src/commands/run.ts @@ -104,11 +104,11 @@ async function buildDistWorkspace(workspaceName: string, rootDir: string) { { helpers: { version(name: string) { - const pkg = require(`${name}/package.json`); - if (!pkg) { + const pkge = require(`${name}/package.json`); + if (!pkge) { throw new Error(`No version available for package ${name}`); } - return pkg.version; + return pkge.version; }, }, }, 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/ScmIntegrations.test.ts b/packages/integration/src/ScmIntegrations.test.ts index b43e69eba4..44e427a5d0 100644 --- a/packages/integration/src/ScmIntegrations.test.ts +++ b/packages/integration/src/ScmIntegrations.test.ts @@ -43,10 +43,10 @@ describe('ScmIntegrations', () => { } as GitLabIntegrationConfig); const i = new ScmIntegrations({ - azure: basicIntegrations([azure], i => i.config.host), - bitbucket: basicIntegrations([bitbucket], i => i.config.host), - github: basicIntegrations([github], i => i.config.host), - gitlab: basicIntegrations([gitlab], i => i.config.host), + azure: basicIntegrations([azure], item => item.config.host), + bitbucket: basicIntegrations([bitbucket], item => item.config.host), + github: basicIntegrations([github], item => item.config.host), + gitlab: basicIntegrations([gitlab], item => item.config.host), }); it('can get the specifics', () => { @@ -73,4 +73,19 @@ describe('ScmIntegrations', () => { expect(i.byHost('github.local')).toBe(github); expect(i.byHost('gitlab.local')).toBe(gitlab); }); + + it('can resolveUrl using fallback', () => { + expect( + i.resolveUrl({ + url: '../b.yaml', + base: 'https://no-matching-integration.com/x/a.yaml', + }), + ).toBe('https://no-matching-integration.com/b.yaml'); + expect( + i.resolveUrl({ + url: 'https://absolute.com/path', + base: 'https://no-matching-integration.com/x/a.yaml', + }), + ).toBe('https://absolute.com/path'); + }); }); diff --git a/packages/integration/src/ScmIntegrations.ts b/packages/integration/src/ScmIntegrations.ts index 102273a03b..c20fdcef9c 100644 --- a/packages/integration/src/ScmIntegrations.ts +++ b/packages/integration/src/ScmIntegrations.ts @@ -81,4 +81,13 @@ export class ScmIntegrations implements ScmIntegrationRegistry { .map(i => i.byHost(host)) .find(Boolean); } + + resolveUrl(options: { url: string; base: string }): string { + const resolve = this.byUrl(options.base)?.resolveUrl; + if (!resolve) { + return new URL(options.url, options.base).toString(); + } + + return resolve(options); + } } diff --git a/packages/integration/src/azure/AzureIntegration.test.ts b/packages/integration/src/azure/AzureIntegration.test.ts index 90c098b637..8a10e40bcf 100644 --- a/packages/integration/src/azure/AzureIntegration.test.ts +++ b/packages/integration/src/azure/AzureIntegration.test.ts @@ -41,4 +41,52 @@ describe('AzureIntegration', () => { expect(integration.type).toBe('azure'); expect(integration.title).toBe('h.com'); }); + + describe('resolveUrl', () => { + it('works for valid urls', () => { + const integration = new AzureIntegration({ + host: 'dev.azure.com', + } as any); + + expect( + integration.resolveUrl({ + url: '../a.yaml', + base: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Ffolder%2Fcatalog-info.yaml', + }), + ).toBe( + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fa.yaml', + ); + + expect( + integration.resolveUrl({ + url: './a.yaml', + base: 'https://dev.azure.com/organization/project/_git/repository', + }), + ).toBe( + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fa.yaml', + ); + + expect( + integration.resolveUrl({ + url: 'https://absolute.com/path', + base: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }), + ).toBe('https://absolute.com/path'); + }); + + it('falls back to regular URL resolution if not in a repo', () => { + const integration = new AzureIntegration({ + host: 'dev.azure.com', + } as any); + + expect( + integration.resolveUrl({ + url: './test', + base: 'https://dev.azure.com/organization/project/_git', + }), + ).toBe('https://dev.azure.com/organization/project/test'); + }); + }); }); diff --git a/packages/integration/src/azure/AzureIntegration.ts b/packages/integration/src/azure/AzureIntegration.ts index 446e6a9480..1413b7b343 100644 --- a/packages/integration/src/azure/AzureIntegration.ts +++ b/packages/integration/src/azure/AzureIntegration.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import parseGitUrl from 'git-url-parse'; import { basicIntegrations } from '../helpers'; import { ScmIntegration, ScmIntegrationsFactory } from '../types'; import { AzureIntegrationConfig, readAzureIntegrationConfigs } from './config'; @@ -42,4 +43,39 @@ export class AzureIntegration implements ScmIntegration { get config(): AzureIntegrationConfig { return this.integrationConfig; } + + /* + * Azure repo URLs on the form with a `path` query param are treated specially. + * + * Example base URL: https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml + */ + resolveUrl(options: { url: string; base: string }): string { + const { url, base } = options; + + // If we can parse the url, it is absolute - then return it verbatim + try { + // eslint-disable-next-line no-new + new URL(url); + return url; + } catch { + // Ignore intentionally - looks like a relative path + } + + const parsed = parseGitUrl(base); + const { organization, owner, name, filepath } = parsed; + + // If not an actual file path within a repo, treat the URL as raw + if (!organization || !owner || !name) { + return new URL(url, base).toString(); + } + + const path = filepath?.replace(/^\//, '') || ''; + const mockBaseUrl = new URL(`https://a.com/${path}`); + const updatedPath = new URL(url, mockBaseUrl).pathname; + + const newUrl = new URL(base); + newUrl.searchParams.set('path', updatedPath); + + return newUrl.toString(); + } } diff --git a/packages/integration/src/bitbucket/core.test.ts b/packages/integration/src/bitbucket/core.test.ts index 1287ab4d66..22b17d51fa 100644 --- a/packages/integration/src/bitbucket/core.test.ts +++ b/packages/integration/src/bitbucket/core.test.ts @@ -125,6 +125,7 @@ describe('bitbucket core', () => { ), ), ); + const config: BitbucketIntegrationConfig = { host: 'bitbucket.mycompany.net', apiBaseUrl: 'https://api.bitbucket.mycompany.net/rest/api/1.0', @@ -250,5 +251,40 @@ describe('bitbucket core', () => { ); expect(defaultBranch).toEqual('main'); }); + + it('return default branch for Bitbucket Server for bitbucket version 5.11', async () => { + const defaultBranchResponse = { + displayId: 'main', + }; + worker.use( + rest.get( + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/default-branch', + (_, res, ctx) => + res( + ctx.status(404), + ctx.set('Content-Type', 'application/json'), + ctx.json(defaultBranchResponse), + ), + ), + rest.get( + 'https://api.bitbucket.mycompany.net/rest/api/1.0/projects/backstage/repos/mock/branches/default', + (_, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json(defaultBranchResponse), + ), + ), + ); + const config: BitbucketIntegrationConfig = { + host: 'bitbucket.mycompany.net', + apiBaseUrl: 'https://api.bitbucket.mycompany.net/rest/api/1.0', + }; + const defaultBranch = await getBitbucketDefaultBranch( + 'https://bitbucket.mycompany.net/projects/backstage/repos/mock/browse/README.md', + config, + ); + expect(defaultBranch).toEqual('main'); + }); }); }); diff --git a/packages/integration/src/bitbucket/core.ts b/packages/integration/src/bitbucket/core.ts index f5235d8189..8b1d7d6b18 100644 --- a/packages/integration/src/bitbucket/core.ts +++ b/packages/integration/src/bitbucket/core.ts @@ -32,11 +32,19 @@ export async function getBitbucketDefaultBranch( const isHosted = resource === 'bitbucket.org'; // Bitbucket Server https://docs.atlassian.com/bitbucket-server/rest/7.9.0/bitbucket-rest.html#idp184 - const branchUrl = isHosted + let branchUrl = isHosted ? `${config.apiBaseUrl}/repositories/${project}/${repoName}` : `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/default-branch`; - const response = await fetch(branchUrl, getBitbucketRequestOptions(config)); + let response = await fetch(branchUrl, getBitbucketRequestOptions(config)); + + if (response.status === 404 && !isHosted) { + // First try the new format, and then if it gets specifically a 404 it should try the old format + // (to support old Atlassian Bitbucket v5.11.1 format ) + branchUrl = `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/branches/default`; + response = await fetch(branchUrl, getBitbucketRequestOptions(config)); + } + if (!response.ok) { const message = `Failed to retrieve default branch from ${branchUrl}, ${response.status} ${response.statusText}`; throw new Error(message); diff --git a/packages/integration/src/github/GithubCredentialsProvider.test.ts b/packages/integration/src/github/GithubCredentialsProvider.test.ts index f708f75184..d295677c55 100644 --- a/packages/integration/src/github/GithubCredentialsProvider.test.ts +++ b/packages/integration/src/github/GithubCredentialsProvider.test.ts @@ -215,21 +215,21 @@ describe('GithubCredentialsProvider tests', () => { }); it('should return the default token if no app is configured', async () => { - const github = GithubCredentialsProvider.create({ + const githubProvider = GithubCredentialsProvider.create({ host: 'github.com', apps: [], token: 'fallback_token', }); await expect( - github.getCredentials({ + githubProvider.getCredentials({ url: 'https://github.com/404/foobar', }), ).resolves.toEqual(expect.objectContaining({ token: 'fallback_token' })); }); it('should return the configured token if listing installations throws', async () => { - const github = GithubCredentialsProvider.create({ + const githubProvider = GithubCredentialsProvider.create({ host: 'github.com', apps: [ { @@ -245,19 +245,19 @@ describe('GithubCredentialsProvider tests', () => { octokit.apps.listInstallations.mockRejectedValue({ status: 304 }); await expect( - github.getCredentials({ + githubProvider.getCredentials({ url: 'https://github.com/backstage', }), ).resolves.toEqual(expect.objectContaining({ token: 'hardcoded_token' })); }); it('should return undefined if no token or apps are configured', async () => { - const github = GithubCredentialsProvider.create({ + const githubProvider = GithubCredentialsProvider.create({ host: 'github.com', }); await expect( - github.getCredentials({ + githubProvider.getCredentials({ url: 'https://github.com/backstage', }), ).resolves.toEqual({ headers: undefined, token: undefined }); diff --git a/packages/integration/src/github/GithubCredentialsProvider.ts b/packages/integration/src/github/GithubCredentialsProvider.ts index dfb809ee5f..a22c69909b 100644 --- a/packages/integration/src/github/GithubCredentialsProvider.ts +++ b/packages/integration/src/github/GithubCredentialsProvider.ts @@ -177,7 +177,7 @@ export class GithubAppCredentialsMux { ), ); - const result = results.find(result => result.credentials); + const result = results.find(resultItem => resultItem.credentials); if (result) { return result.credentials!.accessToken; } diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index 43fea72e0b..2b4713604c 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -49,23 +49,23 @@ describe('gitlab core', () => { { config: configWithNoToken, url: - 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', + 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yaml', result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', + 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', }, { config: configWithToken, url: - 'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', + 'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yaml', result: - 'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', + 'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', }, { config: configWithNoToken, url: - 'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path/to/file.yaml', // Repo not in subgroup + 'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yaml', // Repo not in subgroup result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', + 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', }, // Raw URLs { diff --git a/packages/integration/src/gitlab/core.ts b/packages/integration/src/gitlab/core.ts index c1d43c3a46..66b6733f56 100644 --- a/packages/integration/src/gitlab/core.ts +++ b/packages/integration/src/gitlab/core.ts @@ -109,7 +109,7 @@ export function buildProjectUrl(target: string, projectID: Number): URL { '/api/v4/projects', projectID, 'repository/files', - encodeURIComponent(filePath.join('/')), + encodeURIComponent(decodeURIComponent(filePath.join('/'))), 'raw', ].join('/'); url.search = `?ref=${branch}`; diff --git a/packages/integration/src/types.ts b/packages/integration/src/types.ts index d8fb7a14e2..7d5b0fbe74 100644 --- a/packages/integration/src/types.ts +++ b/packages/integration/src/types.ts @@ -34,6 +34,18 @@ export interface ScmIntegration { * differentiate between different integrations. */ title: string; + + /** + * Works like the two-argument form of the URL constructor, resolving an + * absolute or relative URL in relation to a base URL. + * + * If this method is not implemented, the URL constructor is used instead for + * URLs that match this integration. + * + * @param options.url The (absolute or relative) URL or path to resolve + * @param options.base The base URL onto which this resolution happens + */ + resolveUrl?(options: { url: string; base: string }): string; } /** @@ -69,6 +81,15 @@ export interface ScmIntegrationRegistry bitbucket: ScmIntegrationsGroup; github: ScmIntegrationsGroup; gitlab: ScmIntegrationsGroup; + + /** + * Works like the two-argument form of the URL constructor, resolving an + * absolute or relative URL in relation to a base URL. + * + * @param options.url The (absolute or relative) URL or path to resolve + * @param options.base The base URL onto which this resolution happens + */ + resolveUrl(options: { url: string; base: string }): string; } export type ScmIntegrationsFactory = (options: { 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/techdocs-common/src/stages/publish/azureBlobStorage.ts b/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts index 1b4e59a714..a02639e63f 100644 --- a/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts +++ b/packages/techdocs-common/src/stages/publish/azureBlobStorage.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import path from 'path'; +import platformPath from 'path'; import express from 'express'; import { BlobServiceClient, @@ -135,7 +135,7 @@ export class AzureBlobStoragePublish implements PublisherBase { // e.g. ['index.html', 'sub-page/index.html', 'assets/images/favicon.png'] const relativeFilePath = filePath.replace(`${directory}/`, ''); const entityRootDir = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`; - const destination = path.normalize( + const destination = platformPath.normalize( `${entityRootDir}/${relativeFilePath}`, ); // Azure Blob Storage Container file relative path @@ -217,7 +217,7 @@ export class AzureBlobStoragePublish implements PublisherBase { // filePath example - /default/Component/documented-component/index.html const filePath = req.path.replace(/^\//, ''); // Files with different extensions (CSS, HTML) need to be served with different headers - const fileExtension = path.extname(filePath); + const fileExtension = platformPath.extname(filePath); const responseHeaders = getHeadersForFileExtension(fileExtension); try { diff --git a/packages/techdocs-common/src/stages/publish/local.test.ts b/packages/techdocs-common/src/stages/publish/local.test.ts index efd56285ef..cd1a17ab5f 100644 --- a/packages/techdocs-common/src/stages/publish/local.test.ts +++ b/packages/techdocs-common/src/stages/publish/local.test.ts @@ -13,34 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* eslint-disable no-restricted-syntax */ -import fs from 'fs-extra'; -import path from 'path'; import { getVoidLogger, PluginEndpointDiscovery, } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; +import mockFs from 'mock-fs'; +import * as os from 'os'; import { LocalPublish } from './local'; -jest.mock('fs-extra', () => { - const fsOriginal = jest.requireActual('fs-extra'); - return { - ...fsOriginal, - access: jest.fn().mockImplementation((path, checkType, callback) => { - if ( - path.includes('http://localhost:7000/static') && - checkType === fs.constants.F_OK - ) { - callback(); - } else { - callback(new Error()); - } - }), - }; -}); - const createMockEntity = (annotations = {}) => { return { apiVersion: 'version', @@ -56,43 +37,33 @@ const createMockEntity = (annotations = {}) => { const logger = getVoidLogger(); +const tmpDir = + os.platform() === 'win32' ? 'C:\\tmp\\generatedDir' : '/tmp/generatedDir'; + describe('local publisher', () => { it('should publish generated documentation dir', async () => { - const testDiscovery: jest.Mocked = { - getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7000'), - getExternalBaseUrl: jest.fn(), - }; - - const mockConfig = new ConfigReader({ - techdocs: { - requestUrl: 'http://localhost:7000', - storageUrl: 'http://localhost:7000/static/docs', + mockFs({ + [tmpDir]: { + 'index.html': '', }, }); + const testDiscovery: jest.Mocked = { + getBaseUrl: jest + .fn() + .mockResolvedValue('http://localhost:7000/api/techdocs'), + getExternalBaseUrl: jest.fn(), + }; + + const mockConfig = new ConfigReader({}); + const publisher = new LocalPublish(mockConfig, logger, testDiscovery); const mockEntity = createMockEntity(); - const tempDir = fs.mkdtempSync(`${__dirname}/test-component-folder-`); - expect(tempDir).toBeTruthy(); - fs.closeSync(fs.openSync(path.join(tempDir, '/mock-file'), 'w')); - await publisher.publish({ entity: mockEntity, directory: tempDir }); - - const publishDir = path.resolve( - __dirname, - `../../../../../plugins/techdocs-backend/static/docs/${mockEntity.metadata.name}`, - ); - const resultDir = path.resolve( - __dirname, - `../../../../../plugins/techdocs-backend/static/docs/default/${mockEntity.kind}/${mockEntity.metadata.name}`, - ); - - expect(fs.existsSync(resultDir)).toBeTruthy(); - expect(fs.existsSync(path.join(resultDir, '/mock-file'))).toBeTruthy(); + await publisher.publish({ entity: mockEntity, directory: tmpDir }); expect(await publisher.hasDocsBeenGenerated(mockEntity)).toBe(true); - fs.removeSync(publishDir); - fs.removeSync(tempDir); + mockFs.restore(); }); }); diff --git a/packages/techdocs-common/src/stages/publish/local.ts b/packages/techdocs-common/src/stages/publish/local.ts index d07472e17d..e349a2119a 100644 --- a/packages/techdocs-common/src/stages/publish/local.ts +++ b/packages/techdocs-common/src/stages/publish/local.ts @@ -13,18 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import fetch from 'cross-fetch'; +import { + PluginEndpointDiscovery, + resolvePackagePath, +} from '@backstage/backend-common'; +import { Entity, EntityName } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; import express from 'express'; import fs from 'fs-extra'; -import path from 'path'; import os from 'os'; +import path from 'path'; import { Logger } from 'winston'; -import { Entity, EntityName } from '@backstage/catalog-model'; -import { - resolvePackagePath, - PluginEndpointDiscovery, -} from '@backstage/backend-common'; -import { Config } from '@backstage/config'; import { PublisherBase, PublishRequest, @@ -52,17 +51,14 @@ try { * called "static" at the root of techdocs-backend plugin. */ export class LocalPublish implements PublisherBase { - private readonly config: Config; - private readonly logger: Logger; - private readonly discovery: PluginEndpointDiscovery; - // TODO: Use a static fromConfig method to create a LocalPublish instance, similar to aws/gcs publishers. // Move the logic of setting staticDocsDir based on config over to fromConfig, // and set the value as a class parameter. constructor( - config: Config, - logger: Logger, - discovery: PluginEndpointDiscovery, + // @ts-ignore + private readonly config: Config, + private readonly logger: Logger, + private readonly discovery: PluginEndpointDiscovery, ) { this.config = config; this.logger = logger; @@ -107,34 +103,25 @@ export class LocalPublish implements PublisherBase { }); } - fetchTechDocsMetadata(entityName: EntityName): Promise { - return new Promise((resolve, reject) => { - this.discovery.getBaseUrl('techdocs').then(techdocsApiUrl => { - const storageUrl = new URL( - new URL(this.config.getString('techdocs.storageUrl')).pathname, - techdocsApiUrl, - ).toString(); + async fetchTechDocsMetadata( + entityName: EntityName, + ): Promise { + const metadataPath = path.join( + staticDocsDir, + entityName.namespace, + entityName.kind, + entityName.name, + 'techdocs_metadata.json', + ); - const entityRootDir = `${entityName.namespace}/${entityName.kind}/${entityName.name}`; - const metadataURL = `${storageUrl}/${entityRootDir}/techdocs_metadata.json`; - fetch(metadataURL) - .then(response => - response - .json() - .then(techdocsMetadata => resolve(techdocsMetadata)) - .catch(err => { - reject( - `Unable to parse metadata JSON for ${entityRootDir}. Error: ${err}`, - ); - }), - ) - .catch(err => { - reject( - `Unable to fetch metadata for ${entityRootDir}. Error ${err}`, - ); - }); - }); - }); + try { + return await fs.readJson(metadataPath); + } catch (err) { + this.logger.error( + `Unable to read techdocs_metadata.json at ${metadataPath}. Error: ${err}`, + ); + throw new Error(err.message); + } } docsRouter(): express.Handler { @@ -143,24 +130,21 @@ export class LocalPublish implements PublisherBase { async hasDocsBeenGenerated(entity: Entity): Promise { const namespace = entity.metadata.namespace ?? 'default'; - return new Promise(resolve => { - this.discovery.getBaseUrl('techdocs').then(techdocsApiUrl => { - const storageUrl = new URL( - new URL(this.config.getString('techdocs.storageUrl')).pathname, - techdocsApiUrl, - ).toString(); - const entityRootDir = `${namespace}/${entity.kind}/${entity.metadata.name}`; - const indexHtmlUrl = `${storageUrl}/${entityRootDir}/index.html`; - // Check if the file exists - fs.access(indexHtmlUrl, fs.constants.F_OK, err => { - if (err) { - resolve(false); - } else { - resolve(true); - } - }); - }); - }); + const indexHtmlPath = path.join( + staticDocsDir, + namespace, + entity.kind, + entity.metadata.name, + 'index.html', + ); + + // Check if the file exists + try { + fs.access(indexHtmlPath, fs.constants.F_OK); + return true; + } catch (err) { + return false; + } } } 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/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/api-docs/src/components/ApiDefinitionCard/ApiDefinitionCard.test.tsx b/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionCard.test.tsx index 0d2648ab5f..0107472acf 100644 --- a/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionCard.test.tsx +++ b/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionCard.test.tsx @@ -75,8 +75,8 @@ paths: type: 'openapi', title: 'OpenAPI', rawLanguage: 'yaml', - component: definition => ( - + component: definitionString => ( + ), }); 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 264bda0556..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,9 +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.2", "@octokit/graphql": "^4.5.8", "@types/express": "^4.17.6", "@types/ldapjs": "^1.0.9", @@ -57,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/catalog/DatabaseEntitiesCatalog.ts b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts index 76fc63c9b3..b03183cf34 100644 --- a/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/catalog/DatabaseEntitiesCatalog.ts @@ -124,7 +124,7 @@ export class DatabaseEntitiesCatalog implements EntitiesCatalog { // produce tens of thousands of entities, and those are too large batch // sizes to reasonably send to the database. const batches = Object.values(requestsByKindAndNamespace) - .map(requests => chunk(requests, BATCH_SIZE)) + .map(request => chunk(request, BATCH_SIZE)) .flat(); // Bound the number of concurrent batches. We want a bit of concurrency for diff --git a/plugins/catalog-backend/src/ingestion/processors/AwsOrganizationCloudAccountProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/AwsOrganizationCloudAccountProcessor.test.ts index 6eb7a45c63..28200021cc 100644 --- a/plugins/catalog-backend/src/ingestion/processors/AwsOrganizationCloudAccountProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/AwsOrganizationCloudAccountProcessor.test.ts @@ -65,7 +65,10 @@ describe('AwsOrganizationCloudAccountProcessor', () => { }); it('filters out accounts not in specified location target', async () => { - const location = { type: 'aws-cloud-accounts', target: 'o-1vl18kc5a3' }; + const locationTest = { + type: 'aws-cloud-accounts', + target: 'o-1vl18kc5a3', + }; listAccounts.mockImplementation(() => Promise.resolve({ Accounts: [ @@ -83,11 +86,11 @@ describe('AwsOrganizationCloudAccountProcessor', () => { NextToken: undefined, }), ); - await processor.readLocation(location, false, emit); + await processor.readLocation(locationTest, false, emit); expect(emit).toBeCalledTimes(1); expect(emit).toBeCalledWith({ type: 'entity', - location, + location: locationTest, entity: { apiVersion: 'backstage.io/v1alpha1', kind: 'Resource', diff --git a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts index c75a46874d..ef94c54010 100644 --- a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts @@ -66,8 +66,8 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor { async validateEntityKind(entity: Entity): Promise { for (const validator of this.validators) { - const result = await validator.check(entity); - if (result) { + const results = await validator.check(entity); + if (results) { return true; } } diff --git a/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.test.ts index 998dfb62a2..476510d757 100644 --- a/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.test.ts @@ -15,30 +15,73 @@ */ import { LocationSpec } from '@backstage/catalog-model'; -import { toAbsoluteUrl } from './LocationEntityProcessor'; +import { ConfigReader } from '@backstage/config'; +import { + ScmIntegrations, + ScmIntegrationRegistry, +} from '@backstage/integration'; import path from 'path'; +import { toAbsoluteUrl } from './LocationEntityProcessor'; describe('LocationEntityProcessor', () => { describe('toAbsoluteUrl', () => { it('handles files', () => { + const integrations = ({} as unknown) as ScmIntegrationRegistry; const base: LocationSpec = { type: 'file', target: `some${path.sep}path${path.sep}catalog-info.yaml`, }; - expect(toAbsoluteUrl(base, `.${path.sep}c`)).toBe( + expect(toAbsoluteUrl(integrations, base, `.${path.sep}c`)).toBe( `some${path.sep}path${path.sep}c`, ); - expect(toAbsoluteUrl(base, `${path.sep}c`)).toBe(`${path.sep}c`); + expect(toAbsoluteUrl(integrations, base, `${path.sep}c`)).toBe( + `${path.sep}c`, + ); }); it('handles urls', () => { + const integrations = ScmIntegrations.fromConfig(new ConfigReader({})); const base: LocationSpec = { type: 'url', target: 'http://a.com/b/catalog-info.yaml', }; - expect(toAbsoluteUrl(base, './c/d')).toBe('http://a.com/b/c/d'); - expect(toAbsoluteUrl(base, 'c/d')).toBe('http://a.com/b/c/d'); - expect(toAbsoluteUrl(base, 'http://b.com/z')).toBe('http://b.com/z'); + jest.spyOn(integrations, 'resolveUrl'); + + expect(toAbsoluteUrl(integrations, base, './c/d')).toBe( + 'http://a.com/b/c/d', + ); + expect(toAbsoluteUrl(integrations, base, 'c/d')).toBe( + 'http://a.com/b/c/d', + ); + expect(toAbsoluteUrl(integrations, base, 'http://b.com/z')).toBe( + 'http://b.com/z', + ); + + expect(integrations.resolveUrl).toBeCalledTimes(3); + }); + + it('handles azure urls specifically', () => { + const integrations = ScmIntegrations.fromConfig( + new ConfigReader({ + integrations: { + azure: [{ host: 'dev.azure.com' }], + }, + }), + ); + + expect( + toAbsoluteUrl( + integrations, + { + type: 'url', + target: + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fcatalog-info.yaml', + }, + './a.yaml', + ), + ).toBe( + 'https://dev.azure.com/organization/project/_git/repository?path=%2Fa.yaml', + ); }); }); }); diff --git a/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.ts index 1c7e13f1c4..f4c8c82957 100644 --- a/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/LocationEntityProcessor.ts @@ -15,11 +15,16 @@ */ import { Entity, LocationEntity, LocationSpec } from '@backstage/catalog-model'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import path from 'path'; import * as result from './results'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; -import path from 'path'; -export function toAbsoluteUrl(base: LocationSpec, target: string): string { +export function toAbsoluteUrl( + integrations: ScmIntegrationRegistry, + base: LocationSpec, + target: string, +): string { try { if (base.type === 'file') { if (target.startsWith('.')) { @@ -27,13 +32,19 @@ export function toAbsoluteUrl(base: LocationSpec, target: string): string { } return target; } - return new URL(target, base.target).toString(); + return integrations.resolveUrl({ url: target, base: base.target }); } catch (e) { return target; } } -export class LocationRefProcessor implements CatalogProcessor { +type Options = { + integrations: ScmIntegrationRegistry; +}; + +export class LocationEntityProcessor implements CatalogProcessor { + constructor(private readonly options: Options) {} + async postProcessEntity( entity: Entity, location: LocationSpec, @@ -47,7 +58,7 @@ export class LocationRefProcessor implements CatalogProcessor { emit( result.inputError( location, - `LocationRefProcessor cannot handle ${type} type location with target ${location.target} that ends with a path separator`, + `LocationEntityProcessor cannot handle ${type} type location with target ${location.target} that ends with a path separator`, ), ); } @@ -61,7 +72,11 @@ export class LocationRefProcessor implements CatalogProcessor { } for (const maybeRelativeTarget of targets) { - const target = toAbsoluteUrl(location, maybeRelativeTarget); + const target = toAbsoluteUrl( + this.options.integrations, + location, + maybeRelativeTarget, + ); emit(result.location({ type, target }, false)); } } diff --git a/plugins/catalog-backend/src/ingestion/processors/index.ts b/plugins/catalog-backend/src/ingestion/processors/index.ts index a7b00d7065..05dd327f0e 100644 --- a/plugins/catalog-backend/src/ingestion/processors/index.ts +++ b/plugins/catalog-backend/src/ingestion/processors/index.ts @@ -23,7 +23,7 @@ export { CodeOwnersProcessor } from './CodeOwnersProcessor'; export { FileReaderProcessor } from './FileReaderProcessor'; export { GithubOrgReaderProcessor } from './GithubOrgReaderProcessor'; export { LdapOrgReaderProcessor } from './LdapOrgReaderProcessor'; -export { LocationRefProcessor } from './LocationEntityProcessor'; +export { LocationEntityProcessor } from './LocationEntityProcessor'; export { MicrosoftGraphOrgReaderProcessor } from './MicrosoftGraphOrgReaderProcessor'; export { PlaceholderProcessor } from './PlaceholderProcessor'; export type { PlaceholderResolver } from './PlaceholderProcessor'; diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 938a406e56..f7544ef42e 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -26,6 +26,7 @@ import { Validators, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; import lodash from 'lodash'; import { Logger } from 'winston'; import { @@ -46,8 +47,8 @@ import { HigherOrderOperation, HigherOrderOperations, LdapOrgReaderProcessor, + LocationEntityProcessor, LocationReaders, - LocationRefProcessor, MicrosoftGraphOrgReaderProcessor, PlaceholderProcessor, PlaceholderResolver, @@ -280,6 +281,7 @@ export class CatalogBuilder { private buildProcessors(): CatalogProcessor[] { const { config, logger, reader } = this.env; + const integrations = ScmIntegrations.fromConfig(config); this.checkDeprecatedReaderProcessors(); @@ -306,7 +308,7 @@ export class CatalogBuilder { MicrosoftGraphOrgReaderProcessor.fromConfig(config, { logger }), new UrlReaderProcessor({ reader, logger }), new CodeOwnersProcessor({ reader, logger }), - new LocationRefProcessor(), + new LocationEntityProcessor({ integrations }), new AnnotateLocationEntityProcessor(), ); } 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-import/src/components/ImportComponentForm.tsx b/plugins/catalog-import/src/components/ImportComponentForm.tsx index a3d355b33f..b3ec050ea3 100644 --- a/plugins/catalog-import/src/components/ImportComponentForm.tsx +++ b/plugins/catalog-import/src/components/ImportComponentForm.tsx @@ -71,8 +71,8 @@ export const RegisterComponentForm = ({ const onSubmit = async (formData: Record) => { const { componentLocation: target } = formData; - async function saveCatalogFileConfig(target: string) { - const data = await catalogApi.addLocation({ target }); + async function saveCatalogFileConfig(targetString: string) { + const data = await catalogApi.addLocation({ target: targetString }); saveConfig({ type: 'file', location: data.location.target, @@ -80,12 +80,12 @@ export const RegisterComponentForm = ({ }); } - async function trySaveRepositoryConfig(target: string) { - const existingCatalog = await checkForExistingCatalogInfo(target); + async function trySaveRepositoryConfig(targetString: string) { + const existingCatalog = await checkForExistingCatalogInfo(targetString); if (existingCatalog.exists) { - const targetUrl = target.endsWith('/') - ? `${target}${existingCatalog.url}` - : `${target}/${existingCatalog.url}`; + const targetUrl = targetString.endsWith('/') + ? `${targetString}${existingCatalog.url}` + : `${targetString}/${existingCatalog.url}`; await saveCatalogFileConfig(targetUrl); } else { saveConfig({ diff --git a/plugins/catalog-import/src/components/ImportComponentPage.tsx b/plugins/catalog-import/src/components/ImportComponentPage.tsx index e284e95456..adae137a50 100644 --- a/plugins/catalog-import/src/components/ImportComponentPage.tsx +++ b/plugins/catalog-import/src/components/ImportComponentPage.tsx @@ -46,20 +46,20 @@ function manifestGenerationAvailable(configApi: ConfigApi): boolean { function repositories(configApi: ConfigApi): string[] { const integrations = configApi.getConfig('integrations'); - const repositories = []; + const repos = []; if (integrations.has('github')) { - repositories.push('GitHub'); + repos.push('GitHub'); } if (integrations.has('bitbucket')) { - repositories.push('Bitbucket'); + repos.push('Bitbucket'); } if (integrations.has('gitlab')) { - repositories.push('GitLab'); + repos.push('GitLab'); } if (integrations.has('azure')) { - repositories.push('Azure'); + repos.push('Azure'); } - return repositories; + return repos; } export const ImportComponentPage = ({ 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-react/src/utils/isOwnerOf.ts b/plugins/catalog-react/src/utils/isOwnerOf.ts index 455e06dc13..d135e4030a 100644 --- a/plugins/catalog-react/src/utils/isOwnerOf.ts +++ b/plugins/catalog-react/src/utils/isOwnerOf.ts @@ -34,13 +34,13 @@ export function isOwnerOf(owner: Entity, owned: Entity) { const owners = getEntityRelations(owned, RELATION_OWNED_BY); - for (const owner of owners) { + for (const ownerItem of owners) { if ( possibleOwners.find( o => - owner.kind.toLowerCase() === o.kind.toLowerCase() && - owner.namespace.toLowerCase() === o.namespace.toLowerCase() && - owner.name.toLowerCase() === o.name.toLowerCase(), + ownerItem.kind.toLowerCase() === o.kind.toLowerCase() && + ownerItem.namespace.toLowerCase() === o.namespace.toLowerCase() && + ownerItem.name.toLowerCase() === o.name.toLowerCase(), ) !== undefined ) { return true; 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/catalog/src/components/EntityLayout/EntityLayout.test.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx index 0d8ae56262..7356ccc27b 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx @@ -22,7 +22,7 @@ import { ApiRegistry, } from '@backstage/core'; import { catalogApiRef, EntityContext } from '@backstage/plugin-catalog-react'; -import { renderInTestApp, withLogCollector } from '@backstage/test-utils'; +import { renderInTestApp } from '@backstage/test-utils'; import { fireEvent } from '@testing-library/react'; import React from 'react'; import { act } from 'react-dom/test-utils'; @@ -59,34 +59,11 @@ describe('EntityLayout', () => { , ); + expect(rendered.getByText('my-entity')).toBeInTheDocument(); expect(rendered.getByText('tabbed-test-title')).toBeInTheDocument(); expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument(); }); - it('throws if any other component is a child of TabbedLayout', async () => { - const { error } = await withLogCollector(async () => { - await expect( - renderInTestApp( - - -
tabbed-test-content
-
-
This will cause app to throw
-
, - ), - ).rejects.toThrow(/Child of EntityLayout must be an EntityLayout.Route/); - }); - - expect(error).toEqual([ - expect.stringMatching( - /Child of EntityLayout must be an EntityLayout.Route/, - ), - expect.stringMatching( - /The above error occurred in the component/, - ), - ]); - }); - it('navigates when user clicks different tab', async () => { const rendered = await renderInTestApp( diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx index 4f7cb09cb6..c4cd4c5c71 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx @@ -16,12 +16,12 @@ import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model'; import { - attachComponentData, Content, Header, HeaderLabel, Page, Progress, + TabbedLayout, } from '@backstage/core'; import { EntityContext, @@ -29,12 +29,9 @@ import { } from '@backstage/plugin-catalog-react'; import { Box } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; -import React, { - Children, - Fragment, - isValidElement, +import { + default as React, PropsWithChildren, - ReactNode, useContext, useState, } from 'react'; @@ -42,37 +39,6 @@ import { useNavigate } from 'react-router'; import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu'; import { FavouriteEntity } from '../FavouriteEntity/FavouriteEntity'; import { UnregisterEntityDialog } from '../UnregisterEntityDialog/UnregisterEntityDialog'; -import { TabbedLayout } from './TabbedLayout'; - -type SubRoute = { - path: string; - title: string; - children: JSX.Element; -}; - -const Route: (props: SubRoute) => null = () => null; - -// This causes all mount points that are discovered within this route to use the path of the route itself -attachComponentData(Route, 'core.gatherMountPoints', true); - -export function createSubRoutesFromChildren(children: ReactNode): SubRoute[] { - return Children.toArray(children).flatMap(child => { - if (!isValidElement(child)) { - return []; - } - - if (child.type === Fragment) { - return createSubRoutesFromChildren(child.props.children); - } - - if (child.type !== Route) { - throw new Error('Child of EntityLayout must be an EntityLayout.Route'); - } - - const { path, title, children } = child.props; - return [{ path, title, children }]; - }); -} const EntityLayoutTitle = ({ entity, @@ -132,7 +98,6 @@ export const EntityLayout = ({ children }: PropsWithChildren<{}>) => { const { kind, namespace, name } = useEntityCompoundName(); const { entity, loading, error } = useContext(EntityContext); - const routes = createSubRoutesFromChildren(children); const { headerTitle, headerType } = headerProps( kind, namespace, @@ -174,7 +139,7 @@ export const EntityLayout = ({ children }: PropsWithChildren<{}>) => { {loading && } - {entity && } + {entity && {children}} {error && ( @@ -191,4 +156,4 @@ export const EntityLayout = ({ children }: PropsWithChildren<{}>) => { ); }; -EntityLayout.Route = Route; +EntityLayout.Route = TabbedLayout.Route; diff --git a/plugins/catalog/src/components/EntitySwitch/EntitySwitch.tsx b/plugins/catalog/src/components/EntitySwitch/EntitySwitch.tsx index d5593edcc2..a3ede42288 100644 --- a/plugins/catalog/src/components/EntitySwitch/EntitySwitch.tsx +++ b/plugins/catalog/src/components/EntitySwitch/EntitySwitch.tsx @@ -35,8 +35,8 @@ type SwitchCase = { children: JSX.Element; }; -function createSwitchCasesFromChildren(children: ReactNode): SwitchCase[] { - return Children.toArray(children).flatMap(child => { +function createSwitchCasesFromChildren(childrenNode: ReactNode): SwitchCase[] { + return Children.toArray(childrenNode).flatMap(child => { if (!isValidElement(child)) { return []; } 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/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/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/package.json b/plugins/cloudbuild/package.json index 3e5bbef3a9..41a5285d7d 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,9 @@ "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/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 +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/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/components/AlertInsights/AlertInsights.tsx b/plugins/cost-insights/src/components/AlertInsights/AlertInsights.tsx index 59b2dc9eec..7360c99cf7 100644 --- a/plugins/cost-insights/src/components/AlertInsights/AlertInsights.tsx +++ b/plugins/cost-insights/src/components/AlertInsights/AlertInsights.tsx @@ -124,18 +124,18 @@ export const AlertInsights = ({ setSnackbarOpen(!!error); }, [error]); - function onSnooze(alert: Alert) { - setAlert(alert); + function onSnooze(alertToSnooze: Alert) { + setAlert(alertToSnooze); setStatus(AlertStatus.Snoozed); } - function onAccept(alert: Alert) { - setAlert(alert); + function onAccept(alertToAccept: Alert) { + setAlert(alertToAccept); setStatus(AlertStatus.Accepted); } - function onDismiss(alert: Alert) { - setAlert(alert); + function onDismiss(alertToDismiss: Alert) { + setAlert(alertToDismiss); setStatus(AlertStatus.Dismissed); } @@ -148,8 +148,8 @@ export const AlertInsights = ({ setStatus(null); } - function onDialogFormSubmit(data: any) { - setData(data); + function onDialogFormSubmit(formData: any) { + setData(formData); } function onSummaryButtonClick() { @@ -175,10 +175,10 @@ export const AlertInsights = ({
{isAlertInsightSectionDisplayed && ( - {active.map((alert, index) => ( + {active.map((activeAlert, index) => ( ) => { +}: PropsWithChildren) => { const classes = useBarChartLabelStyles(); const translateX = width * -0.5; diff --git a/plugins/cost-insights/src/components/BarChart/BarChartSteps.tsx b/plugins/cost-insights/src/components/BarChart/BarChartSteps.tsx index 11a295965e..8157e05444 100644 --- a/plugins/cost-insights/src/components/BarChart/BarChartSteps.tsx +++ b/plugins/cost-insights/src/components/BarChart/BarChartSteps.tsx @@ -18,7 +18,7 @@ import React from 'react'; import { ButtonBase } from '@material-ui/core'; import { useBarChartStepperStyles as useStyles } from '../../utils/styles'; -export type BarChartSteps = { +export type BarChartStepsProps = { steps: number; activeStep: number; onClick: (index: number) => void; @@ -28,7 +28,7 @@ export const BarChartSteps = ({ steps, activeStep, onClick, -}: BarChartSteps) => { +}: BarChartStepsProps) => { const classes = useStyles(); const handleOnClick = (index: number) => ( event: React.MouseEvent, diff --git a/plugins/cost-insights/src/components/ProductInsights/ProductInsights.tsx b/plugins/cost-insights/src/components/ProductInsights/ProductInsights.tsx index 0ef35bf04c..5702e67172 100644 --- a/plugins/cost-insights/src/components/ProductInsights/ProductInsights.tsx +++ b/plugins/cost-insights/src/components/ProductInsights/ProductInsights.tsx @@ -82,12 +82,7 @@ export const ProductInsights = ({ ); useEffect(() => { - async function getAllProductInsights( - group: string, - project: Maybe, - products: Product[], - lastCompleteBillingDate: string, - ) { + async function getAllProductInsights() { try { dispatchLoadingProducts(true); const responses = await Promise.allSettled( @@ -101,10 +96,10 @@ export const ProductInsights = ({ ), ).then(settledResponseOf); - const initialStates = initialStatesOf(products, responses).sort( + const updatedInitialStates = initialStatesOf(products, responses).sort( totalAggregationSort, ); - setStates(initialStates); + setStates(updatedInitialStates); } catch (e) { setError(e); } finally { @@ -112,7 +107,7 @@ export const ProductInsights = ({ } } - getAllProductInsights(group, project, products, lastCompleteBillingDate); + getAllProductInsights(); }, [ client, group, @@ -125,8 +120,8 @@ export const ProductInsights = ({ useEffect( function handleOnLoaded() { if (onceRef.current) { - const products = initialStates.map(state => state.product); - onLoaded(products); + const initialProducts = initialStates.map(state => state.product); + onLoaded(initialProducts); } else { onceRef.current = true; } diff --git a/plugins/cost-insights/src/utils/change.test.ts b/plugins/cost-insights/src/utils/change.test.ts index 7cc03caa0b..9516dfe270 100644 --- a/plugins/cost-insights/src/utils/change.test.ts +++ b/plugins/cost-insights/src/utils/change.test.ts @@ -76,13 +76,13 @@ describe('getPreviousPeriodTotalCost', () => { change: changeOf(MockAggregatedDailyCosts), trendline: trendlineOf(MockAggregatedDailyCosts), }; - const exclusiveEndDate = '2020-09-30'; + const inclusiveEndDate = '2020-09-30'; expect( getPreviousPeriodTotalCost( mockGroupDailyCost.aggregation, Duration.P30D, - exclusiveEndDate, + inclusiveEndDate, ), - ).toEqual(100_000); + ).toEqual(96_600); }); }); diff --git a/plugins/cost-insights/src/utils/change.ts b/plugins/cost-insights/src/utils/change.ts index fc50439aad..950fbfeb82 100644 --- a/plugins/cost-insights/src/utils/change.ts +++ b/plugins/cost-insights/src/utils/change.ts @@ -22,14 +22,13 @@ import { GrowthType, MetricData, Duration, - DEFAULT_DATE_FORMAT, DateAggregation, } from '../types'; import dayjs, { OpUnitType } from 'dayjs'; -import duration from 'dayjs/plugin/duration'; +import durationPlugin from 'dayjs/plugin/duration'; import { inclusiveStartDateOf } from './duration'; -dayjs.extend(duration); +dayjs.extend(durationPlugin); // Used for displaying status colors export function growthOf(ratio: number, amount?: number) { @@ -73,10 +72,7 @@ export function getPreviousPeriodTotalCost( inclusiveEndDate: string, ): number { const dayjsDuration = dayjs.duration(duration); - const startDate = inclusiveStartDateOf( - duration, - dayjs(inclusiveEndDate).add(1, 'day').format(DEFAULT_DATE_FORMAT), - ); + const startDate = inclusiveStartDateOf(duration, inclusiveEndDate); // dayjs doesn't allow adding an ISO 8601 period to dates. const [amount, type]: [number, OpUnitType] = dayjsDuration.days() ? [dayjsDuration.days(), 'day'] diff --git a/plugins/cost-insights/src/utils/duration.ts b/plugins/cost-insights/src/utils/duration.ts index 79ea150fc5..27447537cc 100644 --- a/plugins/cost-insights/src/utils/duration.ts +++ b/plugins/cost-insights/src/utils/duration.ts @@ -24,23 +24,21 @@ export const DEFAULT_DURATION = Duration.P30D; * Derive the start date of a given period, assuming two repeating intervals. * * @param duration see comment on Duration enum - * @param exclusiveEndDate from CostInsightsApi.getLastCompleteBillingDate + 1 day + * @param inclusiveEndDate from CostInsightsApi.getLastCompleteBillingDate */ export function inclusiveStartDateOf( duration: Duration, - exclusiveEndDate: string, + inclusiveEndDate: string, ): string { switch (duration) { case Duration.P7D: case Duration.P30D: case Duration.P90D: - return moment(exclusiveEndDate) - .utc() + return moment(inclusiveEndDate) .subtract(moment.duration(duration).add(moment.duration(duration))) .format(DEFAULT_DATE_FORMAT); case Duration.P3M: - return moment(exclusiveEndDate) - .utc() + return moment(inclusiveEndDate) .startOf('quarter') .subtract(moment.duration(duration).add(moment.duration(duration))) .format(DEFAULT_DATE_FORMAT); @@ -57,13 +55,9 @@ export function exclusiveEndDateOf( case Duration.P7D: case Duration.P30D: case Duration.P90D: - return moment(inclusiveEndDate) - .utc() - .add(1, 'day') - .format(DEFAULT_DATE_FORMAT); + return moment(inclusiveEndDate).add(1, 'day').format(DEFAULT_DATE_FORMAT); case Duration.P3M: return moment(quarterEndDate(inclusiveEndDate)) - .utc() .add(1, 'day') .format(DEFAULT_DATE_FORMAT); default: @@ -76,7 +70,6 @@ export function inclusiveEndDateOf( inclusiveEndDate: string, ): string { return moment(exclusiveEndDateOf(duration, inclusiveEndDate)) - .utc() .subtract(1, 'day') .format(DEFAULT_DATE_FORMAT); } @@ -94,7 +87,7 @@ export function intervalsOf( } export function quarterEndDate(inclusiveEndDate: string): string { - const endDate = moment(inclusiveEndDate).utc(); + const endDate = moment(inclusiveEndDate); const endOfQuarter = endDate.endOf('quarter').format(DEFAULT_DATE_FORMAT); if (endOfQuarter === inclusiveEndDate) { return endDate.format(DEFAULT_DATE_FORMAT); diff --git a/plugins/cost-insights/src/utils/formatters.ts b/plugins/cost-insights/src/utils/formatters.ts index 182c567644..8f2b94f997 100644 --- a/plugins/cost-insights/src/utils/formatters.ts +++ b/plugins/cost-insights/src/utils/formatters.ts @@ -16,7 +16,7 @@ import moment from 'moment'; import pluralize from 'pluralize'; -import { Duration, DEFAULT_DATE_FORMAT } from '../types'; +import { Duration } from '../types'; import { inclusiveEndDateOf, inclusiveStartDateOf } from '../utils/duration'; export type Period = { @@ -92,11 +92,8 @@ export function formatPercent(n: number): string { } export function formatLastTwoLookaheadQuarters(inclusiveEndDate: string) { - const exclusiveEndDate = moment(inclusiveEndDate) - .add(1, 'day') - .format(DEFAULT_DATE_FORMAT); const start = moment( - inclusiveStartDateOf(Duration.P3M, exclusiveEndDate), + inclusiveStartDateOf(Duration.P3M, inclusiveEndDate), ).format('[Q]Q YYYY'); const end = moment(inclusiveEndDateOf(Duration.P3M, inclusiveEndDate)).format( '[Q]Q YYYY', diff --git a/plugins/cost-insights/src/utils/mockData.ts b/plugins/cost-insights/src/utils/mockData.ts index 14ff9aecd1..d4ac4cd2df 100644 --- a/plugins/cost-insights/src/utils/mockData.ts +++ b/plugins/cost-insights/src/utils/mockData.ts @@ -36,7 +36,7 @@ import { getDefaultState as getDefaultLoadingState, } from '../utils/loading'; import { findAlways } from '../utils/assert'; -import { inclusiveStartDateOf } from './duration'; +import { inclusiveEndDateOf, inclusiveStartDateOf } from './duration'; type mockAlertRenderer = (alert: T) => T; type mockEntityRenderer = (entity: T) => T; @@ -228,8 +228,9 @@ export function aggregationFor( baseline: number, ): DateAggregation[] { const { duration, endDate } = parseIntervals(intervals); + const inclusiveEndDate = inclusiveEndDateOf(duration, endDate); const days = dayjs(endDate).diff( - inclusiveStartDateOf(duration, endDate), + inclusiveStartDateOf(duration, inclusiveEndDate), 'day', ); @@ -244,7 +245,7 @@ export function aggregationFor( return [...Array(days).keys()].reduce( (values: DateAggregation[], i: number): DateAggregation[] => { const last = values.length ? values[values.length - 1].amount : baseline; - const date = dayjs(inclusiveStartDateOf(duration, endDate)) + const date = dayjs(inclusiveStartDateOf(duration, inclusiveEndDate)) .add(i, 'day') .format(DEFAULT_DATE_FORMAT); const amount = Math.max(0, last + nextDelta()); diff --git a/plugins/explore-react/.eslintrc.js b/plugins/explore-react/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/plugins/explore-react/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; 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/README.md b/plugins/explore-react/README.md new file mode 100644 index 0000000000..4a881955df --- /dev/null +++ b/plugins/explore-react/README.md @@ -0,0 +1,4 @@ +# explore-react + +This package provides helpers to the `explore` plugin that can be imported by +any other plugin or app. diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json new file mode 100644 index 0000000000..924c723a67 --- /dev/null +++ b/plugins/explore-react/package.json @@ -0,0 +1,48 @@ +{ + "name": "@backstage/plugin-explore-react", + "version": "0.0.2", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": false, + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/explore-react" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "build": "backstage-cli plugin:build", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "clean": "backstage-cli clean", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack" + }, + "dependencies": { + "@backstage/core": "^0.6.0" + }, + "devDependencies": { + "@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", + "@testing-library/user-event": "^12.0.7", + "@types/jest": "^26.0.7", + "@types/node": "^12.0.0", + "cross-fetch": "^3.0.6", + "msw": "^0.21.2" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/explore/src/components/Router.tsx b/plugins/explore-react/src/index.ts similarity index 66% rename from plugins/explore/src/components/Router.tsx rename to plugins/explore-react/src/index.ts index becb2522d0..d46f5d4f27 100644 --- a/plugins/explore/src/components/Router.tsx +++ b/plugins/explore-react/src/index.ts @@ -14,13 +14,4 @@ * limitations under the License. */ -import React from 'react'; -import { Route, Routes } from 'react-router'; -import { ExplorePluginPage } from './ExplorePluginPage'; -import { rootRouteRef } from '../plugin'; - -export const Router = () => ( - - } /> - -); +export * from './tools'; diff --git a/plugins/explore-react/src/setupTests.ts b/plugins/explore-react/src/setupTests.ts new file mode 100644 index 0000000000..825bcd4115 --- /dev/null +++ b/plugins/explore-react/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * 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 '@testing-library/jest-dom'; diff --git a/plugins/explore-react/src/tools/api.test.ts b/plugins/explore-react/src/tools/api.test.ts new file mode 100644 index 0000000000..386d66ead2 --- /dev/null +++ b/plugins/explore-react/src/tools/api.test.ts @@ -0,0 +1,23 @@ +/* + * 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 { exploreToolsConfigRef } from './api'; + +describe('api', () => { + // This is a dummy test to have at least one test in the package. + it('api ref exists', () => { + expect(exploreToolsConfigRef.id).toBe('plugin.explore.toolsconfig'); + }); +}); diff --git a/plugins/explore-react/src/tools/api.ts b/plugins/explore-react/src/tools/api.ts new file mode 100644 index 0000000000..5d96033546 --- /dev/null +++ b/plugins/explore-react/src/tools/api.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createApiRef } from '@backstage/core'; + +export const exploreToolsConfigRef = createApiRef({ + id: 'plugin.explore.toolsconfig', + description: 'Used to configure tools displayed in the explore plugin', +}); + +export type ExploreTool = { + title: string; + description?: string; + url: string; + image: string; + tags?: string[]; + lifecycle?: string; + newsTag?: string; +}; + +export interface ExploreToolsConfig { + getTools: () => Promise; +} diff --git a/plugins/explore-react/src/tools/index.ts b/plugins/explore-react/src/tools/index.ts new file mode 100644 index 0000000000..7f727881ca --- /dev/null +++ b/plugins/explore-react/src/tools/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { exploreToolsConfigRef } from './api'; +export type { ExploreTool, ExploreToolsConfig } from './api'; 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/README.md b/plugins/explore/README.md index d5453e594c..ec00cb4dee 100644 --- a/plugins/explore/README.md +++ b/plugins/explore/README.md @@ -1,7 +1,32 @@ -# Title +# explore Welcome to the explore plugin! +This plugin helps to visualize the domains and tools in your ecosystem. -## Sub-section 1 +## Getting started -## Sub-section 2 +To install the plugin, include the following import your `plugins.ts`: + +```typescript +export { explorePlugin } from '@backstage/plugin-explore'; +``` + +Register the route in `App.tsx`: + +```typescript +import { ExplorePage } from '@backstage/plugin-explore'; + +... + +} /> +``` + +Add a link to the sidebar in `Root.tsx`: + +```typescript +import LayersIcon from '@material-ui/icons/Layers'; + +... + + +``` diff --git a/plugins/explore/dev/index.tsx b/plugins/explore/dev/index.tsx index 812a5585d4..9a7b66a7b5 100644 --- a/plugins/explore/dev/index.tsx +++ b/plugins/explore/dev/index.tsx @@ -14,7 +14,59 @@ * limitations under the License. */ +import { Entity } from '@backstage/catalog-model'; import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { exploreToolsConfigRef } from '@backstage/plugin-explore-react'; +import React from 'react'; +import { ExplorePage, explorePlugin } from '../src'; +import { exampleTools } from '../src/util/examples'; -createDevApp().registerPlugin(plugin).render(); +createDevApp() + .registerPlugin(explorePlugin) + .registerApi({ + api: exploreToolsConfigRef, + deps: {}, + factory: () => ({ + async getTools() { + return exampleTools; + }, + }), + }) + .registerApi({ + api: catalogApiRef, + deps: {}, + factory: () => + ({ + async getEntities() { + const domainNames = [ + 'playback', + 'artists', + 'payments', + 'analytics', + 'songs', + 'devops', + ]; + + return { + items: domainNames.map( + (n, i) => + ({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Domain', + metadata: { + name: n, + description: `Everything about ${n}`, + tags: i % 2 === 0 ? [n] : undefined, + }, + spec: { + owner: `${n}@example.com`, + }, + } as Entity), + ), + }; + }, + } as CatalogApi), + }) + .addPage({ element: , title: 'Explore' }) + .render(); diff --git a/plugins/explore/package.json b/plugins/explore/package.json index c6668c9c4d..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,20 +30,23 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.5.0", - "@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", "classnames": "^2.2.6", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-router": "6.0.0-beta.0", + "react-router-dom": "6.0.0-beta.0", "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/explore/src/components/DomainCard/DomainCard.test.tsx b/plugins/explore/src/components/DomainCard/DomainCard.test.tsx new file mode 100644 index 0000000000..9d409051f6 --- /dev/null +++ b/plugins/explore/src/components/DomainCard/DomainCard.test.tsx @@ -0,0 +1,49 @@ +/* + * 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 { DomainEntity } from '@backstage/catalog-model'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { DomainCard } from './DomainCard'; + +describe('', () => { + it('renders a domain card', () => { + const entity: DomainEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Domain', + metadata: { + name: 'artists', + description: 'Everything about artists', + tags: ['a-tag'], + }, + spec: { + owner: 'guest', + }, + }; + const { getByText } = render(, { + wrapper: MemoryRouter, + }); + + expect(getByText('artists')).toBeInTheDocument(); + expect(getByText('Everything about artists')).toBeInTheDocument(); + expect(getByText('a-tag')).toBeInTheDocument(); + expect(getByText('Explore').parentElement).toHaveAttribute( + 'href', + '/catalog/default/domain/artists', + ); + }); +}); diff --git a/plugins/explore/src/components/DomainCard/DomainCard.tsx b/plugins/explore/src/components/DomainCard/DomainCard.tsx new file mode 100644 index 0000000000..2c0126b94a --- /dev/null +++ b/plugins/explore/src/components/DomainCard/DomainCard.tsx @@ -0,0 +1,41 @@ +/* + * 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 { DomainEntity } from '@backstage/catalog-model'; +import { ItemCard } from '@backstage/core'; +import { + entityRoute, + entityRouteParams, +} from '@backstage/plugin-catalog-react'; +import React from 'react'; +import { generatePath } from 'react-router-dom'; + +type DomainCardProps = { + entity: DomainEntity; +}; + +export const DomainCard = ({ entity }: DomainCardProps) => ( + +); diff --git a/plugins/explore/src/components/DomainCard/DomainCardGrid.test.tsx b/plugins/explore/src/components/DomainCard/DomainCardGrid.test.tsx new file mode 100644 index 0000000000..bad3ca581b --- /dev/null +++ b/plugins/explore/src/components/DomainCard/DomainCardGrid.test.tsx @@ -0,0 +1,54 @@ +/* + * 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 { DomainEntity } from '@backstage/catalog-model'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { DomainCardGrid } from './DomainCardGrid'; + +describe('', () => { + it('renders a grid of domain cards', () => { + const entities: DomainEntity[] = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Domain', + metadata: { + name: 'playback', + }, + spec: { + owner: 'guest', + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Domain', + metadata: { + name: 'artists', + }, + spec: { + owner: 'guest', + }, + }, + ]; + const { getByText } = render(, { + wrapper: MemoryRouter, + }); + + expect(getByText('artists')).toBeInTheDocument(); + expect(getByText('playback')).toBeInTheDocument(); + }); +}); diff --git a/plugins/explore/src/components/DomainCard/DomainCardGrid.tsx b/plugins/explore/src/components/DomainCard/DomainCardGrid.tsx new file mode 100644 index 0000000000..b4a13aa39f --- /dev/null +++ b/plugins/explore/src/components/DomainCard/DomainCardGrid.tsx @@ -0,0 +1,33 @@ +/* + * 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 { DomainEntity } from '@backstage/catalog-model'; +import { Grid } from '@material-ui/core'; +import React from 'react'; +import { DomainCard } from '.'; + +type DomainCardGridProps = { + entities: DomainEntity[]; +}; + +export const DomainCardGrid = ({ entities }: DomainCardGridProps) => ( + + {entities.map((e, i) => ( + + + + ))} + +); diff --git a/plugins/explore/src/components/DomainCard/index.ts b/plugins/explore/src/components/DomainCard/index.ts new file mode 100644 index 0000000000..6acf10800a --- /dev/null +++ b/plugins/explore/src/components/DomainCard/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { DomainCard } from './DomainCard'; +export { DomainCardGrid } from './DomainCardGrid'; diff --git a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx new file mode 100644 index 0000000000..4846565bdd --- /dev/null +++ b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.test.tsx @@ -0,0 +1,93 @@ +/* + * 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 { DomainEntity } from '@backstage/catalog-model'; +import { ApiProvider, ApiRegistry } from '@backstage/core'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { render, waitFor } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { DomainExplorerContent } from './DomainExplorerContent'; + +describe('', () => { + const catalogApi: jest.Mocked = { + addLocation: jest.fn(_a => new Promise(() => {})), + getEntities: jest.fn(), + getLocationByEntity: jest.fn(), + getLocationById: jest.fn(), + removeEntityByUid: jest.fn(), + getEntityByName: jest.fn(), + }; + + const Wrapper = ({ children }: { children?: React.ReactNode }) => ( + + + {children} + + + ); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('renders a grid of domains', async () => { + const entities: DomainEntity[] = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Domain', + metadata: { + name: 'playback', + }, + spec: { + owner: 'guest', + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Domain', + metadata: { + name: 'artists', + }, + spec: { + owner: 'guest', + }, + }, + ]; + catalogApi.getEntities.mockResolvedValue({ items: entities }); + + const { getByText } = render(, { + wrapper: Wrapper, + }); + + await waitFor(() => { + expect(getByText('artists')).toBeInTheDocument(); + expect(getByText('playback')).toBeInTheDocument(); + }); + }); + + it('renders empty state', async () => { + catalogApi.getEntities.mockResolvedValue({ items: [] }); + + const { getByText } = render(, { + wrapper: Wrapper, + }); + + await waitFor(() => + expect(getByText('No domains to display')).toBeInTheDocument(), + ); + }); +}); diff --git a/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.tsx b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.tsx new file mode 100644 index 0000000000..ca00c525c9 --- /dev/null +++ b/plugins/explore/src/components/DomainExplorerContent/DomainExplorerContent.tsx @@ -0,0 +1,67 @@ +/* + * 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 { DomainEntity } from '@backstage/catalog-model'; +import { + Content, + ContentHeader, + EmptyState, + Progress, + SupportButton, + useApi, +} from '@backstage/core'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { Button } from '@material-ui/core'; +import React from 'react'; +import { useAsync } from 'react-use'; +import { DomainCardGrid } from '../DomainCard'; + +export const DomainExplorerContent = () => { + const catalogApi = useApi(catalogApiRef); + const { value: entities, loading } = useAsync(async () => { + const response = await catalogApi.getEntities({ + filter: { kind: 'domain' }, + }); + + return response.items as DomainEntity[]; + }, [catalogApi]); + + return ( + + + Discover the domains in your ecosystem. + + + {loading && } + {!loading && (!entities || entities.length === 0) && ( + + Read more + + } + /> + )} + {!loading && entities && } + + ); +}; diff --git a/plugins/explore/src/components/DomainExplorerContent/index.ts b/plugins/explore/src/components/DomainExplorerContent/index.ts new file mode 100644 index 0000000000..4012332006 --- /dev/null +++ b/plugins/explore/src/components/DomainExplorerContent/index.ts @@ -0,0 +1,16 @@ +/* + * 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 { DomainExplorerContent } from './DomainExplorerContent'; diff --git a/plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx b/plugins/explore/src/components/ExplorePage/ExplorePage.tsx similarity index 51% rename from plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx rename to plugins/explore/src/components/ExplorePage/ExplorePage.tsx index fe99e70575..3f9394a1ab 100644 --- a/plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx +++ b/plugins/explore/src/components/ExplorePage/ExplorePage.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2020 Spotify AB + * 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. @@ -13,28 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +import { configApiRef, Header, Page, useApi } from '@backstage/core'; import React from 'react'; -import { Content, Header, Page } from '@backstage/core'; -import { RollbarProjectTable } from '../RollbarProjectTable/RollbarProjectTable'; -import { useRollbarEntities } from '../../hooks/useRollbarEntities'; - -export const RollbarHome = () => { - const { entities, loading, error } = useRollbarEntities(); +import { ExploreTabs } from './ExploreTabs'; +export const ExplorePage = () => { + const configApi = useApi(configApiRef); + const organizationName = + configApi.getOptionalString('organization.name') ?? 'Backstage'; return ( - +
- - - + + ); }; diff --git a/plugins/explore/src/components/ExplorePage/ExploreTabs.tsx b/plugins/explore/src/components/ExplorePage/ExploreTabs.tsx new file mode 100644 index 0000000000..0cf28f9f1c --- /dev/null +++ b/plugins/explore/src/components/ExplorePage/ExploreTabs.tsx @@ -0,0 +1,30 @@ +/* + * 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 { TabbedLayout } from '@backstage/core'; +import React from 'react'; +import { DomainExplorerContent } from '../DomainExplorerContent'; +import { ToolExplorerContent } from '../ToolExplorerContent'; + +export const ExploreTabs = () => ( + + + + + + + + +); diff --git a/plugins/explore/src/components/ExplorePage/index.ts b/plugins/explore/src/components/ExplorePage/index.ts new file mode 100644 index 0000000000..b075c410c3 --- /dev/null +++ b/plugins/explore/src/components/ExplorePage/index.ts @@ -0,0 +1,16 @@ +/* + * 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 { ExplorePage } from './ExplorePage'; diff --git a/plugins/explore/src/components/ExploreCard.test.js b/plugins/explore/src/components/ToolCard/ToolCard.test.tsx similarity index 70% rename from plugins/explore/src/components/ExploreCard.test.js rename to plugins/explore/src/components/ToolCard/ToolCard.test.tsx index 45652015a5..b3c1737ae6 100644 --- a/plugins/explore/src/components/ExploreCard.test.js +++ b/plugins/explore/src/components/ToolCard/ToolCard.test.tsx @@ -14,11 +14,10 @@ * limitations under the License. */ -import React from 'react'; -import { render } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; - -import ExploreCard from './ExploreCard'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { ToolCard } from './ToolCard'; const minProps = { card: { @@ -30,37 +29,31 @@ const minProps = { }, }; -describe('', () => { +describe('', () => { it('renders without exploding', () => { - const { getByText } = render(wrapInTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText('Explore')).toBeInTheDocument(); }); it('renders props correctly', () => { - const { getByText } = render(wrapInTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText(minProps.card.title)).toBeInTheDocument(); expect(getByText(minProps.card.description)).toBeInTheDocument(); }); it('should link out', () => { - const rendered = render(wrapInTestApp()); + const rendered = render(wrapInTestApp()); const anchor = rendered.container.querySelector('a'); - expect(anchor.href).toBe(minProps.card.url); + expect(anchor).toHaveAttribute('href', minProps.card.url); }); it('renders default description when missing', () => { - const propsWithoutDescription = { - card: { - card: { - title: 'Title', - url: 'http://spotify.com/', - image: 'https://developer.spotify.com/assets/WebAPI_intro.png', - }, - }, + const card = { + title: 'Title', + url: 'http://spotify.com/', + image: 'https://developer.spotify.com/assets/WebAPI_intro.png', }; - const { getByText } = render( - wrapInTestApp(), - ); + const { getByText } = render(wrapInTestApp()); expect(getByText('Description missing')).toBeInTheDocument(); }); @@ -74,13 +67,13 @@ describe('', () => { }, }; const { queryByText } = render( - wrapInTestApp(), + wrapInTestApp(), ); expect(queryByText('GA')).not.toBeInTheDocument(); }); it('renders tags correctly', () => { - const { getByText } = render(wrapInTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText(minProps.card.tags[0])).toBeInTheDocument(); expect(getByText(minProps.card.tags[1])).toBeInTheDocument(); }); diff --git a/plugins/explore/src/components/ExploreCard.tsx b/plugins/explore/src/components/ToolCard/ToolCard.tsx similarity index 91% rename from plugins/explore/src/components/ExploreCard.tsx rename to plugins/explore/src/components/ToolCard/ToolCard.tsx index 8d1348c116..c6d812b098 100644 --- a/plugins/explore/src/components/ExploreCard.tsx +++ b/plugins/explore/src/components/ToolCard/ToolCard.tsx @@ -14,8 +14,8 @@ * limitations under the License. */ -import React from 'react'; -import classNames from 'classnames'; +import { ExploreTool } from '@backstage/plugin-explore-react'; +import { BackstageTheme } from '@backstage/theme'; import { Button, Card, @@ -23,10 +23,13 @@ import { CardContent, CardMedia, Chip, - Typography, makeStyles, + Typography, } from '@material-ui/core'; -import { BackstageTheme } from '@backstage/theme'; +import classNames from 'classnames'; +import React from 'react'; + +// TODO: Align styling between Domain and ToolCard const useStyles = makeStyles(theme => ({ card: { @@ -65,22 +68,12 @@ const useStyles = makeStyles(theme => ({ }, })); -export type CardData = { - title: string; - description: string; - url: string; - image: string; - tags?: string[]; - lifecycle?: string; - newsTag?: string; -}; - type Props = { - card: CardData; + card: ExploreTool; objectFit?: 'cover' | 'contain'; }; -const ExploreCard = ({ card, objectFit }: Props) => { +export const ToolCard = ({ card, objectFit }: Props) => { const classes = useStyles(); const { title, description, url, image, lifecycle, newsTag, tags } = card; @@ -130,5 +123,3 @@ const ExploreCard = ({ card, objectFit }: Props) => { ); }; - -export default ExploreCard; diff --git a/plugins/explore/src/components/ToolCard/ToolCardGrid.tsx b/plugins/explore/src/components/ToolCard/ToolCardGrid.tsx new file mode 100644 index 0000000000..5b6fbd1834 --- /dev/null +++ b/plugins/explore/src/components/ToolCard/ToolCardGrid.tsx @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ExploreTool } from '@backstage/plugin-explore-react'; +import { BackstageTheme } from '@backstage/theme'; +import { makeStyles } from '@material-ui/core'; +import React from 'react'; +import { ToolCard } from './ToolCard'; + +const useStyles = makeStyles(theme => ({ + container: { + display: 'grid', + gridTemplateColumns: 'repeat(auto-fill, 296px)', + gridGap: theme.spacing(3), + marginBottom: theme.spacing(6), + }, +})); + +type ToolCardGridProps = { + tools: ExploreTool[]; +}; + +export const ToolCardGrid = ({ tools }: ToolCardGridProps) => { + const classes = useStyles(); + + return ( +
+ {tools.map((card: ExploreTool, ix: any) => ( + + ))} +
+ ); +}; diff --git a/plugins/explore/src/components/ToolCard/index.ts b/plugins/explore/src/components/ToolCard/index.ts new file mode 100644 index 0000000000..84599aa163 --- /dev/null +++ b/plugins/explore/src/components/ToolCard/index.ts @@ -0,0 +1,17 @@ +/* + * 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 { ToolCard } from './ToolCard'; +export { ToolCardGrid } from './ToolCardGrid'; diff --git a/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.test.tsx b/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.test.tsx new file mode 100644 index 0000000000..b0e1330ff3 --- /dev/null +++ b/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.test.tsx @@ -0,0 +1,94 @@ +/* + * 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 { ApiProvider, ApiRegistry } from '@backstage/core'; +import { + ExploreTool, + exploreToolsConfigRef, +} from '@backstage/plugin-explore-react'; +import { lightTheme } from '@backstage/theme'; +import { ThemeProvider } from '@material-ui/core'; +import { render, waitFor } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { ToolExplorerContent } from './ToolExplorerContent'; + +describe('', () => { + const exploreToolsConfigApi: jest.Mocked = { + getTools: jest.fn(), + }; + + const Wrapper = ({ children }: { children?: React.ReactNode }) => ( + + + + {children} + + + + ); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('renders a grid of tools', async () => { + const tools: ExploreTool[] = [ + { + title: 'Lighthouse', + description: + "Google's Lighthouse tool is a great resource for benchmarking and improving the accessibility, performance, SEO, and best practices of your website.", + url: '/lighthouse', + image: + 'https://raw.githubusercontent.com/GoogleChrome/lighthouse/8b3d7f052b2e64dd857e741d7395647f487697e7/assets/lighthouse-logo.png', + tags: ['web', 'seo', 'accessibility', 'performance'], + }, + { + title: 'Tech Radar', + description: + 'Tech Radar is a list of technologies, complemented by an assessment result, called ring assignment.', + url: '/tech-radar', + image: + 'https://storage.googleapis.com/wf-blogs-engineering-media/2018/09/fe13bb32-wf-tech-radar-hero-1024x597.png', + tags: ['standards', 'landscape'], + }, + ]; + exploreToolsConfigApi.getTools.mockResolvedValue(tools); + + const { getByText } = render(, { + wrapper: Wrapper, + }); + + await waitFor(() => { + expect(getByText('Lighthouse')).toBeInTheDocument(); + expect(getByText('Tech Radar')).toBeInTheDocument(); + }); + }); + + it('renders empty state', async () => { + exploreToolsConfigApi.getTools.mockResolvedValue([]); + + const { getByText } = render(, { + wrapper: Wrapper, + }); + + await waitFor(() => + expect(getByText('No tools to display')).toBeInTheDocument(), + ); + }); +}); diff --git a/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.tsx b/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.tsx new file mode 100644 index 0000000000..8b8b3f0a61 --- /dev/null +++ b/plugins/explore/src/components/ToolExplorerContent/ToolExplorerContent.tsx @@ -0,0 +1,52 @@ +/* + * 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 { + Content, + ContentHeader, + EmptyState, + Progress, + SupportButton, + useApi, +} from '@backstage/core'; +import { exploreToolsConfigRef } from '@backstage/plugin-explore-react'; +import React from 'react'; +import { useAsync } from 'react-use'; +import { ToolCardGrid } from '../ToolCard'; + +export const ToolExplorerContent = () => { + const exploreToolsConfigApi = useApi(exploreToolsConfigRef); + const { value: tools, loading } = useAsync(async () => { + return await exploreToolsConfigApi.getTools(); + }, [exploreToolsConfigApi]); + + return ( + + + Discover the tools in your ecosystem. + + + {loading && } + {!loading && (!tools || tools.length === 0) && ( + + )} + {!loading && tools && } + + ); +}; diff --git a/plugins/explore/src/components/ToolExplorerContent/index.ts b/plugins/explore/src/components/ToolExplorerContent/index.ts new file mode 100644 index 0000000000..8fb3072d46 --- /dev/null +++ b/plugins/explore/src/components/ToolExplorerContent/index.ts @@ -0,0 +1,16 @@ +/* + * 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 { ToolExplorerContent } from './ToolExplorerContent'; diff --git a/plugins/explore/src/extensions.tsx b/plugins/explore/src/extensions.tsx new file mode 100644 index 0000000000..cdf43d3035 --- /dev/null +++ b/plugins/explore/src/extensions.tsx @@ -0,0 +1,27 @@ +/* + * 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 { createRoutableExtension } from '@backstage/core'; +import { explorePlugin } from './plugin'; +import { exploreRouteRef } from './routes'; + +export const ExplorePage = explorePlugin.provide( + createRoutableExtension({ + component: () => + import('./components/ExplorePage').then(m => m.ExplorePage), + mountPoint: exploreRouteRef, + }), +); diff --git a/plugins/explore/src/index.ts b/plugins/explore/src/index.ts index ff7857cacd..70a00f5bbb 100644 --- a/plugins/explore/src/index.ts +++ b/plugins/explore/src/index.ts @@ -14,5 +14,6 @@ * limitations under the License. */ -export { plugin } from './plugin'; -export { Router } from './components/Router'; +export * from './extensions'; +export { explorePlugin } from './plugin'; +export * from './routes'; diff --git a/plugins/explore/src/plugin.test.ts b/plugins/explore/src/plugin.test.ts index d6503c038b..652a0590dc 100644 --- a/plugins/explore/src/plugin.test.ts +++ b/plugins/explore/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { explorePlugin } from './plugin'; describe('explore', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(explorePlugin).toBeDefined(); }); }); diff --git a/plugins/explore/src/plugin.ts b/plugins/explore/src/plugin.ts index 75ea892242..27573eaeb9 100644 --- a/plugins/explore/src/plugin.ts +++ b/plugins/explore/src/plugin.ts @@ -14,9 +14,27 @@ * limitations under the License. */ -import { createPlugin, createRouteRef } from '@backstage/core'; +import { createApiFactory, createPlugin } from '@backstage/core'; +import { exploreToolsConfigRef } from '@backstage/plugin-explore-react'; +import { exploreRouteRef } from './routes'; +import { exampleTools } from './util/examples'; -export const rootRouteRef = createRouteRef({ path: '', title: 'Explore' }); -export const plugin = createPlugin({ +export const explorePlugin = createPlugin({ id: 'explore', + apis: [ + // Register a default for exploreToolsConfigRef, you may want to override + // the API locally in your app. + createApiFactory({ + api: exploreToolsConfigRef, + deps: {}, + factory: () => ({ + async getTools() { + return exampleTools; + }, + }), + }), + ], + routes: { + explore: exploreRouteRef, + }, }); diff --git a/plugins/rollbar/src/routes.ts b/plugins/explore/src/routes.ts similarity index 69% rename from plugins/rollbar/src/routes.ts rename to plugins/explore/src/routes.ts index b514dff3c8..c41a53128f 100644 --- a/plugins/rollbar/src/routes.ts +++ b/plugins/explore/src/routes.ts @@ -18,19 +18,7 @@ import { createRouteRef } from '@backstage/core'; const NoIcon = () => null; -export const rootRouteRef = createRouteRef({ +export const exploreRouteRef = createRouteRef({ icon: NoIcon, - path: '/rollbar', - title: 'Rollbar Home', -}); - -export const entityRouteRef = createRouteRef({ - path: '/rollbar/:optionalNamespaceAndName', - title: 'Rollbar', -}); - -export const catalogRouteRef = createRouteRef({ - icon: NoIcon, - path: '', - title: 'Rollbar', + title: 'Explore', }); diff --git a/plugins/explore/src/components/ExplorePluginPage.tsx b/plugins/explore/src/util/examples.ts similarity index 75% rename from plugins/explore/src/components/ExplorePluginPage.tsx rename to plugins/explore/src/util/examples.ts index f3e75e0011..d0a4cdd1f4 100644 --- a/plugins/explore/src/components/ExplorePluginPage.tsx +++ b/plugins/explore/src/util/examples.ts @@ -14,28 +14,7 @@ * limitations under the License. */ -import React from 'react'; -import { makeStyles, Typography } from '@material-ui/core'; -import { - Content, - ContentHeader, - Header, - Page, - SupportButton, -} from '@backstage/core'; -import ExploreCard, { CardData } from './ExploreCard'; -import { BackstageTheme } from '@backstage/theme'; - -const useStyles = makeStyles(theme => ({ - container: { - display: 'grid', - gridTemplateColumns: 'repeat(auto-fill, 296px)', - gridGap: theme.spacing(3), - marginBottom: theme.spacing(6), - }, -})); - -const toolsCards = [ +export const exampleTools = [ { title: 'New Relic', description: @@ -112,28 +91,3 @@ const toolsCards = [ tags: ['rollbar', 'monitoring', 'errors'], }, ]; - -export const ExplorePluginPage = () => { - const classes = useStyles(); - - return ( - -
- - - - Explore tools available in Backstage - - -
- {toolsCards.map((card: CardData, ix: any) => ( - - ))} -
-
- - ); -}; 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/package.json b/plugins/github-actions/package.json index beb35b3cb0..49f1b0007a 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,10 @@ "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/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 +49,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/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/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/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/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/useBuilds.ts b/plugins/jenkins/src/components/useBuilds.ts index db7c7ddd55..a1ff3a1eef 100644 --- a/plugins/jenkins/src/components/useBuilds.ts +++ b/plugins/jenkins/src/components/useBuilds.ts @@ -36,17 +36,17 @@ export function useBuilds(owner: string, repo: string, branch?: string) { const { loading, value: builds, retry } = useAsyncRetry(async () => { try { - let builds; + let build; if (branch) { - builds = await api.getLastBuild(`${owner}/${repo}/${branch}`); + build = await api.getLastBuild(`${owner}/${repo}/${branch}`); } else { - builds = await api.getFolder(`${owner}/${repo}`); + build = await api.getFolder(`${owner}/${repo}`); } - const size = Array.isArray(builds) ? builds?.[0].build_num! : 1; + const size = Array.isArray(build) ? build?.[0].build_num! : 1; setTotal(size); - return builds || []; + return build || []; } catch (e) { errorApi.post(e); throw e; 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/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/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-backend/src/service/getKubernetesObjectsForServiceHandler.ts b/plugins/kubernetes-backend/src/service/getKubernetesObjectsForServiceHandler.ts index 2dd1e32b96..811a3c8acb 100644 --- a/plugins/kubernetes-backend/src/service/getKubernetesObjectsForServiceHandler.ts +++ b/plugins/kubernetes-backend/src/service/getKubernetesObjectsForServiceHandler.ts @@ -85,18 +85,18 @@ export const handleGetKubernetesObjectsForService: GetKubernetesObjectsForServic ] || `backstage.io/kubernetes-id=${requestBody.entity.metadata.name}`; return Promise.all( - clusterDetailsDecoratedForAuth.map(clusterDetails => { + clusterDetailsDecoratedForAuth.map(clusterDetailsItem => { return fetcher .fetchObjectsForService({ serviceId, - clusterDetails, + clusterDetails: clusterDetailsItem, objectTypesToFetch, labelSelector, } as ObjectFetchParams) .then(result => { return { cluster: { - name: clusterDetails.name, + name: clusterDetailsItem.name, }, resources: result.responses, errors: result.errors, 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/package.json b/plugins/kubernetes/package.json index 3dc53a9ea4..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,12 +31,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/plugin-catalog-react": "^0.0.1", + "@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", @@ -48,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/components/DeploymentsAccordions/DeploymentDrawer.tsx b/plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentDrawer.tsx index 6bacad9b16..8c1365769f 100644 --- a/plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentDrawer.tsx +++ b/plugins/kubernetes/src/components/DeploymentsAccordions/DeploymentDrawer.tsx @@ -32,8 +32,8 @@ export const DeploymentDrawer = ({ object={deployment} expanded={expanded} kind="Deployment" - renderObject={(deployment: V1Deployment) => { - const conditions = (deployment.status?.conditions ?? []) + renderObject={(deploymentObj: V1Deployment) => { + const conditions = (deploymentObj.status?.conditions ?? []) .map(renderCondition) .reduce((accum, next) => { accum[next[0]] = next[1]; @@ -41,10 +41,10 @@ export const DeploymentDrawer = ({ }, {} as { [key: string]: React.ReactNode }); return { - strategy: deployment.spec?.strategy ?? '???', - minReadySeconds: deployment.spec?.minReadySeconds ?? '???', + strategy: deploymentObj.spec?.strategy ?? '???', + minReadySeconds: deploymentObj.spec?.minReadySeconds ?? '???', progressDeadlineSeconds: - deployment.spec?.progressDeadlineSeconds ?? '???', + deploymentObj.spec?.progressDeadlineSeconds ?? '???', ...conditions, }; }} diff --git a/plugins/kubernetes/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.tsx b/plugins/kubernetes/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.tsx index 00ab2cad84..26dcdfd249 100644 --- a/plugins/kubernetes/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.tsx +++ b/plugins/kubernetes/src/components/HorizontalPodAutoscalers/HorizontalPodAutoscalerDrawer.tsx @@ -32,16 +32,16 @@ export const HorizontalPodAutoscalerDrawer = ({ kind="HorizontalPodAutoscaler" object={hpa} expanded={expanded} - renderObject={(hpa: V1HorizontalPodAutoscaler) => { + renderObject={(hpaObject: V1HorizontalPodAutoscaler) => { return { targetCPUUtilizationPercentage: - hpa.spec?.targetCPUUtilizationPercentage, + hpaObject.spec?.targetCPUUtilizationPercentage, currentCPUUtilizationPercentage: - hpa.status?.currentCPUUtilizationPercentage, - minReplicas: hpa.spec?.minReplicas, - maxReplicas: hpa.spec?.maxReplicas, - currentReplicas: hpa.status?.currentReplicas, - desiredReplicas: hpa.status?.desiredReplicas, + hpaObject.status?.currentCPUUtilizationPercentage, + minReplicas: hpaObject.spec?.minReplicas, + maxReplicas: hpaObject.spec?.maxReplicas, + currentReplicas: hpaObject.status?.currentReplicas, + desiredReplicas: hpaObject.status?.desiredReplicas, }; }} > diff --git a/plugins/kubernetes/src/components/IngressesAccordions/IngressDrawer.tsx b/plugins/kubernetes/src/components/IngressesAccordions/IngressDrawer.tsx index 9e63f22fda..d619700ac2 100644 --- a/plugins/kubernetes/src/components/IngressesAccordions/IngressDrawer.tsx +++ b/plugins/kubernetes/src/components/IngressesAccordions/IngressDrawer.tsx @@ -31,8 +31,8 @@ export const IngressDrawer = ({ object={ingress} expanded={expanded} kind="Ingress" - renderObject={(ingress: ExtensionsV1beta1Ingress) => { - return ingress.spec || {}; + renderObject={(ingressObject: ExtensionsV1beta1Ingress) => { + return ingressObject.spec || {}; }} > { - const phase = pod.status?.phase ?? 'unknown'; + renderObject={(podObject: V1Pod) => { + const phase = podObject.status?.phase ?? 'unknown'; const ports = - pod.spec?.containers?.map(c => { + podObject.spec?.containers?.map(c => { return { [c.name]: c.ports, }; }) ?? 'N/A'; - const conditions = (pod.status?.conditions ?? []) + const conditions = (podObject.status?.conditions ?? []) .map(renderCondition) .reduce((accum, next) => { accum[next[0]] = next[1]; @@ -55,11 +55,11 @@ export const PodDrawer = ({ }, {} as { [key: string]: React.ReactNode }); return { - images: imageChips(pod), + images: imageChips(podObject), phase: phase, - 'Containers Ready': containersReady(pod), - 'Total Restarts': totalRestarts(pod), - 'Container Statuses': containerStatuses(pod), + 'Containers Ready': containersReady(podObject), + 'Total Restarts': totalRestarts(podObject), + 'Container Statuses': containerStatuses(podObject), ...conditions, 'Exposed ports': ports, }; diff --git a/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx b/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx index d48f17813a..d0962c6314 100644 --- a/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx +++ b/plugins/kubernetes/src/components/ServicesAccordions/ServiceDrawer.tsx @@ -31,8 +31,8 @@ export const ServiceDrawer = ({ object={service} expanded={expanded} kind="Service" - renderObject={(service: V1Service) => { - return service.spec || {}; + renderObject={(serviceObject: V1Service) => { + return serviceObject.spec || {}; }} > { export const containersReady = (pod: V1Pod): string => { const containerStatuses = pod.status?.containerStatuses ?? []; - const containersReady = containerStatuses.filter(cs => cs.ready).length; + const containersReadyItem = containerStatuses.filter(cs => cs.ready).length; - return `${containersReady}/${containerStatuses.length}`; + return `${containersReadyItem}/${containerStatuses.length}`; }; export const totalRestarts = (pod: V1Pod): number => { @@ -47,8 +47,8 @@ export const totalRestarts = (pod: V1Pod): number => { }; export const containerStatuses = (pod: V1Pod): ReactNode => { - const containerStatuses = pod.status?.containerStatuses ?? []; - const errors = containerStatuses.reduce((accum, next) => { + const containerStatusesItem = pod.status?.containerStatuses ?? []; + const errors = containerStatusesItem.reduce((accum, next) => { if (next.state === undefined) { return accum; } 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/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/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/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 f5a1acd5e6..506a98d012 100644 --- a/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx +++ b/plugins/org/src/components/Cards/Group/GroupProfile/GroupProfileCard.tsx @@ -73,12 +73,12 @@ export const GroupProfileCard = ({ } = group; const parent = group?.relations ?.filter(r => r.type === RELATION_CHILD_OF) - ?.map(group => group.target.name) + ?.map(groupItem => groupItem.target.name) .toString(); const childrens = group?.relations ?.filter(r => r.type === RELATION_PARENT_OF) - ?.map(group => group.target.name); + ?.map(groupItem => groupItem.target.name); const displayName = profile?.displayName ?? name; 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/package.json b/plugins/pagerduty/package.json index 0e87bdc2d7..a5db20e9ab 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,9 @@ "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/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 +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/pagerduty/src/components/Escalation/EscalationPolicy.tsx b/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx index faa480f6e2..6fd036330a 100644 --- a/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx +++ b/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx @@ -32,11 +32,11 @@ export const EscalationPolicy = ({ policyId }: Props) => { const { value: users, loading, error } = useAsync(async () => { const oncalls = await api.getOnCallByPolicyId(policyId); - const users = oncalls + const usersItem = oncalls .sort((a, b) => a.escalation_level - b.escalation_level) .map(oncall => oncall.user); - return users; + return usersItem; }); if (error) { diff --git a/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx b/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx index 4fa88a1b9a..c390ed1f82 100644 --- a/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx +++ b/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx @@ -52,11 +52,11 @@ export const TriggerDialog = ({ const [description, setDescription] = useState(''); const [{ value, loading, error }, handleTriggerAlarm] = useAsyncFn( - async (description: string) => + async (descriptions: string) => await api.triggerAlarm({ integrationKey, source: window.location.toString(), - description, + description: descriptions, userName, }), ); 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/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/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/README.md b/plugins/rollbar/README.md index cc862051f7..6337d45ffe 100644 --- a/plugins/rollbar/README.md +++ b/plugins/rollbar/README.md @@ -19,17 +19,7 @@ yarn add @backstage/plugin-rollbar export { plugin as Rollbar } from '@backstage/plugin-rollbar'; ``` -4. Add plugin API to your Backstage instance: - -```ts -// packages/app/src/api.ts -import { RollbarClient, rollbarApiRef } from '@backstage/plugin-rollbar'; - -// ... -builder.add(rollbarApiRef, new RollbarClient({ discoveryApi })); -``` - -5. Add to the app `EntityPage` component: +4. Add to the app `EntityPage` component: ```ts // packages/app/src/components/catalog/EntityPage.tsx @@ -48,7 +38,7 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => ( ); ``` -6. Setup the `app.config.yaml` and account token environment variable +5. Setup the `app.config.yaml` and account token environment variable ```yaml # app.config.yaml @@ -59,7 +49,7 @@ rollbar: $env: ROLLBAR_ACCOUNT_TOKEN ``` -7. Annotate entities with the rollbar project slug +6. Annotate entities with the rollbar project slug ```yaml # pump-station-catalog-component.yaml @@ -71,7 +61,7 @@ metadata: rollbar.com/project-slug: project-name ``` -8. Run app with `yarn start` and navigate to `/rollbar` or a catalog entity +7. Run app with `yarn start` and navigate to `/rollbar` or a catalog entity ## Features diff --git a/plugins/rollbar/dev/index.tsx b/plugins/rollbar/dev/index.tsx index 812a5585d4..6cac0d9a0c 100644 --- a/plugins/rollbar/dev/index.tsx +++ b/plugins/rollbar/dev/index.tsx @@ -15,6 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; +import { rollbarPlugin } from '../src/plugin'; -createDevApp().registerPlugin(plugin).render(); +createDevApp().registerPlugin(rollbarPlugin).render(); 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/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx b/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx index 888b9aabe0..07a39bd147 100644 --- a/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx +++ b/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx @@ -14,14 +14,18 @@ * limitations under the License. */ -import React from 'react'; import { Entity } from '@backstage/catalog-model'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import React from 'react'; import { RollbarProject } from '../RollbarProject/RollbarProject'; type Props = { - entity: Entity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; }; -export const EntityPageRollbar = ({ entity }: Props) => { +export const EntityPageRollbar = (_props: Props) => { + const { entity } = useEntity(); + return ; }; diff --git a/plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx b/plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx deleted file mode 100644 index 5bd885c488..0000000000 --- a/plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as React from 'react'; -import { - ApiProvider, - ApiRegistry, - ConfigApi, - configApiRef, -} from '@backstage/core'; -import { catalogApiRef, CatalogApi } from '@backstage/plugin-catalog-react'; -import { wrapInTestApp } from '@backstage/test-utils'; -import { render } from '@testing-library/react'; -import { RollbarApi, rollbarApiRef } from '../../api/RollbarApi'; -import { RollbarProject } from '../../api/types'; -import { RollbarHome } from './RollbarHome'; - -describe('RollbarHome component', () => { - const projects: RollbarProject[] = [ - { id: 123, name: 'abc', accountId: 1, status: 'enabled' }, - { id: 456, name: 'xyz', accountId: 1, status: 'enabled' }, - ]; - const rollbarApi: Partial = { - getAllProjects: () => Promise.resolve(projects), - }; - const config: Partial = { - getString: () => 'foo', - getOptionalString: () => 'foo', - }; - - const renderWrapped = (children: React.ReactNode) => - render( - wrapInTestApp( - ) as CatalogApi, - ], - ])} - > - {children} - , - ), - ); - - it('should render rollbar landing page', async () => { - const rendered = renderWrapped(); - expect(rendered.getByText(/Rollbar/)).toBeInTheDocument(); - }); -}); diff --git a/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx b/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx index 34881ba560..b69c69a56b 100644 --- a/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx +++ b/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx @@ -14,8 +14,8 @@ * limitations under the License. */ -import React from 'react'; import { Entity } from '@backstage/catalog-model'; +import React from 'react'; import { useTopActiveItems } from '../../hooks/useTopActiveItems'; import { RollbarTopItemsTable } from '../RollbarTopItemsTable/RollbarTopItemsTable'; diff --git a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx b/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx deleted file mode 100644 index 6aeee782c4..0000000000 --- a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - ApiProvider, - ApiRegistry, - ConfigApi, - configApiRef, -} from '@backstage/core'; -import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; -import { wrapInTestApp } from '@backstage/test-utils'; -import { render } from '@testing-library/react'; -import * as React from 'react'; -import { RollbarApi, rollbarApiRef } from '../../api/RollbarApi'; -import { RollbarTopActiveItem } from '../../api/types'; -import { RollbarProjectPage } from './RollbarProjectPage'; - -describe('RollbarProjectPage component', () => { - const items: RollbarTopActiveItem[] = [ - { - item: { - id: 9898989, - counter: 1234, - environment: 'production', - framework: 2, - lastOccurrenceTimestamp: new Date().getTime() / 1000, - level: 50, - occurrences: 100, - projectId: 12345, - title: 'error occurred', - uniqueOccurrences: 10, - }, - counts: [10, 10, 10, 10, 10, 50], - }, - ]; - const rollbarApi: Partial = { - getTopActiveItems: () => Promise.resolve(items), - }; - const config: Partial = { - getString: () => 'foo', - getOptionalString: () => 'foo', - }; - - const renderWrapped = (children: React.ReactNode) => - render( - wrapInTestApp( - ) as CatalogApi, - ], - ])} - > - {children} - , - ), - ); - - it('should render rollbar project page', async () => { - const rendered = renderWrapped(); - expect(rendered.getByText(/Rollbar/)).toBeInTheDocument(); - }); -}); diff --git a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx b/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx deleted file mode 100644 index 5563a6d7a0..0000000000 --- a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { Content, Header, HeaderLabel, Page } from '@backstage/core'; -import { useCatalogEntity } from '../../hooks/useCatalogEntity'; -import { RollbarProject } from '../RollbarProject/RollbarProject'; - -export const RollbarProjectPage = () => { - const { entity } = useCatalogEntity(); - - return ( - -
- - -
- - {entity ? : 'Loading'} - -
- ); -}; diff --git a/plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx b/plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx deleted file mode 100644 index 5b3631ade9..0000000000 --- a/plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { Link as RouterLink, generatePath } from 'react-router-dom'; -import { Table, TableColumn } from '@backstage/core'; -import { Entity } from '@backstage/catalog-model'; -import { Link } from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; -import { entityRouteRef } from '../../routes'; - -const columns: TableColumn[] = [ - { - title: 'Name', - field: 'metadata.name', - type: 'string', - highlight: true, - render: (entity: any) => ( - - {entity.metadata.name} - - ), - }, - { - title: 'Description', - field: 'metadata.description', - }, -]; - -type Props = { - entities: Entity[]; - loading: boolean; - error?: any; -}; - -export const RollbarProjectTable = ({ entities, loading, error }: Props) => { - if (error) { - return ( -
- - Error encountered while fetching rollbar projects. {error.toString()} - -
- ); - } - - return ( - - ); -}; diff --git a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.test.tsx b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.test.tsx index dc177265cd..2916fefbcf 100644 --- a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.test.tsx +++ b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.test.tsx @@ -17,8 +17,8 @@ import { wrapInTestApp } from '@backstage/test-utils'; import { render } from '@testing-library/react'; import * as React from 'react'; -import { RollbarTopItemsTable } from './RollbarTopItemsTable'; import { RollbarTopActiveItem } from '../../api/types'; +import { RollbarTopItemsTable } from './RollbarTopItemsTable'; const items: RollbarTopActiveItem[] = [ { diff --git a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx index a04155a0c3..c22f813dd9 100644 --- a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx +++ b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx @@ -14,10 +14,10 @@ * limitations under the License. */ -import React from 'react'; import { Table, TableColumn } from '@backstage/core'; import { Box, Link, Typography } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; +import React from 'react'; import { RollbarFrameworkId, RollbarLevel, diff --git a/plugins/rollbar/src/components/Router.tsx b/plugins/rollbar/src/components/Router.tsx index f0756cb02a..7b95a4ec7c 100644 --- a/plugins/rollbar/src/components/Router.tsx +++ b/plugins/rollbar/src/components/Router.tsx @@ -14,29 +14,36 @@ * limitations under the License. */ -import React from 'react'; -import { Routes, Route } from 'react-router'; import { Entity } from '@backstage/catalog-model'; import { MissingAnnotationEmptyState } from '@backstage/core'; -import { catalogRouteRef } from '../routes'; +import { useEntity } from '@backstage/plugin-catalog-react'; +import React from 'react'; +import { Route, Routes } from 'react-router'; import { ROLLBAR_ANNOTATION } from '../constants'; +import { rootRouteRef } from '../plugin'; import { EntityPageRollbar } from './EntityPageRollbar/EntityPageRollbar'; export const isPluginApplicableToEntity = (entity: Entity) => Boolean(entity.metadata.annotations?.[ROLLBAR_ANNOTATION]); type Props = { - entity: Entity; + /** @deprecated The entity is now grabbed from context instead */ + entity?: Entity; }; -export const Router = ({ entity }: Props) => - !isPluginApplicableToEntity(entity) ? ( - - ) : ( +export const Router = (_props: Props) => { + const { entity } = useEntity(); + + if (!isPluginApplicableToEntity(entity)) { + ; + } + + return ( } /> ); +}; diff --git a/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx b/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx index ac1a328521..e944a53551 100644 --- a/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx +++ b/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx @@ -14,9 +14,9 @@ * limitations under the License. */ -import React from 'react'; -import { render } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; +import { render } from '@testing-library/react'; +import React from 'react'; import { TrendGraph } from './TrendGraph'; describe('TrendGraph component', () => { diff --git a/plugins/rollbar/src/index.ts b/plugins/rollbar/src/index.ts index 2a31c91a13..def2d99658 100644 --- a/plugins/rollbar/src/index.ts +++ b/plugins/rollbar/src/index.ts @@ -14,10 +14,16 @@ * limitations under the License. */ -export { plugin } from './plugin'; export * from './api'; -export * from './routes'; -export { Router } from './components/Router'; -export { RollbarProjectPage } from './components/RollbarProjectPage/RollbarProjectPage'; export { EntityPageRollbar } from './components/EntityPageRollbar/EntityPageRollbar'; +export { + isPluginApplicableToEntity, + isPluginApplicableToEntity as isRollbarAvailable, + Router, +} from './components/Router'; export { ROLLBAR_ANNOTATION } from './constants'; +export { + EntityRollbarContent, + rollbarPlugin as plugin, + rollbarPlugin, +} from './plugin'; diff --git a/plugins/rollbar/src/plugin.test.ts b/plugins/rollbar/src/plugin.test.ts index 44c2168c78..7ef23b019a 100644 --- a/plugins/rollbar/src/plugin.test.ts +++ b/plugins/rollbar/src/plugin.test.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { plugin } from './plugin'; +import { rollbarPlugin } from './plugin'; describe('rollbar', () => { it('should export plugin', () => { - expect(plugin).toBeDefined(); + expect(rollbarPlugin).toBeDefined(); }); }); diff --git a/plugins/rollbar/src/plugin.ts b/plugins/rollbar/src/plugin.ts index c3ca6173ff..216713b3fc 100644 --- a/plugins/rollbar/src/plugin.ts +++ b/plugins/rollbar/src/plugin.ts @@ -15,17 +15,21 @@ */ import { - createPlugin, createApiFactory, + createPlugin, + createRoutableExtension, + createRouteRef, discoveryApiRef, } from '@backstage/core'; -import { rootRouteRef, entityRouteRef } from './routes'; -import { RollbarHome } from './components/RollbarHome/RollbarHome'; -import { RollbarProjectPage } from './components/RollbarProjectPage/RollbarProjectPage'; import { rollbarApiRef } from './api/RollbarApi'; import { RollbarClient } from './api/RollbarClient'; -export const plugin = createPlugin({ +export const rootRouteRef = createRouteRef({ + path: '', + title: 'Rollbar', +}); + +export const rollbarPlugin = createPlugin({ id: 'rollbar', apis: [ createApiFactory({ @@ -34,8 +38,14 @@ export const plugin = createPlugin({ factory: ({ discoveryApi }) => new RollbarClient({ discoveryApi }), }), ], - register({ router }) { - router.addRoute(rootRouteRef, RollbarHome); - router.addRoute(entityRouteRef, RollbarProjectPage); + routes: { + entityContent: rootRouteRef, }, }); + +export const EntityRollbarContent = rollbarPlugin.provide( + createRoutableExtension({ + component: () => import('./components/Router').then(m => m.Router), + mountPoint: rootRouteRef, + }), +); 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/package.json b/plugins/scaffolder-backend/package.json index 7af9f567e3..95d15c45a8 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", @@ -59,7 +59,7 @@ "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", diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.test.ts index beba62eb2a..faf7f0f6ff 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.test.ts @@ -62,12 +62,12 @@ describe('BitbucketPreparer', () => { }); it('calls the clone command with the correct arguments if an app password is provided for a repository', async () => { - const preparer = BitbucketPreparer.fromConfig({ + const preparerCheck = BitbucketPreparer.fromConfig({ host: 'bitbucket.org', username: 'fake-user', appPassword: 'fake-password', }); - await preparer.prepare(prepareOptions); + await preparerCheck.prepare(prepareOptions); expect(Git.fromAuth).toHaveBeenCalledWith({ logger, @@ -98,12 +98,11 @@ describe('BitbucketPreparer', () => { }); it('calls the clone command with with token for auth method', async () => { - const preparer = BitbucketPreparer.fromConfig({ + const preparerCheck = BitbucketPreparer.fromConfig({ host: 'bitbucket.org', token: 'fake-token', }); - - await preparer.prepare(prepareOptions); + await preparerCheck.prepare(prepareOptions); expect(Git.fromAuth).toHaveBeenCalledWith({ logger, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.test.ts index 1a3ad76499..77368fc1ab 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.test.ts @@ -56,6 +56,7 @@ describe('CookieCutter Templater', () => { dockerClient: mockDocker, }); + expect(fs.ensureDir).toBeCalledWith(path.join('tempdir', 'intermediate')); expect(fs.writeJson).toBeCalledWith( path.join('tempdir', 'template', 'cookiecutter.json'), expect.objectContaining(values), diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.ts b/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.ts index 09d4faa37c..9568af2a15 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.ts @@ -44,6 +44,7 @@ export class CookieCutter implements TemplaterBase { }: TemplaterRunOptions): Promise { const templateDir = path.join(workspacePath, 'template'); const intermediateDir = path.join(workspacePath, 'intermediate'); + await fs.ensureDir(intermediateDir); const resultDir = path.join(workspacePath, 'result'); // First lets grab the default cookiecutter.json file 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/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx index 528d42b94f..27c5b4f18a 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx @@ -19,7 +19,7 @@ import { Box, Button, Paper, - Step, + Step as StepUI, StepContent, StepLabel, Stepper, @@ -67,7 +67,7 @@ export const MultistepJsonForm = ({ <> {steps.map(({ label, schema, ...formProps }) => ( - + {label}
-
+ ))}
{activeStep === steps.length && ( diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index 64351c7ec8..e1422d4ec1 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -92,8 +92,8 @@ export const TemplatePage = () => { ); const [jobId, setJobId] = useState(null); - const job = useJobPolling(jobId, async job => { - if (!job.metadata.catalogInfoUrl) { + const job = useJobPolling(jobId, async jobItem => { + if (!jobItem.metadata.catalogInfoUrl) { errorApi.post( new Error(`No catalogInfoUrl returned from the scaffolder`), ); @@ -103,7 +103,9 @@ export const TemplatePage = () => { try { const { entities: [createdEntity], - } = await catalogApi.addLocation({ target: job.metadata.catalogInfoUrl }); + } = await catalogApi.addLocation({ + target: jobItem.metadata.catalogInfoUrl, + }); const resolvedPath = generatePath( `/catalog/${entityRoute.path}`, @@ -122,8 +124,8 @@ export const TemplatePage = () => { const handleCreate = async () => { try { - const jobId = await scaffolderApi.scaffold(templateName, formState); - setJobId(jobId); + const id = await scaffolderApi.scaffold(templateName, formState); + setJobId(id); setModalOpen(true); } catch (e) { errorApi.post(e); 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/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/components/SearchResult/SearchResult.tsx b/plugins/search/src/components/SearchResult/SearchResult.tsx index 3c43c1d24c..c4d8809732 100644 --- a/plugins/search/src/components/SearchResult/SearchResult.tsx +++ b/plugins/search/src/components/SearchResult/SearchResult.tsx @@ -57,11 +57,6 @@ type TableHeaderProps = { handleToggleFilters: () => void; }; -type Filters = { - selected: string; - checked: Array; -}; - // TODO: move out column to make the search result component more generic const columns: TableColumn[] = [ { 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/config.d.ts b/plugins/techdocs-backend/config.d.ts index b51d86138a..7ec1162d03 100644 --- a/plugins/techdocs-backend/config.d.ts +++ b/plugins/techdocs-backend/config.d.ts @@ -14,17 +14,12 @@ * limitations under the License. */ /** - * techdocs schema below is an abstract of what's used within techdocs-backend and for its visibility - * to view the complete techdoc schema please refer: plugins/techdocs/config.d.ts + * TechDocs schema below is an abstract of what's used within techdocs-backend and for its visibility + * to view the complete TechDocs schema please refer: plugins/techdocs/config.d.ts * */ export interface Config { /** Configuration options for the techdocs-backend plugin */ techdocs: { - /** - * attr: 'storageUrl' - accepts a string value - * e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs - */ - storageUrl: string; /** * documentation building process depends on the builder attr * attr: 'builder' - accepts a string value @@ -45,5 +40,11 @@ export interface Config { */ type: 'local' | 'googleGcs' | 'awsS3'; }; + /** + * attr: 'storageUrl' - accepts a string value + * e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs + * @deprecated + */ + storageUrl?: string; }; } 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-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index dc5e6a4911..fe7b52ab52 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -102,7 +102,9 @@ export async function createRouter({ router.get('/docs/:namespace/:kind/:name/*', async (req, res) => { const { kind, namespace, name } = req.params; - const storageUrl = config.getString('techdocs.storageUrl'); + const storageUrl = + config.getOptionalString('techdocs.storageUrl') ?? + `${await discovery.getBaseUrl('techdocs')}/static/docs`; const catalogUrl = await discovery.getBaseUrl('catalog'); const triple = [kind, namespace, name].map(encodeURIComponent).join('/'); 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/config.d.ts b/plugins/techdocs/config.d.ts index 0af3ab4290..1104d75237 100644 --- a/plugins/techdocs/config.d.ts +++ b/plugins/techdocs/config.d.ts @@ -17,17 +17,6 @@ export interface Config { /** Configuration options for the techdocs plugin */ techdocs: { - /** - * attr: 'requestUrl' - accepts a string value - * e.g. requestUrl: http://localhost:7000/api/techdocs - * @visibility frontend - */ - requestUrl: string; - /** - * attr: 'storageUrl' - accepts a string value - * e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs - */ - storageUrl: string; /** * documentation building process depends on the builder attr * attr: 'builder' - accepts a string value @@ -184,5 +173,18 @@ export interface Config { credentials?: string; }; }; + /** + * attr: 'requestUrl' - accepts a string value + * e.g. requestUrl: http://localhost:7000/api/techdocs + * @visibility frontend + * @deprecated + */ + requestUrl?: string; + /** + * attr: 'storageUrl' - accepts a string value + * e.g. storageUrl: http://localhost:7000/api/techdocs/static/docs + * @deprecated + */ + storageUrl?: string; }; } diff --git a/plugins/techdocs/dev/api.ts b/plugins/techdocs/dev/api.ts index ae2b8c58ae..7d0679f6f6 100644 --- a/plugins/techdocs/dev/api.ts +++ b/plugins/techdocs/dev/api.ts @@ -13,20 +13,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { DiscoveryApi } from '@backstage/core'; +import { Config } from '@backstage/config'; import { EntityName } from '@backstage/catalog-model'; import { TechDocsStorage } from '../src/api'; export class TechDocsDevStorageApi implements TechDocsStorage { - public apiOrigin: string; + public configApi: Config; + public discoveryApi: DiscoveryApi; - constructor({ apiOrigin }: { apiOrigin: string }) { - this.apiOrigin = apiOrigin; + constructor({ + configApi, + discoveryApi, + }: { + configApi: Config; + discoveryApi: DiscoveryApi; + }) { + this.configApi = configApi; + this.discoveryApi = discoveryApi; + } + + async getApiOrigin() { + return ( + this.configApi.getOptionalString('techdocs.requestUrl') ?? + (await this.discoveryApi.getBaseUrl('techdocs')) + ); } async getEntityDocs(entityId: EntityName, path: string) { const { name } = entityId; - const url = `${this.apiOrigin}/${name}/${path}`; + const apiOrigin = await this.getApiOrigin(); + const url = `${apiOrigin}/${name}/${path}`; const request = await fetch( `${url.endsWith('/') ? url : `${url}/`}index.html`, @@ -39,8 +57,13 @@ export class TechDocsDevStorageApi implements TechDocsStorage { return request.text(); } - getBaseUrl(oldBaseUrl: string, entityId: EntityName, path: string): string { + async getBaseUrl( + oldBaseUrl: string, + entityId: EntityName, + path: string, + ): Promise { const { name } = entityId; - return new URL(oldBaseUrl, `${this.apiOrigin}/${name}/${path}`).toString(); + const apiOrigin = await this.getApiOrigin(); + return new URL(oldBaseUrl, `${apiOrigin}/${name}/${path}`).toString(); } } diff --git a/plugins/techdocs/dev/index.tsx b/plugins/techdocs/dev/index.tsx index 12974ef8b7..42fa9a9ec4 100644 --- a/plugins/techdocs/dev/index.tsx +++ b/plugins/techdocs/dev/index.tsx @@ -14,6 +14,7 @@ * limitations under the License. */ +import { configApiRef, discoveryApiRef } from '@backstage/core'; import { createDevApp } from '@backstage/dev-utils'; import { plugin } from '../src/plugin'; import { TechDocsDevStorageApi } from './api'; @@ -22,10 +23,11 @@ import { techdocsStorageApiRef } from '../src'; createDevApp() .registerApi({ api: techdocsStorageApiRef, - deps: {}, - factory: () => + deps: { configApi: configApiRef, discoveryApi: discoveryApiRef }, + factory: ({ configApi, discoveryApi }) => new TechDocsDevStorageApi({ - apiOrigin: 'http://localhost:3000/api', + configApi, + discoveryApi, }), }) .registerPlugin(plugin) diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 90c8fd3840..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", @@ -31,12 +31,13 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.7.0", - "@backstage/core": "^0.5.0", - "@backstage/plugin-catalog-react": "^0.0.1", + "@backstage/config": "^0.1.2", + "@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", @@ -49,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/api.test.ts b/plugins/techdocs/src/api.test.ts index 132976e280..734650d7c8 100644 --- a/plugins/techdocs/src/api.test.ts +++ b/plugins/techdocs/src/api.test.ts @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { Config } from '@backstage/config'; +import { UrlPatternDiscovery } from '@backstage/core'; import { TechDocsStorageApi } from './api'; -const DOC_STORAGE_URL = 'https://example-storage.com'; - const mockEntity = { kind: 'Component', namespace: 'default', @@ -24,19 +24,31 @@ const mockEntity = { }; describe('TechDocsStorageApi', () => { - it('should return correct base url based on defined storage', () => { - const storageApi = new TechDocsStorageApi({ apiOrigin: DOC_STORAGE_URL }); + const mockBaseUrl = 'http://backstage:9191/api/techdocs'; + const configApi = { + getOptionalString: () => 'http://backstage:9191/api/techdocs', + } as Partial; + const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); - expect(storageApi.getBaseUrl('test.js', mockEntity, '')).toEqual( - `${DOC_STORAGE_URL}/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test.js`, + it('should return correct base url based on defined storage', async () => { + // @ts-ignore Partial not assignable to Config. + const storageApi = new TechDocsStorageApi({ configApi, discoveryApi }); + + await expect( + storageApi.getBaseUrl('test.js', mockEntity, ''), + ).resolves.toEqual( + `${mockBaseUrl}/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test.js`, ); }); - it('should return base url with correct entity structure', () => { - const storageApi = new TechDocsStorageApi({ apiOrigin: DOC_STORAGE_URL }); + it('should return base url with correct entity structure', async () => { + // @ts-ignore Partial not assignable to Config. + const storageApi = new TechDocsStorageApi({ configApi, discoveryApi }); - expect(storageApi.getBaseUrl('test/', mockEntity, '')).toEqual( - `${DOC_STORAGE_URL}/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test/`, + await expect( + storageApi.getBaseUrl('test/', mockEntity, ''), + ).resolves.toEqual( + `${mockBaseUrl}/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test/`, ); }); }); diff --git a/plugins/techdocs/src/api.ts b/plugins/techdocs/src/api.ts index 3a950aeeb3..a8b1f1e34f 100644 --- a/plugins/techdocs/src/api.ts +++ b/plugins/techdocs/src/api.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { createApiRef } from '@backstage/core'; +import { createApiRef, DiscoveryApi } from '@backstage/core'; +import { Config } from '@backstage/config'; import { EntityName } from '@backstage/catalog-model'; import { TechDocsMetadata } from './types'; @@ -30,7 +31,11 @@ export const techdocsApiRef = createApiRef({ export interface TechDocsStorage { getEntityDocs(entityId: EntityName, path: string): Promise; - getBaseUrl(oldBaseUrl: string, entityId: EntityName, path: string): string; + getBaseUrl( + oldBaseUrl: string, + entityId: EntityName, + path: string, + ): Promise; } export interface TechDocs { @@ -44,10 +49,25 @@ export interface TechDocs { * @property {string} apiOrigin Set to techdocs.requestUrl as the URL for techdocs-backend API */ export class TechDocsApi implements TechDocs { - public apiOrigin: string; + public configApi: Config; + public discoveryApi: DiscoveryApi; - constructor({ apiOrigin }: { apiOrigin: string }) { - this.apiOrigin = apiOrigin; + constructor({ + configApi, + discoveryApi, + }: { + configApi: Config; + discoveryApi: DiscoveryApi; + }) { + this.configApi = configApi; + this.discoveryApi = discoveryApi; + } + + async getApiOrigin() { + return ( + this.configApi.getOptionalString('techdocs.requestUrl') ?? + (await this.discoveryApi.getBaseUrl('techdocs')) + ); } /** @@ -62,7 +82,8 @@ export class TechDocsApi implements TechDocs { async getTechDocsMetadata(entityId: EntityName) { const { kind, namespace, name } = entityId; - const requestUrl = `${this.apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`; + const apiOrigin = await this.getApiOrigin(); + const requestUrl = `${apiOrigin}/metadata/techdocs/${namespace}/${kind}/${name}`; const request = await fetch(`${requestUrl}`); const res = await request.json(); @@ -81,7 +102,8 @@ export class TechDocsApi implements TechDocs { async getEntityMetadata(entityId: EntityName) { const { kind, namespace, name } = entityId; - const requestUrl = `${this.apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`; + const apiOrigin = await this.getApiOrigin(); + const requestUrl = `${apiOrigin}/metadata/entity/${namespace}/${kind}/${name}`; const request = await fetch(`${requestUrl}`); const res = await request.json(); @@ -96,10 +118,25 @@ export class TechDocsApi implements TechDocs { * @property {string} apiOrigin Set to techdocs.requestUrl as the URL for techdocs-backend API */ export class TechDocsStorageApi implements TechDocsStorage { - public apiOrigin: string; + public configApi: Config; + public discoveryApi: DiscoveryApi; - constructor({ apiOrigin }: { apiOrigin: string }) { - this.apiOrigin = apiOrigin; + constructor({ + configApi, + discoveryApi, + }: { + configApi: Config; + discoveryApi: DiscoveryApi; + }) { + this.configApi = configApi; + this.discoveryApi = discoveryApi; + } + + async getApiOrigin() { + return ( + this.configApi.getOptionalString('techdocs.requestUrl') ?? + (await this.discoveryApi.getBaseUrl('techdocs')) + ); } /** @@ -113,7 +150,8 @@ export class TechDocsStorageApi implements TechDocsStorage { async getEntityDocs(entityId: EntityName, path: string) { const { kind, namespace, name } = entityId; - const url = `${this.apiOrigin}/docs/${namespace}/${kind}/${name}/${path}`; + const apiOrigin = await this.getApiOrigin(); + const url = `${apiOrigin}/docs/${namespace}/${kind}/${name}/${path}`; const request = await fetch( `${url.endsWith('/') ? url : `${url}/`}index.html`, @@ -132,12 +170,18 @@ export class TechDocsStorageApi implements TechDocsStorage { return request.text(); } - getBaseUrl(oldBaseUrl: string, entityId: EntityName, path: string): string { + async getBaseUrl( + oldBaseUrl: string, + entityId: EntityName, + path: string, + ): Promise { const { kind, namespace, name } = entityId; + const apiOrigin = await this.getApiOrigin(); + return new URL( oldBaseUrl, - `${this.apiOrigin}/docs/${namespace}/${kind}/${name}/${path}`, + `${apiOrigin}/docs/${namespace}/${kind}/${name}/${path}`, ).toString(); } } diff --git a/plugins/techdocs/src/plugin.ts b/plugins/techdocs/src/plugin.ts index 576ba0a292..982b749f2c 100644 --- a/plugins/techdocs/src/plugin.ts +++ b/plugins/techdocs/src/plugin.ts @@ -34,6 +34,7 @@ import { createRouteRef, createApiFactory, configApiRef, + discoveryApiRef, } from '@backstage/core'; import { techdocsStorageApiRef, @@ -57,24 +58,25 @@ export const rootCatalogDocsRouteRef = createRouteRef({ title: 'Docs', }); -// TODO: Use discovery API for frontend to get URL for techdocs-backend instead of requestUrl export const plugin = createPlugin({ id: 'techdocs', apis: [ createApiFactory({ api: techdocsStorageApiRef, - deps: { configApi: configApiRef }, - factory: ({ configApi }) => + deps: { configApi: configApiRef, discoveryApi: discoveryApiRef }, + factory: ({ configApi, discoveryApi }) => new TechDocsStorageApi({ - apiOrigin: configApi.getString('techdocs.requestUrl'), + configApi, + discoveryApi, }), }), createApiFactory({ api: techdocsApiRef, - deps: { configApi: configApiRef }, - factory: ({ configApi }) => + deps: { configApi: configApiRef, discoveryApi: discoveryApiRef }, + factory: ({ configApi, discoveryApi }) => new TechDocsApi({ - apiOrigin: configApi.getString('techdocs.requestUrl'), + configApi, + discoveryApi, }), }), ], diff --git a/plugins/techdocs/src/reader/components/Reader.tsx b/plugins/techdocs/src/reader/components/Reader.tsx index 1264e2b6eb..50990911a1 100644 --- a/plugins/techdocs/src/reader/components/Reader.tsx +++ b/plugins/techdocs/src/reader/components/Reader.tsx @@ -129,7 +129,7 @@ export const Reader = ({ entityId, onReady }: Props) => { }, }), onCssReady({ - docStorageUrl: techdocsStorageApi.apiOrigin, + docStorageUrl: techdocsStorageApi.getApiOrigin(), onLoading: (dom: Element) => { (dom as HTMLElement).style.setProperty('opacity', '0'); }, diff --git a/plugins/techdocs/src/reader/components/TechDocsHome.tsx b/plugins/techdocs/src/reader/components/TechDocsHome.tsx index 2d8b5c7dcc..f064c35517 100644 --- a/plugins/techdocs/src/reader/components/TechDocsHome.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsHome.tsx @@ -25,13 +25,12 @@ import { import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { Grid } from '@material-ui/core'; import React from 'react'; -import { generatePath, useNavigate } from 'react-router-dom'; +import { generatePath } from 'react-router-dom'; import { useAsync } from 'react-use'; import { rootDocsRouteRef } from '../../plugin'; export const TechDocsHome = () => { const catalogApi = useApi(catalogApiRef); - const navigate = useNavigate(); const { value, loading, error } = useAsync(async () => { const response = await catalogApi.getEntities(); @@ -80,15 +79,11 @@ export const TechDocsHome = () => { ? value.map((entity, index: number) => ( - navigate( - generatePath(rootDocsRouteRef.path, { - namespace: entity.metadata.namespace ?? 'default', - kind: entity.kind, - name: entity.metadata.name, - }), - ) - } + href={generatePath(rootDocsRouteRef.path, { + namespace: entity.metadata.namespace ?? 'default', + kind: entity.kind, + name: entity.metadata.name, + })} title={entity.metadata.name} label="Read Docs" description={entity.metadata.description} diff --git a/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx index bc84f792a7..4b578bef38 100644 --- a/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx @@ -56,7 +56,8 @@ describe('', () => { }; const techdocsStorageApi: Partial = { getEntityDocs: (): Promise => Promise.resolve('String'), - getBaseUrl: (): string => '', + getBaseUrl: (): Promise => Promise.resolve('String'), + getApiOrigin: (): Promise => Promise.resolve('String'), }; const apiRegistry = ApiRegistry.from([ diff --git a/plugins/techdocs/src/reader/transformers/addBaseUrl.test.ts b/plugins/techdocs/src/reader/transformers/addBaseUrl.test.ts index 728c39826d..10c7191b63 100644 --- a/plugins/techdocs/src/reader/transformers/addBaseUrl.test.ts +++ b/plugins/techdocs/src/reader/transformers/addBaseUrl.test.ts @@ -21,7 +21,7 @@ import { TechDocsStorage } from '../../api'; const DOC_STORAGE_URL = 'https://example-host.storage.googleapis.com'; const techdocsStorageApi: TechDocsStorage = { - getBaseUrl: jest.fn(() => DOC_STORAGE_URL), + getBaseUrl: jest.fn(() => Promise.resolve(DOC_STORAGE_URL)), getEntityDocs: () => new Promise(resolve => resolve('yes!')), }; diff --git a/plugins/techdocs/src/reader/transformers/addBaseUrl.ts b/plugins/techdocs/src/reader/transformers/addBaseUrl.ts index 8d9d5a7294..2872ad36cc 100644 --- a/plugins/techdocs/src/reader/transformers/addBaseUrl.ts +++ b/plugins/techdocs/src/reader/transformers/addBaseUrl.ts @@ -35,12 +35,12 @@ export const addBaseUrl = ({ ): void => { Array.from(list) .filter(elem => !!elem.getAttribute(attributeName)) - .forEach((elem: T) => { + .forEach(async (elem: T) => { const elemAttribute = elem.getAttribute(attributeName); if (!elemAttribute) return; elem.setAttribute( attributeName, - techdocsStorageApi.getBaseUrl(elemAttribute, entityId, path), + await techdocsStorageApi.getBaseUrl(elemAttribute, entityId, path), ); }); }; diff --git a/plugins/techdocs/src/reader/transformers/onCssReady.test.ts b/plugins/techdocs/src/reader/transformers/onCssReady.test.ts index 67ae38c56b..1fbc59e213 100644 --- a/plugins/techdocs/src/reader/transformers/onCssReady.test.ts +++ b/plugins/techdocs/src/reader/transformers/onCssReady.test.ts @@ -22,8 +22,9 @@ import { } from '../../test-utils'; import { onCssReady } from '../transformers'; -const docStorageUrl: string = - 'https://techdocs-mock-sites.storage.googleapis.com'; +const docStorageUrl: Promise = Promise.resolve( + 'https://techdocs-mock-sites.storage.googleapis.com', +); const fixture = ` diff --git a/plugins/techdocs/src/reader/transformers/onCssReady.ts b/plugins/techdocs/src/reader/transformers/onCssReady.ts index dd50879459..50dbe52cbd 100644 --- a/plugins/techdocs/src/reader/transformers/onCssReady.ts +++ b/plugins/techdocs/src/reader/transformers/onCssReady.ts @@ -17,7 +17,7 @@ import type { Transformer } from './index'; type OnCssReadyOptions = { - docStorageUrl: string; + docStorageUrl: Promise; onLoading: (dom: Element) => void; onLoaded: (dom: Element) => void; }; @@ -30,7 +30,9 @@ export const onCssReady = ({ return dom => { const cssPages = Array.from( dom.querySelectorAll('head > link[rel="stylesheet"]'), - ).filter(elem => elem.getAttribute('href')?.startsWith(docStorageUrl)); + ).filter(async elem => + elem.getAttribute('href')?.startsWith(await docStorageUrl), + ); let count = cssPages.length; 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/user-settings/src/plugin.ts b/plugins/user-settings/src/plugin.ts index 5353c12f10..36d2254c11 100644 --- a/plugins/user-settings/src/plugin.ts +++ b/plugins/user-settings/src/plugin.ts @@ -21,6 +21,7 @@ import { } from '@backstage/core'; export const settingsRouteRef = createRouteRef({ + path: '/settings', title: 'Settings', }); 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 aac0d3735b..482ce1f737 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2655,53 +2655,54 @@ resolved "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-5.0.0.tgz#3ba791f37b90e7f6170d252b63aacfcae943c039" integrity sha512-WmKrB/575EJCzbeSJR3YQ5sET5FaizeljLRw1382qVUeGqzuWBgIS+AF5a0FO51uQTrDpoRgvuHC2IWVsgwkkA== -"@changesets/apply-release-plan@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-4.0.0.tgz#e78efb56a4e459a8dab814ba43045f2ace0f27c9" - integrity sha512-MrcUd8wIlQ4S/PznzqJVsmnEpUGfPEkCGF54iqt8G05GEqi/zuxpoTfebcScpj5zeiDyxFIcA9RbeZ3pvJJxoA== +"@changesets/apply-release-plan@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-4.2.0.tgz#f1005815f27c3238f66507e90c6ae14d8fc62b41" + integrity sha512-/vt6UwgQldhOw93Gb8llI5OuYGlJt2+U45AfcXsoxzl8gZzCmChGm3vUaQJYbmtL8TbL8OOVXHRIKJJidMNPKw== dependencies: - "@babel/runtime" "^7.4.4" - "@changesets/config" "^1.2.0" + "@babel/runtime" "^7.10.4" + "@changesets/config" "^1.5.0" "@changesets/get-version-range-type" "^0.3.2" "@changesets/git" "^1.0.5" - "@changesets/types" "^3.1.0" + "@changesets/types" "^3.3.0" "@manypkg/get-packages" "^1.0.1" + detect-indent "^6.0.0" fs-extra "^7.0.1" lodash.startcase "^4.4.0" outdent "^0.5.0" - prettier "^1.18.2" + prettier "^1.19.1" 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== +"@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== dependencies: "@babel/runtime" "^7.10.4" "@changesets/errors" "^0.1.4" - "@changesets/get-dependents-graph" "^1.1.3" - "@changesets/types" "^3.1.0" + "@changesets/get-dependents-graph" "^1.2.0" + "@changesets/types" "^3.3.0" "@manypkg/get-packages" "^1.0.1" semver "^5.4.1" -"@changesets/cli@^2.11.0": - version "2.12.0" - resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.12.0.tgz#26124b051e6ce6dcc5aa4595588c8cb2ce3e4363" - integrity sha512-dGdFkg75zsaEObsG8gwMLglS6sJVjXWwgVTAzEIjqIoWVnKwqZqccTb4gn0noq47uCwy7SqxiAJqGibIy9UOKw== +"@changesets/cli@^2.14.0": + version "2.14.0" + resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.14.0.tgz#b8d1d33d832c640ce0b95333bbd8d5ac5b9c9824" + integrity sha512-rbQMRDXl1cXOglnjUvYyrFLlYBbS0YZdfxZfW3ZbGLzLoS4n50+B9fLSE9oW20hQuL3zAnyLyacb9cwNhF2lig== dependencies: "@babel/runtime" "^7.10.4" - "@changesets/apply-release-plan" "^4.0.0" - "@changesets/assemble-release-plan" "^4.0.0" - "@changesets/config" "^1.4.0" + "@changesets/apply-release-plan" "^4.2.0" + "@changesets/assemble-release-plan" "^4.1.0" + "@changesets/config" "^1.5.0" "@changesets/errors" "^0.1.4" - "@changesets/get-dependents-graph" "^1.1.3" + "@changesets/get-dependents-graph" "^1.2.0" "@changesets/get-release-plan" "^2.0.1" - "@changesets/git" "^1.0.6" + "@changesets/git" "^1.1.0" "@changesets/logger" "^0.0.5" "@changesets/pre" "^1.0.4" "@changesets/read" "^0.4.6" - "@changesets/types" "^3.2.0" + "@changesets/types" "^3.3.0" "@changesets/write" "^0.1.3" "@manypkg/get-packages" "^1.0.1" "@types/semver" "^6.0.0" @@ -2721,15 +2722,15 @@ term-size "^2.1.0" tty-table "^2.8.10" -"@changesets/config@^1.2.0", "@changesets/config@^1.4.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== +"@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== dependencies: "@changesets/errors" "^0.1.4" - "@changesets/get-dependents-graph" "^1.1.3" + "@changesets/get-dependents-graph" "^1.2.0" "@changesets/logger" "^0.0.5" - "@changesets/types" "^3.2.0" + "@changesets/types" "^3.3.0" "@manypkg/get-packages" "^1.0.1" fs-extra "^7.0.1" micromatch "^4.0.2" @@ -2741,12 +2742,12 @@ 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== +"@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" + integrity sha512-96NInEKpEZH8KvmXyh42PynXVAdq3kQ9VjAeswHtJ3umUCeTF42b/KVXaov+5P1RNnaUVtRuEwzs4syGuowDTw== dependencies: - "@changesets/types" "^3.0.0" + "@changesets/types" "^3.3.0" "@manypkg/get-packages" "^1.0.1" chalk "^2.1.0" fs-extra "^7.0.1" @@ -2770,10 +2771,10 @@ 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", "@changesets/git@^1.0.6": - version "1.0.6" - resolved "https://registry.npmjs.org/@changesets/git/-/git-1.0.6.tgz#057e627e5d3fcb74bf6c18d7284e130ba5a7632e" - integrity sha512-e0M06XuME3W5lGhz+CO0vLc60u+hLk/pYjOx/6GXEWuQrwtGgeycFIfRgRt8qTs664o1oKtVHBbd7ItpoWgFfA== +"@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== dependencies: "@babel/runtime" "^7.10.4" "@changesets/errors" "^0.1.4" @@ -2790,9 +2791,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" @@ -2822,10 +2823,10 @@ 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.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== "@changesets/write@^0.1.3": version "0.1.3" @@ -7686,9 +7687,9 @@ integrity sha512-MBSp62AjB1KrSOI3gX9GekddXU5YYQAVA93+aSl78biBqoSzxg876aQY2KJK5Gnfbpqq7O2cadVX5kPAtBqIXw== "@types/zen-observable@^0.8.0": - version "0.8.0" - resolved "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d" - integrity sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg== + version "0.8.2" + resolved "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.2.tgz#808c9fa7e4517274ed555fa158f2de4b4f468e71" + integrity sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg== "@typescript-eslint/eslint-plugin@^v4.14.0": version "4.14.0" @@ -21260,7 +21261,7 @@ prepend-http@^2.0.0: resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@^1.18.2: +prettier@^1.18.2, prettier@^1.19.1: version "1.19.1" resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==