diff --git a/.changeset/cool-months-tickle.md b/.changeset/cool-months-tickle.md new file mode 100644 index 0000000000..281c74bab0 --- /dev/null +++ b/.changeset/cool-months-tickle.md @@ -0,0 +1,17 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +Enhancing GitLab provider with filtering projects by pattern RegExp + +```yaml +providers: + gitlab: + stg: + host: gitlab.stg.company.io + branch: main + projectPattern: 'john/' # new option + entityFilename: template.yaml +``` + +With the aforementioned parameter you can filter projects, and keep only who belongs to the namespace "john". diff --git a/.changeset/create-app-1659429685.md b/.changeset/create-app-1659429685.md new file mode 100644 index 0000000000..b50d431d4b --- /dev/null +++ b/.changeset/create-app-1659429685.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Bumped create-app version. diff --git a/.changeset/eighty-radios-look.md b/.changeset/eighty-radios-look.md new file mode 100644 index 0000000000..2db51d47d7 --- /dev/null +++ b/.changeset/eighty-radios-look.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-sonarqube-backend': minor +--- + +Initial creation of the plugin diff --git a/.changeset/empty-apple-pie.md b/.changeset/empty-apple-pie.md new file mode 100644 index 0000000000..8e9fecdafb --- /dev/null +++ b/.changeset/empty-apple-pie.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Adding a `className` prop to the `MarkdownContent` component diff --git a/.changeset/empty-apples-tie.md b/.changeset/empty-apples-tie.md new file mode 100644 index 0000000000..3ebfe0fc70 --- /dev/null +++ b/.changeset/empty-apples-tie.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder': minor +'@backstage/plugin-scaffolder-backend': minor +--- + +Starting the implementation of the Wizard page for the `next` scaffolder plugin diff --git a/.changeset/flat-zebras-draw.md b/.changeset/flat-zebras-draw.md new file mode 100644 index 0000000000..ba82f156ef --- /dev/null +++ b/.changeset/flat-zebras-draw.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes': patch +--- + +Adds namespace column to Kubernetes error reporting table diff --git a/.changeset/forty-lobsters-guess.md b/.changeset/forty-lobsters-guess.md new file mode 100644 index 0000000000..1a722fa04d --- /dev/null +++ b/.changeset/forty-lobsters-guess.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-sonarqube': minor +--- + +**BREAKING** This plugin now call the `sonarqube-backend` plugin instead of relying on the proxy plugin + +The whole proxy's `'/sonarqube':` key can be removed from your configuration files. + +Then head to the [README in sonarqube-backend plugin page](https://github.com/backstage/backstage/tree/master/plugins/sonarqube-backend/README.md) to learn how to set-up the link to your Sonarqube instances. diff --git a/.changeset/lovely-walls-brush.md b/.changeset/lovely-walls-brush.md new file mode 100644 index 0000000000..8834673d3b --- /dev/null +++ b/.changeset/lovely-walls-brush.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-common': patch +--- + +Export aggregated list of all catalog permissions diff --git a/.changeset/odd-tomatoes-juggle.md b/.changeset/odd-tomatoes-juggle.md new file mode 100644 index 0000000000..336af17eb4 --- /dev/null +++ b/.changeset/odd-tomatoes-juggle.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +Github Entity Provider functionality for adding entities to the catalog. + +This provider replaces the GithubDiscoveryProcessor functionality as providers offer more flexibility with scheduling ingestion, removing and preventing orphaned entities. + +More information can be found on the [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery) page. diff --git a/.changeset/plenty-timers-flow.md b/.changeset/plenty-timers-flow.md new file mode 100644 index 0000000000..8a26c8068b --- /dev/null +++ b/.changeset/plenty-timers-flow.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-cost-insights': patch +'@backstage/plugin-cost-insights-common': patch +--- + +Add name property to Group diff --git a/.changeset/pre.json b/.changeset/pre.json index 6af2afaf45..f20db5bacb 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -165,34 +165,54 @@ "@backstage/plugin-vault": "0.1.1", "@backstage/plugin-vault-backend": "0.2.0", "@backstage/plugin-xcmetrics": "0.2.27", - "@internal/plugin-catalog-customized": "0.0.0" + "@internal/plugin-catalog-customized": "0.0.0", + "@backstage/plugin-sonarqube-backend": "0.0.0" }, "changesets": [ + "big-mirrors-play", "calm-clocks-drum", "create-app-1658824524", + "create-app-1659429685", + "dull-owls-grab", "dull-pumas-hope", "dull-starfishes-chew", + "eighty-radios-look", + "empty-apple-pie", + "empty-apples-tie", "famous-bikes-brush", "fast-panthers-fold", "few-berries-deny", + "forty-lobsters-guess", "fresh-hounds-argue", "friendly-sheep-flash", + "itchy-mice-kiss", "khaki-meals-hammer", + "little-laws-heal", "loud-panthers-arrive", + "lovely-walls-brush", + "mean-ants-hang", "metal-points-itch", "mighty-penguins-tap", "modern-shrimps-wave", "nine-mails-crash", "odd-adults-smash", + "odd-tomatoes-juggle", "olive-tips-camp", "pretty-gifts-do", "purple-apricots-build", + "red-turtles-melt", "renovate-15030f1", "renovate-5b7b62b", + "renovate-5ba3a71", + "rotten-moles-give", "short-trains-roll", "silver-poets-push", "strange-crabs-confess", + "strange-moles-design", + "techdocs-eagles-stare", + "ten-roses-walk", "thick-readers-invite", + "twenty-humans-visit", "violet-mayflies-mix", "violet-trees-play" ] diff --git a/.changeset/red-turtles-melt.md b/.changeset/red-turtles-melt.md new file mode 100644 index 0000000000..436e69116c --- /dev/null +++ b/.changeset/red-turtles-melt.md @@ -0,0 +1,7 @@ +--- +'@backstage/integration': minor +'@backstage/plugin-techdocs-node': minor +'@backstage/plugin-techdocs-module-addons-contrib': patch +--- + +feat(techdocs): add edit button support for bitbucketServer diff --git a/.changeset/rich-readers-return.md b/.changeset/rich-readers-return.md new file mode 100644 index 0000000000..3c8f3d7b5a --- /dev/null +++ b/.changeset/rich-readers-return.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Scroll techdocs navigation into focus and expand any nested navigation items. diff --git a/.changeset/rotten-moles-give.md b/.changeset/rotten-moles-give.md new file mode 100644 index 0000000000..0ca3d3eadc --- /dev/null +++ b/.changeset/rotten-moles-give.md @@ -0,0 +1,7 @@ +--- +'@backstage/integration': patch +--- + +Fixed bug in getGitLabFileFetchUrl where a target whose path did not contain the +`/-/` scope would result in a fetch URL that did not support +private-token-based authentication. diff --git a/.changeset/silver-carpets-grin.md b/.changeset/silver-carpets-grin.md new file mode 100644 index 0000000000..9865393631 --- /dev/null +++ b/.changeset/silver-carpets-grin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-github-issues': minor +--- + +New plugin for displaying GitHub Issues added diff --git a/.changeset/strange-moles-design.md b/.changeset/strange-moles-design.md new file mode 100644 index 0000000000..8515d02e9b --- /dev/null +++ b/.changeset/strange-moles-design.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Fix issue for conditional decisions based on properties stored as arrays, like tags. + +Before this change, having a permission policy returning conditional decisions based on metadata like tags, such like `createCatalogConditionalDecision(permission, catalogConditions.hasMetadata('tags', 'java'),)`, was producing wrong results. The issue occurred when authorizing entities already loaded from the database, for example when authorizing `catalogEntityDeletePermission`. diff --git a/.changeset/techdocs-eagles-stare.md b/.changeset/techdocs-eagles-stare.md new file mode 100644 index 0000000000..cf8bda4024 --- /dev/null +++ b/.changeset/techdocs-eagles-stare.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs-node': patch +--- + +Bump default `TechDocs` image to `v1.1.0`, see the release [here](https://github.com/backstage/techdocs-container/releases/tag/v1.1.0). diff --git a/.changeset/ten-roses-walk.md b/.changeset/ten-roses-walk.md new file mode 100644 index 0000000000..87b711db2a --- /dev/null +++ b/.changeset/ten-roses-walk.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-sonarqube': patch +--- + +Add ability to provide an optional Sonarqube instance into the annotation in the `catalog-info.yaml` file diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index cd01425a5e..5324ce2b2a 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -283,6 +283,7 @@ shoutout siloed Sinon Snyk +Sonarqube sourcemaps sparklines Splunk diff --git a/ADOPTERS.md b/ADOPTERS.md index 8fef7803a4..828e1c0f76 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -168,7 +168,7 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi | [Forto](https://forto.com) | [Rodolfo Matos](mailto:rodolfo.matos@forto.com) | Still in a experimental phase/assessing the organisational fit. We will be using it mostly a developer portal -- pretty standard use case. | | [BetterUp](https://betterup.com) | [Jordan Hochenbaum](mailto:jordan.hochenbaum@betterup.co) | We're starting to use Backstage as the central hub for service discovery, documentation, and develop experience. | | [warung pintar](https://warungpintar.co.id/) | [Muhammad Rafly Andrianza](mailto:rafly.andrianza@warungpintar.co) | Initial Work Developer Portal with TechRadar, Service Catalogue, TechDocs, anything about platform & infrastructure resources. | -| [RaiaDrogasil](https://rd.com.br/) | [Michael Lima](mailto:midsilva@rd.com.br) | We are building our developer portal. Software catalog, Tech Radar and Scaffolding are among the initial features. | +| [RaiaDrogasil](https://rd.com.br/) | [Michael Lima](mailto:midsilva@rd.com.br) | We are building our developer portal. Software catalog, Tech Radar and Scaffolding are among the initial features. | | [AEB](https://www.aeb.com/) | [David Fankhänel](mailto:dfl@aeb.com) | Central developer platform for creating new apps via templates, getting an overview via software catalog, etc | | [SALTO Systems](https://saltosystems.com) | [Ian Cowley](mailto:i.cowley@saltosystems.com) | Currently using Backstage as an internal documentation portal. | | [Lummo](https://lummo.com) | [Anjul Sahu](mailto:anjul@lummo.com) | We are building the internal developer portal using Backstage and bringing up all integrations and service information at one place. | @@ -196,9 +196,14 @@ _You can do this by using the [Adopter form](https://form.typeform.com/to/zcOaKi | [Adaptavist](https://adaptavist.com) | [Lilly Holden](mailto:lholden@adaptavist.com) | Developer portal, service catalog, documentation and self-service platform | | [Shipshape](https://shipshape.io) | [Chuck Carpenter](mailto:chuck@shipshape.io) | We are a consultancy helping teams implement and customize Backstage. | | [Backbase](https://backbase.com) | [Nicolas Torres](mailto:ntorres.dev@gmail.com) | To catalog components and teams | -| [https://www.clear.sale](https://www.clear.sale) | [Paulo Baima](mailto:paulo.filho@clear.sale) | Central Hub for all the company modules, enabling the track of ownership of components and resources and how they relate to each other. | -| [www.leroymerlin.com.br](https://www.leroymerlin.com.br) | [Rodrigo Franzoni](mailto:rfranzoni@leroymerlin.com.br) | Our engineers use the Backstage to solve problems around ownership and visibility of our applications, access service catalog, documentation, observability and infrastructure. | +| [clearSale](https://www.clear.sale) | [Paulo Baima](mailto:paulo.filho@clear.sale) | Central Hub for all the company modules, enabling the track of ownership of components and resources and how they relate to each other. | +| [LeroyMerlin](https://www.leroymerlin.com.br) | [Rodrigo Franzoni](mailto:rfranzoni@leroymerlin.com.br) | Our engineers use the Backstage to solve problems around ownership and visibility of our applications, access service catalog, documentation, observability and infrastructure. | | [Intility](https://intility.no/en/) | [@daniwk](https://github.com/daniwk) | We are creating a developer portal powered by Backstage, with software catalog, documentation, templates and integrations to our infrastructure and internal tools. | -| [ImmobiliareLabs](https://labs.immobiliare.it/) | [@JellyBellyDev](https://github.com/JellyBellyDev) | Centralized portal with our internal services, infrastructures, relationships between systems, technical documentation, templates, monitoring and custom integrations with our own DX tools. | -| [Skillz](https://skillz.com/) | [Peiman Jafari](https://github.com/peimanja) | Internal developers portal for technical documentations, components ownership and relationship, software templates and integrations with internal tools | -| [Telus](https://www.telus.com/en/) | [Leo Li](mailto:leo.li@telus.com) and [Laurent Robichaud](mailto:laurent.robichaud@telus.com) | Simplifying the developer experience through centralized team member portals. Our current focus includes the adoption of Tech Docs, Software Catalog, Software Templates, the plethora of plugins, and contributing features back to Backstage. 🤖 | +| [ImmobiliareLabs](https://labs.immobiliare.it/) | [@JellyBellyDev](https://github.com/JellyBellyDev) | Centralized portal with our internal services, infrastructures, relationships between systems, technical documentation, templates, monitoring and custom integrations with our own DX tools. | +| [Skillz](https://skillz.com/) | [Peiman Jafari](https://github.com/peimanja) | Internal developers portal for technical documentations, components ownership and relationship, software templates and integrations with internal tools | +| [Telus](https://www.telus.com/en/) | [Leo Li](mailto:leo.li@telus.com), [Laurent Robichaud](mailto:laurent.robichaud@telus.com) | Simplifying the developer experience through centralized team member portals. Our current focus includes the adoption of Tech Docs, Software Catalog, Software Templates, the plethora of plugins, and contributing features back to Backstage. 🤖 | +| [Fidelity Investments](https://fidelity.com) | [Ankita Upadhyay](mailto:ankita.upadhyay@fmr.com) | Getting started with the adoption for Monorepo projects | +| [Verisk](https://verisk.com) | [Callen Barton](mailto:cbarton@verisk.com) | Developer portal to quickly create and deploy microservices. | +| [iodigital](https://iodigital.com) | [Jan-Willem Mulder](mailto:jan-willem.mulder@iodigital.com) | Internal developer portal for discovery of applications, projects and teams. Using several plugins like the Software Catalog and Tech Insights for promoting best practices and supporting our SDLC toolchain | +| [Fanatics](https://www.fanaticsinc.com/) | [Rory Scott](mailto:rscott@fanatics.com) | Internal Portal consolidating documentation, making it easier to manage applications, internal developer community platform, and self-service cloud infrastructure + pipelines. | +| [Appfolio](https://appfolio.com) | [Andy Vaughn](mailto:andy.vaughn@appfolio.com) | Internal software catalog, tech radar, documentation portal to disambiguate software and domain ownership, foster exploration of available developer platform services and tools, improve communication, democratize documentation and knowledge sharing, and coordinate the software lifecycle; all in service of a best-in-class developer experience. | diff --git a/docs/auth/cloudflare/access.md b/docs/auth/cloudflare/access.md index 340817097b..c7db308438 100644 --- a/docs/auth/cloudflare/access.md +++ b/docs/auth/cloudflare/access.md @@ -84,19 +84,6 @@ Now the backend is ready to serve auth requests on the frontend sign-in mechanism to poll that endpoint through Cloudflare Access, on the user's behalf. -## Frontend Changes - -It is recommended to use the `ProxiedSignInPage` for this provider, which is -installed in `packages/app/src/App.tsx` like this: - -```diff -+import { ProxiedSignInPage } from '@backstage/core-components'; - - const app = createApp({ - components: { -+ SignInPage: props => , -``` - ## Adding the provider to the Backstage frontend It is recommended to use the `ProxiedSignInPage` for this provider, which is diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index c3559585f7..dc541c5c50 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -236,10 +236,12 @@ kubernetes: ##### `clusters.\*.caData` (optional) -PEM-encoded certificate authority certificates. +Base64-encoded certificate authority bundle in PEM format. The Kubernetes client +will verify that TLS certificate presented by the API server is signed by this +CA. -This values could be obtained via inspecting the Kubernetes config file (usually -at `~/.kube/config`) under `clusters.cluster.certificate-authority-data`. For +This value could be obtained via inspecting the kubeconfig file (usually +at `~/.kube/config`) under `clusters[*].cluster.certificate-authority-data`. For GKE, execute the following command to obtain the value ``` diff --git a/docs/features/software-catalog/external-integrations.md b/docs/features/software-catalog/external-integrations.md index 30bd4c77bc..40f917e2f3 100644 --- a/docs/features/software-catalog/external-integrations.md +++ b/docs/features/software-catalog/external-integrations.md @@ -377,6 +377,10 @@ import { export class SystemXReaderProcessor implements CatalogProcessor { constructor(private readonly reader: UrlReader) {} + getProcessorName(): string { + return 'SystemXReaderProcessor'; + } + async readLocation( location: LocationSpec, _optional: boolean, diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index f8bf98c0e0..c2070e7840 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -278,10 +278,7 @@ Note: We recommend Python version 3.7 or higher. > Caveat: Please install the `mkdocs-techdocs-core` package after all other > Python packages. The order is important to make sure we get correct version of -> some of the dependencies. For example, we want `Markdown` version to be -> [3.2.2](https://github.com/backstage/backstage/blob/f9f70c225548017b6a14daea75b00fbd399c11eb/packages/techdocs-container/techdocs-core/requirements.txt#L11). -> You can also explicitly install `Markdown==3.2.2` after installing all other -> Python packages. +> some of the dependencies. ## Running Backstage locally diff --git a/docs/integrations/github/discovery.md b/docs/integrations/github/discovery.md index a0c3fed153..3b49644613 100644 --- a/docs/integrations/github/discovery.md +++ b/docs/integrations/github/discovery.md @@ -6,6 +6,119 @@ sidebar_label: Discovery description: Automatically discovering catalog entities from repositories in a GitHub organization --- +## GitHub Provider + +The GitHub integration has a discovery provider for discovering catalog +entities within a GitHub organization. The provider will crawl the GitHub +organization and register entities matching the configured path. This can be +useful as an alternative to static locations or manually adding things to the +catalog. This is the prefered method for ingesting entities into the catalog. + +## Installation + +You will have to add the provider in the catalog initialization code of your +backend. They are not installed by default, therefore you have to add a +dependency on `@backstage/plugin-catalog-backend-module-github` to your backend +package. + +```bash +# From your Backstage root directory +yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-github +``` + +And then add the entity provider to your catalog builder: + +```diff + // In packages/backend/src/plugins/catalog.ts ++ import { GitHubEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; + + export default async function createPlugin( + env: PluginEnvironment, + ): Promise { + const builder = await CatalogBuilder.create(env); ++ builder.addEntityProvider( ++ GitHubEntityProvider.fromConfig(env.config, { ++ logger: env.logger, ++ schedule: env.scheduler.createScheduledTaskRunner({ ++ frequency: { minutes: 30 }, ++ timeout: { minutes: 3 }, ++ }), ++ }), ++ ); + + // [...] + } +``` + +## Configuration + +To use the discovery provider, you'll need a GitHub integration +[set up](locations.md) with either a [Personal Access Token](../../getting-started/configuration.md#setting-up-a-github-integration) or [GitHub Apps](./github-apps.md). + +Then you can add a github config to the catalog providers configuration: + +```yaml +catalog: + providers: + github: + # the provider ID can be any camelCase string + providerId: + organization: 'backstage' # string + catalogPath: '/catalog-info.yaml' # string + filters: + branch: 'main' # string + repository: '.*' # Regex + customProviderId: + organization: 'new-org' # string + catalogPath: '/custom/path/catalog-info.yaml' # string + filters: # optional filters + branch: 'develop' # optional string + repository: '.*' # optional Regex +``` + +This provider supports multiple organizations via unique provider IDs. + +> **Note:** It is possible but certainly not recommended to skip the provider ID level. +> If you do so, `default` will be used as provider ID. + +- **`catalogPath`** _(optional)_: + Default: `/catalog-info.yaml`. + Path where to look for `catalog-info.yaml` files. + When started with `/`, it is an absolute path from the repo root. +- **filters** _(optional)_: + - **branch** _(optional)_: + String used to filter results based on the branch name. + - **repository** _(optional)_: + Regular expression used to filter results based on the repository name. +- **organization**: + Name of your organization account/workspace. + If you want to add multiple organizations, you need to add one provider config each. + +## GitHub API Rate Limits + +GitHub [rate limits](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting) API requests to 5,000 per hour (or more for Enterprise +accounts). The snippet below refreshes the Backstage catalog data every 35 minutes, which issues an API request for each discovered location. + +If your requests are too frequent then you may get throttled by +rate limiting. You can change the refresh frequency of the catalog in your `packages/backend/src/plugins/catalog.ts` file: + +```typescript +schedule: env.scheduler.createScheduledTaskRunner({ + frequency: { minutes: 35 }, + timeout: { minutes: 30 }, +}), +``` + +More information about scheduling can be found on the [TaskScheduleDefinition](https://backstage.io/docs/reference/backend-tasks.taskscheduledefinition) page. + +Alternatively, or additionally, you can configure [github-apps](github-apps.md) authentication +which carries a much higher rate limit at GitHub. + +This is true for any method of adding GitHub entities to the catalog, but +especially easy to hit with automatic discovery. + +## GitHub Processor (To Be Deprecated) + The GitHub integration has a special discovery processor for discovering catalog entities within a GitHub organization. The processor will crawl the GitHub organization and register entities matching the configured path. This can be diff --git a/docs/integrations/gitlab/discovery.md b/docs/integrations/gitlab/discovery.md index aad73c8209..df5aadcab4 100644 --- a/docs/integrations/gitlab/discovery.md +++ b/docs/integrations/gitlab/discovery.md @@ -24,6 +24,7 @@ catalog: branch: main # Optional. Uses `master` as default group: example-group # Optional. Group and subgroup (if needed) to look for repositories. If not present the whole project will be scanned entityFilename: catalog-info.yaml # Optional. Defaults to `catalog-info.yaml` + projectPattern: /[\s\S]*/ # Optional. Filters found projects based on provided patter. Defaults to `/[\s\S]*/`, what means to not filter anything ``` As this provider is not one of the default providers, you will first need to install diff --git a/docs/releases/v1.5.0-next.1-changelog.md b/docs/releases/v1.5.0-next.1-changelog.md new file mode 100644 index 0000000000..deedd1dc44 --- /dev/null +++ b/docs/releases/v1.5.0-next.1-changelog.md @@ -0,0 +1,274 @@ +# Release v1.5.0-next.1 + +## @backstage/integration@1.3.0-next.1 + +### Minor Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer + +### Patch Changes + +- 1f27d83933: Fixed bug in getGitLabFileFetchUrl where a target whose path did not contain the + `/-/` scope would result in a fetch URL that did not support + private-token-based authentication. + +## @backstage/plugin-catalog@1.5.0-next.1 + +### Minor Changes + +- fe94398418: Allow changing the subtitle of the `CatalogTable` component + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-scaffolder@1.5.0-next.1 + +### Minor Changes + +- c4b452e16a: Starting the implementation of the Wizard page for the `next` scaffolder plugin + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-scaffolder-backend@1.5.0-next.1 + +### Minor Changes + +- c4b452e16a: Starting the implementation of the Wizard page for the `next` scaffolder plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-backend@1.3.1-next.1 + +## @backstage/plugin-sonarqube@0.4.0-next.1 + +### Minor Changes + +- 619b515172: **BREAKING** This plugin now call the `sonarqube-backend` plugin instead of relying on the proxy plugin + + The whole proxy's `'/sonarqube':` key can be removed from your configuration files. + + Then head to the [README in sonarqube-backend plugin page](https://github.com/backstage/backstage/tree/master/plugins/sonarqube-backend/README.md) to learn how to set-up the link to your Sonarqube instances. + +### Patch Changes + +- f9c310a439: Add ability to provide an optional Sonarqube instance into the annotation in the `catalog-info.yaml` file +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-sonarqube-backend@0.1.0-next.0 + +### Minor Changes + +- e2be9ab3a4: Initial creation of the plugin + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + +## @backstage/plugin-techdocs-node@1.3.0-next.1 + +### Minor Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer + +### Patch Changes + +- f833344611: Bump default `TechDocs` image to `v1.1.0`, see the release [here](https://github.com/backstage/techdocs-container/releases/tag/v1.1.0). +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + +## @backstage/backend-common@0.15.0-next.1 + +### Patch Changes + +- 1732a18a7a: Exported `redactLogLine` function to be able to use it in custom loggers and renamed it to `redactWinstonLogLine`. +- Updated dependencies + - @backstage/integration@1.3.0-next.1 + +## @backstage/core-components@0.10.1-next.1 + +### Patch Changes + +- a22af3edc8: Adding a `className` prop to the `MarkdownContent` component + +## @backstage/create-app@0.4.30-next.1 + +### Patch Changes + +- Bumped create-app version. + +## @techdocs/cli@1.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/plugin-techdocs-node@1.3.0-next.1 + +## @backstage/plugin-api-docs@0.8.8-next.1 + +### Patch Changes + +- dae12c71cf: Updated dependency `@asyncapi/react-component` to `1.0.0-next.40`. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog@1.5.0-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-catalog-backend@1.3.1-next.1 + +### Patch Changes + +- e3d3018531: Fix issue for conditional decisions based on properties stored as arrays, like tags. + + Before this change, having a permission policy returning conditional decisions based on metadata like tags, such like `createCatalogConditionalDecision(permission, catalogConditions.hasMetadata('tags', 'java'),)`, was producing wrong results. The issue occurred when authorizing entities already loaded from the database, for example when authorizing `catalogEntityDeletePermission`. + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.1.6-next.1 + +### Patch Changes + +- f48950e34b: Github Entity Provider functionality for adding entities to the catalog. + + This provider replaces the GithubDiscoveryProcessor functionality as providers offer more flexibility with scheduling ingestion, removing and preventing orphaned entities. + + More information can be found on the [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery) page. + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-backend@1.3.1-next.1 + +## @backstage/plugin-catalog-common@1.0.5-next.0 + +### Patch Changes + +- 92103db537: Export aggregated list of all catalog permissions + +## @backstage/plugin-catalog-react@1.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/integration@1.3.0-next.1 + +## @backstage/plugin-home@0.4.24-next.1 + +### Patch Changes + +- df7b9158b8: Add wrap-around for the listing of tools to prevent increasing width with name length. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-jenkins@0.7.7-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + - @backstage/plugin-jenkins-common@0.1.7-next.0 + +## @backstage/plugin-jenkins-backend@0.1.25-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/plugin-jenkins-common@0.1.7-next.0 + +## @backstage/plugin-jenkins-common@0.1.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + +## @backstage/plugin-kubernetes@0.7.1-next.1 + +### Patch Changes + +- 860ed68343: Fixed bug in CronJobsAccordions component that causes an error when cronjobs use a kubernetes alias, such as `@hourly` or `@daily` instead of standard cron syntax. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-techdocs@1.3.1-next.1 + +### Patch Changes + +- b86ed4d990: Add highlight to active navigation item and navigation parents. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + +## @backstage/plugin-techdocs-backend@1.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-node@1.3.0-next.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.0.3-next.1 + +### Patch Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + +## @backstage/plugin-techdocs-react@1.0.3-next.1 + +### Patch Changes + +- 29d6cf0147: Add `toLowerEntityRefMaybe()` helper function for handling `techdocs.legacyUseCaseSensitiveTripletPaths` flag. + Pass modified `entityRef` to `TechDocsReaderPageContext` to handle the `techdocs.legacyUseCaseSensitiveTripletPaths` flag. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + +## example-app@0.2.74-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes@0.7.1-next.1 + - @backstage/plugin-home@0.4.24-next.1 + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-scaffolder@1.5.0-next.1 + - @backstage/plugin-techdocs@1.3.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.3-next.1 + - @backstage/plugin-api-docs@0.8.8-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + - @backstage/plugin-jenkins@0.7.7-next.1 diff --git a/microsite/data/on-demand/20220720-1.yaml b/microsite/data/on-demand/20220720-1.yaml index a1f51859f4..a7c0386a56 100644 --- a/microsite/data/on-demand/20220720-1.yaml +++ b/microsite/data/on-demand/20220720-1.yaml @@ -1,7 +1,7 @@ --- title: Adopters Community Sessions date: July 20, 2022 -category: Upcoming +category: Meetup description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc. youtubeUrl: https://youtu.be/4VFNlPxWcx8 youtubeImgUrl: https://backstage.io/img/b-sessions.png diff --git a/microsite/data/on-demand/20220727-1.yaml b/microsite/data/on-demand/20220727-1.yaml index 5f7712596f..b25b2e0789 100644 --- a/microsite/data/on-demand/20220727-1.yaml +++ b/microsite/data/on-demand/20220727-1.yaml @@ -1,9 +1,9 @@ --- title: Contributor Community Sessions date: July 27, 2022 -category: Upcoming +category: Meetup description: Join the maintainers and contributors for the Contributor Community Sessions -youtubeUrl: https://youtu.be/4VFNlPxWcx8 +youtubeUrl: https://youtu.be/pNLLrNN_hkE youtubeImgUrl: https://backstage.io/img/b-sessions.png rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com eventUrl: https://github.com/backstage/community/issues/52 diff --git a/microsite/data/on-demand/20220817-1.yaml b/microsite/data/on-demand/20220817-1.yaml new file mode 100644 index 0000000000..c0973656b4 --- /dev/null +++ b/microsite/data/on-demand/20220817-1.yaml @@ -0,0 +1,9 @@ +--- +title: Adopters Community Sessions +date: August 17, 2022 +category: Upcoming +description: Adopters Community Session ✨. It's the monthly meetup where we all come together to listen to the latest maintainer updates, learn from each other about adopting, share exciting new demos or discuss any relevant topic like developer effectiveness, developer experience, developer portals, etc. +youtubeUrl: https://youtu.be/qYnvc8ge1kg +youtubeImgUrl: https://backstage.io/img/b-sessions.png +rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com +eventUrl: https://github.com/backstage/community/issues/54 diff --git a/microsite/data/on-demand/20220824-1.yaml b/microsite/data/on-demand/20220824-1.yaml new file mode 100644 index 0000000000..411b87c74f --- /dev/null +++ b/microsite/data/on-demand/20220824-1.yaml @@ -0,0 +1,9 @@ +--- +title: Contributor Community Sessions +date: August 24, 2022 +category: Upcoming +description: Join the maintainers and contributors for the Contributor Community Sessions +youtubeUrl: https://youtu.be/qYnvc8ge1kg +youtubeImgUrl: https://backstage.io/img/b-sessions.png +rsvpUrl: https://calendar.google.com/calendar/embed?src=c_qup9gbhn9sqpuao6trttd8mk5s@group.calendar.google.com +eventUrl: https://github.com/backstage/community/issues/54 diff --git a/microsite/pages/en/live.js b/microsite/pages/en/live.js index f2ebd4bb1d..ee681a0835 100644 --- a/microsite/pages/en/live.js +++ b/microsite/pages/en/live.js @@ -34,7 +34,7 @@ const Background = props => { diff --git a/package.json b/package.json index 8c8c643879..23e847f49f 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@types/react": "^17", "@types/react-dom": "^17" }, - "version": "1.5.0-next.0", + "version": "1.5.0-next.1", "dependencies": { "@manypkg/get-packages": "^1.1.3", "@microsoft/api-documenter": "^7.17.11", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 2f4c0e7bff..002ea41927 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,22 @@ # example-app +## 0.2.74-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes@0.7.1-next.1 + - @backstage/plugin-home@0.4.24-next.1 + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-scaffolder@1.5.0-next.1 + - @backstage/plugin-techdocs@1.3.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.0.3-next.1 + - @backstage/plugin-api-docs@0.8.8-next.1 + - @backstage/plugin-techdocs-react@1.0.3-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + - @backstage/plugin-jenkins@0.7.7-next.1 + ## 0.2.74-next.0 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 738dbc2246..8fdbce600d 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.74-next.0", + "version": "0.2.74-next.1", "private": true, "backstage": { "role": "frontend" @@ -12,18 +12,18 @@ "@backstage/cli": "^0.18.1-next.0", "@backstage/config": "^1.0.1", "@backstage/core-app-api": "^1.0.5-next.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/integration-react": "^1.1.3-next.0", "@backstage/plugin-airbrake": "^0.3.8-next.0", - "@backstage/plugin-api-docs": "^0.8.8-next.0", + "@backstage/plugin-api-docs": "^0.8.8-next.1", "@backstage/plugin-azure-devops": "^0.1.24-next.0", "@backstage/plugin-apache-airflow": "^0.2.1-next.0", "@backstage/plugin-badges": "^0.2.32-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-catalog-graph": "^0.2.20-next.0", "@backstage/plugin-catalog-import": "^0.8.11-next.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/plugin-circleci": "^0.3.8-next.0", "@backstage/plugin-cloudbuild": "^0.3.8-next.0", "@backstage/plugin-code-coverage": "^0.2.1-next.0", @@ -35,10 +35,10 @@ "@backstage/plugin-github-actions": "^0.5.8-next.0", "@backstage/plugin-gocd": "^0.1.14-next.0", "@backstage/plugin-graphiql": "^0.2.40-next.0", - "@backstage/plugin-home": "^0.4.24-next.0", - "@backstage/plugin-jenkins": "^0.7.7-next.0", + "@backstage/plugin-home": "^0.4.24-next.1", + "@backstage/plugin-jenkins": "^0.7.7-next.1", "@backstage/plugin-kafka": "^0.3.8-next.0", - "@backstage/plugin-kubernetes": "^0.7.1-next.0", + "@backstage/plugin-kubernetes": "^0.7.1-next.1", "@backstage/plugin-lighthouse": "^0.3.8-next.0", "@backstage/plugin-newrelic": "^0.3.26-next.0", "@backstage/plugin-newrelic-dashboard": "^0.2.1-next.0", @@ -46,7 +46,7 @@ "@backstage/plugin-pagerduty": "0.5.1-next.0", "@backstage/plugin-permission-react": "^0.4.4-next.0", "@backstage/plugin-rollbar": "^0.4.8-next.0", - "@backstage/plugin-scaffolder": "^1.4.1-next.0", + "@backstage/plugin-scaffolder": "^1.5.0-next.1", "@backstage/plugin-search": "^1.0.1-next.0", "@backstage/plugin-search-common": "^1.0.0", "@backstage/plugin-search-react": "^1.0.1-next.0", @@ -55,9 +55,9 @@ "@backstage/plugin-stack-overflow": "^0.1.4-next.0", "@backstage/plugin-tech-insights": "^0.2.4-next.0", "@backstage/plugin-tech-radar": "^0.5.15-next.0", - "@backstage/plugin-techdocs": "^1.3.1-next.0", - "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.3-next.0", - "@backstage/plugin-techdocs-react": "^1.0.3-next.0", + "@backstage/plugin-techdocs": "^1.3.1-next.1", + "@backstage/plugin-techdocs-module-addons-contrib": "^1.0.3-next.1", + "@backstage/plugin-techdocs-react": "^1.0.3-next.1", "@backstage/plugin-todo": "^0.2.10-next.0", "@backstage/plugin-user-settings": "^0.4.7-next.0", "@backstage/theme": "^0.2.16", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 289af8d40f..3f748813f5 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -62,6 +62,7 @@ import { NewRelicPage } from '@backstage/plugin-newrelic'; import { ScaffolderFieldExtensions, ScaffolderPage, + NextScaffolderPage, scaffolderPlugin, } from '@backstage/plugin-scaffolder'; import { SearchPage } from '@backstage/plugin-search'; @@ -212,6 +213,24 @@ const routes = ( + + entity?.metadata?.tags?.includes('recommended') ?? false, + }, + ]} + /> + } + > + + + + } /> { ); it.each([ - // Project URLs + // Scoped routes { url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', config: createConfig(), @@ -135,12 +135,12 @@ describe('GitlabUrlReader', () => { }), }, - // Raw URLs + // Unscoped route { url: 'https://gitlab.example.com/a/b/blob/master/c.yaml', config: createConfig(), response: expect.objectContaining({ - url: 'https://gitlab.example.com/a/b/raw/master/c.yaml', + url: 'https://gitlab.example.com/api/v4/projects/12345/repository/files/c.yaml/raw?ref=master', }), }, ])('should handle happy path %#', async ({ url, config, response }) => { diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 8edd7e8242..35dd20153d 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/core-components +## 0.10.1-next.1 + +### Patch Changes + +- a22af3edc8: Adding a `className` prop to the `MarkdownContent` component + ## 0.10.1-next.0 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 5a67fa32c3..e8aae8d2fa 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-components", "description": "Core components used by Backstage plugins and apps", - "version": "0.10.1-next.0", + "version": "0.10.1-next.1", "private": false, "publishConfig": { "access": "public", diff --git a/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx b/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx index 0e5aedda90..013e81817a 100644 --- a/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx +++ b/packages/core-components/src/components/MarkdownContent/MarkdownContent.tsx @@ -70,6 +70,7 @@ type Props = { linkTarget?: Options['linkTarget']; transformLinkUri?: (href: string) => string; transformImageUri?: (href: string) => string; + className?: string; }; const components: Options['components'] = { @@ -99,12 +100,13 @@ export function MarkdownContent(props: Props) { linkTarget, transformLinkUri, transformImageUri, + className, } = props; const classes = useStyles(); return ( ( @@ -206,6 +208,7 @@ export function SelectComponent(props: SelectProps) { data-testid="select" displayEmpty multiple={multiple} + margin={margin} onChange={handleChange} onClick={handleClick} open={isOpen} diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index adbd0c50fd..d3180a9332 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/create-app +## 0.4.30-next.1 + +### Patch Changes + +- Bumped create-app version. + ## 0.4.30-next.0 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 3182e2e83a..8b5daf3030 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.30-next.0", + "version": "0.4.30-next.1", "private": false, "publishConfig": { "access": "public" diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index e2487eb1fb..ad2a32a713 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/integration +## 1.3.0-next.1 + +### Minor Changes + +- ad35364e97: feat(techdocs): add edit button support for bitbucketServer + +### Patch Changes + +- 1f27d83933: Fixed bug in getGitLabFileFetchUrl where a target whose path did not contain the + `/-/` scope would result in a fetch URL that did not support + private-token-based authentication. + ## 1.3.0-next.0 ### Minor Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index ade3399415..30eed36ae4 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration", "description": "Helpers for managing integrations towards external systems", - "version": "1.3.0-next.0", + "version": "1.3.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/integration/src/ScmIntegrations.ts b/packages/integration/src/ScmIntegrations.ts index 3e712cc012..6d745dcf1c 100644 --- a/packages/integration/src/ScmIntegrations.ts +++ b/packages/integration/src/ScmIntegrations.ts @@ -113,9 +113,21 @@ export class ScmIntegrations implements ScmIntegrationRegistry { } byUrl(url: string | URL): ScmIntegration | undefined { - return Object.values(this.byType) + let candidates = Object.values(this.byType) .map(i => i.byUrl(url)) - .find(Boolean); + .filter(Boolean); + + // Do not return deprecated integrations if there are other options + if (candidates.length > 1) { + const filteredCandidates = candidates.filter( + x => !(x instanceof BitbucketIntegration), + ); + if (filteredCandidates.length !== 0) { + candidates = filteredCandidates; + } + } + + return candidates[0]; } byHost(host: string): ScmIntegration | undefined { diff --git a/packages/integration/src/bitbucketServer/BitbucketServerIntegration.test.ts b/packages/integration/src/bitbucketServer/BitbucketServerIntegration.test.ts index 24d7935e72..00b5e21316 100644 --- a/packages/integration/src/bitbucketServer/BitbucketServerIntegration.test.ts +++ b/packages/integration/src/bitbucketServer/BitbucketServerIntegration.test.ts @@ -44,31 +44,58 @@ describe('BitbucketServerIntegration', () => { expect(integration.title).toBe('h.com'); }); - it('resolves url line number correctly', () => { + it('resolves url', () => { const integration = new BitbucketServerIntegration({ host: 'h.com', } as any); expect( integration.resolveUrl({ - url: './a.yaml', - base: 'https://h.com/my-owner/my-project/src/master/README.md', - lineNumber: 14, + url: './README.md', + base: 'https://h.com/projects/my-project/repos/my-repo/browse/?at=master', }), - ).toBe('https://h.com/my-owner/my-project/src/master/a.yaml#a.yaml-14'); + ).toBe( + 'https://h.com/projects/my-project/repos/my-repo/browse/README.md?at=master', + ); }); - it('resolve edit URL', () => { + it('resolves url with line number', () => { + const integration = new BitbucketServerIntegration({ + host: 'h.com', + } as any); + + expect( + integration.resolveUrl({ + url: './README.md', + base: 'https://h.com/projects/my-project/repos/my-repo/browse/?at=master', + lineNumber: 14, + }), + ).toBe( + 'https://h.com/projects/my-project/repos/my-repo/browse/README.md?at=master#14', + ); + }); + + it('resolves edit url', () => { const integration = new BitbucketServerIntegration({ host: 'h.com', } as any); expect( integration.resolveEditUrl( - 'https://h.com/my-owner/my-project/src/master/README.md', + 'https://h.com/projects/my-project/repos/my-repo/browse/README.md', ), - ).toBe( - 'https://h.com/my-owner/my-project/src/master/README.md?mode=edit&spa=0&at=master', - ); + ).toBe('https://h.com/projects/my-project/repos/my-repo/browse/README.md'); + }); + + it('resolves edit url with query params', () => { + const integration = new BitbucketServerIntegration({ + host: 'h.com', + } as any); + + expect( + integration.resolveEditUrl( + 'https://h.com/projects/my-project/repos/my-repo/browse/README.md?at=master', + ), + ).toBe('https://h.com/projects/my-project/repos/my-repo/browse/README.md'); }); }); diff --git a/packages/integration/src/bitbucketServer/BitbucketServerIntegration.ts b/packages/integration/src/bitbucketServer/BitbucketServerIntegration.ts index 10055aeddc..01886e16bc 100644 --- a/packages/integration/src/bitbucketServer/BitbucketServerIntegration.ts +++ b/packages/integration/src/bitbucketServer/BitbucketServerIntegration.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import parseGitUrl from 'git-url-parse'; import { basicIntegrations, defaultScmResolveUrl } from '../helpers'; import { ScmIntegration, ScmIntegrationsFactory } from '../types'; import { @@ -63,12 +62,11 @@ export class BitbucketServerIntegration implements ScmIntegration { }): string { const resolved = defaultScmResolveUrl(options); - // Bitbucket Server line numbers use the syntax #example.txt-42, rather than #L42 + // Bitbucket Server line numbers use the syntax #42, rather than #L42 if (options.lineNumber) { const url = new URL(resolved); - const filename = url.pathname.split('/').slice(-1)[0]; - url.hash = `${filename}-${options.lineNumber}`; + url.hash = options.lineNumber.toString(); return url.toString(); } @@ -76,14 +74,11 @@ export class BitbucketServerIntegration implements ScmIntegration { } resolveEditUrl(url: string): string { - const urlData = parseGitUrl(url); - const editUrl = new URL(url); - - editUrl.searchParams.set('mode', 'edit'); - // TODO: Not sure what spa=0 does, at least bitbucket.org doesn't support it - // but this is taken over from the initial implementation. - editUrl.searchParams.set('spa', '0'); - editUrl.searchParams.set('at', urlData.ref); - return editUrl.toString(); + // Bitbucket Server doesn't support deep linking to edit mode, therefore there's nothing to do here. + // We just remove query parameters since they cause issues with TechDocs edit button. + if (url.includes('?')) { + return url.substring(0, url.indexOf('?')); + } + return url; } } diff --git a/packages/integration/src/gitlab/core.test.ts b/packages/integration/src/gitlab/core.test.ts index d043aba55a..98fd9b7c13 100644 --- a/packages/integration/src/gitlab/core.test.ts +++ b/packages/integration/src/gitlab/core.test.ts @@ -28,19 +28,15 @@ describe('gitlab core', () => { beforeEach(() => { worker.use( - rest.get('*/api/v4/projects/:name', (_, res, ctx) => + rest.get('*/api/v4/projects/group%2Fproject', (_, res, ctx) => + res(ctx.status(200), ctx.json({ id: 12345 })), + ), + rest.get('*/api/v4/projects/group%2Fsubgroup%2Fproject', (_, res, ctx) => res(ctx.status(200), ctx.json({ id: 12345 })), ), ); }); - const configWithToken: GitLabIntegrationConfig = { - host: 'gitlab.com', - token: '0123456789', - apiBaseUrl: '', - baseUrl: '', - }; - const configWithNoToken: GitLabIntegrationConfig = { host: 'gitlab.com', apiBaseUrl: '', @@ -61,163 +57,133 @@ describe('gitlab core', () => { baseUrl: 'https://gitlab.mycompany.com', }; - describe('getGitLabFileFetchUrl with .yaml extension', () => { - it.each([ - // Project URLs - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configSelfHosteWithRelativePath, - url: 'https://gitlab.mycompany.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', - result: - 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configSelfHostedWithoutRelativePath, - url: 'https://gitlab.mycompany.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yaml', - result: - 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configWithNoToken, - // Works with non URI encoded link - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yaml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yaml/raw?ref=branch', - }, - { - config: configSelfHosteWithRelativePath, - url: 'https://gitlab.mycompany.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yaml', - result: - 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yaml/raw?ref=branch', - }, - { - config: configSelfHostedWithoutRelativePath, - url: 'https://gitlab.mycompany.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yaml', - result: - 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yaml/raw?ref=branch', - }, - { - config: configWithNoToken, - url: '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%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configWithToken, - url: '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%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', - }, - { - config: configWithNoToken, - url: '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%20with%20spaces%2Fto%2Ffile.yaml/raw?ref=branch', - }, - // Raw URLs - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/b/blob/master/c.yaml', - result: 'https://gitlab.example.com/a/b/raw/master/c.yaml', - }, - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/b/repo/blob/master/c.yaml', - result: 'https://gitlab.example.com/a/b/repo/raw/master/c.yaml', - }, - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/blob/blob/master/c.yaml', - result: 'https://gitlab.example.com/a/blob/raw/master/c.yaml', - }, - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/b/blob/blob/c.yaml', - result: 'https://gitlab.example.com/a/b/raw/blob/c.yaml', - }, - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a//blob/blob/c.yaml', - result: 'https://gitlab.example.com/a/blob/raw/c.yaml', - }, - ])('should handle happy path %#', async ({ config, url, result }) => { - await expect(getGitLabFileFetchUrl(url, config)).resolves.toBe(result); - }); - }); + describe('getGitLabFileFetchUrl', () => { + describe('when target has a scoped route', () => { + it('returns a projects API URL', async () => { + const target = + 'https://gitlab.com/group/project/-/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); - describe('getGitLabFileFetchUrl with .yml extension', () => { - it.each([ - // Project URLs - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configSelfHosteWithRelativePath, - url: 'https://gitlab.mycompany.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yml', - result: - 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configSelfHostedWithoutRelativePath, - url: 'https://gitlab.mycompany.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file.yml', - result: - 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configWithNoToken, - // Works with non URI encoded link - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yml/raw?ref=branch', - }, - { - config: configSelfHosteWithRelativePath, - // Works with non URI encoded link - url: 'https://gitlab.mycompany.com/gitlab/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yml', - result: - 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yml/raw?ref=branch', - }, - { - config: configSelfHostedWithoutRelativePath, - // Works with non URI encoded link - url: 'https://gitlab.mycompany.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path/to/file with spaces.yml', - result: - 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/my%2Fpath%2Fto%2Ffile%20with%20spaces.yml/raw?ref=branch', - }, - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yml', - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configWithToken, - url: 'https://gitlab.example.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yml', - result: - 'https://gitlab.example.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yml/raw?ref=branch', - }, - { - config: configWithNoToken, - url: 'https://gitlab.com/groupA/teams/teamA/repoA/-/blob/branch/my/path%20with%20spaces/to/file.yml', // Repo not in subgroup - result: - 'https://gitlab.com/api/v4/projects/12345/repository/files/my%2Fpath%20with%20spaces%2Fto%2Ffile.yml/raw?ref=branch', - }, - // Raw URLs - { - config: configWithNoToken, - url: 'https://gitlab.example.com/a/b/blob/master/c.yml', - result: 'https://gitlab.example.com/a/b/raw/master/c.yml', - }, - ])('should handle happy path %#', async ({ config, url, result }) => { - await expect(getGitLabFileFetchUrl(url, config)).resolves.toBe(result); + it('supports folder named "blob"', async () => { + const target = + 'https://gitlab.com/group/project/-/blob/branch/blob/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/blob%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('locates projects in subgroups', async () => { + const target = + 'https://gitlab.com/group/subgroup/project/-/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports filename with .yml extension', async () => { + const target = + 'https://gitlab.com/group/project/-/blob/branch/folder/file.yml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports non-URI-encoded target', async () => { + const target = + 'https://gitlab.com/group/project/-/blob/branch/folder/file with spaces.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile%20with%20spaces.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + describe('when gitlab is self-hosted', () => { + it('returns projects API URL', async () => { + const target = + 'https://gitlab.mycompany.com/group/project/-/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configSelfHostedWithoutRelativePath), + ).resolves.toBe(fetchUrl); + }); + + it('handles non-URI-encoded target', async () => { + const target = + 'https://gitlab.mycompany.com/group/project/-/blob/branch/folder/file with spaces.yaml'; + const fetchUrl = + 'https://gitlab.mycompany.com/api/v4/projects/12345/repository/files/folder%2Ffile%20with%20spaces.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configSelfHostedWithoutRelativePath), + ).resolves.toBe(fetchUrl); + }); + + describe('with a relative path', () => { + it('returns projects API URL', async () => { + const target = + 'https://gitlab.mycompany.com/gitlab/group/project/-/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configSelfHosteWithRelativePath), + ).resolves.toBe(fetchUrl); + }); + + it('handles non-URI-encoded target', async () => { + const target = + 'https://gitlab.mycompany.com/gitlab/group/project/-/blob/branch/folder/file with spaces.yaml'; + const fetchUrl = + 'https://gitlab.mycompany.com/gitlab/api/v4/projects/12345/repository/files/folder%2Ffile%20with%20spaces.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configSelfHosteWithRelativePath), + ).resolves.toBe(fetchUrl); + }); + }); + }); + }); + + describe('when target has an unscoped route', () => { + it('returns projects API URL', async () => { + const target = + 'https://gitlab.com/group/project/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports project in subgroup', async () => { + const target = + 'https://gitlab.com/group/subgroup/project/blob/branch/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=branch'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); + + it('supports repo with branch named "blob"', async () => { + const target = + 'https://gitlab.com/group/project/blob/blob/folder/file.yaml'; + const fetchUrl = + 'https://gitlab.com/api/v4/projects/12345/repository/files/folder%2Ffile.yaml/raw?ref=blob'; + await expect( + getGitLabFileFetchUrl(target, configWithNoToken), + ).resolves.toBe(fetchUrl); + }); }); }); }); diff --git a/packages/integration/src/gitlab/core.ts b/packages/integration/src/gitlab/core.ts index 1fcf15a78f..040ca202d6 100644 --- a/packages/integration/src/gitlab/core.ts +++ b/packages/integration/src/gitlab/core.ts @@ -19,7 +19,6 @@ import { GitLabIntegrationConfig, } from './config'; import fetch from 'cross-fetch'; -import { InputError } from '@backstage/errors'; /** * Given a URL pointing to a file on a provider, returns a URL that is suitable @@ -29,7 +28,7 @@ import { InputError } from '@backstage/errors'; * * Converts * from: https://gitlab.example.com/a/b/blob/master/c.yaml - * to: https://gitlab.example.com/a/b/raw/master/c.yaml + * to: https://gitlab.com/api/v4/projects/projectId/repository/c.yaml?ref=master * -or- * from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath * to: https://gitlab.com/api/v4/projects/projectId/repository/files/filepath?ref=branch @@ -42,15 +41,8 @@ export async function getGitLabFileFetchUrl( url: string, config: GitLabIntegrationConfig, ): Promise { - // TODO(Rugvip): From the old GitlabReaderProcessor; used - // the existence of /-/blob/ to switch the logic. Don't know if this - // makes sense and it might require some more work. - - if (url.includes('/-/blob/')) { - const projectID = await getProjectId(url, config); - return buildProjectUrl(url, projectID, config).toString(); - } - return buildRawUrl(url).toString(); + const projectID = await getProjectId(url, config); + return buildProjectUrl(url, projectID, config).toString(); } /** @@ -70,38 +62,6 @@ export function getGitLabRequestOptions(config: GitLabIntegrationConfig): { }; } -// Converts -// from: https://gitlab.example.com/groupA/teams/repoA/blob/master/c.yaml -// to: https://gitlab.example.com/groupA/teams/repoA/raw/master/c.yaml -export function buildRawUrl(target: string): URL { - try { - const url = new URL(target); - - const splitPath = url.pathname.split('/').filter(Boolean); - - // Check blob existence - const blobIndex = splitPath.indexOf('blob', 2); - if (blobIndex < 2 || blobIndex === splitPath.length - 1) { - throw new InputError('Wrong GitLab URL'); - } - - // Take repo path - const repoPath = splitPath.slice(0, blobIndex); - const restOfPath = splitPath.slice(blobIndex + 1); - - if (!restOfPath.join('/').match(/\.(yaml|yml)$/)) { - throw new InputError('Wrong GitLab URL'); - } - - // Replace 'blob' with 'raw' - url.pathname = [...repoPath, 'raw', ...restOfPath].join('/'); - - return url; - } catch (e) { - throw new InputError(`Incorrect url: ${target}, ${e}`); - } -} - // Converts // from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath // to: https://gitlab.com/api/v4/projects/projectId/repository/files/filepath?ref=branch @@ -113,7 +73,10 @@ export function buildProjectUrl( try { const url = new URL(target); - const branchAndFilePath = url.pathname.split('/-/blob/')[1]; + const branchAndFilePath = url.pathname + .split('/blob/') + .slice(1) + .join('/blob/'); const [branch, ...filePath] = branchAndFilePath.split('/'); const relativePath = getGitLabIntegrationRelativePath(config); @@ -143,12 +106,12 @@ export async function getProjectId( ): Promise { const url = new URL(target); - if (!url.pathname.includes('/-/blob/')) { + if (!url.pathname.includes('/blob/')) { throw new Error('Please provide full path to yaml file from GitLab'); } try { - let repo = url.pathname.split('/-/blob/')[0]; + let repo = url.pathname.split('/-/blob/')[0].split('/blob/')[0]; // Get gitlab relative path const relativePath = getGitLabIntegrationRelativePath(config); diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index fe5db6db4c..feda80db73 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,13 @@ # @techdocs/cli +## 1.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/plugin-techdocs-node@1.3.0-next.1 + ## 1.1.4-next.0 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 14e09515ea..c47270ed70 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "Utility CLI for managing TechDocs sites in Backstage.", - "version": "1.1.4-next.0", + "version": "1.1.4-next.1", "private": false, "publishConfig": { "access": "public" @@ -62,11 +62,11 @@ "ext": "ts" }, "dependencies": { - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/catalog-model": "^1.1.0", "@backstage/cli-common": "^0.1.9", "@backstage/config": "^1.0.1", - "@backstage/plugin-techdocs-node": "^1.2.1-next.0", + "@backstage/plugin-techdocs-node": "^1.3.0-next.1", "@types/dockerode": "^3.3.0", "commander": "^9.1.0", "dockerode": "^3.3.1", diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 25e36a0a35..b4744d0f80 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/dev-utils": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 77c175f12d..cf32d42566 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -26,7 +26,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 300402bc83..99c159b474 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index 29448beef5..9b72ec0b20 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -23,7 +23,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index ca61827a0a..fbde937344 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-api-docs +## 0.8.8-next.1 + +### Patch Changes + +- dae12c71cf: Updated dependency `@asyncapi/react-component` to `1.0.0-next.40`. +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog@1.5.0-next.1 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 0.8.8-next.0 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 5c0f3dfce5..bac0fd8e39 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-api-docs", "description": "A Backstage plugin that helps represent API entities in the frontend", - "version": "0.8.8-next.0", + "version": "0.8.8-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -35,10 +35,10 @@ "dependencies": { "@asyncapi/react-component": "1.0.0-next.40", "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", - "@backstage/plugin-catalog": "^1.5.0-next.0", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog": "^1.5.0-next.1", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index bf782919a0..c0f4f89354 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-azure-devops-common": "^0.2.4", diff --git a/plugins/badges/package.json b/plugins/badges/package.json index d7b6bd6489..4c93e4474a 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index d08ca17676..9ddb42d9e8 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -27,7 +27,7 @@ "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/cli": "^0.18.1-next.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog": "^1.5.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 0517a594f8..f6e2b5bebf 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index aabee0b1eb..7403016bf1 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-github +## 0.1.6-next.1 + +### Patch Changes + +- f48950e34b: Github Entity Provider functionality for adding entities to the catalog. + + This provider replaces the GithubDiscoveryProcessor functionality as providers offer more flexibility with scheduling ingestion, removing and preventing orphaned entities. + + More information can be found on the [GitHub Discovery](https://backstage.io/docs/integrations/github/discovery) page. + +- Updated dependencies + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + - @backstage/plugin-catalog-backend@1.3.1-next.1 + ## 0.1.6-next.0 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/api-report.md b/plugins/catalog-backend-module-github/api-report.md index e5fa2ea46a..3e4c2cb06b 100644 --- a/plugins/catalog-backend-module-github/api-report.md +++ b/plugins/catalog-backend-module-github/api-report.md @@ -40,6 +40,24 @@ export class GithubDiscoveryProcessor implements CatalogProcessor { ): Promise; } +// @public +export class GitHubEntityProvider implements EntityProvider { + // (undocumented) + connect(connection: EntityProviderConnection): Promise; + // (undocumented) + static fromConfig( + config: Config, + options: { + logger: Logger; + schedule: TaskRunner; + }, + ): GitHubEntityProvider[]; + // (undocumented) + getProviderName(): string; + // (undocumented) + refresh(logger: Logger): Promise; +} + // @public export type GithubMultiOrgConfig = Array<{ name: string; diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index ed45d98b73..53ef808262 100644 --- a/plugins/catalog-backend-module-github/package.json +++ b/plugins/catalog-backend-module-github/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github", "description": "A Backstage catalog backend module that helps integrate towards GitHub", - "version": "0.1.6-next.0", + "version": "0.1.6-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,13 +33,13 @@ "start": "backstage-cli package start" }, "dependencies": { - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/backend-tasks": "^0.3.4-next.0", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", - "@backstage/plugin-catalog-backend": "^1.3.1-next.0", + "@backstage/integration": "^1.3.0-next.1", + "@backstage/plugin-catalog-backend": "^1.3.1-next.1", "@backstage/types": "^1.0.0", "@octokit/graphql": "^5.0.0", "lodash": "^4.17.21", diff --git a/plugins/catalog-backend-module-github/src/index.ts b/plugins/catalog-backend-module-github/src/index.ts index 2f666e6547..22a1167d48 100644 --- a/plugins/catalog-backend-module-github/src/index.ts +++ b/plugins/catalog-backend-module-github/src/index.ts @@ -20,9 +20,10 @@ * @packageDocumentation */ -export { GithubDiscoveryProcessor } from './GithubDiscoveryProcessor'; -export { GithubMultiOrgReaderProcessor } from './GithubMultiOrgReaderProcessor'; -export { GitHubOrgEntityProvider } from './GitHubOrgEntityProvider'; -export type { GitHubOrgEntityProviderOptions } from './GitHubOrgEntityProvider'; -export { GithubOrgReaderProcessor } from './GithubOrgReaderProcessor'; +export { GithubDiscoveryProcessor } from './processors/GithubDiscoveryProcessor'; +export { GithubMultiOrgReaderProcessor } from './processors/GithubMultiOrgReaderProcessor'; +export { GithubOrgReaderProcessor } from './processors/GithubOrgReaderProcessor'; +export { GitHubEntityProvider } from './providers/GitHubEntityProvider'; +export { GitHubOrgEntityProvider } from './providers/GitHubOrgEntityProvider'; +export type { GitHubOrgEntityProviderOptions } from './providers/GitHubOrgEntityProvider'; export type { GithubMultiOrgConfig } from './lib'; diff --git a/plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.test.ts b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.test.ts rename to plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts index b18e3baf75..7ce6f3f9cf 100644 --- a/plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.test.ts @@ -22,9 +22,9 @@ import { } from '@backstage/integration'; import { LocationSpec } from '@backstage/plugin-catalog-backend'; import { GithubDiscoveryProcessor, parseUrl } from './GithubDiscoveryProcessor'; -import { getOrganizationRepositories } from './lib'; +import { getOrganizationRepositories } from '../lib'; -jest.mock('./lib'); +jest.mock('../lib'); const mockGetOrganizationRepositories = getOrganizationRepositories as jest.MockedFunction< typeof getOrganizationRepositories diff --git a/plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.ts rename to plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.ts index 78a1bca169..97c77bf033 100644 --- a/plugins/catalog-backend-module-github/src/GithubDiscoveryProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubDiscoveryProcessor.ts @@ -29,7 +29,7 @@ import { } from '@backstage/plugin-catalog-backend'; import { graphql } from '@octokit/graphql'; import { Logger } from 'winston'; -import { getOrganizationRepositories } from './lib'; +import { getOrganizationRepositories } from '../lib'; /** * Extracts repositories out of a GitHub org. diff --git a/plugins/catalog-backend-module-github/src/GithubMultiOrgReaderProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GithubMultiOrgReaderProcessor.ts rename to plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts index 321e9cc8f8..c5315ad166 100644 --- a/plugins/catalog-backend-module-github/src/GithubMultiOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubMultiOrgReaderProcessor.ts @@ -37,7 +37,7 @@ import { getOrganizationUsers, GithubMultiOrgConfig, readGithubMultiOrgConfig, -} from './lib'; +} from '../lib'; /** * Extracts teams and users out of a multiple GitHub orgs namespaced per org. diff --git a/plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.test.ts b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.test.ts similarity index 100% rename from plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.test.ts rename to plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.test.ts diff --git a/plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.ts b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.ts rename to plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts index ca1dd96b3c..c6f2f5d0e2 100644 --- a/plugins/catalog-backend-module-github/src/GithubOrgReaderProcessor.ts +++ b/plugins/catalog-backend-module-github/src/processors/GithubOrgReaderProcessor.ts @@ -36,7 +36,7 @@ import { getOrganizationTeams, getOrganizationUsers, parseGitHubOrgUrl, -} from './lib'; +} from '../lib'; type GraphQL = typeof graphql; diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts new file mode 100644 index 0000000000..0bda258b6e --- /dev/null +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.test.ts @@ -0,0 +1,185 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getVoidLogger } from '@backstage/backend-common'; +import { TaskInvocationDefinition, TaskRunner } from '@backstage/backend-tasks'; +import { ConfigReader } from '@backstage/config'; +import { EntityProviderConnection } from '@backstage/plugin-catalog-backend'; +import { GitHubEntityProvider } from './GitHubEntityProvider'; +import * as helpers from '../lib/github'; + +class PersistingTaskRunner implements TaskRunner { + private tasks: TaskInvocationDefinition[] = []; + + getTasks() { + return this.tasks; + } + + run(task: TaskInvocationDefinition): Promise { + this.tasks.push(task); + return Promise.resolve(undefined); + } +} + +const logger = getVoidLogger(); + +describe('GitHubEntityProvider', () => { + afterEach(() => jest.resetAllMocks()); + + it('no provider config', () => { + const schedule = new PersistingTaskRunner(); + const config = new ConfigReader({}); + const providers = GitHubEntityProvider.fromConfig(config, { + logger, + schedule, + }); + + expect(providers).toHaveLength(0); + }); + + it('single simple provider config', () => { + const schedule = new PersistingTaskRunner(); + const config = new ConfigReader({ + catalog: { + providers: { + github: { + organization: 'test-org', + }, + }, + }, + }); + const providers = GitHubEntityProvider.fromConfig(config, { + logger, + schedule, + }); + + expect(providers).toHaveLength(1); + expect(providers[0].getProviderName()).toEqual('github-provider:default'); + }); + + it('multiple provider configs', () => { + const schedule = new PersistingTaskRunner(); + const config = new ConfigReader({ + catalog: { + providers: { + github: { + myProvider: { + organization: 'test-org1', + }, + anotherProvider: { + organization: 'test-org2', + }, + }, + }, + }, + }); + const providers = GitHubEntityProvider.fromConfig(config, { + logger, + schedule, + }); + + expect(providers).toHaveLength(2); + expect(providers[0].getProviderName()).toEqual( + 'github-provider:myProvider', + ); + expect(providers[1].getProviderName()).toEqual( + 'github-provider:anotherProvider', + ); + }); + + it('apply full update on scheduled execution', async () => { + const config = new ConfigReader({ + catalog: { + providers: { + github: { + myProvider: { + organization: 'test-org', + catalogPath: 'custom/path/catalog-custom.yaml', + filters: { + branch: 'main', + repository: 'test-.*', + }, + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + }; + + const provider = GitHubEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + + const mockGetOrganizationRepositories = jest.spyOn( + helpers, + 'getOrganizationRepositories', + ); + + mockGetOrganizationRepositories.mockReturnValue( + Promise.resolve({ + repositories: [ + { + name: 'test-repo', + url: 'https://github.com/test-org/test-repo', + isArchived: false, + defaultBranchRef: { + name: 'main', + }, + }, + ], + }), + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual('github-provider:myProvider:refresh'); + await (taskDef.fn as () => Promise)(); + + const url = `https://github.com/test-org/test-repo/blob/main/catalog-custom.yaml`; + const expectedEntities = [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': `url:${url}`, + 'backstage.io/managed-by-origin-location': `url:${url}`, + }, + name: 'generated-21936a3d1e926b8bb3b00ac4398dc9a8dbb90b45', + }, + spec: { + presence: 'optional', + target: `${url}`, + type: 'url', + }, + }, + locationKey: 'github-provider:myProvider', + }, + ]; + + expect(entityProviderConnection.applyMutation).toBeCalledTimes(1); + expect(entityProviderConnection.applyMutation).toBeCalledWith({ + type: 'full', + entities: expectedEntities, + }); + }); +}); diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts new file mode 100644 index 0000000000..43c01e8f7c --- /dev/null +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProvider.ts @@ -0,0 +1,253 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TaskRunner } from '@backstage/backend-tasks'; +import { Config } from '@backstage/config'; +import { + GithubCredentialsProvider, + ScmIntegrations, + GitHubIntegrationConfig, + GitHubIntegration, + SingleInstanceGithubCredentialsProvider, +} from '@backstage/integration'; +import { + EntityProvider, + EntityProviderConnection, + LocationSpec, + locationSpecToLocationEntity, +} from '@backstage/plugin-catalog-backend'; + +import { graphql } from '@octokit/graphql'; +import * as uuid from 'uuid'; +import { Logger } from 'winston'; +import { + readProviderConfigs, + GitHubEntityProviderConfig, +} from './GitHubEntityProviderConfig'; +import { getOrganizationRepositories, Repository } from '../lib/github'; + +/** + * Discovers catalog files located in [GitHub](https://github.com). + * The provider will search your GitHub account and register catalog files matching the configured path + * as Location entity and via following processing steps add all contained catalog entities. + * This can be useful as an alternative to static locations or manually adding things to the catalog. + * + * @public + */ +export class GitHubEntityProvider implements EntityProvider { + private readonly config: GitHubEntityProviderConfig; + private readonly logger: Logger; + private readonly integration: GitHubIntegrationConfig; + private readonly scheduleFn: () => Promise; + private connection?: EntityProviderConnection; + private readonly githubCredentialsProvider: GithubCredentialsProvider; + + static fromConfig( + config: Config, + options: { + logger: Logger; + schedule: TaskRunner; + }, + ): GitHubEntityProvider[] { + const integrations = ScmIntegrations.fromConfig(config); + const integration = integrations.github.byHost('github.com'); + + if (!integration) { + throw new Error( + `There is no GitHub config that matches github. Please add a configuration entry for it under integrations.github`, + ); + } + + return readProviderConfigs(config).map( + providerConfig => + new GitHubEntityProvider( + providerConfig, + integration, + options.logger, + options.schedule, + ), + ); + } + + private constructor( + config: GitHubEntityProviderConfig, + integration: GitHubIntegration, + logger: Logger, + schedule: TaskRunner, + ) { + this.config = config; + this.integration = integration.config; + this.logger = logger.child({ + target: this.getProviderName(), + }); + this.scheduleFn = this.createScheduleFn(schedule); + this.githubCredentialsProvider = + SingleInstanceGithubCredentialsProvider.create(integration.config); + this.scheduleFn = this.createScheduleFn(schedule); + } + + /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */ + getProviderName(): string { + return `github-provider:${this.config.id}`; + } + + /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */ + async connect(connection: EntityProviderConnection): Promise { + this.connection = connection; + return await this.scheduleFn(); + } + + private createScheduleFn(schedule: TaskRunner): () => Promise { + return async () => { + const taskId = `${this.getProviderName()}:refresh`; + return schedule.run({ + id: taskId, + fn: async () => { + const logger = this.logger.child({ + class: GitHubEntityProvider.prototype.constructor.name, + taskId, + taskInstanceId: uuid.v4(), + }); + try { + await this.refresh(logger); + } catch (error) { + logger.error(error); + } + }, + }); + }; + } + + async refresh(logger: Logger) { + if (!this.connection) { + throw new Error('Not initialized'); + } + + const targets = await this.findCatalogFiles(); + const matchingTargets = this.matchesFilters(targets); + const entities = matchingTargets + .map(repository => this.createLocationUrl(repository)) + .map(GitHubEntityProvider.toLocationSpec) + .map(location => { + return { + locationKey: this.getProviderName(), + entity: locationSpecToLocationEntity({ location }), + }; + }); + + await this.connection.applyMutation({ + type: 'full', + entities, + }); + + logger.info( + `Read ${targets.length} GitHub repositories (${entities.length} matching the pattern)`, + ); + } + + // go to the server and get all of the repositories + private async findCatalogFiles(): Promise { + const organization = this.config.organization; + const host = this.integration.host; + const orgUrl = `https://${host}/${organization}`; + + const { headers } = await this.githubCredentialsProvider.getCredentials({ + url: orgUrl, + }); + + const client = graphql.defaults({ + baseUrl: this.integration.apiBaseUrl, + headers, + }); + + const { repositories } = await getOrganizationRepositories( + client, + organization, + ); + + return repositories; + } + + private matchesFilters(repositories: Repository[]) { + const repositoryFilter = this.config.filters?.repository; + + const matchingRepositories = repositories.filter(r => { + return !r.isArchived && repositoryFilter + ? repositoryFilter?.test(r.name) + : true && r.defaultBranchRef?.name; + }); + return matchingRepositories; + } + + private createLocationUrl(repository: Repository): string { + const branch = + this.config.filters?.branch || repository.defaultBranchRef?.name || '-'; + const catalogFile = this.config.catalogPath.substring( + this.config.catalogPath.lastIndexOf('/') + 1, + ); + return `${repository.url}/blob/${branch}/${catalogFile}`; + } + + private static toLocationSpec(target: string): LocationSpec { + return { + type: 'url', + target: target, + presence: 'optional', + }; + } +} + +/* + * Helpers + */ + +export function parseUrl(urlString: string): { + org: string; + repoSearchPath: RegExp; + catalogPath: string; + branch: string; + host: string; +} { + const url = new URL(urlString); + const path = url.pathname.substr(1).split('/'); + + // /backstage/techdocs-*/blob/master/catalog-info.yaml + // can also be + // /backstage + if (path.length > 2 && path[0].length && path[1].length) { + return { + org: decodeURIComponent(path[0]), + repoSearchPath: escapeRegExp(decodeURIComponent(path[1])), + catalogPath: `/${decodeURIComponent(path.slice(4).join('/'))}`, + branch: decodeURIComponent(path[3]), + host: url.host, + }; + } else if (path.length === 1 && path[0].length) { + return { + org: decodeURIComponent(path[0]), + repoSearchPath: escapeRegExp('*'), + catalogPath: '/catalog-info.yaml', + branch: '-', + host: url.host, + }; + } + + throw new Error(`Failed to parse ${urlString}`); +} + +export function escapeRegExp(str: string): RegExp { + return new RegExp(`^${str.replace(/\*/g, '.*')}$`); +} diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.test.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.test.ts new file mode 100644 index 0000000000..ba72dbf950 --- /dev/null +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.test.ts @@ -0,0 +1,115 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigReader } from '@backstage/config'; +import { readProviderConfigs } from './GitHubEntityProviderConfig'; + +describe('readProviderConfigs', () => { + afterEach(() => jest.resetAllMocks()); + + it('no provider config', () => { + const config = new ConfigReader({}); + const providerConfigs = readProviderConfigs(config); + + expect(providerConfigs).toHaveLength(0); + }); + + it('single simple provider config', () => { + const config = new ConfigReader({ + catalog: { + providers: { + github: { + organization: 'test-org', + }, + }, + }, + }); + const providerConfigs = readProviderConfigs(config); + + expect(providerConfigs).toHaveLength(1); + expect(providerConfigs[0].id).toEqual('default'); + expect(providerConfigs[0].organization).toEqual('test-org'); + }); + + it('multiple provider configs', () => { + const config = new ConfigReader({ + catalog: { + providers: { + github: { + providerOrganizationOnly: { + organization: 'test-org1', + }, + providerCustomCatalogPath: { + organization: 'test-org2', + catalogPath: 'custom/path/catalog-info.yaml', + }, + providerWithRepositoryFilter: { + organization: 'test-org3', + filters: { + repository: 'repository.*filter', + }, + }, + providerWithBranchFilter: { + organization: 'test-org4', + filters: { + branch: 'branch-name', + }, + }, + }, + }, + }, + }); + const providerConfigs = readProviderConfigs(config); + + expect(providerConfigs).toHaveLength(4); + expect(providerConfigs[0]).toEqual({ + id: 'providerOrganizationOnly', + organization: 'test-org1', + catalogPath: '/catalog-info.yaml', + filters: { + repository: undefined, + branch: undefined, + }, + }); + expect(providerConfigs[1]).toEqual({ + id: 'providerCustomCatalogPath', + organization: 'test-org2', + catalogPath: 'custom/path/catalog-info.yaml', + filters: { + repository: undefined, + branch: undefined, + }, + }); + expect(providerConfigs[2]).toEqual({ + id: 'providerWithRepositoryFilter', + organization: 'test-org3', // organization + catalogPath: '/catalog-info.yaml', // file + filters: { + repository: /^repository.*filter$/, // repo + branch: undefined, // branch + }, + }); + expect(providerConfigs[3]).toEqual({ + id: 'providerWithBranchFilter', + organization: 'test-org4', + catalogPath: '/catalog-info.yaml', + filters: { + repository: undefined, + branch: 'branch-name', + }, + }); + }); +}); diff --git a/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.ts b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.ts new file mode 100644 index 0000000000..b5929c5300 --- /dev/null +++ b/plugins/catalog-backend-module-github/src/providers/GitHubEntityProviderConfig.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Config } from '@backstage/config'; + +const DEFAULT_CATALOG_PATH = '/catalog-info.yaml'; +const DEFAULT_PROVIDER_ID = 'default'; + +export type GitHubEntityProviderConfig = { + id: string; + catalogPath: string; + organization: string; + filters?: { + repository?: RegExp; + branch?: string; + }; +}; + +export function readProviderConfigs( + config: Config, +): GitHubEntityProviderConfig[] { + const providersConfig = config.getOptionalConfig('catalog.providers.github'); + if (!providersConfig) { + return []; + } + + if (providersConfig.has('organization')) { + // simple/single config variant + return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)]; + } + + return providersConfig.keys().map(id => { + const providerConfig = providersConfig.getConfig(id); + + return readProviderConfig(id, providerConfig); + }); +} + +function readProviderConfig( + id: string, + config: Config, +): GitHubEntityProviderConfig { + const organization = config.getString('organization'); + const catalogPath = + config.getOptionalString('catalogPath') ?? DEFAULT_CATALOG_PATH; + const repositoryPattern = config.getOptionalString('filters.repository'); + const branchPattern = config.getOptionalString('filters.branch'); + + return { + id, + catalogPath, + organization, + filters: { + repository: repositoryPattern + ? compileRegExp(repositoryPattern) + : undefined, + branch: branchPattern || undefined, + }, + }; +} +/** + * Compiles a RegExp while enforcing the pattern to contain + * the start-of-line and end-of-line anchors. + * + * @param pattern + */ +function compileRegExp(pattern: string): RegExp { + let fullLinePattern = pattern; + if (!fullLinePattern.startsWith('^')) { + fullLinePattern = `^${fullLinePattern}`; + } + if (!fullLinePattern.endsWith('$')) { + fullLinePattern = `${fullLinePattern}$`; + } + + return new RegExp(fullLinePattern); +} diff --git a/plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.test.ts similarity index 100% rename from plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.test.ts rename to plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.test.ts diff --git a/plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.ts similarity index 99% rename from plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.ts rename to plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.ts index e6cb413a6f..bb994c193c 100644 --- a/plugins/catalog-backend-module-github/src/GitHubOrgEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GitHubOrgEntityProvider.ts @@ -42,7 +42,7 @@ import { getOrganizationTeams, getOrganizationUsers, parseGitHubOrgUrl, -} from './lib'; +} from '../lib'; /** * Options for {@link GitHubOrgEntityProvider}. diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index 69de9d28c7..8a3c33c8f2 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -35,4 +35,5 @@ export type GitlabProviderConfig = { id: string; branch: string; catalogFile: string; + projectPattern: RegExp; }; diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts index dc70772d3d..d4a13cf81e 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts @@ -227,4 +227,113 @@ describe('GitlabDiscoveryEntityProvider', () => { entities: expectedEntities, }); }); + + it('should filter found projects based on a provided project pattern', async () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'test-gitlab', + apiBaseUrl: 'https://api.gitlab.example/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'test-gitlab', + projectPattern: 'john/', + }, + }, + }, + }, + }); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + }; + const provider = GitlabDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + + server.use( + rest.get( + `https://api.gitlab.example/api/v4/projects`, + (_req, res, ctx) => { + const response = [ + { + id: 123, + default_branch: 'master', + archived: false, + last_activity_at: new Date().toString(), + web_url: 'https://api.gitlab.example/test-group/test-repo', + path_with_namespace: 'test-group/test-repo', + }, + { + id: 124, + default_branch: 'master', + archived: false, + last_activity_at: new Date().toString(), + web_url: 'https://api.gitlab.example/john/example', + path_with_namespace: 'john/example', + }, + ]; + return res(ctx.json(response)); + }, + ), + rest.head( + 'https://api.gitlab.example/api/v4/projects/test-group%2Ftest-repo/repository/files/catalog-info.yaml', + (req, res, ctx) => { + if (req.url.searchParams.get('ref') === 'master') { + return res(ctx.status(200)); + } + return res(ctx.status(404, 'Not Found')); + }, + ), + rest.head( + 'https://api.gitlab.example/api/v4/projects/john%2Fexample/repository/files/catalog-info.yaml', + (req, res, ctx) => { + if (req.url.searchParams.get('ref') === 'master') { + return res(ctx.status(200)); + } + return res(ctx.status(404, 'Not Found')); + }, + ), + ); + + await provider.connect(entityProviderConnection); + + await provider.refresh(logger); + + expect(entityProviderConnection.applyMutation).toBeCalledWith({ + type: 'full', + entities: [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://api.gitlab.example/john/example/-/blob/master/catalog-info.yaml', + 'backstage.io/managed-by-origin-location': + 'url:https://api.gitlab.example/john/example/-/blob/master/catalog-info.yaml', + }, + name: 'generated-2045212e5b3e9e6bacf51cec709e362282e3cda9', + }, + spec: { + presence: 'optional', + target: + 'https://api.gitlab.example/john/example/-/blob/master/catalog-info.yaml', + type: 'url', + }, + }, + locationKey: 'GitlabDiscoveryEntityProvider:test-id', + }, + ], + }); + }); }); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts index 36c3ee90be..ffb123edf7 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts @@ -147,6 +147,10 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { }; for await (const project of projects) { + if (!this.config.projectPattern.test(project.path_with_namespace ?? '')) { + continue; + } + res.scanned++; if (project.archived) { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts index 892ce5f25c..cb36e5166c 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.test.ts @@ -52,6 +52,7 @@ describe('config', () => { branch: 'master', host: 'host', catalogFile: 'catalog-info.yaml', + projectPattern: /[\s\S]*/, }), ); }); @@ -81,6 +82,7 @@ describe('config', () => { branch: 'not-master', host: 'host', catalogFile: 'custom-file.yaml', + projectPattern: /[\s\S]*/, }), ); }); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/config.ts b/plugins/catalog-backend-module-gitlab/src/providers/config.ts index d6ad28b2ca..392922860f 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/config.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/config.ts @@ -15,13 +15,14 @@ */ import { Config } from '@backstage/config'; -import { GitlabProviderConfig } from '../lib/types'; +import { GitlabProviderConfig } from '../lib'; /** * Extracts the gitlab config from a config object * * @public * + * @param id - The provider key * @param config - The config object to extract from */ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { @@ -30,6 +31,9 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { const branch = config.getOptionalString('branch') ?? 'master'; const catalogFile = config.getOptionalString('entityFilename') ?? 'catalog-info.yaml'; + const projectPattern = new RegExp( + config.getOptionalString('projectPattern') ?? /[\s\S]*/, + ); return { id, @@ -37,6 +41,7 @@ function readGitlabConfig(id: string, config: Config): GitlabProviderConfig { branch, host, catalogFile, + projectPattern, }; } diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 287ab75267..f7a42d0bf5 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend +## 1.3.1-next.1 + +### Patch Changes + +- e3d3018531: Fix issue for conditional decisions based on properties stored as arrays, like tags. + + Before this change, having a permission policy returning conditional decisions based on metadata like tags, such like `createCatalogConditionalDecision(permission, catalogConditions.hasMetadata('tags', 'java'),)`, was producing wrong results. The issue occurred when authorizing entities already loaded from the database, for example when authorizing `catalogEntityDeletePermission`. + +- Updated dependencies + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/backend-common@0.15.0-next.1 + - @backstage/integration@1.3.0-next.1 + ## 1.3.1-next.0 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index fbc9dabf85..63ef5bc397 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "1.3.1-next.0", + "version": "1.3.1-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,13 +36,13 @@ "dependencies": { "@backstage/backend-plugin-api": "^0.1.1-next.0", "@backstage/plugin-catalog-node": "^1.0.1-next.0", - "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-common": "^0.15.0-next.1", "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/integration": "^1.3.0-next.1", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-permission-common": "^0.6.3", "@backstage/plugin-permission-node": "^0.6.4-next.0", "@backstage/plugin-scaffolder-common": "^1.1.2", diff --git a/plugins/catalog-backend/src/permissions/rules/createPropertyRule.test.ts b/plugins/catalog-backend/src/permissions/rules/createPropertyRule.test.ts index 80c86cf250..cb11add9ed 100644 --- a/plugins/catalog-backend/src/permissions/rules/createPropertyRule.test.ts +++ b/plugins/catalog-backend/src/permissions/rules/createPropertyRule.test.ts @@ -46,6 +46,22 @@ describe('createPropertyRule', () => { ).toBe(false); }); + it('returns false when specified key is an empty array', () => { + expect( + apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + tags: [], + }, + }, + 'tags', + ), + ).toBe(false); + }); + it('returns true when specified key is present', () => { expect( apply( @@ -63,6 +79,22 @@ describe('createPropertyRule', () => { ), ).toBe(true); }); + + it('returns true when specified key is an array containing more than an element', () => { + expect( + apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + tags: ['java'], + }, + }, + 'tags', + ), + ).toBe(true); + }); }); describe('key and value', () => { @@ -101,6 +133,23 @@ describe('createPropertyRule', () => { ).toBe(false); }); + it(`returns false when key is an array and doesn't contain the specified value`, () => { + expect( + apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + tags: ['java'], + }, + }, + 'tags', + 'python', + ), + ).toBe(false); + }); + it('returns true when specified key and value is present', () => { expect( apply( @@ -119,6 +168,23 @@ describe('createPropertyRule', () => { ), ).toBe(true); }); + + it(`returns true when key is an array and contains the specified value`, () => { + expect( + apply( + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'test-component', + tags: ['java', 'java11'], + }, + }, + 'tags', + 'java', + ), + ).toBe(true); + }); }); }); diff --git a/plugins/catalog-backend/src/permissions/rules/createPropertyRule.ts b/plugins/catalog-backend/src/permissions/rules/createPropertyRule.ts index 3808eced7b..57de5eb922 100644 --- a/plugins/catalog-backend/src/permissions/rules/createPropertyRule.ts +++ b/plugins/catalog-backend/src/permissions/rules/createPropertyRule.ts @@ -26,6 +26,13 @@ export const createPropertyRule = (propertyType: 'metadata' | 'spec') => resourceType: RESOURCE_TYPE_CATALOG_ENTITY, apply: (resource: Entity, key: string, value?: string) => { const foundValue = get(resource[propertyType], key); + + if (Array.isArray(foundValue)) { + if (value !== undefined) { + return foundValue.includes(value); + } + return foundValue.length > 0; + } if (value !== undefined) { return value === foundValue; } diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index a9ba5bbb23..e9e35301c3 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -91,7 +91,10 @@ import { } from '@backstage/plugin-permission-node'; import { AuthorizedEntitiesCatalog } from './AuthorizedEntitiesCatalog'; import { basicEntityFilter } from './request/basicEntityFilter'; -import { RESOURCE_TYPE_CATALOG_ENTITY } from '@backstage/plugin-catalog-common'; +import { + catalogPermissions, + RESOURCE_TYPE_CATALOG_ENTITY, +} from '@backstage/plugin-catalog-common'; import { AuthorizedLocationService } from './AuthorizedLocationService'; /** @public */ @@ -435,6 +438,7 @@ export class CatalogBuilder { entitiesByRef[stringifyEntityRef(parseEntityRef(resourceRef))], ); }, + permissions: catalogPermissions, rules: this.permissionRules, }); const stitcher = new Stitcher(dbClient, logger); diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index 05830979e5..b05ac57b9f 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-catalog-common +## 1.0.5-next.0 + +### Patch Changes + +- 92103db537: Export aggregated list of all catalog permissions + ## 1.0.4 ### Patch Changes diff --git a/plugins/catalog-common/api-report.md b/plugins/catalog-common/api-report.md index ab540d446b..b7eaf99d8b 100644 --- a/plugins/catalog-common/api-report.md +++ b/plugins/catalog-common/api-report.md @@ -49,6 +49,12 @@ export const catalogLocationDeletePermission: BasicPermission; // @alpha export const catalogLocationReadPermission: BasicPermission; +// @alpha +export const catalogPermissions: ( + | BasicPermission + | ResourcePermission<'catalog-entity'> +)[]; + // @alpha export const RESOURCE_TYPE_CATALOG_ENTITY = 'catalog-entity'; ``` diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 329db25c75..f3cfa2d236 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-common", "description": "Common functionalities for the catalog plugin", - "version": "1.0.4", + "version": "1.0.5-next.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-common/src/index.ts b/plugins/catalog-common/src/index.ts index dfa90c448b..614948e56c 100644 --- a/plugins/catalog-common/src/index.ts +++ b/plugins/catalog-common/src/index.ts @@ -30,6 +30,7 @@ export { catalogLocationReadPermission, catalogLocationCreatePermission, catalogLocationDeletePermission, + catalogPermissions, } from './permissions'; export type { CatalogEntityPermission } from './permissions'; diff --git a/plugins/catalog-common/src/permissions.ts b/plugins/catalog-common/src/permissions.ts index aa95e8c00f..615f02a7fb 100644 --- a/plugins/catalog-common/src/permissions.ts +++ b/plugins/catalog-common/src/permissions.ts @@ -129,3 +129,17 @@ export const catalogLocationDeletePermission = createPermission({ action: 'delete', }, }); + +/** + * List of all catalog permissions. + * @alpha + */ +export const catalogPermissions = [ + catalogEntityReadPermission, + catalogEntityCreatePermission, + catalogEntityDeletePermission, + catalogEntityRefreshPermission, + catalogLocationReadPermission, + catalogLocationCreatePermission, + catalogLocationDeletePermission, +]; diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index e444c84713..a46d8b5ec3 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -26,7 +26,7 @@ "dependencies": { "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index d44b9aaa67..61e2ecc2a6 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -37,7 +37,7 @@ "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/integration": "^1.3.0-next.0", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 51ef8b15a0..f9a6b39e96 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-react +## 1.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/integration@1.3.0-next.1 + ## 1.1.3-next.0 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 8bc5f1dfd0..b5ebf51c78 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "1.1.3-next.0", + "version": "1.1.3-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,11 +36,11 @@ "dependencies": { "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", - "@backstage/integration": "^1.3.0-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/integration": "^1.3.0-next.1", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-permission-common": "^0.6.3", "@backstage/plugin-permission-react": "^0.4.4-next.0", "@backstage/theme": "^0.2.16", @@ -65,7 +65,7 @@ "devDependencies": { "@backstage/cli": "^0.18.1-next.0", "@backstage/core-app-api": "^1.0.5-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", "@backstage/plugin-scaffolder-common": "^1.1.2", "@backstage/test-utils": "^1.1.3-next.0", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index e1583cb69e..ac7c8bb06f 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog +## 1.5.0-next.1 + +### Minor Changes + +- fe94398418: Allow changing the subtitle of the `CatalogTable` component + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.10.1-next.1 + - @backstage/plugin-catalog-common@1.0.5-next.0 + - @backstage/plugin-catalog-react@1.1.3-next.1 + ## 1.5.0-next.0 ### Minor Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 7bf2c9d5ec..04d9b98701 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog", "description": "The Backstage plugin for browsing the Backstage catalog", - "version": "1.5.0-next.0", + "version": "1.5.0-next.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -36,12 +36,12 @@ "dependencies": { "@backstage/catalog-client": "^1.0.4", "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/integration-react": "^1.1.3-next.0", - "@backstage/plugin-catalog-common": "^1.0.4", - "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/plugin-catalog-common": "^1.0.5-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.1", "@backstage/plugin-search-common": "^1.0.0", "@backstage/plugin-search-react": "^1.0.1-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 8810aca917..a4add36d06 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 8107d4c411..d6ffd896a1 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 5e1313a8f8..53c2d0f9e0 100644 --- a/plugins/code-climate/package.json +++ b/plugins/code-climate/package.json @@ -24,7 +24,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index d6e67ae320..d5adc75d4f 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -26,7 +26,7 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 80fdaf693c..9a04af2abf 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/cost-insights-common/api-report.md b/plugins/cost-insights-common/api-report.md index a5f7045854..8d9e2d030d 100644 --- a/plugins/cost-insights-common/api-report.md +++ b/plugins/cost-insights-common/api-report.md @@ -44,6 +44,7 @@ export interface Entity { // @public (undocumented) export type Group = { id: string; + name?: string; }; // @public (undocumented) diff --git a/plugins/cost-insights-common/src/types/Group.ts b/plugins/cost-insights-common/src/types/Group.ts index b34cac083f..ad384abe7b 100644 --- a/plugins/cost-insights-common/src/types/Group.ts +++ b/plugins/cost-insights-common/src/types/Group.ts @@ -19,4 +19,5 @@ */ export type Group = { id: string; + name?: string; }; diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 980b916e31..dadf992c5d 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -36,7 +36,7 @@ "dependencies": { "@backstage/catalog-model": "^1.1.0", "@backstage/config": "^1.0.1", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-cost-insights-common": "^0.1.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.test.tsx b/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.test.tsx index 6da6286515..2e2131daff 100644 --- a/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.test.tsx +++ b/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.test.tsx @@ -32,6 +32,7 @@ const mockGroups: Group[] = [ }, { id: 'test-group-3', + name: 'Test Group 3', }, ]; @@ -76,7 +77,7 @@ describe('', () => { ); await userEvent.click(rendered.getByTestId('cost-insights-groups-tab')); mockGroups.forEach(group => - expect(rendered.getByText(group.id)).toBeInTheDocument(), + expect(rendered.getByText(group.name ?? group.id)).toBeInTheDocument(), ); }); }); diff --git a/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.tsx b/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.tsx index 3bb3f14214..935184ee55 100644 --- a/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.tsx +++ b/plugins/cost-insights/src/components/CostInsightsTabs/CostInsightsTabs.tsx @@ -100,7 +100,7 @@ export const CostInsightsTabs = ({ groups }: CostInsightsTabsProps) => { data-testid={g.id} onClick={updateGroupFilterAndCloseMenu(g)} > - {g.id} + {g.name ?? g.id} ))} diff --git a/plugins/cost-insights/src/example/client.ts b/plugins/cost-insights/src/example/client.ts index a7a2a0e22f..a6aadedd09 100644 --- a/plugins/cost-insights/src/example/client.ts +++ b/plugins/cost-insights/src/example/client.ts @@ -52,7 +52,8 @@ export class ExampleCostInsightsClient implements CostInsightsApi { async getUserGroups(userId: string): Promise { const groups: Group[] = await this.request({ userId }, [ - { id: 'pied-piper' }, + { id: 'group-a', name: 'Group A' }, + { id: 'group-b', name: 'Group B' }, ]); return groups; diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index e767c59cd4..4fdaf42140 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 209a22ff39..9d10bb182c 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/plugin-explore-react": "^0.0.20-next.0", diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 100ed11839..4cfaa1be32 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -25,7 +25,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index b24f02fa71..e0946d30a3 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -36,7 +36,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 3f78ea6609..824fbd80ed 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index fb357a2944..83710dc5e1 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/integration": "^1.3.0-next.0", "@backstage/theme": "^0.2.16", diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index a589741d33..57a4789f3e 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -37,7 +37,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/integration": "^1.3.0-next.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 75b7fcbb92..504b65fff4 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/integration": "^1.3.0-next.0", diff --git a/plugins/github-issues/.eslintrc.js b/plugins/github-issues/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/github-issues/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/github-issues/README.md b/plugins/github-issues/README.md new file mode 100644 index 0000000000..eeb93ab27b --- /dev/null +++ b/plugins/github-issues/README.md @@ -0,0 +1,63 @@ +# GitHub Issues plugin + +Welcome to the GitHub Issues plugin! + +Based on the [well-known GitHub slug annotation](https://backstage.io/docs/features/software-catalog/well-known-annotations#githubcomproject-slug) associated with the Entity, it renders the list of Open issues in GitHub. + +The plugin is designed to work with four Entity kinds, and it behaves a bit differently depending on that kind: + +- Kind: Group/User: plugin renders issues from all repositories for which the Entity is the owner. +- Kind: API/Component: plugin renders issues from only one repository assigned to the Entity + +**Issues are sorted from the recently updated DESC order (the plugin might not render all issues from a single repo next to each other).** + +## Prerequisites + +- [GitHub Authentication Provider](https://backstage.io/docs/auth/github/provider) + +## Usage + +Install the plugin by running the following command **from your Backstage root directory** + +`yarn --cwd packages/app add @backstage/plugin-github-issues` + +After installation, the plugin can be used as a Card or as a Page. + +```typescript +import { + GitHubIssuesCard, + GitHubIssuesPage, +} from '@backstage/plugin-github-issues'; + +// To use as a page Plugin needs to be wrapped in EntityLayout.Route +const RenderGitHubIssuesPage = () => ( + + + + + + + +); + +// To use as a card and make it render correctly please place it inside appropriate Grid elements +const RenderGitHubIssuesCard = () => ( + + + + + + + + + +); +``` + +## Configuration + +Both `GitHubIssuesPage` and `GitHubIssuesCard` provide default configuration. It is ready to use out of the box. +However, you can configure the plugin with props: + +- `itemsPerPage: number = 10` - Issues in the list are paginated, number of issues on a single page is controlled with this prop +- `itemsPerRepo: number = 40` - the plugin doesn't download all Issues available on GitHub. By default, it will get at most 40 Issues - this prop controls this behaviour diff --git a/plugins/github-issues/api-report.md b/plugins/github-issues/api-report.md new file mode 100644 index 0000000000..eb69fc8e8e --- /dev/null +++ b/plugins/github-issues/api-report.md @@ -0,0 +1,33 @@ +## API Report File for "@backstage/plugin-github-issues" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { RouteRef } from '@backstage/core-plugin-api'; + +// @public (undocumented) +export const GitHubIssuesCard: (props: GitHubIssuesProps) => JSX.Element; + +// @public (undocumented) +export const GitHubIssuesPage: (props: GitHubIssuesProps) => JSX.Element; + +// @public (undocumented) +export const gitHubIssuesPlugin: BackstagePlugin< + { + root: RouteRef; + }, + {}, + {} +>; + +// @public (undocumented) +export type GitHubIssuesProps = { + itemsPerPage?: number; + itemsPerRepo?: number; +}; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json new file mode 100644 index 0000000000..5435f81324 --- /dev/null +++ b/plugins/github-issues/package.json @@ -0,0 +1,61 @@ +{ + "name": "@backstage/plugin-github-issues", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin" + }, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "prettier": "@spotify/prettier-config", + "dependencies": { + "@backstage/catalog-model": "^1.0.3", + "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-plugin-api": "^1.0.5-next.0", + "@backstage/integration": "^1.3.0-next.0", + "@backstage/plugin-catalog-react": "^1.1.3-next.0", + "@backstage/theme": "^0.2.15", + "@material-ui/core": "^4.12.4", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.61", + "luxon": "^2.4.0", + "octokit": "^2.0.4", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.18.1-next.0", + "@backstage/core-app-api": "^1.0.5-next.0", + "@backstage/dev-utils": "^1.0.5-next.0", + "@backstage/test-utils": "^1.1.3-next.0", + "@spotify/prettier-config": "^13.0.1", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/jest": "*", + "@types/node": "*", + "@types/react": "^16.13.1 || ^17.0.0", + "cross-fetch": "^3.1.5", + "msw": "^0.44.0", + "prettier": "^2.7.1" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx new file mode 100644 index 0000000000..5380c8eb22 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -0,0 +1,89 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; + +import { Box, IconButton, Typography } from '@material-ui/core'; +import { InfoCard, Progress } from '@backstage/core-components'; +import RefreshIcon from '@material-ui/icons/Refresh'; + +import { useEntityGitHubRepositories } from '../../hooks/useEntityGitHubRepositories'; +import { + RepoIssues, + useGetIssuesByRepoFromGitHub, +} from '../../hooks/useGetIssuesByRepoFromGitHub'; + +import { IssueList } from './IssuesList'; +import { NoRepositoriesInfo } from './NoRepositoriesInfo'; + +/** + * @public + */ +export type GitHubIssuesProps = { + itemsPerPage?: number; + itemsPerRepo?: number; +}; + +export const GitHubIssues = (props: GitHubIssuesProps) => { + const { itemsPerPage = 10, itemsPerRepo = 40 } = props; + + const [isLoading, setIsLoading] = React.useState(true); + + const [issuesByRepository, setIssuesByRepository] = + React.useState>(); + + const { repositories } = useEntityGitHubRepositories(); + const getIssues = useGetIssuesByRepoFromGitHub(); + + const fetchGitHubIssues = React.useCallback(async () => { + setIsLoading(true); + const issuesByRepo = await getIssues(repositories, itemsPerRepo); + + setIssuesByRepository(issuesByRepo); + setIsLoading(false); + }, [itemsPerRepo, getIssues, repositories]); + + React.useEffect(() => { + if (repositories.length) { + fetchGitHubIssues(); + } else { + setIsLoading(false); + } + }, [repositories.length, fetchGitHubIssues]); + + if (!repositories.length) { + return ; + } + + return ( + + Open GitHub Issues + + + + + } + > + {isLoading && } + + + + ); +}; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx new file mode 100644 index 0000000000..173c8d9439 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/Assignees.tsx @@ -0,0 +1,59 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Typography, Box, Avatar, makeStyles } from '@material-ui/core'; + +type AssigneesProps = { + name?: string; + avatar?: string; +}; + +const useStyles = makeStyles(theme => ({ + small: { + width: theme.spacing(4), + height: theme.spacing(4), + marginLeft: theme.spacing(1), + }, + noAssignees: { + height: theme.spacing(4), + }, +})); + +export const Assignees = (props: AssigneesProps) => { + const { name, avatar } = props; + const classes = useStyles(); + + // todo: many assignees -> NUM assignees + stock images on each other + return name ? ( + + + {name} + + + + ) : ( + + + No assignees + + + ); +}; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx new file mode 100644 index 0000000000..80a365cbbb --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/CommentsCount.tsx @@ -0,0 +1,40 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { ChatIcon } from '@backstage/core-components'; +import { Box, Badge } from '@material-ui/core'; + +type CommentsCountProps = { + commentsCount: number; +}; + +export const CommentsCount = (props: CommentsCountProps) => { + const { commentsCount } = props; + + return ( + + + + + + ); +}; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx new file mode 100644 index 0000000000..95658fb343 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx @@ -0,0 +1,102 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { DateTime } from 'luxon'; + +import { + Box, + Paper, + Typography, + CardActionArea, + Link, +} from '@material-ui/core'; +import { Assignees } from './Assignees'; +import { CommentsCount } from './CommentsCount'; + +import Divider from '@material-ui/core/Divider'; + +type IssueCardProps = { + title: string; + createdAt: string; + updatedAt?: string; + url: string; + authorName: string; + assigneeName?: string; + assigneeAvatar?: string; + authorAvatar?: string; + repositoryName: string; + commentsCount: number; + even: boolean; +}; + +const getElapsedTime = (isoDate: string) => + DateTime.fromISO(isoDate).toRelative(); + +export const IssueCard = (props: IssueCardProps) => { + const { + title, + createdAt, + updatedAt, + url, + assigneeName, + assigneeAvatar, + authorName, + repositoryName, + commentsCount, + } = props; + + return ( + + + + + + + {repositoryName} + + + + + + {title} + + + + + + + Created at: {getElapsedTime(createdAt)} by{' '} + {authorName} + + {updatedAt && ( + + Last update at: {getElapsedTime(updatedAt)} + + )} + + {commentsCount > 0 && ( + + )} + + + + + + ); +}; diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/SecretsContext/index.ts b/plugins/github-issues/src/components/GitHubIssues/IssueCard/index.ts similarity index 85% rename from plugins/scaffolder/src/next/TemplateWizardPage/SecretsContext/index.ts rename to plugins/github-issues/src/components/GitHubIssues/IssueCard/index.ts index 65b530dea1..5c60abf6ab 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/SecretsContext/index.ts +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/index.ts @@ -13,8 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { - useTemplateSecrets, - SecretsContext, - SecretsContextProvider, -} from './SecretsContext'; +export { IssueCard } from './IssueCard'; diff --git a/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx b/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx new file mode 100644 index 0000000000..de071ab5bb --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/IssuesList/Filters/Filters.tsx @@ -0,0 +1,67 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Select, SelectedItems, SelectItem } from '@backstage/core-components'; +import { makeStyles, Box, Typography } from '@material-ui/core'; + +type RepositoryFiltersProps = { + items: Array; + totalIssuesInGitHub: number; + placeholder: string; + onChange: (active: Array) => void; +}; + +const useStyles = makeStyles(theme => ({ + filters: { + margin: theme.spacing(0, 0, 2, 0), + '& > div': { + maxWidth: '800px', + '& > div': { + maxWidth: '800px', + }, + }, + }, +})); + +const checkSelectedItems: ( + onChange: (active: Array) => void, +) => (active: SelectedItems) => void = onChange => active => { + return onChange(active as Array); +}; + +export const RepositoryFilters = ({ + items, + onChange, + placeholder, +}: RepositoryFiltersProps) => { + const css = useStyles(); + + return ( + + + + + +
+ +
+ +
+ +
+
+
+
+
+
+ +
+
+
+ + + +
+
+

+ MkDocs +

+

Project documentation with Markdown.

+
+

+ Overview +

+

+ MkDocs is a fast, simple and + downright gorgeous static site generator that's + geared towards building project documentation. Documentation + source files are written in Markdown, and configured with a + single YAML configuration file. Start by reading the + introduction below, then check the User Guide for more info. +

+

+ Host anywhere +

+

+ MkDocs builds completely static HTML sites that you can host on + GitHub pages, Amazon S3, or + anywhere else you + choose. +

+

+ Great themes available +

+

+ There's a stack of good looking + themes available for + MkDocs. Choose between the built in themes: + mkdocs and + readthedocs, select one of the 3rd party themes listed on the + MkDocs Themes + wiki page, or + build your own. +

+

+ Preview your site as you work +

+

+ The built-in dev-server allows you to preview your documentation + as you're writing it. It will even auto-reload and refresh your + browser whenever you save your changes. +

+

+ Easy to customize +

+

+ Get your project documentation looking just the way you want it + by customizing the + theme and/or + installing some plugins. +

+
+

+ Installation +

+

+ Install with a Package Manager +

+

+ If you have and use a package manager (such as + apt-get, + dnf, homebrew, + yum, + chocolatey, etc.) to + install packages on your system, then you may want to search for + a "MkDocs" package and, if a recent version is available, + install it with your package manager (check your system's + documentation for details). That's it, you're done! Skip down to + Getting Started. +

+

+ If your package manager does not have a recent "MkDocs" package, + you can still use your package manager to install "Python" and + "pip". Then you can use pip to + install MkDocs. +

+

+ Manual Installation +

+

+ In order to manually install MkDocs you'll need + Python installed on your + system, as well as the Python package manager, + pip. You can check if you have these already installed from the + command line: +

+
+
$ python --version
+Python 3.8.2
+$ pip --version
+pip 20.0.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)
+
+
+ +

+ MkDocs supports Python versions 3.5, 3.6, 3.7, 3.8, and pypy3. +

+

+ Installing Python +

+

+ Install Python by + downloading an installer appropriate for your system from + python.org and + running it. +

+
+

Note

+

+ If you are installing Python on Windows, be sure to check the + box to have Python added to your PATH if the installer offers + such an option (it's normally off by default). +

+

+ Add Python to PATH +

+
+

+ Installing pip +

+

+ If you're using a recent version of Python, the Python package + manager, + pip, is most likely installed by default. However, you may need to + upgrade pip to the lasted version: +

+
+
pip install --upgrade pip
+
+
+ +

+ If you need to install + pip + for the first time, download + get-pip.py. + Then run the following command to install it: +

+
+
python get-pip.py
+
+
+ +

+ Installing MkDocs +

+

Install the mkdocs package using pip:

+
+
pip install mkdocs
+
+
+ +

+ You should now have the mkdocs command installed on + your system. Run mkdocs --version to check that + everything worked okay. +

+
+
$ mkdocs --version
+mkdocs, version 0.15.3
+
+
+ +
+

Note

+

+ If you would like manpages installed for MkDocs, the + click-man + tool can generate and install them for you. Simply run the + following two commands: +

+ + + + + +
+
+
+1
+2
+
+
+
+
pip install click-man
+click-man --target path/to/man/pages mkdocs
+
+
+
+ +

+ See the + click-man documentation + for an explanation of why manpages are not automatically + generated and installed by pip. +

+
+
+

Note

+

+ If you are using Windows, some of the above commands may not + work out-of-the-box. +

+

+ A quick solution may be to preface every Python command with + python -m like this: +

+ + + + + +
+
+
+1
+2
+
+
+
+
python -m pip install mkdocs
+python -m mkdocs
+
+
+
+ +

+ For a more permanent solution, you may need to edit your + PATH environment variable to include the + Scripts directory of your Python installation. + Recent versions of Python include a script to do this for you. + Navigate to your Python installation directory (for example + C:\Python38\), open the Tools, then + Scripts folder, and run the + win_add2path.py file by double clicking on it. + Alternatively, you can + download + the script and run it (python win_add2path.py). +

+
+
+

+ Getting Started +

+

Getting started is super easy.

+
+
mkdocs new my-project
+cd my-project
+
+
+ +

+ Take a moment to review the initial project that has been + created for you. +

+

+ The initial MkDocs layout +

+

+ There's a single configuration file named + mkdocs.yml, and a folder named + docs that will contain your documentation source + files. Right now the docs folder just contains a + single documentation page, named index.md. +

+

+ MkDocs comes with a built-in dev-server that lets you preview + your documentation as you work on it. Make sure you're in the + same directory as the mkdocs.yml configuration + file, and then start the server by running the + mkdocs serve command: +

+
+
$ mkdocs serve
+INFO    -  Building documentation...
+INFO    -  Cleaning site directory
+[I 160402 15:50:43 server:271] Serving on http://127.0.0.1:8000
+[I 160402 15:50:43 handlers:58] Start watching changes
+[I 160402 15:50:43 handlers:60] Start detecting changes
+
+
+ +

+ Open up http://127.0.0.1:8000/ in your browser, and + you'll see the default home page being displayed: +

+

+ The MkDocs live server +

+

+ The dev-server also supports auto-reloading, and will rebuild + your documentation whenever anything in the configuration file, + documentation directory, or theme directory changes. +

+

+ Open the docs/index.md document in your text editor + of choice, change the initial heading to MkLorum, + and save your changes. Your browser will auto-reload and you + should see your updated documentation immediately. +

+

+ Now try editing the configuration file: mkdocs.yml. + Change the + site_name + setting to MkLorum and save the file. +

+
+
site_name: MkLorum
+
+
+ +

+ Your browser should immediately reload, and you'll see your new + site name take effect. +

+

The site_name setting

+

+ Adding pages +

+

Now add a second page to your documentation:

+
+
curl 'https://jaspervdj.be/lorem-markdownum/markdown.txt' > docs/about.md
+
+
+ +

+ As our documentation site will include some navigation headers, + you may want to edit the configuration file and add some + information about the order, title, and nesting of each page in + the navigation header by adding a + nav + setting: +

+
+
site_name: MkLorum
+nav:
+    - Home: index.md
+    - About: about.md
+
+
+ +

+ Save your changes and you'll now see a navigation bar with + Home and About items on the left as + well as Search, Previous, and + Next items on the right. +

+

Screenshot

+

+ Try the menu items and navigate back and forth between pages. + Then click on Search. A search dialog will appear, + allowing you to search for any text on any page. Notice that the + search results include every occurrence of the search term on + the site and links directly to the section of the page in which + the search term appears. You get all of that with no effort or + configuration on your part! +

+

Screenshot

+

+ Theming our documentation +

+

+ Now change the configuration file to alter how the documentation + is displayed by changing the theme. Edit the + mkdocs.yml file and add a + theme + setting: +

+
+
site_name: MkLorum
+nav:
+    - Home: index.md
+    - About: about.md
+theme: readthedocs
+
+
+ +

+ Save your changes, and you'll see the ReadTheDocs theme being + used. +

+

Screenshot

+

+ Changing the Favicon Icon +

+

+ By default, MkDocs uses the + MkDocs favicon icon. To use a + different icon, create an img subdirectory in your + docs_dir and copy your custom + favicon.ico file to that directory. MkDocs will + automatically detect and use that file as your favicon icon. +

+

+ Building the site +

+

+ That's looking good. You're ready to deploy the first pass of + your MkLorum documentation. First build the + documentation: +

+
+
mkdocs build
+
+
+ +

+ This will create a new directory, named site. Take + a look inside the directory: +

+
+
$ ls site
+about  fonts  index.html  license  search.html
+css    img    js          mkdocs   sitemap.xml
+
+
+ +

+ Notice that your source documentation has been output as two + HTML files named index.html and + about/index.html. You also have various other media + that's been copied into the site directory as part + of the documentation theme. You even have a + sitemap.xml file and + mkdocs/search_index.json. +

+

+ If you're using source code control such as git you + probably don't want to check your documentation builds into the + repository. Add a line containing site/ to your + .gitignore file. +

+
+
echo "site/" >> .gitignore
+
+
+ +

+ If you're using another source code control tool you'll want to + check its documentation on how to ignore specific directories. +

+

+ After some time, files may be removed from the documentation but + they will still reside in the site directory. To + remove those stale files, just run mkdocs with the + --clean switch. +

+
+
mkdocs build --clean
+
+
+ +

+ Other Commands and Options +

+

+ There are various other commands and options available. For a + complete list of commands, use the --help flag: +

+
+
mkdocs --help
+
+
+ +

+ To view a list of options available on a given command, use the + --help flag with that command. For example, to get + a list of all options available for the + build command run the following: +

+
+
mkdocs build --help
+
+
+ +

+ Deploying +

+

+ The documentation site that you just built only uses static + files so you'll be able to host it from pretty much anywhere. + GitHub project pages + and + Amazon S3 + may be good hosting options, depending upon your needs. Upload + the contents of the entire site directory to + wherever you're hosting your website from and you're done. For + specific instructions on a number of common hosts, see the + Deploying your Docs + page. +

+

+ Getting help +

+

+ To get help with MkDocs, please use the + discussion group, + GitHub issues + or the MkDocs IRC channel #mkdocs on freenode. +

+
+
+
+
+ + +
+ + + + + + + + +`; diff --git a/plugins/techdocs/src/test-utils/index.ts b/plugins/techdocs/src/test-utils/index.ts index 584934f732..3ed7161f01 100644 --- a/plugins/techdocs/src/test-utils/index.ts +++ b/plugins/techdocs/src/test-utils/index.ts @@ -15,9 +15,11 @@ */ import FIXTURE_STANDARD_PAGE from './fixtures/mkdocs-index'; +import FIXTURE_STANDARD_PAGE_EXPANDED_NAVIGATION from './fixtures/mkdocs-expanded-index'; export const FIXTURES = { FIXTURE_STANDARD_PAGE, + FIXTURE_STANDARD_PAGE_EXPANDED_NAVIGATION, }; export * from './shadowDom'; diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 6e1d555ab0..a025c3c136 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "@backstage/catalog-model": "^1.1.0", - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/plugin-catalog-react": "^1.1.3-next.0", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 2a16a80332..05ceb6f5f5 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -34,7 +34,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/theme": "^0.2.16", "@material-ui/core": "^4.12.2", diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 2dbc98a290..68b8c834eb 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -24,7 +24,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@backstage/core-components": "^0.10.1-next.0", + "@backstage/core-components": "^0.10.1-next.1", "@backstage/core-plugin-api": "^1.0.5-next.0", "@backstage/errors": "^1.1.0", "@backstage/theme": "^0.2.16", diff --git a/storybook/yarn.lock b/storybook/yarn.lock index f603d5ba1a..bec1d7019f 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -7783,9 +7783,9 @@ style-to-object@0.3.0, style-to-object@^0.3.0: inline-style-parser "0.1.1" sucrase@^3.21.0: - version "3.24.0" - resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.24.0.tgz#66a8f2cc845bc441706ce5f3056de283289067b6" - integrity sha512-SevqflhW356TKEyWjFHg2e5f3eH+5rzmsMJxrVMDvZIEHh/goYrpzDGA6APEj4ME9MdGm8oNgIzi1eF3c3dDQA== + version "3.25.0" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.25.0.tgz#6dffa34e614b3347877507a4380cc4f022b7b7aa" + integrity sha512-WxTtwEYXSmZArPGStGBicyRsg5TBEFhT5b7N+tF+zauImP0Acy+CoUK0/byJ8JNPK/5lbpWIVuFagI4+0l85QQ== dependencies: commander "^4.0.0" glob "7.1.6" diff --git a/yarn.lock b/yarn.lock index fe03c06949..b934d159e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1908,7 +1908,7 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.11.2", "@babel/runtime-corejs3@^7.16.8": +"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.11.2": version "7.17.2" resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz#fdca2cd05fba63388babe85d349b6801b008fd13" integrity sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg== @@ -1916,6 +1916,14 @@ core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" +"@babel/runtime-corejs3@^7.18.9": + version "7.18.9" + resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.18.9.tgz#7bacecd1cb2dd694eacd32a91fcf7021c20770ae" + integrity sha512-qZEWeccZCrHA2Au4/X05QW5CMdm4VjUDCrGq5gf1ZDcM4hRqreKrtwAn7yci9zfgAS9apvnsFXiGBHBAxZdK9A== + dependencies: + core-js-pure "^3.20.2" + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.17.7" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" @@ -2072,52 +2080,7 @@ zen-observable "^0.8.15" zod "^3.11.6" -"@backstage/core-components@^0.9.0": - version "0.9.5" - resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.5.tgz#5a0b34867aaee0549bfa67b39a69c09588fa3c7a" - integrity sha512-kfAdN70idiEqHeH9ZQryn6C0RxJEKiRc/7srYIz0CVV88zJfc0nmZ5C/S10Gkht2xWfm95tTSw2P1vEYIBbfxg== - dependencies: - "@backstage/config" "^1.0.1" - "@backstage/core-plugin-api" "^1.0.3" - "@backstage/errors" "^1.0.0" - "@backstage/theme" "^0.2.15" - "@backstage/version-bridge" "^1.0.1" - "@material-table/core" "^3.1.0" - "@material-ui/core" "^4.12.2" - "@material-ui/icons" "^4.9.1" - "@material-ui/lab" "4.0.0-alpha.57" - "@react-hookz/web" "^14.0.0" - "@types/react-sparklines" "^1.7.0" - "@types/react-text-truncate" "^0.14.0" - ansi-regex "^6.0.1" - classnames "^2.2.6" - d3-selection "^3.0.0" - d3-shape "^3.0.0" - d3-zoom "^3.0.0" - dagre "^0.8.5" - history "^5.0.0" - immer "^9.0.1" - lodash "^4.17.21" - pluralize "^8.0.0" - prop-types "^15.7.2" - qs "^6.9.4" - rc-progress "3.3.3" - react-helmet "6.1.0" - react-hook-form "^7.12.2" - react-markdown "^8.0.0" - react-router "6.0.0-beta.0" - react-router-dom "6.0.0-beta.0" - react-sparklines "^1.7.0" - react-syntax-highlighter "^15.4.5" - react-text-truncate "^0.19.0" - react-use "^17.3.2" - react-virtualized-auto-sizer "^1.0.6" - react-window "^1.8.6" - remark-gfm "^3.0.1" - zen-observable "^0.8.15" - zod "^3.11.6" - -"@backstage/core-plugin-api@^1.0.0", "@backstage/core-plugin-api@^1.0.3", "@backstage/core-plugin-api@^1.0.4": +"@backstage/core-plugin-api@^1.0.0", "@backstage/core-plugin-api@^1.0.4": version "1.0.4" resolved "https://registry.npmjs.org/@backstage/core-plugin-api/-/core-plugin-api-1.0.4.tgz#0dbe80be1d298273df0299ef69baa18522d9a808" integrity sha512-fMMpjqW2RjwclnHUJsSyPCTguplflQYEWv7wsk7IoanEkWx39pensi8OsdIBawXrOixXEnI47dgxtVMOQUxOKA== @@ -2159,6 +2122,14 @@ lodash "^4.17.21" luxon "^3.0.0" +"@backstage/plugin-catalog-common@^1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@backstage/plugin-catalog-common/-/plugin-catalog-common-1.0.4.tgz#94389cb6555eeaea2814d286744d951578ae9132" + integrity sha512-6+3pQMFOjvsswzaGZ1qqgkc2dnuQOFILDk4zmmc/bq35R4ICk48Pbw41gH0/YR7yupXPi3OwN4la50ECUELCqw== + dependencies: + "@backstage/plugin-permission-common" "^0.6.3" + "@backstage/plugin-search-common" "^1.0.0" + "@backstage/plugin-catalog-react@^1.0.0", "@backstage/plugin-catalog-react@^1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@backstage/plugin-catalog-react/-/plugin-catalog-react-1.1.2.tgz#253a99d9ced5d751f9d1fb3d278511d754aaed4e" @@ -2787,9 +2758,9 @@ integrity sha512-91ArYvRgXWb73YvEOBMmOcJc0bDRs5yiVHnqkwoG0f3nm7nZuipllz6e7BvFESBvjkDTBC0zMD8QxedUwNLc1A== "@google-cloud/storage@^6.0.0": - version "6.2.3" - resolved "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.2.3.tgz#e3dae8708488cf2e0e4fbf0488083d9d279ee097" - integrity sha512-UJqn3Ln8wFBPLuwBaNu3PlhzQDL3EKKfP1+3mzLRQhcFqgpBSMPLDgAXxc6e9S0l0kqsi4GOuAA7fA+l/VAMjQ== + version "6.3.0" + resolved "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.3.0.tgz#0a9765416b659f54477da6611d9c12b914c04a61" + integrity sha512-Ah4wl9cWUEW+2lAqHsKauaLlPmbtdOdQkvJE6BFwmTSZhywYVtVHLcEpf5F+/GmmNTnirFGNdE7UjgbyOxcnRg== dependencies: "@google-cloud/paginator" "^3.0.7" "@google-cloud/projectify" "^3.0.0" @@ -2835,9 +2806,9 @@ meros "^1.1.4" "@graphql-codegen/cli@^2.3.1": - version "2.11.2" - resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.11.2.tgz#f502d0e9e19305acffca5f07789dde8d4e0fa656" - integrity sha512-dt70+et0QFmhL3krrlYWcsp7T6pvChEQ1vEGoNn46Rn53velGDwP546DtSPpHJmajY/eJ11CueoI0J/3o0/BTA== + version "2.11.3" + resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.11.3.tgz#6cb0fd6da0773957b531cccf7459303a23ee1c05" + integrity sha512-C1d88Kx0a0PF1tOR00UIZjHq5aWNNcw5fM2k08rOY9O5b4sU7kEb+YbGKP6EExTtJnYb49fePLKVvrIv1ejDFg== dependencies: "@graphql-codegen/core" "2.6.0" "@graphql-codegen/plugin-helpers" "^2.6.1" @@ -3435,15 +3406,20 @@ object-assign "^4.1.1" scheduler "^0.20.2" -"@humanwhocodes/config-array@^0.9.2": - version "0.9.2" - resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" - integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== +"@humanwhocodes/config-array@^0.10.4": + version "0.10.4" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz#01e7366e57d2ad104feea63e72248f22015c520c" + integrity sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" minimatch "^3.0.4" +"@humanwhocodes/gitignore-to-minimatch@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz#316b0a63b91c10e53f242efb4ace5c3b34e8728d" + integrity sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA== + "@humanwhocodes/object-schema@^1.2.1": version "1.2.1" resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" @@ -4883,7 +4859,7 @@ react-beautiful-dnd "^13.0.0" react-double-scrollbar "0.0.15" -"@material-ui/core@^4.11.0", "@material-ui/core@^4.11.3", "@material-ui/core@^4.12.1", "@material-ui/core@^4.12.2", "@material-ui/core@^4.9.10", "@material-ui/core@^4.9.13": +"@material-ui/core@^4.11.0", "@material-ui/core@^4.11.3", "@material-ui/core@^4.12.1", "@material-ui/core@^4.12.2", "@material-ui/core@^4.12.4", "@material-ui/core@^4.9.10", "@material-ui/core@^4.9.13": version "4.12.4" resolved "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz#4ac17488e8fcaf55eb6a7f5efb2a131e10138a73" integrity sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ== @@ -4930,7 +4906,7 @@ prop-types "^15.7.2" react-is "^16.8.0 || ^17.0.0" -"@material-ui/lab@^4.0.0-alpha.57", "@material-ui/lab@^4.0.0-alpha.60": +"@material-ui/lab@^4.0.0-alpha.57", "@material-ui/lab@^4.0.0-alpha.60", "@material-ui/lab@^4.0.0-alpha.61": version "4.0.0-alpha.61" resolved "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.61.tgz#9bf8eb389c0c26c15e40933cc114d4ad85e3d978" integrity sha512-rSzm+XKiNUjKegj8bzt5+pygZeckNLOr+IjykH8sYdVk7dE9y2ZuUSofiMV2bJk3qU+JHwexmw+q0RyNZB9ugg== @@ -6000,13 +5976,6 @@ resolved "https://registry.npmjs.org/@react-hookz/deep-equal/-/deep-equal-1.0.2.tgz#4e8bdeda027379dcf8b62a42e5f75f0351b11b35" integrity sha512-cM5kPFb6EFH5q52WzRxfRX9+8g5kq78McWOYs6e1seo+nK6NpfLupT5uOCIJp37jU8ayd4Su8ni3HRFTN2C2kg== -"@react-hookz/web@^14.0.0": - version "14.7.1" - resolved "https://registry.npmjs.org/@react-hookz/web/-/web-14.7.1.tgz#5e39e6fc21331cc4ae95f36e8135ad763e6c29fb" - integrity sha512-kU1CccZDXvQ9G4vcCCpX3mDQqYKkuLXGFOtPMgmbZ9KrvkEduMRH4JqSVXp1nI/bGI1GJ0KAWm4UEb1x5eDGAg== - dependencies: - "@react-hookz/deep-equal" "^1.0.2" - "@react-hookz/web@^15.0.0": version "15.0.1" resolved "https://registry.npmjs.org/@react-hookz/web/-/web-15.0.1.tgz#a6e5460dd16e54ccc0b899e1eed4ae29e871060f" @@ -6035,12 +6004,12 @@ integrity sha512-8UiDeDbjCImFSfOegGu13otQ7OdP9FOYpcLjeouppnhs+MPeIEAtYS+jCcBKmi3reyTagC15/KVSRhde1wS1vg== "@roadiehq/backstage-plugin-buildkite@^2.0.0": - version "2.0.4" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-buildkite/-/backstage-plugin-buildkite-2.0.4.tgz#cd72fd35a9f8b6bb1c2ccd3c13d2aece2ecaf86e" - integrity sha512-bOrqKO9MmRB5jgue+S8WEmJk83h6g4EdGp2qmirVODQddL03gtFNgMTauQkKAV7T8N+C948xDcgdL3pjvLYJdA== + version "2.0.5" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-buildkite/-/backstage-plugin-buildkite-2.0.5.tgz#540679bd1dbb4cadf654e3d939cc9cbe4cf6e2e5" + integrity sha512-zMTlBzjEHdydWSddCt+Mr+2wjbMWn2f/AgBTXfYvaGDTY1fCmEFQ3gOL2fHd7UHk635AE/DKuGLL8gyEvLbqjg== dependencies: "@backstage/catalog-model" "^1.0.0" - "@backstage/core-components" "^0.9.0" + "@backstage/core-components" "^0.10.0" "@backstage/core-plugin-api" "^1.0.0" "@backstage/plugin-catalog-react" "^1.0.0" "@backstage/theme" "^0.2.6" @@ -6054,12 +6023,12 @@ react-use "^17.2.4" "@roadiehq/backstage-plugin-github-insights@^2.0.0": - version "2.0.1" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-2.0.1.tgz#b0cccdd5cfe1c94055ad372087a1daba9ec72bb4" - integrity sha512-Kq3JdzSIpLV0Ka6GqX7Ok2QW/s6w18l0Kyec+OtQ+/1dz8AeG7UoYwUtBI/+sTd+gveTHAonwi9xINYbcIvQhQ== + version "2.0.2" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-insights/-/backstage-plugin-github-insights-2.0.2.tgz#d6a953123f8a60be5df5b32583c5c2b22d18f8bb" + integrity sha512-3f+iTuAqINdolxrOjAS2XR2JDv7v2BALfAnr/EuCXfIS5qbJqn6IpktC1FcS0HHV1hmI/y+fyI3V5/69RjNBnQ== dependencies: "@backstage/catalog-model" "^1.0.0" - "@backstage/core-components" "^0.9.0" + "@backstage/core-components" "^0.10.0" "@backstage/core-plugin-api" "^1.0.0" "@backstage/integration-react" "^1.0.0" "@backstage/plugin-catalog-react" "^1.0.0" @@ -6068,7 +6037,6 @@ "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.45" - "@octokit/request-error" "^2.1.0" "@octokit/rest" "^18.5.3" "@octokit/types" "^6.14.2" history "^5.0.0" @@ -6078,12 +6046,12 @@ zustand "3.6.9" "@roadiehq/backstage-plugin-github-pull-requests@^2.0.0": - version "2.2.1" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.2.1.tgz#a50ca71c70fb16283bd65427688c3c5e9425dec7" - integrity sha512-oMLe1ew8hee9LfV5Pdw25sV1XdoMxpq/ZKZWWtZTS0iCudgWleslkdj20preF8FPuHQjkr1xAtnDdnMWvejtxQ== + version "2.2.3" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-github-pull-requests/-/backstage-plugin-github-pull-requests-2.2.3.tgz#8a5f5c18f0d0196c3fb5b350598293f2e441c9cd" + integrity sha512-ClZc4gLSsE+e+C6tpXJFJ2bXSo28UdlEACKzVK/w1H63XnyebsJHNu8uJJbdZL7GImHM3P9HjkXhSjj01g6HUg== dependencies: "@backstage/catalog-model" "^1.0.0" - "@backstage/core-components" "^0.9.0" + "@backstage/core-components" "^0.10.0" "@backstage/core-plugin-api" "^1.0.0" "@backstage/plugin-catalog-react" "^1.0.0" "@backstage/plugin-home" "^0.4.19" @@ -6102,12 +6070,12 @@ react-use "^17.2.4" "@roadiehq/backstage-plugin-travis-ci@^2.0.0": - version "2.0.1" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-travis-ci/-/backstage-plugin-travis-ci-2.0.1.tgz#0d706d3a31b123cd2e76b6d7fd849ae8cb97e786" - integrity sha512-Qay8Ad+heMEyW5QPi2I4C7ky3NUYhgE7FF+pV77ES21zyytCcTHQIkYHJd0FrR6WpedtNSegfcRj61VSZfbRKA== + version "2.0.2" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-travis-ci/-/backstage-plugin-travis-ci-2.0.2.tgz#9a7aca54a6728bf836c5f51e22fd1a397801c9e0" + integrity sha512-fIevPreKE16nEuJzg5WPN3xI+z8EaotXwqCpWk7GR/8UjLSB5bt7wAwaMsQdywvmK21rBLAmKBlSn5x0TfYoLQ== dependencies: "@backstage/catalog-model" "^1.0.0" - "@backstage/core-components" "^0.9.0" + "@backstage/core-components" "^0.10.0" "@backstage/core-plugin-api" "^1.0.0" "@backstage/plugin-catalog-react" "^1.0.0" "@backstage/theme" "^0.2.9" @@ -6302,6 +6270,11 @@ resolved "https://registry.npmjs.org/@spotify/eslint-config-typescript/-/eslint-config-typescript-14.0.1.tgz#850a435b0defebbb3de591d83e3fc369bbc51753" integrity sha512-y/8on49Wtg3HvKd9A32Q7iJaOgngcSJR8hjGx/POFhJFcPRcZuTJSlhd31CF8fg78bMuzdvYH8au7FhNKjnEVw== +"@spotify/prettier-config@^13.0.1": + version "13.0.1" + resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-13.0.1.tgz#0fdceb3d4ab543259ce6adc0ec1d10e34898b812" + integrity sha512-oVd4hjx2+y0MeUdk1l+ItwVLwlrDlvTlGwXBWMMzPYc7DLyxuxFvDfoHGkAQkrikfAgtdnzxrW6u9a8ywUqdfw== + "@spotify/prettier-config@^14.0.0": version "14.0.1" resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-14.0.1.tgz#a3a2342ec07693647ab76a64a623fbb79d464fa7" @@ -7396,9 +7369,9 @@ integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== "@types/node@^16.0.0", "@types/node@^16.11.26", "@types/node@^16.9.2": - version "16.11.46" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.46.tgz#26047602eefa47b36759d9ebb1b55ad08ce97a73" - integrity sha512-x+sfpb2dMrhCQPL4NAGs64Z9hh0t72aP0dg+PuZidmPr/0Gj5ELQTjD/t46dq3DF/8ZvSHOaIyDIbAsdPshyVQ== + version "16.11.47" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.47.tgz#efa9e3e0f72e7aa6a138055dace7437a83d9f91c" + integrity sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -7799,7 +7772,7 @@ "@types/cookiejar" "*" "@types/node" "*" -"@types/supertest@^2.0.8": +"@types/supertest@^2.0.12", "@types/supertest@^2.0.8": version "2.0.12" resolved "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.12.tgz#ddb4a0568597c9aadff8dbec5b2e8fddbe8692fc" integrity sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ== @@ -7829,12 +7802,12 @@ "@types/node" "*" "@types/tar@^6.1.1": - version "6.1.1" - resolved "https://registry.npmjs.org/@types/tar/-/tar-6.1.1.tgz#ab341ec1f149d7eb2a4f4ded56ff85f0d4fe7cb5" - integrity sha512-8mto3YZfVpqB1CHMaYz1TUYIQfZFbh/QbEq5Hsn6D0ilCfqRVCdalmc89B7vi3jhl9UYIk+dWDABShNfOkv5HA== + version "6.1.2" + resolved "https://registry.npmjs.org/@types/tar/-/tar-6.1.2.tgz#e60108a7d1b08cc91bf2faf1286cc08fdad48bbe" + integrity sha512-bnX3RRm70/n1WMwmevdOAeDU4YP7f5JSubgnuU+yrO+xQQjwDboJj3u2NTJI5ngCQhXihqVVAH5h5J8YpdpEvg== dependencies: - "@types/minipass" "*" "@types/node" "*" + minipass "^3.3.5" "@types/tern@*": version "0.23.4" @@ -7988,13 +7961,13 @@ integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== "@typescript-eslint/eslint-plugin@^5.9.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz#cae1967b1e569e6171bbc6bec2afa4e0c8efccfe" - integrity sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ== + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.32.0.tgz#e27e38cffa4a61226327c874a7be965e9a861624" + integrity sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew== dependencies: - "@typescript-eslint/scope-manager" "5.31.0" - "@typescript-eslint/type-utils" "5.31.0" - "@typescript-eslint/utils" "5.31.0" + "@typescript-eslint/scope-manager" "5.32.0" + "@typescript-eslint/type-utils" "5.32.0" + "@typescript-eslint/utils" "5.32.0" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -8015,13 +7988,13 @@ eslint-utils "^3.0.0" "@typescript-eslint/parser@^5.9.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.31.0.tgz#7f42d7dcc68a0a6d80a0f3d9a65063aee7bb8d2c" - integrity sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw== + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.32.0.tgz#1de243443bc6186fb153b9e395b842e46877ca5d" + integrity sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A== dependencies: - "@typescript-eslint/scope-manager" "5.31.0" - "@typescript-eslint/types" "5.31.0" - "@typescript-eslint/typescript-estree" "5.31.0" + "@typescript-eslint/scope-manager" "5.32.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/typescript-estree" "5.32.0" debug "^4.3.4" "@typescript-eslint/scope-manager@5.20.0": @@ -8032,13 +8005,13 @@ "@typescript-eslint/types" "5.20.0" "@typescript-eslint/visitor-keys" "5.20.0" -"@typescript-eslint/scope-manager@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz#f47a794ba84d9b818ab7f8f44fff55a61016c606" - integrity sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg== +"@typescript-eslint/scope-manager@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz#763386e963a8def470580cc36cf9228864190b95" + integrity sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg== dependencies: - "@typescript-eslint/types" "5.31.0" - "@typescript-eslint/visitor-keys" "5.31.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/visitor-keys" "5.32.0" "@typescript-eslint/scope-manager@5.9.0": version "5.9.0" @@ -8048,12 +8021,12 @@ "@typescript-eslint/types" "5.9.0" "@typescript-eslint/visitor-keys" "5.9.0" -"@typescript-eslint/type-utils@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz#70a0b7201360b5adbddb0c36080495aa08f6f3d9" - integrity sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w== +"@typescript-eslint/type-utils@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.32.0.tgz#45a14506fe3fb908600b4cef2f70778f7b5cdc79" + integrity sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg== dependencies: - "@typescript-eslint/utils" "5.31.0" + "@typescript-eslint/utils" "5.32.0" debug "^4.3.4" tsutils "^3.21.0" @@ -8062,10 +8035,10 @@ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz#fa39c3c2aa786568302318f1cb51fcf64258c20c" integrity sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg== -"@typescript-eslint/types@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.31.0.tgz#7aa389122b64b18e473c1672fb3b8310e5f07a9a" - integrity sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g== +"@typescript-eslint/types@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz#484273021eeeae87ddb288f39586ef5efeb6dcd8" + integrity sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ== "@typescript-eslint/types@5.9.0": version "5.9.0" @@ -8085,13 +8058,13 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz#eb92970c9d6e3946690d50c346fb9b1d745ee882" - integrity sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw== +"@typescript-eslint/typescript-estree@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz#282943f34babf07a4afa7b0ff347a8e7b6030d12" + integrity sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg== dependencies: - "@typescript-eslint/types" "5.31.0" - "@typescript-eslint/visitor-keys" "5.31.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/visitor-keys" "5.32.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -8111,15 +8084,15 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.31.0.tgz#e146fa00dca948bfe547d665b2138a2dc1b79acd" - integrity sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg== +"@typescript-eslint/utils@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz#eccb6b672b94516f1afc6508d05173c45924840c" + integrity sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.31.0" - "@typescript-eslint/types" "5.31.0" - "@typescript-eslint/typescript-estree" "5.31.0" + "@typescript-eslint/scope-manager" "5.32.0" + "@typescript-eslint/types" "5.32.0" + "@typescript-eslint/typescript-estree" "5.32.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -8143,12 +8116,12 @@ "@typescript-eslint/types" "5.20.0" eslint-visitor-keys "^3.0.0" -"@typescript-eslint/visitor-keys@5.31.0": - version "5.31.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz#b0eca264df01ce85dceb76aebff3784629258f54" - integrity sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg== +"@typescript-eslint/visitor-keys@5.32.0": + version "5.32.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz#b9715d0b11fdb5dd10fd0c42ff13987470525394" + integrity sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g== dependencies: - "@typescript-eslint/types" "5.31.0" + "@typescript-eslint/types" "5.32.0" eslint-visitor-keys "^3.3.0" "@typescript-eslint/visitor-keys@5.9.0": @@ -8437,6 +8410,11 @@ acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.0, acorn@^8.7.1: resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== +acorn@^8.8.0: + version "8.8.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" @@ -9115,9 +9093,9 @@ aws-sdk-mock@^5.2.1: traverse "^0.6.6" aws-sdk@^2.1122.0, aws-sdk@^2.814.0, aws-sdk@^2.840.0, aws-sdk@^2.948.0: - version "2.1184.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1184.0.tgz#6f800815382284825a3f03422410eaf3cefcac68" - integrity sha512-g4UQgc8+Ljk2e6xJYwBSQrDJ8BmQ/E3nHLw9ITEJKC1hgK8DLy77PUielA0ptscoKz5ySCSSGbMjR1B1HgThKQ== + version "2.1186.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1186.0.tgz#f08fc5f1f53defa1fff83177621947dc0ca8d29b" + integrity sha512-3yDWwNWgbSH9tRVyan0PlRU938Po9QH+06XHwRNwAa/6bixYl4L48c6YgpfxBpwl0IvcCCTivD7ZqshndwishQ== dependencies: buffer "4.9.2" events "1.1.1" @@ -11068,9 +11046,9 @@ core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.10: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-js@^3.4.1, core-js@^3.6.5: - version "3.24.0" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.24.0.tgz#4928d4e99c593a234eb1a1f9abd3122b04d3ac57" - integrity sha512-IeOyT8A6iK37Ep4kZDD423mpi6JfPRoPUdQwEWYiGolvn4o6j2diaRzNfDfpTdu3a5qMbrGUzKUpYpRY8jXCkQ== + version "3.24.1" + resolved "https://registry.npmjs.org/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f" + integrity sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -12238,9 +12216,9 @@ docker-modem@^3.0.0: ssh2 "^1.4.0" dockerode@^3.3.1: - version "3.3.2" - resolved "https://registry.npmjs.org/dockerode/-/dockerode-3.3.2.tgz#f3545700d2f7f86141b58843a755eeb21e38d5cd" - integrity sha512-oXN+1XVH2TeyE0Jj9Ci6Fim8ZIDxyqeJrkx9qhEOaRiA+nhLihKfd3M2L+Aqrj5C2ObPw8RVN2zPWvvk0x2dwg== + version "3.3.3" + resolved "https://registry.npmjs.org/dockerode/-/dockerode-3.3.3.tgz#7504db10d23866c6f267e7b0b7b4a75fc2203e8d" + integrity sha512-lvKV6/NGf2/CYLt5V4c0fd6Fl9XZSCo1Z2HBT9ioKrKLMB2o+gA62Uza8RROpzGvYv57KJx2dKu+ZwSpB//OIA== dependencies: docker-modem "^3.0.0" tar-fs "~2.0.1" @@ -12324,12 +12302,7 @@ domhandler@^4.0.0, domhandler@^4.2.0: dependencies: domelementtype "^2.2.0" -dompurify@=2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" - integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== - -dompurify@^2.2.7, dompurify@^2.2.9, dompurify@^2.3.6: +dompurify@=2.3.10, dompurify@^2.2.7, dompurify@^2.2.9, dompurify@^2.3.6: version "2.3.10" resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.10.tgz#901f7390ffe16a91a5a556b94043314cd4850385" integrity sha512-o7Fg/AgC7p/XpKjf/+RC3Ok6k4St5F7Q6q6+Nnm3p2zGWioAY6dh0CbbuwOhH2UcSzKsdniE/YnE2/92JcsA+g== @@ -12959,9 +12932,9 @@ eslint-plugin-import@^2.25.4: tsconfig-paths "^3.14.1" eslint-plugin-jest@^26.1.2: - version "26.6.0" - resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.6.0.tgz#546804fa42da75d7d58d4d3b278d5186abd3f6c0" - integrity sha512-f8n46/97ZFdU4KqeQYqO8AEVGIhHWvkpgNBWHH3jrM28/y8llnbf3IjfIKv6p2pZIMinK1PCqbbROxs9Eud02Q== + version "26.7.0" + resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.7.0.tgz#41d405ac9143e1284a3401282db47ed459436778" + integrity sha512-/YNitdfG3o3cC6juZziAdkk6nfJt01jXVfj4AgaYVLs7bupHzRDL5K+eipdzhDXtQsiqaX1TzfwSuRlEgeln1A== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -13076,12 +13049,13 @@ eslint-webpack-plugin@^3.1.1: schema-utils "^4.0.0" eslint@^8.6.0: - version "8.20.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b" - integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA== + version "8.21.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz#1940a68d7e0573cef6f50037addee295ff9be9ef" + integrity sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA== dependencies: "@eslint/eslintrc" "^1.3.0" - "@humanwhocodes/config-array" "^0.9.2" + "@humanwhocodes/config-array" "^0.10.4" + "@humanwhocodes/gitignore-to-minimatch" "^1.0.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -13091,14 +13065,17 @@ eslint@^8.6.0: eslint-scope "^7.1.1" eslint-utils "^3.0.0" eslint-visitor-keys "^3.3.0" - espree "^9.3.2" + espree "^9.3.3" esquery "^1.4.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" + find-up "^5.0.0" functional-red-black-tree "^1.0.1" glob-parent "^6.0.1" globals "^13.15.0" + globby "^11.1.0" + grapheme-splitter "^1.0.4" ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" @@ -13130,6 +13107,15 @@ espree@^9.3.2: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" +espree@^9.3.3: + version "9.3.3" + resolved "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz#2dd37c4162bb05f433ad3c1a52ddf8a49dc08e9d" + integrity sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -13246,25 +13232,25 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: safe-buffer "^5.1.1" "example-app@link:packages/app": - version "0.2.74-next.0" + version "0.2.74-next.1" dependencies: "@backstage/app-defaults" "^1.0.5-next.0" "@backstage/catalog-model" "^1.1.0" "@backstage/cli" "^0.18.1-next.0" "@backstage/config" "^1.0.1" "@backstage/core-app-api" "^1.0.5-next.0" - "@backstage/core-components" "^0.10.1-next.0" + "@backstage/core-components" "^0.10.1-next.1" "@backstage/core-plugin-api" "^1.0.5-next.0" "@backstage/integration-react" "^1.1.3-next.0" "@backstage/plugin-airbrake" "^0.3.8-next.0" "@backstage/plugin-apache-airflow" "^0.2.1-next.0" - "@backstage/plugin-api-docs" "^0.8.8-next.0" + "@backstage/plugin-api-docs" "^0.8.8-next.1" "@backstage/plugin-azure-devops" "^0.1.24-next.0" "@backstage/plugin-badges" "^0.2.32-next.0" - "@backstage/plugin-catalog-common" "^1.0.4" + "@backstage/plugin-catalog-common" "^1.0.5-next.0" "@backstage/plugin-catalog-graph" "^0.2.20-next.0" "@backstage/plugin-catalog-import" "^0.8.11-next.0" - "@backstage/plugin-catalog-react" "^1.1.3-next.0" + "@backstage/plugin-catalog-react" "^1.1.3-next.1" "@backstage/plugin-circleci" "^0.3.8-next.0" "@backstage/plugin-cloudbuild" "^0.3.8-next.0" "@backstage/plugin-code-coverage" "^0.2.1-next.0" @@ -13276,10 +13262,10 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-github-actions" "^0.5.8-next.0" "@backstage/plugin-gocd" "^0.1.14-next.0" "@backstage/plugin-graphiql" "^0.2.40-next.0" - "@backstage/plugin-home" "^0.4.24-next.0" - "@backstage/plugin-jenkins" "^0.7.7-next.0" + "@backstage/plugin-home" "^0.4.24-next.1" + "@backstage/plugin-jenkins" "^0.7.7-next.1" "@backstage/plugin-kafka" "^0.3.8-next.0" - "@backstage/plugin-kubernetes" "^0.7.1-next.0" + "@backstage/plugin-kubernetes" "^0.7.1-next.1" "@backstage/plugin-lighthouse" "^0.3.8-next.0" "@backstage/plugin-newrelic" "^0.3.26-next.0" "@backstage/plugin-newrelic-dashboard" "^0.2.1-next.0" @@ -13287,7 +13273,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-pagerduty" "0.5.1-next.0" "@backstage/plugin-permission-react" "^0.4.4-next.0" "@backstage/plugin-rollbar" "^0.4.8-next.0" - "@backstage/plugin-scaffolder" "^1.4.1-next.0" + "@backstage/plugin-scaffolder" "^1.5.0-next.1" "@backstage/plugin-search" "^1.0.1-next.0" "@backstage/plugin-search-common" "^1.0.0" "@backstage/plugin-search-react" "^1.0.1-next.0" @@ -13296,9 +13282,9 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: "@backstage/plugin-stack-overflow" "^0.1.4-next.0" "@backstage/plugin-tech-insights" "^0.2.4-next.0" "@backstage/plugin-tech-radar" "^0.5.15-next.0" - "@backstage/plugin-techdocs" "^1.3.1-next.0" - "@backstage/plugin-techdocs-module-addons-contrib" "^1.0.3-next.0" - "@backstage/plugin-techdocs-react" "^1.0.3-next.0" + "@backstage/plugin-techdocs" "^1.3.1-next.1" + "@backstage/plugin-techdocs-module-addons-contrib" "^1.0.3-next.1" + "@backstage/plugin-techdocs-react" "^1.0.3-next.1" "@backstage/plugin-todo" "^0.2.10-next.0" "@backstage/plugin-user-settings" "^0.4.7-next.0" "@backstage/theme" "^0.2.16" @@ -16358,6 +16344,11 @@ isarray@2.0.1: resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= +isbinaryfile@^4.0.10: + version "4.0.10" + resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + isbinaryfile@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf" @@ -18280,6 +18271,11 @@ luxon@^1.23.x: resolved "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz#e7f96daad3938c06a62de0fb027115d251251fbf" integrity sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ== +luxon@^2.4.0: + version "2.5.0" + resolved "https://registry.npmjs.org/luxon/-/luxon-2.5.0.tgz#098090f67d690b247e83c090267a60b1aa8ea96c" + integrity sha512-IDkEPB80Rb6gCAU+FEib0t4FeJ4uVOuX1CQ9GsvU3O+JAGIgu0J7sf1OarXKaKDygTZIoJyU6YdZzTFRu+YR0A== + luxon@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/luxon/-/luxon-3.0.1.tgz#6901111d10ad06fd267ad4e4128a84bef8a77299" @@ -19286,6 +19282,13 @@ minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3. dependencies: yallist "^4.0.0" +minipass@^3.3.5: + version "3.3.5" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.5.tgz#6da7e53a48db8a856eeb9153d85b230a2119e819" + integrity sha512-rQ/p+KfKBkeNwo04U15i+hOwoVBVmekmm/HcfTkTN2t9pbQKCMm4eN5gFeqgrrSp/kH/7BYYhTIHOxGqzbBPaA== + dependencies: + yallist "^4.0.0" + minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -19445,7 +19448,7 @@ msw@^0.43.0: type-fest "^1.2.2" yargs "^17.3.1" -msw@^0.44.0: +msw@^0.44.0, msw@^0.44.2: version "0.44.2" resolved "https://registry.npmjs.org/msw/-/msw-0.44.2.tgz#00a901b6cc9d119fb30f794330d96dca6944afc2" integrity sha512-u8wjzzcMWouoZtuIShCwx4M3wFF5sBAV1f8K4a0WX8kiihFjzl89IKE1VYmTclLyMIwpOq8qQ1HTpuh2BFX/3A== @@ -20173,7 +20176,7 @@ octokit-plugin-create-pull-request@^3.10.0: dependencies: "@octokit/types" "^6.8.2" -octokit@^2.0.0: +octokit@^2.0.0, octokit@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/octokit/-/octokit-2.0.4.tgz#cfd3adee6b775d3fa8cd8746590bed36127cc0a0" integrity sha512-9QvgYGzrSTGmr3koSGtbgeMgqYI20QI0Vv8Bk9y6phchk6L2aHFhcrUOIeNUPj1Z+KZnEBd6A/8faNpDFNfVjg== @@ -21618,7 +21621,7 @@ prettier@^1.16.4, prettier@^1.19.1: resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -prettier@^2.2.1: +prettier@^2.2.1, prettier@^2.7.1: version "2.7.1" resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== @@ -22099,15 +22102,6 @@ raw-body@2.5.1, raw-body@^2.4.1: iconv-lite "0.4.24" unpipe "1.0.0" -rc-progress@3.3.3: - version "3.3.3" - resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz#eb9bffbacab1534f2542f9f6861ce772254362b1" - integrity sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.6" - rc-util "^5.16.1" - rc-progress@3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-3.4.0.tgz#80a33c25c9675f5836ba25a87cd8dc310aad72b1" @@ -22165,13 +22159,13 @@ react-copy-to-clipboard@^5.0.4: copy-to-clipboard "^3.3.1" prop-types "^15.8.1" -react-debounce-input@=3.2.4: - version "3.2.4" - resolved "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.2.4.tgz#8204373a6498776536a2fcc7e467d054c3b729d4" - integrity sha512-fX70bNj0fLEYO2Zcvuh7eh9wOUQ29GIx6r8IxIJlc0i0mpUH++9ax0BhfAYfzndADli3RAMROrZQ014J01owrg== +react-debounce-input@=3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.3.0.tgz#85e3ebcaa41f2016e50613134a1ec9fe3cdb422e" + integrity sha512-VEqkvs8JvY/IIZvh71Z0TC+mdbxERvYF33RcebnodlsUZ8RSgyKe2VWaHXv4+/8aoOgXLxWrdsYs2hDhcwbUgA== dependencies: lodash.debounce "^4" - prop-types "^15.7.2" + prop-types "^15.8.1" react-dev-utils@^12.0.0-next.60: version "12.0.1" @@ -24795,9 +24789,9 @@ subscriptions-transport-ws@^0.11.0: ws "^5.2.0 || ^6.0.0 || ^7.0.0" sucrase@^3.18.0, sucrase@^3.20.2: - version "3.24.0" - resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.24.0.tgz#66a8f2cc845bc441706ce5f3056de283289067b6" - integrity sha512-SevqflhW356TKEyWjFHg2e5f3eH+5rzmsMJxrVMDvZIEHh/goYrpzDGA6APEj4ME9MdGm8oNgIzi1eF3c3dDQA== + version "3.25.0" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.25.0.tgz#6dffa34e614b3347877507a4380cc4f022b7b7aa" + integrity sha512-WxTtwEYXSmZArPGStGBicyRsg5TBEFhT5b7N+tF+zauImP0Acy+CoUK0/byJ8JNPK/5lbpWIVuFagI4+0l85QQ== dependencies: commander "^4.0.0" glob "7.1.6" @@ -24823,7 +24817,7 @@ superagent@^8.0.0: readable-stream "^3.6.0" semver "^7.3.7" -supertest@^6.1.3, supertest@^6.1.6: +supertest@^6.1.3, supertest@^6.1.6, supertest@^6.2.4: version "6.2.4" resolved "https://registry.npmjs.org/supertest/-/supertest-6.2.4.tgz#3dcebe42f7fd6f28dd7ac74c6cba881f7101b2f0" integrity sha512-M8xVnCNv+q2T2WXVzxDECvL2695Uv2uUj2O0utxsld/HRyJvOU8W9f1gvsYxSNU4wmIe0/L/ItnpU4iKq0emDA== @@ -24903,17 +24897,17 @@ swagger-client@^3.18.5: url "~0.11.0" swagger-ui-react@^4.11.1: - version "4.13.0" - resolved "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-4.13.0.tgz#da4192b9b2a761a1e761c268606741ba200e971d" - integrity sha512-SNAByPvnpFKXUnrH6+V2TjVrbilftyVLWK+7K73tBX3uRNAYv0hzNs5Q6xPIekq4iq7xRtuUhVA7Qxn9vK4C+w== + version "4.13.2" + resolved "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-4.13.2.tgz#dee4f42dae9ca8b9ac85e64a46fc12c694100a80" + integrity sha512-U3IarPb0Vyi5/bHb45Q8uWf/7fowPp3B+LeYF0VKB4xhgKNiaPypPHoSJW9oCse/lkFGd4ZKyqBOpYXCsWMcgA== dependencies: - "@babel/runtime-corejs3" "^7.16.8" + "@babel/runtime-corejs3" "^7.18.9" "@braintree/sanitize-url" "=6.0.0" base64-js "^1.5.1" classnames "^2.3.1" css.escape "1.5.1" deep-extend "0.6.0" - dompurify "=2.3.3" + dompurify "=2.3.10" ieee754 "^1.2.1" immutable "^3.x.x" js-file-download "^0.4.12" @@ -24923,7 +24917,7 @@ swagger-ui-react@^4.11.1: randexp "^0.5.3" randombytes "^2.1.0" react-copy-to-clipboard "5.0.4" - react-debounce-input "=3.2.4" + react-debounce-input "=3.3.0" react-immutable-proptypes "2.2.0" react-immutable-pure-component "^2.2.0" react-inspector "^5.1.1" @@ -26678,7 +26672,7 @@ winston-transport@^4.5.0: readable-stream "^3.6.0" triple-beam "^1.3.0" -winston@^3.2.1, winston@^3.7.2: +winston@^3.2.1, winston@^3.7.2, winston@^3.8.1: version "3.8.1" resolved "https://registry.npmjs.org/winston/-/winston-3.8.1.tgz#76f15b3478cde170b780234e0c4cf805c5a7fb57" integrity sha512-r+6YAiCR4uI3N8eQNOg8k3P3PqwAm20cLKlzVD9E66Ch39+LZC+VH1UKf9JemQj2B3QoUHfKD7Poewn0Pr3Y1w== @@ -27113,9 +27107,9 @@ yeast@0.1.2: integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= yeoman-environment@^3.9.1: - version "3.9.1" - resolved "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-3.9.1.tgz#21912bdee4b1d302a5c25a7d31338fa092ea7116" - integrity sha512-IdRnbQt/DSOSnao0oD9c+or1X2UrL+fx9eC0O7Lq/MGZV68nhv9k77MqG+hEAySPSlyCpocVlhfQwV62hczk5Q== + version "3.10.0" + resolved "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-3.10.0.tgz#d8c56571b68d16b4af8abfb950f83acc503eed77" + integrity sha512-sYtSxBK9daq21QjoskJTHKLQ1xEsRPURkmFV/aM8HS8ZlQVzwx57Rz1zCs8EGPhK4vqsmTE8H92Gp1jg1fT3EA== dependencies: "@npmcli/arborist" "^4.0.4" are-we-there-yet "^2.0.0" @@ -27135,6 +27129,7 @@ yeoman-environment@^3.9.1: grouped-queue "^2.0.0" inquirer "^8.0.0" is-scoped "^2.1.0" + isbinaryfile "^4.0.10" lodash "^4.17.10" log-symbols "^4.0.0" mem-fs "^1.2.0 || ^2.0.0"