From 454d17c9902cc2e21dc46be8594cc4830e1e66fd Mon Sep 17 00:00:00 2001 From: secustor Date: Tue, 12 Dec 2023 11:45:57 +0100 Subject: [PATCH 001/241] refactor(backend-common/GithubUrlReader): only call fetch inside fetchResponse Signed-off-by: secustor --- .changeset/eight-rice-cross.md | 5 ++ .../src/reading/GithubUrlReader.ts | 55 ++++++++----------- 2 files changed, 28 insertions(+), 32 deletions(-) create mode 100644 .changeset/eight-rice-cross.md diff --git a/.changeset/eight-rice-cross.md b/.changeset/eight-rice-cross.md new file mode 100644 index 0000000000..e40f731a4e --- /dev/null +++ b/.changeset/eight-rice-cross.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Do not call fetch directly but rather use fetchResponse facility diff --git a/packages/backend-common/src/reading/GithubUrlReader.ts b/packages/backend-common/src/reading/GithubUrlReader.ts index 764431386d..175815cabf 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.ts @@ -107,7 +107,7 @@ export class GithubUrlReader implements UrlReader { let response: Response; try { - response = await fetch(ghUrl, { + response = await this.fetchResponse(ghUrl, { headers: { ...credentials?.headers, ...(options?.etag && { 'If-None-Match': options.etag }), @@ -125,38 +125,13 @@ export class GithubUrlReader implements UrlReader { signal: options?.signal as any, }); } catch (e) { - throw new Error(`Unable to read ${url}, ${e}`); + throw e; } - if (response.status === 304) { - throw new NotModifiedError(); - } - - if (response.ok) { - return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { - etag: response.headers.get('ETag') ?? undefined, - lastModifiedAt: parseLastModified( - response.headers.get('Last-Modified'), - ), - }); - } - - let message = `${url} could not be read as ${ghUrl}, ${response.status} ${response.statusText}`; - if (response.status === 404) { - throw new NotFoundError(message); - } - - // GitHub returns a 403 response with a couple of headers indicating rate - // limit status. See more in the GitHub docs: - // https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting - if ( - response.status === 403 && - response.headers.get('X-RateLimit-Remaining') === '0' - ) { - message += ' (rate limit exceeded)'; - } - - throw new Error(message); + return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { + etag: response.headers.get('ETag') ?? undefined, + lastModifiedAt: parseLastModified(response.headers.get('Last-Modified')), + }); } async readTree( @@ -350,10 +325,26 @@ export class GithubUrlReader implements UrlReader { const response = await fetch(urlAsString, init); if (!response.ok) { - const message = `Request failed for ${urlAsString}, ${response.status} ${response.statusText}`; + let message = `Request failed for ${urlAsString}, ${response.status} ${response.statusText}`; + + if (response.status === 304) { + throw new NotModifiedError(); + } + if (response.status === 404) { throw new NotFoundError(message); } + + // GitHub returns a 403 response with a couple of headers indicating rate + // limit status. See more in the GitHub docs: + // https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting + if ( + response.status === 403 && + response.headers.get('X-RateLimit-Remaining') === '0' + ) { + message += ' (rate limit exceeded)'; + } + throw new Error(message); } From 88fcc3b5e56d839b32492ddee45c40fc010514bf Mon Sep 17 00:00:00 2001 From: secustor Date: Tue, 12 Dec 2023 11:53:04 +0100 Subject: [PATCH 002/241] docs(backend-common/GithubUrlReader): put fetchResponse in code block Signed-off-by: secustor --- .changeset/eight-rice-cross.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eight-rice-cross.md b/.changeset/eight-rice-cross.md index e40f731a4e..1628276817 100644 --- a/.changeset/eight-rice-cross.md +++ b/.changeset/eight-rice-cross.md @@ -2,4 +2,4 @@ '@backstage/backend-common': patch --- -Do not call fetch directly but rather use fetchResponse facility +Do not call fetch directly but rather use `fetchResponse` facility From 42b4db71ded631e9a286c6b19c6fe16fc211f184 Mon Sep 17 00:00:00 2001 From: secustor Date: Tue, 12 Dec 2023 14:37:11 +0100 Subject: [PATCH 003/241] make fetchResponse protected to allow overwriting Signed-off-by: secustor --- packages/backend-common/src/reading/GithubUrlReader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-common/src/reading/GithubUrlReader.ts b/packages/backend-common/src/reading/GithubUrlReader.ts index 175815cabf..fed6fd9430 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.ts @@ -317,7 +317,7 @@ export class GithubUrlReader implements UrlReader { return repo.default_branch; } - private async fetchResponse( + protected async fetchResponse( url: string | URL, init: RequestInit, ): Promise { From f4d77420496ff7bb9092a56509bcd643208beac4 Mon Sep 17 00:00:00 2001 From: secustor Date: Thu, 14 Dec 2023 15:50:16 +0100 Subject: [PATCH 004/241] remove unnecessary try catch block Signed-off-by: secustor --- .../src/reading/GithubUrlReader.ts | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/packages/backend-common/src/reading/GithubUrlReader.ts b/packages/backend-common/src/reading/GithubUrlReader.ts index fed6fd9430..6fd24afc08 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.ts @@ -105,28 +105,23 @@ export class GithubUrlReader implements UrlReader { credentials, ); - let response: Response; - try { - response = await this.fetchResponse(ghUrl, { - headers: { - ...credentials?.headers, - ...(options?.etag && { 'If-None-Match': options.etag }), - ...(options?.lastModifiedAfter && { - 'If-Modified-Since': options.lastModifiedAfter.toUTCString(), - }), - Accept: 'application/vnd.github.v3.raw', - }, - // TODO(freben): The signal cast is there because pre-3.x versions of - // node-fetch have a very slightly deviating AbortSignal type signature. - // The difference does not affect us in practice however. The cast can - // be removed after we support ESM for CLI dependencies and migrate to - // version 3 of node-fetch. - // https://github.com/backstage/backstage/issues/8242 - signal: options?.signal as any, - }); - } catch (e) { - throw e; - } + const response = await this.fetchResponse(ghUrl, { + headers: { + ...credentials?.headers, + ...(options?.etag && { 'If-None-Match': options.etag }), + ...(options?.lastModifiedAfter && { + 'If-Modified-Since': options.lastModifiedAfter.toUTCString(), + }), + Accept: 'application/vnd.github.v3.raw', + }, + // TODO(freben): The signal cast is there because pre-3.x versions of + // node-fetch have a very slightly deviating AbortSignal type signature. + // The difference does not affect us in practice however. The cast can + // be removed after we support ESM for CLI dependencies and migrate to + // version 3 of node-fetch. + // https://github.com/backstage/backstage/issues/8242 + signal: options?.signal as any, + }); return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { etag: response.headers.get('ETag') ?? undefined, From 9c20b935bc0c778e906e1cbe932313fd47a9ef73 Mon Sep 17 00:00:00 2001 From: David Martin Date: Fri, 15 Dec 2023 12:08:58 +0000 Subject: [PATCH 005/241] Update configuration.md The wording for the default behaviour reads a little odd. I think this clears it up Signed-off-by: David Martin --- docs/features/kubernetes/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 494e51320a..4ca59f1a94 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -593,7 +593,7 @@ SingleTenant Cluster: In the example above, we configured the "backstage.io/kubernetes-cluster" annotation on the entity `catalog-info.yaml` file to specify that the current component is running in a single cluster called "dice-cluster", so this cluster must have been specified in the `app-config.yaml`, under the Kubernetes clusters configuration (for more details, see [`Configuring Kubernetes clusters`](#configuring-kubernetes-clusters)). -If you do not specify the annotation by `default Backstage fetches all` defined Kubernetes cluster. +If you do not specify the annotation, by default Backstage fetches from all defined Kubernetes clusters. [1]: https://cloud.google.com/kubernetes-engine [2]: https://cloud.google.com/docs/authentication/production#linux-or-macos From 60e4c2a86d0b67ca47c1c7d2e6d17da7fbb0a235 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 18 Dec 2023 07:48:43 +0100 Subject: [PATCH 006/241] feat: add callback transformers to GitlabOrgDiscoveryEntityProvider Signed-off-by: Markus --- .changeset/neat-hotels-wink.md | 5 + .../src/lib/defaultTransformers.ts | 125 +++++++++++++++ .../src/lib/types.ts | 39 +++++ .../GitlabOrgDiscoveryEntityProvider.ts | 142 ++++++------------ 4 files changed, 211 insertions(+), 100 deletions(-) create mode 100644 .changeset/neat-hotels-wink.md create mode 100644 plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts diff --git a/.changeset/neat-hotels-wink.md b/.changeset/neat-hotels-wink.md new file mode 100644 index 0000000000..a37d282578 --- /dev/null +++ b/.changeset/neat-hotels-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +add `groupTransformer`, `userTransformer` and `groupNameTransformer` to allow custom transformations when groups and users are created diff --git a/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts b/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts new file mode 100644 index 0000000000..6612086dab --- /dev/null +++ b/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts @@ -0,0 +1,125 @@ +/* + * Copyright 2023 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 { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { + GitLabGroup, + GitLabUser, + GitlabProviderConfig, + GroupNameTransformer, +} from './types'; +import { GitLabIntegrationConfig } from '@backstage/integration'; + +export function defaultGroupNameTransformer( + group: GitLabGroup, + config: GitlabProviderConfig, +): string { + if (config.group && group.full_path.startsWith(`${config.group}/`)) { + return group.full_path.replace(`${config.group}/`, '').replaceAll('/', '-'); + } + return group.full_path.replaceAll('/', '-'); +} + +export function defaultGroupTransformer( + group: GitLabGroup, + provConfig: GitlabProviderConfig, + groupNameTransformer: GroupNameTransformer, +): GroupEntity { + const annotations: { [annotationName: string]: string } = {}; + + annotations[`${provConfig.host}/team-path`] = group.full_path; + + const entity: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: groupNameTransformer(group, provConfig), + annotations: annotations, + }, + spec: { + type: 'team', + children: [], + profile: { + displayName: group.name, + }, + }, + }; + + if (group.description) { + entity.metadata.description = group.description; + } + + return entity; +} + +/** + * The default implementation of the transformation from a graph user entry to + * a User entity. + * + * @public + */ +export function defaultUserTransformer( + user: GitLabUser, + intConfig: GitLabIntegrationConfig, + provConfig: GitlabProviderConfig, + groupNameTransformer: GroupNameTransformer, +): UserEntity { + const annotations: { [annotationName: string]: string } = {}; + + annotations[`${intConfig.host}/user-login`] = user.web_url; + if (user?.group_saml_identity?.extern_uid) { + annotations[`${intConfig.host}/saml-external-uid`] = + user.group_saml_identity.extern_uid; + } + + const entity: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: user.username, + annotations: annotations, + }, + spec: { + profile: { + displayName: user.name || undefined, + picture: user.avatar_url || undefined, + }, + memberOf: [], + }, + }; + + if (user.email) { + if (!entity.spec) { + entity.spec = {}; + } + + if (!entity.spec.profile) { + entity.spec.profile = {}; + } + + entity.spec.profile.email = user.email; + } + + if (user.groups) { + for (const group of user.groups) { + if (!entity.spec.memberOf) { + entity.spec.memberOf = []; + } + entity.spec.memberOf.push(groupNameTransformer(group, provConfig)); + } + } + + return entity; +} diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index fa2eb73da6..1ecd186a59 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ import { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { GitLabIntegrationConfig } from '@backstage/integration'; export type PagedResponse = { items: T[]; @@ -116,6 +118,10 @@ export type GitLabDescendantGroupsResponse = { export type GitlabProviderConfig = { host: string; + /** + * Group and subgroup (if needed) to look for repositories. If not present the whole instance will be scanned. + * If present this if present, the discovered groups won't contain this prefix + */ group: string; id: string; /** @@ -136,3 +142,36 @@ export type GitlabProviderConfig = { schedule?: TaskScheduleDefinition; skipForkedRepos?: boolean; }; + +/** + * Customize how group names are generated + * + * @public + */ +export type GroupNameTransformer = ( + group: GitLabGroup, + config: GitlabProviderConfig, +) => string; + +/** + * Customize the ingested User entity + * + * @public + */ +export type UserTransformer = ( + user: GitLabUser, + intConfig: GitLabIntegrationConfig, + provConfig: GitlabProviderConfig, + groupNameTransformer: GroupNameTransformer, +) => UserEntity; + +/** + * Customize the ingested Group entity + * + * @public + */ +export type GroupTransformer = ( + group: GitLabGroup, + provConfig: GitlabProviderConfig, + groupNameTransformer: GroupNameTransformer, +) => GroupEntity; diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index affa8a41cf..16b1c326f3 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -19,7 +19,6 @@ import { ANNOTATION_ORIGIN_LOCATION, Entity, GroupEntity, - UserEntity, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { GitLabIntegration, ScmIntegrations } from '@backstage/integration'; @@ -37,7 +36,19 @@ import { paginated, readGitlabConfigs, } from '../lib'; -import { GitLabGroup, GitLabUser, PagedResponse } from '../lib/types'; +import { + GitLabGroup, + GitLabUser, + PagedResponse, + UserTransformer, + GroupTransformer, + GroupNameTransformer, +} from '../lib/types'; +import { + defaultGroupNameTransformer, + defaultGroupTransformer, + defaultUserTransformer, +} from '../lib/defaultTransformers'; type Result = { scanned: number; @@ -59,6 +70,9 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { private readonly logger: Logger; private readonly scheduleFn: () => Promise; private connection?: EntityProviderConnection; + private userTransformer: UserTransformer; + private groupTransformer: GroupTransformer; + private groupNameTransformer: GroupNameTransformer; static fromConfig( config: Config, @@ -66,6 +80,9 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { logger: Logger; schedule?: TaskRunner; scheduler?: PluginTaskScheduler; + userTransformer?: UserTransformer; + groupTransformer?: GroupTransformer; + groupNameTransformer?: GroupNameTransformer; }, ): GitlabOrgDiscoveryEntityProvider[] { if (!options.schedule && !options.scheduler) { @@ -122,6 +139,9 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { integration: GitLabIntegration; logger: Logger; taskRunner: TaskRunner; + userTransformer?: UserTransformer; + groupTransformer?: GroupTransformer; + groupNameTransformer?: GroupNameTransformer; }) { this.config = options.config; this.integration = options.integration; @@ -129,6 +149,10 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { target: this.getProviderName(), }); this.scheduleFn = this.createScheduleFn(options.taskRunner); + this.userTransformer = options.userTransformer ?? defaultUserTransformer; + this.groupTransformer = options.groupTransformer ?? defaultGroupTransformer; + this.groupNameTransformer = + options.groupNameTransformer ?? defaultGroupNameTransformer; } getProviderName(): string { @@ -271,12 +295,14 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }); const userEntities = res.matches.map(p => - this.createUserEntity(p, this.integration.config.host), - ); - const groupEntities = this.createGroupEntities( - groupsWithUsers, - this.integration.config.host, + this.userTransformer( + p, + this.integration.config, + this.config, + this.groupNameTransformer, + ), ); + const groupEntities = this.createGroupEntities(groupsWithUsers); await this.connection.applyMutation({ type: 'full', @@ -291,10 +317,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }); } - private createGroupEntities( - groupResult: GitLabGroup[], - host: string, - ): GroupEntity[] { + private createGroupEntities(groupResult: GitLabGroup[]): GroupEntity[] { const idMapped: { [groupId: number]: GitLabGroup } = {}; const entities: GroupEntity[] = []; @@ -303,11 +326,16 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { } for (const group of groupResult) { - const entity = this.createGroupEntity(group, host); + const entity = this.groupTransformer( + group, + this.config, + this.groupNameTransformer, + ); if (group.parent_id && idMapped.hasOwnProperty(group.parent_id)) { - entity.spec.parent = this.groupName( - idMapped[group.parent_id].full_path, + entity.spec.parent = this.groupNameTransformer( + idMapped[group.parent_id], + this.config, ); } @@ -334,90 +362,4 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { entity, ) as Entity; } - - private createUserEntity(user: GitLabUser, host: string): UserEntity { - const annotations: { [annotationName: string]: string } = {}; - - annotations[`${host}/user-login`] = user.web_url; - if (user?.group_saml_identity?.extern_uid) { - annotations[`${host}/saml-external-uid`] = - user.group_saml_identity.extern_uid; - } - - const entity: UserEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'User', - metadata: { - name: user.username, - annotations: annotations, - }, - spec: { - profile: { - displayName: user.name || undefined, - picture: user.avatar_url || undefined, - }, - memberOf: [], - }, - }; - - if (user.email) { - if (!entity.spec) { - entity.spec = {}; - } - - if (!entity.spec.profile) { - entity.spec.profile = {}; - } - - entity.spec.profile.email = user.email; - } - - if (user.groups) { - for (const group of user.groups) { - if (!entity.spec.memberOf) { - entity.spec.memberOf = []; - } - entity.spec.memberOf.push(this.groupName(group.full_path)); - } - } - - return entity; - } - - private groupName(full_path: string): string { - if (this.config.group && full_path.startsWith(`${this.config.group}/`)) { - return full_path - .replace(`${this.config.group}/`, '') - .replaceAll('/', '-'); - } - return full_path.replaceAll('/', '-'); - } - - private createGroupEntity(group: GitLabGroup, host: string): GroupEntity { - const annotations: { [annotationName: string]: string } = {}; - - annotations[`${host}/team-path`] = group.full_path; - - const entity: GroupEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: this.groupName(group.full_path), - annotations: annotations, - }, - spec: { - type: 'team', - children: [], - profile: { - displayName: group.name, - }, - }, - }; - - if (group.description) { - entity.metadata.description = group.description; - } - - return entity; - } } From 1228c1d584366f4cb9f59a8bd581f6881d2f7e47 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 18 Dec 2023 17:45:33 +0100 Subject: [PATCH 007/241] chore: rename variables Signed-off-by: Markus --- .../src/lib/defaultTransformers.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts b/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts index 6612086dab..1fbe60ebe7 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts @@ -34,18 +34,18 @@ export function defaultGroupNameTransformer( export function defaultGroupTransformer( group: GitLabGroup, - provConfig: GitlabProviderConfig, + providerConfig: GitlabProviderConfig, groupNameTransformer: GroupNameTransformer, ): GroupEntity { const annotations: { [annotationName: string]: string } = {}; - annotations[`${provConfig.host}/team-path`] = group.full_path; + annotations[`${providerConfig.host}/team-path`] = group.full_path; const entity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Group', metadata: { - name: groupNameTransformer(group, provConfig), + name: groupNameTransformer(group, providerConfig), annotations: annotations, }, spec: { @@ -72,15 +72,15 @@ export function defaultGroupTransformer( */ export function defaultUserTransformer( user: GitLabUser, - intConfig: GitLabIntegrationConfig, - provConfig: GitlabProviderConfig, + integrationConfig: GitLabIntegrationConfig, + providerConfig: GitlabProviderConfig, groupNameTransformer: GroupNameTransformer, ): UserEntity { const annotations: { [annotationName: string]: string } = {}; - annotations[`${intConfig.host}/user-login`] = user.web_url; + annotations[`${integrationConfig.host}/user-login`] = user.web_url; if (user?.group_saml_identity?.extern_uid) { - annotations[`${intConfig.host}/saml-external-uid`] = + annotations[`${integrationConfig.host}/saml-external-uid`] = user.group_saml_identity.extern_uid; } @@ -117,7 +117,7 @@ export function defaultUserTransformer( if (!entity.spec.memberOf) { entity.spec.memberOf = []; } - entity.spec.memberOf.push(groupNameTransformer(group, provConfig)); + entity.spec.memberOf.push(groupNameTransformer(group, providerConfig)); } } From 198ef79ee4123fd297f534f673f00e951fd30ab8 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 18 Dec 2023 18:27:30 +0100 Subject: [PATCH 008/241] chore: refactor function inputs Signed-off-by: Markus --- .../src/lib/defaultTransformers.ts | 129 +++++++++++------- .../src/lib/types.ts | 31 +++-- .../GitlabOrgDiscoveryEntityProvider.ts | 61 +++------ 3 files changed, 115 insertions(+), 106 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts b/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts index 1fbe60ebe7..d7a6bf76e9 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/defaultTransformers.ts @@ -16,52 +16,74 @@ import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { GitLabGroup, - GitLabUser, - GitlabProviderConfig, - GroupNameTransformer, + GroupNameTransformerOptions, + GroupTransformerOptions, + UserTransformerOptions, } from './types'; -import { GitLabIntegrationConfig } from '@backstage/integration'; export function defaultGroupNameTransformer( - group: GitLabGroup, - config: GitlabProviderConfig, + options: GroupNameTransformerOptions, ): string { - if (config.group && group.full_path.startsWith(`${config.group}/`)) { - return group.full_path.replace(`${config.group}/`, '').replaceAll('/', '-'); + if ( + options.providerConfig.group && + options.group.full_path.startsWith(`${options.providerConfig.group}/`) + ) { + return options.group.full_path + .replace(`${options.providerConfig.group}/`, '') + .replaceAll('/', '-'); } - return group.full_path.replaceAll('/', '-'); + return options.group.full_path.replaceAll('/', '-'); } -export function defaultGroupTransformer( - group: GitLabGroup, - providerConfig: GitlabProviderConfig, - groupNameTransformer: GroupNameTransformer, -): GroupEntity { - const annotations: { [annotationName: string]: string } = {}; +export function defaultGroupEntitiesTransformer( + options: GroupTransformerOptions, +): GroupEntity[] { + const idMapped: { [groupId: number]: GitLabGroup } = {}; + const entities: GroupEntity[] = []; - annotations[`${providerConfig.host}/team-path`] = group.full_path; - - const entity: GroupEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: groupNameTransformer(group, providerConfig), - annotations: annotations, - }, - spec: { - type: 'team', - children: [], - profile: { - displayName: group.name, - }, - }, - }; - - if (group.description) { - entity.metadata.description = group.description; + for (const group of options.groups) { + idMapped[group.id] = group; } - return entity; + for (const group of options.groups) { + const annotations: { [annotationName: string]: string } = {}; + + annotations[`${options.providerConfig.host}/team-path`] = group.full_path; + + const entity: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: options.groupNameTransformer({ + group, + providerConfig: options.providerConfig, + }), + annotations: annotations, + }, + spec: { + type: 'team', + children: [], + profile: { + displayName: group.name, + }, + }, + }; + + if (group.description) { + entity.metadata.description = group.description; + } + + if (group.parent_id && idMapped.hasOwnProperty(group.parent_id)) { + entity.spec.parent = options.groupNameTransformer({ + group: idMapped[group.parent_id], + providerConfig: options.providerConfig, + }); + } + + entities.push(entity); + } + + return entities; } /** @@ -71,36 +93,34 @@ export function defaultGroupTransformer( * @public */ export function defaultUserTransformer( - user: GitLabUser, - integrationConfig: GitLabIntegrationConfig, - providerConfig: GitlabProviderConfig, - groupNameTransformer: GroupNameTransformer, + options: UserTransformerOptions, ): UserEntity { const annotations: { [annotationName: string]: string } = {}; - annotations[`${integrationConfig.host}/user-login`] = user.web_url; - if (user?.group_saml_identity?.extern_uid) { - annotations[`${integrationConfig.host}/saml-external-uid`] = - user.group_saml_identity.extern_uid; + annotations[`${options.integrationConfig.host}/user-login`] = + options.user.web_url; + if (options.user?.group_saml_identity?.extern_uid) { + annotations[`${options.integrationConfig.host}/saml-external-uid`] = + options.user.group_saml_identity.extern_uid; } const entity: UserEntity = { apiVersion: 'backstage.io/v1alpha1', kind: 'User', metadata: { - name: user.username, + name: options.user.username, annotations: annotations, }, spec: { profile: { - displayName: user.name || undefined, - picture: user.avatar_url || undefined, + displayName: options.user.name || undefined, + picture: options.user.avatar_url || undefined, }, memberOf: [], }, }; - if (user.email) { + if (options.user.email) { if (!entity.spec) { entity.spec = {}; } @@ -109,15 +129,20 @@ export function defaultUserTransformer( entity.spec.profile = {}; } - entity.spec.profile.email = user.email; + entity.spec.profile.email = options.user.email; } - if (user.groups) { - for (const group of user.groups) { + if (options.user.groups) { + for (const group of options.user.groups) { if (!entity.spec.memberOf) { entity.spec.memberOf = []; } - entity.spec.memberOf.push(groupNameTransformer(group, providerConfig)); + entity.spec.memberOf.push( + options.groupNameTransformer({ + group, + providerConfig: options.providerConfig, + }), + ); } } diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index 1ecd186a59..4a15d44d04 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -149,21 +149,25 @@ export type GitlabProviderConfig = { * @public */ export type GroupNameTransformer = ( - group: GitLabGroup, - config: GitlabProviderConfig, + options: GroupNameTransformerOptions, ) => string; +export interface GroupNameTransformerOptions { + group: GitLabGroup; + providerConfig: GitlabProviderConfig; +} /** * Customize the ingested User entity * * @public */ -export type UserTransformer = ( - user: GitLabUser, - intConfig: GitLabIntegrationConfig, - provConfig: GitlabProviderConfig, - groupNameTransformer: GroupNameTransformer, -) => UserEntity; +export type UserTransformer = (options: UserTransformerOptions) => UserEntity; +export interface UserTransformerOptions { + user: GitLabUser; + integrationConfig: GitLabIntegrationConfig; + providerConfig: GitlabProviderConfig; + groupNameTransformer: GroupNameTransformer; +} /** * Customize the ingested Group entity @@ -171,7 +175,10 @@ export type UserTransformer = ( * @public */ export type GroupTransformer = ( - group: GitLabGroup, - provConfig: GitlabProviderConfig, - groupNameTransformer: GroupNameTransformer, -) => GroupEntity; + options: GroupTransformerOptions, +) => GroupEntity[]; +export interface GroupTransformerOptions { + groups: GitLabGroup[]; + providerConfig: GitlabProviderConfig; + groupNameTransformer: GroupNameTransformer; +} diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index 16b1c326f3..1157a2f1f3 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -18,7 +18,6 @@ import { ANNOTATION_LOCATION, ANNOTATION_ORIGIN_LOCATION, Entity, - GroupEntity, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { GitLabIntegration, ScmIntegrations } from '@backstage/integration'; @@ -41,12 +40,12 @@ import { GitLabUser, PagedResponse, UserTransformer, - GroupTransformer, + GroupTransformer as GroupEntitiesTransformer, GroupNameTransformer, } from '../lib/types'; import { defaultGroupNameTransformer, - defaultGroupTransformer, + defaultGroupEntitiesTransformer, defaultUserTransformer, } from '../lib/defaultTransformers'; @@ -71,7 +70,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { private readonly scheduleFn: () => Promise; private connection?: EntityProviderConnection; private userTransformer: UserTransformer; - private groupTransformer: GroupTransformer; + private groupEntitiesTransformer: GroupEntitiesTransformer; private groupNameTransformer: GroupNameTransformer; static fromConfig( @@ -81,7 +80,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { schedule?: TaskRunner; scheduler?: PluginTaskScheduler; userTransformer?: UserTransformer; - groupTransformer?: GroupTransformer; + groupEntitiesTransformer?: GroupEntitiesTransformer; groupNameTransformer?: GroupNameTransformer; }, ): GitlabOrgDiscoveryEntityProvider[] { @@ -140,7 +139,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { logger: Logger; taskRunner: TaskRunner; userTransformer?: UserTransformer; - groupTransformer?: GroupTransformer; + groupEntitiesTransformer?: GroupEntitiesTransformer; groupNameTransformer?: GroupNameTransformer; }) { this.config = options.config; @@ -150,7 +149,8 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }); this.scheduleFn = this.createScheduleFn(options.taskRunner); this.userTransformer = options.userTransformer ?? defaultUserTransformer; - this.groupTransformer = options.groupTransformer ?? defaultGroupTransformer; + this.groupEntitiesTransformer = + options.groupEntitiesTransformer ?? defaultGroupEntitiesTransformer; this.groupNameTransformer = options.groupNameTransformer ?? defaultGroupNameTransformer; } @@ -295,14 +295,19 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }); const userEntities = res.matches.map(p => - this.userTransformer( - p, - this.integration.config, - this.config, - this.groupNameTransformer, - ), + this.userTransformer({ + user: p, + integrationConfig: this.integration.config, + providerConfig: this.config, + groupNameTransformer: this.groupNameTransformer, + }), ); - const groupEntities = this.createGroupEntities(groupsWithUsers); + + const groupEntities = this.groupEntitiesTransformer({ + groups: groupsWithUsers, + providerConfig: this.config, + groupNameTransformer: this.groupNameTransformer, + }); await this.connection.applyMutation({ type: 'full', @@ -317,34 +322,6 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { }); } - private createGroupEntities(groupResult: GitLabGroup[]): GroupEntity[] { - const idMapped: { [groupId: number]: GitLabGroup } = {}; - const entities: GroupEntity[] = []; - - for (const group of groupResult) { - idMapped[group.id] = group; - } - - for (const group of groupResult) { - const entity = this.groupTransformer( - group, - this.config, - this.groupNameTransformer, - ); - - if (group.parent_id && idMapped.hasOwnProperty(group.parent_id)) { - entity.spec.parent = this.groupNameTransformer( - idMapped[group.parent_id], - this.config, - ); - } - - entities.push(entity); - } - - return entities; - } - private withLocations(host: string, baseUrl: string, entity: Entity): Entity { const location = entity.kind === 'Group' From 08e2eb67b2270a9d2b9be5c7ec541bc0b9de26a6 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 18 Dec 2023 18:30:57 +0100 Subject: [PATCH 009/241] chore: update api report Signed-off-by: Markus --- plugins/catalog-backend-module-gitlab/api-report.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/catalog-backend-module-gitlab/api-report.md b/plugins/catalog-backend-module-gitlab/api-report.md index 6620f6445f..eeab252b59 100644 --- a/plugins/catalog-backend-module-gitlab/api-report.md +++ b/plugins/catalog-backend-module-gitlab/api-report.md @@ -8,10 +8,14 @@ import { CatalogProcessorEmit } from '@backstage/plugin-catalog-node'; import { Config } from '@backstage/config'; import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; +import { GitLabIntegrationConfig } from '@backstage/integration'; +import { GroupEntity } from '@backstage/catalog-model'; import { LocationSpec } from '@backstage/plugin-catalog-node'; import { Logger } from 'winston'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { TaskRunner } from '@backstage/backend-tasks'; +import { TaskScheduleDefinition } from '@backstage/backend-tasks'; +import { UserEntity } from '@backstage/catalog-model'; // @public export class GitlabDiscoveryEntityProvider implements EntityProvider { @@ -64,9 +68,18 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { logger: Logger; schedule?: TaskRunner; scheduler?: PluginTaskScheduler; + userTransformer?: UserTransformer; + groupEntitiesTransformer?: GroupTransformer; + groupNameTransformer?: GroupNameTransformer; }, ): GitlabOrgDiscoveryEntityProvider[]; // (undocumented) getProviderName(): string; } + +// Warnings were encountered during analysis: +// +// src/providers/GitlabOrgDiscoveryEntityProvider.d.ts:23:9 - (ae-forgotten-export) The symbol "UserTransformer" needs to be exported by the entry point index.d.ts +// src/providers/GitlabOrgDiscoveryEntityProvider.d.ts:24:9 - (ae-forgotten-export) The symbol "GroupTransformer" needs to be exported by the entry point index.d.ts +// src/providers/GitlabOrgDiscoveryEntityProvider.d.ts:25:9 - (ae-forgotten-export) The symbol "GroupNameTransformer" needs to be exported by the entry point index.d.ts ``` From 926abed8507cae629560b5503ed232bfc7840342 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 18 Dec 2023 22:06:51 +0100 Subject: [PATCH 010/241] chore: api report Signed-off-by: Markus --- .../api-report.md | 90 +++++++++++++++++-- .../src/index.ts | 12 +++ .../src/lib/index.ts | 9 ++ .../src/lib/types.ts | 64 ++++++++++++- 4 files changed, 167 insertions(+), 8 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/api-report.md b/plugins/catalog-backend-module-gitlab/api-report.md index eeab252b59..bb52d8908a 100644 --- a/plugins/catalog-backend-module-gitlab/api-report.md +++ b/plugins/catalog-backend-module-gitlab/api-report.md @@ -57,6 +57,20 @@ export class GitLabDiscoveryProcessor implements CatalogProcessor { ): Promise; } +// @public +export type GitLabGroup = { + id: number; + name: string; + full_path: string; + description?: string; + parent_id?: number; +}; + +// @public (undocumented) +export type GitLabGroupSamlIdentity = { + extern_uid: string; +}; + // @public export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { // (undocumented) @@ -77,9 +91,75 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { getProviderName(): string; } -// Warnings were encountered during analysis: -// -// src/providers/GitlabOrgDiscoveryEntityProvider.d.ts:23:9 - (ae-forgotten-export) The symbol "UserTransformer" needs to be exported by the entry point index.d.ts -// src/providers/GitlabOrgDiscoveryEntityProvider.d.ts:24:9 - (ae-forgotten-export) The symbol "GroupTransformer" needs to be exported by the entry point index.d.ts -// src/providers/GitlabOrgDiscoveryEntityProvider.d.ts:25:9 - (ae-forgotten-export) The symbol "GroupNameTransformer" needs to be exported by the entry point index.d.ts +// @public +export type GitlabProviderConfig = { + host: string; + group: string; + id: string; + branch?: string; + fallbackBranch: string; + catalogFile: string; + projectPattern: RegExp; + userPattern: RegExp; + groupPattern: RegExp; + orgEnabled?: boolean; + schedule?: TaskScheduleDefinition; + skipForkedRepos?: boolean; +}; + +// @public +export type GitLabUser = { + id: number; + username: string; + email?: string; + name: string; + state: string; + web_url: string; + avatar_url: string; + groups?: GitLabGroup[]; + group_saml_identity?: GitLabGroupSamlIdentity; +}; + +// @public +export type GroupNameTransformer = ( + options: GroupNameTransformerOptions, +) => string; + +// @public +export interface GroupNameTransformerOptions { + // (undocumented) + group: GitLabGroup; + // (undocumented) + providerConfig: GitlabProviderConfig; +} + +// @public +export type GroupTransformer = ( + options: GroupTransformerOptions, +) => GroupEntity[]; + +// @public +export interface GroupTransformerOptions { + // (undocumented) + groupNameTransformer: GroupNameTransformer; + // (undocumented) + groups: GitLabGroup[]; + // (undocumented) + providerConfig: GitlabProviderConfig; +} + +// @public +export type UserTransformer = (options: UserTransformerOptions) => UserEntity; + +// @public +export interface UserTransformerOptions { + // (undocumented) + groupNameTransformer: GroupNameTransformer; + // (undocumented) + integrationConfig: GitLabIntegrationConfig; + // (undocumented) + providerConfig: GitlabProviderConfig; + // (undocumented) + user: GitLabUser; +} ``` diff --git a/plugins/catalog-backend-module-gitlab/src/index.ts b/plugins/catalog-backend-module-gitlab/src/index.ts index 2dd19c041d..cedcb828d6 100644 --- a/plugins/catalog-backend-module-gitlab/src/index.ts +++ b/plugins/catalog-backend-module-gitlab/src/index.ts @@ -25,3 +25,15 @@ export { GitlabDiscoveryEntityProvider, GitlabOrgDiscoveryEntityProvider, } from './providers'; +export type { + GitLabUser, + GitLabGroup, + GitlabProviderConfig, + GitLabGroupSamlIdentity, + GroupNameTransformer, + GroupNameTransformerOptions, + GroupTransformer, + GroupTransformerOptions, + UserTransformer, + UserTransformerOptions, +} from './lib'; diff --git a/plugins/catalog-backend-module-gitlab/src/lib/index.ts b/plugins/catalog-backend-module-gitlab/src/lib/index.ts index 53fad07994..1eee268862 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/index.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/index.ts @@ -16,8 +16,17 @@ export { GitLabClient, paginated } from './client'; export type { + GitLabUser, + GitLabGroup, + GitLabGroupSamlIdentity, GitLabProject, GitlabProviderConfig, GitlabGroupDescription, + GroupNameTransformer, + GroupNameTransformerOptions, + GroupTransformer, + GroupTransformerOptions, + UserTransformer, + UserTransformerOptions, } from './types'; export { readGitlabConfigs } from '../providers/config'; diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index 4a15d44d04..25c9a4a232 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -42,6 +42,11 @@ export type GitLabProject = { forked_from_project?: GitlabProjectForkedFrom; }; +/** + * Representation of a GitLab user in the GitLab API + * + * @public + */ export type GitLabUser = { id: number; username: string; @@ -54,10 +59,18 @@ export type GitLabUser = { group_saml_identity?: GitLabGroupSamlIdentity; }; +/** + * @public + */ export type GitLabGroupSamlIdentity = { extern_uid: string; }; +/** + * Representation of a GitLab group in the GitLab API + * + * @public + */ export type GitLabGroup = { id: number; name: string; @@ -115,14 +128,25 @@ export type GitLabDescendantGroupsResponse = { }; }; }; - +/** + * The configuration parameters for the GitlabProvider + * + * @public + */ export type GitlabProviderConfig = { + /** + * Identifies one of the hosts set up in the integrations + */ host: string; /** - * Group and subgroup (if needed) to look for repositories. If not present the whole instance will be scanned. - * If present this if present, the discovered groups won't contain this prefix + * Required for gitlab.com when `orgEnabled: true`. + * Optional for self managed. Must not end with slash. + * Accepts only groups under the provided path (which will be stripped) */ group: string; + /** + * ??? + */ id: string; /** * The name of the branch to be used, to discover catalog files. @@ -134,12 +158,31 @@ export type GitlabProviderConfig = { * Defaults to: `master` */ fallbackBranch: string; + /** + * Defaults to `catalog-info.yaml` + */ catalogFile: string; + /** + * Filters found projects based on provided patter. + * Defaults to `[\s\S]*`, which means to not filter anything + */ projectPattern: RegExp; + /** + * Filters found users based on provided patter. + * Defaults to `[\s\S]*`, which means to not filter anything + */ userPattern: RegExp; + /** + * Filters found groups based on provided patter. + * Defaults to `[\s\S]*`, which means to not filter anything + */ groupPattern: RegExp; + orgEnabled?: boolean; schedule?: TaskScheduleDefinition; + /** + * If the project is a fork, skip repository + */ skipForkedRepos?: boolean; }; @@ -152,6 +195,11 @@ export type GroupNameTransformer = ( options: GroupNameTransformerOptions, ) => string; +/** + * The GroupTransformerOptions + * + * @public + */ export interface GroupNameTransformerOptions { group: GitLabGroup; providerConfig: GitlabProviderConfig; @@ -162,6 +210,11 @@ export interface GroupNameTransformerOptions { * @public */ export type UserTransformer = (options: UserTransformerOptions) => UserEntity; +/** + * The UserTransformerOptions + * + * @public + */ export interface UserTransformerOptions { user: GitLabUser; integrationConfig: GitLabIntegrationConfig; @@ -177,6 +230,11 @@ export interface UserTransformerOptions { export type GroupTransformer = ( options: GroupTransformerOptions, ) => GroupEntity[]; +/** + * The GroupTransformer options + * + * @public + */ export interface GroupTransformerOptions { groups: GitLabGroup[]; providerConfig: GitlabProviderConfig; From 36d598bf98ff2389fac3b100d3880c8646b942ad Mon Sep 17 00:00:00 2001 From: Adam Vollrath Date: Tue, 19 Dec 2023 01:18:55 -0600 Subject: [PATCH 011/241] Sanitize input between PR deployment workflows. Signed-off-by: Adam Vollrath --- .github/workflows/uffizzi-preview.yaml | 28 +++++++++----------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml index a9cce41fce..79f735c352 100644 --- a/.github/workflows/uffizzi-preview.yaml +++ b/.github/workflows/uffizzi-preview.yaml @@ -48,47 +48,37 @@ jobs: let fs = require('fs'); fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/preview-spec.zip`, Buffer.from(download.data)); - - name: 'Unzip artifact' - run: unzip preview-spec.zip + - name: 'Accept event from first stage' + run: unzip preview-spec.zip event.json - name: Read Event into ENV run: | - echo 'EVENT_JSON<> $GITHUB_ENV - cat event.json >> $GITHUB_ENV - echo -e '\nEOF' >> $GITHUB_ENV + echo PR_NUMBER=$(jq '.number | tonumber' < event.json) >> $GITHUB_ENV + echo ACTION=$(jq --raw-output '.action | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_ENV + echo GIT_REF=$(jq --raw-output '.pull_request.head.sha | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_ENV - name: Hash Rendered Manifests File id: hash # If the previous workflow was triggered by a PR close event, we will not have a manifests file artifact. - if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} + if: ${{ env.ACTION != 'closed' }} run: | + unzip preview-spec.zip manifests.rendered.yml ls echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_ENV - name: Cache Manifests File - if: ${{ fromJSON(env.EVENT_JSON).action != 'closed' }} + if: ${{ env.ACTION != 'closed' }} uses: actions/cache@v3.3.2 with: path: manifests.rendered.yml key: ${{ env.MANIFESTS_FILE_HASH }} - - name: Read PR Number From Event Object - id: pr - run: echo "PR_NUMBER=${{ fromJSON(env.EVENT_JSON).number }}" >> $GITHUB_ENV - - - name: Read Event Type from Event Object - id: action - run: echo "ACTION=${{ fromJSON(env.EVENT_JSON).action }}" >> $GITHUB_ENV - - - name: Read Git Ref From Event Object - id: ref - run: echo "GIT_REF=${{ fromJSON(env.EVENT_JSON).pull_request.head.sha }}" >> $GITHUB_ENV - - name: DEBUG - Print Job Outputs if: ${{ runner.debug }} run: | echo "PR number: ${{ env.PR_NUMBER }}" echo "Git Ref: ${{ env.GIT_REF }}" + echo "Action: ${{ env.ACTION }}" echo "Manifests file hash: ${{ env.MANIFESTS_FILE_HASH }}" cat event.json From 08faa6ed060da7ca940b9f0534bc2fc6d853b672 Mon Sep 17 00:00:00 2001 From: Adam Vollrath Date: Tue, 19 Dec 2023 12:27:49 -0600 Subject: [PATCH 012/241] Update to store user input in a safer place. Signed-off-by: Adam Vollrath --- .github/workflows/uffizzi-preview.yaml | 32 +++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml index 79f735c352..cd1f6f939c 100644 --- a/.github/workflows/uffizzi-preview.yaml +++ b/.github/workflows/uffizzi-preview.yaml @@ -13,10 +13,10 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} outputs: - manifests-cache-key: ${{ env.MANIFESTS_FILE_HASH }} - git-ref: ${{ env.GIT_REF }} - pr-number: ${{ env.PR_NUMBER }} - action: ${{ env.ACTION }} + manifests-cache-key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} + git-ref: ${{ steps.event.outputs.GIT_REF }} + pr-number: ${{ steps.event.outputs.PR_NUMBER }} + action: ${{ steps.event.outputs.ACTION }} steps: - name: Harden Runner uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 @@ -52,34 +52,35 @@ jobs: run: unzip preview-spec.zip event.json - name: Read Event into ENV + id: event run: | - echo PR_NUMBER=$(jq '.number | tonumber' < event.json) >> $GITHUB_ENV - echo ACTION=$(jq --raw-output '.action | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_ENV - echo GIT_REF=$(jq --raw-output '.pull_request.head.sha | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_ENV + echo PR_NUMBER=$(jq '.number | tonumber' < event.json) >> $GITHUB_OUTPUT + echo ACTION=$(jq --raw-output '.action | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT + echo GIT_REF=$(jq --raw-output '.pull_request.head.sha | tostring | [scan("\\w+")][0]' < event.json) >> $GITHUB_OUTPUT - name: Hash Rendered Manifests File id: hash # If the previous workflow was triggered by a PR close event, we will not have a manifests file artifact. - if: ${{ env.ACTION != 'closed' }} + if: ${{ steps.event.outputs.ACTION != 'closed' }} run: | unzip preview-spec.zip manifests.rendered.yml ls - echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_ENV + echo "MANIFESTS_FILE_HASH=$(md5sum manifests.rendered.yml | awk '{ print $1 }')" >> $GITHUB_OUTPUT - name: Cache Manifests File - if: ${{ env.ACTION != 'closed' }} + if: ${{ steps.event.outputs.ACTION != 'closed' }} uses: actions/cache@v3.3.2 with: path: manifests.rendered.yml - key: ${{ env.MANIFESTS_FILE_HASH }} + key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} - name: DEBUG - Print Job Outputs if: ${{ runner.debug }} run: | - echo "PR number: ${{ env.PR_NUMBER }}" - echo "Git Ref: ${{ env.GIT_REF }}" - echo "Action: ${{ env.ACTION }}" - echo "Manifests file hash: ${{ env.MANIFESTS_FILE_HASH }}" + echo "PR number: ${{ steps.event.outputs.PR_NUMBER }}" + echo "Git Ref: ${{ steps.event.outputs.GIT_REF }}" + echo "Action: ${{ steps.event.outputs.ACTION }}" + echo "Manifests file hash: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }}" cat event.json deploy-uffizzi-preview: @@ -132,7 +133,6 @@ jobs: - name: Fetch cached Manifests File id: cache - # if: ${{ contains(fromJSON('["create", "update"]'), env.UFFIZZI_ACTION) }} uses: actions/cache@v3 with: path: manifests.rendered.yml From 1f70e46680b82ea9ae0c2a68788fbe33127bab7d Mon Sep 17 00:00:00 2001 From: Samuel Stadler Date: Wed, 22 Nov 2023 18:51:32 +0100 Subject: [PATCH 013/241] improves EntityValidationPage UX Signed-off-by: Samuel Stadler --- .changeset/metal-students-drive.md | 5 + .../EntityValidationPage.test.tsx | 91 +++++++++++++++++++ .../EntityValidationPage.tsx | 81 +++++++++++------ 3 files changed, 148 insertions(+), 29 deletions(-) create mode 100644 .changeset/metal-students-drive.md create mode 100644 plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.test.tsx diff --git a/.changeset/metal-students-drive.md b/.changeset/metal-students-drive.md new file mode 100644 index 0000000000..5ba8f4ee3d --- /dev/null +++ b/.changeset/metal-students-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-entity-validation': minor +--- + +Improves UX of the EntityValidationPage: Moves the validate button below the EntityTextArea which is actually validated, the location TextField can now be hidden to prevent confusion about what is validated and additional content can be added to the top of the validation page. diff --git a/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.test.tsx b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.test.tsx new file mode 100644 index 0000000000..c8827ffc13 --- /dev/null +++ b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.test.tsx @@ -0,0 +1,91 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { TestApiProvider, renderInTestApp } from '@backstage/test-utils'; +import { EntityValidationPage } from './EntityValidationPage'; +import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { MarkdownContent } from '@backstage/core-components'; + +describe('EntityValidatorPage', () => { + const catalogApi: Partial = { + getEntities: () => + Promise.resolve({ + items: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'Entity1', + annotations: { + 'backstage.io/view-url': 'viewurl', + 'backstage.io/edit-url': 'editurl', + }, + }, + spec: { type: 'openapi' }, + }, + ], + }), + }; + + const contentHead = ; + + it('should show loation text field', async () => { + const { getByText, getByTestId } = await renderInTestApp( + + + , + ); + const mainGrid = getByTestId('main-grid'); + + expect(mainGrid.children.length).toBe(2); + expect(getByText('File Location')).toBeInTheDocument(); + }); + + it('should not show loation text field', async () => { + const { queryByText, getByTestId } = await renderInTestApp( + + + , + ); + const mainGrid = getByTestId('main-grid'); + + expect(mainGrid.children.length).toBe(1); + expect(queryByText('File Location')).not.toBeInTheDocument(); + }); + + it('should not show content head', async () => { + const { getByTestId } = await renderInTestApp( + + + , + ); + const mainGrid = getByTestId('main-grid'); + + expect(mainGrid.children.length).toBe(2); + }); + + it('should show content head', async () => { + const { getByTestId } = await renderInTestApp( + + + , + ); + const mainGrid = getByTestId('main-grid'); + + expect(mainGrid.children.length).toBe(3); + }); +}); diff --git a/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx index 0f0e60366b..c3e6386a37 100644 --- a/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx +++ b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx @@ -15,9 +15,9 @@ */ import React, { useState } from 'react'; -import { Content, Header, LinkButton, Page } from '@backstage/core-components'; +import { Content, Header, Page } from '@backstage/core-components'; import { EntityTextArea } from '../EntityTextArea'; -import { Grid, TextField } from '@material-ui/core'; +import { Button, Grid, TextField } from '@material-ui/core'; import { CatalogProcessorResult } from '../../types'; import { parseEntityYaml } from '../../utils'; import { EntityValidationOutput } from '../EntityValidationOutput'; @@ -40,10 +40,14 @@ spec: export const EntityValidationPage = (props: { defaultYaml?: string; defaultLocation?: string; + hideFileLocationField?: boolean; + contentHead?: React.ReactNode; }) => { const { defaultYaml = EXAMPLE_CATALOG_INFO_YAML, defaultLocation = 'https://github.com/backstage/backstage/blob/master/catalog-info.yaml', + hideFileLocationField = false, + contentHead, } = props; const [catalogYaml, setCatalogYaml] = useState(defaultYaml); @@ -67,8 +71,16 @@ export const EntityValidationPage = (props: { subtitle="Tool to validate catalog-info.yaml files" /> - - + + {contentHead} + + {!hideFileLocationField && ( setLocationUrl(e.target.value)} /> - - - - - - Validate - + )} + + + + + + setCatalogYaml(value)} + catalogYaml={catalogYaml} + /> + + + + - - - - - setCatalogYaml(value)} - catalogYaml={catalogYaml} - /> - - - - - + + + + + From 8edf7a9d0198ce3cecf2b601fd7261489ab8d1b0 Mon Sep 17 00:00:00 2001 From: Samuel Stadler Date: Thu, 23 Nov 2023 09:02:27 +0100 Subject: [PATCH 014/241] update api-report.md Signed-off-by: Samuel Stadler --- plugins/entity-validation/api-report.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/entity-validation/api-report.md b/plugins/entity-validation/api-report.md index 9d69458ed0..95fdfaf42c 100644 --- a/plugins/entity-validation/api-report.md +++ b/plugins/entity-validation/api-report.md @@ -7,12 +7,15 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { JSX as JSX_2 } from 'react'; +import { ReactNode } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; // @public (undocumented) export const EntityValidationPage: (props: { defaultYaml?: string | undefined; defaultLocation?: string | undefined; + hideFileLocationField?: boolean | undefined; + contentHead?: ReactNode; }) => JSX_2.Element; // @public (undocumented) From 84ca0aef20329ba9d3f6130fdd96fec661042dc8 Mon Sep 17 00:00:00 2001 From: Samuel Stadler Date: Tue, 12 Dec 2023 09:42:01 +0100 Subject: [PATCH 015/241] use patch impact for changeset Signed-off-by: Samuel Stadler --- .changeset/metal-students-drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/metal-students-drive.md b/.changeset/metal-students-drive.md index 5ba8f4ee3d..04f338c64e 100644 --- a/.changeset/metal-students-drive.md +++ b/.changeset/metal-students-drive.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-entity-validation': minor +'@backstage/plugin-entity-validation': patch --- Improves UX of the EntityValidationPage: Moves the validate button below the EntityTextArea which is actually validated, the location TextField can now be hidden to prevent confusion about what is validated and additional content can be added to the top of the validation page. From 14e40441790cf37029db328d3574d7769d98ecb6 Mon Sep 17 00:00:00 2001 From: Samuel Stadler Date: Fri, 22 Dec 2023 12:20:04 +0100 Subject: [PATCH 016/241] add @backstage/test-utils as devDependency Signed-off-by: Samuel Stadler --- plugins/entity-validation/package.json | 1 + yarn.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/entity-validation/package.json b/plugins/entity-validation/package.json index 76decd04f6..052835c061 100644 --- a/plugins/entity-validation/package.json +++ b/plugins/entity-validation/package.json @@ -57,6 +57,7 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", "@testing-library/dom": "^9.0.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^14.0.0" diff --git a/yarn.lock b/yarn.lock index 45162812d9..fa2180a957 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6241,6 +6241,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/plugin-catalog-common": "workspace:^" "@backstage/plugin-catalog-react": "workspace:^" + "@backstage/test-utils": "workspace:^" "@codemirror/language": ^6.0.0 "@codemirror/legacy-modes": ^6.1.0 "@codemirror/view": ^6.0.0 From b17facf2f7c874b28d26c69f4a35bcf027609c2c Mon Sep 17 00:00:00 2001 From: Markus Siebert Date: Sat, 23 Dec 2023 08:46:33 +0100 Subject: [PATCH 017/241] neat-hotels-wink.md aktualisieren Co-authored-by: Vincenzo Scamporlino Signed-off-by: Markus Siebert --- .changeset/neat-hotels-wink.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/neat-hotels-wink.md b/.changeset/neat-hotels-wink.md index a37d282578..fca82e38fa 100644 --- a/.changeset/neat-hotels-wink.md +++ b/.changeset/neat-hotels-wink.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend-module-gitlab': patch --- -add `groupTransformer`, `userTransformer` and `groupNameTransformer` to allow custom transformations when groups and users are created +Added the option to provide custom `groupTransformer`, `userTransformer` and `groupNameTransformer` to allow custom transformations of groups and users From f180cba319a13f2ee013920dced6d58786e6dcb5 Mon Sep 17 00:00:00 2001 From: Andres Mauricio Gomez P Date: Wed, 13 Dec 2023 10:21:56 -0500 Subject: [PATCH 018/241] Enabling authentication to kubernetes clusters with mTLS x509 client certs Signed-off-by: Andres Mauricio Gomez P --- .changeset/tame-numbers-smile.md | 6 +++ .../src/service/KubernetesFetcher.test.ts | 2 +- .../src/service/KubernetesFetcher.ts | 7 ++- .../src/service/KubernetesProxy.ts | 43 +++++++++++-------- plugins/kubernetes-node/api-report.md | 5 +++ plugins/kubernetes-node/src/types/types.ts | 1 + 6 files changed, 43 insertions(+), 21 deletions(-) create mode 100644 .changeset/tame-numbers-smile.md diff --git a/.changeset/tame-numbers-smile.md b/.changeset/tame-numbers-smile.md new file mode 100644 index 0000000000..1d675f8c9c --- /dev/null +++ b/.changeset/tame-numbers-smile.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-node': patch +--- + +Enabling authentication to kubernetes clusters with mTLS x509 client certs diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts index e388589e74..0d9f067707 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts @@ -895,7 +895,7 @@ describe('KubernetesFetcher', () => { customResources: [], }); return expect(result).rejects.toThrow( - "no bearer token for cluster 'unauthenticated-cluster' and not running in Kubernetes", + "no bearer token or client cert for cluster 'unauthenticated-cluster' and not running in Kubernetes", ); }); }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts index 99501c48c6..4daf3e80f6 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts @@ -224,13 +224,14 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { [url, requestInit] = this.fetchArgsInCluster(credential); } else if ( credential.type === 'bearer token' || + credential.type === 'x509 client certificate' || authProvider === 'localKubectlProxy' ) { [url, requestInit] = this.fetchArgs(clusterDetails, credential); } else { return Promise.reject( new Error( - `no bearer token for cluster '${clusterDetails.name}' and not running in Kubernetes`, + `no bearer token or client cert for cluster '${clusterDetails.name}' and not running in Kubernetes`, ), ); } @@ -272,6 +273,10 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { clusterDetails.caData, ) ?? undefined, rejectUnauthorized: !clusterDetails.skipTLSVerify, + ...(credential.type === 'x509 client certificate' && { + cert: credential.cert, + key: credential.key, + }), }); } return [url, requestInit]; diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts index 8a07267cde..209d01b703 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.ts @@ -113,24 +113,6 @@ export class KubernetesProxy { return; } - const authHeader = req.header(HEADER_KUBERNETES_AUTH); - if (authHeader) { - req.headers.authorization = authHeader; - } else { - // Map Backstage-Kubernetes-Authorization-X-X headers to a KubernetesRequestAuth object - const authObj = KubernetesProxy.authHeadersToKubernetesRequestAuth( - req.headers, - ); - - const credential = await this.getClusterForRequest(req).then(cd => { - return this.authStrategy.getCredential(cd, authObj); - }); - - if (credential.type === 'bearer token') { - req.headers.authorization = `Bearer ${credential.token}`; - } - } - const middleware = await this.getMiddleware(req); // If req is an upgrade handshake, use middleware upgrade instead of http request handler https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade @@ -173,7 +155,7 @@ export class KubernetesProxy { const cluster = await this.getClusterForRequest(req); const url = new URL(cluster.url); - return { + const target: any = { protocol: url.protocol, host: url.hostname, port: url.port, @@ -182,6 +164,29 @@ export class KubernetesProxy { cluster.caData, )?.toString(), }; + + const authHeader = req.header(HEADER_KUBERNETES_AUTH); + if (authHeader) { + req.headers.authorization = authHeader; + } else { + // Map Backstage-Kubernetes-Authorization-X-X headers to a KubernetesRequestAuth object + const authObj = KubernetesProxy.authHeadersToKubernetesRequestAuth( + req.headers, + ); + + const credential = await this.getClusterForRequest(req).then(cd => { + return this.authStrategy.getCredential(cd, authObj); + }); + + if (credential.type === 'bearer token') { + req.headers.authorization = `Bearer ${credential.token}`; + } else if (credential.type === 'x509 client certificate') { + target.key = credential.key; + target.cert = credential.cert; + } + } + + return target; }, onError: (error, req, res) => { const wrappedError = new ForwardedError( diff --git a/plugins/kubernetes-node/api-report.md b/plugins/kubernetes-node/api-report.md index 2272035742..4c858ec969 100644 --- a/plugins/kubernetes-node/api-report.md +++ b/plugins/kubernetes-node/api-report.md @@ -100,6 +100,11 @@ export type KubernetesCredential = type: 'bearer token'; token: string; } + | { + type: 'x509 client certificate'; + cert: string; + key: string; + } | { type: 'anonymous'; }; diff --git a/plugins/kubernetes-node/src/types/types.ts b/plugins/kubernetes-node/src/types/types.ts index a0f48d0c26..036b54ed98 100644 --- a/plugins/kubernetes-node/src/types/types.ts +++ b/plugins/kubernetes-node/src/types/types.ts @@ -139,6 +139,7 @@ export interface KubernetesClustersSupplier { */ export type KubernetesCredential = | { type: 'bearer token'; token: string } + | { type: 'x509 client certificate'; cert: string; key: string } | { type: 'anonymous' }; /** From 3cc0d262066b83c8ae5f100af6a271ed27d6cdd7 Mon Sep 17 00:00:00 2001 From: Andres Mauricio Gomez P Date: Thu, 14 Dec 2023 14:19:24 -0500 Subject: [PATCH 019/241] Adding tests on KubernetesFetcher and KubernetesProxy for x509 client cert authentication Signed-off-by: Andres Mauricio Gomez P --- .../src/service/KubernetesFetcher.test.ts | 123 ++++++++++++++++++ .../src/service/KubernetesFetcher.ts | 33 +++-- .../src/service/KubernetesProxy.test.ts | 61 +++++++++ 3 files changed, 209 insertions(+), 8 deletions(-) diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts index 0d9f067707..966fda7ce5 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts @@ -812,6 +812,129 @@ describe('KubernetesFetcher', () => { const [[{ agent }]] = httpsRequest.mock.calls; expect(agent.options.rejectUnauthorized).toBe(false); }); + + it('should use a x509 client cert authentication strategy to consume kubeapi when backstage-kubernetes-auth field is not provided and the authStrategy enables x509 client cert authentication - fetchObjectsForService', async () => { + worker.use( + rest.get('https://localhost:9999/api/v1/pods', (req, res, ctx) => + res( + checkToken(req, ctx, 'token'), + withLabels(req, ctx, { + items: [{ metadata: { name: 'pod-name' } }], + }), + ), + ), + ); + + const myCert = 'MOCKCert'; + const myKey = 'MOCKKey'; + + const result = sut.fetchObjectsForService({ + serviceId: 'some-service', + clusterDetails: { + name: 'cluster1', + url: 'https://localhost:9999', + authMetadata: {}, + caData: 'MOCKCA', + }, + credential: { + type: 'x509 client certificate', + cert: myCert, + key: myKey, + }, + objectTypesToFetch: new Set([ + { + group: '', + apiVersion: 'v1', + plural: 'pods', + objectType: 'pods', + }, + ]), + labelSelector: '', + customResources: [], + }); + + await expect(result).rejects.toThrow(/PEM/); + + expect(httpsRequest).toHaveBeenCalledTimes(1); + const [[{ agent }]] = httpsRequest.mock.calls; + expect(agent.options.ca.toString('base64')).toMatch('MOCKCA'); + expect(agent.options.cert).toEqual(myCert); + expect(agent.options.key).toEqual(myKey); + }); + + it('should use a x509 client cert authentication strategy to consume kubeapi when backstage-kubernetes-auth field is not provided and the authStrategy enables x509 client cert authentication - fetchPodMetricsByNamespaces', async () => { + worker.use( + rest.get( + 'https://localhost:9999/api/v1/namespaces/:namespace/pods', + (req, res, ctx) => + res( + withLabels(req, ctx, { + items: [ + { + metadata: { name: 'pod-name' }, + spec: { + containers: [ + { + name: 'container-name', + resources: { + requests: { cpu: '500m', memory: '512M' }, + limits: { cpu: '1000m', memory: '1G' }, + }, + }, + ], + }, + }, + ], + }), + ), + ), + rest.get( + 'https://localhost:9999/apis/metrics.k8s.io/v1beta1/namespaces/:namespace/pods', + (req, res, ctx) => + res( + withLabels(req, ctx, { + items: [ + { + metadata: { name: 'pod-name' }, + containers: [ + { + name: 'container-name', + usage: { cpu: '0', memory: '0' }, + }, + ], + }, + ], + }), + ), + ), + ); + + const myCert = 'MOCKCert'; + const myKey = 'MOCKKey'; + + const result = sut.fetchPodMetricsByNamespaces( + { + name: 'cluster1', + url: 'https://localhost:9999', + authMetadata: {}, + caData: 'MOCKCA', + }, + { + type: 'x509 client certificate', + cert: myCert, + key: myKey, + }, + new Set(['ns-a']), + ); + + await expect(result).rejects.toThrow(/PEM/); + + expect(httpsRequest).toHaveBeenCalledTimes(2); + const [[{ agent }]] = httpsRequest.mock.calls; + expect(agent.options.ca.toString('base64')).toMatch('MOCKCA'); + expect(agent.options.cert).toEqual(myCert); + expect(agent.options.key).toEqual(myKey); + }); }); it('should use namespace if provided', async () => { diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts index 4daf3e80f6..cf4e3f9440 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts @@ -216,16 +216,11 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { let requestInit: RequestInit; const authProvider = clusterDetails.authMetadata[ANNOTATION_KUBERNETES_AUTH_PROVIDER]; - if ( - authProvider === 'serviceAccount' && - !clusterDetails.authMetadata.serviceAccountToken && - fs.pathExistsSync(Config.SERVICEACCOUNT_CA_PATH) - ) { + + if (this.isServiceAccountAuthentication(authProvider, clusterDetails)) { [url, requestInit] = this.fetchArgsInCluster(credential); } else if ( - credential.type === 'bearer token' || - credential.type === 'x509 client certificate' || - authProvider === 'localKubectlProxy' + this.isTokenOrClientCertificateAuthentication(authProvider, credential) ) { [url, requestInit] = this.fetchArgs(clusterDetails, credential); } else { @@ -249,6 +244,28 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { return fetch(url, requestInit); } + private isServiceAccountAuthentication( + authProvider: string, + clusterDetails: ClusterDetails, + ) { + return ( + authProvider === 'serviceAccount' && + !clusterDetails.authMetadata.serviceAccountToken && + fs.pathExistsSync(Config.SERVICEACCOUNT_CA_PATH) + ); + } + + private isTokenOrClientCertificateAuthentication( + authProvider: string, + credential: KubernetesCredential, + ) { + return ( + credential.type === 'bearer token' || + credential.type === 'x509 client certificate' || + authProvider === 'localKubectlProxy' + ); + } + private fetchArgs( clusterDetails: ClusterDetails, credential: KubernetesCredential, diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 9bee21867d..94a8b2918e 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -820,6 +820,67 @@ describe('KubernetesProxy', () => { expect(ca).toMatch('MOCKCA'); }); }); + + it('should use a x509 client cert authentication strategy to consume kubeapi when backstage-kubernetes-auth field is not provided and the authStrategy enables x509 client cert authentication', async () => { + worker.use( + rest.get( + 'https://localhost:9999/api/v1/namespaces', + (req: any, res: any, ctx: any) => { + if (req.headers.get('Authorization')) { + return res(ctx.status(403)); + } + + return res( + ctx.status(200), + ctx.json({ + kind: 'NamespaceList', + apiVersion: 'v1', + items: [], + }), + ); + }, + ), + ); + + clusterSupplier.getClusters.mockResolvedValue([ + { + name: 'cluster1', + url: 'https://localhost:9999', + authMetadata: {}, + }, + ]); + + const myCert = 'MOCKCert'; + const myKey = 'MOCKKey'; + + authStrategy.getCredential.mockResolvedValue({ + type: 'x509 client certificate', + cert: myCert, + key: myKey, + }); + + const requestPromise = setupProxyPromise({ + proxyPath: '/mountpath', + requestPath: '/api/v1/namespaces', + + headers: { [HEADER_KUBERNETES_CLUSTER]: 'cluster1' }, + }); + + const response = await requestPromise; + + expect(authStrategy.getCredential).toHaveBeenCalledTimes(1); + expect(authStrategy.getCredential).toHaveBeenCalledWith( + expect.anything(), + {}, + ); + + const [[{ key, cert }]] = httpsRequest.mock.calls; + expect(cert).toEqual(myCert); + expect(key).toEqual(myKey); + + // 500 Since the key and cert are fake + expect(response.status).toEqual(500); + }); }); describe('WebSocket', () => { From 618ed7830f85479ec09cb40f399fe2adf51057e5 Mon Sep 17 00:00:00 2001 From: Mayaw Power Date: Mon, 1 Jan 2024 16:15:45 +0800 Subject: [PATCH 020/241] Update README-zh_Hans.md fix typo error Signed-off-by: Mayaw Power --- README-zh_Hans.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-zh_Hans.md b/README-zh_Hans.md index bf96eea389..b1e5a16add 100644 --- a/README-zh_Hans.md +++ b/README-zh_Hans.md @@ -57,7 +57,7 @@ Backstage 的文档包括: - [参与贡献 Backstage](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md) - 如果您想做出贡献,请从这里开始 - [RFCs](https://github.com/backstage/backstage/labels/rfc) - 帮助制定技术方向 - [FAQ](https://backstage.io/docs/FAQ) - n.: 常问问题 -- [行为准则](CODE_OF_CONDUCT.md) - 这是我们的刑事方式 +- [行为准则](CODE_OF_CONDUCT.md) - 这是我们的行事方式 - [采纳者](ADOPTERS.md) - 已经在使用 Backstage 的公司 - [博客](https://backstage.io/blog/) - 公告和更新 - [通讯](https://spoti.fi/backstagenewsletter) - 订阅我们的电子邮件通讯 From 047beadd9ddebbf2b9b44d27055d1b30a8af3e7b Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Mon, 4 Dec 2023 12:36:50 +0200 Subject: [PATCH 021/241] feat: signals plugins next try after #18153 without any external dependencies and only supporting websocket. missing tests and necessary documentation but will work on those after initial comments if this would be proper way to go forward. already planning for the notification plugins on top of this. Signed-off-by: Heikki Hellgren --- .changeset/real-eggs-sip.md | 7 + packages/backend/package.json | 2 + packages/backend/src/index.ts | 11 +- packages/backend/src/plugins/signals.ts | 39 +++ .../Content/InfoContent/InfoContent.tsx | 13 + plugins/signals-backend/.eslintrc.js | 1 + plugins/signals-backend/README.md | 31 +++ plugins/signals-backend/api-report.md | 22 ++ plugins/signals-backend/catalog-info.yaml | 9 + plugins/signals-backend/package.json | 50 ++++ plugins/signals-backend/src/index.ts | 16 ++ plugins/signals-backend/src/run.ts | 32 +++ .../src/service/router.test.ts | 48 ++++ plugins/signals-backend/src/service/router.ts | 57 +++++ .../src/service/standaloneServer.ts | 69 ++++++ plugins/signals-backend/src/setupTests.ts | 16 ++ plugins/signals-node/.eslintrc.js | 1 + plugins/signals-node/README.md | 5 + plugins/signals-node/api-report.md | 47 ++++ plugins/signals-node/catalog-info.yaml | 10 + plugins/signals-node/package.json | 42 ++++ plugins/signals-node/src/SignalsService.ts | 226 ++++++++++++++++++ plugins/signals-node/src/index.ts | 18 ++ plugins/signals-node/src/setupTests.ts | 16 ++ plugins/signals-node/src/types.ts | 39 +++ plugins/signals-react/.eslintrc.js | 1 + plugins/signals-react/README.md | 5 + plugins/signals-react/api-report.md | 45 ++++ plugins/signals-react/catalog-info.yaml | 10 + plugins/signals-react/package.json | 43 ++++ plugins/signals-react/src/api/SignalsApi.ts | 32 +++ .../signals-react/src/api/SignalsClient.ts | 133 +++++++++++ plugins/signals-react/src/api/index.ts | 17 ++ plugins/signals-react/src/hooks/index.ts | 16 ++ .../signals-react/src/hooks/useSignalsApi.ts | 37 +++ plugins/signals-react/src/index.ts | 18 ++ plugins/signals-react/src/setupTests.ts | 16 ++ yarn.lock | 115 ++++++++- 38 files changed, 1308 insertions(+), 7 deletions(-) create mode 100644 .changeset/real-eggs-sip.md create mode 100644 packages/backend/src/plugins/signals.ts create mode 100644 plugins/signals-backend/.eslintrc.js create mode 100644 plugins/signals-backend/README.md create mode 100644 plugins/signals-backend/api-report.md create mode 100644 plugins/signals-backend/catalog-info.yaml create mode 100644 plugins/signals-backend/package.json create mode 100644 plugins/signals-backend/src/index.ts create mode 100644 plugins/signals-backend/src/run.ts create mode 100644 plugins/signals-backend/src/service/router.test.ts create mode 100644 plugins/signals-backend/src/service/router.ts create mode 100644 plugins/signals-backend/src/service/standaloneServer.ts create mode 100644 plugins/signals-backend/src/setupTests.ts create mode 100644 plugins/signals-node/.eslintrc.js create mode 100644 plugins/signals-node/README.md create mode 100644 plugins/signals-node/api-report.md create mode 100644 plugins/signals-node/catalog-info.yaml create mode 100644 plugins/signals-node/package.json create mode 100644 plugins/signals-node/src/SignalsService.ts create mode 100644 plugins/signals-node/src/index.ts create mode 100644 plugins/signals-node/src/setupTests.ts create mode 100644 plugins/signals-node/src/types.ts create mode 100644 plugins/signals-react/.eslintrc.js create mode 100644 plugins/signals-react/README.md create mode 100644 plugins/signals-react/api-report.md create mode 100644 plugins/signals-react/catalog-info.yaml create mode 100644 plugins/signals-react/package.json create mode 100644 plugins/signals-react/src/api/SignalsApi.ts create mode 100644 plugins/signals-react/src/api/SignalsClient.ts create mode 100644 plugins/signals-react/src/api/index.ts create mode 100644 plugins/signals-react/src/hooks/index.ts create mode 100644 plugins/signals-react/src/hooks/useSignalsApi.ts create mode 100644 plugins/signals-react/src/index.ts create mode 100644 plugins/signals-react/src/setupTests.ts diff --git a/.changeset/real-eggs-sip.md b/.changeset/real-eggs-sip.md new file mode 100644 index 0000000000..ca05205083 --- /dev/null +++ b/.changeset/real-eggs-sip.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-signals-backend': patch +'@backstage/plugin-signals-react': patch +'@backstage/plugin-signals-node': patch +--- + +Add support to subscribe and publish messages through signals plugins diff --git a/packages/backend/package.json b/packages/backend/package.json index a70e5b5d3b..8899115c17 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -72,6 +72,8 @@ "@backstage/plugin-search-backend-module-techdocs": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-search-common": "workspace:^", + "@backstage/plugin-signals-backend": "workspace:^", + "@backstage/plugin-signals-node": "workspace:^", "@backstage/plugin-tech-insights-backend": "workspace:^", "@backstage/plugin-tech-insights-backend-module-jsonfc": "workspace:^", "@backstage/plugin-tech-insights-node": "workspace:^", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 8df01b050e..cefc272aa7 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -26,19 +26,19 @@ import Router from 'express-promise-router'; import { CacheManager, createServiceBuilder, + DatabaseManager, getRootLogger, + HostDiscovery, loadBackendConfig, notFoundHandler, - DatabaseManager, - HostDiscovery, + ServerTokenManager, UrlReaders, useHotMemoize, - ServerTokenManager, } from '@backstage/backend-common'; import { TaskScheduler } from '@backstage/backend-tasks'; import { Config } from '@backstage/config'; import healthcheck from './plugins/healthcheck'; -import { metricsInit, metricsHandler } from './metrics'; +import { metricsHandler, metricsInit } from './metrics'; import auth from './plugins/auth'; import azureDevOps from './plugins/azure-devops'; import catalog from './plugins/catalog'; @@ -65,6 +65,7 @@ import lighthouse from './plugins/lighthouse'; import linguist from './plugins/linguist'; import devTools from './plugins/devtools'; import nomad from './plugins/nomad'; +import signals from './plugins/signals'; import { PluginEnvironment } from './types'; import { ServerPermissionClient } from '@backstage/plugin-permission-node'; import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; @@ -172,6 +173,7 @@ async function main() { const linguistEnv = useHotMemoize(module, () => createEnv('linguist')); const devToolsEnv = useHotMemoize(module, () => createEnv('devtools')); const nomadEnv = useHotMemoize(module, () => createEnv('nomad')); + const signalsEnv = useHotMemoize(module, () => createEnv('signals')); const apiRouter = Router(); apiRouter.use('/catalog', await catalog(catalogEnv)); @@ -198,6 +200,7 @@ async function main() { apiRouter.use('/linguist', await linguist(linguistEnv)); apiRouter.use('/devtools', await devTools(devToolsEnv)); apiRouter.use('/nomad', await nomad(nomadEnv)); + apiRouter.use('/signals', await signals(signalsEnv)); apiRouter.use(notFoundHandler()); await lighthouse(lighthouseEnv); diff --git a/packages/backend/src/plugins/signals.ts b/packages/backend/src/plugins/signals.ts new file mode 100644 index 0000000000..8e2d0b2d3f --- /dev/null +++ b/packages/backend/src/plugins/signals.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2023 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 { Router } from 'express'; +import { createRouter } from '@backstage/plugin-signals-backend'; +import { SignalsService } from '@backstage/plugin-signals-node'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const service = SignalsService.create({ + logger: env.logger, + identity: env.identity, + eventBroker: env.eventBroker, + }); + + setInterval(() => { + console.log('publishing'); + service.publish('*', { hello: 'world' }); + }, 5000); + + return await createRouter({ + logger: env.logger, + service, + }); +} diff --git a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx index 0ed43d2fee..810a823027 100644 --- a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx @@ -27,6 +27,7 @@ import { makeStyles, Paper, Theme, + Typography, } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; import React from 'react'; @@ -38,6 +39,7 @@ import DeveloperBoardIcon from '@material-ui/icons/DeveloperBoard'; import { BackstageLogoIcon } from './BackstageLogoIcon'; import FileCopyIcon from '@material-ui/icons/FileCopy'; import { DevToolsInfo } from '@backstage/plugin-devtools-common'; +import { useSignalsApi } from '@backstage/plugin-signals-react'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -73,6 +75,12 @@ const copyToClipboard = ({ about }: { about: DevToolsInfo | undefined }) => { export const InfoContent = () => { const classes = useStyles(); const { about, loading, error } = useInfo(); + // Just testing for signals + const [messages, setMessages] = React.useState([]); + useSignalsApi(message => { + messages.push(JSON.stringify(message)); + setMessages([...messages]); + }); if (loading) { return ; @@ -81,6 +89,11 @@ export const InfoContent = () => { } return ( + + {messages.map((msg, i) => { + return {msg}; + })} + diff --git a/plugins/signals-backend/.eslintrc.js b/plugins/signals-backend/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/signals-backend/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/signals-backend/README.md b/plugins/signals-backend/README.md new file mode 100644 index 0000000000..d194b852f2 --- /dev/null +++ b/plugins/signals-backend/README.md @@ -0,0 +1,31 @@ +# signals + +Welcome to the signals backend plugin! + +Signals plugin allows backend plugins to publish messages to frontend plugins. + +## Getting started + +Add Signals router to your backend in `packages/backend/src/plugins/signals.ts`: + +```ts +import { Router } from 'express'; +import { createRouter } from '@backstage/plugin-signals-backend'; +import { SignalsService } from '@backstage/plugin-signals-node'; +import { PluginEnvironment } from '../types'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const service = SignalsService.create({ + logger: env.logger, + identity: env.identity, + eventBroker: env.eventBroker, + }); + + return await createRouter({ + logger: env.logger, + service, + }); +} +``` diff --git a/plugins/signals-backend/api-report.md b/plugins/signals-backend/api-report.md new file mode 100644 index 0000000000..0ea56c707a --- /dev/null +++ b/plugins/signals-backend/api-report.md @@ -0,0 +1,22 @@ +## API Report File for "@backstage/plugin-signals-backend" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import express from 'express'; +import { Logger } from 'winston'; +import { SignalsService } from '@backstage/plugin-signals-node'; + +// @public (undocumented) +export function createRouter(options: RouterOptions): Promise; + +// @public (undocumented) +export interface RouterOptions { + // (undocumented) + logger: Logger; + // (undocumented) + service: SignalsService; +} + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/signals-backend/catalog-info.yaml b/plugins/signals-backend/catalog-info.yaml new file mode 100644 index 0000000000..0a025b77b5 --- /dev/null +++ b/plugins/signals-backend/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-signals-backend + title: '@backstage/plugin-signals-backend' +spec: + lifecycle: experimental + type: backstage-backend-plugin + owner: maintainers diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json new file mode 100644 index 0000000000..ee303cdf3b --- /dev/null +++ b/plugins/signals-backend/package.json @@ -0,0 +1,50 @@ +{ + "name": "@backstage/plugin-signals-backend", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "backend-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" + }, + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "@backstage/plugin-signals-node": "workspace:^", + "@backstage/types": "workspace:^", + "@types/express": "*", + "express": "^4.17.1", + "express-promise-router": "^4.1.0", + "http-proxy-middleware": "^2.0.0", + "node-fetch": "^2.6.7", + "uuid": "^8.0.0", + "winston": "^3.2.1", + "ws": "^8.14.2", + "yn": "^4.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@types/supertest": "^2.0.8", + "msw": "^1.0.0", + "supertest": "^6.2.4" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/signals-backend/src/index.ts b/plugins/signals-backend/src/index.ts new file mode 100644 index 0000000000..d2e8d61bad --- /dev/null +++ b/plugins/signals-backend/src/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './service/router'; diff --git a/plugins/signals-backend/src/run.ts b/plugins/signals-backend/src/run.ts new file mode 100644 index 0000000000..d299ed23e9 --- /dev/null +++ b/plugins/signals-backend/src/run.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2023 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 { getRootLogger } from '@backstage/backend-common'; +import yn from 'yn'; +import { startStandaloneServer } from './service/standaloneServer'; + +const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007; +const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); +const logger = getRootLogger(); + +startStandaloneServer({ port, enableCors, logger }).catch(err => { + logger.error(err); + process.exit(1); +}); + +process.on('SIGINT', () => { + logger.info('CTRL+C pressed; exiting.'); + process.exit(0); +}); diff --git a/plugins/signals-backend/src/service/router.test.ts b/plugins/signals-backend/src/service/router.test.ts new file mode 100644 index 0000000000..d7091827f9 --- /dev/null +++ b/plugins/signals-backend/src/service/router.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2023 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 express from 'express'; +import request from 'supertest'; + +import { createRouter } from './router'; +import { SignalsService } from '@backstage/plugin-signals-node'; + +const signalsServiceMock: jest.Mocked = {} as any; + +describe('createRouter', () => { + let app: express.Express; + + beforeAll(async () => { + const router = await createRouter({ + logger: getVoidLogger(), + service: signalsServiceMock, + }); + app = express().use(router); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('GET /health', () => { + it('returns ok', async () => { + const response = await request(app).get('/health'); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ status: 'ok' }); + }); + }); +}); diff --git a/plugins/signals-backend/src/service/router.ts b/plugins/signals-backend/src/service/router.ts new file mode 100644 index 0000000000..0027acef30 --- /dev/null +++ b/plugins/signals-backend/src/service/router.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2023 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 { errorHandler } from '@backstage/backend-common'; +import express from 'express'; +import Router from 'express-promise-router'; +import { Logger } from 'winston'; +import { SignalsService } from '@backstage/plugin-signals-node'; + +/** @public */ +export interface RouterOptions { + logger: Logger; + service: SignalsService; +} + +/** @public */ +export async function createRouter( + options: RouterOptions, +): Promise { + const { logger, service } = options; + + const router = Router(); + router.use(express.json()); + + router.get('/health', (_, response) => { + logger.info('PONG!'); + response.json({ status: 'ok' }); + }); + + router.get('/', async (req, _, next) => { + if ( + !req.headers || + req.headers.upgrade === undefined || + req.headers.upgrade.toLowerCase() !== 'websocket' + ) { + next(); + return; + } + + await service.handleUpgrade(req); + }); + + router.use(errorHandler()); + return router; +} diff --git a/plugins/signals-backend/src/service/standaloneServer.ts b/plugins/signals-backend/src/service/standaloneServer.ts new file mode 100644 index 0000000000..c13d718734 --- /dev/null +++ b/plugins/signals-backend/src/service/standaloneServer.ts @@ -0,0 +1,69 @@ +/* + * Copyright 2023 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 { + createServiceBuilder, + HostDiscovery, + loadBackendConfig, +} from '@backstage/backend-common'; +import { Server } from 'http'; +import { Logger } from 'winston'; +import { createRouter } from './router'; +import { SignalsService } from '@backstage/plugin-signals-node'; +import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; + +export interface ServerOptions { + port: number; + enableCors: boolean; + logger: Logger; +} + +export async function startStandaloneServer( + options: ServerOptions, +): Promise { + const logger = options.logger.child({ service: 'signals-backend' }); + logger.debug('Starting application server...'); + const config = await loadBackendConfig({ logger, argv: process.argv }); + const discovery = HostDiscovery.fromConfig(config); + + const identity = DefaultIdentityClient.create({ + discovery, + issuer: await discovery.getExternalBaseUrl('auth'), + }); + + const signals = SignalsService.create({ + logger: logger, + identity, + }); + + const router = await createRouter({ + logger, + service: signals, + }); + + let service = createServiceBuilder(module) + .setPort(options.port) + .addRouter('/signals', router); + if (options.enableCors) { + service = service.enableCors({ origin: 'http://localhost:3000' }); + } + + return await service.start().catch(err => { + logger.error(err); + process.exit(1); + }); +} + +module.hot?.accept(); diff --git a/plugins/signals-backend/src/setupTests.ts b/plugins/signals-backend/src/setupTests.ts new file mode 100644 index 0000000000..4b9026cde5 --- /dev/null +++ b/plugins/signals-backend/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export {}; diff --git a/plugins/signals-node/.eslintrc.js b/plugins/signals-node/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/signals-node/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/signals-node/README.md b/plugins/signals-node/README.md new file mode 100644 index 0000000000..55d766f9e0 --- /dev/null +++ b/plugins/signals-node/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-signals-node + +Welcome to the Node.js library package for the signals plugin! + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md new file mode 100644 index 0000000000..e8c9900908 --- /dev/null +++ b/plugins/signals-node/api-report.md @@ -0,0 +1,47 @@ +## API Report File for "@backstage/plugin-signals-node" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { EventBroker } from '@backstage/plugin-events-node'; +import { EventParams } from '@backstage/plugin-events-node'; +import { EventSubscriber } from '@backstage/plugin-events-node'; +import { IdentityApi } from '@backstage/plugin-auth-node'; +import { JsonObject } from '@backstage/types'; +import { Logger } from 'winston'; +import { Request as Request_2 } from 'express'; + +// @public (undocumented) +export type ServiceOptions = { + eventBroker?: EventBroker; + logger: Logger; + identity: IdentityApi; +}; + +// @public (undocumented) +export type SignalsEventBrokerPayload = { + recipients?: string[]; + topic?: string; + message?: JsonObject; +}; + +// @public (undocumented) +export class SignalsService implements EventSubscriber { + // (undocumented) + static create(options: ServiceOptions): SignalsService; + // (undocumented) + handleUpgrade: (req: Request_2) => Promise; + // (undocumented) + onEvent(params: EventParams): Promise; + // (undocumented) + publish( + to: string | string[], + message: JsonObject, + topic?: string, + ): Promise; + // (undocumented) + supportsEventTopics(): string[]; +} + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/signals-node/catalog-info.yaml b/plugins/signals-node/catalog-info.yaml new file mode 100644 index 0000000000..5e3af0acde --- /dev/null +++ b/plugins/signals-node/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-signals-node + title: '@backstage/plugin-signals-node' + description: Node.js library for the signals plugin +spec: + lifecycle: experimental + type: backstage-node-library + owner: maintainers diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json new file mode 100644 index 0000000000..66e4528678 --- /dev/null +++ b/plugins/signals-node/package.json @@ -0,0 +1,42 @@ +{ + "name": "@backstage/plugin-signals-node", + "description": "Node.js library for the signals plugin", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "node-library" + }, + "scripts": { + "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" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@types/express": "^4.17.21" + }, + "files": [ + "dist" + ], + "dependencies": { + "@backstage/backend-common": "workspace:^", + "@backstage/config": "workspace:^", + "@backstage/plugin-auth-node": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", + "@backstage/types": "workspace:^", + "express": "^4.17.1", + "uuid": "^8.0.0", + "winston": "^3.2.1", + "ws": "^8.14.2" + } +} diff --git a/plugins/signals-node/src/SignalsService.ts b/plugins/signals-node/src/SignalsService.ts new file mode 100644 index 0000000000..6404386129 --- /dev/null +++ b/plugins/signals-node/src/SignalsService.ts @@ -0,0 +1,226 @@ +/* + * Copyright 2023 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 { + EventBroker, + EventParams, + EventSubscriber, +} from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; +import { ServiceOptions, SignalConnection } from './types'; +import { RawData, WebSocket, WebSocketServer } from 'ws'; +import { IncomingMessage } from 'http'; +import { v4 as uuid } from 'uuid'; +import { Request } from 'express'; +import { JsonObject } from '@backstage/types'; +import { + BackstageIdentityResponse, + IdentityApi, +} from '@backstage/plugin-auth-node'; + +/** @public */ +export type SignalsEventBrokerPayload = { + recipients?: string[]; + topic?: string; + message?: JsonObject; +}; + +/** @public */ +export class SignalsService implements EventSubscriber { + private readonly serverId: string; + private connections: Map = new Map< + string, + SignalConnection + >(); + private eventBroker?: EventBroker; + private logger: Logger; + private identity: IdentityApi; + private server: WebSocketServer; + + static create(options: ServiceOptions) { + return new SignalsService(options); + } + + private constructor(options: ServiceOptions) { + ({ + eventBroker: this.eventBroker, + logger: this.logger, + identity: this.identity, + } = options); + + this.serverId = uuid(); + this.server = new WebSocketServer({ + noServer: true, + }); + + this.server.on('close', () => { + this.logger.info('Closing signals server'); + this.connections.forEach(conn => { + conn.ws.close(); + }); + this.connections = new Map(); + }); + + this.eventBroker?.subscribe(this); + } + + handleUpgrade = async (req: Request) => { + const identity = await this.identity.getIdentity({ + request: req, + }); + + this.server.handleUpgrade( + req, + req.socket, + Buffer.from(''), + (ws: WebSocket, __: IncomingMessage) => { + this.addConnection(ws, identity); + }, + ); + }; + + private addConnection(ws: WebSocket, identity?: BackstageIdentityResponse) { + const id = uuid(); + + const conn = { + id, + user: identity?.identity.userEntityRef ?? 'user:default/guest', + ws, + ownershipEntityRefs: identity?.identity.ownershipEntityRefs ?? [], + subscriptions: new Set(), + }; + + this.connections.set(id, conn); + + ws.on('error', (err: Error) => { + this.logger.info( + `Error occurred with connection ${id}: ${err}, closing connection`, + ); + ws.close(); + this.connections.delete(id); + }); + + ws.on('close', (code: number, reason: Buffer) => { + this.logger.info( + `Connection ${id} closed with code ${code}, reason: ${reason}`, + ); + this.connections.delete(id); + }); + + ws.on('ping', () => { + this.logger.debug(`Ping from connection ${id}`); + ws.pong(); + }); + + ws.on('message', (data: RawData, isBinary: boolean) => { + this.logger.debug(`Received message from connection ${id}: ${data}`); + if (isBinary) { + return; + } + + try { + const json = JSON.parse(data.toString()) as JsonObject; + this.handleMessage(conn, json); + } catch (err: any) { + this.logger.error( + `Invalid message received from connection ${id}: ${err}`, + ); + } + }); + } + + private handleMessage(connection: SignalConnection, message: JsonObject) { + if (message.action === 'subscribe' && message.topic) { + this.logger.info( + `Connection ${connection.id} subscribed to ${message.topic}`, + ); + connection.subscriptions.add(message.topic as string); + } + + if (message.action === 'unsubscribe' && message.topic) { + this.logger.info( + `Connection ${connection.id} unsubscribed from ${message.topic}`, + ); + connection.subscriptions.delete(message.topic as string); + } + } + + async publish(to: string | string[], message: JsonObject, topic?: string) { + await this.publishInternal( + Array.isArray(to) ? to : [to], + message, + false, + topic, + ); + } + + private async publishInternal( + recipients: string[], + message: JsonObject, + brokedEvent: boolean, + topic?: string, + ) { + this.connections.forEach(conn => { + if (topic && !conn.subscriptions.has(topic)) { + return; + } + // Sending to all users can be done with '*' + if ( + !recipients.includes('*') && + !conn.ownershipEntityRefs.some(ref => recipients.includes(ref)) + ) { + return; + } + conn.ws.send(JSON.stringify({ topic, message })); + }); + + // If this event has not been broadcasted to all servers, then use + // EventBroker to do that + if (this.eventBroker && !brokedEvent) { + await this.eventBroker.publish({ + topic: 'signals', + eventPayload: { + recipients, + message, + topic, + }, + metadata: { server: this.serverId }, + }); + } + } + + async onEvent(params: EventParams): Promise { + const { eventPayload, metadata } = params; + // Discard message from same server to prevent duplicate messages + if (!metadata?.server || metadata.server === this.serverId) { + return; + } + + if (!eventPayload?.recipients || !eventPayload.message) { + return; + } + + await this.publishInternal( + eventPayload.recipients, + eventPayload.message, + true, + eventPayload.topic, + ); + } + + supportsEventTopics(): string[] { + return ['signals']; + } +} diff --git a/plugins/signals-node/src/index.ts b/plugins/signals-node/src/index.ts new file mode 100644 index 0000000000..5427711cbe --- /dev/null +++ b/plugins/signals-node/src/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './SignalsService'; +export * from './types'; diff --git a/plugins/signals-node/src/setupTests.ts b/plugins/signals-node/src/setupTests.ts new file mode 100644 index 0000000000..4b9026cde5 --- /dev/null +++ b/plugins/signals-node/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export {}; diff --git a/plugins/signals-node/src/types.ts b/plugins/signals-node/src/types.ts new file mode 100644 index 0000000000..c53bfdb20e --- /dev/null +++ b/plugins/signals-node/src/types.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2023 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 { IdentityApi } from '@backstage/plugin-auth-node'; +import { EventBroker } from '@backstage/plugin-events-node'; +import { Logger } from 'winston'; +import { WebSocket } from 'ws'; + +/** + * @public + */ +export type ServiceOptions = { + eventBroker?: EventBroker; + logger: Logger; + identity: IdentityApi; +}; + +/** + * @internal + */ +export type SignalConnection = { + id: string; + user: string; + ws: WebSocket; + ownershipEntityRefs: string[]; + subscriptions: Set; +}; diff --git a/plugins/signals-react/.eslintrc.js b/plugins/signals-react/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/signals-react/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/signals-react/README.md b/plugins/signals-react/README.md new file mode 100644 index 0000000000..4b6b4e00bc --- /dev/null +++ b/plugins/signals-react/README.md @@ -0,0 +1,5 @@ +# @backstage/plugin-signals-react + +Welcome to the web library package for the signals plugin! + +_This plugin was created through the Backstage CLI_ diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md new file mode 100644 index 0000000000..14d78d4517 --- /dev/null +++ b/plugins/signals-react/api-report.md @@ -0,0 +1,45 @@ +## API Report File for "@backstage/plugin-signals-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ApiRef } from '@backstage/core-plugin-api'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { JSONObject } from '@apollo/explorer/src/helpers/types'; +import { JsonObject } from '@backstage/types'; + +// @public (undocumented) +export type SignalsApi = { + subscribe( + onMessage: (message: JsonObject, topic?: string) => void, + topic?: string, + ): void; + unsubscribe(topic?: string): void; +}; + +// @public (undocumented) +export const signalsApiRef: ApiRef; + +// @public (undocumented) +export class SignalsClient implements SignalsApi { + // (undocumented) + static create(options: { discoveryApi: DiscoveryApi }): SignalsClient; + // (undocumented) + static instance: SignalsClient | null; + // (undocumented) + subscribe( + onMessage: (message: JsonObject, topic?: string) => void, + topic?: string, + ): void; + // (undocumented) + unsubscribe(topic?: string): void; +} + +// @public (undocumented) +export const useSignalsApi: ( + onMessage: (message: JSONObject) => void, + topic?: string, +) => void; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/signals-react/catalog-info.yaml b/plugins/signals-react/catalog-info.yaml new file mode 100644 index 0000000000..ac8093ed0c --- /dev/null +++ b/plugins/signals-react/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-signals-react + title: '@backstage/plugin-signals-react' + description: Web library for the signals plugin +spec: + lifecycle: experimental + type: backstage-web-library + owner: maintainers diff --git a/plugins/signals-react/package.json b/plugins/signals-react/package.json new file mode 100644 index 0000000000..148bc27cb3 --- /dev/null +++ b/plugins/signals-react/package.json @@ -0,0 +1,43 @@ +{ + "name": "@backstage/plugin-signals-react", + "description": "Web library for the signals plugin", + "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": "web-library" + }, + "sideEffects": false, + "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" + }, + "dependencies": { + "@backstage/core-plugin-api": "workspace:^", + "@backstage/types": "workspace:^", + "@material-ui/core": "^4.9.13" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/signals-react/src/api/SignalsApi.ts b/plugins/signals-react/src/api/SignalsApi.ts new file mode 100644 index 0000000000..685cd560aa --- /dev/null +++ b/plugins/signals-react/src/api/SignalsApi.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2023 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 { createApiRef } from '@backstage/core-plugin-api'; +import { JsonObject } from '@backstage/types'; + +/** @public */ +export const signalsApiRef = createApiRef({ + id: 'plugin.signals.service', +}); + +/** @public */ +export type SignalsApi = { + subscribe( + onMessage: (message: JsonObject, topic?: string) => void, + topic?: string, + ): void; + + unsubscribe(topic?: string): void; +}; diff --git a/plugins/signals-react/src/api/SignalsClient.ts b/plugins/signals-react/src/api/SignalsClient.ts new file mode 100644 index 0000000000..71984a5c23 --- /dev/null +++ b/plugins/signals-react/src/api/SignalsClient.ts @@ -0,0 +1,133 @@ +/* + * Copyright 2023 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 { SignalsApi } from './SignalsApi'; +import { JsonObject } from '@backstage/types'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; + +/** @public */ +export class SignalsClient implements SignalsApi { + static instance: SignalsClient | null = null; + private ws: WebSocket | null = null; + private discoveryApi: DiscoveryApi; + private cbs: Map void> = + new Map(); + private queue: JsonObject[] = []; + private reconnectTimeout: any; + + static create(options: { discoveryApi: DiscoveryApi }) { + if (!SignalsClient.instance) { + SignalsClient.instance = new SignalsClient(options); + } + return SignalsClient.instance; + } + + private constructor(options: { discoveryApi: DiscoveryApi }) { + this.discoveryApi = options.discoveryApi; + } + + subscribe( + onMessage: (message: JsonObject, topic?: string) => void, + topic?: string, + ): void { + const subscriptionTopic = topic ?? '*'; + // Do not allow to subscribe to same topic multiple times + if (this.cbs.has(subscriptionTopic)) { + return; + } + + this.cbs.set(subscriptionTopic, onMessage); + this.connect().then(() => { + this.send({ action: 'subscribe', topic }); + }); + } + + unsubscribe(topic?: string): void { + const subscriptionTopic = topic ?? '*'; + this.cbs.delete(subscriptionTopic); + this.send({ action: 'unsubscribe', topic }); + } + + private send(data?: JsonObject): void { + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { + if (data) { + this.queue.push(data); + } + return; + } + + // First send queue + for (const msg of this.queue) { + this.ws!.send(JSON.stringify(msg)); + } + this.queue = []; + if (data) { + this.ws!.send(JSON.stringify(data)); + } + } + + private async connect() { + if (this.ws) { + return; + } + + const apiUrl = `${await this.discoveryApi.getBaseUrl('signals')}`; + const url = new URL(apiUrl); + url.protocol = url.protocol === 'http:' ? 'ws' : 'wss'; + this.ws = new WebSocket(url.toString()); + + this.ws.onmessage = (data: MessageEvent) => { + try { + const json = JSON.parse(data.data) as JsonObject; + let cb = this.cbs.get('*'); + if (json.topic) { + cb = this.cbs.get(json.topic as string); + } + if (cb) { + cb(json.message as JsonObject, json.topic as string); + } + } catch (e) { + // NOOP + } + }; + + this.ws.onerror = () => { + this.reconnect(); + }; + + this.ws.onclose = () => { + this.reconnect(); + }; + + while (this.ws.readyState !== WebSocket.OPEN) { + await new Promise(r => setTimeout(r, 10)); + } + this.send(); + } + + private reconnect() { + if (this.reconnectTimeout) { + clearTimeout(this.reconnectTimeout); + } + + this.reconnectTimeout = setTimeout(() => { + if (this.ws) { + this.ws.close(); + } + this.ws = null; + this.connect(); + }, 5000); + } +} diff --git a/plugins/signals-react/src/api/index.ts b/plugins/signals-react/src/api/index.ts new file mode 100644 index 0000000000..b8dea2af34 --- /dev/null +++ b/plugins/signals-react/src/api/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './SignalsApi'; +export * from './SignalsClient'; diff --git a/plugins/signals-react/src/hooks/index.ts b/plugins/signals-react/src/hooks/index.ts new file mode 100644 index 0000000000..0d5967f9eb --- /dev/null +++ b/plugins/signals-react/src/hooks/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './useSignalsApi'; diff --git a/plugins/signals-react/src/hooks/useSignalsApi.ts b/plugins/signals-react/src/hooks/useSignalsApi.ts new file mode 100644 index 0000000000..3bfbba5d71 --- /dev/null +++ b/plugins/signals-react/src/hooks/useSignalsApi.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2023 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 { SignalsClient } from '../api'; +import { discoveryApiRef, useApi } from '@backstage/core-plugin-api'; +import { JSONObject } from '@apollo/explorer/src/helpers/types'; +import { useEffect } from 'react'; + +/** @public */ +export const useSignalsApi = ( + onMessage: (message: JSONObject) => void, + topic?: string, +) => { + const discovery = useApi(discoveryApiRef); + const signals = SignalsClient.create({ discoveryApi: discovery }); + useEffect(() => { + signals.subscribe(onMessage, topic); + }, [signals, onMessage, topic]); + + useEffect(() => { + return () => { + signals.unsubscribe(topic); + }; + }, [signals, topic]); +}; diff --git a/plugins/signals-react/src/index.ts b/plugins/signals-react/src/index.ts new file mode 100644 index 0000000000..0f44901352 --- /dev/null +++ b/plugins/signals-react/src/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './api'; +export * from './hooks'; diff --git a/plugins/signals-react/src/setupTests.ts b/plugins/signals-react/src/setupTests.ts new file mode 100644 index 0000000000..865308e634 --- /dev/null +++ b/plugins/signals-react/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 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 '@testing-library/jest-dom'; diff --git a/yarn.lock b/yarn.lock index 2d59eecaac..cdd232b103 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,7 +12,7 @@ __metadata: languageName: node linkType: hard -"@adobe/css-tools@npm:^4.3.2": +"@adobe/css-tools@npm:^4.0.1, @adobe/css-tools@npm:^4.3.2": version: 4.3.2 resolution: "@adobe/css-tools@npm:4.3.2" checksum: 9667d61d55dc3b0a315c530ae84e016ce5267c4dd8ac00abb40108dc98e07b98e3090ce8b87acd51a41a68d9e84dcccb08cdf21c902572a9cf9dcaf830da4ae3 @@ -8833,6 +8833,66 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-signals-backend@workspace:^, @backstage/plugin-signals-backend@workspace:plugins/signals-backend": + version: 0.0.0-use.local + resolution: "@backstage/plugin-signals-backend@workspace:plugins/signals-backend" + dependencies: + "@backstage/backend-common": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/plugin-auth-node": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + "@backstage/plugin-signals-node": "workspace:^" + "@backstage/types": "workspace:^" + "@types/express": "*" + "@types/supertest": ^2.0.8 + express: ^4.17.1 + express-promise-router: ^4.1.0 + http-proxy-middleware: ^2.0.0 + msw: ^1.0.0 + node-fetch: ^2.6.7 + supertest: ^6.2.4 + uuid: ^8.0.0 + winston: ^3.2.1 + ws: ^8.14.2 + yn: ^4.0.0 + languageName: unknown + linkType: soft + +"@backstage/plugin-signals-node@workspace:^, @backstage/plugin-signals-node@workspace:plugins/signals-node": + version: 0.0.0-use.local + resolution: "@backstage/plugin-signals-node@workspace:plugins/signals-node" + dependencies: + "@backstage/backend-common": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/plugin-auth-node": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + "@backstage/types": "workspace:^" + "@types/express": ^4.17.21 + express: ^4.17.1 + uuid: ^8.0.0 + winston: ^3.2.1 + ws: ^8.14.2 + languageName: unknown + linkType: soft + +"@backstage/plugin-signals-react@workspace:plugins/signals-react": + version: 0.0.0-use.local + resolution: "@backstage/plugin-signals-react@workspace:plugins/signals-react" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/types": "workspace:^" + "@material-ui/core": ^4.9.13 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + languageName: unknown + linkType: soft + "@backstage/plugin-sonarqube-backend@workspace:^, @backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend": version: 0.0.0-use.local resolution: "@backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend" @@ -17125,6 +17185,22 @@ __metadata: languageName: unknown linkType: soft +"@testing-library/dom@npm:^8.0.0": + version: 8.20.1 + resolution: "@testing-library/dom@npm:8.20.1" + dependencies: + "@babel/code-frame": ^7.10.4 + "@babel/runtime": ^7.12.5 + "@types/aria-query": ^5.0.1 + aria-query: 5.1.3 + chalk: ^4.1.0 + dom-accessibility-api: ^0.5.9 + lz-string: ^1.5.0 + pretty-format: ^27.0.2 + checksum: 06fc8dc67849aadb726cbbad0e7546afdf8923bd39acb64c576d706249bd7d0d05f08e08a31913fb621162e3b9c2bd0dce15964437f030f9fa4476326fdd3007 + languageName: node + linkType: hard + "@testing-library/dom@npm:^9.0.0": version: 9.3.3 resolution: "@testing-library/dom@npm:9.3.3" @@ -17141,6 +17217,23 @@ __metadata: languageName: node linkType: hard +"@testing-library/jest-dom@npm:^5.10.1": + version: 5.17.0 + resolution: "@testing-library/jest-dom@npm:5.17.0" + dependencies: + "@adobe/css-tools": ^4.0.1 + "@babel/runtime": ^7.9.2 + "@types/testing-library__jest-dom": ^5.9.1 + aria-query: ^5.0.0 + chalk: ^3.0.0 + css.escape: ^1.5.1 + dom-accessibility-api: ^0.5.6 + lodash: ^4.17.15 + redent: ^3.0.0 + checksum: 9f28dbca8b50d7c306aae40c3aa8e06f0e115f740360004bd87d57f95acf7ab4b4f4122a7399a76dbf2bdaaafb15c99cc137fdcb0ae457a92e2de0f3fbf9b03b + languageName: node + linkType: hard + "@testing-library/jest-dom@npm:^6.0.0": version: 6.1.6 resolution: "@testing-library/jest-dom@npm:6.1.6" @@ -17193,6 +17286,20 @@ __metadata: languageName: node linkType: hard +"@testing-library/react@npm:^12.1.3": + version: 12.1.5 + resolution: "@testing-library/react@npm:12.1.5" + dependencies: + "@babel/runtime": ^7.12.5 + "@testing-library/dom": ^8.0.0 + "@types/react-dom": <18.0.0 + peerDependencies: + react: <18.0.0 + react-dom: <18.0.0 + checksum: 4abd0490405e709a7df584a0db604e508a4612398bb1326e8fa32dd9393b15badc826dcf6d2f7525437886d507871f719f127b9860ed69ddd204d1fa834f576a + languageName: node + linkType: hard + "@testing-library/react@npm:^14.0.0": version: 14.1.2 resolution: "@testing-library/react@npm:14.1.2" @@ -17884,7 +17991,7 @@ __metadata: languageName: node linkType: hard -"@types/express@npm:*, @types/express@npm:^4.17.13, @types/express@npm:^4.17.17, @types/express@npm:^4.17.6": +"@types/express@npm:*, @types/express@npm:^4.17.13, @types/express@npm:^4.17.17, @types/express@npm:^4.17.21, @types/express@npm:^4.17.6": version: 4.17.21 resolution: "@types/express@npm:4.17.21" dependencies: @@ -26588,6 +26695,8 @@ __metadata: "@backstage/plugin-search-backend-module-techdocs": "workspace:^" "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" + "@backstage/plugin-signals-backend": "workspace:^" + "@backstage/plugin-signals-node": "workspace:^" "@backstage/plugin-tech-insights-backend": "workspace:^" "@backstage/plugin-tech-insights-backend-module-jsonfc": "workspace:^" "@backstage/plugin-tech-insights-node": "workspace:^" @@ -44545,7 +44654,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:*, ws@npm:8.14.2, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.8.0": +"ws@npm:*, ws@npm:8.14.2, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.14.2, ws@npm:^8.8.0": version: 8.14.2 resolution: "ws@npm:8.14.2" peerDependencies: From 01d02b0d3b08f28fe69bfbe6b77a46cc234e24a3 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Mon, 4 Dec 2023 14:21:40 +0200 Subject: [PATCH 022/241] chore: make topic mandatory for signals Signed-off-by: Heikki Hellgren --- packages/backend/src/plugins/signals.ts | 2 +- .../Content/InfoContent/InfoContent.tsx | 2 +- plugins/signals-node/api-report.md | 4 +-- plugins/signals-node/src/SignalsService.ts | 27 +++++++++++---- plugins/signals-react/api-report.md | 13 +++---- plugins/signals-react/src/api/SignalsApi.ts | 4 +-- .../signals-react/src/api/SignalsClient.ts | 34 +++++++++---------- .../signals-react/src/hooks/useSignalsApi.ts | 2 +- 8 files changed, 48 insertions(+), 40 deletions(-) diff --git a/packages/backend/src/plugins/signals.ts b/packages/backend/src/plugins/signals.ts index 8e2d0b2d3f..dae2731c52 100644 --- a/packages/backend/src/plugins/signals.ts +++ b/packages/backend/src/plugins/signals.ts @@ -29,7 +29,7 @@ export default async function createPlugin( setInterval(() => { console.log('publishing'); - service.publish('*', { hello: 'world' }); + service.publish('*', 'devtools:info', { now: new Date().toISOString() }); }, 5000); return await createRouter({ diff --git a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx index 810a823027..adca500fad 100644 --- a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx @@ -77,7 +77,7 @@ export const InfoContent = () => { const { about, loading, error } = useInfo(); // Just testing for signals const [messages, setMessages] = React.useState([]); - useSignalsApi(message => { + useSignalsApi('devtools:info', message => { messages.push(JSON.stringify(message)); setMessages([...messages]); }); diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md index e8c9900908..15a6f67d87 100644 --- a/plugins/signals-node/api-report.md +++ b/plugins/signals-node/api-report.md @@ -29,15 +29,13 @@ export type SignalsEventBrokerPayload = { export class SignalsService implements EventSubscriber { // (undocumented) static create(options: ServiceOptions): SignalsService; - // (undocumented) handleUpgrade: (req: Request_2) => Promise; // (undocumented) onEvent(params: EventParams): Promise; - // (undocumented) publish( to: string | string[], + topic: string, message: JsonObject, - topic?: string, ): Promise; // (undocumented) supportsEventTopics(): string[]; diff --git a/plugins/signals-node/src/SignalsService.ts b/plugins/signals-node/src/SignalsService.ts index 6404386129..15a63e15d7 100644 --- a/plugins/signals-node/src/SignalsService.ts +++ b/plugins/signals-node/src/SignalsService.ts @@ -76,6 +76,11 @@ export class SignalsService implements EventSubscriber { this.eventBroker?.subscribe(this); } + /** + * Handles request upgradce to websocket and adds the connection to internal + * list for publish/subscribe functionality + * @param req - Request + */ handleUpgrade = async (req: Request) => { const identity = await this.identity.getIdentity({ request: req, @@ -157,23 +162,29 @@ export class SignalsService implements EventSubscriber { } } - async publish(to: string | string[], message: JsonObject, topic?: string) { + /** + * Publishes a message to user refs to specific topic + * @param to - string or array of user ref strings to publish message to + * @param topic - message topic + * @param message - message to publish + */ + async publish(to: string | string[], topic: string, message: JsonObject) { await this.publishInternal( Array.isArray(to) ? to : [to], + topic, message, false, - topic, ); } private async publishInternal( recipients: string[], + topic: string, message: JsonObject, brokedEvent: boolean, - topic?: string, ) { this.connections.forEach(conn => { - if (topic && !conn.subscriptions.has(topic)) { + if (!conn.subscriptions.has(topic)) { return; } // Sending to all users can be done with '*' @@ -208,15 +219,19 @@ export class SignalsService implements EventSubscriber { return; } - if (!eventPayload?.recipients || !eventPayload.message) { + if ( + !eventPayload?.recipients || + !eventPayload.topic || + !eventPayload.message + ) { return; } await this.publishInternal( eventPayload.recipients, + eventPayload.topic, eventPayload.message, true, - eventPayload.topic, ); } diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md index 14d78d4517..22e9306c14 100644 --- a/plugins/signals-react/api-report.md +++ b/plugins/signals-react/api-report.md @@ -12,9 +12,9 @@ import { JsonObject } from '@backstage/types'; export type SignalsApi = { subscribe( onMessage: (message: JsonObject, topic?: string) => void, - topic?: string, + topic: string, ): void; - unsubscribe(topic?: string): void; + unsubscribe(topic: string): void; }; // @public (undocumented) @@ -27,18 +27,15 @@ export class SignalsClient implements SignalsApi { // (undocumented) static instance: SignalsClient | null; // (undocumented) - subscribe( - onMessage: (message: JsonObject, topic?: string) => void, - topic?: string, - ): void; + subscribe(onMessage: (message: JsonObject) => void, topic: string): void; // (undocumented) - unsubscribe(topic?: string): void; + unsubscribe(topic: string): void; } // @public (undocumented) export const useSignalsApi: ( + topic: string, onMessage: (message: JSONObject) => void, - topic?: string, ) => void; // (No @packageDocumentation comment for this package) diff --git a/plugins/signals-react/src/api/SignalsApi.ts b/plugins/signals-react/src/api/SignalsApi.ts index 685cd560aa..28f9da39dc 100644 --- a/plugins/signals-react/src/api/SignalsApi.ts +++ b/plugins/signals-react/src/api/SignalsApi.ts @@ -25,8 +25,8 @@ export const signalsApiRef = createApiRef({ export type SignalsApi = { subscribe( onMessage: (message: JsonObject, topic?: string) => void, - topic?: string, + topic: string, ): void; - unsubscribe(topic?: string): void; + unsubscribe(topic: string): void; }; diff --git a/plugins/signals-react/src/api/SignalsClient.ts b/plugins/signals-react/src/api/SignalsClient.ts index 71984a5c23..cdfa7e5606 100644 --- a/plugins/signals-react/src/api/SignalsClient.ts +++ b/plugins/signals-react/src/api/SignalsClient.ts @@ -22,8 +22,7 @@ export class SignalsClient implements SignalsApi { static instance: SignalsClient | null = null; private ws: WebSocket | null = null; private discoveryApi: DiscoveryApi; - private cbs: Map void> = - new Map(); + private cbs: Map void> = new Map(); private queue: JsonObject[] = []; private reconnectTimeout: any; @@ -38,25 +37,20 @@ export class SignalsClient implements SignalsApi { this.discoveryApi = options.discoveryApi; } - subscribe( - onMessage: (message: JsonObject, topic?: string) => void, - topic?: string, - ): void { - const subscriptionTopic = topic ?? '*'; + subscribe(onMessage: (message: JsonObject) => void, topic: string): void { // Do not allow to subscribe to same topic multiple times - if (this.cbs.has(subscriptionTopic)) { + if (this.cbs.has(topic)) { return; } - this.cbs.set(subscriptionTopic, onMessage); + this.cbs.set(topic, onMessage); this.connect().then(() => { this.send({ action: 'subscribe', topic }); }); } - unsubscribe(topic?: string): void { - const subscriptionTopic = topic ?? '*'; - this.cbs.delete(subscriptionTopic); + unsubscribe(topic: string): void { + this.cbs.delete(topic); this.send({ action: 'unsubscribe', topic }); } @@ -91,12 +85,11 @@ export class SignalsClient implements SignalsApi { this.ws.onmessage = (data: MessageEvent) => { try { const json = JSON.parse(data.data) as JsonObject; - let cb = this.cbs.get('*'); if (json.topic) { - cb = this.cbs.get(json.topic as string); - } - if (cb) { - cb(json.message as JsonObject, json.topic as string); + const cb = this.cbs.get(json.topic as string); + if (cb) { + cb(json.message as JsonObject); + } } } catch (e) { // NOOP @@ -127,7 +120,12 @@ export class SignalsClient implements SignalsApi { this.ws.close(); } this.ws = null; - this.connect(); + this.connect().then(() => { + // Resubscribe to existing topics in case we lost connection + for (const topic of this.cbs.keys()) { + this.send({ action: 'subscribe', topic }); + } + }); }, 5000); } } diff --git a/plugins/signals-react/src/hooks/useSignalsApi.ts b/plugins/signals-react/src/hooks/useSignalsApi.ts index 3bfbba5d71..88112cebc7 100644 --- a/plugins/signals-react/src/hooks/useSignalsApi.ts +++ b/plugins/signals-react/src/hooks/useSignalsApi.ts @@ -20,8 +20,8 @@ import { useEffect } from 'react'; /** @public */ export const useSignalsApi = ( + topic: string, onMessage: (message: JSONObject) => void, - topic?: string, ) => { const discovery = useApi(discoveryApiRef); const signals = SignalsClient.create({ discoveryApi: discovery }); From 5e1a90daa2175e2ff44518b4bb8185c889f5563e Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Mon, 4 Dec 2023 15:00:02 +0200 Subject: [PATCH 023/241] chore: move signals client to fronend plugin Signed-off-by: Heikki Hellgren --- .changeset/real-eggs-sip.md | 1 + packages/app/package.json | 1 + packages/app/src/plugins.ts | 1 + plugins/signals-node/package.json | 4 +- plugins/signals-react/api-report.md | 16 +----- plugins/signals-react/src/api/index.ts | 1 - .../signals-react/src/hooks/useSignalsApi.ts | 11 ++-- plugins/signals/.eslintrc.js | 1 + plugins/signals/README.md | 13 +++++ plugins/signals/api-report.md | 27 ++++++++++ plugins/signals/catalog-info.yaml | 9 ++++ plugins/signals/dev/index.tsx | 35 +++++++++++++ plugins/signals/package.json | 52 +++++++++++++++++++ .../src/api/SignalsClient.ts | 2 +- plugins/signals/src/api/index.ts | 16 ++++++ plugins/signals/src/index.ts | 17 ++++++ plugins/signals/src/plugin.test.ts | 22 ++++++++ plugins/signals/src/plugin.ts | 39 ++++++++++++++ plugins/signals/src/setupTests.ts | 16 ++++++ yarn.lock | 27 ++++++++++ 20 files changed, 286 insertions(+), 25 deletions(-) create mode 100644 plugins/signals/.eslintrc.js create mode 100644 plugins/signals/README.md create mode 100644 plugins/signals/api-report.md create mode 100644 plugins/signals/catalog-info.yaml create mode 100644 plugins/signals/dev/index.tsx create mode 100644 plugins/signals/package.json rename plugins/{signals-react => signals}/src/api/SignalsClient.ts (98%) create mode 100644 plugins/signals/src/api/index.ts create mode 100644 plugins/signals/src/index.ts create mode 100644 plugins/signals/src/plugin.test.ts create mode 100644 plugins/signals/src/plugin.ts create mode 100644 plugins/signals/src/setupTests.ts diff --git a/.changeset/real-eggs-sip.md b/.changeset/real-eggs-sip.md index ca05205083..ca23d792f8 100644 --- a/.changeset/real-eggs-sip.md +++ b/.changeset/real-eggs-sip.md @@ -1,5 +1,6 @@ --- '@backstage/plugin-signals-backend': patch +'@backstage/plugin-signals': patch '@backstage/plugin-signals-react': patch '@backstage/plugin-signals-node': patch --- diff --git a/packages/app/package.json b/packages/app/package.json index c6ceafcf04..53a2b60a52 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -73,6 +73,7 @@ "@backstage/plugin-search-react": "workspace:^", "@backstage/plugin-sentry": "workspace:^", "@backstage/plugin-shortcuts": "workspace:^", + "@backstage/plugin-signals": "workspace:^", "@backstage/plugin-stack-overflow": "workspace:^", "@backstage/plugin-stackstorm": "workspace:^", "@backstage/plugin-tech-insights": "workspace:^", diff --git a/packages/app/src/plugins.ts b/packages/app/src/plugins.ts index 36f7a86acc..ddd12bea2c 100644 --- a/packages/app/src/plugins.ts +++ b/packages/app/src/plugins.ts @@ -19,3 +19,4 @@ export { badgesPlugin } from '@backstage/plugin-badges'; export { shortcutsPlugin } from '@backstage/plugin-shortcuts'; export { homePlugin } from '@backstage/plugin-home'; +export { signalsPlugin } from '@backstage/plugin-signals'; diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 66e4528678..2dc17f5e54 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -22,8 +22,7 @@ "postpack": "backstage-cli package postpack" }, "devDependencies": { - "@backstage/cli": "workspace:^", - "@types/express": "^4.17.21" + "@backstage/cli": "workspace:^" }, "files": [ "dist" @@ -34,6 +33,7 @@ "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-events-node": "workspace:^", "@backstage/types": "workspace:^", + "@types/express": "^4.17.21", "express": "^4.17.1", "uuid": "^8.0.0", "winston": "^3.2.1", diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md index 22e9306c14..0ab752be60 100644 --- a/plugins/signals-react/api-report.md +++ b/plugins/signals-react/api-report.md @@ -4,8 +4,6 @@ ```ts import { ApiRef } from '@backstage/core-plugin-api'; -import { DiscoveryApi } from '@backstage/core-plugin-api'; -import { JSONObject } from '@apollo/explorer/src/helpers/types'; import { JsonObject } from '@backstage/types'; // @public (undocumented) @@ -20,22 +18,10 @@ export type SignalsApi = { // @public (undocumented) export const signalsApiRef: ApiRef; -// @public (undocumented) -export class SignalsClient implements SignalsApi { - // (undocumented) - static create(options: { discoveryApi: DiscoveryApi }): SignalsClient; - // (undocumented) - static instance: SignalsClient | null; - // (undocumented) - subscribe(onMessage: (message: JsonObject) => void, topic: string): void; - // (undocumented) - unsubscribe(topic: string): void; -} - // @public (undocumented) export const useSignalsApi: ( topic: string, - onMessage: (message: JSONObject) => void, + onMessage: (message: JsonObject) => void, ) => void; // (No @packageDocumentation comment for this package) diff --git a/plugins/signals-react/src/api/index.ts b/plugins/signals-react/src/api/index.ts index b8dea2af34..9d5c4c5656 100644 --- a/plugins/signals-react/src/api/index.ts +++ b/plugins/signals-react/src/api/index.ts @@ -14,4 +14,3 @@ * limitations under the License. */ export * from './SignalsApi'; -export * from './SignalsClient'; diff --git a/plugins/signals-react/src/hooks/useSignalsApi.ts b/plugins/signals-react/src/hooks/useSignalsApi.ts index 88112cebc7..d97d80ed76 100644 --- a/plugins/signals-react/src/hooks/useSignalsApi.ts +++ b/plugins/signals-react/src/hooks/useSignalsApi.ts @@ -13,18 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { SignalsClient } from '../api'; -import { discoveryApiRef, useApi } from '@backstage/core-plugin-api'; -import { JSONObject } from '@apollo/explorer/src/helpers/types'; +import { signalsApiRef } from '../api'; +import { useApi } from '@backstage/core-plugin-api'; +import { JsonObject } from '@backstage/types'; import { useEffect } from 'react'; /** @public */ export const useSignalsApi = ( topic: string, - onMessage: (message: JSONObject) => void, + onMessage: (message: JsonObject) => void, ) => { - const discovery = useApi(discoveryApiRef); - const signals = SignalsClient.create({ discoveryApi: discovery }); + const signals = useApi(signalsApiRef); useEffect(() => { signals.subscribe(onMessage, topic); }, [signals, onMessage, topic]); diff --git a/plugins/signals/.eslintrc.js b/plugins/signals/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/signals/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/signals/README.md b/plugins/signals/README.md new file mode 100644 index 0000000000..604fa98a33 --- /dev/null +++ b/plugins/signals/README.md @@ -0,0 +1,13 @@ +# signals + +Welcome to the signals plugin! + +_This plugin was created through the Backstage CLI_ + +## Getting started + +Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/signals](http://localhost:3000/signals). + +You can also serve the plugin in isolation by running `yarn start` in the plugin directory. +This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. +It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. diff --git a/plugins/signals/api-report.md b/plugins/signals/api-report.md new file mode 100644 index 0000000000..d2dd111fe6 --- /dev/null +++ b/plugins/signals/api-report.md @@ -0,0 +1,27 @@ +## API Report File for "@backstage/plugin-signals" + +> 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 { DiscoveryApi } from '@backstage/core-plugin-api'; +import { JsonObject } from '@backstage/types'; +import { SignalsApi } from '@backstage/plugin-signals-react'; + +// @public (undocumented) +export class SignalsClient implements SignalsApi { + // (undocumented) + static create(options: { discoveryApi: DiscoveryApi }): SignalsClient; + // (undocumented) + static instance: SignalsClient | null; + // (undocumented) + subscribe(onMessage: (message: JsonObject) => void, topic: string): void; + // (undocumented) + unsubscribe(topic: string): void; +} + +// @public (undocumented) +export const signalsPlugin: BackstagePlugin<{}, {}>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/signals/catalog-info.yaml b/plugins/signals/catalog-info.yaml new file mode 100644 index 0000000000..ab52477147 --- /dev/null +++ b/plugins/signals/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-signals + title: '@backstage/plugin-signals' +spec: + lifecycle: experimental + type: backstage-frontend-plugin + owner: maintainers diff --git a/plugins/signals/dev/index.tsx b/plugins/signals/dev/index.tsx new file mode 100644 index 0000000000..e8c7928f57 --- /dev/null +++ b/plugins/signals/dev/index.tsx @@ -0,0 +1,35 @@ +/* + * Copyright 2023 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 { createDevApp } from '@backstage/dev-utils'; +import { signalsPlugin } from '../src/plugin'; +import { Content, Header, Page } from '@backstage/core-components'; +import { Typography } from '@material-ui/core'; + +createDevApp() + .registerPlugin(signalsPlugin) + .addPage({ + title: 'Debug', + element: ( + +
+ + TODO + + + ), + }) + .render(); diff --git a/plugins/signals/package.json b/plugins/signals/package.json new file mode 100644 index 0000000000..9c0bcb5c13 --- /dev/null +++ b/plugins/signals/package.json @@ -0,0 +1,52 @@ +{ + "name": "@backstage/plugin-signals", + "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" + }, + "sideEffects": false, + "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" + }, + "dependencies": { + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-signals-react": "workspace:^", + "@backstage/theme": "workspace:^", + "@backstage/types": "workspace:^", + "@material-ui/core": "^4.9.13", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.61", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "msw": "^1.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/signals-react/src/api/SignalsClient.ts b/plugins/signals/src/api/SignalsClient.ts similarity index 98% rename from plugins/signals-react/src/api/SignalsClient.ts rename to plugins/signals/src/api/SignalsClient.ts index cdfa7e5606..34ef557f31 100644 --- a/plugins/signals-react/src/api/SignalsClient.ts +++ b/plugins/signals/src/api/SignalsClient.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { SignalsApi } from './SignalsApi'; +import { SignalsApi } from '@backstage/plugin-signals-react'; import { JsonObject } from '@backstage/types'; import { DiscoveryApi } from '@backstage/core-plugin-api'; diff --git a/plugins/signals/src/api/index.ts b/plugins/signals/src/api/index.ts new file mode 100644 index 0000000000..80e69259af --- /dev/null +++ b/plugins/signals/src/api/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './SignalsClient'; diff --git a/plugins/signals/src/index.ts b/plugins/signals/src/index.ts new file mode 100644 index 0000000000..ddf8afb9c6 --- /dev/null +++ b/plugins/signals/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { signalsPlugin } from './plugin'; +export * from './api'; diff --git a/plugins/signals/src/plugin.test.ts b/plugins/signals/src/plugin.test.ts new file mode 100644 index 0000000000..cc8ecf44ed --- /dev/null +++ b/plugins/signals/src/plugin.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2023 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 { signalsPlugin } from './plugin'; + +describe('signals', () => { + it('should export plugin', () => { + expect(signalsPlugin).toBeDefined(); + }); +}); diff --git a/plugins/signals/src/plugin.ts b/plugins/signals/src/plugin.ts new file mode 100644 index 0000000000..457b3d9925 --- /dev/null +++ b/plugins/signals/src/plugin.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2023 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 { + createApiFactory, + createPlugin, + discoveryApiRef, +} from '@backstage/core-plugin-api'; +import { signalsApiRef } from '@backstage/plugin-signals-react'; +import { SignalsClient } from './api/SignalsClient'; + +/** @public */ +export const signalsPlugin = createPlugin({ + id: 'signals', + apis: [ + createApiFactory({ + api: signalsApiRef, + deps: { + discoveryApi: discoveryApiRef, + }, + factory: ({ discoveryApi }) => + SignalsClient.create({ + discoveryApi, + }), + }), + ], +}); diff --git a/plugins/signals/src/setupTests.ts b/plugins/signals/src/setupTests.ts new file mode 100644 index 0000000000..865308e634 --- /dev/null +++ b/plugins/signals/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 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 '@testing-library/jest-dom'; diff --git a/yarn.lock b/yarn.lock index cdd232b103..a6e69edc89 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8893,6 +8893,32 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-signals@workspace:^, @backstage/plugin-signals@workspace:plugins/signals": + version: 0.0.0-use.local + resolution: "@backstage/plugin-signals@workspace:plugins/signals" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/dev-utils": "workspace:^" + "@backstage/plugin-signals-react": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@backstage/types": "workspace:^" + "@material-ui/core": ^4.9.13 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": ^4.0.0-alpha.61 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + "@testing-library/user-event": ^14.0.0 + msw: ^1.0.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + languageName: unknown + linkType: soft + "@backstage/plugin-sonarqube-backend@workspace:^, @backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend": version: 0.0.0-use.local resolution: "@backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend" @@ -26556,6 +26582,7 @@ __metadata: "@backstage/plugin-search-react": "workspace:^" "@backstage/plugin-sentry": "workspace:^" "@backstage/plugin-shortcuts": "workspace:^" + "@backstage/plugin-signals": "workspace:^" "@backstage/plugin-stack-overflow": "workspace:^" "@backstage/plugin-stackstorm": "workspace:^" "@backstage/plugin-tech-insights": "workspace:^" From d05a6f566fde13de901659ffdcc232ce15bde3ef Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Tue, 5 Dec 2023 09:01:37 +0200 Subject: [PATCH 024/241] feat: allow multiple subscriptions to single topic + auth Signed-off-by: Heikki Hellgren --- plugins/signals-node/src/SignalsService.ts | 25 ++- plugins/signals-react/api-report.md | 4 +- plugins/signals-react/src/api/SignalsApi.ts | 4 +- .../signals-react/src/hooks/useSignalsApi.ts | 16 +- plugins/signals/api-report.md | 14 +- plugins/signals/package.json | 3 +- plugins/signals/src/api/SignalsClient.ts | 183 +++++++++++++----- plugins/signals/src/plugin.ts | 5 +- yarn.lock | 1 + 9 files changed, 187 insertions(+), 68 deletions(-) diff --git a/plugins/signals-node/src/SignalsService.ts b/plugins/signals-node/src/SignalsService.ts index 15a63e15d7..9cbe4b1565 100644 --- a/plugins/signals-node/src/SignalsService.ts +++ b/plugins/signals-node/src/SignalsService.ts @@ -28,6 +28,7 @@ import { JsonObject } from '@backstage/types'; import { BackstageIdentityResponse, IdentityApi, + IdentityApiGetIdentityRequest, } from '@backstage/plugin-auth-node'; /** @public */ @@ -160,6 +161,23 @@ export class SignalsService implements EventSubscriber { ); connection.subscriptions.delete(message.topic as string); } + + if (message.action === 'authenticate' && message.token) { + this.logger.info(`Connection ${connection.id} authenticated`); + this.identity + .getIdentity({ + request: { + headers: { authorization: message.token }, + }, + } as IdentityApiGetIdentityRequest) + .then(identity => { + if (identity) { + connection.user = identity.identity.userEntityRef; + connection.ownershipEntityRefs = + identity.identity.ownershipEntityRefs; + } + }); + } } /** @@ -183,6 +201,11 @@ export class SignalsService implements EventSubscriber { message: JsonObject, brokedEvent: boolean, ) { + const jsonMessage = JSON.stringify({ topic, message }); + if (jsonMessage.length === 0) { + return; + } + this.connections.forEach(conn => { if (!conn.subscriptions.has(topic)) { return; @@ -194,7 +217,7 @@ export class SignalsService implements EventSubscriber { ) { return; } - conn.ws.send(JSON.stringify({ topic, message })); + conn.ws.send(jsonMessage); }); // If this event has not been broadcasted to all servers, then use diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md index 0ab752be60..75aeb5d77d 100644 --- a/plugins/signals-react/api-report.md +++ b/plugins/signals-react/api-report.md @@ -11,8 +11,8 @@ export type SignalsApi = { subscribe( onMessage: (message: JsonObject, topic?: string) => void, topic: string, - ): void; - unsubscribe(topic: string): void; + ): string; + unsubscribe(subscription: string): void; }; // @public (undocumented) diff --git a/plugins/signals-react/src/api/SignalsApi.ts b/plugins/signals-react/src/api/SignalsApi.ts index 28f9da39dc..e592b56df0 100644 --- a/plugins/signals-react/src/api/SignalsApi.ts +++ b/plugins/signals-react/src/api/SignalsApi.ts @@ -26,7 +26,7 @@ export type SignalsApi = { subscribe( onMessage: (message: JsonObject, topic?: string) => void, topic: string, - ): void; + ): string; - unsubscribe(topic: string): void; + unsubscribe(subscription: string): void; }; diff --git a/plugins/signals-react/src/hooks/useSignalsApi.ts b/plugins/signals-react/src/hooks/useSignalsApi.ts index d97d80ed76..327ca08ff9 100644 --- a/plugins/signals-react/src/hooks/useSignalsApi.ts +++ b/plugins/signals-react/src/hooks/useSignalsApi.ts @@ -16,7 +16,7 @@ import { signalsApiRef } from '../api'; import { useApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; /** @public */ export const useSignalsApi = ( @@ -24,13 +24,19 @@ export const useSignalsApi = ( onMessage: (message: JsonObject) => void, ) => { const signals = useApi(signalsApiRef); + const [subscription, setSubscription] = useState(null); useEffect(() => { - signals.subscribe(onMessage, topic); - }, [signals, onMessage, topic]); + if (!subscription) { + const sub = signals.subscribe(onMessage, topic); + setSubscription(sub); + } + }, [subscription, signals, onMessage, topic]); useEffect(() => { return () => { - signals.unsubscribe(topic); + if (subscription) { + signals.unsubscribe(subscription); + } }; - }, [signals, topic]); + }, [subscription, signals, topic]); }; diff --git a/plugins/signals/api-report.md b/plugins/signals/api-report.md index d2dd111fe6..2c9777a5c0 100644 --- a/plugins/signals/api-report.md +++ b/plugins/signals/api-report.md @@ -5,19 +5,25 @@ ```ts import { BackstagePlugin } from '@backstage/core-plugin-api'; import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { IdentityApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { SignalsApi } from '@backstage/plugin-signals-react'; // @public (undocumented) export class SignalsClient implements SignalsApi { // (undocumented) - static create(options: { discoveryApi: DiscoveryApi }): SignalsClient; + static readonly CONNECT_TIMEOUT_MS: number; // (undocumented) - static instance: SignalsClient | null; + static create(options: { + identity: IdentityApi; + discoveryApi: DiscoveryApi; + }): SignalsClient; // (undocumented) - subscribe(onMessage: (message: JsonObject) => void, topic: string): void; + static readonly RECONNECT_TIMEOUT_MS: number; // (undocumented) - unsubscribe(topic: string): void; + subscribe(onMessage: (message: JsonObject) => void, topic: string): string; + // (undocumented) + unsubscribe(subscription: string): void; } // @public (undocumented) diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 9c0bcb5c13..35ffc8e212 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -31,7 +31,8 @@ "@material-ui/core": "^4.9.13", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", - "react-use": "^17.2.4" + "react-use": "^17.2.4", + "uuid": "^8.0.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0" diff --git a/plugins/signals/src/api/SignalsClient.ts b/plugins/signals/src/api/SignalsClient.ts index 34ef557f31..cc1254578f 100644 --- a/plugins/signals/src/api/SignalsClient.ts +++ b/plugins/signals/src/api/SignalsClient.ts @@ -15,60 +15,105 @@ */ import { SignalsApi } from '@backstage/plugin-signals-react'; import { JsonObject } from '@backstage/types'; -import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; +import { v4 as uuid } from 'uuid'; + +/** @internal */ +type Subscription = { + topic: string; + callback: (message: JsonObject) => void; +}; + +/** @internal */ +const WS_CLOSE_NORMAL = 1000; +/** @internal */ +const WS_CLOSE_GOING_AWAY = 1001; /** @public */ export class SignalsClient implements SignalsApi { - static instance: SignalsClient | null = null; + static readonly CONNECT_TIMEOUT_MS: number = 1000; + static readonly RECONNECT_TIMEOUT_MS: number = 5000; private ws: WebSocket | null = null; - private discoveryApi: DiscoveryApi; - private cbs: Map void> = new Map(); - private queue: JsonObject[] = []; + private subscriptions: Map = new Map(); + private messageQueue: string[] = []; private reconnectTimeout: any; - static create(options: { discoveryApi: DiscoveryApi }) { - if (!SignalsClient.instance) { - SignalsClient.instance = new SignalsClient(options); - } - return SignalsClient.instance; + static create(options: { + identity: IdentityApi; + discoveryApi: DiscoveryApi; + }) { + const { identity, discoveryApi } = options; + return new SignalsClient(identity, discoveryApi); } - private constructor(options: { discoveryApi: DiscoveryApi }) { - this.discoveryApi = options.discoveryApi; + private constructor( + private identity: IdentityApi, + private discoveryApi: DiscoveryApi, + ) {} + + subscribe(onMessage: (message: JsonObject) => void, topic: string): string { + const subscriptionId = uuid(); + const exists = [...this.subscriptions.values()].find( + sub => sub.topic === topic, + ); + this.subscriptions.set(subscriptionId, { topic, callback: onMessage }); + + this.connect() + .then(() => { + // Do not subscribe twice to same topic even there is multiple callbacks + if (!exists) { + this.send({ action: 'subscribe', topic }); + } + }) + .catch(() => { + this.reconnect(); + }); + return subscriptionId; } - subscribe(onMessage: (message: JsonObject) => void, topic: string): void { - // Do not allow to subscribe to same topic multiple times - if (this.cbs.has(topic)) { + unsubscribe(subscription: string): void { + const sub = this.subscriptions.get(subscription); + if (!sub) { return; } + const topic = sub.topic; + this.subscriptions.delete(subscription); + const exists = [...this.subscriptions.values()].find( + s => s.topic === topic, + ); + // If there are subscriptions still listening to this topic, do not + // unsubscribe from the server + if (!exists) { + this.send({ action: 'unsubscribe', topic: sub.topic }); + } - this.cbs.set(topic, onMessage); - this.connect().then(() => { - this.send({ action: 'subscribe', topic }); - }); - } - - unsubscribe(topic: string): void { - this.cbs.delete(topic); - this.send({ action: 'unsubscribe', topic }); + // If there are no subscriptions, close the connection + if (this.subscriptions.size === 0) { + this.ws?.close(WS_CLOSE_NORMAL); + this.ws = null; + } } private send(data?: JsonObject): void { + const jsonMessage = JSON.stringify(data); + if (jsonMessage.length === 0) { + return; + } + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { if (data) { - this.queue.push(data); + this.messageQueue.unshift(jsonMessage); } return; } // First send queue - for (const msg of this.queue) { - this.ws!.send(JSON.stringify(msg)); + for (const msg of this.messageQueue) { + this.ws!.send(msg); } - this.queue = []; + this.messageQueue = []; if (data) { - this.ws!.send(JSON.stringify(data)); + this.ws!.send(jsonMessage); } } @@ -83,31 +128,60 @@ export class SignalsClient implements SignalsApi { this.ws = new WebSocket(url.toString()); this.ws.onmessage = (data: MessageEvent) => { - try { - const json = JSON.parse(data.data) as JsonObject; - if (json.topic) { - const cb = this.cbs.get(json.topic as string); - if (cb) { - cb(json.message as JsonObject); - } - } - } catch (e) { - // NOOP - } + this.handleMessage(data); }; this.ws.onerror = () => { this.reconnect(); }; - this.ws.onclose = () => { - this.reconnect(); + this.ws.onclose = (ev: CloseEvent) => { + if (ev.code !== WS_CLOSE_NORMAL && ev.code !== WS_CLOSE_GOING_AWAY) { + this.reconnect(); + } }; - while (this.ws.readyState !== WebSocket.OPEN) { - await new Promise(r => setTimeout(r, 10)); + // Wait until connection is open + let connectSleep = 0; + while ( + this.ws && + this.ws.readyState !== WebSocket.OPEN && + connectSleep < SignalsClient.CONNECT_TIMEOUT_MS + ) { + await new Promise(r => setTimeout(r, 100)); + connectSleep += 100; + } + + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { + throw new Error('Connect timeout'); + } + + // Authenticate + await this.authenticate(); + } + + private handleMessage(data: MessageEvent) { + try { + const json = JSON.parse(data.data) as JsonObject; + if (json.topic) { + for (const sub of this.subscriptions.values()) { + if (sub.topic === json.topic) { + sub.callback(json.message as JsonObject); + } + } + } + } catch (e) { + // NOOP + } + } + + private async authenticate() { + const { token } = await this.identity.getCredentials(); + if (token) { + // Authentication is done with websocket message to server as the plain + // websocket does not allow sending headers during connection upgrade + this.send({ action: 'authenticate', token: token }); } - this.send(); } private reconnect() { @@ -116,16 +190,21 @@ export class SignalsClient implements SignalsApi { } this.reconnectTimeout = setTimeout(() => { + this.reconnectTimeout = null; if (this.ws) { this.ws.close(); } this.ws = null; - this.connect().then(() => { - // Resubscribe to existing topics in case we lost connection - for (const topic of this.cbs.keys()) { - this.send({ action: 'subscribe', topic }); - } - }); - }, 5000); + this.connect() + .then(() => { + // Resubscribe to existing topics in case we lost connection + for (const topic of this.subscriptions.keys()) { + this.send({ action: 'subscribe', topic }); + } + }) + .catch(() => { + this.reconnect(); + }); + }, SignalsClient.RECONNECT_TIMEOUT_MS); } } diff --git a/plugins/signals/src/plugin.ts b/plugins/signals/src/plugin.ts index 457b3d9925..d1b0311116 100644 --- a/plugins/signals/src/plugin.ts +++ b/plugins/signals/src/plugin.ts @@ -17,6 +17,7 @@ import { createApiFactory, createPlugin, discoveryApiRef, + identityApiRef, } from '@backstage/core-plugin-api'; import { signalsApiRef } from '@backstage/plugin-signals-react'; import { SignalsClient } from './api/SignalsClient'; @@ -28,10 +29,12 @@ export const signalsPlugin = createPlugin({ createApiFactory({ api: signalsApiRef, deps: { + identity: identityApiRef, discoveryApi: discoveryApiRef, }, - factory: ({ discoveryApi }) => + factory: ({ identity, discoveryApi }) => SignalsClient.create({ + identity, discoveryApi, }), }), diff --git a/yarn.lock b/yarn.lock index a6e69edc89..c89f106c57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8914,6 +8914,7 @@ __metadata: "@testing-library/user-event": ^14.0.0 msw: ^1.0.0 react-use: ^17.2.4 + uuid: ^8.0.0 peerDependencies: react: ^16.13.1 || ^17.0.0 languageName: unknown From 7af9750ea8f9d7bf815ffe21565f50f993700368 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Tue, 5 Dec 2023 09:19:50 +0200 Subject: [PATCH 025/241] feat: use websocket header to pass the auth token Signed-off-by: Heikki Hellgren --- plugins/signals-node/src/SignalsService.ts | 45 ++++++++-------------- plugins/signals-node/src/types.ts | 8 ++++ plugins/signals/src/api/SignalsClient.ts | 16 ++------ 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/plugins/signals-node/src/SignalsService.ts b/plugins/signals-node/src/SignalsService.ts index 9cbe4b1565..6a1547a6bb 100644 --- a/plugins/signals-node/src/SignalsService.ts +++ b/plugins/signals-node/src/SignalsService.ts @@ -19,7 +19,11 @@ import { EventSubscriber, } from '@backstage/plugin-events-node'; import { Logger } from 'winston'; -import { ServiceOptions, SignalConnection } from './types'; +import { + ServiceOptions, + SignalConnection, + SignalsEventBrokerPayload, +} from './types'; import { RawData, WebSocket, WebSocketServer } from 'ws'; import { IncomingMessage } from 'http'; import { v4 as uuid } from 'uuid'; @@ -31,13 +35,6 @@ import { IdentityApiGetIdentityRequest, } from '@backstage/plugin-auth-node'; -/** @public */ -export type SignalsEventBrokerPayload = { - recipients?: string[]; - topic?: string; - message?: JsonObject; -}; - /** @public */ export class SignalsService implements EventSubscriber { private readonly serverId: string; @@ -83,9 +80,18 @@ export class SignalsService implements EventSubscriber { * @param req - Request */ handleUpgrade = async (req: Request) => { - const identity = await this.identity.getIdentity({ - request: req, - }); + let identity: BackstageIdentityResponse | undefined = undefined; + + // Authentication token is passed in Sec-WebSocket-Protocol header as there + // is no other way to pass the token with plain websockets + const token = req.headers['sec-websocket-protocol']; + if (token) { + identity = await this.identity.getIdentity({ + request: { + headers: { authorization: token }, + }, + } as IdentityApiGetIdentityRequest); + } this.server.handleUpgrade( req, @@ -161,23 +167,6 @@ export class SignalsService implements EventSubscriber { ); connection.subscriptions.delete(message.topic as string); } - - if (message.action === 'authenticate' && message.token) { - this.logger.info(`Connection ${connection.id} authenticated`); - this.identity - .getIdentity({ - request: { - headers: { authorization: message.token }, - }, - } as IdentityApiGetIdentityRequest) - .then(identity => { - if (identity) { - connection.user = identity.identity.userEntityRef; - connection.ownershipEntityRefs = - identity.identity.ownershipEntityRefs; - } - }); - } } /** diff --git a/plugins/signals-node/src/types.ts b/plugins/signals-node/src/types.ts index c53bfdb20e..090e4b2ff1 100644 --- a/plugins/signals-node/src/types.ts +++ b/plugins/signals-node/src/types.ts @@ -17,6 +17,7 @@ import { IdentityApi } from '@backstage/plugin-auth-node'; import { EventBroker } from '@backstage/plugin-events-node'; import { Logger } from 'winston'; import { WebSocket } from 'ws'; +import { JsonObject } from '@backstage/types'; /** * @public @@ -27,6 +28,13 @@ export type ServiceOptions = { identity: IdentityApi; }; +/** @public */ +export type SignalsEventBrokerPayload = { + recipients?: string[]; + topic?: string; + message?: JsonObject; +}; + /** * @internal */ diff --git a/plugins/signals/src/api/SignalsClient.ts b/plugins/signals/src/api/SignalsClient.ts index cc1254578f..d8d3328411 100644 --- a/plugins/signals/src/api/SignalsClient.ts +++ b/plugins/signals/src/api/SignalsClient.ts @@ -123,9 +123,11 @@ export class SignalsClient implements SignalsApi { } const apiUrl = `${await this.discoveryApi.getBaseUrl('signals')}`; + const { token } = await this.identity.getCredentials(); + const url = new URL(apiUrl); url.protocol = url.protocol === 'http:' ? 'ws' : 'wss'; - this.ws = new WebSocket(url.toString()); + this.ws = new WebSocket(url.toString(), token); this.ws.onmessage = (data: MessageEvent) => { this.handleMessage(data); @@ -155,9 +157,6 @@ export class SignalsClient implements SignalsApi { if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { throw new Error('Connect timeout'); } - - // Authenticate - await this.authenticate(); } private handleMessage(data: MessageEvent) { @@ -175,15 +174,6 @@ export class SignalsClient implements SignalsApi { } } - private async authenticate() { - const { token } = await this.identity.getCredentials(); - if (token) { - // Authentication is done with websocket message to server as the plain - // websocket does not allow sending headers during connection upgrade - this.send({ action: 'authenticate', token: token }); - } - } - private reconnect() { if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout); From 8fbabdc2cbb5cfe5c0777fb8d9cac9e9739f00f8 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Tue, 5 Dec 2023 09:31:46 +0200 Subject: [PATCH 026/241] chore: add check for connection status before sending Signed-off-by: Heikki Hellgren --- plugins/signals-node/src/SignalsService.ts | 5 +++++ plugins/signals/src/api/SignalsClient.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/signals-node/src/SignalsService.ts b/plugins/signals-node/src/SignalsService.ts index 6a1547a6bb..c743c958dd 100644 --- a/plugins/signals-node/src/SignalsService.ts +++ b/plugins/signals-node/src/SignalsService.ts @@ -206,6 +206,11 @@ export class SignalsService implements EventSubscriber { ) { return; } + + if (conn.ws.readyState !== WebSocket.OPEN) { + return; + } + conn.ws.send(jsonMessage); }); diff --git a/plugins/signals/src/api/SignalsClient.ts b/plugins/signals/src/api/SignalsClient.ts index d8d3328411..1fbe374ad9 100644 --- a/plugins/signals/src/api/SignalsClient.ts +++ b/plugins/signals/src/api/SignalsClient.ts @@ -126,7 +126,7 @@ export class SignalsClient implements SignalsApi { const { token } = await this.identity.getCredentials(); const url = new URL(apiUrl); - url.protocol = url.protocol === 'http:' ? 'ws' : 'wss'; + url.protocol = url.protocol === 'http:' ? 'ws:' : 'wss:'; this.ws = new WebSocket(url.toString(), token); this.ws.onmessage = (data: MessageEvent) => { From db84649e81ce0b6e8128314afcca6435d0b69d97 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Tue, 5 Dec 2023 10:40:48 +0200 Subject: [PATCH 027/241] test: add tests for signals client Signed-off-by: Heikki Hellgren --- plugins/signals-react/api-report.md | 5 +- plugins/signals-react/src/api/SignalsApi.ts | 5 +- .../signals-react/src/hooks/useSignalsApi.ts | 2 +- plugins/signals/api-report.md | 10 +- plugins/signals/package.json | 1 + plugins/signals/src/api/SignalsClient.test.ts | 119 ++++++++++++++++++ plugins/signals/src/api/SignalsClient.ts | 46 ++++--- yarn.lock | 1 + 8 files changed, 160 insertions(+), 29 deletions(-) create mode 100644 plugins/signals/src/api/SignalsClient.test.ts diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md index 75aeb5d77d..21f070c35d 100644 --- a/plugins/signals-react/api-report.md +++ b/plugins/signals-react/api-report.md @@ -8,10 +8,7 @@ import { JsonObject } from '@backstage/types'; // @public (undocumented) export type SignalsApi = { - subscribe( - onMessage: (message: JsonObject, topic?: string) => void, - topic: string, - ): string; + subscribe(topic: string, onMessage: (message: JsonObject) => void): string; unsubscribe(subscription: string): void; }; diff --git a/plugins/signals-react/src/api/SignalsApi.ts b/plugins/signals-react/src/api/SignalsApi.ts index e592b56df0..2aefa5d166 100644 --- a/plugins/signals-react/src/api/SignalsApi.ts +++ b/plugins/signals-react/src/api/SignalsApi.ts @@ -23,10 +23,7 @@ export const signalsApiRef = createApiRef({ /** @public */ export type SignalsApi = { - subscribe( - onMessage: (message: JsonObject, topic?: string) => void, - topic: string, - ): string; + subscribe(topic: string, onMessage: (message: JsonObject) => void): string; unsubscribe(subscription: string): void; }; diff --git a/plugins/signals-react/src/hooks/useSignalsApi.ts b/plugins/signals-react/src/hooks/useSignalsApi.ts index 327ca08ff9..0fcc69efed 100644 --- a/plugins/signals-react/src/hooks/useSignalsApi.ts +++ b/plugins/signals-react/src/hooks/useSignalsApi.ts @@ -27,7 +27,7 @@ export const useSignalsApi = ( const [subscription, setSubscription] = useState(null); useEffect(() => { if (!subscription) { - const sub = signals.subscribe(onMessage, topic); + const sub = signals.subscribe(topic, onMessage); setSubscription(sub); } }, [subscription, signals, onMessage, topic]); diff --git a/plugins/signals/api-report.md b/plugins/signals/api-report.md index 2c9777a5c0..08c52ef418 100644 --- a/plugins/signals/api-report.md +++ b/plugins/signals/api-report.md @@ -11,17 +11,19 @@ import { SignalsApi } from '@backstage/plugin-signals-react'; // @public (undocumented) export class SignalsClient implements SignalsApi { - // (undocumented) - static readonly CONNECT_TIMEOUT_MS: number; // (undocumented) static create(options: { identity: IdentityApi; discoveryApi: DiscoveryApi; + connectTimeout?: number; + reconnectTimeout?: number; }): SignalsClient; // (undocumented) - static readonly RECONNECT_TIMEOUT_MS: number; + static readonly DEFAULT_CONNECT_TIMEOUT_MS: number; // (undocumented) - subscribe(onMessage: (message: JsonObject) => void, topic: string): string; + static readonly DEFAULT_RECONNECT_TIMEOUT_MS: number; + // (undocumented) + subscribe(topic: string, onMessage: (message: JsonObject) => void): string; // (undocumented) unsubscribe(subscription: string): void; } diff --git a/plugins/signals/package.json b/plugins/signals/package.json index 35ffc8e212..e708d46329 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -45,6 +45,7 @@ "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", + "jest-websocket-mock": "^2.5.0", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/signals/src/api/SignalsClient.test.ts b/plugins/signals/src/api/SignalsClient.test.ts new file mode 100644 index 0000000000..03b25d580d --- /dev/null +++ b/plugins/signals/src/api/SignalsClient.test.ts @@ -0,0 +1,119 @@ +/* + * Copyright 2023 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 { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; +import WS from 'jest-websocket-mock'; +import { SignalsClient } from './SignalsClient'; + +describe('SignalsClient', () => { + const tokenFunction = jest.fn(); + const baseUrlFunction = jest.fn(); + const identity = { + getCredentials: tokenFunction, + } as unknown as IdentityApi; + const discoveryApi = { + getBaseUrl: baseUrlFunction, + } as unknown as DiscoveryApi; + + let server: WS; + + beforeEach(async () => { + jest.resetAllMocks(); + tokenFunction.mockResolvedValue({ token: '12345' }); + baseUrlFunction.mockResolvedValue('http://localhost:1234'); + server = new WS('ws://localhost:1234', { jsonProtocol: true }); + }); + + afterEach(() => { + WS.clean(); + }); + + it('should handle single subscription correctly', async () => { + const messageMock = jest.fn(); + const client = SignalsClient.create({ discoveryApi, identity }); + const sub = client.subscribe('topic', messageMock); + await server.connected; + + await expect(server).toReceiveMessage({ + action: 'subscribe', + topic: 'topic', + }); + server.send({ topic: 'topic', message: { hello: 'world' } }); + expect(messageMock).toHaveBeenCalledWith({ hello: 'world' }); + + client.unsubscribe(sub); + await expect(server).toReceiveMessage({ + action: 'unsubscribe', + topic: 'topic', + }); + }); + + it('should handle multiple subscription correctly', async () => { + const messageMock1 = jest.fn(); + const messageMock2 = jest.fn(); + const client1 = SignalsClient.create({ discoveryApi, identity }); + const client2 = SignalsClient.create({ discoveryApi, identity }); + const sub1 = client1.subscribe('topic', messageMock1); + const sub2 = client2.subscribe('topic', messageMock2); + + await server.connected; + + await expect(server).toReceiveMessage({ + action: 'subscribe', + topic: 'topic', + }); + server.send({ topic: 'topic', message: { hello: 'world' } }); + expect(messageMock1).toHaveBeenCalledWith({ hello: 'world' }); + expect(messageMock2).toHaveBeenCalledWith({ hello: 'world' }); + + client1.unsubscribe(sub1); + await expect(server).not.toReceiveMessage({ + action: 'unsubscribe', + topic: 'topic', + }); + + client2.unsubscribe(sub2); + await expect(server).toReceiveMessage({ + action: 'unsubscribe', + topic: 'topic', + }); + }); + + it('should reconnect on error', async () => { + const messageMock = jest.fn(); + const client = SignalsClient.create({ + discoveryApi, + identity, + reconnectTimeout: 10, + connectTimeout: 100, + }); + + client.subscribe('topic', messageMock); + await server.connected; + await expect(server).toReceiveMessage({ + action: 'subscribe', + topic: 'topic', + }); + + await server.server.emit('error', null); + + await new Promise(r => setTimeout(r, 50)); + await expect(server).toReceiveMessage({ + action: 'subscribe', + topic: 'topic', + }); + }); +}); diff --git a/plugins/signals/src/api/SignalsClient.ts b/plugins/signals/src/api/SignalsClient.ts index 1fbe374ad9..4051468a9e 100644 --- a/plugins/signals/src/api/SignalsClient.ts +++ b/plugins/signals/src/api/SignalsClient.ts @@ -31,27 +31,41 @@ const WS_CLOSE_GOING_AWAY = 1001; /** @public */ export class SignalsClient implements SignalsApi { - static readonly CONNECT_TIMEOUT_MS: number = 1000; - static readonly RECONNECT_TIMEOUT_MS: number = 5000; + static readonly DEFAULT_CONNECT_TIMEOUT_MS: number = 1000; + static readonly DEFAULT_RECONNECT_TIMEOUT_MS: number = 5000; private ws: WebSocket | null = null; private subscriptions: Map = new Map(); private messageQueue: string[] = []; - private reconnectTimeout: any; + private reconnectTo: any; static create(options: { identity: IdentityApi; discoveryApi: DiscoveryApi; + connectTimeout?: number; + reconnectTimeout?: number; }) { - const { identity, discoveryApi } = options; - return new SignalsClient(identity, discoveryApi); + const { + identity, + discoveryApi, + connectTimeout = SignalsClient.DEFAULT_CONNECT_TIMEOUT_MS, + reconnectTimeout = SignalsClient.DEFAULT_RECONNECT_TIMEOUT_MS, + } = options; + return new SignalsClient( + identity, + discoveryApi, + connectTimeout, + reconnectTimeout, + ); } private constructor( private identity: IdentityApi, private discoveryApi: DiscoveryApi, + private connectTimeout: number, + private reconnectTimeout: number, ) {} - subscribe(onMessage: (message: JsonObject) => void, topic: string): string { + subscribe(topic: string, onMessage: (message: JsonObject) => void): string { const subscriptionId = uuid(); const exists = [...this.subscriptions.values()].find( sub => sub.topic === topic, @@ -118,11 +132,11 @@ export class SignalsClient implements SignalsApi { } private async connect() { - if (this.ws) { + if (this.ws && this.ws.readyState === WebSocket.OPEN) { return; } - const apiUrl = `${await this.discoveryApi.getBaseUrl('signals')}`; + const apiUrl = await this.discoveryApi.getBaseUrl('signals'); const { token } = await this.identity.getCredentials(); const url = new URL(apiUrl); @@ -148,7 +162,7 @@ export class SignalsClient implements SignalsApi { while ( this.ws && this.ws.readyState !== WebSocket.OPEN && - connectSleep < SignalsClient.CONNECT_TIMEOUT_MS + connectSleep < this.connectTimeout ) { await new Promise(r => setTimeout(r, 100)); connectSleep += 100; @@ -175,12 +189,12 @@ export class SignalsClient implements SignalsApi { } private reconnect() { - if (this.reconnectTimeout) { - clearTimeout(this.reconnectTimeout); + if (this.reconnectTo) { + clearTimeout(this.reconnectTo); } - this.reconnectTimeout = setTimeout(() => { - this.reconnectTimeout = null; + this.reconnectTo = setTimeout(() => { + this.reconnectTo = null; if (this.ws) { this.ws.close(); } @@ -188,13 +202,13 @@ export class SignalsClient implements SignalsApi { this.connect() .then(() => { // Resubscribe to existing topics in case we lost connection - for (const topic of this.subscriptions.keys()) { - this.send({ action: 'subscribe', topic }); + for (const sub of this.subscriptions.values()) { + this.send({ action: 'subscribe', topic: sub.topic }); } }) .catch(() => { this.reconnect(); }); - }, SignalsClient.RECONNECT_TIMEOUT_MS); + }, this.reconnectTimeout); } } diff --git a/yarn.lock b/yarn.lock index c89f106c57..d44cfeab72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8912,6 +8912,7 @@ __metadata: "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/user-event": ^14.0.0 + jest-websocket-mock: ^2.5.0 msw: ^1.0.0 react-use: ^17.2.4 uuid: ^8.0.0 From 59a4508efeceed5f3e821053a1305b60ea725328 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Tue, 5 Dec 2023 15:35:36 +0200 Subject: [PATCH 028/241] feat: update devtools almost real time using signals Signed-off-by: Heikki Hellgren --- .changeset/poor-sheep-tease.md | 6 ++++ packages/backend/src/index.ts | 7 ++++ packages/backend/src/plugins/devtools.ts | 1 + packages/backend/src/plugins/signals.ts | 14 +------- packages/backend/src/types.ts | 2 ++ plugins/devtools-backend/api-report.md | 3 ++ plugins/devtools-backend/package.json | 1 + .../devtools-backend/src/service/router.ts | 14 +++++++- .../Content/InfoContent/InfoContent.tsx | 36 +++++++++---------- plugins/signals-backend/api-report.md | 4 +-- .../src/service/router.test.ts | 4 +-- plugins/signals-backend/src/service/router.ts | 4 +-- .../src/service/standaloneServer.ts | 4 +-- plugins/signals-node/api-report.md | 9 ++--- .../{SignalsService.ts => SignalService.ts} | 23 +++++++++--- plugins/signals-node/src/index.ts | 2 +- plugins/signals-node/src/types.ts | 2 +- plugins/signals-react/api-report.md | 6 ++-- .../src/api/{SignalsApi.ts => SignalApi.ts} | 6 ++-- plugins/signals-react/src/api/index.ts | 2 +- plugins/signals-react/src/hooks/index.ts | 2 +- .../{useSignalsApi.ts => useSignalApi.ts} | 6 ++-- plugins/signals/api-report.md | 6 ++-- .../api/{SignalsClient.ts => SignalClient.ts} | 13 +++---- plugins/signals/src/api/SignalsClient.test.ts | 10 +++--- plugins/signals/src/api/index.ts | 2 +- plugins/signals/src/plugin.ts | 8 ++--- yarn.lock | 1 + 28 files changed, 114 insertions(+), 84 deletions(-) create mode 100644 .changeset/poor-sheep-tease.md rename plugins/signals-node/src/{SignalsService.ts => SignalService.ts} (90%) rename plugins/signals-react/src/api/{SignalsApi.ts => SignalApi.ts} (88%) rename plugins/signals-react/src/hooks/{useSignalsApi.ts => useSignalApi.ts} (91%) rename plugins/signals/src/api/{SignalsClient.ts => SignalClient.ts} (94%) diff --git a/.changeset/poor-sheep-tease.md b/.changeset/poor-sheep-tease.md new file mode 100644 index 0000000000..fa89ac4749 --- /dev/null +++ b/.changeset/poor-sheep-tease.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-devtools-backend': patch +'@backstage/plugin-devtools': patch +--- + +Update devtools information almost real time using signals plugin diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index cefc272aa7..fc6b814c00 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -73,6 +73,7 @@ import { DefaultEventBroker } from '@backstage/plugin-events-backend'; import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'; import { MeterProvider } from '@opentelemetry/sdk-metrics'; import { metrics } from '@opentelemetry/api'; +import { SignalService } from '@backstage/plugin-signals-node'; // Expose opentelemetry metrics using a Prometheus exporter on // http://localhost:9464/metrics . See prometheus.yml in packages/backend for @@ -99,6 +100,11 @@ function makeCreateEnv(config: Config) { }); const eventBroker = new DefaultEventBroker(root.child({ type: 'plugin' })); + const signalService = SignalService.create({ + logger: root, + eventBroker, + identity, + }); root.info(`Created UrlReader ${reader}`); @@ -120,6 +126,7 @@ function makeCreateEnv(config: Config) { permissions, scheduler, identity, + signalService, }; }; } diff --git a/packages/backend/src/plugins/devtools.ts b/packages/backend/src/plugins/devtools.ts index 8e1767ddb1..5488033682 100644 --- a/packages/backend/src/plugins/devtools.ts +++ b/packages/backend/src/plugins/devtools.ts @@ -25,5 +25,6 @@ export default async function createPlugin( logger: env.logger, config: env.config, permissions: env.permissions, + signalService: env.signalService, }); } diff --git a/packages/backend/src/plugins/signals.ts b/packages/backend/src/plugins/signals.ts index dae2731c52..687fcfaa33 100644 --- a/packages/backend/src/plugins/signals.ts +++ b/packages/backend/src/plugins/signals.ts @@ -15,25 +15,13 @@ */ import { Router } from 'express'; import { createRouter } from '@backstage/plugin-signals-backend'; -import { SignalsService } from '@backstage/plugin-signals-node'; import { PluginEnvironment } from '../types'; export default async function createPlugin( env: PluginEnvironment, ): Promise { - const service = SignalsService.create({ - logger: env.logger, - identity: env.identity, - eventBroker: env.eventBroker, - }); - - setInterval(() => { - console.log('publishing'); - service.publish('*', 'devtools:info', { now: new Date().toISOString() }); - }, 5000); - return await createRouter({ logger: env.logger, - service, + service: env.signalService, }); } diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index ab1baf0c95..d76e68c1c9 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -27,6 +27,7 @@ import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { EventBroker } from '@backstage/plugin-events-node'; +import { SignalService } from '@backstage/plugin-signals-node'; export type PluginEnvironment = { logger: Logger; @@ -40,4 +41,5 @@ export type PluginEnvironment = { scheduler: PluginTaskScheduler; identity: IdentityApi; eventBroker: EventBroker; + signalService: SignalService; }; diff --git a/plugins/devtools-backend/api-report.md b/plugins/devtools-backend/api-report.md index b9eb7b5a0c..85b2bf6efa 100644 --- a/plugins/devtools-backend/api-report.md +++ b/plugins/devtools-backend/api-report.md @@ -11,6 +11,7 @@ import express from 'express'; import { ExternalDependency } from '@backstage/plugin-devtools-common'; import { Logger } from 'winston'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; +import { SignalService } from '@backstage/plugin-signals-node'; // @public (undocumented) export function createRouter(options: RouterOptions): Promise; @@ -40,5 +41,7 @@ export interface RouterOptions { logger: Logger; // (undocumented) permissions: PermissionEvaluator; + // (undocumented) + signalService?: SignalService; } ``` diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 18013bc52f..8de7da1b39 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -38,6 +38,7 @@ "@backstage/plugin-devtools-common": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", + "@backstage/plugin-signals-node": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", "@types/express": "*", diff --git a/plugins/devtools-backend/src/service/router.ts b/plugins/devtools-backend/src/service/router.ts index fbeeb5af84..fb8b106337 100644 --- a/plugins/devtools-backend/src/service/router.ts +++ b/plugins/devtools-backend/src/service/router.ts @@ -33,6 +33,7 @@ import { errorHandler } from '@backstage/backend-common'; import express from 'express'; import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; +import { SignalService } from '@backstage/plugin-signals-node'; /** @public */ export interface RouterOptions { @@ -40,17 +41,28 @@ export interface RouterOptions { logger: Logger; config: Config; permissions: PermissionEvaluator; + signalService?: SignalService; } /** @public */ export async function createRouter( options: RouterOptions, ): Promise { - const { logger, config, permissions } = options; + const { logger, config, permissions, signalService } = options; const devToolsBackendApi = options.devToolsBackendApi || new DevToolsBackendApi(logger, config); + if (signalService) { + // Publish info periodically using the signal service + setInterval(async () => { + if (signalService.hasSubscribers('devtools:info')) { + const info = await devToolsBackendApi.listInfo(); + await signalService.publish('*', 'devtools:info', info); + } + }, 5000); + } + const router = Router(); router.use(express.json()); router.use( diff --git a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx index adca500fad..74587d3e57 100644 --- a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx @@ -27,10 +27,9 @@ import { makeStyles, Paper, Theme, - Typography, } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { useInfo } from '../../../hooks'; import { InfoDependenciesTable } from './InfoDependenciesTable'; import DescriptionIcon from '@material-ui/icons/Description'; @@ -39,7 +38,7 @@ import DeveloperBoardIcon from '@material-ui/icons/DeveloperBoard'; import { BackstageLogoIcon } from './BackstageLogoIcon'; import FileCopyIcon from '@material-ui/icons/FileCopy'; import { DevToolsInfo } from '@backstage/plugin-devtools-common'; -import { useSignalsApi } from '@backstage/plugin-signals-react'; +import { useSignalApi } from '@backstage/plugin-signals-react'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -74,14 +73,18 @@ const copyToClipboard = ({ about }: { about: DevToolsInfo | undefined }) => { /** @public */ export const InfoContent = () => { const classes = useStyles(); + const [info, setInfo] = useState(undefined); const { about, loading, error } = useInfo(); - // Just testing for signals - const [messages, setMessages] = React.useState([]); - useSignalsApi('devtools:info', message => { - messages.push(JSON.stringify(message)); - setMessages([...messages]); + useSignalApi('devtools:info', message => { + setInfo(message as DevToolsInfo); }); + useEffect(() => { + if (!loading && !error && about) { + setInfo(about); + } + }, [about, loading, error]); + if (loading) { return ; } else if (error) { @@ -89,11 +92,6 @@ export const InfoContent = () => { } return ( - - {messages.map((msg, i) => { - return {msg}; - })} - @@ -104,7 +102,7 @@ export const InfoContent = () => { @@ -115,7 +113,7 @@ export const InfoContent = () => { @@ -126,7 +124,7 @@ export const InfoContent = () => { @@ -137,14 +135,14 @@ export const InfoContent = () => { { - copyToClipboard({ about }); + copyToClipboard({ about: info }); }} className={classes.copyButton} > @@ -157,7 +155,7 @@ export const InfoContent = () => { - + ); }; diff --git a/plugins/signals-backend/api-report.md b/plugins/signals-backend/api-report.md index 0ea56c707a..309bd22ce3 100644 --- a/plugins/signals-backend/api-report.md +++ b/plugins/signals-backend/api-report.md @@ -5,7 +5,7 @@ ```ts import express from 'express'; import { Logger } from 'winston'; -import { SignalsService } from '@backstage/plugin-signals-node'; +import { SignalService } from '@backstage/plugin-signals-node'; // @public (undocumented) export function createRouter(options: RouterOptions): Promise; @@ -15,7 +15,7 @@ export interface RouterOptions { // (undocumented) logger: Logger; // (undocumented) - service: SignalsService; + service: SignalService; } // (No @packageDocumentation comment for this package) diff --git a/plugins/signals-backend/src/service/router.test.ts b/plugins/signals-backend/src/service/router.test.ts index d7091827f9..b41704e008 100644 --- a/plugins/signals-backend/src/service/router.test.ts +++ b/plugins/signals-backend/src/service/router.test.ts @@ -18,9 +18,9 @@ import express from 'express'; import request from 'supertest'; import { createRouter } from './router'; -import { SignalsService } from '@backstage/plugin-signals-node'; +import { SignalService } from '@backstage/plugin-signals-node'; -const signalsServiceMock: jest.Mocked = {} as any; +const signalsServiceMock: jest.Mocked = {} as any; describe('createRouter', () => { let app: express.Express; diff --git a/plugins/signals-backend/src/service/router.ts b/plugins/signals-backend/src/service/router.ts index 0027acef30..c47517e06c 100644 --- a/plugins/signals-backend/src/service/router.ts +++ b/plugins/signals-backend/src/service/router.ts @@ -17,12 +17,12 @@ import { errorHandler } from '@backstage/backend-common'; import express from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; -import { SignalsService } from '@backstage/plugin-signals-node'; +import { SignalService } from '@backstage/plugin-signals-node'; /** @public */ export interface RouterOptions { logger: Logger; - service: SignalsService; + service: SignalService; } /** @public */ diff --git a/plugins/signals-backend/src/service/standaloneServer.ts b/plugins/signals-backend/src/service/standaloneServer.ts index c13d718734..0728b2fde5 100644 --- a/plugins/signals-backend/src/service/standaloneServer.ts +++ b/plugins/signals-backend/src/service/standaloneServer.ts @@ -21,7 +21,7 @@ import { import { Server } from 'http'; import { Logger } from 'winston'; import { createRouter } from './router'; -import { SignalsService } from '@backstage/plugin-signals-node'; +import { SignalService } from '@backstage/plugin-signals-node'; import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; export interface ServerOptions { @@ -43,7 +43,7 @@ export async function startStandaloneServer( issuer: await discovery.getExternalBaseUrl('auth'), }); - const signals = SignalsService.create({ + const signals = SignalService.create({ logger: logger, identity, }); diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md index 15a6f67d87..5c9f2fad54 100644 --- a/plugins/signals-node/api-report.md +++ b/plugins/signals-node/api-report.md @@ -19,19 +19,20 @@ export type ServiceOptions = { }; // @public (undocumented) -export type SignalsEventBrokerPayload = { +export type SignalEventBrokerPayload = { recipients?: string[]; topic?: string; message?: JsonObject; }; // @public (undocumented) -export class SignalsService implements EventSubscriber { +export class SignalService implements EventSubscriber { // (undocumented) - static create(options: ServiceOptions): SignalsService; + static create(options: ServiceOptions): SignalService; handleUpgrade: (req: Request_2) => Promise; + hasSubscribers(topic: string): boolean; // (undocumented) - onEvent(params: EventParams): Promise; + onEvent(params: EventParams): Promise; publish( to: string | string[], topic: string, diff --git a/plugins/signals-node/src/SignalsService.ts b/plugins/signals-node/src/SignalService.ts similarity index 90% rename from plugins/signals-node/src/SignalsService.ts rename to plugins/signals-node/src/SignalService.ts index c743c958dd..4846fe7b6f 100644 --- a/plugins/signals-node/src/SignalsService.ts +++ b/plugins/signals-node/src/SignalService.ts @@ -22,7 +22,7 @@ import { Logger } from 'winston'; import { ServiceOptions, SignalConnection, - SignalsEventBrokerPayload, + SignalEventBrokerPayload, } from './types'; import { RawData, WebSocket, WebSocketServer } from 'ws'; import { IncomingMessage } from 'http'; @@ -36,7 +36,7 @@ import { } from '@backstage/plugin-auth-node'; /** @public */ -export class SignalsService implements EventSubscriber { +export class SignalService implements EventSubscriber { private readonly serverId: string; private connections: Map = new Map< string, @@ -48,7 +48,7 @@ export class SignalsService implements EventSubscriber { private server: WebSocketServer; static create(options: ServiceOptions) { - return new SignalsService(options); + return new SignalService(options); } private constructor(options: ServiceOptions) { @@ -75,7 +75,7 @@ export class SignalsService implements EventSubscriber { } /** - * Handles request upgradce to websocket and adds the connection to internal + * Handles request upgrade to websocket and adds the connection to internal * list for publish/subscribe functionality * @param req - Request */ @@ -184,6 +184,19 @@ export class SignalsService implements EventSubscriber { ); } + /** + * Checks if there is active subscriptions to specific topic. + * This can be useful to skip heavy processing before publishing messages if there are no subscriptions. + * @param topic - topic to check for subscriptions + */ + hasSubscribers(topic: string): boolean { + return ( + [...this.connections.values()].find(conn => + conn.subscriptions.has(topic), + ) !== undefined + ); + } + private async publishInternal( recipients: string[], topic: string, @@ -229,7 +242,7 @@ export class SignalsService implements EventSubscriber { } } - async onEvent(params: EventParams): Promise { + async onEvent(params: EventParams): Promise { const { eventPayload, metadata } = params; // Discard message from same server to prevent duplicate messages if (!metadata?.server || metadata.server === this.serverId) { diff --git a/plugins/signals-node/src/index.ts b/plugins/signals-node/src/index.ts index 5427711cbe..289efade07 100644 --- a/plugins/signals-node/src/index.ts +++ b/plugins/signals-node/src/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export * from './SignalsService'; +export * from './SignalService'; export * from './types'; diff --git a/plugins/signals-node/src/types.ts b/plugins/signals-node/src/types.ts index 090e4b2ff1..99821f641d 100644 --- a/plugins/signals-node/src/types.ts +++ b/plugins/signals-node/src/types.ts @@ -29,7 +29,7 @@ export type ServiceOptions = { }; /** @public */ -export type SignalsEventBrokerPayload = { +export type SignalEventBrokerPayload = { recipients?: string[]; topic?: string; message?: JsonObject; diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md index 21f070c35d..d28b806103 100644 --- a/plugins/signals-react/api-report.md +++ b/plugins/signals-react/api-report.md @@ -7,16 +7,16 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; // @public (undocumented) -export type SignalsApi = { +export type SignalApi = { subscribe(topic: string, onMessage: (message: JsonObject) => void): string; unsubscribe(subscription: string): void; }; // @public (undocumented) -export const signalsApiRef: ApiRef; +export const signalApiRef: ApiRef; // @public (undocumented) -export const useSignalsApi: ( +export const useSignalApi: ( topic: string, onMessage: (message: JsonObject) => void, ) => void; diff --git a/plugins/signals-react/src/api/SignalsApi.ts b/plugins/signals-react/src/api/SignalApi.ts similarity index 88% rename from plugins/signals-react/src/api/SignalsApi.ts rename to plugins/signals-react/src/api/SignalApi.ts index 2aefa5d166..f63023bf5f 100644 --- a/plugins/signals-react/src/api/SignalsApi.ts +++ b/plugins/signals-react/src/api/SignalApi.ts @@ -17,12 +17,12 @@ import { createApiRef } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; /** @public */ -export const signalsApiRef = createApiRef({ - id: 'plugin.signals.service', +export const signalApiRef = createApiRef({ + id: 'plugin.signal.service', }); /** @public */ -export type SignalsApi = { +export type SignalApi = { subscribe(topic: string, onMessage: (message: JsonObject) => void): string; unsubscribe(subscription: string): void; diff --git a/plugins/signals-react/src/api/index.ts b/plugins/signals-react/src/api/index.ts index 9d5c4c5656..8d728dbd0f 100644 --- a/plugins/signals-react/src/api/index.ts +++ b/plugins/signals-react/src/api/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './SignalsApi'; +export * from './SignalApi'; diff --git a/plugins/signals-react/src/hooks/index.ts b/plugins/signals-react/src/hooks/index.ts index 0d5967f9eb..921eca8d30 100644 --- a/plugins/signals-react/src/hooks/index.ts +++ b/plugins/signals-react/src/hooks/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './useSignalsApi'; +export * from './useSignalApi'; diff --git a/plugins/signals-react/src/hooks/useSignalsApi.ts b/plugins/signals-react/src/hooks/useSignalApi.ts similarity index 91% rename from plugins/signals-react/src/hooks/useSignalsApi.ts rename to plugins/signals-react/src/hooks/useSignalApi.ts index 0fcc69efed..bb6f47a5fe 100644 --- a/plugins/signals-react/src/hooks/useSignalsApi.ts +++ b/plugins/signals-react/src/hooks/useSignalApi.ts @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { signalsApiRef } from '../api'; +import { signalApiRef } from '../api'; import { useApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { useEffect, useState } from 'react'; /** @public */ -export const useSignalsApi = ( +export const useSignalApi = ( topic: string, onMessage: (message: JsonObject) => void, ) => { - const signals = useApi(signalsApiRef); + const signals = useApi(signalApiRef); const [subscription, setSubscription] = useState(null); useEffect(() => { if (!subscription) { diff --git a/plugins/signals/api-report.md b/plugins/signals/api-report.md index 08c52ef418..28a70a339c 100644 --- a/plugins/signals/api-report.md +++ b/plugins/signals/api-report.md @@ -7,17 +7,17 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { IdentityApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; -import { SignalsApi } from '@backstage/plugin-signals-react'; +import { SignalApi } from '@backstage/plugin-signals-react'; // @public (undocumented) -export class SignalsClient implements SignalsApi { +export class SignalClient implements SignalApi { // (undocumented) static create(options: { identity: IdentityApi; discoveryApi: DiscoveryApi; connectTimeout?: number; reconnectTimeout?: number; - }): SignalsClient; + }): SignalClient; // (undocumented) static readonly DEFAULT_CONNECT_TIMEOUT_MS: number; // (undocumented) diff --git a/plugins/signals/src/api/SignalsClient.ts b/plugins/signals/src/api/SignalClient.ts similarity index 94% rename from plugins/signals/src/api/SignalsClient.ts rename to plugins/signals/src/api/SignalClient.ts index 4051468a9e..64c1866fab 100644 --- a/plugins/signals/src/api/SignalsClient.ts +++ b/plugins/signals/src/api/SignalClient.ts @@ -13,24 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { SignalsApi } from '@backstage/plugin-signals-react'; +import { SignalApi } from '@backstage/plugin-signals-react'; import { JsonObject } from '@backstage/types'; import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; import { v4 as uuid } from 'uuid'; -/** @internal */ type Subscription = { topic: string; callback: (message: JsonObject) => void; }; -/** @internal */ const WS_CLOSE_NORMAL = 1000; -/** @internal */ const WS_CLOSE_GOING_AWAY = 1001; /** @public */ -export class SignalsClient implements SignalsApi { +export class SignalClient implements SignalApi { static readonly DEFAULT_CONNECT_TIMEOUT_MS: number = 1000; static readonly DEFAULT_RECONNECT_TIMEOUT_MS: number = 5000; private ws: WebSocket | null = null; @@ -47,10 +44,10 @@ export class SignalsClient implements SignalsApi { const { identity, discoveryApi, - connectTimeout = SignalsClient.DEFAULT_CONNECT_TIMEOUT_MS, - reconnectTimeout = SignalsClient.DEFAULT_RECONNECT_TIMEOUT_MS, + connectTimeout = SignalClient.DEFAULT_CONNECT_TIMEOUT_MS, + reconnectTimeout = SignalClient.DEFAULT_RECONNECT_TIMEOUT_MS, } = options; - return new SignalsClient( + return new SignalClient( identity, discoveryApi, connectTimeout, diff --git a/plugins/signals/src/api/SignalsClient.test.ts b/plugins/signals/src/api/SignalsClient.test.ts index 03b25d580d..60d67e6c4b 100644 --- a/plugins/signals/src/api/SignalsClient.test.ts +++ b/plugins/signals/src/api/SignalsClient.test.ts @@ -16,7 +16,7 @@ import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; import WS from 'jest-websocket-mock'; -import { SignalsClient } from './SignalsClient'; +import { SignalClient } from './SignalClient'; describe('SignalsClient', () => { const tokenFunction = jest.fn(); @@ -43,7 +43,7 @@ describe('SignalsClient', () => { it('should handle single subscription correctly', async () => { const messageMock = jest.fn(); - const client = SignalsClient.create({ discoveryApi, identity }); + const client = SignalClient.create({ discoveryApi, identity }); const sub = client.subscribe('topic', messageMock); await server.connected; @@ -64,8 +64,8 @@ describe('SignalsClient', () => { it('should handle multiple subscription correctly', async () => { const messageMock1 = jest.fn(); const messageMock2 = jest.fn(); - const client1 = SignalsClient.create({ discoveryApi, identity }); - const client2 = SignalsClient.create({ discoveryApi, identity }); + const client1 = SignalClient.create({ discoveryApi, identity }); + const client2 = SignalClient.create({ discoveryApi, identity }); const sub1 = client1.subscribe('topic', messageMock1); const sub2 = client2.subscribe('topic', messageMock2); @@ -94,7 +94,7 @@ describe('SignalsClient', () => { it('should reconnect on error', async () => { const messageMock = jest.fn(); - const client = SignalsClient.create({ + const client = SignalClient.create({ discoveryApi, identity, reconnectTimeout: 10, diff --git a/plugins/signals/src/api/index.ts b/plugins/signals/src/api/index.ts index 80e69259af..c76ae196ed 100644 --- a/plugins/signals/src/api/index.ts +++ b/plugins/signals/src/api/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './SignalsClient'; +export * from './SignalClient'; diff --git a/plugins/signals/src/plugin.ts b/plugins/signals/src/plugin.ts index d1b0311116..946e9aaa71 100644 --- a/plugins/signals/src/plugin.ts +++ b/plugins/signals/src/plugin.ts @@ -19,21 +19,21 @@ import { discoveryApiRef, identityApiRef, } from '@backstage/core-plugin-api'; -import { signalsApiRef } from '@backstage/plugin-signals-react'; -import { SignalsClient } from './api/SignalsClient'; +import { signalApiRef } from '@backstage/plugin-signals-react'; +import { SignalClient } from './api/SignalClient'; /** @public */ export const signalsPlugin = createPlugin({ id: 'signals', apis: [ createApiFactory({ - api: signalsApiRef, + api: signalApiRef, deps: { identity: identityApiRef, discoveryApi: discoveryApiRef, }, factory: ({ identity, discoveryApi }) => - SignalsClient.create({ + SignalClient.create({ identity, discoveryApi, }), diff --git a/yarn.lock b/yarn.lock index d44cfeab72..de28fd808d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6203,6 +6203,7 @@ __metadata: "@backstage/plugin-devtools-common": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" + "@backstage/plugin-signals-node": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": ^1.1.3 "@types/express": "*" From a219469cf33391312dc26a23291c782f3bd1e5ab Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Tue, 5 Dec 2023 16:03:41 +0200 Subject: [PATCH 029/241] docs: add signals plugin docs Signed-off-by: Heikki Hellgren --- plugins/signals-backend/README.md | 13 ++---- plugins/signals-node/README.md | 67 ++++++++++++++++++++++++++++++- plugins/signals-react/README.md | 44 +++++++++++++++++++- plugins/signals/README.md | 38 +++++++++++++++--- 4 files changed, 146 insertions(+), 16 deletions(-) diff --git a/plugins/signals-backend/README.md b/plugins/signals-backend/README.md index d194b852f2..1f58c1195a 100644 --- a/plugins/signals-backend/README.md +++ b/plugins/signals-backend/README.md @@ -6,26 +6,21 @@ Signals plugin allows backend plugins to publish messages to frontend plugins. ## Getting started -Add Signals router to your backend in `packages/backend/src/plugins/signals.ts`: +First install the `@backstage/plugin-signals-node` plugin to get the `SignalService` set up. + +Next, add Signals router to your backend in `packages/backend/src/plugins/signals.ts`: ```ts import { Router } from 'express'; import { createRouter } from '@backstage/plugin-signals-backend'; -import { SignalsService } from '@backstage/plugin-signals-node'; import { PluginEnvironment } from '../types'; export default async function createPlugin( env: PluginEnvironment, ): Promise { - const service = SignalsService.create({ - logger: env.logger, - identity: env.identity, - eventBroker: env.eventBroker, - }); - return await createRouter({ logger: env.logger, - service, + service: env.signalsService, }); } ``` diff --git a/plugins/signals-node/README.md b/plugins/signals-node/README.md index 55d766f9e0..abea6c6d22 100644 --- a/plugins/signals-node/README.md +++ b/plugins/signals-node/README.md @@ -2,4 +2,69 @@ Welcome to the Node.js library package for the signals plugin! -_This plugin was created through the Backstage CLI_ +Signals plugin allows backend plugins to publish messages to frontend plugins. + +## Getting started + +Add SignalService to your plugin environment in `packages/backend/src/types.ts`: + +```ts +import { SignalService } from '@backstage/plugin-signals-node'; + +export type PluginEnvironment = { + // ... + signalService: SignalService; +}; +``` + +Add it also to your `makeCreateEnv` to allow access from the other plugins: + +```ts +import { SignalService } from '@backstage/plugin-signals-node'; +import { DefaultEventBroker } from '@backstage/plugin-events-backend'; + +function makeCreateEnv(config: Config) { + // ... + + const eventBroker = new DefaultEventBroker(root.child({ type: 'plugin' })); + const signalService = SignalService.create({ + logger: root, + eventBroker, // EventBroker is optional + identity, + }); + + return (plugin: string): PluginEnvironment => { + const logger = root.child({ type: 'plugin', plugin }); + return { + logger, + eventBroker, + signalService, + // ... + }; + }; +} +``` + +To allow connections from the frontend, you should also install the `@backstage/plugin-signals-backend`. + +## Using the service + +Once you have both of the backend plugins installed, you can utilize the signal service by calling the +`publish` method. This will publish the message to all subscribers in the frontend. To send message to +all subscribers, you can use `*` as `to` parameter. + +```ts +// Periodic sending example +setInterval(async () => { + // You can use hasSubscribers to check if the message will be sent to anyone + // in case you need some heavy processing before that + if (signalService.hasSubscribers('plugin:topic')) { + await signalService.publish('*', 'plugin:topic', { + message: 'hello world', + }); + } +}, 5000); +``` + +To receive this message in the frontend, check the documentation of `@backstage/plugin-signals` and +`@backstage/plugin-signals-react`. diff --git a/plugins/signals-react/README.md b/plugins/signals-react/README.md index 4b6b4e00bc..9bdf5e964f 100644 --- a/plugins/signals-react/README.md +++ b/plugins/signals-react/README.md @@ -2,4 +2,46 @@ Welcome to the web library package for the signals plugin! -_This plugin was created through the Backstage CLI_ +Signals plugin allows backend plugins to publish messages to frontend plugins. + +## Getting started + +This plugin contains functionalities that help utilize the signals plugin. To get started, +see installation instructions from `@backstage/plugin-signals-node`, `@backstage/plugin-signals-backend`, and +`@backstage/plugin-signals`. + +There are two ways to utilize the signals plugin; either by using the hook or by directly using the API. + +## Using the hook + +By using the hook, unsubscribe is automatically taken care of. This helps to maintain only necessary amount +of connections to the backend and also to allow multiple subscriptions using the same connection. + +Example of using the hook: + +```ts +import { useSignalApi } from '@backstage/plugin-signals-react'; + +const [message, setMessage] = useState(undefined); +useSignalApi('myplugin:topic', message => { + setMessage(message); +}); +``` + +Whenever backend publishes new message to the topic `myplugin:topic`, the state of this component is changed. + +## Using API directly + +You can also use the signal API directly. This allows more fine-grained control over the state of the connections and +subscriptions. + +```ts +import { signalsApiRef } from '@backstage/plugin-signals-react'; + +const signals = useApi(signalsApiRef); +signals.subscribe('myplugin:topic', (message: JsonObject) => { + console.log(message); +}); +// Remember to unsubscribe +signals.unsubscribe('myplugin:topic'); +``` diff --git a/plugins/signals/README.md b/plugins/signals/README.md index 604fa98a33..e70c1ef7d8 100644 --- a/plugins/signals/README.md +++ b/plugins/signals/README.md @@ -2,12 +2,40 @@ Welcome to the signals plugin! -_This plugin was created through the Backstage CLI_ +Signals plugin allows backend plugins to publish messages to frontend plugins. ## Getting started -Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/signals](http://localhost:3000/signals). +This plugin contains client that can receive messages from the backend. To get started, +see installation instructions from `@backstage/plugin-signals-node`, `@backstage/plugin-signals-backend`. -You can also serve the plugin in isolation by running `yarn start` in the plugin directory. -This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. -It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. +To install the plugin, you have to add the following to your `packages/app/src/plugins.ts`: + +```ts +export { signalsPlugin } from '@backstage/plugin-signals'; +``` + +And make sure that your `packages/app/src/App.tsx` contains: + +```ts +import * as plugins from './plugins'; + +const app = createApp({ + // ... + plugins: Object.values(plugins), + // ... +}); +``` + +Now you can utilize the API from other plugins using the `@backstage/plugin-signals-react` package or simply by: + +```ts +import { signalsApiRef } from '@backstage/plugin-signals-react'; + +const signals = useApi(signalsApiRef); +signals.subscribe('myplugin:topic', (message: JsonObject) => { + console.log(message); +}); +// Remember to unsubscribe +signals.unsubscribe('myplugin:topic'); +``` From 6a730a43104dff559ca1535957edf2c80c60dcaa Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Fri, 8 Dec 2023 14:28:22 +0200 Subject: [PATCH 030/241] fix: handle upgrade properly in signal router Signed-off-by: Heikki Hellgren --- plugins/devtools-backend/api-report.md | 2 ++ .../src/api/DevToolsBackendApi.ts | 16 +++++---- .../devtools-backend/src/service/router.ts | 8 +++-- .../Content/InfoContent/InfoContent.tsx | 20 +++++------ plugins/signals-backend/src/service/router.ts | 35 +++++++++++++------ plugins/signals-node/api-report.md | 11 ++++-- plugins/signals-node/src/SignalService.ts | 27 +++++--------- 7 files changed, 69 insertions(+), 50 deletions(-) diff --git a/plugins/devtools-backend/api-report.md b/plugins/devtools-backend/api-report.md index 85b2bf6efa..7049285c02 100644 --- a/plugins/devtools-backend/api-report.md +++ b/plugins/devtools-backend/api-report.md @@ -25,6 +25,8 @@ export class DevToolsBackendApi { listExternalDependencyDetails(): Promise; // (undocumented) listInfo(): Promise; + // (undocumented) + listResourceUtilization(): Promise; } // @public diff --git a/plugins/devtools-backend/src/api/DevToolsBackendApi.ts b/plugins/devtools-backend/src/api/DevToolsBackendApi.ts index b71edb3391..da9a1ca0dd 100644 --- a/plugins/devtools-backend/src/api/DevToolsBackendApi.ts +++ b/plugins/devtools-backend/src/api/DevToolsBackendApi.ts @@ -203,17 +203,21 @@ export class DevToolsBackendApi { return configInfo; } - public async listInfo(): Promise { - const operatingSystem = `${os.hostname()}: ${os.type} ${os.release} - ${ - os.platform - }/${os.arch}`; + public async listResourceUtilization(): Promise { const usedMem = Math.floor((os.totalmem() - os.freemem()) / (1024 * 1024)); - const resources = `Memory: ${usedMem}/${Math.floor( + return `Memory: ${usedMem}/${Math.floor( os.totalmem() / (1024 * 1024), )}MB - Load: ${os .loadavg() .map(v => v.toFixed(2)) .join('/')}`; + } + + public async listInfo(): Promise { + const operatingSystem = `${os.hostname()}: ${os.type} ${os.release} - ${ + os.platform + }/${os.arch}`; + const nodeJsVersion = process.version; /* eslint-disable-next-line no-restricted-syntax */ @@ -247,7 +251,7 @@ export class DevToolsBackendApi { const info: DevToolsInfo = { operatingSystem: operatingSystem ?? 'N/A', - resourceUtilization: resources ?? 'N/A', + resourceUtilization: (await this.listResourceUtilization()) ?? 'N/A', nodeJsVersion: nodeJsVersion ?? 'N/A', backstageVersion: backstageJson && backstageJson.version ? backstageJson.version : 'N/A', diff --git a/plugins/devtools-backend/src/service/router.ts b/plugins/devtools-backend/src/service/router.ts index fb8b106337..106eb44309 100644 --- a/plugins/devtools-backend/src/service/router.ts +++ b/plugins/devtools-backend/src/service/router.ts @@ -56,9 +56,11 @@ export async function createRouter( if (signalService) { // Publish info periodically using the signal service setInterval(async () => { - if (signalService.hasSubscribers('devtools:info')) { - const info = await devToolsBackendApi.listInfo(); - await signalService.publish('*', 'devtools:info', info); + if (signalService.hasSubscribers('devtools:resources')) { + const info = await devToolsBackendApi.listResourceUtilization(); + await signalService.publish('*', 'devtools:resources', { + resources: info, + }); } }, 5000); } diff --git a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx index 74587d3e57..2480bf5233 100644 --- a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx @@ -73,15 +73,15 @@ const copyToClipboard = ({ about }: { about: DevToolsInfo | undefined }) => { /** @public */ export const InfoContent = () => { const classes = useStyles(); - const [info, setInfo] = useState(undefined); + const [resources, setResources] = useState(undefined); const { about, loading, error } = useInfo(); - useSignalApi('devtools:info', message => { - setInfo(message as DevToolsInfo); + useSignalApi('devtools:resources', message => { + setResources(message.resources as string); }); useEffect(() => { if (!loading && !error && about) { - setInfo(about); + setResources(about.resourceUtilization); } }, [about, loading, error]); @@ -102,7 +102,7 @@ export const InfoContent = () => { @@ -113,7 +113,7 @@ export const InfoContent = () => { @@ -124,7 +124,7 @@ export const InfoContent = () => { @@ -135,14 +135,14 @@ export const InfoContent = () => { { - copyToClipboard({ about: info }); + copyToClipboard({ about }); }} className={classes.copyButton} > @@ -155,7 +155,7 @@ export const InfoContent = () => { - + ); }; diff --git a/plugins/signals-backend/src/service/router.ts b/plugins/signals-backend/src/service/router.ts index c47517e06c..acffde19c7 100644 --- a/plugins/signals-backend/src/service/router.ts +++ b/plugins/signals-backend/src/service/router.ts @@ -14,10 +14,12 @@ * limitations under the License. */ import { errorHandler } from '@backstage/backend-common'; -import express from 'express'; +import express, { NextFunction, Request, Response } from 'express'; import Router from 'express-promise-router'; import { Logger } from 'winston'; import { SignalService } from '@backstage/plugin-signals-node'; +import * as https from 'https'; +import http from 'http'; /** @public */ export interface RouterOptions { @@ -30,17 +32,14 @@ export async function createRouter( options: RouterOptions, ): Promise { const { logger, service } = options; + let subscribed = false; - const router = Router(); - router.use(express.json()); - - router.get('/health', (_, response) => { - logger.info('PONG!'); - response.json({ status: 'ok' }); - }); - - router.get('/', async (req, _, next) => { + const upgradeMiddleware = (req: Request, _: Response, next: NextFunction) => { + const server: https.Server | http.Server = ( + (req.socket ?? req.connection) as any + )?.server; if ( + !server || !req.headers || req.headers.upgrade === undefined || req.headers.upgrade.toLowerCase() !== 'websocket' @@ -49,7 +48,21 @@ export async function createRouter( return; } - await service.handleUpgrade(req); + if (!subscribed) { + server.on('upgrade', async (request, socket, head) => { + await service.handleUpgrade(request, socket, head); + }); + subscribed = true; + } + }; + + const router = Router(); + router.use(express.json()); + router.use(upgradeMiddleware); + + router.get('/health', (_, response) => { + logger.info('PONG!'); + response.json({ status: 'ok' }); }); router.use(errorHandler()); diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md index 5c9f2fad54..3ad4da11ee 100644 --- a/plugins/signals-node/api-report.md +++ b/plugins/signals-node/api-report.md @@ -3,13 +3,16 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// + +import { Duplex } from 'stream'; import { EventBroker } from '@backstage/plugin-events-node'; import { EventParams } from '@backstage/plugin-events-node'; import { EventSubscriber } from '@backstage/plugin-events-node'; import { IdentityApi } from '@backstage/plugin-auth-node'; +import { IncomingMessage } from 'http'; import { JsonObject } from '@backstage/types'; import { Logger } from 'winston'; -import { Request as Request_2 } from 'express'; // @public (undocumented) export type ServiceOptions = { @@ -29,7 +32,11 @@ export type SignalEventBrokerPayload = { export class SignalService implements EventSubscriber { // (undocumented) static create(options: ServiceOptions): SignalService; - handleUpgrade: (req: Request_2) => Promise; + handleUpgrade: ( + req: IncomingMessage, + socket: Duplex, + head: Buffer, + ) => Promise; hasSubscribers(topic: string): boolean; // (undocumented) onEvent(params: EventParams): Promise; diff --git a/plugins/signals-node/src/SignalService.ts b/plugins/signals-node/src/SignalService.ts index 4846fe7b6f..5ae7b63deb 100644 --- a/plugins/signals-node/src/SignalService.ts +++ b/plugins/signals-node/src/SignalService.ts @@ -27,13 +27,13 @@ import { import { RawData, WebSocket, WebSocketServer } from 'ws'; import { IncomingMessage } from 'http'; import { v4 as uuid } from 'uuid'; -import { Request } from 'express'; import { JsonObject } from '@backstage/types'; import { BackstageIdentityResponse, IdentityApi, IdentityApiGetIdentityRequest, } from '@backstage/plugin-auth-node'; +import { Duplex } from 'stream'; /** @public */ export class SignalService implements EventSubscriber { @@ -61,14 +61,7 @@ export class SignalService implements EventSubscriber { this.serverId = uuid(); this.server = new WebSocketServer({ noServer: true, - }); - - this.server.on('close', () => { - this.logger.info('Closing signals server'); - this.connections.forEach(conn => { - conn.ws.close(); - }); - this.connections = new Map(); + clientTracking: false, }); this.eventBroker?.subscribe(this); @@ -79,7 +72,11 @@ export class SignalService implements EventSubscriber { * list for publish/subscribe functionality * @param req - Request */ - handleUpgrade = async (req: Request) => { + handleUpgrade = async ( + req: IncomingMessage, + socket: Duplex, + head: Buffer, + ) => { let identity: BackstageIdentityResponse | undefined = undefined; // Authentication token is passed in Sec-WebSocket-Protocol header as there @@ -95,8 +92,8 @@ export class SignalService implements EventSubscriber { this.server.handleUpgrade( req, - req.socket, - Buffer.from(''), + socket, + head, (ws: WebSocket, __: IncomingMessage) => { this.addConnection(ws, identity); }, @@ -131,17 +128,11 @@ export class SignalService implements EventSubscriber { this.connections.delete(id); }); - ws.on('ping', () => { - this.logger.debug(`Ping from connection ${id}`); - ws.pong(); - }); - ws.on('message', (data: RawData, isBinary: boolean) => { this.logger.debug(`Received message from connection ${id}: ${data}`); if (isBinary) { return; } - try { const json = JSON.parse(data.toString()) as JsonObject; this.handleMessage(conn, json); From ec8c5fcb707164b6269d221beee09a321b023273 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Fri, 8 Dec 2023 14:38:34 +0200 Subject: [PATCH 031/241] fix: only allow one signal client instance at once Signed-off-by: Heikki Hellgren --- plugins/signals/src/plugin.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/plugins/signals/src/plugin.ts b/plugins/signals/src/plugin.ts index 946e9aaa71..1482d7dae1 100644 --- a/plugins/signals/src/plugin.ts +++ b/plugins/signals/src/plugin.ts @@ -22,6 +22,8 @@ import { import { signalApiRef } from '@backstage/plugin-signals-react'; import { SignalClient } from './api/SignalClient'; +let clientInstance: SignalClient | undefined = undefined; + /** @public */ export const signalsPlugin = createPlugin({ id: 'signals', @@ -32,11 +34,15 @@ export const signalsPlugin = createPlugin({ identity: identityApiRef, discoveryApi: discoveryApiRef, }, - factory: ({ identity, discoveryApi }) => - SignalClient.create({ - identity, - discoveryApi, - }), + factory: ({ identity, discoveryApi }) => { + if (!clientInstance) { + clientInstance = SignalClient.create({ + identity, + discoveryApi, + }); + } + return clientInstance; + }, }), ], }); From aaa4e910e29e9cdc30df26d988d7db54e29ff678 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Fri, 8 Dec 2023 14:53:46 +0200 Subject: [PATCH 032/241] deps: move express types to dev deps Signed-off-by: Heikki Hellgren --- plugins/signals-node/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 2dc17f5e54..66e4528678 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -22,7 +22,8 @@ "postpack": "backstage-cli package postpack" }, "devDependencies": { - "@backstage/cli": "workspace:^" + "@backstage/cli": "workspace:^", + "@types/express": "^4.17.21" }, "files": [ "dist" @@ -33,7 +34,6 @@ "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-events-node": "workspace:^", "@backstage/types": "workspace:^", - "@types/express": "^4.17.21", "express": "^4.17.1", "uuid": "^8.0.0", "winston": "^3.2.1", From f3575bc34c2f53fb20362ca7e871dfd6c7cd0fcb Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Fri, 8 Dec 2023 15:33:42 +0200 Subject: [PATCH 033/241] fix: initial review finding fixes Signed-off-by: Heikki Hellgren --- plugins/devtools-backend/src/plugin.ts | 5 +- plugins/signals-backend/README.md | 18 +++++++ plugins/signals-backend/api-report.md | 5 ++ plugins/signals-backend/package.json | 1 + plugins/signals-backend/src/index.ts | 1 + plugins/signals-backend/src/plugin.ts | 48 +++++++++++++++++++ plugins/signals-backend/src/service/router.ts | 3 +- plugins/signals-node/api-report.md | 4 ++ plugins/signals-node/package.json | 1 + plugins/signals-node/src/index.ts | 1 + plugins/signals-node/src/lib.ts | 21 ++++++++ yarn.lock | 2 + 12 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 plugins/signals-backend/src/plugin.ts create mode 100644 plugins/signals-node/src/lib.ts diff --git a/plugins/devtools-backend/src/plugin.ts b/plugins/devtools-backend/src/plugin.ts index 685522557e..02c3831128 100644 --- a/plugins/devtools-backend/src/plugin.ts +++ b/plugins/devtools-backend/src/plugin.ts @@ -20,6 +20,7 @@ import { createBackendPlugin, } from '@backstage/backend-plugin-api'; import { createRouter } from './service/router'; +import { signalService } from '@backstage/plugin-signals-node'; /** * DevTools backend plugin @@ -35,13 +36,15 @@ export const devtoolsPlugin = createBackendPlugin({ logger: coreServices.logger, permissions: coreServices.permissions, httpRouter: coreServices.httpRouter, + signals: signalService, }, - async init({ config, logger, permissions, httpRouter }) { + async init({ config, logger, permissions, httpRouter, signals }) { httpRouter.use( await createRouter({ config, logger: loggerToWinstonLogger(logger), permissions, + signalService: signals, }), ); }, diff --git a/plugins/signals-backend/README.md b/plugins/signals-backend/README.md index 1f58c1195a..f9ebfb80c7 100644 --- a/plugins/signals-backend/README.md +++ b/plugins/signals-backend/README.md @@ -24,3 +24,21 @@ export default async function createPlugin( }); } ``` + +Now add the signals to `packages/backend/src/index.ts`: + +```ts +// ... +import signals from './plugins/sonarqube'; + +async function main() { + // ... + const signalsEnv = useHotMemoize(module, () => createEnv('signals')); + + const apiRouter = Router(); + // ... + apiRouter.use('/signals', await signals(signalsEnv)); + apiRouter.use(notFoundHandler()); + // ... +} +``` diff --git a/plugins/signals-backend/api-report.md b/plugins/signals-backend/api-report.md index 309bd22ce3..afbc63abf2 100644 --- a/plugins/signals-backend/api-report.md +++ b/plugins/signals-backend/api-report.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { BackendFeature } from '@backstage/backend-plugin-api'; import express from 'express'; import { Logger } from 'winston'; import { SignalService } from '@backstage/plugin-signals-node'; @@ -18,5 +19,9 @@ export interface RouterOptions { service: SignalService; } +// @public +const signalsPlugin: () => BackendFeature; +export default signalsPlugin; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/signals-backend/package.json b/plugins/signals-backend/package.json index ee303cdf3b..2fe6d86480 100644 --- a/plugins/signals-backend/package.json +++ b/plugins/signals-backend/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-events-node": "workspace:^", diff --git a/plugins/signals-backend/src/index.ts b/plugins/signals-backend/src/index.ts index d2e8d61bad..05e1f941b2 100644 --- a/plugins/signals-backend/src/index.ts +++ b/plugins/signals-backend/src/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export * from './service/router'; +export { signalsPlugin as default } from './plugin'; diff --git a/plugins/signals-backend/src/plugin.ts b/plugins/signals-backend/src/plugin.ts new file mode 100644 index 0000000000..b4a0a3e095 --- /dev/null +++ b/plugins/signals-backend/src/plugin.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2023 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 { loggerToWinstonLogger } from '@backstage/backend-common'; +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { createRouter } from './service/router'; +import { signalService } from '@backstage/plugin-signals-node'; + +/** + * Signals backend plugin + * + * @public + */ +export const signalsPlugin = createBackendPlugin({ + pluginId: 'devtools', + register(env) { + env.registerInit({ + deps: { + httpRouter: coreServices.httpRouter, + logger: coreServices.logger, + service: signalService, + }, + async init({ httpRouter, logger, service }) { + httpRouter.use( + await createRouter({ + logger: loggerToWinstonLogger(logger), + service, + }), + ); + }, + }); + }, +}); diff --git a/plugins/signals-backend/src/service/router.ts b/plugins/signals-backend/src/service/router.ts index acffde19c7..7b0cc02a1d 100644 --- a/plugins/signals-backend/src/service/router.ts +++ b/plugins/signals-backend/src/service/router.ts @@ -33,7 +33,6 @@ export async function createRouter( ): Promise { const { logger, service } = options; let subscribed = false; - const upgradeMiddleware = (req: Request, _: Response, next: NextFunction) => { const server: https.Server | http.Server = ( (req.socket ?? req.connection) as any @@ -49,10 +48,10 @@ export async function createRouter( } if (!subscribed) { + subscribed = true; server.on('upgrade', async (request, socket, head) => { await service.handleUpgrade(request, socket, head); }); - subscribed = true; } }; diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md index 3ad4da11ee..750dd1774a 100644 --- a/plugins/signals-node/api-report.md +++ b/plugins/signals-node/api-report.md @@ -13,6 +13,7 @@ import { IdentityApi } from '@backstage/plugin-auth-node'; import { IncomingMessage } from 'http'; import { JsonObject } from '@backstage/types'; import { Logger } from 'winston'; +import { ServiceRef } from '@backstage/backend-plugin-api'; // @public (undocumented) export type ServiceOptions = { @@ -49,5 +50,8 @@ export class SignalService implements EventSubscriber { supportsEventTopics(): string[]; } +// @public (undocumented) +export const signalService: ServiceRef; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index 66e4528678..d5e980d857 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -30,6 +30,7 @@ ], "dependencies": { "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-events-node": "workspace:^", diff --git a/plugins/signals-node/src/index.ts b/plugins/signals-node/src/index.ts index 289efade07..43a3a88ac0 100644 --- a/plugins/signals-node/src/index.ts +++ b/plugins/signals-node/src/index.ts @@ -14,5 +14,6 @@ * limitations under the License. */ +export * from './lib'; export * from './SignalService'; export * from './types'; diff --git a/plugins/signals-node/src/lib.ts b/plugins/signals-node/src/lib.ts new file mode 100644 index 0000000000..d303b4d3cc --- /dev/null +++ b/plugins/signals-node/src/lib.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 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 { createServiceRef } from '@backstage/backend-plugin-api'; + +/** @public */ +export const signalService = createServiceRef< + import('./SignalService').SignalService +>({ id: 'signals.service', scope: 'plugin' }); diff --git a/yarn.lock b/yarn.lock index de28fd808d..7a3fbb3902 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8839,6 +8839,7 @@ __metadata: resolution: "@backstage/plugin-signals-backend@workspace:plugins/signals-backend" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" @@ -8865,6 +8866,7 @@ __metadata: resolution: "@backstage/plugin-signals-node@workspace:plugins/signals-node" dependencies: "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" From 5368d38e9d0dbfb03745db0de44277a9bae2a219 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Fri, 8 Dec 2023 15:50:41 +0200 Subject: [PATCH 034/241] fix: add check for request path to upgrade Signed-off-by: Heikki Hellgren --- plugins/signals-backend/src/service/router.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/signals-backend/src/service/router.ts b/plugins/signals-backend/src/service/router.ts index 7b0cc02a1d..8926910544 100644 --- a/plugins/signals-backend/src/service/router.ts +++ b/plugins/signals-backend/src/service/router.ts @@ -34,9 +34,7 @@ export async function createRouter( const { logger, service } = options; let subscribed = false; const upgradeMiddleware = (req: Request, _: Response, next: NextFunction) => { - const server: https.Server | http.Server = ( - (req.socket ?? req.connection) as any - )?.server; + const server: https.Server | http.Server = (req.socket as any)?.server; if ( !server || !req.headers || @@ -50,7 +48,10 @@ export async function createRouter( if (!subscribed) { subscribed = true; server.on('upgrade', async (request, socket, head) => { - await service.handleUpgrade(request, socket, head); + // Only upgrade if request to root of the signals plugin + if (request.url === '/api/signals') { + await service.handleUpgrade(request, socket, head); + } }); } }; From 3b6b645d93125a1a88dfe6edc973047f2f44353a Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Fri, 8 Dec 2023 16:42:16 +0200 Subject: [PATCH 035/241] feat: add service factory for signal service Signed-off-by: Heikki Hellgren --- plugins/signals-backend/src/plugin.ts | 2 +- plugins/signals-node/api-report.md | 4 ++-- plugins/signals-node/src/SignalService.ts | 4 ++-- plugins/signals-node/src/lib.ts | 26 +++++++++++++++++++---- plugins/signals-node/src/types.ts | 4 ++-- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/plugins/signals-backend/src/plugin.ts b/plugins/signals-backend/src/plugin.ts index b4a0a3e095..8ade4e85b5 100644 --- a/plugins/signals-backend/src/plugin.ts +++ b/plugins/signals-backend/src/plugin.ts @@ -27,7 +27,7 @@ import { signalService } from '@backstage/plugin-signals-node'; * @public */ export const signalsPlugin = createBackendPlugin({ - pluginId: 'devtools', + pluginId: 'signals', register(env) { env.registerInit({ deps: { diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md index 750dd1774a..7bfffc2540 100644 --- a/plugins/signals-node/api-report.md +++ b/plugins/signals-node/api-report.md @@ -12,13 +12,13 @@ import { EventSubscriber } from '@backstage/plugin-events-node'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { IncomingMessage } from 'http'; import { JsonObject } from '@backstage/types'; -import { Logger } from 'winston'; +import { LoggerService } from '@backstage/backend-plugin-api'; import { ServiceRef } from '@backstage/backend-plugin-api'; // @public (undocumented) export type ServiceOptions = { eventBroker?: EventBroker; - logger: Logger; + logger: LoggerService; identity: IdentityApi; }; diff --git a/plugins/signals-node/src/SignalService.ts b/plugins/signals-node/src/SignalService.ts index 5ae7b63deb..54f09f583a 100644 --- a/plugins/signals-node/src/SignalService.ts +++ b/plugins/signals-node/src/SignalService.ts @@ -18,7 +18,6 @@ import { EventParams, EventSubscriber, } from '@backstage/plugin-events-node'; -import { Logger } from 'winston'; import { ServiceOptions, SignalConnection, @@ -34,6 +33,7 @@ import { IdentityApiGetIdentityRequest, } from '@backstage/plugin-auth-node'; import { Duplex } from 'stream'; +import { LoggerService } from '@backstage/backend-plugin-api'; /** @public */ export class SignalService implements EventSubscriber { @@ -43,7 +43,7 @@ export class SignalService implements EventSubscriber { SignalConnection >(); private eventBroker?: EventBroker; - private logger: Logger; + private logger: LoggerService; private identity: IdentityApi; private server: WebSocketServer; diff --git a/plugins/signals-node/src/lib.ts b/plugins/signals-node/src/lib.ts index d303b4d3cc..b95d4a9231 100644 --- a/plugins/signals-node/src/lib.ts +++ b/plugins/signals-node/src/lib.ts @@ -13,9 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createServiceRef } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, + createServiceRef, +} from '@backstage/backend-plugin-api'; +import { SignalService } from './SignalService'; /** @public */ -export const signalService = createServiceRef< - import('./SignalService').SignalService ->({ id: 'signals.service', scope: 'plugin' }); +export const signalService = createServiceRef({ + id: 'signals.service', + scope: 'plugin', + defaultFactory: async service => + createServiceFactory({ + service, + deps: { + logger: coreServices.logger, + identity: coreServices.identity, + // TODO: EventBroker + }, + factory({ logger, identity }) { + return SignalService.create({ identity, logger }); + }, + }), +}); diff --git a/plugins/signals-node/src/types.ts b/plugins/signals-node/src/types.ts index 99821f641d..6bfafae0b2 100644 --- a/plugins/signals-node/src/types.ts +++ b/plugins/signals-node/src/types.ts @@ -15,16 +15,16 @@ */ import { IdentityApi } from '@backstage/plugin-auth-node'; import { EventBroker } from '@backstage/plugin-events-node'; -import { Logger } from 'winston'; import { WebSocket } from 'ws'; import { JsonObject } from '@backstage/types'; +import { LoggerService } from '@backstage/backend-plugin-api'; /** * @public */ export type ServiceOptions = { eventBroker?: EventBroker; - logger: Logger; + logger: LoggerService; identity: IdentityApi; }; From 0b2142260417015d1865f4381e0057e9827b6cad Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Thu, 14 Dec 2023 15:47:29 +0200 Subject: [PATCH 036/241] chore: simplify events backend and signal hook Signed-off-by: Heikki Hellgren --- plugins/signals-node/src/SignalService.ts | 38 ++++++++----------- .../signals-react/src/hooks/useSignalApi.ts | 11 ++++-- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/plugins/signals-node/src/SignalService.ts b/plugins/signals-node/src/SignalService.ts index 54f09f583a..9c621d5cbd 100644 --- a/plugins/signals-node/src/SignalService.ts +++ b/plugins/signals-node/src/SignalService.ts @@ -37,7 +37,6 @@ import { LoggerService } from '@backstage/backend-plugin-api'; /** @public */ export class SignalService implements EventSubscriber { - private readonly serverId: string; private connections: Map = new Map< string, SignalConnection @@ -58,7 +57,6 @@ export class SignalService implements EventSubscriber { identity: this.identity, } = options); - this.serverId = uuid(); this.server = new WebSocketServer({ noServer: true, clientTracking: false, @@ -199,6 +197,21 @@ export class SignalService implements EventSubscriber { return; } + // If there is event broker, use that to publish the message to + // all signal services, including this one. + if (this.eventBroker && !brokedEvent) { + await this.eventBroker.publish({ + topic: 'signals', + eventPayload: { + recipients, + message, + topic, + }, + }); + return; + } + + // Actual websocket message sending this.connections.forEach(conn => { if (!conn.subscriptions.has(topic)) { return; @@ -217,29 +230,10 @@ export class SignalService implements EventSubscriber { conn.ws.send(jsonMessage); }); - - // If this event has not been broadcasted to all servers, then use - // EventBroker to do that - if (this.eventBroker && !brokedEvent) { - await this.eventBroker.publish({ - topic: 'signals', - eventPayload: { - recipients, - message, - topic, - }, - metadata: { server: this.serverId }, - }); - } } async onEvent(params: EventParams): Promise { - const { eventPayload, metadata } = params; - // Discard message from same server to prevent duplicate messages - if (!metadata?.server || metadata.server === this.serverId) { - return; - } - + const { eventPayload } = params; if ( !eventPayload?.recipients || !eventPayload.topic || diff --git a/plugins/signals-react/src/hooks/useSignalApi.ts b/plugins/signals-react/src/hooks/useSignalApi.ts index bb6f47a5fe..8534732264 100644 --- a/plugins/signals-react/src/hooks/useSignalApi.ts +++ b/plugins/signals-react/src/hooks/useSignalApi.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { signalApiRef } from '../api'; -import { useApi } from '@backstage/core-plugin-api'; +import { useApiHolder } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { useEffect, useState } from 'react'; @@ -23,10 +23,13 @@ export const useSignalApi = ( topic: string, onMessage: (message: JsonObject) => void, ) => { - const signals = useApi(signalApiRef); + const apiHolder = useApiHolder(); + // Use apiHolder instead useApi in case signalApi is not available in the + // backstage instance this is used + const signals = apiHolder.get(signalApiRef); const [subscription, setSubscription] = useState(null); useEffect(() => { - if (!subscription) { + if (signals && !subscription) { const sub = signals.subscribe(topic, onMessage); setSubscription(sub); } @@ -34,7 +37,7 @@ export const useSignalApi = ( useEffect(() => { return () => { - if (subscription) { + if (signals && subscription) { signals.unsubscribe(subscription); } }; From da5c3fb8188051edd4069ee24520865737b10f3e Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Tue, 2 Jan 2024 09:57:19 +0200 Subject: [PATCH 037/241] fix: address review comments Signed-off-by: Heikki Hellgren --- .changeset/poor-sheep-tease.md | 6 - packages/backend/src/index.ts | 4 +- packages/backend/src/plugins/devtools.ts | 1 - packages/backend/src/types.ts | 4 +- plugins/devtools-backend/api-report.md | 5 - plugins/devtools-backend/package.json | 1 - .../src/api/DevToolsBackendApi.ts | 16 +- plugins/devtools-backend/src/plugin.ts | 5 +- .../devtools-backend/src/service/router.ts | 16 +- .../Content/InfoContent/InfoContent.tsx | 15 +- plugins/signals-backend/api-report.md | 4 +- plugins/signals-backend/src/plugin.ts | 3 +- .../src/service/router.test.ts | 4 +- plugins/signals-backend/src/service/router.ts | 8 +- .../src/service/standaloneServer.ts | 4 +- plugins/signals-node/README.md | 10 +- plugins/signals-node/api-report.md | 41 +-- plugins/signals-node/package.json | 1 - .../signals-node/src/DefaultSignalService.ts | 238 +++++++++++++++++ plugins/signals-node/src/SignalService.ts | 250 ++---------------- plugins/signals-node/src/index.ts | 1 + plugins/signals-node/src/lib.ts | 3 +- plugins/signals-react/README.md | 20 +- plugins/signals-react/api-report.md | 15 +- plugins/signals-react/package.json | 6 +- plugins/signals-react/src/api/SignalApi.ts | 7 +- plugins/signals-react/src/hooks/index.ts | 2 +- .../hooks/{useSignalApi.ts => useSignal.ts} | 27 +- plugins/signals/api-report.md | 9 +- plugins/signals/package.json | 6 +- plugins/signals/src/api/SignalClient.ts | 49 ++-- plugins/signals/src/api/SignalsClient.test.ts | 19 +- plugins/signals/src/plugin.ts | 13 +- yarn.lock | 65 +---- 34 files changed, 413 insertions(+), 465 deletions(-) delete mode 100644 .changeset/poor-sheep-tease.md create mode 100644 plugins/signals-node/src/DefaultSignalService.ts rename plugins/signals-react/src/hooks/{useSignalApi.ts => useSignal.ts} (69%) diff --git a/.changeset/poor-sheep-tease.md b/.changeset/poor-sheep-tease.md deleted file mode 100644 index fa89ac4749..0000000000 --- a/.changeset/poor-sheep-tease.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-devtools-backend': patch -'@backstage/plugin-devtools': patch ---- - -Update devtools information almost real time using signals plugin diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index fc6b814c00..0e92698230 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -73,7 +73,7 @@ import { DefaultEventBroker } from '@backstage/plugin-events-backend'; import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'; import { MeterProvider } from '@opentelemetry/sdk-metrics'; import { metrics } from '@opentelemetry/api'; -import { SignalService } from '@backstage/plugin-signals-node'; +import { DefaultSignalService } from '@backstage/plugin-signals-node'; // Expose opentelemetry metrics using a Prometheus exporter on // http://localhost:9464/metrics . See prometheus.yml in packages/backend for @@ -100,7 +100,7 @@ function makeCreateEnv(config: Config) { }); const eventBroker = new DefaultEventBroker(root.child({ type: 'plugin' })); - const signalService = SignalService.create({ + const signalService = DefaultSignalService.create({ logger: root, eventBroker, identity, diff --git a/packages/backend/src/plugins/devtools.ts b/packages/backend/src/plugins/devtools.ts index 5488033682..8e1767ddb1 100644 --- a/packages/backend/src/plugins/devtools.ts +++ b/packages/backend/src/plugins/devtools.ts @@ -25,6 +25,5 @@ export default async function createPlugin( logger: env.logger, config: env.config, permissions: env.permissions, - signalService: env.signalService, }); } diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index d76e68c1c9..3dad2f739b 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -27,7 +27,7 @@ import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { EventBroker } from '@backstage/plugin-events-node'; -import { SignalService } from '@backstage/plugin-signals-node'; +import { DefaultSignalService } from '@backstage/plugin-signals-node'; export type PluginEnvironment = { logger: Logger; @@ -41,5 +41,5 @@ export type PluginEnvironment = { scheduler: PluginTaskScheduler; identity: IdentityApi; eventBroker: EventBroker; - signalService: SignalService; + signalService: DefaultSignalService; }; diff --git a/plugins/devtools-backend/api-report.md b/plugins/devtools-backend/api-report.md index 7049285c02..b9eb7b5a0c 100644 --- a/plugins/devtools-backend/api-report.md +++ b/plugins/devtools-backend/api-report.md @@ -11,7 +11,6 @@ import express from 'express'; import { ExternalDependency } from '@backstage/plugin-devtools-common'; import { Logger } from 'winston'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; -import { SignalService } from '@backstage/plugin-signals-node'; // @public (undocumented) export function createRouter(options: RouterOptions): Promise; @@ -25,8 +24,6 @@ export class DevToolsBackendApi { listExternalDependencyDetails(): Promise; // (undocumented) listInfo(): Promise; - // (undocumented) - listResourceUtilization(): Promise; } // @public @@ -43,7 +40,5 @@ export interface RouterOptions { logger: Logger; // (undocumented) permissions: PermissionEvaluator; - // (undocumented) - signalService?: SignalService; } ``` diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 8de7da1b39..18013bc52f 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -38,7 +38,6 @@ "@backstage/plugin-devtools-common": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", - "@backstage/plugin-signals-node": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", "@types/express": "*", diff --git a/plugins/devtools-backend/src/api/DevToolsBackendApi.ts b/plugins/devtools-backend/src/api/DevToolsBackendApi.ts index da9a1ca0dd..b71edb3391 100644 --- a/plugins/devtools-backend/src/api/DevToolsBackendApi.ts +++ b/plugins/devtools-backend/src/api/DevToolsBackendApi.ts @@ -203,21 +203,17 @@ export class DevToolsBackendApi { return configInfo; } - public async listResourceUtilization(): Promise { + public async listInfo(): Promise { + const operatingSystem = `${os.hostname()}: ${os.type} ${os.release} - ${ + os.platform + }/${os.arch}`; const usedMem = Math.floor((os.totalmem() - os.freemem()) / (1024 * 1024)); - return `Memory: ${usedMem}/${Math.floor( + const resources = `Memory: ${usedMem}/${Math.floor( os.totalmem() / (1024 * 1024), )}MB - Load: ${os .loadavg() .map(v => v.toFixed(2)) .join('/')}`; - } - - public async listInfo(): Promise { - const operatingSystem = `${os.hostname()}: ${os.type} ${os.release} - ${ - os.platform - }/${os.arch}`; - const nodeJsVersion = process.version; /* eslint-disable-next-line no-restricted-syntax */ @@ -251,7 +247,7 @@ export class DevToolsBackendApi { const info: DevToolsInfo = { operatingSystem: operatingSystem ?? 'N/A', - resourceUtilization: (await this.listResourceUtilization()) ?? 'N/A', + resourceUtilization: resources ?? 'N/A', nodeJsVersion: nodeJsVersion ?? 'N/A', backstageVersion: backstageJson && backstageJson.version ? backstageJson.version : 'N/A', diff --git a/plugins/devtools-backend/src/plugin.ts b/plugins/devtools-backend/src/plugin.ts index 02c3831128..685522557e 100644 --- a/plugins/devtools-backend/src/plugin.ts +++ b/plugins/devtools-backend/src/plugin.ts @@ -20,7 +20,6 @@ import { createBackendPlugin, } from '@backstage/backend-plugin-api'; import { createRouter } from './service/router'; -import { signalService } from '@backstage/plugin-signals-node'; /** * DevTools backend plugin @@ -36,15 +35,13 @@ export const devtoolsPlugin = createBackendPlugin({ logger: coreServices.logger, permissions: coreServices.permissions, httpRouter: coreServices.httpRouter, - signals: signalService, }, - async init({ config, logger, permissions, httpRouter, signals }) { + async init({ config, logger, permissions, httpRouter }) { httpRouter.use( await createRouter({ config, logger: loggerToWinstonLogger(logger), permissions, - signalService: signals, }), ); }, diff --git a/plugins/devtools-backend/src/service/router.ts b/plugins/devtools-backend/src/service/router.ts index 106eb44309..fbeeb5af84 100644 --- a/plugins/devtools-backend/src/service/router.ts +++ b/plugins/devtools-backend/src/service/router.ts @@ -33,7 +33,6 @@ import { errorHandler } from '@backstage/backend-common'; import express from 'express'; import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node'; import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; -import { SignalService } from '@backstage/plugin-signals-node'; /** @public */ export interface RouterOptions { @@ -41,30 +40,17 @@ export interface RouterOptions { logger: Logger; config: Config; permissions: PermissionEvaluator; - signalService?: SignalService; } /** @public */ export async function createRouter( options: RouterOptions, ): Promise { - const { logger, config, permissions, signalService } = options; + const { logger, config, permissions } = options; const devToolsBackendApi = options.devToolsBackendApi || new DevToolsBackendApi(logger, config); - if (signalService) { - // Publish info periodically using the signal service - setInterval(async () => { - if (signalService.hasSubscribers('devtools:resources')) { - const info = await devToolsBackendApi.listResourceUtilization(); - await signalService.publish('*', 'devtools:resources', { - resources: info, - }); - } - }, 5000); - } - const router = Router(); router.use(express.json()); router.use( diff --git a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx index 2480bf5233..0ed43d2fee 100644 --- a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx @@ -29,7 +29,7 @@ import { Theme, } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; -import React, { useEffect, useState } from 'react'; +import React from 'react'; import { useInfo } from '../../../hooks'; import { InfoDependenciesTable } from './InfoDependenciesTable'; import DescriptionIcon from '@material-ui/icons/Description'; @@ -38,7 +38,6 @@ import DeveloperBoardIcon from '@material-ui/icons/DeveloperBoard'; import { BackstageLogoIcon } from './BackstageLogoIcon'; import FileCopyIcon from '@material-ui/icons/FileCopy'; import { DevToolsInfo } from '@backstage/plugin-devtools-common'; -import { useSignalApi } from '@backstage/plugin-signals-react'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -73,17 +72,7 @@ const copyToClipboard = ({ about }: { about: DevToolsInfo | undefined }) => { /** @public */ export const InfoContent = () => { const classes = useStyles(); - const [resources, setResources] = useState(undefined); const { about, loading, error } = useInfo(); - useSignalApi('devtools:resources', message => { - setResources(message.resources as string); - }); - - useEffect(() => { - if (!loading && !error && about) { - setResources(about.resourceUtilization); - } - }, [about, loading, error]); if (loading) { return ; @@ -113,7 +102,7 @@ export const InfoContent = () => { diff --git a/plugins/signals-backend/api-report.md b/plugins/signals-backend/api-report.md index afbc63abf2..e96dd2e09c 100644 --- a/plugins/signals-backend/api-report.md +++ b/plugins/signals-backend/api-report.md @@ -5,7 +5,7 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; import express from 'express'; -import { Logger } from 'winston'; +import { LoggerService } from '@backstage/backend-plugin-api'; import { SignalService } from '@backstage/plugin-signals-node'; // @public (undocumented) @@ -14,7 +14,7 @@ export function createRouter(options: RouterOptions): Promise; // @public (undocumented) export interface RouterOptions { // (undocumented) - logger: Logger; + logger: LoggerService; // (undocumented) service: SignalService; } diff --git a/plugins/signals-backend/src/plugin.ts b/plugins/signals-backend/src/plugin.ts index 8ade4e85b5..68bbf27377 100644 --- a/plugins/signals-backend/src/plugin.ts +++ b/plugins/signals-backend/src/plugin.ts @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { loggerToWinstonLogger } from '@backstage/backend-common'; import { coreServices, createBackendPlugin, @@ -38,7 +37,7 @@ export const signalsPlugin = createBackendPlugin({ async init({ httpRouter, logger, service }) { httpRouter.use( await createRouter({ - logger: loggerToWinstonLogger(logger), + logger, service, }), ); diff --git a/plugins/signals-backend/src/service/router.test.ts b/plugins/signals-backend/src/service/router.test.ts index b41704e008..281d6ed4a5 100644 --- a/plugins/signals-backend/src/service/router.test.ts +++ b/plugins/signals-backend/src/service/router.test.ts @@ -18,9 +18,9 @@ import express from 'express'; import request from 'supertest'; import { createRouter } from './router'; -import { SignalService } from '@backstage/plugin-signals-node'; +import { DefaultSignalService } from '@backstage/plugin-signals-node'; -const signalsServiceMock: jest.Mocked = {} as any; +const signalsServiceMock: jest.Mocked = {} as any; describe('createRouter', () => { let app: express.Express; diff --git a/plugins/signals-backend/src/service/router.ts b/plugins/signals-backend/src/service/router.ts index 8926910544..28bafce14a 100644 --- a/plugins/signals-backend/src/service/router.ts +++ b/plugins/signals-backend/src/service/router.ts @@ -16,14 +16,14 @@ import { errorHandler } from '@backstage/backend-common'; import express, { NextFunction, Request, Response } from 'express'; import Router from 'express-promise-router'; -import { Logger } from 'winston'; +import { LoggerService } from '@backstage/backend-plugin-api'; import { SignalService } from '@backstage/plugin-signals-node'; import * as https from 'https'; import http from 'http'; /** @public */ export interface RouterOptions { - logger: Logger; + logger: LoggerService; service: SignalService; } @@ -48,9 +48,9 @@ export async function createRouter( if (!subscribed) { subscribed = true; server.on('upgrade', async (request, socket, head) => { - // Only upgrade if request to root of the signals plugin + // TODO: Find a way to make this more generic if (request.url === '/api/signals') { - await service.handleUpgrade(request, socket, head); + await service.handleUpgrade({ server, request, socket, head }); } }); } diff --git a/plugins/signals-backend/src/service/standaloneServer.ts b/plugins/signals-backend/src/service/standaloneServer.ts index 0728b2fde5..e1ce27aee4 100644 --- a/plugins/signals-backend/src/service/standaloneServer.ts +++ b/plugins/signals-backend/src/service/standaloneServer.ts @@ -21,7 +21,7 @@ import { import { Server } from 'http'; import { Logger } from 'winston'; import { createRouter } from './router'; -import { SignalService } from '@backstage/plugin-signals-node'; +import { DefaultSignalService } from '@backstage/plugin-signals-node'; import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; export interface ServerOptions { @@ -43,7 +43,7 @@ export async function startStandaloneServer( issuer: await discovery.getExternalBaseUrl('auth'), }); - const signals = SignalService.create({ + const signals = DefaultSignalService.create({ logger: logger, identity, }); diff --git a/plugins/signals-node/README.md b/plugins/signals-node/README.md index abea6c6d22..14c9332dc1 100644 --- a/plugins/signals-node/README.md +++ b/plugins/signals-node/README.md @@ -56,13 +56,9 @@ all subscribers, you can use `*` as `to` parameter. ```ts // Periodic sending example setInterval(async () => { - // You can use hasSubscribers to check if the message will be sent to anyone - // in case you need some heavy processing before that - if (signalService.hasSubscribers('plugin:topic')) { - await signalService.publish('*', 'plugin:topic', { - message: 'hello world', - }); - } + await signalService.publish('*', 'plugin:topic', { + message: 'hello world', + }); }, 5000); ``` diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md index 7bfffc2540..d85163040b 100644 --- a/plugins/signals-node/api-report.md +++ b/plugins/signals-node/api-report.md @@ -7,14 +7,26 @@ import { Duplex } from 'stream'; import { EventBroker } from '@backstage/plugin-events-node'; -import { EventParams } from '@backstage/plugin-events-node'; -import { EventSubscriber } from '@backstage/plugin-events-node'; +import http from 'http'; +import https from 'https'; import { IdentityApi } from '@backstage/plugin-auth-node'; import { IncomingMessage } from 'http'; import { JsonObject } from '@backstage/types'; import { LoggerService } from '@backstage/backend-plugin-api'; import { ServiceRef } from '@backstage/backend-plugin-api'; +// @public (undocumented) +export class DefaultSignalService implements SignalService { + // (undocumented) + static create(options: ServiceOptions): DefaultSignalService; + handleUpgrade(options: SignalServiceUpgradeOptions): Promise; + publish( + to: string | string[], + topic: string, + message: JsonObject, + ): Promise; +} + // @public (undocumented) export type ServiceOptions = { eventBroker?: EventBroker; @@ -30,28 +42,25 @@ export type SignalEventBrokerPayload = { }; // @public (undocumented) -export class SignalService implements EventSubscriber { - // (undocumented) - static create(options: ServiceOptions): SignalService; - handleUpgrade: ( - req: IncomingMessage, - socket: Duplex, - head: Buffer, - ) => Promise; - hasSubscribers(topic: string): boolean; - // (undocumented) - onEvent(params: EventParams): Promise; +export type SignalService = { publish( to: string | string[], topic: string, message: JsonObject, ): Promise; - // (undocumented) - supportsEventTopics(): string[]; -} + handleUpgrade(options: SignalServiceUpgradeOptions): Promise; +}; // @public (undocumented) export const signalService: ServiceRef; +// @public (undocumented) +export type SignalServiceUpgradeOptions = { + server: https.Server | http.Server; + request: IncomingMessage; + socket: Duplex; + head: Buffer; +}; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/signals-node/package.json b/plugins/signals-node/package.json index d5e980d857..d3230432f1 100644 --- a/plugins/signals-node/package.json +++ b/plugins/signals-node/package.json @@ -37,7 +37,6 @@ "@backstage/types": "workspace:^", "express": "^4.17.1", "uuid": "^8.0.0", - "winston": "^3.2.1", "ws": "^8.14.2" } } diff --git a/plugins/signals-node/src/DefaultSignalService.ts b/plugins/signals-node/src/DefaultSignalService.ts new file mode 100644 index 0000000000..cab6e83c81 --- /dev/null +++ b/plugins/signals-node/src/DefaultSignalService.ts @@ -0,0 +1,238 @@ +/* + * Copyright 2023 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 { EventBroker, EventParams } from '@backstage/plugin-events-node'; +import { + ServiceOptions, + SignalConnection, + SignalEventBrokerPayload, +} from './types'; +import { RawData, WebSocket, WebSocketServer } from 'ws'; +import { IncomingMessage } from 'http'; +import { v4 as uuid } from 'uuid'; +import { JsonObject } from '@backstage/types'; +import { + BackstageIdentityResponse, + IdentityApi, + IdentityApiGetIdentityRequest, +} from '@backstage/plugin-auth-node'; +import { LoggerService } from '@backstage/backend-plugin-api'; +import { SignalService, SignalServiceUpgradeOptions } from './SignalService'; + +/** @public */ +export class DefaultSignalService implements SignalService { + private connections: Map = new Map< + string, + SignalConnection + >(); + private eventBroker?: EventBroker; + private logger: LoggerService; + private identity: IdentityApi; + private server: WebSocketServer; + + static create(options: ServiceOptions) { + return new DefaultSignalService(options); + } + + private constructor(options: ServiceOptions) { + ({ + eventBroker: this.eventBroker, + logger: this.logger, + identity: this.identity, + } = options); + + this.server = new WebSocketServer({ + noServer: true, + clientTracking: false, + }); + + this.eventBroker?.subscribe({ + supportsEventTopics: () => ['signals'], + onEvent: (params: EventParams) => + this.onEventBrokerEvent(params), + }); + } + + /** + * Handles request upgrade to websocket and adds the connection to internal + * list for publish/subscribe functionality + * @param req - Request + */ + async handleUpgrade(options: SignalServiceUpgradeOptions) { + const { request, socket, head } = options; + let identity: BackstageIdentityResponse | undefined = undefined; + + // Authentication token is passed in Sec-WebSocket-Protocol header as there + // is no other way to pass the token with plain websockets + const token = request.headers['sec-websocket-protocol']; + if (token) { + identity = await this.identity.getIdentity({ + request: { + headers: { authorization: token }, + }, + } as IdentityApiGetIdentityRequest); + } + + this.server.handleUpgrade( + request, + socket, + head, + (ws: WebSocket, __: IncomingMessage) => { + this.addConnection(ws, identity); + }, + ); + } + + private addConnection(ws: WebSocket, identity?: BackstageIdentityResponse) { + const id = uuid(); + + const conn = { + id, + user: identity?.identity.userEntityRef ?? 'user:default/guest', + ws, + ownershipEntityRefs: identity?.identity.ownershipEntityRefs ?? [], + subscriptions: new Set(), + }; + + this.connections.set(id, conn); + + ws.on('error', (err: Error) => { + this.logger.info( + `Error occurred with connection ${id}: ${err}, closing connection`, + ); + ws.close(); + this.connections.delete(id); + }); + + ws.on('close', (code: number, reason: Buffer) => { + this.logger.info( + `Connection ${id} closed with code ${code}, reason: ${reason}`, + ); + this.connections.delete(id); + }); + + ws.on('message', (data: RawData, isBinary: boolean) => { + this.logger.debug(`Received message from connection ${id}: ${data}`); + if (isBinary) { + return; + } + try { + const json = JSON.parse(data.toString()) as JsonObject; + this.handleMessage(conn, json); + } catch (err: any) { + this.logger.error( + `Invalid message received from connection ${id}: ${err}`, + ); + } + }); + } + + private handleMessage(connection: SignalConnection, message: JsonObject) { + if (message.action === 'subscribe' && message.topic) { + this.logger.info( + `Connection ${connection.id} subscribed to ${message.topic}`, + ); + connection.subscriptions.add(message.topic as string); + } + + if (message.action === 'unsubscribe' && message.topic) { + this.logger.info( + `Connection ${connection.id} unsubscribed from ${message.topic}`, + ); + connection.subscriptions.delete(message.topic as string); + } + } + + /** + * Publishes a message to user refs to specific topic + * @param to - string or array of user ref strings to publish message to + * @param topic - message topic + * @param message - message to publish + */ + async publish(to: string | string[], topic: string, message: JsonObject) { + await this.publishInternal( + Array.isArray(to) ? to : [to], + topic, + message, + false, + ); + } + + private async publishInternal( + recipients: string[], + topic: string, + message: JsonObject, + brokedEvent: boolean, + ) { + const jsonMessage = JSON.stringify({ topic, message }); + if (jsonMessage.length === 0) { + return; + } + + // If there is event broker, use that to publish the message to + // all signal services, including this one. + if (this.eventBroker && !brokedEvent) { + await this.eventBroker.publish({ + topic: 'signals', + eventPayload: { + recipients, + message, + topic, + }, + }); + return; + } + + // Actual websocket message sending + this.connections.forEach(conn => { + if (!conn.subscriptions.has(topic)) { + return; + } + // Sending to all users can be done with '*' + if ( + !recipients.includes('*') && + !conn.ownershipEntityRefs.some(ref => recipients.includes(ref)) + ) { + return; + } + + if (conn.ws.readyState !== WebSocket.OPEN) { + return; + } + + conn.ws.send(jsonMessage); + }); + } + + private async onEventBrokerEvent( + params: EventParams, + ): Promise { + const { eventPayload } = params; + if ( + !eventPayload?.recipients || + !eventPayload.topic || + !eventPayload.message + ) { + return; + } + + await this.publishInternal( + eventPayload.recipients, + eventPayload.topic, + eventPayload.message, + true, + ); + } +} diff --git a/plugins/signals-node/src/SignalService.ts b/plugins/signals-node/src/SignalService.ts index 9c621d5cbd..7095c29858 100644 --- a/plugins/signals-node/src/SignalService.ts +++ b/plugins/signals-node/src/SignalService.ts @@ -1,5 +1,5 @@ /* - * Copyright 2023 The Backstage Authors + * Copyright 2024 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. @@ -13,244 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - EventBroker, - EventParams, - EventSubscriber, -} from '@backstage/plugin-events-node'; -import { - ServiceOptions, - SignalConnection, - SignalEventBrokerPayload, -} from './types'; -import { RawData, WebSocket, WebSocketServer } from 'ws'; -import { IncomingMessage } from 'http'; -import { v4 as uuid } from 'uuid'; import { JsonObject } from '@backstage/types'; -import { - BackstageIdentityResponse, - IdentityApi, - IdentityApiGetIdentityRequest, -} from '@backstage/plugin-auth-node'; +import http, { IncomingMessage } from 'http'; import { Duplex } from 'stream'; -import { LoggerService } from '@backstage/backend-plugin-api'; +import https from 'https'; /** @public */ -export class SignalService implements EventSubscriber { - private connections: Map = new Map< - string, - SignalConnection - >(); - private eventBroker?: EventBroker; - private logger: LoggerService; - private identity: IdentityApi; - private server: WebSocketServer; - - static create(options: ServiceOptions) { - return new SignalService(options); - } - - private constructor(options: ServiceOptions) { - ({ - eventBroker: this.eventBroker, - logger: this.logger, - identity: this.identity, - } = options); - - this.server = new WebSocketServer({ - noServer: true, - clientTracking: false, - }); - - this.eventBroker?.subscribe(this); - } - - /** - * Handles request upgrade to websocket and adds the connection to internal - * list for publish/subscribe functionality - * @param req - Request - */ - handleUpgrade = async ( - req: IncomingMessage, - socket: Duplex, - head: Buffer, - ) => { - let identity: BackstageIdentityResponse | undefined = undefined; - - // Authentication token is passed in Sec-WebSocket-Protocol header as there - // is no other way to pass the token with plain websockets - const token = req.headers['sec-websocket-protocol']; - if (token) { - identity = await this.identity.getIdentity({ - request: { - headers: { authorization: token }, - }, - } as IdentityApiGetIdentityRequest); - } - - this.server.handleUpgrade( - req, - socket, - head, - (ws: WebSocket, __: IncomingMessage) => { - this.addConnection(ws, identity); - }, - ); - }; - - private addConnection(ws: WebSocket, identity?: BackstageIdentityResponse) { - const id = uuid(); - - const conn = { - id, - user: identity?.identity.userEntityRef ?? 'user:default/guest', - ws, - ownershipEntityRefs: identity?.identity.ownershipEntityRefs ?? [], - subscriptions: new Set(), - }; - - this.connections.set(id, conn); - - ws.on('error', (err: Error) => { - this.logger.info( - `Error occurred with connection ${id}: ${err}, closing connection`, - ); - ws.close(); - this.connections.delete(id); - }); - - ws.on('close', (code: number, reason: Buffer) => { - this.logger.info( - `Connection ${id} closed with code ${code}, reason: ${reason}`, - ); - this.connections.delete(id); - }); - - ws.on('message', (data: RawData, isBinary: boolean) => { - this.logger.debug(`Received message from connection ${id}: ${data}`); - if (isBinary) { - return; - } - try { - const json = JSON.parse(data.toString()) as JsonObject; - this.handleMessage(conn, json); - } catch (err: any) { - this.logger.error( - `Invalid message received from connection ${id}: ${err}`, - ); - } - }); - } - - private handleMessage(connection: SignalConnection, message: JsonObject) { - if (message.action === 'subscribe' && message.topic) { - this.logger.info( - `Connection ${connection.id} subscribed to ${message.topic}`, - ); - connection.subscriptions.add(message.topic as string); - } - - if (message.action === 'unsubscribe' && message.topic) { - this.logger.info( - `Connection ${connection.id} unsubscribed from ${message.topic}`, - ); - connection.subscriptions.delete(message.topic as string); - } - } +export type SignalServiceUpgradeOptions = { + server: https.Server | http.Server; + request: IncomingMessage; + socket: Duplex; + head: Buffer; +}; +/** @public */ +export type SignalService = { /** * Publishes a message to user refs to specific topic - * @param to - string or array of user ref strings to publish message to - * @param topic - message topic - * @param message - message to publish */ - async publish(to: string | string[], topic: string, message: JsonObject) { - await this.publishInternal( - Array.isArray(to) ? to : [to], - topic, - message, - false, - ); - } - - /** - * Checks if there is active subscriptions to specific topic. - * This can be useful to skip heavy processing before publishing messages if there are no subscriptions. - * @param topic - topic to check for subscriptions - */ - hasSubscribers(topic: string): boolean { - return ( - [...this.connections.values()].find(conn => - conn.subscriptions.has(topic), - ) !== undefined - ); - } - - private async publishInternal( - recipients: string[], + publish( + to: string | string[], topic: string, message: JsonObject, - brokedEvent: boolean, - ) { - const jsonMessage = JSON.stringify({ topic, message }); - if (jsonMessage.length === 0) { - return; - } + ): Promise; - // If there is event broker, use that to publish the message to - // all signal services, including this one. - if (this.eventBroker && !brokedEvent) { - await this.eventBroker.publish({ - topic: 'signals', - eventPayload: { - recipients, - message, - topic, - }, - }); - return; - } - - // Actual websocket message sending - this.connections.forEach(conn => { - if (!conn.subscriptions.has(topic)) { - return; - } - // Sending to all users can be done with '*' - if ( - !recipients.includes('*') && - !conn.ownershipEntityRefs.some(ref => recipients.includes(ref)) - ) { - return; - } - - if (conn.ws.readyState !== WebSocket.OPEN) { - return; - } - - conn.ws.send(jsonMessage); - }); - } - - async onEvent(params: EventParams): Promise { - const { eventPayload } = params; - if ( - !eventPayload?.recipients || - !eventPayload.topic || - !eventPayload.message - ) { - return; - } - - await this.publishInternal( - eventPayload.recipients, - eventPayload.topic, - eventPayload.message, - true, - ); - } - - supportsEventTopics(): string[] { - return ['signals']; - } -} + /** + * Handles request upgrade + */ + handleUpgrade(options: SignalServiceUpgradeOptions): Promise; +}; diff --git a/plugins/signals-node/src/index.ts b/plugins/signals-node/src/index.ts index 43a3a88ac0..f9c220b1e9 100644 --- a/plugins/signals-node/src/index.ts +++ b/plugins/signals-node/src/index.ts @@ -15,5 +15,6 @@ */ export * from './lib'; +export * from './DefaultSignalService'; export * from './SignalService'; export * from './types'; diff --git a/plugins/signals-node/src/lib.ts b/plugins/signals-node/src/lib.ts index b95d4a9231..c7e7c4a6ae 100644 --- a/plugins/signals-node/src/lib.ts +++ b/plugins/signals-node/src/lib.ts @@ -18,6 +18,7 @@ import { createServiceFactory, createServiceRef, } from '@backstage/backend-plugin-api'; +import { DefaultSignalService } from './DefaultSignalService'; import { SignalService } from './SignalService'; /** @public */ @@ -33,7 +34,7 @@ export const signalService = createServiceRef({ // TODO: EventBroker }, factory({ logger, identity }) { - return SignalService.create({ identity, logger }); + return DefaultSignalService.create({ identity, logger }); }, }), }); diff --git a/plugins/signals-react/README.md b/plugins/signals-react/README.md index 9bdf5e964f..244a4ec43d 100644 --- a/plugins/signals-react/README.md +++ b/plugins/signals-react/README.md @@ -20,15 +20,12 @@ of connections to the backend and also to allow multiple subscriptions using the Example of using the hook: ```ts -import { useSignalApi } from '@backstage/plugin-signals-react'; +import { useSignal } from '@backstage/plugin-signals-react'; -const [message, setMessage] = useState(undefined); -useSignalApi('myplugin:topic', message => { - setMessage(message); -}); +const { lastSignal } = useSignal('myplugin:topic'); ``` -Whenever backend publishes new message to the topic `myplugin:topic`, the state of this component is changed. +Whenever backend publishes new message to the topic `myplugin:topic`, the lastSignal is changed. ## Using API directly @@ -39,9 +36,12 @@ subscriptions. import { signalsApiRef } from '@backstage/plugin-signals-react'; const signals = useApi(signalsApiRef); -signals.subscribe('myplugin:topic', (message: JsonObject) => { - console.log(message); -}); +const { unsubscribe } = signals.subscribe( + 'myplugin:topic', + (message: JsonObject) => { + console.log(message); + }, +); // Remember to unsubscribe -signals.unsubscribe('myplugin:topic'); +unsubscribe(); ``` diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md index d28b806103..8ad0c06fbe 100644 --- a/plugins/signals-react/api-report.md +++ b/plugins/signals-react/api-report.md @@ -8,18 +8,21 @@ import { JsonObject } from '@backstage/types'; // @public (undocumented) export type SignalApi = { - subscribe(topic: string, onMessage: (message: JsonObject) => void): string; - unsubscribe(subscription: string): void; + subscribe( + topic: string, + onMessage: (message: JsonObject) => void, + ): { + unsubscribe: () => void; + }; }; // @public (undocumented) export const signalApiRef: ApiRef; // @public (undocumented) -export const useSignalApi: ( - topic: string, - onMessage: (message: JsonObject) => void, -) => void; +export const useSignal: (topic: string) => { + lastSignal: JsonObject | null; +}; // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/signals-react/package.json b/plugins/signals-react/package.json index 148bc27cb3..06df050ccd 100644 --- a/plugins/signals-react/package.json +++ b/plugins/signals-react/package.json @@ -26,7 +26,7 @@ "dependencies": { "@backstage/core-plugin-api": "workspace:^", "@backstage/types": "workspace:^", - "@material-ui/core": "^4.9.13" + "@material-ui/core": "^4.12.4" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0" @@ -34,8 +34,8 @@ "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", - "@testing-library/jest-dom": "^5.10.1", - "@testing-library/react": "^12.1.3" + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^14.0.0" }, "files": [ "dist" diff --git a/plugins/signals-react/src/api/SignalApi.ts b/plugins/signals-react/src/api/SignalApi.ts index f63023bf5f..09eacafa4d 100644 --- a/plugins/signals-react/src/api/SignalApi.ts +++ b/plugins/signals-react/src/api/SignalApi.ts @@ -23,7 +23,8 @@ export const signalApiRef = createApiRef({ /** @public */ export type SignalApi = { - subscribe(topic: string, onMessage: (message: JsonObject) => void): string; - - unsubscribe(subscription: string): void; + subscribe( + topic: string, + onMessage: (message: JsonObject) => void, + ): { unsubscribe: () => void }; }; diff --git a/plugins/signals-react/src/hooks/index.ts b/plugins/signals-react/src/hooks/index.ts index 921eca8d30..a7bf7ebad2 100644 --- a/plugins/signals-react/src/hooks/index.ts +++ b/plugins/signals-react/src/hooks/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './useSignalApi'; +export * from './useSignal'; diff --git a/plugins/signals-react/src/hooks/useSignalApi.ts b/plugins/signals-react/src/hooks/useSignal.ts similarity index 69% rename from plugins/signals-react/src/hooks/useSignalApi.ts rename to plugins/signals-react/src/hooks/useSignal.ts index 8534732264..1176769a06 100644 --- a/plugins/signals-react/src/hooks/useSignalApi.ts +++ b/plugins/signals-react/src/hooks/useSignal.ts @@ -19,27 +19,26 @@ import { JsonObject } from '@backstage/types'; import { useEffect, useState } from 'react'; /** @public */ -export const useSignalApi = ( - topic: string, - onMessage: (message: JsonObject) => void, -) => { +export const useSignal = (topic: string) => { const apiHolder = useApiHolder(); // Use apiHolder instead useApi in case signalApi is not available in the // backstage instance this is used const signals = apiHolder.get(signalApiRef); - const [subscription, setSubscription] = useState(null); + const [lastSignal, setLastSignal] = useState(null); useEffect(() => { - if (signals && !subscription) { - const sub = signals.subscribe(topic, onMessage); - setSubscription(sub); + let unsub: null | (() => void) = null; + if (signals) { + const { unsubscribe } = signals.subscribe(topic, (msg: JsonObject) => { + setLastSignal(msg); + }); + unsub = unsubscribe; } - }, [subscription, signals, onMessage, topic]); - - useEffect(() => { return () => { - if (signals && subscription) { - signals.unsubscribe(subscription); + if (signals && unsub) { + unsub(); } }; - }, [subscription, signals, topic]); + }, [signals, topic]); + + return { lastSignal }; }; diff --git a/plugins/signals/api-report.md b/plugins/signals/api-report.md index 28a70a339c..97c882dda4 100644 --- a/plugins/signals/api-report.md +++ b/plugins/signals/api-report.md @@ -23,9 +23,12 @@ export class SignalClient implements SignalApi { // (undocumented) static readonly DEFAULT_RECONNECT_TIMEOUT_MS: number; // (undocumented) - subscribe(topic: string, onMessage: (message: JsonObject) => void): string; - // (undocumented) - unsubscribe(subscription: string): void; + subscribe( + topic: string, + onMessage: (message: JsonObject) => void, + ): { + unsubscribe: () => void; + }; } // @public (undocumented) diff --git a/plugins/signals/package.json b/plugins/signals/package.json index e708d46329..cec95280c1 100644 --- a/plugins/signals/package.json +++ b/plugins/signals/package.json @@ -28,7 +28,7 @@ "@backstage/plugin-signals-react": "workspace:^", "@backstage/theme": "workspace:^", "@backstage/types": "workspace:^", - "@material-ui/core": "^4.9.13", + "@material-ui/core": "^4.12.4", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.61", "react-use": "^17.2.4", @@ -42,8 +42,8 @@ "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", "@backstage/test-utils": "workspace:^", - "@testing-library/jest-dom": "^5.10.1", - "@testing-library/react": "^12.1.3", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", "jest-websocket-mock": "^2.5.0", "msw": "^1.0.0" diff --git a/plugins/signals/src/api/SignalClient.ts b/plugins/signals/src/api/SignalClient.ts index 64c1866fab..24a38a49e3 100644 --- a/plugins/signals/src/api/SignalClient.ts +++ b/plugins/signals/src/api/SignalClient.ts @@ -62,7 +62,10 @@ export class SignalClient implements SignalApi { private reconnectTimeout: number, ) {} - subscribe(topic: string, onMessage: (message: JsonObject) => void): string { + subscribe( + topic: string, + onMessage: (message: JsonObject) => void, + ): { unsubscribe: () => void } { const subscriptionId = uuid(); const exists = [...this.subscriptions.values()].find( sub => sub.topic === topic, @@ -79,30 +82,30 @@ export class SignalClient implements SignalApi { .catch(() => { this.reconnect(); }); - return subscriptionId; - } - unsubscribe(subscription: string): void { - const sub = this.subscriptions.get(subscription); - if (!sub) { - return; - } - const topic = sub.topic; - this.subscriptions.delete(subscription); - const exists = [...this.subscriptions.values()].find( - s => s.topic === topic, - ); - // If there are subscriptions still listening to this topic, do not - // unsubscribe from the server - if (!exists) { - this.send({ action: 'unsubscribe', topic: sub.topic }); - } + const unsubscribe = () => { + const sub = this.subscriptions.get(subscriptionId); + if (!sub) { + return; + } + this.subscriptions.delete(subscriptionId); + const multipleExists = [...this.subscriptions.values()].find( + s => s.topic === topic, + ); + // If there are subscriptions still listening to this topic, do not + // unsubscribe from the server + if (!multipleExists) { + this.send({ action: 'unsubscribe', topic: sub.topic }); + } - // If there are no subscriptions, close the connection - if (this.subscriptions.size === 0) { - this.ws?.close(WS_CLOSE_NORMAL); - this.ws = null; - } + // If there are no subscriptions, close the connection + if (this.subscriptions.size === 0) { + this.ws?.close(WS_CLOSE_NORMAL); + this.ws = null; + } + }; + + return { unsubscribe }; } private send(data?: JsonObject): void { diff --git a/plugins/signals/src/api/SignalsClient.test.ts b/plugins/signals/src/api/SignalsClient.test.ts index 60d67e6c4b..ec202e2703 100644 --- a/plugins/signals/src/api/SignalsClient.test.ts +++ b/plugins/signals/src/api/SignalsClient.test.ts @@ -44,7 +44,7 @@ describe('SignalsClient', () => { it('should handle single subscription correctly', async () => { const messageMock = jest.fn(); const client = SignalClient.create({ discoveryApi, identity }); - const sub = client.subscribe('topic', messageMock); + const { unsubscribe } = client.subscribe('topic', messageMock); await server.connected; await expect(server).toReceiveMessage({ @@ -54,7 +54,8 @@ describe('SignalsClient', () => { server.send({ topic: 'topic', message: { hello: 'world' } }); expect(messageMock).toHaveBeenCalledWith({ hello: 'world' }); - client.unsubscribe(sub); + await unsubscribe(); + await expect(server).toReceiveMessage({ action: 'unsubscribe', topic: 'topic', @@ -66,8 +67,14 @@ describe('SignalsClient', () => { const messageMock2 = jest.fn(); const client1 = SignalClient.create({ discoveryApi, identity }); const client2 = SignalClient.create({ discoveryApi, identity }); - const sub1 = client1.subscribe('topic', messageMock1); - const sub2 = client2.subscribe('topic', messageMock2); + const { unsubscribe: unsubscribe1 } = client1.subscribe( + 'topic', + messageMock1, + ); + const { unsubscribe: unsubscribe2 } = client2.subscribe( + 'topic', + messageMock2, + ); await server.connected; @@ -79,13 +86,13 @@ describe('SignalsClient', () => { expect(messageMock1).toHaveBeenCalledWith({ hello: 'world' }); expect(messageMock2).toHaveBeenCalledWith({ hello: 'world' }); - client1.unsubscribe(sub1); + await unsubscribe1(); await expect(server).not.toReceiveMessage({ action: 'unsubscribe', topic: 'topic', }); - client2.unsubscribe(sub2); + await unsubscribe2(); await expect(server).toReceiveMessage({ action: 'unsubscribe', topic: 'topic', diff --git a/plugins/signals/src/plugin.ts b/plugins/signals/src/plugin.ts index 1482d7dae1..eb3f9126e2 100644 --- a/plugins/signals/src/plugin.ts +++ b/plugins/signals/src/plugin.ts @@ -22,8 +22,6 @@ import { import { signalApiRef } from '@backstage/plugin-signals-react'; import { SignalClient } from './api/SignalClient'; -let clientInstance: SignalClient | undefined = undefined; - /** @public */ export const signalsPlugin = createPlugin({ id: 'signals', @@ -35,13 +33,10 @@ export const signalsPlugin = createPlugin({ discoveryApi: discoveryApiRef, }, factory: ({ identity, discoveryApi }) => { - if (!clientInstance) { - clientInstance = SignalClient.create({ - identity, - discoveryApi, - }); - } - return clientInstance; + return SignalClient.create({ + identity, + discoveryApi, + }); }, }), ], diff --git a/yarn.lock b/yarn.lock index 7a3fbb3902..72e4e43d02 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,7 +12,7 @@ __metadata: languageName: node linkType: hard -"@adobe/css-tools@npm:^4.0.1, @adobe/css-tools@npm:^4.3.2": +"@adobe/css-tools@npm:^4.3.2": version: 4.3.2 resolution: "@adobe/css-tools@npm:4.3.2" checksum: 9667d61d55dc3b0a315c530ae84e016ce5267c4dd8ac00abb40108dc98e07b98e3090ce8b87acd51a41a68d9e84dcccb08cdf21c902572a9cf9dcaf830da4ae3 @@ -6203,7 +6203,6 @@ __metadata: "@backstage/plugin-devtools-common": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" - "@backstage/plugin-signals-node": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": ^1.1.3 "@types/express": "*" @@ -8875,12 +8874,11 @@ __metadata: "@types/express": ^4.17.21 express: ^4.17.1 uuid: ^8.0.0 - winston: ^3.2.1 ws: ^8.14.2 languageName: unknown linkType: soft -"@backstage/plugin-signals-react@workspace:plugins/signals-react": +"@backstage/plugin-signals-react@workspace:^, @backstage/plugin-signals-react@workspace:plugins/signals-react": version: 0.0.0-use.local resolution: "@backstage/plugin-signals-react@workspace:plugins/signals-react" dependencies: @@ -8888,9 +8886,9 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" - "@material-ui/core": ^4.9.13 - "@testing-library/jest-dom": ^5.10.1 - "@testing-library/react": ^12.1.3 + "@material-ui/core": ^4.12.4 + "@testing-library/jest-dom": ^6.0.0 + "@testing-library/react": ^14.0.0 peerDependencies: react: ^16.13.1 || ^17.0.0 languageName: unknown @@ -8909,11 +8907,11 @@ __metadata: "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" - "@material-ui/core": ^4.9.13 + "@material-ui/core": ^4.12.4 "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.61 - "@testing-library/jest-dom": ^5.10.1 - "@testing-library/react": ^12.1.3 + "@testing-library/jest-dom": ^6.0.0 + "@testing-library/react": ^14.0.0 "@testing-library/user-event": ^14.0.0 jest-websocket-mock: ^2.5.0 msw: ^1.0.0 @@ -17216,22 +17214,6 @@ __metadata: languageName: unknown linkType: soft -"@testing-library/dom@npm:^8.0.0": - version: 8.20.1 - resolution: "@testing-library/dom@npm:8.20.1" - dependencies: - "@babel/code-frame": ^7.10.4 - "@babel/runtime": ^7.12.5 - "@types/aria-query": ^5.0.1 - aria-query: 5.1.3 - chalk: ^4.1.0 - dom-accessibility-api: ^0.5.9 - lz-string: ^1.5.0 - pretty-format: ^27.0.2 - checksum: 06fc8dc67849aadb726cbbad0e7546afdf8923bd39acb64c576d706249bd7d0d05f08e08a31913fb621162e3b9c2bd0dce15964437f030f9fa4476326fdd3007 - languageName: node - linkType: hard - "@testing-library/dom@npm:^9.0.0": version: 9.3.3 resolution: "@testing-library/dom@npm:9.3.3" @@ -17248,23 +17230,6 @@ __metadata: languageName: node linkType: hard -"@testing-library/jest-dom@npm:^5.10.1": - version: 5.17.0 - resolution: "@testing-library/jest-dom@npm:5.17.0" - dependencies: - "@adobe/css-tools": ^4.0.1 - "@babel/runtime": ^7.9.2 - "@types/testing-library__jest-dom": ^5.9.1 - aria-query: ^5.0.0 - chalk: ^3.0.0 - css.escape: ^1.5.1 - dom-accessibility-api: ^0.5.6 - lodash: ^4.17.15 - redent: ^3.0.0 - checksum: 9f28dbca8b50d7c306aae40c3aa8e06f0e115f740360004bd87d57f95acf7ab4b4f4122a7399a76dbf2bdaaafb15c99cc137fdcb0ae457a92e2de0f3fbf9b03b - languageName: node - linkType: hard - "@testing-library/jest-dom@npm:^6.0.0": version: 6.1.6 resolution: "@testing-library/jest-dom@npm:6.1.6" @@ -17317,20 +17282,6 @@ __metadata: languageName: node linkType: hard -"@testing-library/react@npm:^12.1.3": - version: 12.1.5 - resolution: "@testing-library/react@npm:12.1.5" - dependencies: - "@babel/runtime": ^7.12.5 - "@testing-library/dom": ^8.0.0 - "@types/react-dom": <18.0.0 - peerDependencies: - react: <18.0.0 - react-dom: <18.0.0 - checksum: 4abd0490405e709a7df584a0db604e508a4612398bb1326e8fa32dd9393b15badc826dcf6d2f7525437886d507871f719f127b9860ed69ddd204d1fa834f576a - languageName: node - linkType: hard - "@testing-library/react@npm:^14.0.0": version: 14.1.2 resolution: "@testing-library/react@npm:14.1.2" From e85aa989defcf5bd93c787e2f79c39d0ab321c48 Mon Sep 17 00:00:00 2001 From: zcmander Date: Fri, 22 Dec 2023 10:02:39 +0200 Subject: [PATCH 038/241] backend-test-utils: drop database in shutdown Signed-off-by: zcmander --- .changeset/fifty-files-argue.md | 6 ++ packages/backend-common/api-report.md | 6 ++ .../src/database/connection.test.ts | 78 ++++++++++++++++++- .../backend-common/src/database/connection.ts | 16 ++++ .../src/database/connectors/mysql.ts | 35 +++++++++ .../src/database/connectors/postgres.ts | 19 +++++ packages/backend-common/src/database/index.ts | 6 +- packages/backend-common/src/database/types.ts | 2 + .../src/database/TestDatabases.ts | 60 ++++++++++---- .../backend-test-utils/src/database/types.ts | 2 + 10 files changed, 211 insertions(+), 19 deletions(-) create mode 100644 .changeset/fifty-files-argue.md diff --git a/.changeset/fifty-files-argue.md b/.changeset/fifty-files-argue.md new file mode 100644 index 0000000000..b80b2989af --- /dev/null +++ b/.changeset/fifty-files-argue.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-test-utils': minor +'@backstage/backend-common': minor +--- + +drop databases after unit tests if the database instance is not running in docker diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index e7d89c2aa5..2255513d91 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -276,6 +276,12 @@ export class DockerContainerRunner implements ContainerRunner { runContainer(options: RunContainerOptions): Promise; } +// @public +export function dropDatabase( + dbConfig: Config, + ...databases: Array +): Promise; + // @public export function ensureDatabaseExists( dbConfig: Config, diff --git a/packages/backend-common/src/database/connection.test.ts b/packages/backend-common/src/database/connection.test.ts index caf2fccc30..3028d46cae 100644 --- a/packages/backend-common/src/database/connection.test.ts +++ b/packages/backend-common/src/database/connection.test.ts @@ -19,10 +19,11 @@ import { createDatabaseClient, createNameOverride, createSchemaOverride, + dropDatabase, ensureSchemaExists, parseConnectionString, } from './connection'; -import { pgConnector } from './connectors'; +import { mysqlConnector, pgConnector } from './connectors'; const mocked = (f: Function) => f as jest.Mock; @@ -30,8 +31,13 @@ jest.mock('./connectors', () => { const connectors = jest.requireActual('./connectors'); return { ...connectors, + mysqlConnector: { + ...connectors.mysqlConnector, + dropDatabase: jest.fn(), + }, pgConnector: { ...connectors.pgConnector, + dropDatabase: jest.fn(), ensureSchemaExists: jest.fn(), }, }; @@ -229,4 +235,74 @@ describe('database connection', () => { ).resolves.toBeUndefined(); }); }); + + describe('dropDatabase', () => { + it('returns successfully with pg client', async () => { + await dropDatabase( + new ConfigReader({ + client: 'pg', + schema: 'catalog', + connection: 'postgresql://testuser:testpass@acme:5432/userdbname', + }), + 'backstage_plugin_foobar', + ); + + const mockCalls = mocked( + pgConnector.dropDatabase as Function, + ).mock.calls.splice(-1); + const [baseConfig, databaseName] = mockCalls[0]; + + expect(baseConfig.get()).toMatchObject({ + client: 'pg', + connection: 'postgresql://testuser:testpass@acme:5432/userdbname', + }); + + expect(databaseName).toEqual('backstage_plugin_foobar'); + }); + + it('returns successfully with mysql client', async () => { + await dropDatabase( + new ConfigReader({ + client: 'mysql2', + connection: { + host: '127.0.0.1', + user: 'foo', + password: 'bar', + database: 'dbname', + }, + }), + 'backstage_plugin_foobar', + ); + + const mockCalls = mocked( + mysqlConnector.dropDatabase as Function, + ).mock.calls.splice(-1); + const [baseConfig, databaseName] = mockCalls[0]; + + expect(baseConfig.get()).toMatchObject({ + client: 'mysql2', + connection: { + host: '127.0.0.1', + user: 'foo', + password: 'bar', + database: 'dbname', + }, + }); + + expect(databaseName).toEqual('backstage_plugin_foobar'); + }); + + it('does nothing in other database drivers', () => { + return expect( + dropDatabase( + new ConfigReader({ + client: 'better-sqlite3', + schema: 'catalog', + connection: ':memory:', + }), + 'catalog', + ), + ).resolves.toBeUndefined(); + }); + }); }); diff --git a/packages/backend-common/src/database/connection.ts b/packages/backend-common/src/database/connection.ts index e369323e04..c0e031516f 100644 --- a/packages/backend-common/src/database/connection.ts +++ b/packages/backend-common/src/database/connection.ts @@ -95,6 +95,22 @@ export async function ensureDatabaseExists( ); } +/** + * Drops the given databases. + * + * @public + */ +export async function dropDatabase( + dbConfig: Config, + ...databases: Array +): Promise { + const client: DatabaseClient = dbConfig.getString('client'); + + return await ddlLimiter(() => + ConnectorMapping[client]?.dropDatabase?.(dbConfig, ...databases), + ); +} + /** * Ensures that the given schemas all exist, creating them if they do not. * diff --git a/packages/backend-common/src/database/connectors/mysql.ts b/packages/backend-common/src/database/connectors/mysql.ts index 16610dd920..a4bac3f7e1 100644 --- a/packages/backend-common/src/database/connectors/mysql.ts +++ b/packages/backend-common/src/database/connectors/mysql.ts @@ -183,6 +183,40 @@ export async function ensureMysqlDatabaseExists( } } +/** + * Drops the given mysql databases. + * + * @param dbConfig - The database config + * @param databases - The names of the databases to create + */ +export async function dropMysqlDatabase( + dbConfig: Config, + ...databases: Array +) { + const admin = createMysqlDatabaseClient(dbConfig, { + connection: { + database: null as unknown as string, + }, + pool: { + min: 0, + acquireTimeoutMillis: 10000, + }, + }); + + try { + const dropDatabase = async (database: string) => { + await admin.raw(`DROP DATABASE ??`, [database]); + }; + await Promise.all( + databases.map(async database => { + return await dropDatabase(database); + }), + ); + } finally { + await admin.destroy(); + } +} + /** * MySQL database connector. * @@ -193,4 +227,5 @@ export const mysqlConnector: DatabaseConnector = Object.freeze({ ensureDatabaseExists: ensureMysqlDatabaseExists, createNameOverride: defaultNameOverride, parseConnectionString: parseMysqlConnectionString, + dropDatabase: dropMysqlDatabase, }); diff --git a/packages/backend-common/src/database/connectors/postgres.ts b/packages/backend-common/src/database/connectors/postgres.ts index f132488e29..dc9b19f6ad 100644 --- a/packages/backend-common/src/database/connectors/postgres.ts +++ b/packages/backend-common/src/database/connectors/postgres.ts @@ -199,6 +199,24 @@ export async function ensurePgSchemaExists( } } +/** + * Drops the Postgres databases. + * + * @param dbConfig - The database config + * @param databases - The name of the databases to drop + */ +export async function dropPgDatabase( + dbConfig: Config, + ...databases: Array +) { + const admin = createPgDatabaseClient(dbConfig); + await Promise.all( + databases.map(async database => { + await admin.raw(`DROP DATABASE ??`, [database]); + }), + ); +} + /** * PostgreSQL database connector. * @@ -211,4 +229,5 @@ export const pgConnector: DatabaseConnector = Object.freeze({ createNameOverride: defaultNameOverride, createSchemaOverride: defaultSchemaOverride, parseConnectionString: parsePgConnectionString, + dropDatabase: dropPgDatabase, }); diff --git a/packages/backend-common/src/database/index.ts b/packages/backend-common/src/database/index.ts index 0dde1ec239..330429f0ef 100644 --- a/packages/backend-common/src/database/index.ts +++ b/packages/backend-common/src/database/index.ts @@ -20,7 +20,11 @@ export * from './DatabaseManager'; * Undocumented API surface from connection is being reduced for future deprecation. * Avoid exporting additional symbols. */ -export { createDatabaseClient, ensureDatabaseExists } from './connection'; +export { + createDatabaseClient, + ensureDatabaseExists, + dropDatabase, +} from './connection'; export type { PluginDatabaseManager } from './types'; export { isDatabaseConflictError } from './util'; diff --git a/packages/backend-common/src/database/types.ts b/packages/backend-common/src/database/types.ts index 621bcc676b..3e9832aec5 100644 --- a/packages/backend-common/src/database/types.ts +++ b/packages/backend-common/src/database/types.ts @@ -79,4 +79,6 @@ export interface DatabaseConnector { dbConfig: Config, ...schemas: Array ): Promise; + + dropDatabase?(dbConfig: Config, ...databases: Array): Promise; } diff --git a/packages/backend-test-utils/src/database/TestDatabases.ts b/packages/backend-test-utils/src/database/TestDatabases.ts index 1913075b1f..4ea8fe05d7 100644 --- a/packages/backend-test-utils/src/database/TestDatabases.ts +++ b/packages/backend-test-utils/src/database/TestDatabases.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DatabaseManager } from '@backstage/backend-common'; +import { DatabaseManager, dropDatabase } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { randomBytes } from 'crypto'; import { Knex } from 'knex'; @@ -157,11 +157,13 @@ export class TestDatabases { } // Ensure that a unique logical database is created in the instance + const databaseName = `db${randomBytes(16).toString('hex')}`; const connection = await instance.databaseManager - .forPlugin(`db${randomBytes(16).toString('hex')}`) + .forPlugin(databaseName) .getClient(); instance.connections.push(connection); + instance.databaseNames.push(databaseName); return connection; } @@ -173,21 +175,30 @@ export class TestDatabases { if (envVarName) { const connectionString = process.env[envVarName]; if (connectionString) { - const databaseManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - knexConfig: properties.driver.includes('sqlite') - ? {} - : LARGER_POOL_CONFIG, - client: properties.driver, - connection: connectionString, - }, + const config = new ConfigReader({ + backend: { + database: { + knexConfig: properties.driver.includes('sqlite') + ? {} + : LARGER_POOL_CONFIG, + client: properties.driver, + connection: connectionString, }, - }), - ); + }, + }); + const databaseManager = DatabaseManager.fromConfig(config); + const databaseNames: Array = []; return { + dropDatabases: async () => { + await dropDatabase( + config.getConfig('backend.database'), + ...databaseNames.map( + databaseName => `backstage_plugin_${databaseName}`, + ), + ); + }, databaseManager, + databaseNames, connections: [], }; } @@ -226,10 +237,10 @@ export class TestDatabases { }, }), ); - return { stopContainer: stop, databaseManager, + databaseNames: [], connections: [], }; } @@ -256,6 +267,7 @@ export class TestDatabases { return { stopContainer: stop, databaseManager, + databaseNames: [], connections: [], }; } @@ -273,9 +285,9 @@ export class TestDatabases { }, }), ); - return { databaseManager, + databaseNames: [], connections: [], }; } @@ -284,7 +296,12 @@ export class TestDatabases { const instances = [...this.instanceById.values()]; this.instanceById.clear(); - for (const { stopContainer, connections, databaseManager } of instances) { + for (const { + stopContainer, + dropDatabases, + connections, + databaseManager, + } of instances) { for (const connection of connections) { try { await connection.destroy(); @@ -296,6 +313,15 @@ export class TestDatabases { } } + // If the database is not running in docker then drop the databases + try { + await dropDatabases?.(); + } catch (error) { + console.warn(`TestDatabases: Failed to drop databases`, { + error, + }); + } + try { await stopContainer?.(); } catch (error) { diff --git a/packages/backend-test-utils/src/database/types.ts b/packages/backend-test-utils/src/database/types.ts index 75c24dc725..77a0c4e960 100644 --- a/packages/backend-test-utils/src/database/types.ts +++ b/packages/backend-test-utils/src/database/types.ts @@ -43,8 +43,10 @@ export type TestDatabaseProperties = { export type Instance = { stopContainer?: () => Promise; + dropDatabases?: () => Promise; databaseManager: DatabaseManager; connections: Array; + databaseNames: Array; }; export const allDatabases: Record = From 67ddf8d6d79e2d2e214411f2be8f2b2114039b02 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Wed, 3 Jan 2024 13:03:53 +0200 Subject: [PATCH 039/241] docs: fix example of signal api in README Signed-off-by: Heikki Hellgren --- plugins/signals/README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/signals/README.md b/plugins/signals/README.md index e70c1ef7d8..7b96da32f1 100644 --- a/plugins/signals/README.md +++ b/plugins/signals/README.md @@ -33,9 +33,12 @@ Now you can utilize the API from other plugins using the `@backstage/plugin-sign import { signalsApiRef } from '@backstage/plugin-signals-react'; const signals = useApi(signalsApiRef); -signals.subscribe('myplugin:topic', (message: JsonObject) => { - console.log(message); -}); +const { unsubscribe } = signals.subscribe( + 'myplugin:topic', + (message: JsonObject) => { + console.log(message); + }, +); // Remember to unsubscribe -signals.unsubscribe('myplugin:topic'); +unsubscribe(); ``` From 7bb31d5455c335a79f2190820b776a6e56da8952 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 15:11:04 +0000 Subject: [PATCH 040/241] chore(deps): update dependency aws-sdk-client-mock-jest to v3.0.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 954435a662..0d21078b4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20881,14 +20881,14 @@ __metadata: linkType: hard "aws-sdk-client-mock-jest@npm:^3.0.0": - version: 3.0.0 - resolution: "aws-sdk-client-mock-jest@npm:3.0.0" + version: 3.0.1 + resolution: "aws-sdk-client-mock-jest@npm:3.0.1" dependencies: "@types/jest": ^28.1.3 tslib: ^2.1.0 peerDependencies: - aws-sdk-client-mock: 3.0.0 - checksum: 83f49e1d048bf32bb88b6a2ac8b3d14761a14dd699adc7c0e4bd9397b4771dd3e23779ec180bf63c03be7e85b2322840373a4c4d9840722ab15d409d6f4e8bd1 + aws-sdk-client-mock: 3.0.1 + checksum: c5c72ae63c9d3862636b833c66ebc708a1c170ba1159508f9a1e56c8e71ba82f7f85a00e68148b72cc699ab3e7ce6945d29bfd23151ae62c3f78133d56585ddd languageName: node linkType: hard From 3a7deeef9208a776d70693c72518fea79f4647d4 Mon Sep 17 00:00:00 2001 From: Tommy Le Date: Thu, 4 Jan 2024 10:35:27 +0100 Subject: [PATCH 041/241] fix: api returns questions with relevant tags Signed-off-by: Tommy Le --- plugins/stack-overflow/src/api/StackOverflowClient.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/stack-overflow/src/api/StackOverflowClient.ts b/plugins/stack-overflow/src/api/StackOverflowClient.ts index f598f912bd..d2f95c5236 100644 --- a/plugins/stack-overflow/src/api/StackOverflowClient.ts +++ b/plugins/stack-overflow/src/api/StackOverflowClient.ts @@ -46,6 +46,7 @@ export class StackOverflowClient implements StackOverflowApi { }): Promise { const params = qs.stringify(options.requestParams, { addQueryPrefix: true, + arrayFormat: 'repeat', }); const response = await fetch(`${this.baseUrl}/questions${params}`); const data = await response.json(); From c1bc3318b48d43e1d39af72044cee488b83c5cf4 Mon Sep 17 00:00:00 2001 From: Tommy Le Date: Thu, 4 Jan 2024 10:41:33 +0100 Subject: [PATCH 042/241] add changeset Signed-off-by: Tommy Le --- .changeset/polite-meals-hug.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/polite-meals-hug.md diff --git a/.changeset/polite-meals-hug.md b/.changeset/polite-meals-hug.md new file mode 100644 index 0000000000..664f450c6d --- /dev/null +++ b/.changeset/polite-meals-hug.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-stack-overflow': patch +--- + +Fixes a bug that made the API return questions not related to the tags provided From 15b8c1c48dae385d2602bacd75e43d025f570581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Mauricio=20G=C3=B3mez=20P?= Date: Thu, 4 Jan 2024 08:09:17 -0500 Subject: [PATCH 043/241] Update plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jamie Klassen Signed-off-by: Andrés Mauricio Gómez P --- .../kubernetes-backend/src/service/KubernetesFetcher.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts index 966fda7ce5..04b3d098ca 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts @@ -813,7 +813,7 @@ describe('KubernetesFetcher', () => { expect(agent.options.rejectUnauthorized).toBe(false); }); - it('should use a x509 client cert authentication strategy to consume kubeapi when backstage-kubernetes-auth field is not provided and the authStrategy enables x509 client cert authentication - fetchObjectsForService', async () => { + it('fetchObjectsForService authenticates with k8s using x509 client cert from authentication strategy', async () => { worker.use( rest.get('https://localhost:9999/api/v1/pods', (req, res, ctx) => res( From 77c8c4ecfc445eb8813c30095da87fa43a00cc04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Mauricio=20G=C3=B3mez=20P?= Date: Thu, 4 Jan 2024 08:09:30 -0500 Subject: [PATCH 044/241] Update plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jamie Klassen Signed-off-by: Andrés Mauricio Gómez P --- .../kubernetes-backend/src/service/KubernetesFetcher.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts index 04b3d098ca..3b435fad74 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.test.ts @@ -862,7 +862,7 @@ describe('KubernetesFetcher', () => { expect(agent.options.key).toEqual(myKey); }); - it('should use a x509 client cert authentication strategy to consume kubeapi when backstage-kubernetes-auth field is not provided and the authStrategy enables x509 client cert authentication - fetchPodMetricsByNamespaces', async () => { + it('fetchPodMetricsByNamespaces authenticates with k8s using x509 client cert from authentication strategy', async () => { worker.use( rest.get( 'https://localhost:9999/api/v1/namespaces/:namespace/pods', From 73a5e1b0c563c9fac5ac066b20a5a73ca01c8146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Mauricio=20G=C3=B3mez=20P?= Date: Thu, 4 Jan 2024 08:18:07 -0500 Subject: [PATCH 045/241] Update plugins/kubernetes-backend/src/service/KubernetesFetcher.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jamie Klassen Signed-off-by: Andrés Mauricio Gómez P --- plugins/kubernetes-backend/src/service/KubernetesFetcher.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts index cf4e3f9440..8d8e8f4d97 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts @@ -220,7 +220,7 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { if (this.isServiceAccountAuthentication(authProvider, clusterDetails)) { [url, requestInit] = this.fetchArgsInCluster(credential); } else if ( - this.isTokenOrClientCertificateAuthentication(authProvider, credential) + !this.isCredentialMissing(authProvider, credential) ) { [url, requestInit] = this.fetchArgs(clusterDetails, credential); } else { From 5e6f1706c1b8147b544e11073dd6e51b0deeda7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Mauricio=20G=C3=B3mez=20P?= Date: Thu, 4 Jan 2024 08:18:18 -0500 Subject: [PATCH 046/241] Update plugins/kubernetes-backend/src/service/KubernetesFetcher.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jamie Klassen Signed-off-by: Andrés Mauricio Gómez P Signed-off-by: Andres Mauricio Gomez P --- .../src/service/KubernetesFetcher.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts index 8d8e8f4d97..b7354d54d4 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFetcher.ts @@ -219,9 +219,7 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { if (this.isServiceAccountAuthentication(authProvider, clusterDetails)) { [url, requestInit] = this.fetchArgsInCluster(credential); - } else if ( - !this.isCredentialMissing(authProvider, credential) - ) { + } else if (!this.isCredentialMissing(authProvider, credential)) { [url, requestInit] = this.fetchArgs(clusterDetails, credential); } else { return Promise.reject( @@ -255,14 +253,12 @@ export class KubernetesClientBasedFetcher implements KubernetesFetcher { ); } - private isTokenOrClientCertificateAuthentication( + private isCredentialMissing( authProvider: string, credential: KubernetesCredential, ) { return ( - credential.type === 'bearer token' || - credential.type === 'x509 client certificate' || - authProvider === 'localKubectlProxy' + authProvider !== 'localKubectlProxy' && credential.type === 'anonymous' ); } From db1054bb92eda59e50f47ea8dce05f015cc1b28b Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Thu, 4 Jan 2024 09:35:43 -0500 Subject: [PATCH 047/241] fix invocation of kubernetesAuthProvidersApi Pass token provider when authenticating via openID tokens. Signed-off-by: Jamie Klassen --- .changeset/six-melons-end.md | 5 +++ .../src/api/KubernetesBackendClient.test.ts | 39 +++++++++++++++++++ .../src/api/KubernetesBackendClient.ts | 12 +++++- 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 .changeset/six-melons-end.md diff --git a/.changeset/six-melons-end.md b/.changeset/six-melons-end.md new file mode 100644 index 0000000000..f139e49887 --- /dev/null +++ b/.changeset/six-melons-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-react': patch +--- + +Fixed a bug where the logs dialog and any other functionality depending on the proxy endpoint would fail for clusters configured with the OIDC auth provider. diff --git a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts index fd999ab335..0535e404f6 100644 --- a/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts +++ b/plugins/kubernetes-react/src/api/KubernetesBackendClient.test.ts @@ -448,6 +448,9 @@ describe('KubernetesBackendClient', () => { const response = await backendClient.proxy(request); await expect(response.json()).resolves.toStrictEqual(nsResponse); + expect(kubernetesAuthProvidersApi.getCredentials).toHaveBeenCalledWith( + 'oidc.okta', + ); }); it('hits the /proxy API with serviceAccount as auth provider', async () => { @@ -495,6 +498,42 @@ describe('KubernetesBackendClient', () => { const response = await backendClient.proxy(request); await expect(response.json()).resolves.toStrictEqual(nsResponse); + expect(kubernetesAuthProvidersApi.getCredentials).toHaveBeenCalledWith( + 'serviceAccount', + ); + }); + + it('ignores oidcTokenProvider for non-oidc auth provider', async () => { + worker.use( + rest.get( + 'http://localhost:1234/api/kubernetes/clusters', + (_, res, ctx) => + res( + ctx.json({ + items: [ + { + name: 'cluster-a', + authProvider: 'not oidc', + oidcTokenProvider: 'should be ignored', + }, + ], + }), + ), + ), + rest.get( + 'http://localhost:1234/api/kubernetes/proxy/api/v1/namespaces', + (_, res, ctx) => res(ctx.json([])), + ), + ); + + await backendClient.proxy({ + clusterName: 'cluster-a', + path: '/api/v1/namespaces', + }); + + expect(kubernetesAuthProvidersApi.getCredentials).toHaveBeenCalledWith( + 'not oidc', + ); }); it('hits /proxy api when signed in as a guest', async () => { diff --git a/plugins/kubernetes-react/src/api/KubernetesBackendClient.ts b/plugins/kubernetes-react/src/api/KubernetesBackendClient.ts index a769eb088d..461b1d1ffe 100644 --- a/plugins/kubernetes-react/src/api/KubernetesBackendClient.ts +++ b/plugins/kubernetes-react/src/api/KubernetesBackendClient.ts @@ -92,8 +92,13 @@ export class KubernetesBackendClient implements KubernetesApi { private async getCredentials( authProvider: string, + oidcTokenProvider?: string, ): Promise<{ token?: string }> { - return await this.kubernetesAuthProvidersApi.getCredentials(authProvider); + return await this.kubernetesAuthProvidersApi.getCredentials( + authProvider === 'oidc' + ? `${authProvider}.${oidcTokenProvider}` + : authProvider, + ); } async getObjectsByEntity( @@ -145,7 +150,10 @@ export class KubernetesBackendClient implements KubernetesApi { const { authProvider, oidcTokenProvider } = await this.getCluster( options.clusterName, ); - const kubernetesCredentials = await this.getCredentials(authProvider); + const kubernetesCredentials = await this.getCredentials( + authProvider, + oidcTokenProvider, + ); const url = `${await this.discoveryApi.getBaseUrl('kubernetes')}/proxy${ options.path }`; From c01835945b63e3e49cb34641c9417048343c121f Mon Sep 17 00:00:00 2001 From: Adam Vollrath Date: Thu, 4 Jan 2024 10:59:41 -0600 Subject: [PATCH 048/241] Limit permissions of GHA token in Uffizzi second stage workflow. Signed-off-by: Adam Vollrath --- .github/workflows/uffizzi-preview.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml index cd1f6f939c..93c42e6c71 100644 --- a/.github/workflows/uffizzi-preview.yaml +++ b/.github/workflows/uffizzi-preview.yaml @@ -12,6 +12,8 @@ jobs: name: Cache Manifests File runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} + permissions: + actions: read outputs: manifests-cache-key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} git-ref: ${{ steps.event.outputs.GIT_REF }} @@ -84,14 +86,14 @@ jobs: cat event.json deploy-uffizzi-preview: - permissions: - contents: read - pull-requests: write - id-token: write name: Deploy to Uffizzi Virtual Cluster needs: - cache-manifests-file if: ${{ github.event.workflow_run.conclusion == 'success' && needs.cache-manifests-file.outputs.action != 'closed' }} + permissions: + contents: read + pull-requests: write + id-token: write runs-on: ubuntu-latest steps: - name: Checkout From 9f4cb8a8f797981b802aee49a5d0190deab5820f Mon Sep 17 00:00:00 2001 From: Adam Vollrath Date: Thu, 4 Jan 2024 11:18:53 -0600 Subject: [PATCH 049/241] Enforce harden-runner policy. Signed-off-by: Adam Vollrath --- .github/workflows/uffizzi-preview.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml index 93c42e6c71..c1659097a7 100644 --- a/.github/workflows/uffizzi-preview.yaml +++ b/.github/workflows/uffizzi-preview.yaml @@ -13,7 +13,9 @@ jobs: runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} permissions: - actions: read + # "If you specify the access for any of these scopes, all of those that are not specified are set to none." + # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions + actions: read # Access cache outputs: manifests-cache-key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} git-ref: ${{ steps.event.outputs.GIT_REF }} @@ -23,7 +25,10 @@ jobs: - name: Harden Runner uses: step-security/harden-runner@eb238b55efaa70779f274895e782ed17c84f2895 # v2.6.1 with: - egress-policy: audit + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.github.com:443 - name: 'Download artifacts' # Fetch output (zip archive) from the workflow run that triggered this workflow. From 4d1ebeff985eda0ab0cae4728ce047eb26ff3284 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Jan 2024 19:23:58 +0000 Subject: [PATCH 050/241] fix(deps): update dependency postcss to v8.4.33 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 15212e967e..5e3c2e4879 100644 --- a/yarn.lock +++ b/yarn.lock @@ -37330,13 +37330,13 @@ __metadata: linkType: hard "postcss@npm:^8.1.0, postcss@npm:^8.4.21, postcss@npm:^8.4.27": - version: 8.4.32 - resolution: "postcss@npm:8.4.32" + version: 8.4.33 + resolution: "postcss@npm:8.4.33" dependencies: nanoid: ^3.3.7 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: 220d9d0bf5d65be7ed31006c523bfb11619461d296245c1231831f90150aeb4a31eab9983ac9c5c89759a3ca8b60b3e0d098574964e1691673c3ce5c494305ae + checksum: 6f98b2af4b76632a3de20c4f47bf0e984a1ce1a531cf11adcb0b1d63a6cbda0aae4165e578b66c32ca4879038e3eaad386a6be725a8fb4429c78e3c1ab858fe9 languageName: node linkType: hard From bbea3b24177556b193c7734e2834567885ac2487 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 6 Jan 2024 10:31:35 +0000 Subject: [PATCH 051/241] fix(deps): update dependency openid-client to v5.6.4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 15212e967e..60f6701715 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35689,14 +35689,14 @@ __metadata: linkType: hard "openid-client@npm:^5.2.1, openid-client@npm:^5.3.0, openid-client@npm:^5.4.3": - version: 5.6.2 - resolution: "openid-client@npm:5.6.2" + version: 5.6.4 + resolution: "openid-client@npm:5.6.4" dependencies: jose: ^4.15.4 lru-cache: ^6.0.0 object-hash: ^2.2.0 oidc-token-hash: ^5.0.3 - checksum: e61bc7170bb53d9b50098476b68b72e07f93769caae8ae12ffb885c2dac5fb2fdf6de437a9eb29c5501f52b296f01c083de8d6f3500f2999fc863c9f9f5142fa + checksum: 69843f078dacbbc6bad6d65ca6689414ac73f095dfe2f8e606822e6cfc9d9cd7d0dfaf2649352eda604653806f0ea65326ad2d6266da897e4740ec93d26d21f6 languageName: node linkType: hard From 7233f57136e6b4445945a691e829c5271d052085 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Fri, 15 Dec 2023 13:12:58 -0500 Subject: [PATCH 052/241] fix error message for unsupported serviceLocator Signed-off-by: Jamie Klassen --- .changeset/friendly-cheetahs-rescue.md | 6 ++++++ .../src/service/KubernetesBuilder.test.ts | 21 +++++++++++++++++++ .../src/service/KubernetesBuilder.ts | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 .changeset/friendly-cheetahs-rescue.md diff --git a/.changeset/friendly-cheetahs-rescue.md b/.changeset/friendly-cheetahs-rescue.md new file mode 100644 index 0000000000..4f54a022af --- /dev/null +++ b/.changeset/friendly-cheetahs-rescue.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +Fixed an issue where a misleading error message would be logged when an +unsupported service locator method was specified. diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 77d02a032a..5719a9392a 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -206,6 +206,7 @@ describe('KubernetesBuilder', () => { }); }); }); + describe('post /services/:serviceId', () => { it('happy path: lists kubernetes objects without auth in request body', async () => { const response = await request(app).post( @@ -780,4 +781,24 @@ metadata: }); }); }); + + it('fails when an unsupported serviceLocator type is specified', () => { + return expect(() => + startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { type: 'unsupported' }, + clusterLocatorMethods: [{ type: 'config', clusters: [] }], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + ], + }), + ).rejects.toThrow( + 'Unsupported kubernetes.serviceLocatorMethod "unsupported"', + ); + }); }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index c1ff4688e7..a4a577db85 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -288,7 +288,7 @@ export class KubernetesBuilder { break; default: throw new Error( - `Unsupported kubernetes.clusterLocatorMethod "${method}"`, + `Unsupported kubernetes.serviceLocatorMethod "${method}"`, ); } From d458e043c6210b3cd958fddfb4f22efd2b955c6f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 08:14:37 +0000 Subject: [PATCH 053/241] fix(deps): update dependency @keyv/redis to v2.8.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 53d8974d6c..da3995976a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12155,11 +12155,11 @@ __metadata: linkType: hard "@keyv/redis@npm:^2.5.3": - version: 2.8.0 - resolution: "@keyv/redis@npm:2.8.0" + version: 2.8.3 + resolution: "@keyv/redis@npm:2.8.3" dependencies: ioredis: ^5.3.2 - checksum: 753e18897bf8e1fed585357d85749c7a1689f5efc1eb7114e790bf760460f7f510d5e76da5cc742269949205c18aad3c58ce4f8ceef5db0ace4ee108833632ba + checksum: 4b8fa4baeab75aace0a8c5d02e30dfb87fa2e27236d8ce3577ff862c4efa2ae2f6d4c14b4933e08fd24fd2719a01d17ac596e20792a1d3c0c2af51a46ba48936 languageName: node linkType: hard From 108c28f5ba2fdc2539decc23e7cf21a36ea5ca0b Mon Sep 17 00:00:00 2001 From: Tommy Le Date: Tue, 9 Jan 2024 10:40:25 +0100 Subject: [PATCH 054/241] add test Signed-off-by: Tommy Le --- .../src/api/StackOverflowClient.test.ts | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/plugins/stack-overflow/src/api/StackOverflowClient.test.ts b/plugins/stack-overflow/src/api/StackOverflowClient.test.ts index 6574771350..e5967b6d45 100644 --- a/plugins/stack-overflow/src/api/StackOverflowClient.test.ts +++ b/plugins/stack-overflow/src/api/StackOverflowClient.test.ts @@ -27,19 +27,34 @@ const backstageQuestions: StackOverflowQuestion[] = [ { title: 'What is it?', link: 'https://example.com:9191/questions/1', - tags: ['asdf'], + tags: ['backstage'], owner: { who: 'me' }, answer_count: 3, }, { title: 'Is it?', link: 'https://example.com:9191/questions/2', - tags: ['asdf'], + tags: ['backstage'], owner: { who: 'me' }, answer_count: 4, }, ]; +const vimQuestions: StackOverflowQuestion[] = [ + { + title: 'How do I exit vim?', + link: 'https://example.com:9191/questions/3', + tags: ['vim'], + owner: { who: 'me' }, + answer_count: 5, + }, +]; + +const questionMap: Record = { + backstage: backstageQuestions, + vim: vimQuestions, +}; + describe('StackOverflowClient', () => { setupRequestMockHandlers(server); @@ -48,19 +63,15 @@ describe('StackOverflowClient', () => { const setupHandlers = () => { server.use( rest.get(`${mockBaseUrl}/questions`, (req, res, ctx) => { - return res( - ctx.json({ - items: - req.url.searchParams.get('tagged') === 'backstage' - ? backstageQuestions - : [], - }), - ); + const taggedParam = req.url.searchParams.get('tagged'); + const questions = taggedParam ? questionMap[taggedParam] || [] : []; + + return res(ctx.json({ items: questions })); }), ); }; - it('list questions should return all questions', async () => { + it('list questions should return all questions with the provided tag', async () => { setupHandlers(); const client = StackOverflowClient.fromConfig( new ConfigReader({ @@ -70,10 +81,17 @@ describe('StackOverflowClient', () => { }), ); - const responseQuestions = await client.listQuestions({ + const bsQuestions = await client.listQuestions({ requestParams: { tagged: 'backstage' }, }); - expect(responseQuestions.length).toEqual(2); - expect(responseQuestions).toEqual(backstageQuestions); + + const vQuestions = await client.listQuestions({ + requestParams: { tagged: 'vim' }, + }); + + expect(bsQuestions.length).toEqual(2); + expect(bsQuestions).toEqual(backstageQuestions); + expect(vQuestions.length).toEqual(1); + expect(vQuestions).toEqual(vimQuestions); }); }); From fe84198f47ef1e96043feac0f5c44fc7773dda80 Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Wed, 10 Jan 2024 17:57:33 +0530 Subject: [PATCH 055/241] Plugins page dropdown filter Signed-off-by: AmbrishRamachandiran --- microsite/src/pages/plugins/plugins.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/src/pages/plugins/plugins.module.scss b/microsite/src/pages/plugins/plugins.module.scss index 80ac60cf98..b0427c8f5c 100644 --- a/microsite/src/pages/plugins/plugins.module.scss +++ b/microsite/src/pages/plugins/plugins.module.scss @@ -100,7 +100,7 @@ } :global(.dropdown__label) { - font-size: 15px; + font-size: 14px; cursor: pointer; } From 8f90d69b3ba73ad5203357d7b4533afcbab74f7e Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Wed, 10 Jan 2024 18:20:49 +0530 Subject: [PATCH 056/241] Fixing frontend system docs Signed-off-by: AmbrishRamachandiran --- docs/frontend-system/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/index.md b/docs/frontend-system/index.md index 0dda44555c..201718f6d3 100644 --- a/docs/frontend-system/index.md +++ b/docs/frontend-system/index.md @@ -12,4 +12,4 @@ description: The Frontend System The new frontend system is in alpha, and only a few plugins support the system so far. We do not yet recommend migrating any apps to the new system. If you add support for the new system to your plugin, please do so under a `/alpha` sub-path export. -You can find an example app setup in [the `app-next` package](https://github.com/backstage/backstage/tree/master/packages/app-next). +You can find an example app setup in the [`app-next` package](https://github.com/backstage/backstage/tree/master/packages/app-next). From eb81f4228ade0a2b39c5fe458b7a7284e80be63f Mon Sep 17 00:00:00 2001 From: David Festal Date: Wed, 10 Jan 2024 18:05:28 +0100 Subject: [PATCH 057/241] Rename `backend-plugin-manager` package and make it public Signed-off-by: David Festal --- .changeset/clean-mails-bathe.md | 5 ++ .../.eslintrc.js | 0 .../CHANGELOG.md | 2 +- .../README.md | 18 ++--- .../api-report.md | 2 +- .../catalog-info.yaml | 10 +++ .../config.d.ts | 0 .../package.json | 7 +- .../src/__testUtils__/testUtils.ts | 0 .../src/index.ts | 0 .../src/loader/CommonJSModuleLoader.ts | 0 .../src/loader/index.ts | 0 .../src/loader/types.ts | 0 .../src/manager/index.ts | 0 .../src/manager/plugin-manager.test.ts | 2 +- .../src/manager/plugin-manager.ts | 0 .../src/manager/types.ts | 0 .../src/scanner/index.ts | 0 .../scanner/plugin-scanner-watcher.test.ts | 0 .../src/scanner/plugin-scanner.test.ts | 0 .../src/scanner/plugin-scanner.ts | 0 .../src/scanner/types.ts | 0 .../backend-plugin-manager/catalog-info.yaml | 10 --- yarn.lock | 68 +++++++++---------- 24 files changed, 62 insertions(+), 62 deletions(-) create mode 100644 .changeset/clean-mails-bathe.md rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/.eslintrc.js (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/CHANGELOG.md (99%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/README.md (64%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/api-report.md (98%) create mode 100644 packages/backend-dynamic-feature-service/catalog-info.yaml rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/config.d.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/package.json (92%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/__testUtils__/testUtils.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/index.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/loader/CommonJSModuleLoader.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/loader/index.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/loader/types.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/manager/index.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/manager/plugin-manager.test.ts (99%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/manager/plugin-manager.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/manager/types.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/scanner/index.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/scanner/plugin-scanner-watcher.test.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/scanner/plugin-scanner.test.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/scanner/plugin-scanner.ts (100%) rename packages/{backend-plugin-manager => backend-dynamic-feature-service}/src/scanner/types.ts (100%) delete mode 100644 packages/backend-plugin-manager/catalog-info.yaml diff --git a/.changeset/clean-mails-bathe.md b/.changeset/clean-mails-bathe.md new file mode 100644 index 0000000000..c9afc34f90 --- /dev/null +++ b/.changeset/clean-mails-bathe.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-dynamic-feature-service': minor +--- + +New `backend-dynamic-feature-service` package, for the discovery of dynamic frontend and backend plugins (and modules) and the loading of the backend ones inside the backend application. diff --git a/packages/backend-plugin-manager/.eslintrc.js b/packages/backend-dynamic-feature-service/.eslintrc.js similarity index 100% rename from packages/backend-plugin-manager/.eslintrc.js rename to packages/backend-dynamic-feature-service/.eslintrc.js diff --git a/packages/backend-plugin-manager/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md similarity index 99% rename from packages/backend-plugin-manager/CHANGELOG.md rename to packages/backend-dynamic-feature-service/CHANGELOG.md index 109c2e8409..07b118e771 100644 --- a/packages/backend-plugin-manager/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,4 +1,4 @@ -# @backstage/backend-plugin-manager +# @backstage/backend-dynamic-feature-service ## 0.0.5-next.2 diff --git a/packages/backend-plugin-manager/README.md b/packages/backend-dynamic-feature-service/README.md similarity index 64% rename from packages/backend-plugin-manager/README.md rename to packages/backend-dynamic-feature-service/README.md index c9fd666fb3..211148ee10 100644 --- a/packages/backend-plugin-manager/README.md +++ b/packages/backend-dynamic-feature-service/README.md @@ -1,10 +1,6 @@ -# @backstage/backend-plugin-manager +# @backstage/backend-dynamic-feature-service -This package adds experimental support for **dynamic backend plugins**, according to the content of the proposal in [RFC 18390](https://github.com/backstage/backstage/issues/18390) - -## Status - -**This package is EXPERIMENTAL, and is subject to change according to the discussions and conclusions that happen around the RFC mentioned above.** +This package adds experimental support for **dynamic backend features (plugins and modules)**, according to the content of the proposal in [RFC 18390](https://github.com/backstage/backstage/issues/18390) ## Testing the backend dynamic plugins feature @@ -12,9 +8,9 @@ In order to test the dynamic backend plugins feature provided by this package, e ## How it works -The backend plugin manager is a service that scans a configured root directory (`dynamicPlugins.rootDirectory` in the app config) for dynamic plugin packages, and loads them dynamically. +The dynamic plugin manager is a service that scans a configured root directory (`dynamicPlugins.rootDirectory` in the app config) for dynamic plugin packages, and loads them dynamically. -In the `backend-next` application, it can be enabled by adding the `backend-plugin-manager` as a dependency in the `package.json` and the following lines in the `src/index.ts` file: +In the `backend-next` application, it can be enabled by adding the `backend-dynamic-feature-service` as a dependency in the `package.json` and the following lines in the `src/index.ts` file: ```ts const backend = createBackend(); @@ -36,9 +32,9 @@ Points 2 and 3 can be done by the `export-dynamic-plugin` CLI command used to pe ### About the `export-dynamic-plugin` command -The `export-dynamic-plugin` CLI command, used the dynamic plugin examples provided in the [showcase repository](https://github.com/janus-idp/dynamic-backend-plugins-showcase), is part of a `@backstage/cli` fork (`@dfatwork-pkgs/backstage-cli@0.22.9-next.6`), and can be used to help packaging the dynamic plugins according to the constraints mentioned above, in order to allow straightforward testing of the dynamic plugins feature. +The `export-dynamic-plugin` CLI command, used the dynamic plugin examples provided in the [showcase repository](https://github.com/janus-idp/dynamic-backend-plugins-showcase), is part of the `@janus-idp/cli` package, and can be used to help packaging the dynamic plugins according to the constraints mentioned above, in order to allow straightforward testing of the dynamic plugins feature. -However the `backend-plugin-manager` experimental package does **not** depend on the use of this additional CLI command, and in future steps of this backend dynamic plugin work, the use of such a dedicated command might not even be necessary. +However the `backend-dynamic-feature-service` experimental package does **not** depend on the use of this additional CLI command, and in future steps of this backend dynamic plugin work, the use of such a dedicated command might not even be necessary. ### About the support of the legacy backend system @@ -49,4 +45,4 @@ This is why the API related to the old backend is already marked as deprecated. ### Future work -The current implementation of the backend plugin manager is a first step towards the final implementation of the dynamic backend plugins feature, which will be completed / simplified in future steps, as the status of the backstage codebase allows it. +The current implementation of the dynamic plugin manager is a first step towards the final implementation of the dynamic features loading, which will be completed / simplified in future steps, as the status of the backstage codebase allows it. diff --git a/packages/backend-plugin-manager/api-report.md b/packages/backend-dynamic-feature-service/api-report.md similarity index 98% rename from packages/backend-plugin-manager/api-report.md rename to packages/backend-dynamic-feature-service/api-report.md index dc5973a3ab..caf2cf01ec 100644 --- a/packages/backend-plugin-manager/api-report.md +++ b/packages/backend-dynamic-feature-service/api-report.md @@ -1,4 +1,4 @@ -## API Report File for "@backstage/backend-plugin-manager" +## API Report File for "@backstage/backend-dynamic-feature-service" > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). diff --git a/packages/backend-dynamic-feature-service/catalog-info.yaml b/packages/backend-dynamic-feature-service/catalog-info.yaml new file mode 100644 index 0000000000..1269a5c406 --- /dev/null +++ b/packages/backend-dynamic-feature-service/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-backend-dynamic-feature-service + title: '@backstage/backend-dynamic-feature-service' + description: Backstage backend service to handle dynamic features +spec: + lifecycle: experimental + type: backstage-node-library + owner: maintainers diff --git a/packages/backend-plugin-manager/config.d.ts b/packages/backend-dynamic-feature-service/config.d.ts similarity index 100% rename from packages/backend-plugin-manager/config.d.ts rename to packages/backend-dynamic-feature-service/config.d.ts diff --git a/packages/backend-plugin-manager/package.json b/packages/backend-dynamic-feature-service/package.json similarity index 92% rename from packages/backend-plugin-manager/package.json rename to packages/backend-dynamic-feature-service/package.json index 45344f4c94..cd95d6a5ae 100644 --- a/packages/backend-plugin-manager/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,8 +1,7 @@ { - "name": "@backstage/backend-plugin-manager", - "description": "Backstage plugin management backend", - "version": "0.0.5-next.2", - "private": true, + "name": "@backstage/backend-dynamic-feature-service", + "description": "Backstage dynamic feature service", + "version": "0.0.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-plugin-manager/src/__testUtils__/testUtils.ts b/packages/backend-dynamic-feature-service/src/__testUtils__/testUtils.ts similarity index 100% rename from packages/backend-plugin-manager/src/__testUtils__/testUtils.ts rename to packages/backend-dynamic-feature-service/src/__testUtils__/testUtils.ts diff --git a/packages/backend-plugin-manager/src/index.ts b/packages/backend-dynamic-feature-service/src/index.ts similarity index 100% rename from packages/backend-plugin-manager/src/index.ts rename to packages/backend-dynamic-feature-service/src/index.ts diff --git a/packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts b/packages/backend-dynamic-feature-service/src/loader/CommonJSModuleLoader.ts similarity index 100% rename from packages/backend-plugin-manager/src/loader/CommonJSModuleLoader.ts rename to packages/backend-dynamic-feature-service/src/loader/CommonJSModuleLoader.ts diff --git a/packages/backend-plugin-manager/src/loader/index.ts b/packages/backend-dynamic-feature-service/src/loader/index.ts similarity index 100% rename from packages/backend-plugin-manager/src/loader/index.ts rename to packages/backend-dynamic-feature-service/src/loader/index.ts diff --git a/packages/backend-plugin-manager/src/loader/types.ts b/packages/backend-dynamic-feature-service/src/loader/types.ts similarity index 100% rename from packages/backend-plugin-manager/src/loader/types.ts rename to packages/backend-dynamic-feature-service/src/loader/types.ts diff --git a/packages/backend-plugin-manager/src/manager/index.ts b/packages/backend-dynamic-feature-service/src/manager/index.ts similarity index 100% rename from packages/backend-plugin-manager/src/manager/index.ts rename to packages/backend-dynamic-feature-service/src/manager/index.ts diff --git a/packages/backend-plugin-manager/src/manager/plugin-manager.test.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts similarity index 99% rename from packages/backend-plugin-manager/src/manager/plugin-manager.test.ts rename to packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts index 405fd629f2..487729687f 100644 --- a/packages/backend-plugin-manager/src/manager/plugin-manager.test.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts @@ -47,7 +47,7 @@ import { PluginScanner } from '../scanner/plugin-scanner'; import { findPaths } from '@backstage/cli-common'; import { createMockDirectory } from '@backstage/backend-test-utils'; -describe('backend-plugin-manager', () => { +describe('backend-dynamic-feature-service', () => { const mockDir = createMockDirectory(); describe('loadPlugins', () => { diff --git a/packages/backend-plugin-manager/src/manager/plugin-manager.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts similarity index 100% rename from packages/backend-plugin-manager/src/manager/plugin-manager.ts rename to packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts diff --git a/packages/backend-plugin-manager/src/manager/types.ts b/packages/backend-dynamic-feature-service/src/manager/types.ts similarity index 100% rename from packages/backend-plugin-manager/src/manager/types.ts rename to packages/backend-dynamic-feature-service/src/manager/types.ts diff --git a/packages/backend-plugin-manager/src/scanner/index.ts b/packages/backend-dynamic-feature-service/src/scanner/index.ts similarity index 100% rename from packages/backend-plugin-manager/src/scanner/index.ts rename to packages/backend-dynamic-feature-service/src/scanner/index.ts diff --git a/packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner-watcher.test.ts similarity index 100% rename from packages/backend-plugin-manager/src/scanner/plugin-scanner-watcher.test.ts rename to packages/backend-dynamic-feature-service/src/scanner/plugin-scanner-watcher.test.ts diff --git a/packages/backend-plugin-manager/src/scanner/plugin-scanner.test.ts b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.test.ts similarity index 100% rename from packages/backend-plugin-manager/src/scanner/plugin-scanner.test.ts rename to packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.test.ts diff --git a/packages/backend-plugin-manager/src/scanner/plugin-scanner.ts b/packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.ts similarity index 100% rename from packages/backend-plugin-manager/src/scanner/plugin-scanner.ts rename to packages/backend-dynamic-feature-service/src/scanner/plugin-scanner.ts diff --git a/packages/backend-plugin-manager/src/scanner/types.ts b/packages/backend-dynamic-feature-service/src/scanner/types.ts similarity index 100% rename from packages/backend-plugin-manager/src/scanner/types.ts rename to packages/backend-dynamic-feature-service/src/scanner/types.ts diff --git a/packages/backend-plugin-manager/catalog-info.yaml b/packages/backend-plugin-manager/catalog-info.yaml deleted file mode 100644 index bc1845fe49..0000000000 --- a/packages/backend-plugin-manager/catalog-info.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Component -metadata: - name: backstage-backend-plugin-manager - title: '@backstage/backend-plugin-manager' - description: Backstage plugin management backend -spec: - lifecycle: experimental - type: backstage-node-library - owner: maintainers diff --git a/yarn.lock b/yarn.lock index 03478d5b50..c77da56725 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3344,6 +3344,40 @@ __metadata: languageName: unknown linkType: soft +"@backstage/backend-dynamic-feature-service@workspace:packages/backend-dynamic-feature-service": + version: 0.0.0-use.local + resolution: "@backstage/backend-dynamic-feature-service@workspace:packages/backend-dynamic-feature-service" + dependencies: + "@backstage/backend-app-api": "workspace:^" + "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" + "@backstage/backend-tasks": "workspace:^" + "@backstage/backend-test-utils": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/cli-common": "workspace:^" + "@backstage/cli-node": "workspace:^" + "@backstage/config": "workspace:^" + "@backstage/config-loader": "workspace:^" + "@backstage/errors": "workspace:^" + "@backstage/plugin-auth-node": "workspace:^" + "@backstage/plugin-catalog-backend": "workspace:^" + "@backstage/plugin-events-backend": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" + "@backstage/plugin-permission-common": "workspace:^" + "@backstage/plugin-permission-node": "workspace:^" + "@backstage/plugin-scaffolder-node": "workspace:^" + "@backstage/plugin-search-backend-node": "workspace:^" + "@backstage/plugin-search-common": "workspace:^" + "@backstage/types": "workspace:^" + "@types/express": ^4.17.6 + chokidar: ^3.5.3 + express: ^4.17.1 + lodash: ^4.17.21 + wait-for-expect: ^3.0.2 + winston: ^3.2.1 + languageName: unknown + linkType: soft + "@backstage/backend-openapi-utils@workspace:^, @backstage/backend-openapi-utils@workspace:packages/backend-openapi-utils": version: 0.0.0-use.local resolution: "@backstage/backend-openapi-utils@workspace:packages/backend-openapi-utils" @@ -3380,40 +3414,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/backend-plugin-manager@workspace:packages/backend-plugin-manager": - version: 0.0.0-use.local - resolution: "@backstage/backend-plugin-manager@workspace:packages/backend-plugin-manager" - dependencies: - "@backstage/backend-app-api": "workspace:^" - "@backstage/backend-common": "workspace:^" - "@backstage/backend-plugin-api": "workspace:^" - "@backstage/backend-tasks": "workspace:^" - "@backstage/backend-test-utils": "workspace:^" - "@backstage/cli": "workspace:^" - "@backstage/cli-common": "workspace:^" - "@backstage/cli-node": "workspace:^" - "@backstage/config": "workspace:^" - "@backstage/config-loader": "workspace:^" - "@backstage/errors": "workspace:^" - "@backstage/plugin-auth-node": "workspace:^" - "@backstage/plugin-catalog-backend": "workspace:^" - "@backstage/plugin-events-backend": "workspace:^" - "@backstage/plugin-events-node": "workspace:^" - "@backstage/plugin-permission-common": "workspace:^" - "@backstage/plugin-permission-node": "workspace:^" - "@backstage/plugin-scaffolder-node": "workspace:^" - "@backstage/plugin-search-backend-node": "workspace:^" - "@backstage/plugin-search-common": "workspace:^" - "@backstage/types": "workspace:^" - "@types/express": ^4.17.6 - chokidar: ^3.5.3 - express: ^4.17.1 - lodash: ^4.17.21 - wait-for-expect: ^3.0.2 - winston: ^3.2.1 - languageName: unknown - linkType: soft - "@backstage/backend-tasks@workspace:^, @backstage/backend-tasks@workspace:packages/backend-tasks": version: 0.0.0-use.local resolution: "@backstage/backend-tasks@workspace:packages/backend-tasks" From 353244d8399b16439f0614c0731bd1b44767a024 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 22 Dec 2023 13:22:32 -0600 Subject: [PATCH 058/241] Added note about Service Principals Signed-off-by: Andre Wanlin --- .changeset/cyan-bats-lick.md | 5 +++++ plugins/azure-devops-backend/README.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/cyan-bats-lick.md diff --git a/.changeset/cyan-bats-lick.md b/.changeset/cyan-bats-lick.md new file mode 100644 index 0000000000..0683d806b0 --- /dev/null +++ b/.changeset/cyan-bats-lick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-azure-devops-backend': patch +--- + +Added a note about Service Principles diff --git a/plugins/azure-devops-backend/README.md b/plugins/azure-devops-backend/README.md index 2fe62c90eb..b529faf8a6 100644 --- a/plugins/azure-devops-backend/README.md +++ b/plugins/azure-devops-backend/README.md @@ -23,9 +23,9 @@ Configuration Details: - `AZURE_TOKEN` environment variable must be set to a [Personal Access Token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page) with read access to both Code and Build - `organization` is your Azure DevOps Services (cloud) Organization name or for Azure DevOps Server (on-premise) this will be your Collection name -#### Multi Organization +#### Multi Organization & Service Principles -To support cases where you have multiple Azure DevOps organizations you will want to make sure to configure them in the `integrations.azure` section of your `app-config.yaml` as detailed in the [Azure DevOps Locations](https://backstage.io/docs/integrations/azure/locations) documentation. +To support cases where you have multiple Azure DevOps organizations and/or you want to use a Service Principle you will want to make sure to configure them in the `integrations.azure` section of your `app-config.yaml` as detailed in the [Azure DevOps Locations](https://backstage.io/docs/integrations/azure/locations) documentation. **Note:** You will still need to define the [configuration above](#configuration). From 928efbc54a253d1814c248117051ac27c486daaf Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 22 Dec 2023 13:15:34 -0600 Subject: [PATCH 059/241] Updated auth module default export Signed-off-by: Andre Wanlin --- .changeset/brave-ghosts-pay.md | 5 +++++ .changeset/heavy-moose-reflect.md | 5 +++++ plugins/auth-backend-module-microsoft-provider/src/index.ts | 2 +- plugins/auth-backend-module-pinniped-provider/src/index.ts | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 .changeset/brave-ghosts-pay.md create mode 100644 .changeset/heavy-moose-reflect.md diff --git a/.changeset/brave-ghosts-pay.md b/.changeset/brave-ghosts-pay.md new file mode 100644 index 0000000000..84d255ea0d --- /dev/null +++ b/.changeset/brave-ghosts-pay.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-pinniped-provider': minor +--- + +**BREAKING** The `authModulePinnipedProvider` is now the default export and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));` diff --git a/.changeset/heavy-moose-reflect.md b/.changeset/heavy-moose-reflect.md new file mode 100644 index 0000000000..639e3c8bf4 --- /dev/null +++ b/.changeset/heavy-moose-reflect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-microsoft-provider': minor +--- + +**BREAKING** The `authModuleMicrosoftProvider` is now the default export and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));` diff --git a/plugins/auth-backend-module-microsoft-provider/src/index.ts b/plugins/auth-backend-module-microsoft-provider/src/index.ts index ae4fbf5926..735b6716c5 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/index.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/index.ts @@ -21,5 +21,5 @@ */ export { microsoftAuthenticator } from './authenticator'; -export { authModuleMicrosoftProvider } from './module'; +export { authModuleMicrosoftProvider as default } from './module'; export { microsoftSignInResolvers } from './resolvers'; diff --git a/plugins/auth-backend-module-pinniped-provider/src/index.ts b/plugins/auth-backend-module-pinniped-provider/src/index.ts index df4cd58603..bc2bea4c7e 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/index.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/index.ts @@ -21,4 +21,4 @@ */ export { pinnipedAuthenticator, PinnipedStrategyCache } from './authenticator'; -export { authModulePinnipedProvider } from './module'; +export { authModulePinnipedProvider as default } from './module'; From 25b2d7223813ee23f66528037b4fc1c56c0ff31d Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 22 Dec 2023 14:17:09 -0600 Subject: [PATCH 060/241] Updated so a breaking change is not needed Signed-off-by: Andre Wanlin --- .changeset/brave-ghosts-pay.md | 4 ++-- .changeset/heavy-moose-reflect.md | 4 ++-- .../api-report.md | 4 +++- .../src/deprecated.ts | 23 +++++++++++++++++++ .../src/index.ts | 1 + .../api-report.md | 4 +++- .../src/deprecated.ts | 23 +++++++++++++++++++ .../src/index.ts | 1 + 8 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 plugins/auth-backend-module-microsoft-provider/src/deprecated.ts create mode 100644 plugins/auth-backend-module-pinniped-provider/src/deprecated.ts diff --git a/.changeset/brave-ghosts-pay.md b/.changeset/brave-ghosts-pay.md index 84d255ea0d..d8981fa53b 100644 --- a/.changeset/brave-ghosts-pay.md +++ b/.changeset/brave-ghosts-pay.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-auth-backend-module-pinniped-provider': minor +'@backstage/plugin-auth-backend-module-pinniped-provider': patch --- -**BREAKING** The `authModulePinnipedProvider` is now the default export and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));` +Deprecated the `authModulePinnipedProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));` diff --git a/.changeset/heavy-moose-reflect.md b/.changeset/heavy-moose-reflect.md index 639e3c8bf4..011d3fc023 100644 --- a/.changeset/heavy-moose-reflect.md +++ b/.changeset/heavy-moose-reflect.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-auth-backend-module-microsoft-provider': minor +'@backstage/plugin-auth-backend-module-microsoft-provider': patch --- -**BREAKING** The `authModuleMicrosoftProvider` is now the default export and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));` +Deprecated the `authModuleMicrosoftProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));` diff --git a/plugins/auth-backend-module-microsoft-provider/api-report.md b/plugins/auth-backend-module-microsoft-provider/api-report.md index 21bf77d545..c54b986864 100644 --- a/plugins/auth-backend-module-microsoft-provider/api-report.md +++ b/plugins/auth-backend-module-microsoft-provider/api-report.md @@ -11,7 +11,9 @@ import { PassportProfile } from '@backstage/plugin-auth-node'; import { SignInResolverFactory } from '@backstage/plugin-auth-node'; // @public (undocumented) -export const authModuleMicrosoftProvider: () => BackendFeature; +const authModuleMicrosoftProvider: () => BackendFeature; +export { authModuleMicrosoftProvider }; +export default authModuleMicrosoftProvider; // @public (undocumented) export const microsoftAuthenticator: OAuthAuthenticator< diff --git a/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts b/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts new file mode 100644 index 0000000000..c961e1c942 --- /dev/null +++ b/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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 { authModuleMicrosoftProvider as deprecatedAuthModuleMicrosoftProvider } from './module'; + +/** + * @public + * @deprecated Use default import instead + */ +export { deprecatedAuthModuleMicrosoftProvider as authModuleMicrosoftProvider }; diff --git a/plugins/auth-backend-module-microsoft-provider/src/index.ts b/plugins/auth-backend-module-microsoft-provider/src/index.ts index 735b6716c5..45b7b719cd 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/index.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/index.ts @@ -23,3 +23,4 @@ export { microsoftAuthenticator } from './authenticator'; export { authModuleMicrosoftProvider as default } from './module'; export { microsoftSignInResolvers } from './resolvers'; +export * from './deprecated'; diff --git a/plugins/auth-backend-module-pinniped-provider/api-report.md b/plugins/auth-backend-module-pinniped-provider/api-report.md index 430099713e..3a8b6b5bf6 100644 --- a/plugins/auth-backend-module-pinniped-provider/api-report.md +++ b/plugins/auth-backend-module-pinniped-provider/api-report.md @@ -11,7 +11,9 @@ import { Strategy } from 'openid-client'; import { TokenSet } from 'openid-client'; // @public (undocumented) -export const authModulePinnipedProvider: () => BackendFeature; +const authModulePinnipedProvider: () => BackendFeature; +export { authModulePinnipedProvider }; +export default authModulePinnipedProvider; // @public (undocumented) export const pinnipedAuthenticator: OAuthAuthenticator< diff --git a/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts b/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts new file mode 100644 index 0000000000..f11cdc13e6 --- /dev/null +++ b/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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 { authModulePinnipedProvider as deprecatedAuthModulePinnipedProvider } from './module'; + +/** + * @public + * @deprecated Use default import instead + */ +export { deprecatedAuthModulePinnipedProvider as authModulePinnipedProvider }; diff --git a/plugins/auth-backend-module-pinniped-provider/src/index.ts b/plugins/auth-backend-module-pinniped-provider/src/index.ts index bc2bea4c7e..f4b789644d 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/index.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/index.ts @@ -22,3 +22,4 @@ export { pinnipedAuthenticator, PinnipedStrategyCache } from './authenticator'; export { authModulePinnipedProvider as default } from './module'; +export * from './deprecated'; From e508999a639d7f10d6919e33941e84037f7c15ab Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Wed, 10 Jan 2024 16:22:33 -0600 Subject: [PATCH 061/241] Adjustment based on feedback Signed-off-by: Andre Wanlin --- .../auth-backend-module-microsoft-provider/api-report.md | 8 +++++--- .../src/deprecated.ts | 3 ++- .../auth-backend-module-pinniped-provider/api-report.md | 8 +++++--- .../src/deprecated.ts | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/plugins/auth-backend-module-microsoft-provider/api-report.md b/plugins/auth-backend-module-microsoft-provider/api-report.md index c54b986864..33600c10d8 100644 --- a/plugins/auth-backend-module-microsoft-provider/api-report.md +++ b/plugins/auth-backend-module-microsoft-provider/api-report.md @@ -10,10 +10,12 @@ import { PassportOAuthAuthenticatorHelper } from '@backstage/plugin-auth-node'; import { PassportProfile } from '@backstage/plugin-auth-node'; import { SignInResolverFactory } from '@backstage/plugin-auth-node'; +// @public @deprecated (undocumented) +export const authModuleMicrosoftProvider: () => BackendFeature; + // @public (undocumented) -const authModuleMicrosoftProvider: () => BackendFeature; -export { authModuleMicrosoftProvider }; -export default authModuleMicrosoftProvider; +const authModuleMicrosoftProvider_2: () => BackendFeature; +export default authModuleMicrosoftProvider_2; // @public (undocumented) export const microsoftAuthenticator: OAuthAuthenticator< diff --git a/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts b/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts index c961e1c942..3c671b6c25 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/deprecated.ts @@ -20,4 +20,5 @@ import { authModuleMicrosoftProvider as deprecatedAuthModuleMicrosoftProvider } * @public * @deprecated Use default import instead */ -export { deprecatedAuthModuleMicrosoftProvider as authModuleMicrosoftProvider }; +export const authModuleMicrosoftProvider = + deprecatedAuthModuleMicrosoftProvider; diff --git a/plugins/auth-backend-module-pinniped-provider/api-report.md b/plugins/auth-backend-module-pinniped-provider/api-report.md index 3a8b6b5bf6..182ea8ba21 100644 --- a/plugins/auth-backend-module-pinniped-provider/api-report.md +++ b/plugins/auth-backend-module-pinniped-provider/api-report.md @@ -10,10 +10,12 @@ import { OAuthAuthenticator } from '@backstage/plugin-auth-node'; import { Strategy } from 'openid-client'; import { TokenSet } from 'openid-client'; +// @public @deprecated (undocumented) +export const authModulePinnipedProvider: () => BackendFeature; + // @public (undocumented) -const authModulePinnipedProvider: () => BackendFeature; -export { authModulePinnipedProvider }; -export default authModulePinnipedProvider; +const authModulePinnipedProvider_2: () => BackendFeature; +export default authModulePinnipedProvider_2; // @public (undocumented) export const pinnipedAuthenticator: OAuthAuthenticator< diff --git a/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts b/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts index f11cdc13e6..0dd2ed36bd 100644 --- a/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts +++ b/plugins/auth-backend-module-pinniped-provider/src/deprecated.ts @@ -20,4 +20,4 @@ import { authModulePinnipedProvider as deprecatedAuthModulePinnipedProvider } fr * @public * @deprecated Use default import instead */ -export { deprecatedAuthModulePinnipedProvider as authModulePinnipedProvider }; +export const authModulePinnipedProvider = deprecatedAuthModulePinnipedProvider; From 765af3b39791f2aff77e7a3b4bb60b53635adf1b Mon Sep 17 00:00:00 2001 From: Fer Date: Thu, 21 Dec 2023 11:37:13 -0300 Subject: [PATCH 062/241] Add missing imports on example code Signed-off-by: Fer --- plugins/events-backend/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/events-backend/README.md b/plugins/events-backend/README.md index 6fa02a7e6a..2fd980f003 100644 --- a/plugins/events-backend/README.md +++ b/plugins/events-backend/README.md @@ -42,6 +42,7 @@ Add the following to `makeCreateEnv` ```diff // packages/backend/src/index.ts ++ import { DefaultEventBroker } from '@backstage/plugin-events-backend'; + const eventBroker = new DefaultEventBroker(root.child({ type: 'plugin' })); ``` @@ -49,6 +50,7 @@ Then update plugin environment to include the event broker. ```diff // packages/backend/src/types.ts ++ import { EventBroker } from '@backstage/plugin-events-node'; + eventBroker: EventBroker; ``` From 92ea61543164c2978bdc21ac977026c62bde1528 Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 10 Jan 2024 11:25:27 +0100 Subject: [PATCH 063/241] chore: added chantgeset Signed-off-by: blam Signed-off-by: blam --- .changeset/ninety-impalas-knock.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/ninety-impalas-knock.md diff --git a/.changeset/ninety-impalas-knock.md b/.changeset/ninety-impalas-knock.md new file mode 100644 index 0000000000..78bd55dc1c --- /dev/null +++ b/.changeset/ninety-impalas-knock.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-events-backend': patch +--- + +Update `README.md` From f7f61eb0ecd76c6305c079e5b504e1aebf1e6268 Mon Sep 17 00:00:00 2001 From: Peter Macdonald Date: Thu, 11 Jan 2024 13:04:47 +0100 Subject: [PATCH 064/241] added friendly warning under community contributed plugins Signed-off-by: Peter Macdonald --- microsite/src/pages/plugins/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/microsite/src/pages/plugins/index.tsx b/microsite/src/pages/plugins/index.tsx index 006b7d4807..54f0b3514e 100644 --- a/microsite/src/pages/plugins/index.tsx +++ b/microsite/src/pages/plugins/index.tsx @@ -151,6 +151,9 @@ const Plugins = () => { {showOtherPlugins && (

All Plugins

+

+ Friendly reminder: While we love the variety and contributions of our open source plugins, they haven't been fully vetted by the core Backstage team. We encourage you to exercise caution and do your due diligence before installing. Happy exploring! +

{plugins.otherPlugins .filter( From 732813fb634357367f09bcd894caf61d24265e6d Mon Sep 17 00:00:00 2001 From: Peter Macdonald Date: Thu, 11 Jan 2024 13:22:45 +0100 Subject: [PATCH 065/241] forgot to run prettier Signed-off-by: Peter Macdonald --- microsite/src/pages/plugins/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/microsite/src/pages/plugins/index.tsx b/microsite/src/pages/plugins/index.tsx index 54f0b3514e..2abdbabf4b 100644 --- a/microsite/src/pages/plugins/index.tsx +++ b/microsite/src/pages/plugins/index.tsx @@ -152,7 +152,10 @@ const Plugins = () => {

All Plugins

- Friendly reminder: While we love the variety and contributions of our open source plugins, they haven't been fully vetted by the core Backstage team. We encourage you to exercise caution and do your due diligence before installing. Happy exploring! + Friendly reminder: While we love the variety and contributions of + our open source plugins, they haven't been fully vetted by the + core Backstage team. We encourage you to exercise caution and do + your due diligence before installing. Happy exploring!

{plugins.otherPlugins From 169e3ffc1fcdec3d2eef1b5f84cf488db814c4cc Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Fri, 12 Jan 2024 13:38:34 +0200 Subject: [PATCH 066/241] feat: move all signal handling to backend plugin Signed-off-by: Heikki Hellgren --- packages/backend/src/index.ts | 2 - packages/backend/src/plugins/signals.ts | 3 +- plugins/signals-backend/README.md | 5 +- plugins/signals-backend/api-report.md | 9 +- plugins/signals-backend/src/plugin.ts | 9 +- .../src/service/SignalManager.ts | 213 +++++++++++++++++ .../src/service/router.test.ts | 15 +- plugins/signals-backend/src/service/router.ts | 13 +- .../src/service/standaloneServer.ts | 39 ++- plugins/signals-node/README.md | 34 ++- plugins/signals-node/api-report.md | 46 +--- .../signals-node/src/DefaultSignalService.ts | 222 ++---------------- plugins/signals-node/src/SignalService.ts | 24 +- plugins/signals-node/src/lib.ts | 10 +- plugins/signals-node/src/types.ts | 26 +- plugins/signals-react/README.md | 11 +- plugins/signals-react/api-report.md | 4 +- plugins/signals-react/src/api/SignalApi.ts | 2 +- plugins/signals-react/src/hooks/useSignal.ts | 6 +- plugins/signals/api-report.md | 2 +- plugins/signals/src/api/SignalClient.ts | 29 ++- plugins/signals/src/api/SignalsClient.test.ts | 26 +- 22 files changed, 392 insertions(+), 358 deletions(-) create mode 100644 plugins/signals-backend/src/service/SignalManager.ts diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 0e92698230..bade028597 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -101,9 +101,7 @@ function makeCreateEnv(config: Config) { const eventBroker = new DefaultEventBroker(root.child({ type: 'plugin' })); const signalService = DefaultSignalService.create({ - logger: root, eventBroker, - identity, }); root.info(`Created UrlReader ${reader}`); diff --git a/packages/backend/src/plugins/signals.ts b/packages/backend/src/plugins/signals.ts index 687fcfaa33..477cea1938 100644 --- a/packages/backend/src/plugins/signals.ts +++ b/packages/backend/src/plugins/signals.ts @@ -22,6 +22,7 @@ export default async function createPlugin( ): Promise { return await createRouter({ logger: env.logger, - service: env.signalService, + eventBroker: env.eventBroker, + identity: env.identity, }); } diff --git a/plugins/signals-backend/README.md b/plugins/signals-backend/README.md index f9ebfb80c7..e30a0836e0 100644 --- a/plugins/signals-backend/README.md +++ b/plugins/signals-backend/README.md @@ -20,7 +20,8 @@ export default async function createPlugin( ): Promise { return await createRouter({ logger: env.logger, - service: env.signalsService, + eventBroker: env.eventBroker, + identity: env.identity, }); } ``` @@ -29,7 +30,7 @@ Now add the signals to `packages/backend/src/index.ts`: ```ts // ... -import signals from './plugins/sonarqube'; +import signals from './plugins/signals'; async function main() { // ... diff --git a/plugins/signals-backend/api-report.md b/plugins/signals-backend/api-report.md index e96dd2e09c..dd46778e5d 100644 --- a/plugins/signals-backend/api-report.md +++ b/plugins/signals-backend/api-report.md @@ -4,9 +4,10 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; +import { EventBroker } from '@backstage/plugin-events-node'; import express from 'express'; +import { IdentityApi } from '@backstage/plugin-auth-node'; import { LoggerService } from '@backstage/backend-plugin-api'; -import { SignalService } from '@backstage/plugin-signals-node'; // @public (undocumented) export function createRouter(options: RouterOptions): Promise; @@ -14,9 +15,11 @@ export function createRouter(options: RouterOptions): Promise; // @public (undocumented) export interface RouterOptions { // (undocumented) - logger: LoggerService; + eventBroker?: EventBroker; // (undocumented) - service: SignalService; + identity: IdentityApi; + // (undocumented) + logger: LoggerService; } // @public diff --git a/plugins/signals-backend/src/plugin.ts b/plugins/signals-backend/src/plugin.ts index 68bbf27377..4a9cef028f 100644 --- a/plugins/signals-backend/src/plugin.ts +++ b/plugins/signals-backend/src/plugin.ts @@ -18,7 +18,6 @@ import { createBackendPlugin, } from '@backstage/backend-plugin-api'; import { createRouter } from './service/router'; -import { signalService } from '@backstage/plugin-signals-node'; /** * Signals backend plugin @@ -32,13 +31,15 @@ export const signalsPlugin = createBackendPlugin({ deps: { httpRouter: coreServices.httpRouter, logger: coreServices.logger, - service: signalService, + identity: coreServices.identity, + // TODO: EventBroker. It is optional for now but it's actually required so waiting for the new backend system + // for the events-backend for this to work. }, - async init({ httpRouter, logger, service }) { + async init({ httpRouter, logger, identity }) { httpRouter.use( await createRouter({ logger, - service, + identity, }), ); }, diff --git a/plugins/signals-backend/src/service/SignalManager.ts b/plugins/signals-backend/src/service/SignalManager.ts new file mode 100644 index 0000000000..988db47465 --- /dev/null +++ b/plugins/signals-backend/src/service/SignalManager.ts @@ -0,0 +1,213 @@ +/* + * Copyright 2023 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 { EventBroker, EventParams } from '@backstage/plugin-events-node'; +import { SignalPayload } from '@backstage/plugin-signals-node'; +import { RawData, WebSocket, WebSocketServer } from 'ws'; +import { IncomingMessage } from 'http'; +import { v4 as uuid } from 'uuid'; +import { JsonObject } from '@backstage/types'; +import { + BackstageIdentityResponse, + IdentityApi, + IdentityApiGetIdentityRequest, +} from '@backstage/plugin-auth-node'; +import { LoggerService } from '@backstage/backend-plugin-api'; +import { Duplex } from 'stream'; + +/** @internal */ +export type ConnectionUpgradeOptions = { + request: IncomingMessage; + socket: Duplex; + head: Buffer; +}; + +/** + * @internal + */ +export type SignalConnection = { + id: string; + user: string; + ws: WebSocket; + ownershipEntityRefs: string[]; + subscriptions: Set; +}; + +/** + * @internal + */ +export type SignalManagerOptions = { + // TODO: Remove optional when events-backend can offer this service + eventBroker?: EventBroker; + logger: LoggerService; + identity: IdentityApi; +}; + +/** @internal */ +export class SignalManager { + private connections: Map = new Map< + string, + SignalConnection + >(); + private eventBroker?: EventBroker; + private logger: LoggerService; + private identity: IdentityApi; + private server: WebSocketServer; + + static create(options: SignalManagerOptions) { + return new SignalManager(options); + } + + private constructor(options: SignalManagerOptions) { + ({ + eventBroker: this.eventBroker, + logger: this.logger, + identity: this.identity, + } = options); + + this.server = new WebSocketServer({ + noServer: true, + clientTracking: false, + }); + + this.eventBroker?.subscribe({ + supportsEventTopics: () => ['signals'], + onEvent: (params: EventParams) => + this.onEventBrokerEvent(params), + }); + } + + /** + * Handles request upgrade to websocket and adds the connection to internal + * list for publish/subscribe functionality + * @param req - Request + */ + async handleUpgrade(options: ConnectionUpgradeOptions) { + const { request, socket, head } = options; + let identity: BackstageIdentityResponse | undefined = undefined; + + // Authentication token is passed in Sec-WebSocket-Protocol header as there + // is no other way to pass the token with plain websockets + const token = request.headers['sec-websocket-protocol']; + if (token) { + identity = await this.identity.getIdentity({ + request: { + headers: { authorization: token }, + }, + } as IdentityApiGetIdentityRequest); + } + + this.server.handleUpgrade( + request, + socket, + head, + (ws: WebSocket, __: IncomingMessage) => { + this.addConnection(ws, identity); + }, + ); + } + + private addConnection(ws: WebSocket, identity?: BackstageIdentityResponse) { + const id = uuid(); + + const conn = { + id, + user: identity?.identity.userEntityRef ?? 'user:default/guest', + ws, + ownershipEntityRefs: identity?.identity.ownershipEntityRefs ?? [], + subscriptions: new Set(), + }; + + this.connections.set(id, conn); + + ws.on('error', (err: Error) => { + this.logger.info( + `Error occurred with connection ${id}: ${err}, closing connection`, + ); + ws.close(); + this.connections.delete(id); + }); + + ws.on('close', (code: number, reason: Buffer) => { + this.logger.info( + `Connection ${id} closed with code ${code}, reason: ${reason}`, + ); + this.connections.delete(id); + }); + + ws.on('message', (data: RawData, isBinary: boolean) => { + this.logger.debug(`Received message from connection ${id}: ${data}`); + if (isBinary) { + return; + } + try { + const json = JSON.parse(data.toString()) as JsonObject; + this.handleMessage(conn, json); + } catch (err: any) { + this.logger.error( + `Invalid message received from connection ${id}: ${err}`, + ); + } + }); + } + + private handleMessage(connection: SignalConnection, message: JsonObject) { + if (message.action === 'subscribe' && message.channel) { + this.logger.info( + `Connection ${connection.id} subscribed to ${message.channel}`, + ); + connection.subscriptions.add(message.channel as string); + } else if (message.action === 'unsubscribe' && message.channel) { + this.logger.info( + `Connection ${connection.id} unsubscribed from ${message.channel}`, + ); + connection.subscriptions.delete(message.channel as string); + } + } + + private async onEventBrokerEvent( + params: EventParams, + ): Promise { + const { eventPayload } = params; + if (!eventPayload.channel || !eventPayload.message) { + return; + } + + const { channel, recipients, message } = eventPayload; + const jsonMessage = JSON.stringify({ channel, message }); + + // Actual websocket message sending + this.connections.forEach(conn => { + if (!conn.subscriptions.has(channel)) { + return; + } + // Sending to all users can be done with null + if ( + recipients !== null && + !conn.ownershipEntityRefs.some((ref: string) => + recipients.includes(ref), + ) + ) { + return; + } + + if (conn.ws.readyState !== WebSocket.OPEN) { + return; + } + + conn.ws.send(jsonMessage); + }); + } +} diff --git a/plugins/signals-backend/src/service/router.test.ts b/plugins/signals-backend/src/service/router.test.ts index 281d6ed4a5..ecf2ad4aa6 100644 --- a/plugins/signals-backend/src/service/router.test.ts +++ b/plugins/signals-backend/src/service/router.test.ts @@ -18,9 +18,17 @@ import express from 'express'; import request from 'supertest'; import { createRouter } from './router'; -import { DefaultSignalService } from '@backstage/plugin-signals-node'; +import { EventBroker } from '@backstage/plugin-events-node'; +import { IdentityApi } from '@backstage/plugin-auth-node'; -const signalsServiceMock: jest.Mocked = {} as any; +const eventBrokerMock: jest.Mocked = { + subscribe: jest.fn(), + publish: jest.fn(), +}; + +const identityApiMock: jest.Mocked = { + getIdentity: jest.fn(), +}; describe('createRouter', () => { let app: express.Express; @@ -28,7 +36,8 @@ describe('createRouter', () => { beforeAll(async () => { const router = await createRouter({ logger: getVoidLogger(), - service: signalsServiceMock, + identity: identityApiMock, + eventBroker: eventBrokerMock, }); app = express().use(router); }); diff --git a/plugins/signals-backend/src/service/router.ts b/plugins/signals-backend/src/service/router.ts index 28bafce14a..ec56860bf3 100644 --- a/plugins/signals-backend/src/service/router.ts +++ b/plugins/signals-backend/src/service/router.ts @@ -17,22 +17,27 @@ import { errorHandler } from '@backstage/backend-common'; import express, { NextFunction, Request, Response } from 'express'; import Router from 'express-promise-router'; import { LoggerService } from '@backstage/backend-plugin-api'; -import { SignalService } from '@backstage/plugin-signals-node'; import * as https from 'https'; import http from 'http'; +import { SignalManager } from './SignalManager'; +import { IdentityApi } from '@backstage/plugin-auth-node'; +import { EventBroker } from '@backstage/plugin-events-node'; /** @public */ export interface RouterOptions { logger: LoggerService; - service: SignalService; + eventBroker?: EventBroker; + identity: IdentityApi; } /** @public */ export async function createRouter( options: RouterOptions, ): Promise { - const { logger, service } = options; + const { logger } = options; + const manager = SignalManager.create(options); let subscribed = false; + const upgradeMiddleware = (req: Request, _: Response, next: NextFunction) => { const server: https.Server | http.Server = (req.socket as any)?.server; if ( @@ -50,7 +55,7 @@ export async function createRouter( server.on('upgrade', async (request, socket, head) => { // TODO: Find a way to make this more generic if (request.url === '/api/signals') { - await service.handleUpgrade({ server, request, socket, head }); + await manager.handleUpgrade({ request, socket, head }); } }); } diff --git a/plugins/signals-backend/src/service/standaloneServer.ts b/plugins/signals-backend/src/service/standaloneServer.ts index e1ce27aee4..278de8621e 100644 --- a/plugins/signals-backend/src/service/standaloneServer.ts +++ b/plugins/signals-backend/src/service/standaloneServer.ts @@ -23,6 +23,11 @@ import { Logger } from 'winston'; import { createRouter } from './router'; import { DefaultSignalService } from '@backstage/plugin-signals-node'; import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; +import { + EventBroker, + EventParams, + EventSubscriber, +} from '@backstage/plugin-events-node'; export interface ServerOptions { port: number; @@ -43,14 +48,26 @@ export async function startStandaloneServer( issuer: await discovery.getExternalBaseUrl('auth'), }); + const mockSubscribers: EventSubscriber[] = []; + const eventBroker: EventBroker = { + async publish(params: EventParams): Promise { + mockSubscribers.forEach(sub => sub.onEvent(params)); + }, + subscribe(...subscribers: EventSubscriber[]) { + subscribers.flat().forEach(subscriber => { + mockSubscribers.push(subscriber); + }); + }, + }; + const signals = DefaultSignalService.create({ - logger: logger, - identity, + eventBroker, }); const router = await createRouter({ logger, - service: signals, + identity, + eventBroker, }); let service = createServiceBuilder(module) @@ -60,10 +77,22 @@ export async function startStandaloneServer( service = service.enableCors({ origin: 'http://localhost:3000' }); } - return await service.start().catch(err => { + let server: Promise; + try { + server = service.start(); + + setInterval(() => { + signals.publish({ + recipients: null, + channel: 'test', + message: { hello: 'world' }, + }); + }, 5000); + } catch (err) { logger.error(err); process.exit(1); - }); + } + return server; } module.hot?.accept(); diff --git a/plugins/signals-node/README.md b/plugins/signals-node/README.md index 14c9332dc1..5e738a849d 100644 --- a/plugins/signals-node/README.md +++ b/plugins/signals-node/README.md @@ -27,10 +27,8 @@ function makeCreateEnv(config: Config) { // ... const eventBroker = new DefaultEventBroker(root.child({ type: 'plugin' })); - const signalService = SignalService.create({ - logger: root, - eventBroker, // EventBroker is optional - identity, + const signalService = DefaultSignalService.create({ + eventBroker, }); return (plugin: string): PluginEnvironment => { @@ -51,16 +49,38 @@ To allow connections from the frontend, you should also install the `@backstage/ Once you have both of the backend plugins installed, you can utilize the signal service by calling the `publish` method. This will publish the message to all subscribers in the frontend. To send message to -all subscribers, you can use `*` as `to` parameter. +all subscribers, you can use `null` as `recipients` parameter. ```ts // Periodic sending example setInterval(async () => { - await signalService.publish('*', 'plugin:topic', { - message: 'hello world', + await signalService.publish({ + recipients: null, + channel: 'my_plugin', + message: { + message: 'hello world', + }, }); }, 5000); ``` To receive this message in the frontend, check the documentation of `@backstage/plugin-signals` and `@backstage/plugin-signals-react`. + +## Using event broker directly + +Other way to send signals is to utilize the `EventBroker` directly. This requires that the payload is correct for it +to work: + +```ts +eventBroker.publish({ + topic: 'signals', + eventPayload: { + recipients: ['user:default/user1'], + message: { + message: 'hello world', + }, + channel: 'my_plugin', + }, +}); +``` diff --git a/plugins/signals-node/api-report.md b/plugins/signals-node/api-report.md index d85163040b..00d099f7db 100644 --- a/plugins/signals-node/api-report.md +++ b/plugins/signals-node/api-report.md @@ -3,63 +3,35 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -/// - -import { Duplex } from 'stream'; import { EventBroker } from '@backstage/plugin-events-node'; -import http from 'http'; -import https from 'https'; -import { IdentityApi } from '@backstage/plugin-auth-node'; -import { IncomingMessage } from 'http'; import { JsonObject } from '@backstage/types'; -import { LoggerService } from '@backstage/backend-plugin-api'; import { ServiceRef } from '@backstage/backend-plugin-api'; // @public (undocumented) export class DefaultSignalService implements SignalService { // (undocumented) - static create(options: ServiceOptions): DefaultSignalService; - handleUpgrade(options: SignalServiceUpgradeOptions): Promise; - publish( - to: string | string[], - topic: string, - message: JsonObject, - ): Promise; + static create(options: SignalServiceOptions): DefaultSignalService; + publish(signal: SignalPayload): Promise; } // @public (undocumented) -export type ServiceOptions = { - eventBroker?: EventBroker; - logger: LoggerService; - identity: IdentityApi; -}; - -// @public (undocumented) -export type SignalEventBrokerPayload = { - recipients?: string[]; - topic?: string; - message?: JsonObject; +export type SignalPayload = { + recipients: string[] | null; + channel: string; + message: JsonObject; }; // @public (undocumented) export type SignalService = { - publish( - to: string | string[], - topic: string, - message: JsonObject, - ): Promise; - handleUpgrade(options: SignalServiceUpgradeOptions): Promise; + publish(signal: SignalPayload): Promise; }; // @public (undocumented) export const signalService: ServiceRef; // @public (undocumented) -export type SignalServiceUpgradeOptions = { - server: https.Server | http.Server; - request: IncomingMessage; - socket: Duplex; - head: Buffer; +export type SignalServiceOptions = { + eventBroker?: EventBroker; }; // (No @packageDocumentation comment for this package) diff --git a/plugins/signals-node/src/DefaultSignalService.ts b/plugins/signals-node/src/DefaultSignalService.ts index cab6e83c81..1fba96b8bc 100644 --- a/plugins/signals-node/src/DefaultSignalService.ts +++ b/plugins/signals-node/src/DefaultSignalService.ts @@ -13,226 +13,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { EventBroker, EventParams } from '@backstage/plugin-events-node'; -import { - ServiceOptions, - SignalConnection, - SignalEventBrokerPayload, -} from './types'; -import { RawData, WebSocket, WebSocketServer } from 'ws'; -import { IncomingMessage } from 'http'; -import { v4 as uuid } from 'uuid'; -import { JsonObject } from '@backstage/types'; -import { - BackstageIdentityResponse, - IdentityApi, - IdentityApiGetIdentityRequest, -} from '@backstage/plugin-auth-node'; -import { LoggerService } from '@backstage/backend-plugin-api'; -import { SignalService, SignalServiceUpgradeOptions } from './SignalService'; +import { EventBroker } from '@backstage/plugin-events-node'; +import { SignalPayload, SignalServiceOptions } from './types'; +import { SignalService } from './SignalService'; /** @public */ export class DefaultSignalService implements SignalService { - private connections: Map = new Map< - string, - SignalConnection - >(); + // TODO: Remove this to be optional when events-backend has eventBroker as service private eventBroker?: EventBroker; - private logger: LoggerService; - private identity: IdentityApi; - private server: WebSocketServer; - static create(options: ServiceOptions) { + static create(options: SignalServiceOptions) { return new DefaultSignalService(options); } - private constructor(options: ServiceOptions) { - ({ - eventBroker: this.eventBroker, - logger: this.logger, - identity: this.identity, - } = options); - - this.server = new WebSocketServer({ - noServer: true, - clientTracking: false, - }); - - this.eventBroker?.subscribe({ - supportsEventTopics: () => ['signals'], - onEvent: (params: EventParams) => - this.onEventBrokerEvent(params), - }); - } - - /** - * Handles request upgrade to websocket and adds the connection to internal - * list for publish/subscribe functionality - * @param req - Request - */ - async handleUpgrade(options: SignalServiceUpgradeOptions) { - const { request, socket, head } = options; - let identity: BackstageIdentityResponse | undefined = undefined; - - // Authentication token is passed in Sec-WebSocket-Protocol header as there - // is no other way to pass the token with plain websockets - const token = request.headers['sec-websocket-protocol']; - if (token) { - identity = await this.identity.getIdentity({ - request: { - headers: { authorization: token }, - }, - } as IdentityApiGetIdentityRequest); - } - - this.server.handleUpgrade( - request, - socket, - head, - (ws: WebSocket, __: IncomingMessage) => { - this.addConnection(ws, identity); - }, - ); - } - - private addConnection(ws: WebSocket, identity?: BackstageIdentityResponse) { - const id = uuid(); - - const conn = { - id, - user: identity?.identity.userEntityRef ?? 'user:default/guest', - ws, - ownershipEntityRefs: identity?.identity.ownershipEntityRefs ?? [], - subscriptions: new Set(), - }; - - this.connections.set(id, conn); - - ws.on('error', (err: Error) => { - this.logger.info( - `Error occurred with connection ${id}: ${err}, closing connection`, - ); - ws.close(); - this.connections.delete(id); - }); - - ws.on('close', (code: number, reason: Buffer) => { - this.logger.info( - `Connection ${id} closed with code ${code}, reason: ${reason}`, - ); - this.connections.delete(id); - }); - - ws.on('message', (data: RawData, isBinary: boolean) => { - this.logger.debug(`Received message from connection ${id}: ${data}`); - if (isBinary) { - return; - } - try { - const json = JSON.parse(data.toString()) as JsonObject; - this.handleMessage(conn, json); - } catch (err: any) { - this.logger.error( - `Invalid message received from connection ${id}: ${err}`, - ); - } - }); - } - - private handleMessage(connection: SignalConnection, message: JsonObject) { - if (message.action === 'subscribe' && message.topic) { - this.logger.info( - `Connection ${connection.id} subscribed to ${message.topic}`, - ); - connection.subscriptions.add(message.topic as string); - } - - if (message.action === 'unsubscribe' && message.topic) { - this.logger.info( - `Connection ${connection.id} unsubscribed from ${message.topic}`, - ); - connection.subscriptions.delete(message.topic as string); - } + private constructor(options: SignalServiceOptions) { + ({ eventBroker: this.eventBroker } = options); } /** * Publishes a message to user refs to specific topic - * @param to - string or array of user ref strings to publish message to + * @param recipients - string or array of user ref strings to publish message to * @param topic - message topic * @param message - message to publish */ - async publish(to: string | string[], topic: string, message: JsonObject) { - await this.publishInternal( - Array.isArray(to) ? to : [to], - topic, - message, - false, - ); - } - - private async publishInternal( - recipients: string[], - topic: string, - message: JsonObject, - brokedEvent: boolean, - ) { - const jsonMessage = JSON.stringify({ topic, message }); - if (jsonMessage.length === 0) { - return; - } - - // If there is event broker, use that to publish the message to - // all signal services, including this one. - if (this.eventBroker && !brokedEvent) { - await this.eventBroker.publish({ - topic: 'signals', - eventPayload: { - recipients, - message, - topic, - }, - }); - return; - } - - // Actual websocket message sending - this.connections.forEach(conn => { - if (!conn.subscriptions.has(topic)) { - return; - } - // Sending to all users can be done with '*' - if ( - !recipients.includes('*') && - !conn.ownershipEntityRefs.some(ref => recipients.includes(ref)) - ) { - return; - } - - if (conn.ws.readyState !== WebSocket.OPEN) { - return; - } - - conn.ws.send(jsonMessage); + async publish(signal: SignalPayload) { + const { recipients, channel, message } = signal; + await this.eventBroker?.publish({ + topic: 'signals', + eventPayload: { + recipients, + message, + channel, + }, }); } - - private async onEventBrokerEvent( - params: EventParams, - ): Promise { - const { eventPayload } = params; - if ( - !eventPayload?.recipients || - !eventPayload.topic || - !eventPayload.message - ) { - return; - } - - await this.publishInternal( - eventPayload.recipients, - eventPayload.topic, - eventPayload.message, - true, - ); - } } diff --git a/plugins/signals-node/src/SignalService.ts b/plugins/signals-node/src/SignalService.ts index 7095c29858..f08a12661f 100644 --- a/plugins/signals-node/src/SignalService.ts +++ b/plugins/signals-node/src/SignalService.ts @@ -13,32 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { JsonObject } from '@backstage/types'; -import http, { IncomingMessage } from 'http'; -import { Duplex } from 'stream'; -import https from 'https'; - -/** @public */ -export type SignalServiceUpgradeOptions = { - server: https.Server | http.Server; - request: IncomingMessage; - socket: Duplex; - head: Buffer; -}; +import { SignalPayload } from './types'; /** @public */ export type SignalService = { /** * Publishes a message to user refs to specific topic */ - publish( - to: string | string[], - topic: string, - message: JsonObject, - ): Promise; - - /** - * Handles request upgrade - */ - handleUpgrade(options: SignalServiceUpgradeOptions): Promise; + publish(signal: SignalPayload): Promise; }; diff --git a/plugins/signals-node/src/lib.ts b/plugins/signals-node/src/lib.ts index c7e7c4a6ae..095a2f085d 100644 --- a/plugins/signals-node/src/lib.ts +++ b/plugins/signals-node/src/lib.ts @@ -14,7 +14,6 @@ * limitations under the License. */ import { - coreServices, createServiceFactory, createServiceRef, } from '@backstage/backend-plugin-api'; @@ -29,12 +28,11 @@ export const signalService = createServiceRef({ createServiceFactory({ service, deps: { - logger: coreServices.logger, - identity: coreServices.identity, - // TODO: EventBroker + // TODO: EventBroker. It is optional for now but it's actually required so waiting for the new backend system + // for the events-backend for this to work. }, - factory({ logger, identity }) { - return DefaultSignalService.create({ identity, logger }); + factory({}) { + return DefaultSignalService.create({}); }, }), }); diff --git a/plugins/signals-node/src/types.ts b/plugins/signals-node/src/types.ts index 6bfafae0b2..0220a196aa 100644 --- a/plugins/signals-node/src/types.ts +++ b/plugins/signals-node/src/types.ts @@ -13,35 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { IdentityApi } from '@backstage/plugin-auth-node'; import { EventBroker } from '@backstage/plugin-events-node'; -import { WebSocket } from 'ws'; import { JsonObject } from '@backstage/types'; -import { LoggerService } from '@backstage/backend-plugin-api'; /** * @public */ -export type ServiceOptions = { +export type SignalServiceOptions = { eventBroker?: EventBroker; - logger: LoggerService; - identity: IdentityApi; }; /** @public */ -export type SignalEventBrokerPayload = { - recipients?: string[]; - topic?: string; - message?: JsonObject; -}; - -/** - * @internal - */ -export type SignalConnection = { - id: string; - user: string; - ws: WebSocket; - ownershipEntityRefs: string[]; - subscriptions: Set; +export type SignalPayload = { + recipients: string[] | null; + channel: string; + message: JsonObject; }; diff --git a/plugins/signals-react/README.md b/plugins/signals-react/README.md index 244a4ec43d..4da9338866 100644 --- a/plugins/signals-react/README.md +++ b/plugins/signals-react/README.md @@ -22,10 +22,15 @@ Example of using the hook: ```ts import { useSignal } from '@backstage/plugin-signals-react'; -const { lastSignal } = useSignal('myplugin:topic'); +const { lastSignal } = useSignal('myplugin:channel'); + +useEffect(() => { + console.log(lastSignal); +}, [lastSignal]); ``` -Whenever backend publishes new message to the topic `myplugin:topic`, the lastSignal is changed. +Whenever backend publishes new message to the channel `myplugin:channel`, the `lastSignal` is changed. The `lastSignal` +is always initiated with null value before any messages are received from the backend. ## Using API directly @@ -37,7 +42,7 @@ import { signalsApiRef } from '@backstage/plugin-signals-react'; const signals = useApi(signalsApiRef); const { unsubscribe } = signals.subscribe( - 'myplugin:topic', + 'myplugin:channel', (message: JsonObject) => { console.log(message); }, diff --git a/plugins/signals-react/api-report.md b/plugins/signals-react/api-report.md index 8ad0c06fbe..2df2e4f1ce 100644 --- a/plugins/signals-react/api-report.md +++ b/plugins/signals-react/api-report.md @@ -9,7 +9,7 @@ import { JsonObject } from '@backstage/types'; // @public (undocumented) export type SignalApi = { subscribe( - topic: string, + channel: string, onMessage: (message: JsonObject) => void, ): { unsubscribe: () => void; @@ -20,7 +20,7 @@ export type SignalApi = { export const signalApiRef: ApiRef; // @public (undocumented) -export const useSignal: (topic: string) => { +export const useSignal: (channel: string) => { lastSignal: JsonObject | null; }; diff --git a/plugins/signals-react/src/api/SignalApi.ts b/plugins/signals-react/src/api/SignalApi.ts index 09eacafa4d..b37b3ae2f5 100644 --- a/plugins/signals-react/src/api/SignalApi.ts +++ b/plugins/signals-react/src/api/SignalApi.ts @@ -24,7 +24,7 @@ export const signalApiRef = createApiRef({ /** @public */ export type SignalApi = { subscribe( - topic: string, + channel: string, onMessage: (message: JsonObject) => void, ): { unsubscribe: () => void }; }; diff --git a/plugins/signals-react/src/hooks/useSignal.ts b/plugins/signals-react/src/hooks/useSignal.ts index 1176769a06..a7d50fbe3b 100644 --- a/plugins/signals-react/src/hooks/useSignal.ts +++ b/plugins/signals-react/src/hooks/useSignal.ts @@ -19,7 +19,7 @@ import { JsonObject } from '@backstage/types'; import { useEffect, useState } from 'react'; /** @public */ -export const useSignal = (topic: string) => { +export const useSignal = (channel: string) => { const apiHolder = useApiHolder(); // Use apiHolder instead useApi in case signalApi is not available in the // backstage instance this is used @@ -28,7 +28,7 @@ export const useSignal = (topic: string) => { useEffect(() => { let unsub: null | (() => void) = null; if (signals) { - const { unsubscribe } = signals.subscribe(topic, (msg: JsonObject) => { + const { unsubscribe } = signals.subscribe(channel, (msg: JsonObject) => { setLastSignal(msg); }); unsub = unsubscribe; @@ -38,7 +38,7 @@ export const useSignal = (topic: string) => { unsub(); } }; - }, [signals, topic]); + }, [signals, channel]); return { lastSignal }; }; diff --git a/plugins/signals/api-report.md b/plugins/signals/api-report.md index 97c882dda4..398d5fbfe6 100644 --- a/plugins/signals/api-report.md +++ b/plugins/signals/api-report.md @@ -24,7 +24,7 @@ export class SignalClient implements SignalApi { static readonly DEFAULT_RECONNECT_TIMEOUT_MS: number; // (undocumented) subscribe( - topic: string, + channel: string, onMessage: (message: JsonObject) => void, ): { unsubscribe: () => void; diff --git a/plugins/signals/src/api/SignalClient.ts b/plugins/signals/src/api/SignalClient.ts index 24a38a49e3..ee4ed8756b 100644 --- a/plugins/signals/src/api/SignalClient.ts +++ b/plugins/signals/src/api/SignalClient.ts @@ -19,7 +19,7 @@ import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; import { v4 as uuid } from 'uuid'; type Subscription = { - topic: string; + channel: string; callback: (message: JsonObject) => void; }; @@ -63,20 +63,23 @@ export class SignalClient implements SignalApi { ) {} subscribe( - topic: string, + channel: string, onMessage: (message: JsonObject) => void, ): { unsubscribe: () => void } { const subscriptionId = uuid(); const exists = [...this.subscriptions.values()].find( - sub => sub.topic === topic, + sub => sub.channel === channel, ); - this.subscriptions.set(subscriptionId, { topic, callback: onMessage }); + this.subscriptions.set(subscriptionId, { + channel: channel, + callback: onMessage, + }); this.connect() .then(() => { - // Do not subscribe twice to same topic even there is multiple callbacks + // Do not subscribe twice to same channel even there is multiple callbacks if (!exists) { - this.send({ action: 'subscribe', topic }); + this.send({ action: 'subscribe', channel }); } }) .catch(() => { @@ -90,12 +93,12 @@ export class SignalClient implements SignalApi { } this.subscriptions.delete(subscriptionId); const multipleExists = [...this.subscriptions.values()].find( - s => s.topic === topic, + s => s.channel === channel, ); - // If there are subscriptions still listening to this topic, do not + // If there are subscriptions still listening to this channel, do not // unsubscribe from the server if (!multipleExists) { - this.send({ action: 'unsubscribe', topic: sub.topic }); + this.send({ action: 'unsubscribe', channel: sub.channel }); } // If there are no subscriptions, close the connection @@ -176,9 +179,9 @@ export class SignalClient implements SignalApi { private handleMessage(data: MessageEvent) { try { const json = JSON.parse(data.data) as JsonObject; - if (json.topic) { + if (json.channel) { for (const sub of this.subscriptions.values()) { - if (sub.topic === json.topic) { + if (sub.channel === json.channel) { sub.callback(json.message as JsonObject); } } @@ -201,9 +204,9 @@ export class SignalClient implements SignalApi { this.ws = null; this.connect() .then(() => { - // Resubscribe to existing topics in case we lost connection + // Resubscribe to existing channels in case we lost connection for (const sub of this.subscriptions.values()) { - this.send({ action: 'subscribe', topic: sub.topic }); + this.send({ action: 'subscribe', channel: sub.channel }); } }) .catch(() => { diff --git a/plugins/signals/src/api/SignalsClient.test.ts b/plugins/signals/src/api/SignalsClient.test.ts index ec202e2703..2e93cd69f1 100644 --- a/plugins/signals/src/api/SignalsClient.test.ts +++ b/plugins/signals/src/api/SignalsClient.test.ts @@ -44,21 +44,21 @@ describe('SignalsClient', () => { it('should handle single subscription correctly', async () => { const messageMock = jest.fn(); const client = SignalClient.create({ discoveryApi, identity }); - const { unsubscribe } = client.subscribe('topic', messageMock); + const { unsubscribe } = client.subscribe('channel', messageMock); await server.connected; await expect(server).toReceiveMessage({ action: 'subscribe', - topic: 'topic', + channel: 'channel', }); - server.send({ topic: 'topic', message: { hello: 'world' } }); + server.send({ channel: 'channel', message: { hello: 'world' } }); expect(messageMock).toHaveBeenCalledWith({ hello: 'world' }); await unsubscribe(); await expect(server).toReceiveMessage({ action: 'unsubscribe', - topic: 'topic', + channel: 'channel', }); }); @@ -68,11 +68,11 @@ describe('SignalsClient', () => { const client1 = SignalClient.create({ discoveryApi, identity }); const client2 = SignalClient.create({ discoveryApi, identity }); const { unsubscribe: unsubscribe1 } = client1.subscribe( - 'topic', + 'channel', messageMock1, ); const { unsubscribe: unsubscribe2 } = client2.subscribe( - 'topic', + 'channel', messageMock2, ); @@ -80,22 +80,22 @@ describe('SignalsClient', () => { await expect(server).toReceiveMessage({ action: 'subscribe', - topic: 'topic', + channel: 'channel', }); - server.send({ topic: 'topic', message: { hello: 'world' } }); + server.send({ channel: 'channel', message: { hello: 'world' } }); expect(messageMock1).toHaveBeenCalledWith({ hello: 'world' }); expect(messageMock2).toHaveBeenCalledWith({ hello: 'world' }); await unsubscribe1(); await expect(server).not.toReceiveMessage({ action: 'unsubscribe', - topic: 'topic', + channel: 'channel', }); await unsubscribe2(); await expect(server).toReceiveMessage({ action: 'unsubscribe', - topic: 'topic', + channel: 'channel', }); }); @@ -108,11 +108,11 @@ describe('SignalsClient', () => { connectTimeout: 100, }); - client.subscribe('topic', messageMock); + client.subscribe('channel', messageMock); await server.connected; await expect(server).toReceiveMessage({ action: 'subscribe', - topic: 'topic', + channel: 'channel', }); await server.server.emit('error', null); @@ -120,7 +120,7 @@ describe('SignalsClient', () => { await new Promise(r => setTimeout(r, 50)); await expect(server).toReceiveMessage({ action: 'subscribe', - topic: 'topic', + channel: 'channel', }); }); }); From bb4089890b08acdfac308ccd1568d740b947160b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 10 Jan 2024 19:27:34 +0100 Subject: [PATCH 067/241] core-components: add test for ProxiedSignInPage Signed-off-by: Patrik Oldsberg --- .changeset/strange-parents-hammer.md | 5 + packages/core-components/package.json | 1 + .../ProxiedSignInPage.test.tsx | 103 ++++++++++++++++++ packages/test-utils/api-report.md | 2 + .../test-utils/src/testUtils/appWrappers.tsx | 7 ++ yarn.lock | 1 + 6 files changed, 119 insertions(+) create mode 100644 .changeset/strange-parents-hammer.md create mode 100644 packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx diff --git a/.changeset/strange-parents-hammer.md b/.changeset/strange-parents-hammer.md new file mode 100644 index 0000000000..57d5eeb83d --- /dev/null +++ b/.changeset/strange-parents-hammer.md @@ -0,0 +1,5 @@ +--- +'@backstage/test-utils': minor +--- + +Added `components` option to `TestAppOptions`, which will be forwarded as the `components` option to `createApp`. diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 25d7fe111c..4c635b184c 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -92,6 +92,7 @@ "react-router-dom": "6.0.0-beta.0 || ^6.3.0" }, "devDependencies": { + "@backstage/app-defaults": "workspace:^", "@backstage/cli": "workspace:^", "@backstage/core-app-api": "workspace:^", "@backstage/test-utils": "workspace:^", diff --git a/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx new file mode 100644 index 0000000000..3f0c01b56b --- /dev/null +++ b/packages/core-components/src/layout/ProxiedSignInPage/ProxiedSignInPage.test.tsx @@ -0,0 +1,103 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { + TestApiProvider, + setupRequestMockHandlers, + wrapInTestApp, +} from '@backstage/test-utils'; +import { ProxiedSignInPage } from './ProxiedSignInPage'; +import { discoveryApiRef } from '@backstage/core-plugin-api'; + +describe('ProxiedSignInPage', () => { + const worker = setupServer(); + setupRequestMockHandlers(worker); + + const Subject = wrapInTestApp(
authenticated
, { + components: { + SignInPage: props => ( + 'http://example.com/api/auth', + }, + ], + ]} + > + + + ), + }, + }); + + it('should sign in a user', async () => { + worker.use( + rest.get('http://example.com/api/auth/test/refresh', (_, res, ctx) => + res( + ctx.status(200), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + profile: { + email: 'e', + displayName: 'd', + picture: 'p', + }, + backstageIdentity: { + token: 'a.e30.c', + identity: { + type: 'user', + userEntityRef: 'k:ns/ue', + ownershipEntityRefs: ['k:ns/oe'], + }, + }, + }), + ), + ), + ); + + render(Subject); + + await expect( + screen.findByText('authenticated'), + ).resolves.toBeInTheDocument(); + }); + + it('should forward error', async () => { + worker.use( + rest.get('http://example.com/api/auth/test/refresh', (_, res, ctx) => + res( + ctx.status(401), + ctx.set('Content-Type', 'application/json'), + ctx.json({ + error: { name: 'Error', message: 'not-displayed' }, + }), + ), + ), + ); + + render(Subject); + + await expect( + screen.findByText('Request failed with 401 Error'), + ).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/test-utils/api-report.md b/packages/test-utils/api-report.md index 913413acd1..e31a820a1c 100644 --- a/packages/test-utils/api-report.md +++ b/packages/test-utils/api-report.md @@ -7,6 +7,7 @@ import { AnalyticsApi } from '@backstage/core-plugin-api'; import { AnalyticsEvent } from '@backstage/core-plugin-api'; import { ApiHolder } from '@backstage/core-plugin-api'; import { ApiRef } from '@backstage/core-plugin-api'; +import { AppComponents } from '@backstage/core-plugin-api'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { ComponentType } from 'react'; import { Config } from '@backstage/config'; @@ -243,6 +244,7 @@ export type TestAppOptions = { mountedRoutes?: { [path: string]: RouteRef | ExternalRouteRef; }; + components?: Partial; }; // @public diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index 8bc69e184a..f2c1ff592e 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -25,6 +25,7 @@ import { themes, UnifiedThemeProvider } from '@backstage/theme'; import MockIcon from '@material-ui/icons/AcUnit'; import { createSpecializedApp } from '@backstage/core-app-api'; import { + AppComponents, attachComponentData, BootErrorPageProps, createRouteRef, @@ -101,6 +102,11 @@ export type TestAppOptions = { * const link = useRouteRef(myRouteRef) */ mountedRoutes?: { [path: string]: RouteRef | ExternalRouteRef }; + + /** + * Components to be forwarded to the `components` option of `createApp`. + */ + components?: Partial; }; function isExternalRouteRef( @@ -137,6 +143,7 @@ export function createTestAppWrapper( Router: ({ children }) => ( ), + ...options.components, }, icons: mockIcons, plugins: [], diff --git a/yarn.lock b/yarn.lock index 6be53d3402..ba784c04d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3921,6 +3921,7 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: + "@backstage/app-defaults": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/core-app-api": "workspace:^" From 7e7319bcb00d4c6f9ce4ffffd2234727ad1e17c7 Mon Sep 17 00:00:00 2001 From: Daniel Laird Date: Fri, 12 Jan 2024 15:31:56 +0000 Subject: [PATCH 068/241] Ensure teamReviewer list contains unique team names before sending to API Signed-off-by: Daniel Laird --- .../src/actions/githubPullRequest.test.ts | 4 ++-- .../src/actions/githubPullRequest.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts index 23ac4bda45..c5b1038a01 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.test.ts @@ -377,7 +377,7 @@ describe('createPublishGithubPullRequestAction', () => { branchName: 'new-app', description: 'This PR is really good', reviewers: ['foobar'], - teamReviewers: ['team-foo'], + teamReviewers: ['team-foo', 'team-foo', 'team-bar'], }; mockDir.setContent({ [workspacePath]: {} }); @@ -401,7 +401,7 @@ describe('createPublishGithubPullRequestAction', () => { repo: 'myrepo', pull_number: 123, reviewers: ['foobar'], - team_reviewers: ['team-foo'], + team_reviewers: ['team-foo', 'team-bar'], }); }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts index 0763d4a474..2d8dc7ce8d 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPullRequest.ts @@ -372,7 +372,7 @@ export const createPublishGithubPullRequestAction = ( repo: pr.repo, pull_number: pr.number, reviewers, - team_reviewers: teamReviewers, + team_reviewers: teamReviewers ? [...new Set(teamReviewers)] : undefined, }); const addedUsers = result.data.requested_reviewers?.join(', ') ?? ''; const addedTeams = result.data.requested_teams?.join(', ') ?? ''; From 547030034df4d263a28fe423b3e7a9db2ddf9b38 Mon Sep 17 00:00:00 2001 From: Daniel Laird Date: Fri, 12 Jan 2024 15:33:29 +0000 Subject: [PATCH 069/241] Add Changeset Signed-off-by: Daniel Laird --- .changeset/fair-spies-rescue.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fair-spies-rescue.md diff --git a/.changeset/fair-spies-rescue.md b/.changeset/fair-spies-rescue.md new file mode 100644 index 0000000000..2b49d4b969 --- /dev/null +++ b/.changeset/fair-spies-rescue.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': minor +--- + +Ensure `teamReviewers` list is unique before calling API From 074dfe37b04c9c693d432082176642e0f7ed051b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jan 2024 17:11:34 +0100 Subject: [PATCH 070/241] frontend-app-api: switch undeclared inputs to be a warning instead of error Signed-off-by: Patrik Oldsberg --- .changeset/silver-countries-notice.md | 5 ++++ .../src/tree/instantiateAppNodeTree.test.ts | 24 +++++++++------ .../src/tree/instantiateAppNodeTree.ts | 30 +++++++++---------- 3 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 .changeset/silver-countries-notice.md diff --git a/.changeset/silver-countries-notice.md b/.changeset/silver-countries-notice.md new file mode 100644 index 0000000000..457042487b --- /dev/null +++ b/.changeset/silver-countries-notice.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': minor +--- + +Attaching extensions to an input that does not exist is now a warning rather than an error. diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts index 7855b87df2..ec8712cf59 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts @@ -30,6 +30,7 @@ import { AppNodeSpec } from '@backstage/frontend-plugin-api'; import { resolveAppTree } from './resolveAppTree'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; +import { withLogCollector } from '@backstage/test-utils'; const testDataRef = createExtensionDataRef('test'); const otherDataRef = createExtensionDataRef('other'); @@ -433,8 +434,8 @@ describe('createAppNodeInstance', () => { ); }); - it('should refuse to create an instance with undeclared inputs', () => { - expect(() => + it('should warn when creating an instance with undeclared inputs', () => { + const { warn } = withLogCollector(['warn'], () => createAppNodeInstance({ attachments: new Map([ [ @@ -458,7 +459,7 @@ describe('createAppNodeInstance', () => { resolveExtensionDefinition( createExtension({ namespace: 'app', - name: 'test', + name: 'parent', attachTo: { id: 'ignored', input: 'ignored' }, inputs: { declared: createExtensionInput({ @@ -471,13 +472,15 @@ describe('createAppNodeInstance', () => { ), ), }), - ).toThrow( - "Failed to instantiate extension 'app/test', received undeclared input 'undeclared' from extension 'app/test'", ); + + expect(warn).toEqual([ + "The extension 'app/test' is attached to the input 'undeclared' of 'app/parent', but the extension 'app/parent' noes not declare a 'undeclared' input", + ]); }); it('should refuse to create an instance with multiple undeclared inputs', () => { - expect(() => + const { warn } = withLogCollector(['warn'], () => createAppNodeInstance({ attachments: new Map([ [ @@ -496,7 +499,7 @@ describe('createAppNodeInstance', () => { resolveExtensionDefinition( createExtension({ namespace: 'app', - name: 'test', + name: 'parent', attachTo: { id: 'ignored', input: 'ignored' }, output: {}, factory: () => ({}), @@ -504,9 +507,12 @@ describe('createAppNodeInstance', () => { ), ), }), - ).toThrow( - "Failed to instantiate extension 'app/test', received undeclared inputs 'undeclared1' from extension 'app/test' and 'undeclared2' from extensions 'app/test', 'app/test'", ); + + expect(warn).toEqual([ + "The extension 'app/test' is attached to the input 'undeclared1' of 'app/parent', but the extension 'app/parent' noes not declare a 'undeclared1' input", + "The extensions 'app/test', 'app/test' are attached to the input 'undeclared2' of 'app/parent', but the extension 'app/parent' noes not declare a 'undeclared2' input", + ]); }); it('should refuse to create an instance with multiple inputs for required singleton', () => { diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts index f72fcdd0cb..b1fa9eae39 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts @@ -46,26 +46,26 @@ function resolveInputData( } function resolveInputs( + id: string, inputMap: AnyExtensionInputMap, attachments: ReadonlyMap, ): ResolvedExtensionInputs { const undeclaredAttachments = Array.from(attachments.entries()).filter( ([inputName]) => inputMap[inputName] === undefined, ); - // TODO: Make this a warning rather than an error - if (undeclaredAttachments.length > 0) { - throw new Error( - `received undeclared input${ - undeclaredAttachments.length > 1 ? 's' : '' - } ${undeclaredAttachments - .map( - ([k, exts]) => - `'${k}' from extension${exts.length > 1 ? 's' : ''} '${exts - .map(e => e.spec.id) - .join("', '")}'`, - ) - .join(' and ')}`, - ); + + if (process.env.NODE_ENV !== 'production') { + for (const [name, nodes] of undeclaredAttachments) { + const pl = nodes.length > 1; + // eslint-disable-next-line no-console + console.warn( + `The extension${pl ? 's' : ''} '${nodes + .map(n => n.spec.id) + .join("', '")}' ${ + pl ? 'are' : 'is' + } attached to the input '${name}' of '${id}', but the extension '${id}' noes not declare a '${name}' input`, + ); + } } return mapValues(inputMap, (input, inputName) => { @@ -129,7 +129,7 @@ export function createAppNodeInstance(options: { const namedOutputs = internalExtension.factory({ node, config: parsedConfig, - inputs: resolveInputs(internalExtension.inputs, attachments), + inputs: resolveInputs(id, internalExtension.inputs, attachments), }); for (const [name, output] of Object.entries(namedOutputs)) { From 4780af8e153de5686c61b3cda58da5c7b73d227f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jan 2024 17:49:22 +0100 Subject: [PATCH 071/241] frontend-app-api: list candidate inputs in undeclared input warning Signed-off-by: Patrik Oldsberg --- .../src/tree/instantiateAppNodeTree.test.ts | 6 +++--- .../src/tree/instantiateAppNodeTree.ts | 16 +++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts index ec8712cf59..766cb4804e 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.test.ts @@ -475,7 +475,7 @@ describe('createAppNodeInstance', () => { ); expect(warn).toEqual([ - "The extension 'app/test' is attached to the input 'undeclared' of 'app/parent', but the extension 'app/parent' noes not declare a 'undeclared' input", + "The extension 'app/test' is attached to the input 'undeclared' of the extension 'app/parent', but it has no such input (candidates are 'declared')", ]); }); @@ -510,8 +510,8 @@ describe('createAppNodeInstance', () => { ); expect(warn).toEqual([ - "The extension 'app/test' is attached to the input 'undeclared1' of 'app/parent', but the extension 'app/parent' noes not declare a 'undeclared1' input", - "The extensions 'app/test', 'app/test' are attached to the input 'undeclared2' of 'app/parent', but the extension 'app/parent' noes not declare a 'undeclared2' input", + "The extension 'app/test' is attached to the input 'undeclared1' of the extension 'app/parent', but it has no inputs", + "The extensions 'app/test', 'app/test' are attached to the input 'undeclared2' of the extension 'app/parent', but it has no inputs", ]); }); diff --git a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts index b1fa9eae39..90a256fea6 100644 --- a/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts +++ b/packages/frontend-app-api/src/tree/instantiateAppNodeTree.ts @@ -55,15 +55,21 @@ function resolveInputs( ); if (process.env.NODE_ENV !== 'production') { + const inputNames = Object.keys(inputMap); + for (const [name, nodes] of undeclaredAttachments) { const pl = nodes.length > 1; // eslint-disable-next-line no-console console.warn( - `The extension${pl ? 's' : ''} '${nodes - .map(n => n.spec.id) - .join("', '")}' ${ - pl ? 'are' : 'is' - } attached to the input '${name}' of '${id}', but the extension '${id}' noes not declare a '${name}' input`, + [ + `The extension${pl ? 's' : ''} '${nodes + .map(n => n.spec.id) + .join("', '")}' ${pl ? 'are' : 'is'}`, + `attached to the input '${name}' of the extension '${id}', but it`, + inputNames.length === 0 + ? 'has no inputs' + : `has no such input (candidates are '${inputNames.join("', '")}')`, + ].join(' '), ); } } From c3249d6c11569d086f199db65880f58592cdfb54 Mon Sep 17 00:00:00 2001 From: armandocomellas1 Date: Fri, 12 Jan 2024 11:31:19 -0600 Subject: [PATCH 072/241] Add code to handle URL Reader from GCS with wildcard \* Signed-off-by: armandocomellas1 --- .changeset/thirty-cats-help.md | 5 +++++ .../catalog-backend/src/modules/core/UrlReaderProcessor.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/thirty-cats-help.md diff --git a/.changeset/thirty-cats-help.md b/.changeset/thirty-cats-help.md new file mode 100644 index 0000000000..70ae78e3c1 --- /dev/null +++ b/.changeset/thirty-cats-help.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Change script in **UrlReaderProcessor.ts** Replacing the line code 127 'const { pathname: filepath } = new URL(location)' with to handle URL Reader from GCS with wildcard \* diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts index 5e31dcbd1a..c568f03a81 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.ts @@ -17,7 +17,6 @@ import { UrlReader } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; import { assertError } from '@backstage/errors'; -import parseGitUrl from 'git-url-parse'; import limiterFactory from 'p-limit'; import { Logger } from 'winston'; import { LocationSpec } from '@backstage/plugin-catalog-common'; @@ -124,7 +123,8 @@ export class UrlReaderProcessor implements CatalogProcessor { ): Promise<{ response: { data: Buffer; url: string }[]; etag?: string }> { // Does it contain globs? I.e. does it contain asterisks or question marks // (no curly braces for now) - const { filepath } = parseGitUrl(location); + + const { pathname: filepath } = new URL(location); if (filepath?.match(/[*?]/)) { const limiter = limiterFactory(5); const response = await this.options.reader.search(location, { etag }); From 41b25258bff4869bf6394d7cf353764e1cf7d558 Mon Sep 17 00:00:00 2001 From: armandocomellas1 Date: Fri, 12 Jan 2024 11:36:42 -0600 Subject: [PATCH 073/241] Fixing the linter error with the naming the variable inside the changeset thirty-cats-help.md Signed-off-by: armandocomellas1 --- .changeset/thirty-cats-help.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/thirty-cats-help.md b/.changeset/thirty-cats-help.md index 70ae78e3c1..107fb7584b 100644 --- a/.changeset/thirty-cats-help.md +++ b/.changeset/thirty-cats-help.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend': patch --- -Change script in **UrlReaderProcessor.ts** Replacing the line code 127 'const { pathname: filepath } = new URL(location)' with to handle URL Reader from GCS with wildcard \* +Change script in **UrlReaderProcessor.ts** Replacing the line code 127 **const { pathname: filepath } = new URL(location)** with to handle URL Reader from GCS with wildcard \* From 1de52a9c60d6ba373a8c9f1b2cbb05f198f957fa Mon Sep 17 00:00:00 2001 From: armandocomellas1 Date: Fri, 12 Jan 2024 11:40:45 -0600 Subject: [PATCH 074/241] Fixing the linter error with the naming the variable inside the changeset thirty-cats-help.md Signed-off-by: armandocomellas1 --- .changeset/thirty-cats-help.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/thirty-cats-help.md b/.changeset/thirty-cats-help.md index 107fb7584b..bb6011ca9c 100644 --- a/.changeset/thirty-cats-help.md +++ b/.changeset/thirty-cats-help.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend': patch --- -Change script in **UrlReaderProcessor.ts** Replacing the line code 127 **const { pathname: filepath } = new URL(location)** with to handle URL Reader from GCS with wildcard \* +Change script in **UrlReaderProcessor.ts** Replacing the line code 127 with method (new URL) to handle URL Reader from GCS with wildcard \* From b6b11677582ffe03c5df05b8e9130d2e2c62d96b Mon Sep 17 00:00:00 2001 From: secustor Date: Fri, 12 Jan 2024 20:05:19 +0100 Subject: [PATCH 075/241] chore: revert exposing of fetchResponse Signed-off-by: secustor --- packages/backend-common/src/reading/GithubUrlReader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-common/src/reading/GithubUrlReader.ts b/packages/backend-common/src/reading/GithubUrlReader.ts index 6fd24afc08..67f6a975c1 100644 --- a/packages/backend-common/src/reading/GithubUrlReader.ts +++ b/packages/backend-common/src/reading/GithubUrlReader.ts @@ -312,7 +312,7 @@ export class GithubUrlReader implements UrlReader { return repo.default_branch; } - protected async fetchResponse( + private async fetchResponse( url: string | URL, init: RequestInit, ): Promise { From c97fa1c2bd3bae393f96054f25e8450ab1be4a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 11 Jan 2024 13:56:58 +0100 Subject: [PATCH 076/241] add elements and wrappers to the app root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/silent-horses-raise.md | 7 ++ .../src/extensions/AppRoot.tsx | 40 ++++-- packages/frontend-plugin-api/api-report.md | 56 +++++++++ .../createAppRootElementExtension.test.tsx | 107 ++++++++++++++++ .../createAppRootElementExtension.ts | 71 +++++++++++ .../createAppRootWrapperExtension.test.tsx | 119 ++++++++++++++++++ .../createAppRootWrapperExtension.tsx | 84 +++++++++++++ .../src/extensions/index.ts | 2 + .../src/app/createExtensionTester.tsx | 49 ++++++-- 9 files changed, 514 insertions(+), 21 deletions(-) create mode 100644 .changeset/silent-horses-raise.md create mode 100644 packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx create mode 100644 packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts create mode 100644 packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx create mode 100644 packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx diff --git a/.changeset/silent-horses-raise.md b/.changeset/silent-horses-raise.md new file mode 100644 index 0000000000..de2671c3da --- /dev/null +++ b/.changeset/silent-horses-raise.md @@ -0,0 +1,7 @@ +--- +'@backstage/frontend-plugin-api': patch +'@backstage/frontend-test-utils': patch +'@backstage/frontend-app-api': patch +--- + +Added `elements` and `wrappers` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension` and `createAppRootWrapperExtension` extension creator, respectively, to conveniently create such extensions. diff --git a/packages/frontend-app-api/src/extensions/AppRoot.tsx b/packages/frontend-app-api/src/extensions/AppRoot.tsx index 0894287541..b442533ee6 100644 --- a/packages/frontend-app-api/src/extensions/AppRoot.tsx +++ b/packages/frontend-app-api/src/extensions/AppRoot.tsx @@ -14,9 +14,16 @@ * limitations under the License. */ -import React, { ComponentType, ReactNode, useContext, useState } from 'react'; +import React, { + ComponentType, + Fragment, + ReactNode, + useContext, + useState, +} from 'react'; import { coreExtensionData, + createAppRootWrapperExtension, createExtension, createExtensionInput, createSignInPageExtension, @@ -40,26 +47,43 @@ export const AppRoot = createExtension({ attachTo: { id: 'app', input: 'root' }, inputs: { signInPage: createExtensionInput( - { - component: createSignInPageExtension.componentDataRef, - }, + { component: createSignInPageExtension.componentDataRef }, { singleton: true, optional: true }, ), children: createExtensionInput( - { - element: coreExtensionData.reactElement, - }, + { element: coreExtensionData.reactElement }, { singleton: true }, ), + elements: createExtensionInput( + { element: coreExtensionData.reactElement }, + { optional: true }, + ), + wrappers: createExtensionInput( + { component: createAppRootWrapperExtension.componentDataRef }, + { optional: true }, + ), }, output: { element: coreExtensionData.reactElement, }, factory({ inputs }) { + let content: React.ReactNode = ( + <> + {inputs.elements.map(el => ( + {el.output.element} + ))} + {inputs.children.output.element} + + ); + + for (const wrapper of inputs.wrappers) { + content = {content}; + } + return { element: ( - {inputs.children.output.element} + {content} ), }; diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 2260db334f..6113c946ee 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -67,6 +67,7 @@ import { OpenIdConnectApi } from '@backstage/core-plugin-api'; import { PendingOAuthRequest } from '@backstage/core-plugin-api'; import { ProfileInfo } from '@backstage/core-plugin-api'; import { ProfileInfoApi } from '@backstage/core-plugin-api'; +import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReactNode } from 'react'; import { SessionApi } from '@backstage/core-plugin-api'; @@ -390,6 +391,61 @@ export { createApiFactory }; export { createApiRef }; +// @public +export function createAppRootElementExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + element: + | JSX_2.Element + | ((options: { + inputs: Expand>; + config: TConfig; + }) => JSX_2.Element); +}): ExtensionDefinition; + +// @public +export function createAppRootWrapperExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createAppRootWrapperExtension { + const // (undocumented) + componentDataRef: ConfigurableExtensionDataRef< + React_2.ComponentType<{ + children?: React_2.ReactNode; + }>, + {} + >; +} + // @public (undocumented) export function createComponentExtension< TProps extends {}, diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx new file mode 100644 index 0000000000..c8bf6ee355 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.test.tsx @@ -0,0 +1,107 @@ +/* + * Copyright 2023 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 { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import React from 'react'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { createExtension } from '../wiring/createExtension'; +import { createExtensionInput } from '../wiring/createExtensionInput'; +import { createAppRootElementExtension } from './createAppRootElementExtension'; + +describe('createAppRootElementExtension', () => { + it('works with simple options and just an element', async () => { + const extension = createAppRootElementExtension({ + element:
Hello
, + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-element', + attachTo: { id: 'app/root', input: 'elements' }, + disabled: false, + inputs: {}, + output: { + element: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester(extension).render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + }); + + it('works with complex options and a callback', async () => { + const schema = createSchemaFromZod(z => z.object({ name: z.string() })); + + const extension = createAppRootElementExtension({ + namespace: 'ns', + name: 'test', + configSchema: schema, + attachTo: { id: 'other', input: 'slot' }, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + element: ({ inputs, config }) => ( +
+ Hello, {config.name}, {inputs.children.length} +
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-root-element', + namespace: 'ns', + name: 'test', + attachTo: { id: 'other', input: 'slot' }, + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + element: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester(extension, { config: { name: 'Robin' } }) + .add( + createExtension({ + attachTo: { id: 'app-root-element:ns/test', input: 'children' }, + output: { element: coreExtensionData.reactElement }, + factory: () => ({ element:
}), + }), + ) + .render(); + + await expect( + screen.findByText('Hello, Robin, 1'), + ).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts new file mode 100644 index 0000000000..8be82d5540 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootElementExtension.ts @@ -0,0 +1,71 @@ +/* + * Copyright 2023 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 { JSX } from 'react'; +import { PortableSchema } from '../schema/types'; +import { Expand } from '../types'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { + AnyExtensionInputMap, + ExtensionDefinition, + ResolvedExtensionInputs, + createExtension, +} from '../wiring/createExtension'; + +/** + * Creates an extension that renders a React element at the app root, outside of + * the app layout. This is useful for example for shared popups and similar. + * + * @public + */ +export function createAppRootElementExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + element: + | JSX.Element + | ((options: { + inputs: Expand>; + config: TConfig; + }) => JSX.Element); +}): ExtensionDefinition { + return createExtension({ + kind: 'app-root-element', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'elements' }, + configSchema: options.configSchema, + disabled: options.disabled, + inputs: options.inputs, + output: { + element: coreExtensionData.reactElement, + }, + factory({ inputs, config }) { + return { + element: + typeof options.element === 'function' + ? options.element({ inputs, config }) + : options.element, + }; + }, + }); +} diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx new file mode 100644 index 0000000000..a0625ec1ae --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx @@ -0,0 +1,119 @@ +/* + * Copyright 2023 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 { createExtensionTester } from '@backstage/frontend-test-utils'; +import { screen } from '@testing-library/react'; +import React from 'react'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { createExtension } from '../wiring/createExtension'; +import { createExtensionInput } from '../wiring/createExtensionInput'; +import { createAppRootWrapperExtension } from './createAppRootWrapperExtension'; +import { createPageExtension } from './createPageExtension'; + +describe('createAppRootWrapperExtension', () => { + it('works with simple options and no props', async () => { + const extension = createAppRootWrapperExtension({ + Component: () =>
Hello
, + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-wrapper-component', + attachTo: { id: 'app/root', input: 'wrappers' }, + disabled: false, + inputs: {}, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester( + createPageExtension({ + defaultPath: '/', + loader: async () =>
, + }), + ) + .add(extension) + .render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + }); + + it('works with complex options and props', async () => { + const schema = createSchemaFromZod(z => z.object({ name: z.string() })); + + const extension = createAppRootWrapperExtension({ + namespace: 'ns', + name: 'test', + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + Component: ({ inputs, config, children }) => ( +
+ {children} +
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-wrapper-component', + namespace: 'ns', + name: 'test', + attachTo: { id: 'app/root', input: 'wrappers' }, + configSchema: schema, + disabled: true, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + createExtensionTester( + createPageExtension({ + defaultPath: '/', + loader: async () =>
Hello
, + }), + ) + .add(extension, { config: { name: 'Robin' } }) + .add( + createExtension({ + attachTo: { id: 'app-wrapper-component:ns/test', input: 'children' }, + output: { element: coreExtensionData.reactElement }, + factory: () => ({ element:
}), + }), + ) + .render(); + + await expect(screen.findByText('Hello')).resolves.toBeInTheDocument(); + await expect(screen.findByTestId('Robin-1')).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx new file mode 100644 index 0000000000..1f09b873cc --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2023 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, { ComponentType, PropsWithChildren } from 'react'; +import { PortableSchema } from '../schema/types'; +import { + AnyExtensionInputMap, + ExtensionDefinition, + ResolvedExtensionInputs, + createExtension, +} from '../wiring/createExtension'; +import { createExtensionDataRef } from '../wiring/createExtensionDataRef'; +import { Expand } from '../types'; + +/** + * Creates an extension that renders a React wrapper at the app root, enclosing + * the app layout. This is useful for example for adding global React contexts + * and similar. + * + * @public + */ +export function createAppRootWrapperExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition { + return createExtension({ + kind: 'app-wrapper-component', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'wrappers' }, + configSchema: options.configSchema, + disabled: options.disabled, + inputs: options.inputs, + output: { + component: createAppRootWrapperExtension.componentDataRef, + }, + factory({ inputs, config }) { + const Component = (props: PropsWithChildren<{}>) => { + return ( + + {props.children} + + ); + }; + return { + component: Component, + }; + }, + }); +} + +/** @public */ +export namespace createAppRootWrapperExtension { + export const componentDataRef = + createExtensionDataRef>>( + 'app.root.wrapper', + ); +} diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index fd2e38de49..40e9f6f56d 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -15,6 +15,8 @@ */ export { createApiExtension } from './createApiExtension'; +export { createAppRootElementExtension } from './createAppRootElementExtension'; +export { createAppRootWrapperExtension } from './createAppRootWrapperExtension'; export { createPageExtension } from './createPageExtension'; export { createNavItemExtension } from './createNavItemExtension'; export { createNavLogoExtension } from './createNavLogoExtension'; diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.tsx index 1a4ebbac48..2984af9dbf 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.tsx @@ -14,7 +14,13 @@ * limitations under the License. */ -import React, { ComponentType, ReactNode, useContext, useState } from 'react'; +import React, { + ComponentType, + Fragment, + ReactNode, + useContext, + useState, +} from 'react'; import { MemoryRouter, Link } from 'react-router-dom'; import { RenderResult, render } from '@testing-library/react'; import { createSpecializedApp } from '@backstage/frontend-app-api'; @@ -25,6 +31,7 @@ import { RouteRef, configApiRef, coreExtensionData, + createAppRootWrapperExtension, createExtension, createExtensionInput, createExtensionOverrides, @@ -63,7 +70,7 @@ const NavItem = (props: { ); }; -const TestCoreNavExtension = createExtension({ +const TestAppNavExtension = createExtension({ namespace: 'app', name: 'nav', attachTo: { id: 'app/layout', input: 'nav' }, @@ -149,36 +156,52 @@ const AuthenticationProvider = (props: { return children; }; -const TestCoreRouterExtension = createExtension({ +const TestAppRootExtension = createExtension({ namespace: 'app', name: 'root', attachTo: { id: 'app', input: 'root' }, inputs: { signInPage: createExtensionInput( - { - component: createSignInPageExtension.componentDataRef, - }, + { component: createSignInPageExtension.componentDataRef }, { singleton: true, optional: true }, ), children: createExtensionInput( - { - element: coreExtensionData.reactElement, - }, + { element: coreExtensionData.reactElement }, { singleton: true }, ), + elements: createExtensionInput( + { element: coreExtensionData.reactElement }, + { optional: true }, + ), + wrappers: createExtensionInput( + { component: createAppRootWrapperExtension.componentDataRef }, + { optional: true }, + ), }, output: { element: coreExtensionData.reactElement, }, factory({ inputs }) { const SignInPage = inputs.signInPage?.output.component; - const children = inputs.children.output.element; + + let content: React.ReactNode = ( + <> + {inputs.elements.map(el => ( + {el.output.element} + ))} + {inputs.children.output.element} + + ); + + for (const wrapper of inputs.wrappers) { + content = {content}; + } return { element: ( - {children} + {content} ), @@ -278,8 +301,8 @@ export class ExtensionTester { createExtensionOverrides({ extensions: [ ...this.#extensions.map(extension => extension.definition), - TestCoreNavExtension, - TestCoreRouterExtension, + TestAppNavExtension, + TestAppRootExtension, ], }), ], From 26d01106783c9d6b9ba93deb1716f7ad2051fdce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 12 Jan 2024 21:58:38 +0100 Subject: [PATCH 077/241] review comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../frontend-app-api/src/extensions/AppRoot.tsx | 14 ++++++-------- .../createAppRootWrapperExtension.test.tsx | 6 +++--- .../extensions/createAppRootWrapperExtension.tsx | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/frontend-app-api/src/extensions/AppRoot.tsx b/packages/frontend-app-api/src/extensions/AppRoot.tsx index b442533ee6..883074ca00 100644 --- a/packages/frontend-app-api/src/extensions/AppRoot.tsx +++ b/packages/frontend-app-api/src/extensions/AppRoot.tsx @@ -54,14 +54,12 @@ export const AppRoot = createExtension({ { element: coreExtensionData.reactElement }, { singleton: true }, ), - elements: createExtensionInput( - { element: coreExtensionData.reactElement }, - { optional: true }, - ), - wrappers: createExtensionInput( - { component: createAppRootWrapperExtension.componentDataRef }, - { optional: true }, - ), + elements: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + wrappers: createExtensionInput({ + component: createAppRootWrapperExtension.componentDataRef, + }), }, output: { element: coreExtensionData.reactElement, diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx index a0625ec1ae..d21cfa7583 100644 --- a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.test.tsx @@ -33,7 +33,7 @@ describe('createAppRootWrapperExtension', () => { expect(extension).toEqual({ $$type: '@backstage/ExtensionDefinition', version: 'v1', - kind: 'app-wrapper-component', + kind: 'app-root-wrapper', attachTo: { id: 'app/root', input: 'wrappers' }, disabled: false, inputs: {}, @@ -79,7 +79,7 @@ describe('createAppRootWrapperExtension', () => { expect(extension).toEqual({ $$type: '@backstage/ExtensionDefinition', version: 'v1', - kind: 'app-wrapper-component', + kind: 'app-root-wrapper', namespace: 'ns', name: 'test', attachTo: { id: 'app/root', input: 'wrappers' }, @@ -106,7 +106,7 @@ describe('createAppRootWrapperExtension', () => { .add(extension, { config: { name: 'Robin' } }) .add( createExtension({ - attachTo: { id: 'app-wrapper-component:ns/test', input: 'children' }, + attachTo: { id: 'app-root-wrapper:ns/test', input: 'children' }, output: { element: coreExtensionData.reactElement }, factory: () => ({ element:
}), }), diff --git a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx index 1f09b873cc..bbc51806af 100644 --- a/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx +++ b/packages/frontend-plugin-api/src/extensions/createAppRootWrapperExtension.tsx @@ -50,7 +50,7 @@ export function createAppRootWrapperExtension< >; }): ExtensionDefinition { return createExtension({ - kind: 'app-wrapper-component', + kind: 'app-root-wrapper', namespace: options.namespace, name: options.name, attachTo: options.attachTo ?? { id: 'app/root', input: 'wrappers' }, From b5f6a1dd00150ff2270464abd434ce6345be7469 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Fri, 12 Jan 2024 17:03:38 -0500 Subject: [PATCH 078/241] document catalog cluster locator method and arrange the cluster locator method subsections in alphabetical order. Signed-off-by: Jamie Klassen --- docs/features/kubernetes/configuration.md | 59 +++++++++++++++++++++-- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 494e51320a..2b43d199b6 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -65,20 +65,63 @@ This is an array used to determine where to retrieve cluster configuration from. Valid cluster locator methods are: - [`catalog`](#catalog) -- [`localKubectlProxy`](#localkubectlproxy) - [`config`](#config) - [`gke`](#gke) +- [`localKubectlProxy`](#localkubectlproxy) - [custom `KubernetesClustersSupplier`](#custom-kubernetesclusterssupplier) #### `catalog` -This cluster locator method will read cluster information from the catalog. +This cluster locator method will gather +[Resources](https://backstage.io/docs/features/software-catalog/system-model#resource) +of +[type](https://backstage.io/docs/features/software-catalog/descriptor-format#spectype-required-4) +`kubernetes-cluster` from the catalog and treat them as clusters for the +purposes of the Kubernetes plugin. In order for a resource to be detected by +this method, it must also have the following +[annotations](https://backstage.io/docs/features/software-catalog/descriptor-format#annotations-optional) +(as seen +[here](https://github.com/backstage/backstage/blob/86baccb2d7d378baed74eaebf017c60b410986e5/plugins/kubernetes-backend/src/cluster-locator/CatalogClusterLocator.ts#L51-L61) +in the code): -#### `localKubectlProxy` +- [`kubernetes.io/api-server`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_api_server/), + denoting the base URL of the Kubernetes control plane +- [`kubernetes.io/api-server-certificate-authority`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_api_server_ca/), + containing a base64-encoded certificate authority bundle in PEM format; + Backstage will check that the control plane presents a certificate signed by + this authority. +- [`kubernetes.io/auth-provider`](https://backstage.io/docs/reference/plugin-kubernetes-common.annotation_kubernetes_auth_provider/), + denoting the strategy to use to authenticate with the control plane. -This cluster locator method will assume a locally running [`kubectl proxy`](https://kubernetes.io/docs/tasks/extend-kubernetes/http-proxy-access-api/#using-kubectl-to-start-a-proxy-server) process using the default port (8001). +There are many other annotations that can be applied to a cluster resource to +configure the way Backstage communicates, documented +[here](https://backstage.io/docs/reference/plugin-kubernetes-common#variables) +in the API reference. Here is a YAML snippet illustrating an example of a +cluster in the catalog: -NOTE: This cluster locator method is for local development only and should not be used in production. +```yaml +apiVersion: backstage.io/v1alpha1 +kind: Resource +metadata: + name: my-cluster + annotations: + kubernetes.io/api-server: 'https://127.0.0.1:53725' + kubernetes.io/api-server-certificate-authority: # base64-encoded CA + kubernetes.io/auth-provider: 'oidc' + kubernetes.io/oidc-token-provider: 'microsoft' + kubernetes.io/skip-metrics-lookup: 'true' +spec: + type: kubernetes-cluster + owner: user:guest +``` + +Note that it is insecure to store a Kubernetes service account token in an +annotation on a catalog entity (where it could easily be accidentally revealed +by the catalog API) -- therefore there is no annotation corresponding to the +[`serviceAccountToken` field](#clustersserviceaccounttoken-optional) used by +the [`config`](#config) cluster locator. Accordingly, the catalog cluster +locator does not support the [`serviceAccount`](#clustersauthprovider) auth +strategy. #### `config` @@ -388,6 +431,12 @@ Defaults to `false`. Array of key value labels used to filter out clusters which don't have the matching [resource labels](https://cloud.google.com/resource-manager/docs/creating-managing-labels). +#### `localKubectlProxy` + +This cluster locator method will assume a locally running [`kubectl proxy`](https://kubernetes.io/docs/tasks/extend-kubernetes/http-proxy-access-api/#using-kubectl-to-start-a-proxy-server) process using the default port (8001). + +NOTE: This cluster locator method is for local development only and should not be used in production. + #### Custom `KubernetesClustersSupplier` If the configuration-based cluster locators do not work for your use-case, From 4ef6f1bde6c33af863cd35fc97407e4dfecbbb6d Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Fri, 12 Jan 2024 18:09:14 -0500 Subject: [PATCH 079/241] mention ingestion procedure synergy Signed-off-by: Jamie Klassen --- docs/features/kubernetes/configuration.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 2b43d199b6..612d57334d 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -123,6 +123,15 @@ the [`config`](#config) cluster locator. Accordingly, the catalog cluster locator does not support the [`serviceAccount`](#clustersauthprovider) auth strategy. +This method can be quite helpful when used in combination with an ingestion +procedure like the +[`GkeEntityProvider`](https://backstage.io/docs/reference/plugin-catalog-backend-module-gcp.gkeentityprovider/) +(installation documented +[here](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend-module-gcp#installation)) +or the +[`AwsEKSClusterProcessor`](https://backstage.io/docs/reference/plugin-catalog-backend-module-aws.awseksclusterprocessor/) +to automatically update the set of clusters tracked by Backstage. + #### `config` This cluster locator method will read cluster information from your app-config From e8ce05959e30c1e1028b15d429546741c65fa854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 12 Jan 2024 13:58:56 +0100 Subject: [PATCH 080/241] add router to the app root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/silent-horses-raise.md | 2 +- .../src/extensions/AppRoot.tsx | 33 +++- packages/frontend-plugin-api/api-report.md | 33 ++++ packages/frontend-plugin-api/package.json | 32 ++-- .../extensions/createRouterExtension.test.tsx | 167 ++++++++++++++++++ .../src/extensions/createRouterExtension.tsx | 84 +++++++++ .../src/extensions/index.ts | 1 + .../src/app/createExtensionTester.test.tsx | 12 +- .../src/app/createExtensionTester.tsx | 135 +------------- .../src/app/renderInTestApp.test.tsx | 12 +- 10 files changed, 352 insertions(+), 159 deletions(-) create mode 100644 packages/frontend-plugin-api/src/extensions/createRouterExtension.test.tsx create mode 100644 packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx diff --git a/.changeset/silent-horses-raise.md b/.changeset/silent-horses-raise.md index de2671c3da..a03d662b03 100644 --- a/.changeset/silent-horses-raise.md +++ b/.changeset/silent-horses-raise.md @@ -4,4 +4,4 @@ '@backstage/frontend-app-api': patch --- -Added `elements` and `wrappers` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension` and `createAppRootWrapperExtension` extension creator, respectively, to conveniently create such extensions. +Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). diff --git a/packages/frontend-app-api/src/extensions/AppRoot.tsx b/packages/frontend-app-api/src/extensions/AppRoot.tsx index 883074ca00..2b709f4e42 100644 --- a/packages/frontend-app-api/src/extensions/AppRoot.tsx +++ b/packages/frontend-app-api/src/extensions/AppRoot.tsx @@ -17,6 +17,7 @@ import React, { ComponentType, Fragment, + PropsWithChildren, ReactNode, useContext, useState, @@ -26,6 +27,7 @@ import { createAppRootWrapperExtension, createExtension, createExtensionInput, + createRouterExtension, createSignInPageExtension, } from '@backstage/frontend-plugin-api'; import { @@ -46,6 +48,10 @@ export const AppRoot = createExtension({ name: 'root', attachTo: { id: 'app', input: 'root' }, inputs: { + router: createExtensionInput( + { component: createRouterExtension.componentDataRef }, + { singleton: true, optional: true }, + ), signInPage: createExtensionInput( { component: createSignInPageExtension.componentDataRef }, { singleton: true, optional: true }, @@ -80,7 +86,10 @@ export const AppRoot = createExtension({ return { element: ( - + {content} ), @@ -133,12 +142,18 @@ function SignInPageWrapper({ export interface AppRouterProps { children?: ReactNode; SignInPageComponent?: ComponentType; + RouterComponent?: ComponentType>; +} + +function DefaultRouter(props: PropsWithChildren<{}>) { + const configApi = useApi(configApiRef); + const basePath = getBasePath(configApi); + return {props.children}; } /** * App router and sign-in page wrapper. * - * @public * @remarks * * The AppRouter provides the routing context and renders the sign-in page. @@ -147,7 +162,11 @@ export interface AppRouterProps { * the app, while providing routing and route tracking for the app. */ export function AppRouter(props: AppRouterProps) { - const { children, SignInPageComponent } = props; + const { + children, + SignInPageComponent, + RouterComponent = DefaultRouter, + } = props; const configApi = useApi(configApiRef); const basePath = getBasePath(configApi); @@ -183,15 +202,15 @@ export function AppRouter(props: AppRouterProps) { ); return ( - + {children} - + ); } return ( - + {children} - + ); } diff --git a/packages/frontend-plugin-api/api-report.md b/packages/frontend-plugin-api/api-report.md index 6113c946ee..1d42d8bab8 100644 --- a/packages/frontend-plugin-api/api-report.md +++ b/packages/frontend-plugin-api/api-report.md @@ -687,6 +687,39 @@ export function createRouteRef< } >; +// @public +export function createRouterExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { + id: string; + input: string; + }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition; + +// @public (undocumented) +export namespace createRouterExtension { + const // (undocumented) + componentDataRef: ConfigurableExtensionDataRef< + React_2.ComponentType<{ + children?: React_2.ReactNode; + }>, + {} + >; +} + // @public (undocumented) export function createSchemaFromZod( schemaCreator: (zImpl: typeof z) => ZodSchema, diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index 4722cd1bff..007d76764b 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -22,6 +22,21 @@ "prepack": "backstage-cli package prepack", "postpack": "backstage-cli package postpack" }, + "dependencies": { + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/types": "workspace:^", + "@backstage/version-bridge": "workspace:^", + "@material-ui/core": "^4.12.4", + "@types/react": "^16.13.1 || ^17.0.0", + "lodash": "^4.17.21", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.21.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/frontend-app-api": "workspace:^", @@ -33,20 +48,5 @@ }, "files": [ "dist" - ], - "peerDependencies": { - "react": "^16.13.1 || ^17.0.0 || ^18.0.0", - "react-router-dom": "6.0.0-beta.0 || ^6.3.0" - }, - "dependencies": { - "@backstage/core-components": "workspace:^", - "@backstage/core-plugin-api": "workspace:^", - "@backstage/types": "workspace:^", - "@backstage/version-bridge": "workspace:^", - "@material-ui/core": "^4.12.4", - "@types/react": "^16.13.1 || ^17.0.0", - "lodash": "^4.17.21", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.21.4" - } + ] } diff --git a/packages/frontend-plugin-api/src/extensions/createRouterExtension.test.tsx b/packages/frontend-plugin-api/src/extensions/createRouterExtension.test.tsx new file mode 100644 index 0000000000..7109e1a8aa --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createRouterExtension.test.tsx @@ -0,0 +1,167 @@ +/* + * Copyright 2023 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 { createSpecializedApp } from '@backstage/frontend-app-api'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { MockConfigApi } from '@backstage/test-utils'; +import { MemoryRouter } from 'react-router-dom'; +import { createSchemaFromZod } from '../schema/createSchemaFromZod'; +import { coreExtensionData } from '../wiring/coreExtensionData'; +import { createExtension } from '../wiring/createExtension'; +import { createExtensionInput } from '../wiring/createExtensionInput'; +import { createExtensionOverrides } from '../wiring/createExtensionOverrides'; +import { createPageExtension } from './createPageExtension'; +import { createRouterExtension } from './createRouterExtension'; + +describe('createRouterExtension', () => { + it('works with simple options and no props', async () => { + const extension = createRouterExtension({ + namespace: 'test', + Component: ({ children }) => ( + +
{children}
+
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-router-component', + namespace: 'test', + attachTo: { id: 'app/root', input: 'router' }, + disabled: false, + inputs: {}, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + const app = createSpecializedApp({ + features: [ + createExtensionOverrides({ + extensions: [ + extension, + createPageExtension({ + namespace: 'test', + defaultPath: '/', + loader: async () =>
, + }), + ], + }), + ], + }); + + render(app.createRoot()); + + await expect( + screen.findByTestId('test-contents'), + ).resolves.toBeInTheDocument(); + await expect( + screen.findByTestId('test-router'), + ).resolves.toBeInTheDocument(); + }); + + it('works with complex options and props', async () => { + const schema = createSchemaFromZod(z => z.object({ name: z.string() })); + + const extension = createRouterExtension({ + namespace: 'test', + name: 'test', + configSchema: schema, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + Component: ({ inputs, config, children }) => ( + +
+ {children} +
+
+ ), + }); + + expect(extension).toEqual({ + $$type: '@backstage/ExtensionDefinition', + version: 'v1', + kind: 'app-router-component', + namespace: 'test', + name: 'test', + attachTo: { id: 'app/root', input: 'router' }, + configSchema: schema, + disabled: false, + inputs: { + children: createExtensionInput({ + element: coreExtensionData.reactElement, + }), + }, + output: { + component: expect.anything(), + }, + factory: expect.any(Function), + toString: expect.any(Function), + }); + + const app = createSpecializedApp({ + features: [ + createExtensionOverrides({ + extensions: [ + extension, + createExtension({ + namespace: 'test', + attachTo: { + id: 'app-router-component:test/test', + input: 'children', + }, + output: { element: coreExtensionData.reactElement }, // doesn't matter + factory: () => ({ element:
}), + }), + createPageExtension({ + namespace: 'test', + defaultPath: '/', + loader: async () =>
, + }), + ], + }), + ], + config: new MockConfigApi({ + app: { + extensions: [ + { + 'app-router-component:test/test': { config: { name: 'Robin' } }, + }, + ], + }, + }), + }); + + render(app.createRoot()); + + await expect( + screen.findByTestId('test-contents'), + ).resolves.toBeInTheDocument(); + await expect( + screen.findByTestId('test-router-Robin-1'), + ).resolves.toBeInTheDocument(); + }); +}); diff --git a/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx b/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx new file mode 100644 index 0000000000..32d61f7e60 --- /dev/null +++ b/packages/frontend-plugin-api/src/extensions/createRouterExtension.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2023 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, { ComponentType, PropsWithChildren } from 'react'; +import { PortableSchema } from '../schema/types'; +import { + AnyExtensionInputMap, + ExtensionDefinition, + ResolvedExtensionInputs, + createExtension, +} from '../wiring/createExtension'; +import { createExtensionDataRef } from '../wiring/createExtensionDataRef'; +import { Expand } from '../types'; + +/** + * Creates an extension that replaces the router implementation at the app root. + * This is useful to be able to for example replace the BrowserRouter with a + * MemoryRouter in tests, or to add additional props to a BrowserRouter. + * + * @public + */ +export function createRouterExtension< + TConfig extends {}, + TInputs extends AnyExtensionInputMap, +>(options: { + namespace?: string; + name?: string; + attachTo?: { id: string; input: string }; + configSchema?: PortableSchema; + disabled?: boolean; + inputs?: TInputs; + Component: ComponentType< + PropsWithChildren<{ + inputs: Expand>; + config: TConfig; + }> + >; +}): ExtensionDefinition { + return createExtension({ + kind: 'app-router-component', + namespace: options.namespace, + name: options.name, + attachTo: options.attachTo ?? { id: 'app/root', input: 'router' }, + configSchema: options.configSchema, + disabled: options.disabled, + inputs: options.inputs, + output: { + component: createRouterExtension.componentDataRef, + }, + factory({ inputs, config }) { + const Component = (props: PropsWithChildren<{}>) => { + return ( + + {props.children} + + ); + }; + return { + component: Component, + }; + }, + }); +} + +/** @public */ +export namespace createRouterExtension { + export const componentDataRef = + createExtensionDataRef>>( + 'app.router.wrapper', + ); +} diff --git a/packages/frontend-plugin-api/src/extensions/index.ts b/packages/frontend-plugin-api/src/extensions/index.ts index 40e9f6f56d..562cb728cb 100644 --- a/packages/frontend-plugin-api/src/extensions/index.ts +++ b/packages/frontend-plugin-api/src/extensions/index.ts @@ -17,6 +17,7 @@ export { createApiExtension } from './createApiExtension'; export { createAppRootElementExtension } from './createAppRootElementExtension'; export { createAppRootWrapperExtension } from './createAppRootWrapperExtension'; +export { createRouterExtension } from './createRouterExtension'; export { createPageExtension } from './createPageExtension'; export { createNavItemExtension } from './createNavItemExtension'; export { createNavLogoExtension } from './createNavLogoExtension'; diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx index 40baaa3ac9..d53344f7fd 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.test.tsx @@ -219,10 +219,14 @@ describe('createExtensionTester', () => { fireEvent.click(await screen.findByRole('button', { name: 'See details' })); await waitFor(() => - expect(analyticsApiMock.getEvents()[0]).toMatchObject({ - action: 'click', - subject: 'See details', - }), + expect(analyticsApiMock.getEvents()).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + action: 'click', + subject: 'See details', + }), + ]), + ), ); }); }); diff --git a/packages/frontend-test-utils/src/app/createExtensionTester.tsx b/packages/frontend-test-utils/src/app/createExtensionTester.tsx index 2984af9dbf..a98879fbba 100644 --- a/packages/frontend-test-utils/src/app/createExtensionTester.tsx +++ b/packages/frontend-test-utils/src/app/createExtensionTester.tsx @@ -14,29 +14,20 @@ * limitations under the License. */ -import React, { - ComponentType, - Fragment, - ReactNode, - useContext, - useState, -} from 'react'; +import React from 'react'; import { MemoryRouter, Link } from 'react-router-dom'; import { RenderResult, render } from '@testing-library/react'; import { createSpecializedApp } from '@backstage/frontend-app-api'; import { ExtensionDefinition, IconComponent, - IdentityApi, RouteRef, - configApiRef, coreExtensionData, - createAppRootWrapperExtension, createExtension, createExtensionInput, createExtensionOverrides, createNavItemExtension, - useApi, + createRouterExtension, useRouteRef, } from '@backstage/frontend-plugin-api'; import { MockConfigApi } from '@backstage/test-utils'; @@ -44,15 +35,7 @@ import { JsonArray, JsonObject, JsonValue } from '@backstage/types'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports import { resolveExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { createSignInPageExtension } from '../../../frontend-plugin-api/src/extensions/createSignInPageExtension'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports import { toInternalExtensionDefinition } from '../../../frontend-plugin-api/src/wiring/createExtension'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { InternalAppContext } from '../../../frontend-app-api/src/wiring/InternalAppContext'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { SignInPageProps } from '../../../core-plugin-api'; -// eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { getBasePath } from '../../../core-app-api/src/app/AppRouter'; const NavItem = (props: { routeRef: RouteRef; @@ -102,113 +85,6 @@ const TestAppNavExtension = createExtension({ }, }); -const AuthenticationProvider = (props: { - signInPage?: ComponentType; - children: ReactNode; -}) => { - const { signInPage: SignInPage, children } = props; - const configApi = useApi(configApiRef); - const signOutTargetUrl = getBasePath(configApi) || '/'; - - const internalAppContext = useContext(InternalAppContext); - if (!internalAppContext) { - throw new Error('AppRouter must be rendered within the AppProvider'); - } - - const { appIdentityProxy } = internalAppContext; - const [identityApi, setIdentityApi] = useState(); - - if (!SignInPage) { - appIdentityProxy.setTarget( - { - getUserId: () => 'guest', - getIdToken: async () => undefined, - getProfile: () => ({ - email: 'guest@example.com', - displayName: 'Guest', - }), - getProfileInfo: async () => ({ - email: 'guest@example.com', - displayName: 'Guest', - }), - getBackstageIdentity: async () => ({ - type: 'user', - userEntityRef: 'user:default/guest', - ownershipEntityRefs: ['user:default/guest'], - }), - getCredentials: async () => ({}), - signOut: async () => {}, - }, - { signOutTargetUrl }, - ); - - return children; - } - - if (!identityApi) { - return ; - } - - appIdentityProxy.setTarget(identityApi, { - signOutTargetUrl, - }); - - return children; -}; - -const TestAppRootExtension = createExtension({ - namespace: 'app', - name: 'root', - attachTo: { id: 'app', input: 'root' }, - inputs: { - signInPage: createExtensionInput( - { component: createSignInPageExtension.componentDataRef }, - { singleton: true, optional: true }, - ), - children: createExtensionInput( - { element: coreExtensionData.reactElement }, - { singleton: true }, - ), - elements: createExtensionInput( - { element: coreExtensionData.reactElement }, - { optional: true }, - ), - wrappers: createExtensionInput( - { component: createAppRootWrapperExtension.componentDataRef }, - { optional: true }, - ), - }, - output: { - element: coreExtensionData.reactElement, - }, - factory({ inputs }) { - const SignInPage = inputs.signInPage?.output.component; - - let content: React.ReactNode = ( - <> - {inputs.elements.map(el => ( - {el.output.element} - ))} - {inputs.children.output.element} - - ); - - for (const wrapper of inputs.wrappers) { - content = {content}; - } - - return { - element: ( - - - {content} - - - ), - }; - }, -}); - /** @public */ export class ExtensionTester { /** @internal */ @@ -302,7 +178,12 @@ export class ExtensionTester { extensions: [ ...this.#extensions.map(extension => extension.definition), TestAppNavExtension, - TestAppRootExtension, + createRouterExtension({ + namespace: 'test', + Component: ({ children }) => ( + {children} + ), + }), ], }), ], diff --git a/packages/frontend-test-utils/src/app/renderInTestApp.test.tsx b/packages/frontend-test-utils/src/app/renderInTestApp.test.tsx index a6783d43a3..a56ae2f140 100644 --- a/packages/frontend-test-utils/src/app/renderInTestApp.test.tsx +++ b/packages/frontend-test-utils/src/app/renderInTestApp.test.tsx @@ -56,9 +56,13 @@ describe('renderInTestApp', () => { fireEvent.click(screen.getByRole('link', { name: 'See details' })); - expect(analyticsApiMock.getEvents()[0]).toMatchObject({ - action: 'click', - subject: 'See details', - }); + expect(analyticsApiMock.getEvents()).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + action: 'click', + subject: 'See details', + }), + ]), + ); }); }); From 995d2809b818d34ddea8e30e717cedf979e99053 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Thu, 21 Dec 2023 20:08:08 -0600 Subject: [PATCH 081/241] Added new @backstage/no-top-level-mui4-imports rule Signed-off-by: Andre Wanlin --- .changeset/warm-maps-scream.md | 7 + .changeset/young-rules-repeat.md | 5 + docs/tutorials/migrate-to-mui5.md | 2 +- packages/eslint-plugin/README.md | 1 + .../docs/rules/no-top-level-mui4-imports.md | 43 ++++++ packages/eslint-plugin/index.js | 1 + .../rules/no-top-level-mui4-imports.js | 129 ++++++++++++++++++ .../src/no-top-level-mui4-imports.test.ts | 100 ++++++++++++++ plugins/azure-devops/.eslintrc.js | 6 +- .../AzureGitTagsIcon/AzureGitTagsIcon.tsx | 2 +- .../AzurePipelinesIcon/AzurePipelinesIcon.tsx | 2 +- .../AzurePullRequestsIcon.tsx | 2 +- .../src/components/BuildTable/BuildTable.tsx | 3 +- .../components/GitTagTable/GitTagTable.tsx | 2 +- .../PullRequestStatusButtonGroup.tsx | 3 +- .../PullRequestTable/PullRequestTable.tsx | 3 +- .../lib/PullRequestCard/PullRequestCard.tsx | 4 +- .../lib/PullRequestGrid/PullRequestGrid.tsx | 2 +- .../PullRequestGridColumn.tsx | 4 +- .../src/components/ReadmeCard/ReadmeCard.tsx | 4 +- plugins/devtools/.eslintrc.js | 6 +- .../Content/ConfigContent/ConfigContent.tsx | 10 +- .../ExternalDependenciesContent.tsx | 16 +-- .../Content/InfoContent/BackstageLogoIcon.tsx | 2 +- .../Content/InfoContent/InfoContent.tsx | 24 ++-- .../DevToolsLayout/DevToolsLayout.tsx | 2 +- plugins/linguist/.eslintrc.js | 6 +- .../components/LinguistCard/LinguistCard.tsx | 15 +- 28 files changed, 351 insertions(+), 55 deletions(-) create mode 100644 .changeset/warm-maps-scream.md create mode 100644 .changeset/young-rules-repeat.md create mode 100644 packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md create mode 100644 packages/eslint-plugin/rules/no-top-level-mui4-imports.js create mode 100644 packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts diff --git a/.changeset/warm-maps-scream.md b/.changeset/warm-maps-scream.md new file mode 100644 index 0000000000..3ea5d93b03 --- /dev/null +++ b/.changeset/warm-maps-scream.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-devtools': patch +'@backstage/plugin-linguist': patch +--- + +Updated imports from named to default imports to help with the Material UI v4 to v5 migration diff --git a/.changeset/young-rules-repeat.md b/.changeset/young-rules-repeat.md new file mode 100644 index 0000000000..5c9d790214 --- /dev/null +++ b/.changeset/young-rules-repeat.md @@ -0,0 +1,5 @@ +--- +'@backstage/eslint-plugin': patch +--- + +Added new `@backstage/no-top-level-mui4-imports` rule that forbids top level imports from Material UI v4 packages diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index 96129ceb8a..1b21c8b419 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -56,7 +56,7 @@ For current known issues with the Material UI v5 migration, follow our [Mileston To migrate your plugin to Material UI v5, you can build on the resources available. -1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). +1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). Note: you can use the [new `@backstage/no-top-level-mui4-imports` ESLint](https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md) rule to help with this. 2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/`. 3. Take a look at possible `TODO:` items the `codemod` could not fix. 4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`. diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index c311670603..1304239caf 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -40,3 +40,4 @@ The following rules are provided by this plugin: | [@backstage/no-forbidden-package-imports](./docs/rules/no-forbidden-package-imports.md) | Disallow internal monorepo imports from package subpaths that are not exported. | | [@backstage/no-relative-monorepo-imports](./docs/rules/no-relative-monorepo-imports.md) | Forbid relative imports that reach outside of the package in a monorepo. | | [@backstage/no-undeclared-imports](./docs/rules/no-undeclared-imports.md) | Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`. | +| [@backstage/no-top-level-mui4-imports](./docs/rules/no-top-level-mui4-imports.md) | Forbid top level import from Material UI v4 packages. | diff --git a/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md b/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md new file mode 100644 index 0000000000..85f5821b01 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md @@ -0,0 +1,43 @@ +# @backstage/no-top-level-mui4-imports + +Forbid top level import from Material UI v4 packages. + +## Usage + +Add the rules as follows, it has no options: + +```js +"@backstage/no-top-level-mui4-imports": ["error"] +``` + +## Rule Details + +TBD - Not sure what should go here + +### Fail + +```tsx +import { Box, Typography } from '@material-ui/core'; +``` + +```tsx +import Box from '@material-ui/core'; +``` + +```tsx +import { + Box, + DialogActions, + DialogContent, + DialogTitle, + Grid, + makeStyles, +} from '@material-ui/core'; +``` + +### Pass + +```tsx +import Typography from '@material-ui/core/Typography'; +import Box from '@material-ui/core/Box'; +``` diff --git a/packages/eslint-plugin/index.js b/packages/eslint-plugin/index.js index 20a0ff2d18..6fdc4f89fb 100644 --- a/packages/eslint-plugin/index.js +++ b/packages/eslint-plugin/index.js @@ -29,5 +29,6 @@ module.exports = { 'no-forbidden-package-imports': require('./rules/no-forbidden-package-imports'), 'no-relative-monorepo-imports': require('./rules/no-relative-monorepo-imports'), 'no-undeclared-imports': require('./rules/no-undeclared-imports'), + 'no-top-level-mui4-imports': require('./rules/no-top-level-mui4-imports'), }, }; diff --git a/packages/eslint-plugin/rules/no-top-level-mui4-imports.js b/packages/eslint-plugin/rules/no-top-level-mui4-imports.js new file mode 100644 index 0000000000..c3367a2346 --- /dev/null +++ b/packages/eslint-plugin/rules/no-top-level-mui4-imports.js @@ -0,0 +1,129 @@ +/* + * Copyright 2023 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. + */ + +// @ts-check + +const KNOWN_STYLES = [ + 'makeStyles', + 'withStyles', + 'createStyles', + 'styled', + 'useTheme', + 'Theme', +]; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + fixable: 'code', + messages: { + topLevelImport: 'Top level imports for Material UI are not allowed', + thirdLevelImport: + 'Third level or deeper imports for Material UI are not allowed', + }, + docs: { + description: 'Forbid top level import from Material UI v4 packages.', + url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md', + }, + }, + create: context => ({ + ImportDeclaration: node => { + // Return if empty import + if (node.specifiers.length === 0) return; + // Return if empty source value + if (!node.source.value) return; + // Return if source value not a string + if (typeof node.source.value !== 'string') return; + // Return if import does not start with '@material-ui/' + if (!node.source.value.startsWith('@material-ui/')) return; + // Return if import is from '@material-ui/core/styles', as it's valid already + if (node.source.value === '@material-ui/core/styles') return; + // Return if import is from '@material-ui/core/SvgIcon', as it's valid already + if (node.source.value === '@material-ui/core/SvgIcon') return; + // Return if proper import eg. `import Box from '@material-ui/core/Box'` + if ( + node.specifiers.length === 1 && + node.source.value?.split('/').length === 3 + ) + return; + + // Report third level or deeper imports + if ( + node.specifiers.length === 1 && + node.source.value.split('/').length > 3 + ) { + context.report({ + node, + messageId: 'thirdLevelImport', + }); + return; + } + + // Report all other imports + context.report({ + node, + messageId: 'topLevelImport', + fix: fixer => { + const replacements = []; + const styles = []; + const svgIcon = []; + + const specifiers = node.specifiers.filter( + s => s.type === 'ImportSpecifier', + ); + + for (const specifier of specifiers) { + if (specifier.local.name === 'TabProps') { + replacements.push( + `import { TabProps } from '@material-ui/core/Tab';`, + ); + } else if ( + specifier.local.name === 'SvgIcon' || + specifier.local.name === 'SvgIconProps' + ) { + svgIcon.push(specifier.local.name); + } else if (KNOWN_STYLES.includes(specifier.local.name)) { + styles.push(specifier.local.name); + } else { + const replacement = `import ${specifier.local.name} from '${node.source.value}/${specifier.local.name}';`; + replacements.push(replacement); + } + } + + if (svgIcon.length > 0) { + if (svgIcon.every(s => ['SvgIcon', 'SvgIconProps'].includes(s))) { + replacements.push( + `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, + ); + } + } + + if (styles.length > 0) { + const stylesReplacement = `import { ${styles.join( + ', ', + )} } from '@material-ui/core/styles';`; + replacements.push(stylesReplacement); + } + + const result = fixer.replaceText(node, replacements.join('\n')); + + return result; + }, + }); + }, + }), +}; diff --git a/packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts b/packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts new file mode 100644 index 0000000000..16605aa46f --- /dev/null +++ b/packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts @@ -0,0 +1,100 @@ +/* + * Copyright 2023 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 { RuleTester } from 'eslint'; +import rule from '../rules/no-top-level-mui4-imports'; + +const ruleTester = new RuleTester({ + parserOptions: { + sourceType: 'module', + ecmaVersion: 2021, + }, +}); + +ruleTester.run('path-imports-rule', rule, { + valid: [ + { + code: `import Typography from '@material-ui/core/Typography';`, + }, + { + code: `import Box from '@material-ui/core/Box'`, + }, + { + code: `import { styled, withStyles } from '@material-ui/core/styles';`, + }, + { + code: `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, + }, + ], + invalid: [ + { + code: `import { Box, Typography } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography';`, + }, + { + code: `import { Box } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box';`, + }, + { + code: `import { + Box, + DialogActions, + DialogContent, + DialogTitle, + Grid, + makeStyles, + } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import Grid from '@material-ui/core/Grid'; +import { makeStyles } from '@material-ui/core/styles';`, + }, + { + code: `import { TabIndicator } from '@material-ui/core/Tabs/TabIndicator';`, + errors: [{ messageId: 'thirdLevelImport' }], + }, + { + code: `import { Box, Button, makeStyles } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import { makeStyles } from '@material-ui/core/styles';`, + }, + { + code: `import { Paper, Typography, styled, withStyles } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { styled, withStyles } from '@material-ui/core/styles';`, + }, + { + code: `import { styled } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import { styled } from '@material-ui/core/styles';`, + }, + { + code: `import { TabProps } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import { TabProps } from '@material-ui/core/Tab';`, + }, + ], +}); diff --git a/plugins/azure-devops/.eslintrc.js b/plugins/azure-devops/.eslintrc.js index e2a53a6ad2..9932358b45 100644 --- a/plugins/azure-devops/.eslintrc.js +++ b/plugins/azure-devops/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-mui4-imports': 'error', + }, +}); diff --git a/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx b/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx index c8b63e3259..0d317e3ce1 100644 --- a/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx +++ b/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx b/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx index bd19331f6e..10cdb3a905 100644 --- a/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx +++ b/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx b/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx index 99e3f74e90..e298f8bc25 100644 --- a/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx +++ b/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; /** @public */ export const AzurePullRequestsIcon = (props: SvgIconProps) => ( diff --git a/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx b/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx index 6707929a6c..09eba5f5a2 100644 --- a/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx +++ b/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Box, Typography } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography'; import { BuildResult, BuildRun, diff --git a/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx b/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx index c6abba55e1..f34a1929fe 100644 --- a/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx +++ b/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Box } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; import { Link, ResponseErrorPanel, diff --git a/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx b/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx index f516bfb0e5..1b0b9a8afe 100644 --- a/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx +++ b/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Button, ButtonGroup } from '@material-ui/core'; +import Button from '@material-ui/core/Button'; +import ButtonGroup from '@material-ui/core/ButtonGroup'; import { PullRequestStatus } from '@backstage/plugin-azure-devops-common'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx b/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx index b37ba6e73c..d672102945 100644 --- a/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx +++ b/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Box, Chip } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Chip from '@material-ui/core/Chip'; import { Link, ResponseErrorPanel, diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx index 98237cb2a3..dd9fff86b5 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx @@ -15,7 +15,9 @@ */ import { Avatar, Link } from '@backstage/core-components'; -import { Card, CardContent, CardHeader } from '@material-ui/core'; +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; +import CardHeader from '@material-ui/core/CardHeader'; import Typography from '@material-ui/core/Typography'; import { AutoCompleteIcon } from '../AutoCompleteIcon'; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx index 8b9c49beb4..0244ea3bb1 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx @@ -17,7 +17,7 @@ import { PullRequestGridColumn } from '../PullRequestGridColumn'; import { PullRequestGroup } from '../types'; import React from 'react'; -import { styled } from '@material-ui/core'; +import { styled } from '@material-ui/core/styles'; const GridDiv = styled('div')(({ theme }) => ({ display: 'flex', diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx index 94a648188d..f06216ac76 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx @@ -14,7 +14,9 @@ * limitations under the License. */ -import { Paper, Typography, styled, withStyles } from '@material-ui/core'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { styled, withStyles } from '@material-ui/core/styles'; import { PullRequestCard } from '../PullRequestCard'; import { PullRequestGroup } from '../types'; diff --git a/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx b/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx index 420fe6ecf4..300c9e0d7c 100644 --- a/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx +++ b/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx @@ -14,7 +14,9 @@ * limitations under the License. */ -import { Box, Button, makeStyles } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import { makeStyles } from '@material-ui/core/styles'; import { InfoCard, Progress, diff --git a/plugins/devtools/.eslintrc.js b/plugins/devtools/.eslintrc.js index e2a53a6ad2..9932358b45 100644 --- a/plugins/devtools/.eslintrc.js +++ b/plugins/devtools/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-mui4-imports': 'error', + }, +}); diff --git a/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx b/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx index 66129b5dae..aba46f85b7 100644 --- a/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx +++ b/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx @@ -15,16 +15,16 @@ */ import { Progress, WarningPanel } from '@backstage/core-components'; +import Box from '@material-ui/core/Box'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; import { - Box, createStyles, makeStyles, - Paper, Theme, - Typography, useTheme, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +} from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import ReactJson from 'react-json-view'; import { useConfig } from '../../../hooks'; diff --git a/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx b/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx index a5dd825fe5..c6a46ea8fb 100644 --- a/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx +++ b/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx @@ -23,16 +23,12 @@ import { TableColumn, } from '@backstage/core-components'; import { ExternalDependency } from '@backstage/plugin-devtools-common'; -import { - Box, - createStyles, - Grid, - makeStyles, - Paper, - Theme, - Typography, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +import Box from '@material-ui/core/Box'; +import Grid from '@material-ui/core/Grid'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import { useExternalDependencies } from '../../../hooks'; diff --git a/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx b/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx index 32f35600f2..8a9df77546 100644 --- a/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx index 0ed43d2fee..fcbea53603 100644 --- a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx @@ -15,20 +15,16 @@ */ import { Progress } from '@backstage/core-components'; -import { - Avatar, - Box, - createStyles, - Divider, - List, - ListItem, - ListItemAvatar, - ListItemText, - makeStyles, - Paper, - Theme, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +import Avatar from '@material-ui/core/Avatar'; +import Box from '@material-ui/core/Box'; +import Divider from '@material-ui/core/Divider'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemAvatar from '@material-ui/core/ListItemAvatar'; +import ListItemText from '@material-ui/core/ListItemText'; +import Paper from '@material-ui/core/Paper'; +import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import { useInfo } from '../../../hooks'; import { InfoDependenciesTable } from './InfoDependenciesTable'; diff --git a/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx b/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx index ae9a337ced..bce0837ef1 100644 --- a/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx +++ b/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx @@ -19,7 +19,7 @@ import { attachComponentData, useElementFilter, } from '@backstage/core-plugin-api'; -import { TabProps } from '@material-ui/core'; +import { TabProps } from '@material-ui/core/Tab'; import { default as React } from 'react'; /** @public */ diff --git a/plugins/linguist/.eslintrc.js b/plugins/linguist/.eslintrc.js index e2a53a6ad2..9932358b45 100644 --- a/plugins/linguist/.eslintrc.js +++ b/plugins/linguist/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-mui4-imports': 'error', + }, +}); diff --git a/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx b/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx index 6014487d30..6a07a958c2 100644 --- a/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx +++ b/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx @@ -14,15 +14,12 @@ * limitations under the License. */ -import { - Box, - Chip, - Tooltip, - Typography, - makeStyles, - Grid, - useTheme, -} from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Chip from '@material-ui/core/Chip'; +import Tooltip from '@material-ui/core/Tooltip'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import { makeStyles, useTheme } from '@material-ui/core/styles'; import { InfoCard, Progress } from '@backstage/core-components'; import Alert from '@material-ui/lab/Alert'; import { DateTime } from 'luxon'; From 37867e0c2c17540ea97f158d89a03908d3d7a789 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 22 Dec 2023 06:56:15 -0600 Subject: [PATCH 082/241] Renamed based on feedback Signed-off-by: Andre Wanlin --- .changeset/young-rules-repeat.md | 2 +- docs/tutorials/migrate-to-mui5.md | 2 +- packages/eslint-plugin/README.md | 12 ++++++------ ...orts.md => no-top-level-material-ui-4-imports.md} | 4 ++-- packages/eslint-plugin/index.js | 2 +- ...orts.js => no-top-level-material-ui-4-imports.js} | 2 +- ...ts => no-top-level-material-ui-4-imports.test.ts} | 2 +- plugins/azure-devops/.eslintrc.js | 2 +- plugins/devtools/.eslintrc.js | 2 +- plugins/linguist/.eslintrc.js | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) rename packages/eslint-plugin/docs/rules/{no-top-level-mui4-imports.md => no-top-level-material-ui-4-imports.md} (83%) rename packages/eslint-plugin/rules/{no-top-level-mui4-imports.js => no-top-level-material-ui-4-imports.js} (98%) rename packages/eslint-plugin/src/{no-top-level-mui4-imports.test.ts => no-top-level-material-ui-4-imports.test.ts} (98%) diff --git a/.changeset/young-rules-repeat.md b/.changeset/young-rules-repeat.md index 5c9d790214..6fb17f0608 100644 --- a/.changeset/young-rules-repeat.md +++ b/.changeset/young-rules-repeat.md @@ -2,4 +2,4 @@ '@backstage/eslint-plugin': patch --- -Added new `@backstage/no-top-level-mui4-imports` rule that forbids top level imports from Material UI v4 packages +Added new `@backstage/no-top-level-material-ui-4-imports` rule that forbids top level imports from Material UI v4 packages diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index 1b21c8b419..aaf8cff7f5 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -56,7 +56,7 @@ For current known issues with the Material UI v5 migration, follow our [Mileston To migrate your plugin to Material UI v5, you can build on the resources available. -1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). Note: you can use the [new `@backstage/no-top-level-mui4-imports` ESLint](https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md) rule to help with this. +1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). Note: you can use the [new `@backstage/no-top-level-material-ui-4-imports` ESLint](https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md) rule to help with this. 2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/`. 3. Take a look at possible `TODO:` items the `codemod` could not fix. 4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`. diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 1304239caf..600b3268e1 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -35,9 +35,9 @@ rules: { The following rules are provided by this plugin: -| Rule | Description | -| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -| [@backstage/no-forbidden-package-imports](./docs/rules/no-forbidden-package-imports.md) | Disallow internal monorepo imports from package subpaths that are not exported. | -| [@backstage/no-relative-monorepo-imports](./docs/rules/no-relative-monorepo-imports.md) | Forbid relative imports that reach outside of the package in a monorepo. | -| [@backstage/no-undeclared-imports](./docs/rules/no-undeclared-imports.md) | Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`. | -| [@backstage/no-top-level-mui4-imports](./docs/rules/no-top-level-mui4-imports.md) | Forbid top level import from Material UI v4 packages. | +| Rule | Description | +| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | +| [@backstage/no-forbidden-package-imports](./docs/rules/no-forbidden-package-imports.md) | Disallow internal monorepo imports from package subpaths that are not exported. | +| [@backstage/no-relative-monorepo-imports](./docs/rules/no-relative-monorepo-imports.md) | Forbid relative imports that reach outside of the package in a monorepo. | +| [@backstage/no-undeclared-imports](./docs/rules/no-undeclared-imports.md) | Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`. | +| [@backstage/no-top-level-material-ui-4-imports](./docs/rules/no-top-level-material-ui-4-imports.md) | Forbid top level import from Material UI v4 packages. | diff --git a/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md b/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md similarity index 83% rename from packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md rename to packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md index 85f5821b01..a00eb73ffd 100644 --- a/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md +++ b/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md @@ -1,4 +1,4 @@ -# @backstage/no-top-level-mui4-imports +# @backstage/no-top-level-material-ui-4-imports Forbid top level import from Material UI v4 packages. @@ -7,7 +7,7 @@ Forbid top level import from Material UI v4 packages. Add the rules as follows, it has no options: ```js -"@backstage/no-top-level-mui4-imports": ["error"] +"@backstage/no-top-level-material-ui-4-imports": ["error"] ``` ## Rule Details diff --git a/packages/eslint-plugin/index.js b/packages/eslint-plugin/index.js index 6fdc4f89fb..af1a8891c3 100644 --- a/packages/eslint-plugin/index.js +++ b/packages/eslint-plugin/index.js @@ -29,6 +29,6 @@ module.exports = { 'no-forbidden-package-imports': require('./rules/no-forbidden-package-imports'), 'no-relative-monorepo-imports': require('./rules/no-relative-monorepo-imports'), 'no-undeclared-imports': require('./rules/no-undeclared-imports'), - 'no-top-level-mui4-imports': require('./rules/no-top-level-mui4-imports'), + 'no-top-level-material-ui-4-imports': require('./rules/no-top-level-material-ui-4-imports'), }, }; diff --git a/packages/eslint-plugin/rules/no-top-level-mui4-imports.js b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js similarity index 98% rename from packages/eslint-plugin/rules/no-top-level-mui4-imports.js rename to packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js index c3367a2346..dad034e6f2 100644 --- a/packages/eslint-plugin/rules/no-top-level-mui4-imports.js +++ b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js @@ -37,7 +37,7 @@ module.exports = { }, docs: { description: 'Forbid top level import from Material UI v4 packages.', - url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md', + url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md', }, }, create: context => ({ diff --git a/packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts similarity index 98% rename from packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts rename to packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts index 16605aa46f..cb68a529e9 100644 --- a/packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts +++ b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts @@ -15,7 +15,7 @@ */ import { RuleTester } from 'eslint'; -import rule from '../rules/no-top-level-mui4-imports'; +import rule from '../rules/no-top-level-material-ui-4-imports'; const ruleTester = new RuleTester({ parserOptions: { diff --git a/plugins/azure-devops/.eslintrc.js b/plugins/azure-devops/.eslintrc.js index 9932358b45..e487f765b2 100644 --- a/plugins/azure-devops/.eslintrc.js +++ b/plugins/azure-devops/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { rules: { - '@backstage/no-top-level-mui4-imports': 'error', + '@backstage/no-top-level-material-ui-4-imports': 'error', }, }); diff --git a/plugins/devtools/.eslintrc.js b/plugins/devtools/.eslintrc.js index 9932358b45..e487f765b2 100644 --- a/plugins/devtools/.eslintrc.js +++ b/plugins/devtools/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { rules: { - '@backstage/no-top-level-mui4-imports': 'error', + '@backstage/no-top-level-material-ui-4-imports': 'error', }, }); diff --git a/plugins/linguist/.eslintrc.js b/plugins/linguist/.eslintrc.js index 9932358b45..e487f765b2 100644 --- a/plugins/linguist/.eslintrc.js +++ b/plugins/linguist/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { rules: { - '@backstage/no-top-level-mui4-imports': 'error', + '@backstage/no-top-level-material-ui-4-imports': 'error', }, }); From 74f57943876fc780d25c813e717e9167cc5f37a9 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 22 Dec 2023 07:24:54 -0600 Subject: [PATCH 083/241] Pair of adjustment based on feedback Signed-off-by: Andre Wanlin --- .../rules/no-top-level-material-ui-4-imports.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js index dad034e6f2..1cbc56cf9b 100644 --- a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js +++ b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js @@ -42,6 +42,12 @@ module.exports = { }, create: context => ({ ImportDeclaration: node => { + // Anatomy of a Node + // Example: import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; + // Specifiers are the part between the `import` and `from`, in the example that would be `SvgIcon, { SvgIconProps }` + // Source is the part after the `from`, in the example that would be `'@material-ui/core/SvgIcon'` + // Source value gets you `@material-ui/core/SvgIcon` without the quotes, where as Source raw gets it as is + // Return if empty import if (node.specifiers.length === 0) return; // Return if empty source value @@ -52,11 +58,9 @@ module.exports = { if (!node.source.value.startsWith('@material-ui/')) return; // Return if import is from '@material-ui/core/styles', as it's valid already if (node.source.value === '@material-ui/core/styles') return; - // Return if import is from '@material-ui/core/SvgIcon', as it's valid already - if (node.source.value === '@material-ui/core/SvgIcon') return; // Return if proper import eg. `import Box from '@material-ui/core/Box'` if ( - node.specifiers.length === 1 && + node.specifiers.length >= 1 && node.source.value?.split('/').length === 3 ) return; @@ -87,9 +91,10 @@ module.exports = { ); for (const specifier of specifiers) { - if (specifier.local.name === 'TabProps') { + const propsMatch = /^([A-Z]\w+)Props$/.exec(specifier.local.name); + if (propsMatch) { replacements.push( - `import { TabProps } from '@material-ui/core/Tab';`, + `import { ${specifier.local.name} } from '@material-ui/core/${propsMatch[1]}';`, ); } else if ( specifier.local.name === 'SvgIcon' || From 834d2f530eb818a8134569cff611ded32bbb1fec Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 22 Dec 2023 11:41:47 -0600 Subject: [PATCH 084/241] Applied a map to avoid hard coded cases Signed-off-by: Andre Wanlin --- .../no-top-level-material-ui-4-imports.js | 87 ++++++++++++++----- ...no-top-level-material-ui-4-imports.test.ts | 5 ++ 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js index 1cbc56cf9b..76a928a5e5 100644 --- a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js +++ b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js @@ -84,37 +84,80 @@ module.exports = { fix: fixer => { const replacements = []; const styles = []; - const svgIcon = []; const specifiers = node.specifiers.filter( s => s.type === 'ImportSpecifier', ); - for (const specifier of specifiers) { - const propsMatch = /^([A-Z]\w+)Props$/.exec(specifier.local.name); + const specifiersMap = specifiers.map(s => { + const propsTest = /^([A-Z]\w+)Props$/.test(s.local.name); + const propsMatch = /^([A-Z]\w+)Props$/.exec(s.local.name); + let propValue; if (propsMatch) { - replacements.push( - `import { ${specifier.local.name} } from '@material-ui/core/${propsMatch[1]}';`, - ); - } else if ( - specifier.local.name === 'SvgIcon' || - specifier.local.name === 'SvgIconProps' - ) { - svgIcon.push(specifier.local.name); - } else if (KNOWN_STYLES.includes(specifier.local.name)) { - styles.push(specifier.local.name); - } else { - const replacement = `import ${specifier.local.name} from '${node.source.value}/${specifier.local.name}';`; - replacements.push(replacement); + propValue = propsMatch[1]; } - } + return { + emitComponent: !propsTest, + emitProp: propsTest, + value: s.local.name, + propValue, + }; + }); - if (svgIcon.length > 0) { - if (svgIcon.every(s => ['SvgIcon', 'SvgIconProps'].includes(s))) { - replacements.push( - `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, - ); + // We have 3 cases: + // 1 - Just Prop: import { TabProps } from '@material-ui/core'; + // 2 - Just Component: import { Box } from '@material-ui/core'; + // 3 - Component and Prop: import { SvgIcon, SvgIconProps } from '@material-ui/core'; + + const components = specifiersMap + .filter(f => { + return f.emitComponent; + }) + .map(m => m.value); + const props = specifiersMap + .filter(f => { + return f.emitProp; + }) + .map(m => m.value); + + if ( + specifiersMap.some(s => s.emitProp) && + !specifiersMap.some(s => s.emitComponent) + ) { + // 1 - Just Prop + const propValue = specifiersMap + .filter(f => { + return f.emitProp; + }) + .map(m => m.propValue); + replacements.push( + `import { ${props.join(', ')} } from '@material-ui/core/${ + propValue[0] + }';`, + ); + } else if ( + !specifiersMap.some(s => s.emitProp) && + specifiersMap.some(s => s.emitComponent) + ) { + // 2 - Just Component + for (const specifier of specifiers) { + if (KNOWN_STYLES.includes(specifier.local.name)) { + styles.push(specifier.local.name); + } else { + const replacement = `import ${specifier.local.name} from '${node.source.value}/${specifier.local.name}';`; + replacements.push(replacement); + } } + } else if ( + specifiersMap.some(s => s.emitProp) && + specifiersMap.some(s => s.emitComponent) + ) { + // 3 - Component and Prop + replacements.push( + `import ${components[0]}, { ${props.join( + ', ', + )} } from '@material-ui/core/${components[0]}';`, + ); } if (styles.length > 0) { diff --git a/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts index cb68a529e9..ac0b3770e0 100644 --- a/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts +++ b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts @@ -91,6 +91,11 @@ import { styled, withStyles } from '@material-ui/core/styles';`, errors: [{ messageId: 'topLevelImport' }], output: `import { styled } from '@material-ui/core/styles';`, }, + { + code: `import { SvgIcon, SvgIconProps } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, + }, { code: `import { TabProps } from '@material-ui/core';`, errors: [{ messageId: 'topLevelImport' }], From 7965c57e86b1afeaffbcd33dfed3f0efa61d98c9 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 22 Dec 2023 12:56:47 -0600 Subject: [PATCH 085/241] Removed third level or deeper reporting Signed-off-by: Andre Wanlin --- .../rules/no-top-level-material-ui-4-imports.js | 10 ++-------- .../src/no-top-level-material-ui-4-imports.test.ts | 10 ++++++---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js index 76a928a5e5..dc2a555e24 100644 --- a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js +++ b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js @@ -32,8 +32,6 @@ module.exports = { fixable: 'code', messages: { topLevelImport: 'Top level imports for Material UI are not allowed', - thirdLevelImport: - 'Third level or deeper imports for Material UI are not allowed', }, docs: { description: 'Forbid top level import from Material UI v4 packages.', @@ -65,15 +63,11 @@ module.exports = { ) return; - // Report third level or deeper imports + // Return if third level or deeper imports if ( - node.specifiers.length === 1 && + node.specifiers.length >= 1 && node.source.value.split('/').length > 3 ) { - context.report({ - node, - messageId: 'thirdLevelImport', - }); return; } diff --git a/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts index ac0b3770e0..568bdb8cc8 100644 --- a/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts +++ b/packages/eslint-plugin/src/no-top-level-material-ui-4-imports.test.ts @@ -38,6 +38,12 @@ ruleTester.run('path-imports-rule', rule, { { code: `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, }, + { + code: `import { StyleRules } from '@material-ui/core/styles/withStyles';`, + }, + { + code: `import { CreateCSSProperties, StyledComponentProps } from '@material-ui/core/styles/withStyles';`, + }, ], invalid: [ { @@ -68,10 +74,6 @@ import DialogTitle from '@material-ui/core/DialogTitle'; import Grid from '@material-ui/core/Grid'; import { makeStyles } from '@material-ui/core/styles';`, }, - { - code: `import { TabIndicator } from '@material-ui/core/Tabs/TabIndicator';`, - errors: [{ messageId: 'thirdLevelImport' }], - }, { code: `import { Box, Button, makeStyles } from '@material-ui/core';`, errors: [{ messageId: 'topLevelImport' }], From aeed5347e1da9813aa3149011a364a0d5ce5038e Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Fri, 22 Dec 2023 13:05:08 -0600 Subject: [PATCH 086/241] Updated API Reports Signed-off-by: Andre Wanlin --- plugins/azure-devops/api-report.md | 2 +- plugins/devtools/api-report.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/azure-devops/api-report.md b/plugins/azure-devops/api-report.md index 38c1eed279..cfff4348ee 100644 --- a/plugins/azure-devops/api-report.md +++ b/plugins/azure-devops/api-report.md @@ -22,7 +22,7 @@ import { Readme } from '@backstage/plugin-azure-devops-common'; import { ReadmeConfig } from '@backstage/plugin-azure-devops-common'; import { RepoBuild } from '@backstage/plugin-azure-devops-common'; import { RepoBuildOptions } from '@backstage/plugin-azure-devops-common'; -import { SvgIconProps } from '@material-ui/core'; +import { SvgIconProps } from '@material-ui/core/SvgIcon'; import { Team } from '@backstage/plugin-azure-devops-common'; // @public (undocumented) diff --git a/plugins/devtools/api-report.md b/plugins/devtools/api-report.md index 21754d7c1e..bba36a5a9a 100644 --- a/plugins/devtools/api-report.md +++ b/plugins/devtools/api-report.md @@ -10,7 +10,7 @@ import { default as default_2 } from 'react'; import { JSX as JSX_2 } from 'react'; import { default as React_2 } from 'react'; import { RouteRef } from '@backstage/core-plugin-api'; -import { TabProps } from '@material-ui/core'; +import { TabProps } from '@material-ui/core/Tab'; // @public (undocumented) export const ConfigContent: () => React_2.JSX.Element; From b07ff647d6b2b972e4dbbb0f3cc3f103849faebd Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sat, 13 Jan 2024 15:05:12 -0600 Subject: [PATCH 087/241] Clean-up based on feedback Signed-off-by: Andre Wanlin --- .../no-top-level-material-ui-4-imports.md | 4 +-- .../no-top-level-material-ui-4-imports.js | 27 +++++-------------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md b/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md index a00eb73ffd..a105014abc 100644 --- a/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md +++ b/packages/eslint-plugin/docs/rules/no-top-level-material-ui-4-imports.md @@ -7,12 +7,12 @@ Forbid top level import from Material UI v4 packages. Add the rules as follows, it has no options: ```js -"@backstage/no-top-level-material-ui-4-imports": ["error"] +'@backstage/no-top-level-material-ui-4-imports': 'error' ``` ## Rule Details -TBD - Not sure what should go here +Automatically fixes imports from named to default imports. This will help you comply with [Material UI recommendations](https://mui.com/material-ui/guides/minimizing-bundle-size/) and make migrating to Material UI v5 easier. ### Fail diff --git a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js index dc2a555e24..6a726545fc 100644 --- a/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js +++ b/packages/eslint-plugin/rules/no-top-level-material-ui-4-imports.js @@ -57,19 +57,8 @@ module.exports = { // Return if import is from '@material-ui/core/styles', as it's valid already if (node.source.value === '@material-ui/core/styles') return; // Return if proper import eg. `import Box from '@material-ui/core/Box'` - if ( - node.specifiers.length >= 1 && - node.source.value?.split('/').length === 3 - ) - return; - - // Return if third level or deeper imports - if ( - node.specifiers.length >= 1 && - node.source.value.split('/').length > 3 - ) { - return; - } + // Or if third level or deeper imports + if (node.source.value?.split('/').length >= 3) return; // Report all other imports context.report({ @@ -84,17 +73,13 @@ module.exports = { ); const specifiersMap = specifiers.map(s => { - const propsTest = /^([A-Z]\w+)Props$/.test(s.local.name); const propsMatch = /^([A-Z]\w+)Props$/.exec(s.local.name); - let propValue; - if (propsMatch) { - propValue = propsMatch[1]; - } + return { - emitComponent: !propsTest, - emitProp: propsTest, + emitComponent: !(propsMatch !== null), + emitProp: propsMatch !== null, value: s.local.name, - propValue, + propValue: propsMatch ? propsMatch[1] : undefined, }; }); From 398b44907c2487393fc106b45a8f9c754d84216a Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sun, 14 Jan 2024 14:51:17 +0100 Subject: [PATCH 088/241] Updated Template.v1beta3.schema.json, added a missing "presentation" field Signed-off-by: Bogdan Nechyporenko Signed-off-by: bnechyporenko --- .../src/Template.v1beta3.schema.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/scaffolder-common/src/Template.v1beta3.schema.json b/plugins/scaffolder-common/src/Template.v1beta3.schema.json index d4be9b7538..d7698511d8 100644 --- a/plugins/scaffolder-common/src/Template.v1beta3.schema.json +++ b/plugins/scaffolder-common/src/Template.v1beta3.schema.json @@ -139,6 +139,24 @@ } ] }, + "presentation": { + "type": "object", + "description": "A way to redefine the labels for actionable buttons.", + "properties": { + "backButtonText": { + "type": "string", + "description": "A button which return the user to one step back." + }, + "createButtonText": { + "type": "string", + "description": "A button which start the execution of the template." + }, + "reviewButtonText": { + "type": "string", + "description": "A button which open the review step to verify the input prior to start the execution." + } + } + }, "steps": { "type": "array", "description": "A list of steps to execute.", From 178b8d8a70b7ba877236b8a9763877f71c534b7e Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sun, 14 Jan 2024 14:51:50 +0100 Subject: [PATCH 089/241] Updated Template.v1beta3.schema.json, added a missing "presentation" field Signed-off-by: Bogdan Nechyporenko Signed-off-by: bnechyporenko --- .changeset/fresh-mirrors-shake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fresh-mirrors-shake.md diff --git a/.changeset/fresh-mirrors-shake.md b/.changeset/fresh-mirrors-shake.md new file mode 100644 index 0000000000..a722182986 --- /dev/null +++ b/.changeset/fresh-mirrors-shake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-common': patch +--- + +Updated Template.v1beta3.schema.json, added a missing "presentation" field From 331389fccdfa9d96410cf67c1cf5e3c57b2052d7 Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sun, 14 Jan 2024 14:54:50 +0100 Subject: [PATCH 090/241] wip Signed-off-by: Bogdan Nechyporenko Signed-off-by: bnechyporenko --- .../src/Template.v1beta3.schema.json | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/plugins/scaffolder-common/src/Template.v1beta3.schema.json b/plugins/scaffolder-common/src/Template.v1beta3.schema.json index d7698511d8..d4be9b7538 100644 --- a/plugins/scaffolder-common/src/Template.v1beta3.schema.json +++ b/plugins/scaffolder-common/src/Template.v1beta3.schema.json @@ -139,24 +139,6 @@ } ] }, - "presentation": { - "type": "object", - "description": "A way to redefine the labels for actionable buttons.", - "properties": { - "backButtonText": { - "type": "string", - "description": "A button which return the user to one step back." - }, - "createButtonText": { - "type": "string", - "description": "A button which start the execution of the template." - }, - "reviewButtonText": { - "type": "string", - "description": "A button which open the review step to verify the input prior to start the execution." - } - } - }, "steps": { "type": "array", "description": "A list of steps to execute.", From 04a57a034db2d90fe49d2c889222617f4190e91e Mon Sep 17 00:00:00 2001 From: bnechyporenko Date: Sun, 14 Jan 2024 14:57:15 +0100 Subject: [PATCH 091/241] wip Signed-off-by: Bogdan Nechyporenko Signed-off-by: bnechyporenko --- .../src/Template.v1beta3.schema.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/scaffolder-common/src/Template.v1beta3.schema.json b/plugins/scaffolder-common/src/Template.v1beta3.schema.json index d4be9b7538..d7698511d8 100644 --- a/plugins/scaffolder-common/src/Template.v1beta3.schema.json +++ b/plugins/scaffolder-common/src/Template.v1beta3.schema.json @@ -139,6 +139,24 @@ } ] }, + "presentation": { + "type": "object", + "description": "A way to redefine the labels for actionable buttons.", + "properties": { + "backButtonText": { + "type": "string", + "description": "A button which return the user to one step back." + }, + "createButtonText": { + "type": "string", + "description": "A button which start the execution of the template." + }, + "reviewButtonText": { + "type": "string", + "description": "A button which open the review step to verify the input prior to start the execution." + } + } + }, "steps": { "type": "array", "description": "A list of steps to execute.", From 7b8e551a830cf57f36720c8f4701a46e9505ace2 Mon Sep 17 00:00:00 2001 From: lshwayne96 Date: Mon, 15 Jan 2024 12:37:57 +0800 Subject: [PATCH 092/241] Fix errors when deleting SQS messages Signed-off-by: lshwayne96 --- .changeset/shaggy-coins-happen.md | 8 ++++++++ .../src/publisher/AwsSqsConsumingEventPublisher.ts | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 .changeset/shaggy-coins-happen.md diff --git a/.changeset/shaggy-coins-happen.md b/.changeset/shaggy-coins-happen.md new file mode 100644 index 0000000000..c20a8e0cb2 --- /dev/null +++ b/.changeset/shaggy-coins-happen.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-events-backend-module-aws-sqs': patch +--- + +Fix errors when deleting SQS messages: + +- If zero messages were received, skip deletion to avoid `EmptyBatchRequest` error from the SQS client. +- If zero failures were returned from the SQS client during deletion, skip error logging. diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts index 4f4e6ea55d..a2f6a00fe7 100644 --- a/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts +++ b/plugins/events-backend-module-aws-sqs/src/publisher/AwsSqsConsumingEventPublisher.ts @@ -111,7 +111,7 @@ export class AwsSqsConsumingEventPublisher implements EventPublisher { } private async deleteMessages(messages?: Message[]): Promise { - if (!messages) { + if (!messages || messages.length === 0) { return; } @@ -129,7 +129,7 @@ export class AwsSqsConsumingEventPublisher implements EventPublisher { const result = await this.sqs.send( new DeleteMessageBatchCommand(deleteParams), ); - if (result.Failed) { + if (result.Failed && result.Failed.length > 0) { this.logger.error( `Failed to delete ${result.Failed!.length} of ${ messages.length From 9ac1ceb4b68bb2f5b9b50522f4ce281d424ec401 Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Mon, 15 Jan 2024 09:16:28 +0200 Subject: [PATCH 093/241] chore: move connection upgrade to router, add tests for manager Signed-off-by: Heikki Hellgren --- .../src/service/SignalManager.test.ts | 178 ++++++++++++++++++ .../src/service/SignalManager.ts | 69 +------ plugins/signals-backend/src/service/router.ts | 63 +++++-- 3 files changed, 236 insertions(+), 74 deletions(-) create mode 100644 plugins/signals-backend/src/service/SignalManager.test.ts diff --git a/plugins/signals-backend/src/service/SignalManager.test.ts b/plugins/signals-backend/src/service/SignalManager.test.ts new file mode 100644 index 0000000000..5720d1ff52 --- /dev/null +++ b/plugins/signals-backend/src/service/SignalManager.test.ts @@ -0,0 +1,178 @@ +/* + * Copyright 2024 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 { WebSocket } from 'ws'; +import { EventSubscriber } from '@backstage/plugin-events-node'; +import { SignalManager } from './SignalManager'; +import { getVoidLogger } from '@backstage/backend-common'; + +class MockWebSocket { + closed: boolean = false; + readyState: number = WebSocket.OPEN; + callbacks: Map void> = + new Map(); + data: any[] = []; + + close(_: number, __: string | Buffer): void { + this.readyState = WebSocket.CLOSED; + this.closed = true; + } + + on( + event: string | symbol, + listener: (this: WebSocket, ...args: any[]) => void, + ) { + this.callbacks.set(event, listener); + return this; + } + + // @ts-ignore + send(data: any, _?: (err?: Error) => void): void { + this.data.push(data); + } + + trigger(event: string | symbol, ...args: any[]): void { + const cb = this.callbacks.get(event); + if (!cb) { + throw new Error(`No callback for ${event.toString()}`); + } + // @ts-ignore + cb(...args); + } +} + +describe('SignalManager', () => { + let onEvent: Function; + + const mockEventBroker = { + publish: async () => {}, + subscribe: (subscriber: EventSubscriber) => { + onEvent = subscriber.onEvent; + }, + }; + + const manager = SignalManager.create({ + eventBroker: mockEventBroker, + logger: getVoidLogger(), + }); + + it('should close connection on error', () => { + const ws = new MockWebSocket(); + manager.addConnection(ws as unknown as WebSocket); + + ws.trigger('error', new Error('error')); + expect(ws.closed).toBeTruthy(); + }); + + it('should allow subscribing and unsubscribing to events', async () => { + const ws = new MockWebSocket(); + manager.addConnection(ws as unknown as WebSocket); + + ws.trigger( + 'message', + JSON.stringify({ action: 'subscribe', channel: 'test' }), + false, + ); + + await onEvent({ + topic: 'signals', + eventPayload: { + recipients: null, + channel: 'test', + message: { msg: 'test' }, + }, + }); + + expect(ws.data.length).toEqual(1); + expect(ws.data[0]).toEqual( + JSON.stringify({ channel: 'test', message: { msg: 'test' } }), + ); + + ws.trigger( + 'message', + JSON.stringify({ action: 'unsubscribe', channel: 'test' }), + false, + ); + + await onEvent({ + topic: 'signals', + eventPayload: { + recipients: null, + channel: 'test', + message: { msg: 'test' }, + }, + }); + + expect(ws.data.length).toEqual(1); + }); + + it('should only send to users from identity', async () => { + // Connection without identity + const ws1 = new MockWebSocket(); + manager.addConnection(ws1 as unknown as WebSocket); + + // Connection with identity and subscription + const ws2 = new MockWebSocket(); + manager.addConnection(ws2 as unknown as WebSocket, { + identity: { + type: 'user', + ownershipEntityRefs: ['user:default/john.doe'], + userEntityRef: 'user:default/john.doe', + }, + expiresInSeconds: 3600, + token: '1234', + }); + + // Connection without subscription + const ws3 = new MockWebSocket(); + manager.addConnection(ws3 as unknown as WebSocket, { + identity: { + type: 'user', + ownershipEntityRefs: ['user:default/john.doe'], + userEntityRef: 'user:default/john.doe', + }, + expiresInSeconds: 3600, + token: '1234', + }); + + ws1.trigger( + 'message', + JSON.stringify({ action: 'subscribe', channel: 'test' }), + false, + ); + + ws2.trigger( + 'message', + JSON.stringify({ action: 'subscribe', channel: 'test' }), + false, + ); + + await onEvent({ + topic: 'signals', + eventPayload: { + recipients: 'user:default/john.doe', + channel: 'test', + message: { msg: 'test' }, + }, + }); + + expect(ws1.data.length).toEqual(0); + expect(ws3.data.length).toEqual(0); + expect(ws2.data.length).toEqual(1); + expect(ws2.data[0]).toEqual( + JSON.stringify({ channel: 'test', message: { msg: 'test' } }), + ); + }); +}); diff --git a/plugins/signals-backend/src/service/SignalManager.ts b/plugins/signals-backend/src/service/SignalManager.ts index 988db47465..983496b96b 100644 --- a/plugins/signals-backend/src/service/SignalManager.ts +++ b/plugins/signals-backend/src/service/SignalManager.ts @@ -15,24 +15,11 @@ */ import { EventBroker, EventParams } from '@backstage/plugin-events-node'; import { SignalPayload } from '@backstage/plugin-signals-node'; -import { RawData, WebSocket, WebSocketServer } from 'ws'; -import { IncomingMessage } from 'http'; +import { RawData, WebSocket } from 'ws'; import { v4 as uuid } from 'uuid'; import { JsonObject } from '@backstage/types'; -import { - BackstageIdentityResponse, - IdentityApi, - IdentityApiGetIdentityRequest, -} from '@backstage/plugin-auth-node'; +import { BackstageIdentityResponse } from '@backstage/plugin-auth-node'; import { LoggerService } from '@backstage/backend-plugin-api'; -import { Duplex } from 'stream'; - -/** @internal */ -export type ConnectionUpgradeOptions = { - request: IncomingMessage; - socket: Duplex; - head: Buffer; -}; /** * @internal @@ -52,7 +39,6 @@ export type SignalManagerOptions = { // TODO: Remove optional when events-backend can offer this service eventBroker?: EventBroker; logger: LoggerService; - identity: IdentityApi; }; /** @internal */ @@ -63,24 +49,13 @@ export class SignalManager { >(); private eventBroker?: EventBroker; private logger: LoggerService; - private identity: IdentityApi; - private server: WebSocketServer; static create(options: SignalManagerOptions) { return new SignalManager(options); } private constructor(options: SignalManagerOptions) { - ({ - eventBroker: this.eventBroker, - logger: this.logger, - identity: this.identity, - } = options); - - this.server = new WebSocketServer({ - noServer: true, - clientTracking: false, - }); + ({ eventBroker: this.eventBroker, logger: this.logger } = options); this.eventBroker?.subscribe({ supportsEventTopics: () => ['signals'], @@ -89,37 +64,7 @@ export class SignalManager { }); } - /** - * Handles request upgrade to websocket and adds the connection to internal - * list for publish/subscribe functionality - * @param req - Request - */ - async handleUpgrade(options: ConnectionUpgradeOptions) { - const { request, socket, head } = options; - let identity: BackstageIdentityResponse | undefined = undefined; - - // Authentication token is passed in Sec-WebSocket-Protocol header as there - // is no other way to pass the token with plain websockets - const token = request.headers['sec-websocket-protocol']; - if (token) { - identity = await this.identity.getIdentity({ - request: { - headers: { authorization: token }, - }, - } as IdentityApiGetIdentityRequest); - } - - this.server.handleUpgrade( - request, - socket, - head, - (ws: WebSocket, __: IncomingMessage) => { - this.addConnection(ws, identity); - }, - ); - } - - private addConnection(ws: WebSocket, identity?: BackstageIdentityResponse) { + addConnection(ws: WebSocket, identity?: BackstageIdentityResponse) { const id = uuid(); const conn = { @@ -207,7 +152,11 @@ export class SignalManager { return; } - conn.ws.send(jsonMessage); + conn.ws.send(jsonMessage, err => { + if (err) { + this.logger.error(`Failed to send message to ${conn.id}: ${err}`); + } + }); }); } } diff --git a/plugins/signals-backend/src/service/router.ts b/plugins/signals-backend/src/service/router.ts index ec56860bf3..4394a9f480 100644 --- a/plugins/signals-backend/src/service/router.ts +++ b/plugins/signals-backend/src/service/router.ts @@ -18,10 +18,15 @@ import express, { NextFunction, Request, Response } from 'express'; import Router from 'express-promise-router'; import { LoggerService } from '@backstage/backend-plugin-api'; import * as https from 'https'; -import http from 'http'; +import http, { IncomingMessage } from 'http'; import { SignalManager } from './SignalManager'; -import { IdentityApi } from '@backstage/plugin-auth-node'; +import { + BackstageIdentityResponse, + IdentityApi, + IdentityApiGetIdentityRequest, +} from '@backstage/plugin-auth-node'; import { EventBroker } from '@backstage/plugin-events-node'; +import { WebSocket, WebSocketServer } from 'ws'; /** @public */ export interface RouterOptions { @@ -34,13 +39,23 @@ export interface RouterOptions { export async function createRouter( options: RouterOptions, ): Promise { - const { logger } = options; + const { logger, identity } = options; const manager = SignalManager.create(options); - let subscribed = false; + let subscribedToUpgradeRequests = false; - const upgradeMiddleware = (req: Request, _: Response, next: NextFunction) => { + const webSocketServer = new WebSocketServer({ + noServer: true, + clientTracking: false, + }); + + const upgradeMiddleware = async ( + req: Request, + _: Response, + next: NextFunction, + ) => { const server: https.Server | http.Server = (req.socket as any)?.server; if ( + subscribedToUpgradeRequests || !server || !req.headers || req.headers.upgrade === undefined || @@ -50,15 +65,35 @@ export async function createRouter( return; } - if (!subscribed) { - subscribed = true; - server.on('upgrade', async (request, socket, head) => { - // TODO: Find a way to make this more generic - if (request.url === '/api/signals') { - await manager.handleUpgrade({ request, socket, head }); - } - }); - } + subscribedToUpgradeRequests = true; + server.on('upgrade', async (request, socket, head) => { + // TODO: Find a way to make this more generic + if (request.url !== '/api/signals') { + return; + } + + let userIdentity: BackstageIdentityResponse | undefined = undefined; + + // Authentication token is passed in Sec-WebSocket-Protocol header as there + // is no other way to pass the token with plain websockets + const token = req.headers['sec-websocket-protocol']; + if (token) { + userIdentity = await identity.getIdentity({ + request: { + headers: { authorization: token }, + }, + } as IdentityApiGetIdentityRequest); + } + + webSocketServer.handleUpgrade( + request, + socket, + head, + (ws: WebSocket, __: IncomingMessage) => { + manager.addConnection(ws, userIdentity); + }, + ); + }); }; const router = Router(); From d3be2dac94877c98998ddbb21faea5d8d6333da7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 11:57:44 +0000 Subject: [PATCH 094/241] chore(deps): update helm release postgresql to v13.2.30 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- contrib/chart/backstage/Chart.lock | 6 +++--- contrib/chart/backstage/Chart.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/chart/backstage/Chart.lock b/contrib/chart/backstage/Chart.lock index 542f9d592e..bd909c1071 100644 --- a/contrib/chart/backstage/Chart.lock +++ b/contrib/chart/backstage/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: postgresql repository: https://charts.bitnami.com/bitnami - version: 13.2.27 -digest: sha256:c2272865ffe4c805153440d8fc6af84945d4ce566b14d0fa8698d75382ada06c -generated: "2023-12-31T14:23:23.75461574Z" + version: 13.2.30 +digest: sha256:7b558cf1628b8cce366c980f20bd80a3cd7685fe419e43ee9d6df75bc577ec20 +generated: "2024-01-15T11:57:35.306830879Z" diff --git a/contrib/chart/backstage/Chart.yaml b/contrib/chart/backstage/Chart.yaml index a152ac49ac..f926c1b0d7 100644 --- a/contrib/chart/backstage/Chart.yaml +++ b/contrib/chart/backstage/Chart.yaml @@ -18,7 +18,7 @@ sources: dependencies: - name: postgresql condition: postgresql.enabled - version: 13.2.27 + version: 13.2.30 repository: https://charts.bitnami.com/bitnami maintainers: From 7689c72085b82d45fa40d1c342730fa3c940c43b Mon Sep 17 00:00:00 2001 From: Stefan Buck Date: Mon, 15 Jan 2024 13:39:06 +0100 Subject: [PATCH 095/241] update snyk logo Signed-off-by: Stefan Buck --- microsite/data/plugins/snyk-security.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/data/plugins/snyk-security.yaml b/microsite/data/plugins/snyk-security.yaml index 4abd068247..8c22d44510 100644 --- a/microsite/data/plugins/snyk-security.yaml +++ b/microsite/data/plugins/snyk-security.yaml @@ -5,6 +5,6 @@ authorUrl: https://snyk.io category: Security description: View Snyk scanned vulnerabilities and license compliance of your components directly in Backstage. documentation: https://github.com/snyk-tech-services/backstage-plugin-snyk/blob/main/README.md -iconUrl: https://storage.googleapis.com/snyk-technical-services.appspot.com/snyk-logo-vertical-black.png +iconUrl: https://github.com/snyk-tech-services/backstage-plugin-snyk/assets/109112986/95eb1b06-b3e8-4910-9233-11926e02fa18 npmPackageName: 'backstage-plugin-snyk' addedDate: '2021-01-22' From d16f85f237d54d5e501131bab7c0336b1ee3a0cc Mon Sep 17 00:00:00 2001 From: Heikki Hellgren Date: Mon, 15 Jan 2024 14:40:59 +0200 Subject: [PATCH 096/241] feat: show first scaffolder output text by default usually there's only one output text that could be shown automatically when the output is shown. Signed-off-by: Heikki Hellgren --- .changeset/sixty-plums-switch.md | 5 +++++ .../DefaultTemplateOutputs.test.tsx | 10 +++++++++- .../TemplateOutputs/DefaultTemplateOutputs.tsx | 17 +++++++++-------- .../components/TemplateOutputs/TextOutputs.tsx | 6 +++++- 4 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 .changeset/sixty-plums-switch.md diff --git a/.changeset/sixty-plums-switch.md b/.changeset/sixty-plums-switch.md new file mode 100644 index 0000000000..8da07609c6 --- /dev/null +++ b/.changeset/sixty-plums-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Show first scaffolder output text by default diff --git a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx index 8366dcadf8..4c631b86b0 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.test.tsx @@ -25,7 +25,10 @@ describe('', () => { it('should render template output', async () => { const output = { links: [{ title: 'Link 1', url: 'https://backstage.io/' }], - text: [{ title: 'Text 1', content: 'Hello, **world**!' }], + text: [ + { title: 'Text 1', content: 'Hello, **world**!' }, + { title: 'Text 2', content: 'Hello, **mars**!' }, + ], }; const { getByRole } = await renderInTestApp( @@ -37,6 +40,11 @@ describe('', () => { }, ); + // first text output default visible + expect(getByRole('heading', { level: 2 }).innerHTML).toBe( + output.text[0].title, + ); + // test link outputs for (const link of output.links ?? []) { expect( diff --git a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx index a495e4ca9e..c105c5a571 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateOutputs/DefaultTemplateOutputs.tsx @@ -28,17 +28,18 @@ import { TextOutputs } from './TextOutputs'; export const DefaultTemplateOutputs = (props: { output?: ScaffolderTaskOutput; }) => { - const [textOutputIndex, setTextOutputIndex] = useState(); + const { output } = props; + const [textOutputIndex, setTextOutputIndex] = useState( + output?.text?.length ? 0 : undefined, + ); const textOutput = useMemo( () => - textOutputIndex !== undefined - ? props.output?.text?.[textOutputIndex] - : null, - [props.output, textOutputIndex], + textOutputIndex !== undefined ? output?.text?.[textOutputIndex] : null, + [output, textOutputIndex], ); - if (!props.output) { + if (!output) { return null; } @@ -48,11 +49,11 @@ export const DefaultTemplateOutputs = (props: { - + diff --git a/plugins/scaffolder-react/src/next/components/TemplateOutputs/TextOutputs.tsx b/plugins/scaffolder-react/src/next/components/TemplateOutputs/TextOutputs.tsx index 7e64603e92..8f61aa6a30 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateOutputs/TextOutputs.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateOutputs/TextOutputs.tsx @@ -47,7 +47,11 @@ export const TextOutputs = (props: { startIcon={} component="div" color="primary" - onClick={() => setIndex?.(index !== i ? i : undefined)} + onClick={() => { + if (index !== i) { + setIndex?.(i); + } + }} variant={index === i ? 'outlined' : undefined} > {title} From c3ae0d47da05c5aca0c3c1f3e4329d1b40627748 Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Mon, 15 Jan 2024 19:03:56 +0530 Subject: [PATCH 097/241] Changes is style Signed-off-by: AmbrishRamachandiran --- microsite/src/pages/plugins/plugins.module.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/microsite/src/pages/plugins/plugins.module.scss b/microsite/src/pages/plugins/plugins.module.scss index b0427c8f5c..dbd0c62c75 100644 --- a/microsite/src/pages/plugins/plugins.module.scss +++ b/microsite/src/pages/plugins/plugins.module.scss @@ -78,6 +78,8 @@ :global(.dropdown) { float: right; margin-bottom: 1rem; + text-overflow: ellipsis; + white-space: nowrap; } :global(.button--info) { @@ -100,7 +102,7 @@ } :global(.dropdown__label) { - font-size: 14px; + font-size: 15px; cursor: pointer; } From 9373b4c88ef97306d7f699d21428e5b7f0942f8f Mon Sep 17 00:00:00 2001 From: Daniel Laird Date: Mon, 15 Jan 2024 14:21:23 +0000 Subject: [PATCH 098/241] Resolve PR feedback Signed-off-by: Daniel Laird --- .changeset/fair-spies-rescue.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/fair-spies-rescue.md b/.changeset/fair-spies-rescue.md index 2b49d4b969..d7f1ea5275 100644 --- a/.changeset/fair-spies-rescue.md +++ b/.changeset/fair-spies-rescue.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder-backend-module-github': minor +'@backstage/plugin-scaffolder-backend-module-github': patch --- Ensure `teamReviewers` list is unique before calling API From f5da6523c03fbfc8f6de6e72cfbc47de0a4386da Mon Sep 17 00:00:00 2001 From: armandocomellas1 Date: Mon, 15 Jan 2024 18:01:06 -0600 Subject: [PATCH 099/241] Change the description header of the changeset and also add a unit test for new URL method Signed-off-by: armandocomellas1 --- .changeset/thirty-cats-help.md | 2 +- .../modules/core/UrlReaderProcessor.test.ts | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.changeset/thirty-cats-help.md b/.changeset/thirty-cats-help.md index bb6011ca9c..9c5d24180d 100644 --- a/.changeset/thirty-cats-help.md +++ b/.changeset/thirty-cats-help.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend': patch --- -Change script in **UrlReaderProcessor.ts** Replacing the line code 127 with method (new URL) to handle URL Reader from GCS with wildcard \* +Parse the URL using a different method rather than `git-url-parse` to support wildcards for URLs which are not VCS providers diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts index c9575ce5cd..0a3bec7570 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts @@ -213,4 +213,31 @@ describe('UrlReaderProcessor', () => { expect(reader.search).toHaveBeenCalledTimes(1); }); + + it('parser return valid URL with wildcard *', async () => { + const logger = getVoidLogger(); + + const reader: jest.Mocked = { + readUrl: jest.fn(), + readTree: jest.fn(), + search: jest.fn().mockImplementation(async () => []), + }; + + const processor = new UrlReaderProcessor({ reader, logger }); + + const emit = jest.fn(); + + await processor.readLocation( + { + type: 'url', + target: 'https://storage.cloud.google.com/ah-backstage-poc-catalog/*', + }, + false, + emit, + defaultEntityDataParser, + mockCache, + ); + + expect(reader.search).toHaveReturned(); + }); }); From 0b0396257632d38de2f000673cba73451ebeb4f9 Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Tue, 16 Jan 2024 10:21:27 +0530 Subject: [PATCH 100/241] Updated readme document of adr plugin Signed-off-by: AmbrishRamachandiran --- .changeset/curvy-ladybugs-impress.md | 5 +++++ plugins/adr/README.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/curvy-ladybugs-impress.md diff --git a/.changeset/curvy-ladybugs-impress.md b/.changeset/curvy-ladybugs-impress.md new file mode 100644 index 0000000000..ffeb76399a --- /dev/null +++ b/.changeset/curvy-ladybugs-impress.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-adr': patch +--- + +Updated Readme document in adr plugin diff --git a/plugins/adr/README.md b/plugins/adr/README.md index e6178f003b..4a1f3a7552 100644 --- a/plugins/adr/README.md +++ b/plugins/adr/README.md @@ -2,7 +2,7 @@ Welcome to the ADR plugin! -This plugin allows you to browse ADRs associated with your entities as well as a way to discover ADRs across others entities via Backstage Search. Use this to learn from the past experience of other projects to guide your own architecture decisions. +This plugin allows you to explore ADRs connected with your entities, as well as discover ADRs across other entities using Backstage Search. Use this to inform your own architectural decisions based on the experiences of previous projects. ![ADR tab](./docs/adr-tab.png) From cbf15616cd7d1e0c1adddb6b257afd8c105982e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 16 Jan 2024 08:55:24 +0100 Subject: [PATCH 101/241] exit pre mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/pre.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index 8190034fe5..2ca69b284d 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "next", "initialVersions": { "example-app": "0.2.90", From f6e4c2a9353fc6707e9334608dca5f5ac7a676e5 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 16 Jan 2024 10:24:31 +0100 Subject: [PATCH 102/241] chore: update the test to ensure that it's called with the correct arguments Signed-off-by: blam --- .../src/modules/core/UrlReaderProcessor.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts index 0a3bec7570..e2489df4b4 100644 --- a/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/modules/core/UrlReaderProcessor.test.ts @@ -238,6 +238,9 @@ describe('UrlReaderProcessor', () => { mockCache, ); - expect(reader.search).toHaveReturned(); + expect(reader.search).toHaveBeenCalledWith( + 'https://storage.cloud.google.com/ah-backstage-poc-catalog/*', + { etag: undefined }, + ); }); }); From 1ab53d0f09d3e4ba27a6c48e97e941561195aca1 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Tue, 16 Jan 2024 10:56:13 +0100 Subject: [PATCH 103/241] Add release notes for 1.22.0 Signed-off-by: Philipp Hugenroth --- docs/releases/v1.22.0.md | 69 ++++++++++++++++++++++++++++++++++ microsite/docusaurus.config.js | 2 +- microsite/sidebars.json | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 docs/releases/v1.22.0.md diff --git a/docs/releases/v1.22.0.md b/docs/releases/v1.22.0.md new file mode 100644 index 0000000000..e5ce345ccc --- /dev/null +++ b/docs/releases/v1.22.0.md @@ -0,0 +1,69 @@ +--- +id: v1.22.0 +title: v1.22.0 +description: Backstage Release v1.22.0 +--- + +These are the release notes for the v1.22.0 release of [Backstage](https://backstage.io/). + +A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done. + +## Highlights + +### Updates to new frontend system + +There have been several updates to alpha packages in the new frontend system including a breaking change where the `app/router` extension was renamed to `app/root`. Furthermore `elements`, `wrappers`, and `router` were added as inputs to `app/root` making it possible to pass extensions into the root of the app. + +### Plugins and modules migrated to the New Backend System + +Some more features have been migrated to the new backend system: + +- `@backstage/plugin-auth-backend-module-microsoft-provider` +- `@backstage/plugin-auth-backend-module-pinniped-provider` +- `@backstage/plugin-catalog-backend-module-openapi` +- `@backstage/plugin-events-backend-module-azure` +- `@backstage/plugin-events-backend-module-bitbucket-cloud` +- `@backstage/plugin-events-backend-module-gerrit` +- `@backstage/plugin-linguist` + +### New plugin: App Visualizer + +This release includes the new `@backstage/plugin-app-visualizer` package. This plugin for the new frontend system lets you browse and view the extension structure of your app as a graph, detailed list, or in text form. + +### New feature: Dynamic Feature Service + +This release includes the new `@backstage/backend-dynamic-feature-service` package. +It is a new and experimental service that lets you dynamically detect and load local plugins and modules in your Backstage instance. + +Contributed by [@davidfestal](https://github.com/davidfestal) in [#18862](https://github.com/backstage/backstage/pull/18862) + +### New Scaffolder action `gitlab:issues:create` + +You can now create GitHub issues in your scaffolder flows! Contributed by [@elaine-mattos](https://github.com/elaine-mattos) in [#21929](https://github.com/backstage/backstage/pull/21929) + +### New Scaffolder action `gitlab:repo:push` + +You can now push raw branches to GitLab in your scaffolder flows! Contributed by [@gavlyukovskiy](https://github.com/gavlyukovskiy) in [#21977](https://github.com/backstage/backstage/pull/21977) + +## Security Fixes + +This release does not contain any security fixes. + +However, some updates were made to the build facilities in the CLI and the caches in the backend system, such that you can now perform builds on FIPS compliant systems. This may lead to some internal cache invalidation happening, since the hashing algorithms used were updated. This should not pose a problem unless caches were being used as reliable persistent storage systems. Please let us know if you encounter any issues that may be related to this. + +## Upgrade path + +We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated). + +## Links and References + +Below you can find a list of links and references to help you learn about and start using this new release. + +- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/) +- [GitHub repository](https://github.com/backstage/backstage) +- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy) +- [Community Discord](https://discord.gg/backstage-687207715902193673) for discussions and support +- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.22.0-changelog.md) +- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins) + +Sign up for our [newsletter](https://info.backstage.spotify.com/newsletter_subscribe) if you want to be informed about what is happening in the world of Backstage. diff --git a/microsite/docusaurus.config.js b/microsite/docusaurus.config.js index 85ffacd39d..f2e44aa0d2 100644 --- a/microsite/docusaurus.config.js +++ b/microsite/docusaurus.config.js @@ -182,7 +182,7 @@ module.exports = { position: 'left', }, { - to: 'docs/releases/v1.21.0', + to: 'docs/releases/v1.22.0', label: 'Releases', position: 'left', }, diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 5dd5ce93f8..c54e59f45c 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -1,6 +1,7 @@ { "releases": { "Release Notes": [ + "releases/v1.22.0", "releases/v1.21.0", "releases/v1.20.0", "releases/v1.19.0", From 5fe6600824ca5df919fa80f8577a3083b8ca7472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 16 Jan 2024 11:32:44 +0100 Subject: [PATCH 104/241] add oauth dialog and alert display to the root elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Co-authored-by: blam Co-authored-by: Camila Belo Co-authored-by: Philipp Hugenroth Co-authored-by: Vincenzo Scamporlino Signed-off-by: Fredrik Adelöw --- .changeset/weak-pans-accept.md | 5 +++ package.json | 3 ++ .../src/extensions/elements.tsx | 45 +++++++++++++++++++ .../src/wiring/createApp.test.tsx | 4 ++ .../frontend-app-api/src/wiring/createApp.tsx | 6 +++ 5 files changed, 63 insertions(+) create mode 100644 .changeset/weak-pans-accept.md create mode 100644 packages/frontend-app-api/src/extensions/elements.tsx diff --git a/.changeset/weak-pans-accept.md b/.changeset/weak-pans-accept.md new file mode 100644 index 0000000000..5e75f52058 --- /dev/null +++ b/.changeset/weak-pans-accept.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-app-api': patch +--- + +add oauth dialog and alert display to the root elements diff --git a/package.json b/package.json index 5fbce0ad70..4d052f2ec5 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,11 @@ }, "scripts": { "dev": "concurrently 'yarn start' 'yarn start-backend'", + "dev:next": "concurrently 'yarn start:next' 'yarn start-backend:next'", "start": "yarn workspace example-app start", "start-backend": "yarn workspace example-backend start", + "start:next": "yarn workspace example-app-next start", + "start-backend:next": "yarn workspace example-backend-next start", "build:backend": "yarn workspace example-backend build", "build:all": "backstage-cli repo build --all", "build:api-reports": "yarn build:api-reports:only --tsc", diff --git a/packages/frontend-app-api/src/extensions/elements.tsx b/packages/frontend-app-api/src/extensions/elements.tsx new file mode 100644 index 0000000000..0a764583bb --- /dev/null +++ b/packages/frontend-app-api/src/extensions/elements.tsx @@ -0,0 +1,45 @@ +/* + * Copyright 2023 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 { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components'; +import { + createAppRootElementExtension, + createSchemaFromZod, +} from '@backstage/frontend-plugin-api'; +import React from 'react'; + +export const oauthRequestDialogAppRootElement = createAppRootElementExtension({ + namespace: 'app', + name: 'oauth-request-dialog', + element: , +}); + +export const alertDisplayAppRootElement = createAppRootElementExtension({ + namespace: 'app', + name: 'alert-display', + configSchema: createSchemaFromZod(z => + z.object({ + transientTimeoutMs: z.number().default(5000), + anchorOrigin: z + .object({ + vertical: z.enum(['top', 'bottom']).default('top'), + horizontal: z.enum(['left', 'center', 'right']).default('center'), + }) + .default({}), + }), + ), + element: ({ config }) => , +}); diff --git a/packages/frontend-app-api/src/wiring/createApp.test.tsx b/packages/frontend-app-api/src/wiring/createApp.test.tsx index e6ddc03e38..43bb4499b1 100644 --- a/packages/frontend-app-api/src/wiring/createApp.test.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.test.tsx @@ -259,6 +259,10 @@ describe('createApp', () => { ] ] + elements [ + + + ] ] components [ diff --git a/packages/frontend-app-api/src/wiring/createApp.tsx b/packages/frontend-app-api/src/wiring/createApp.tsx index b25bad03bc..7b2f17193e 100644 --- a/packages/frontend-app-api/src/wiring/createApp.tsx +++ b/packages/frontend-app-api/src/wiring/createApp.tsx @@ -78,6 +78,10 @@ import { apis as defaultApis } from '../../../app-defaults/src/defaults'; import { Route } from 'react-router-dom'; import { SidebarItem } from '@backstage/core-components'; import { DarkTheme, LightTheme } from '../extensions/themes'; +import { + oauthRequestDialogAppRootElement, + alertDisplayAppRootElement, +} from '../extensions/elements'; import { extractRouteInfoFromAppNode } from '../routing/extractRouteInfoFromAppNode'; import { appLanguageApiRef, @@ -116,6 +120,8 @@ export const builtinExtensions = [ DefaultNotFoundErrorPageComponent, LightTheme, DarkTheme, + oauthRequestDialogAppRootElement, + alertDisplayAppRootElement, ...DefaultApis, ].map(def => resolveExtensionDefinition(def)); From 41dc09ccb7867a00074a0a4843aa655607c1cfa9 Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Tue, 16 Jan 2024 16:43:15 +0530 Subject: [PATCH 105/241] changes done as per review Signed-off-by: AmbrishRamachandiran --- .changeset/curvy-ladybugs-impress.md | 2 +- plugins/adr/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/curvy-ladybugs-impress.md b/.changeset/curvy-ladybugs-impress.md index ffeb76399a..3ea90f513a 100644 --- a/.changeset/curvy-ladybugs-impress.md +++ b/.changeset/curvy-ladybugs-impress.md @@ -2,4 +2,4 @@ '@backstage/plugin-adr': patch --- -Updated Readme document in adr plugin +Updated README document in adr plugin diff --git a/plugins/adr/README.md b/plugins/adr/README.md index 4a1f3a7552..3e8647a8fa 100644 --- a/plugins/adr/README.md +++ b/plugins/adr/README.md @@ -2,7 +2,7 @@ Welcome to the ADR plugin! -This plugin allows you to explore ADRs connected with your entities, as well as discover ADRs across other entities using Backstage Search. Use this to inform your own architectural decisions based on the experiences of previous projects. +This plugin allows you to explore ADRs (Architecture Decision Records) associated with your entities, as well as discover ADRs across other entities using Backstage Search. Use this to inform your own architectural decisions based on the experiences of previous projects. ![ADR tab](./docs/adr-tab.png) From 8070f67dc46b6006ab9f034e1c8e85e522f9538a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 16 Jan 2024 11:44:56 +0000 Subject: [PATCH 106/241] Version Packages --- .changeset/afraid-mice-give.md | 5 - .changeset/beige-pillows-repeat.md | 5 - .changeset/blue-hats-admire.md | 5 - .changeset/brave-ghosts-pay.md | 5 - .changeset/brave-queens-crash.md | 5 - .changeset/brave-shirts-hang.md | 5 - .changeset/brown-planes-sort.md | 5 - .changeset/calm-grapes-remember.md | 5 - .changeset/chatty-rivers-hope.md | 5 - .changeset/chilled-seahorses-clean.md | 5 - .changeset/chilled-zebras-wash.md | 5 - .changeset/clean-mails-bathe.md | 5 - .changeset/clever-meals-drop.md | 5 - .changeset/create-app-1703547661.md | 5 - .changeset/create-app-1704804195.md | 5 - .changeset/curvy-dingos-jump.md | 5 - .changeset/eight-rice-cross.md | 5 - .changeset/fair-spies-rescue.md | 5 - .changeset/fast-tables-hammer.md | 7 - .changeset/flat-terms-provide.md | 5 - .changeset/fresh-mirrors-shake.md | 5 - .changeset/friendly-horses-kneel.md | 5 - .changeset/funny-rings-fry.md | 8 - .changeset/giant-fans-type.md | 5 - .changeset/gold-pianos-worry.md | 5 - .changeset/great-adults-begin.md | 14 - .changeset/green-dolphins-cover.md | 6 - .changeset/happy-forks-jam.md | 5 - .changeset/heavy-moose-reflect.md | 5 - .changeset/hip-dancers-pay.md | 5 - .changeset/large-pens-cough.md | 6 - .changeset/large-poets-buy.md | 5 - .changeset/lazy-teachers-walk.md | 5 - .changeset/many-peaches-dress.md | 9 - .changeset/new-plants-sort.md | 8 - .changeset/ninety-impalas-knock.md | 5 - .changeset/odd-ligers-return.md | 7 - .changeset/olive-walls-wonder.md | 6 - .changeset/olive-walls-wonder2.md | 5 - .changeset/orange-planets-suffer.md | 8 - .changeset/pre.json | 297 -- .changeset/quiet-oranges-bake.md | 11 - .changeset/renovate-126fde4.md | 6 - .changeset/renovate-91133b2.md | 11 - .changeset/renovate-9647667.md | 6 - .changeset/rich-poets-stare.md | 6 - .changeset/rotten-tools-clean.md | 145 - .changeset/shaggy-coins-happen.md | 8 - .changeset/silent-horses-raise.md | 7 - .changeset/silver-countries-notice.md | 5 - .changeset/sixty-plums-switch.md | 5 - .changeset/smooth-pumas-fold.md | 5 - .changeset/sour-taxis-rush.md | 5 - .changeset/stale-cars-attack.md | 6 - .changeset/stale-hairs-sparkle.md | 5 - .changeset/tender-roses-teach.md | 8 - .changeset/thirty-cats-help.md | 5 - .changeset/tricky-pans-explain.md | 5 - .changeset/unlucky-bottles-run.md | 5 - .changeset/weak-pans-accept.md | 5 - docs/releases/v1.22.0-changelog.md | 3239 +++++++++++++++++ package.json | 2 +- packages/app-defaults/CHANGELOG.md | 11 + packages/app-defaults/package.json | 2 +- packages/app-next-example-plugin/CHANGELOG.md | 8 + packages/app-next-example-plugin/package.json | 2 +- packages/app-next/CHANGELOG.md | 76 + packages/app-next/package.json | 2 +- packages/app/CHANGELOG.md | 76 + packages/app/package.json | 2 +- packages/backend-app-api/CHANGELOG.md | 18 + packages/backend-app-api/package.json | 2 +- packages/backend-common/CHANGELOG.md | 23 + packages/backend-common/package.json | 2 +- packages/backend-defaults/CHANGELOG.md | 10 + packages/backend-defaults/package.json | 2 +- packages/backend-dev-utils/CHANGELOG.md | 6 + packages/backend-dev-utils/package.json | 2 +- .../CHANGELOG.md | 27 + .../package.json | 2 +- packages/backend-next/CHANGELOG.md | 41 + packages/backend-next/package.json | 2 +- packages/backend-openapi-utils/CHANGELOG.md | 9 + packages/backend-openapi-utils/package.json | 2 +- packages/backend-plugin-api/CHANGELOG.md | 12 + packages/backend-plugin-api/package.json | 2 +- packages/backend-tasks/CHANGELOG.md | 10 + packages/backend-tasks/package.json | 2 +- packages/backend-test-utils/CHANGELOG.md | 13 + packages/backend-test-utils/package.json | 2 +- packages/backend/CHANGELOG.md | 58 + packages/backend/package.json | 2 +- packages/catalog-client/CHANGELOG.md | 9 + packages/catalog-client/package.json | 2 +- packages/cli-node/CHANGELOG.md | 10 + packages/cli-node/package.json | 2 +- packages/cli/CHANGELOG.md | 20 + packages/cli/package.json | 2 +- packages/config-loader/CHANGELOG.md | 11 + packages/config-loader/package.json | 2 +- packages/core-app-api/CHANGELOG.md | 10 + packages/core-app-api/package.json | 2 +- packages/core-compat-api/CHANGELOG.md | 11 + packages/core-compat-api/package.json | 2 +- packages/core-components/CHANGELOG.md | 13 + packages/core-components/package.json | 2 +- packages/core-plugin-api/CHANGELOG.md | 10 + packages/core-plugin-api/package.json | 2 +- packages/create-app/CHANGELOG.md | 10 + packages/create-app/package.json | 2 +- packages/dev-utils/CHANGELOG.md | 14 + packages/dev-utils/package.json | 2 +- packages/e2e-test/CHANGELOG.md | 9 + packages/e2e-test/package.json | 2 +- packages/frontend-app-api/CHANGELOG.md | 24 + packages/frontend-app-api/package.json | 2 +- packages/frontend-plugin-api/CHANGELOG.md | 19 + packages/frontend-plugin-api/package.json | 2 +- packages/frontend-test-utils/CHANGELOG.md | 13 + packages/frontend-test-utils/package.json | 2 +- packages/integration-react/CHANGELOG.md | 9 + packages/integration-react/package.json | 2 +- packages/repo-tools/CHANGELOG.md | 13 + packages/repo-tools/package.json | 2 +- .../techdocs-cli-embedded-app/CHANGELOG.md | 19 + .../techdocs-cli-embedded-app/package.json | 2 +- packages/techdocs-cli/CHANGELOG.md | 11 + packages/techdocs-cli/package.json | 2 +- packages/test-utils/CHANGELOG.md | 13 + packages/test-utils/package.json | 2 +- plugins/adr-backend/CHANGELOG.md | 16 + plugins/adr-backend/package.json | 2 +- plugins/adr-common/CHANGELOG.md | 9 + plugins/adr-common/package.json | 2 +- plugins/adr/CHANGELOG.md | 16 + plugins/adr/package.json | 2 +- plugins/airbrake-backend/CHANGELOG.md | 10 + plugins/airbrake-backend/package.json | 2 +- plugins/airbrake/CHANGELOG.md | 13 + plugins/airbrake/package.json | 2 +- plugins/allure/CHANGELOG.md | 11 + plugins/allure/package.json | 2 +- plugins/analytics-module-ga/CHANGELOG.md | 10 + plugins/analytics-module-ga/package.json | 2 +- plugins/analytics-module-ga4/CHANGELOG.md | 10 + plugins/analytics-module-ga4/package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- plugins/apache-airflow/CHANGELOG.md | 9 + plugins/apache-airflow/package.json | 2 +- plugins/api-docs/CHANGELOG.md | 16 + plugins/api-docs/package.json | 2 +- plugins/apollo-explorer/CHANGELOG.md | 9 + plugins/apollo-explorer/package.json | 2 +- plugins/app-backend/CHANGELOG.md | 13 + plugins/app-backend/package.json | 2 +- plugins/app-node/CHANGELOG.md | 7 + plugins/app-node/package.json | 2 +- plugins/app-visualizer/CHANGELOG.md | 14 + plugins/app-visualizer/package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- plugins/auth-backend/CHANGELOG.md | 24 + plugins/auth-backend/package.json | 2 +- plugins/auth-node/CHANGELOG.md | 13 + plugins/auth-node/package.json | 2 +- plugins/azure-devops-backend/CHANGELOG.md | 16 + plugins/azure-devops-backend/package.json | 2 +- plugins/azure-devops/CHANGELOG.md | 13 + plugins/azure-devops/package.json | 2 +- plugins/azure-sites-backend/CHANGELOG.md | 10 + plugins/azure-sites-backend/package.json | 2 +- plugins/azure-sites/CHANGELOG.md | 13 + plugins/azure-sites/package.json | 2 +- plugins/badges-backend/CHANGELOG.md | 14 + plugins/badges-backend/package.json | 2 +- plugins/badges/CHANGELOG.md | 12 + plugins/badges/package.json | 2 +- plugins/bazaar-backend/CHANGELOG.md | 11 + plugins/bazaar-backend/package.json | 2 +- plugins/bazaar/CHANGELOG.md | 13 + plugins/bazaar/package.json | 2 +- plugins/bitrise/CHANGELOG.md | 11 + plugins/bitrise/package.json | 2 +- .../catalog-backend-module-aws/CHANGELOG.md | 19 + .../catalog-backend-module-aws/package.json | 2 +- .../catalog-backend-module-azure/CHANGELOG.md | 14 + .../catalog-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 15 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../catalog-backend-module-gcp/CHANGELOG.md | 13 + .../catalog-backend-module-gcp/package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 17 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 16 + .../package.json | 2 +- .../catalog-backend-module-ldap/CHANGELOG.md | 13 + .../catalog-backend-module-ldap/package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 26 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/catalog-backend/CHANGELOG.md | 24 + plugins/catalog-backend/package.json | 2 +- plugins/catalog-common/CHANGELOG.md | 9 + plugins/catalog-common/package.json | 2 +- plugins/catalog-graph/CHANGELOG.md | 13 + plugins/catalog-graph/package.json | 2 +- plugins/catalog-import/CHANGELOG.md | 18 + plugins/catalog-import/package.json | 2 +- plugins/catalog-node/CHANGELOG.md | 15 + plugins/catalog-node/package.json | 2 +- plugins/catalog-react/CHANGELOG.md | 19 + plugins/catalog-react/package.json | 2 +- .../catalog-unprocessed-entities/CHANGELOG.md | 11 + .../catalog-unprocessed-entities/package.json | 2 +- plugins/catalog/CHANGELOG.md | 22 + plugins/catalog/package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/cicd-statistics/CHANGELOG.md | 9 + plugins/cicd-statistics/package.json | 2 +- plugins/circleci/CHANGELOG.md | 11 + plugins/circleci/package.json | 2 +- plugins/cloudbuild/CHANGELOG.md | 11 + plugins/cloudbuild/package.json | 2 +- plugins/code-climate/CHANGELOG.md | 11 + plugins/code-climate/package.json | 2 +- plugins/code-coverage-backend/CHANGELOG.md | 15 + plugins/code-coverage-backend/package.json | 2 +- plugins/code-coverage/CHANGELOG.md | 12 + plugins/code-coverage/package.json | 2 +- plugins/codescene/CHANGELOG.md | 12 + plugins/codescene/package.json | 2 +- plugins/config-schema/CHANGELOG.md | 11 + plugins/config-schema/package.json | 2 +- plugins/cost-insights/CHANGELOG.md | 14 + plugins/cost-insights/package.json | 2 +- plugins/devtools-backend/CHANGELOG.md | 18 + plugins/devtools-backend/package.json | 2 +- plugins/devtools-common/CHANGELOG.md | 8 + plugins/devtools-common/package.json | 2 +- plugins/devtools/CHANGELOG.md | 12 + plugins/devtools/package.json | 2 +- plugins/dynatrace/CHANGELOG.md | 11 + plugins/dynatrace/package.json | 2 +- plugins/entity-feedback-backend/CHANGELOG.md | 14 + plugins/entity-feedback-backend/package.json | 2 +- plugins/entity-feedback/CHANGELOG.md | 13 + plugins/entity-feedback/package.json | 2 +- plugins/entity-validation/CHANGELOG.md | 14 + plugins/entity-validation/package.json | 2 +- .../CHANGELOG.md | 18 + .../package.json | 2 +- .../events-backend-module-azure/CHANGELOG.md | 10 + .../events-backend-module-azure/package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../events-backend-module-gerrit/CHANGELOG.md | 10 + .../events-backend-module-gerrit/package.json | 2 +- .../events-backend-module-github/CHANGELOG.md | 10 + .../events-backend-module-github/package.json | 2 +- .../events-backend-module-gitlab/CHANGELOG.md | 10 + .../events-backend-module-gitlab/package.json | 2 +- .../events-backend-test-utils/CHANGELOG.md | 7 + .../events-backend-test-utils/package.json | 2 +- plugins/events-backend/CHANGELOG.md | 12 + plugins/events-backend/package.json | 2 +- plugins/events-node/CHANGELOG.md | 7 + plugins/events-node/package.json | 2 +- .../example-todo-list-backend/CHANGELOG.md | 10 + .../example-todo-list-backend/package.json | 2 +- plugins/example-todo-list-common/CHANGELOG.md | 7 + plugins/example-todo-list-common/package.json | 2 +- plugins/example-todo-list/CHANGELOG.md | 8 + plugins/example-todo-list/package.json | 2 +- plugins/explore-backend/CHANGELOG.md | 12 + plugins/explore-backend/package.json | 2 +- plugins/explore-react/CHANGELOG.md | 9 + plugins/explore-react/package.json | 2 +- plugins/explore/CHANGELOG.md | 17 + plugins/explore/package.json | 2 +- plugins/firehydrant/CHANGELOG.md | 11 + plugins/firehydrant/package.json | 2 +- plugins/fossa/CHANGELOG.md | 12 + plugins/fossa/package.json | 2 +- plugins/gcalendar/CHANGELOG.md | 10 + plugins/gcalendar/package.json | 2 +- plugins/gcp-projects/CHANGELOG.md | 9 + plugins/gcp-projects/package.json | 2 +- plugins/git-release-manager/CHANGELOG.md | 10 + plugins/git-release-manager/package.json | 2 +- plugins/github-actions/CHANGELOG.md | 13 + plugins/github-actions/package.json | 2 +- plugins/github-deployments/CHANGELOG.md | 14 + plugins/github-deployments/package.json | 2 +- plugins/github-issues/CHANGELOG.md | 14 + plugins/github-issues/package.json | 2 +- .../github-pull-requests-board/CHANGELOG.md | 12 + .../github-pull-requests-board/package.json | 2 +- plugins/gitops-profiles/CHANGELOG.md | 9 + plugins/gitops-profiles/package.json | 2 +- plugins/gocd/CHANGELOG.md | 12 + plugins/gocd/package.json | 2 +- plugins/graphiql/CHANGELOG.md | 11 + plugins/graphiql/package.json | 2 +- plugins/graphql-voyager/CHANGELOG.md | 9 + plugins/graphql-voyager/package.json | 2 +- plugins/home-react/CHANGELOG.md | 13 + plugins/home-react/package.json | 2 +- plugins/home/CHANGELOG.md | 21 + plugins/home/package.json | 2 +- plugins/ilert/CHANGELOG.md | 12 + plugins/ilert/package.json | 2 +- plugins/jenkins-backend/CHANGELOG.md | 18 + plugins/jenkins-backend/package.json | 2 +- plugins/jenkins-common/CHANGELOG.md | 8 + plugins/jenkins-common/package.json | 2 +- plugins/jenkins/CHANGELOG.md | 13 + plugins/jenkins/package.json | 2 +- plugins/kafka-backend/CHANGELOG.md | 11 + plugins/kafka-backend/package.json | 2 +- plugins/kafka/CHANGELOG.md | 11 + plugins/kafka/package.json | 2 +- plugins/kubernetes-backend/CHANGELOG.md | 20 + plugins/kubernetes-backend/package.json | 2 +- plugins/kubernetes-cluster/CHANGELOG.md | 13 + plugins/kubernetes-cluster/package.json | 2 +- plugins/kubernetes-common/CHANGELOG.md | 10 + plugins/kubernetes-common/package.json | 2 +- plugins/kubernetes-node/CHANGELOG.md | 10 + plugins/kubernetes-node/package.json | 2 +- plugins/kubernetes-react/CHANGELOG.md | 16 + plugins/kubernetes-react/package.json | 2 +- plugins/kubernetes/CHANGELOG.md | 17 + plugins/kubernetes/package.json | 2 +- plugins/lighthouse-backend/CHANGELOG.md | 15 + plugins/lighthouse-backend/package.json | 2 +- plugins/lighthouse/CHANGELOG.md | 12 + plugins/lighthouse/package.json | 2 +- plugins/linguist-backend/CHANGELOG.md | 18 + plugins/linguist-backend/package.json | 2 +- plugins/linguist/CHANGELOG.md | 16 + plugins/linguist/package.json | 2 +- plugins/microsoft-calendar/CHANGELOG.md | 10 + plugins/microsoft-calendar/package.json | 2 +- plugins/newrelic-dashboard/CHANGELOG.md | 12 + plugins/newrelic-dashboard/package.json | 2 +- plugins/newrelic/CHANGELOG.md | 9 + plugins/newrelic/package.json | 2 +- plugins/nomad-backend/CHANGELOG.md | 11 + plugins/nomad-backend/package.json | 2 +- plugins/nomad/CHANGELOG.md | 11 + plugins/nomad/package.json | 2 +- plugins/octopus-deploy/CHANGELOG.md | 12 + plugins/octopus-deploy/package.json | 2 +- plugins/opencost/CHANGELOG.md | 9 + plugins/opencost/package.json | 2 +- plugins/org-react/CHANGELOG.md | 12 + plugins/org-react/package.json | 2 +- plugins/org/CHANGELOG.md | 12 + plugins/org/package.json | 2 +- plugins/pagerduty/CHANGELOG.md | 13 + plugins/pagerduty/package.json | 2 +- plugins/periskop-backend/CHANGELOG.md | 10 + plugins/periskop-backend/package.json | 2 +- plugins/periskop/CHANGELOG.md | 12 + plugins/periskop/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- plugins/permission-backend/CHANGELOG.md | 14 + plugins/permission-backend/package.json | 2 +- plugins/permission-common/CHANGELOG.md | 10 + plugins/permission-common/package.json | 2 +- plugins/permission-node/CHANGELOG.md | 13 + plugins/permission-node/package.json | 2 +- plugins/permission-react/CHANGELOG.md | 11 + plugins/permission-react/package.json | 2 +- plugins/playlist-backend/CHANGELOG.md | 17 + plugins/playlist-backend/package.json | 2 +- plugins/playlist-common/CHANGELOG.md | 7 + plugins/playlist-common/package.json | 2 +- plugins/playlist/CHANGELOG.md | 17 + plugins/playlist/package.json | 2 +- plugins/proxy-backend/CHANGELOG.md | 9 + plugins/proxy-backend/package.json | 2 +- plugins/puppetdb/CHANGELOG.md | 12 + plugins/puppetdb/package.json | 2 +- plugins/rollbar-backend/CHANGELOG.md | 8 + plugins/rollbar-backend/package.json | 2 +- plugins/rollbar/CHANGELOG.md | 11 + plugins/rollbar/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 10 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- .../CHANGELOG.md | 9 + .../package.json | 2 +- plugins/scaffolder-backend/CHANGELOG.md | 33 + plugins/scaffolder-backend/package.json | 2 +- plugins/scaffolder-common/CHANGELOG.md | 10 + plugins/scaffolder-common/package.json | 2 +- plugins/scaffolder-node/CHANGELOG.md | 13 + plugins/scaffolder-node/package.json | 2 +- plugins/scaffolder-react/CHANGELOG.md | 23 + plugins/scaffolder-react/package.json | 2 +- plugins/scaffolder/CHANGELOG.md | 25 + plugins/scaffolder/package.json | 2 +- .../CHANGELOG.md | 19 + .../package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../CHANGELOG.md | 14 + .../package.json | 2 +- plugins/search-backend-module-pg/CHANGELOG.md | 11 + plugins/search-backend-module-pg/package.json | 2 +- .../CHANGELOG.md | 13 + .../package.json | 2 +- .../CHANGELOG.md | 19 + .../package.json | 2 +- plugins/search-backend-node/CHANGELOG.md | 13 + plugins/search-backend-node/package.json | 2 +- plugins/search-backend/CHANGELOG.md | 18 + plugins/search-backend/package.json | 2 +- plugins/search-common/CHANGELOG.md | 8 + plugins/search-common/package.json | 2 +- plugins/search-react/CHANGELOG.md | 13 + plugins/search-react/package.json | 2 +- plugins/search/CHANGELOG.md | 17 + plugins/search/package.json | 2 +- plugins/sentry/CHANGELOG.md | 11 + plugins/sentry/package.json | 2 +- plugins/shortcuts/CHANGELOG.md | 11 + plugins/shortcuts/package.json | 2 +- plugins/sonarqube-backend/CHANGELOG.md | 11 + plugins/sonarqube-backend/package.json | 2 +- plugins/sonarqube-react/CHANGELOG.md | 8 + plugins/sonarqube-react/package.json | 2 +- plugins/sonarqube/CHANGELOG.md | 12 + plugins/sonarqube/package.json | 2 +- plugins/splunk-on-call/CHANGELOG.md | 11 + plugins/splunk-on-call/package.json | 2 +- plugins/stack-overflow-backend/CHANGELOG.md | 8 + plugins/stack-overflow-backend/package.json | 2 +- plugins/stack-overflow/CHANGELOG.md | 14 + plugins/stack-overflow/package.json | 2 +- plugins/stackstorm/CHANGELOG.md | 10 + plugins/stackstorm/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- plugins/tech-insights-backend/CHANGELOG.md | 15 + plugins/tech-insights-backend/package.json | 2 +- plugins/tech-insights-node/CHANGELOG.md | 11 + plugins/tech-insights-node/package.json | 2 +- plugins/tech-insights/CHANGELOG.md | 14 + plugins/tech-insights/package.json | 2 +- plugins/tech-radar/CHANGELOG.md | 11 + plugins/tech-radar/package.json | 2 +- .../techdocs-addons-test-utils/CHANGELOG.md | 16 + .../techdocs-addons-test-utils/package.json | 2 +- plugins/techdocs-backend/CHANGELOG.md | 18 + plugins/techdocs-backend/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- plugins/techdocs-node/CHANGELOG.md | 14 + plugins/techdocs-node/package.json | 2 +- plugins/techdocs-react/CHANGELOG.md | 12 + plugins/techdocs-react/package.json | 2 +- plugins/techdocs/CHANGELOG.md | 21 + plugins/techdocs/package.json | 2 +- plugins/todo-backend/CHANGELOG.md | 16 + plugins/todo-backend/package.json | 2 +- plugins/todo/CHANGELOG.md | 12 + plugins/todo/package.json | 2 +- plugins/user-settings-backend/CHANGELOG.md | 13 + plugins/user-settings-backend/package.json | 2 +- plugins/user-settings/CHANGELOG.md | 21 + plugins/user-settings/package.json | 2 +- plugins/vault-backend/CHANGELOG.md | 12 + plugins/vault-backend/package.json | 2 +- plugins/vault-node/CHANGELOG.md | 7 + plugins/vault-node/package.json | 2 +- plugins/vault/CHANGELOG.md | 12 + plugins/vault/package.json | 2 +- plugins/xcmetrics/CHANGELOG.md | 10 + plugins/xcmetrics/package.json | 2 +- yarn.lock | 361 +- 539 files changed, 6788 insertions(+), 1310 deletions(-) delete mode 100644 .changeset/afraid-mice-give.md delete mode 100644 .changeset/beige-pillows-repeat.md delete mode 100644 .changeset/blue-hats-admire.md delete mode 100644 .changeset/brave-ghosts-pay.md delete mode 100644 .changeset/brave-queens-crash.md delete mode 100644 .changeset/brave-shirts-hang.md delete mode 100644 .changeset/brown-planes-sort.md delete mode 100644 .changeset/calm-grapes-remember.md delete mode 100644 .changeset/chatty-rivers-hope.md delete mode 100644 .changeset/chilled-seahorses-clean.md delete mode 100644 .changeset/chilled-zebras-wash.md delete mode 100644 .changeset/clean-mails-bathe.md delete mode 100644 .changeset/clever-meals-drop.md delete mode 100644 .changeset/create-app-1703547661.md delete mode 100644 .changeset/create-app-1704804195.md delete mode 100644 .changeset/curvy-dingos-jump.md delete mode 100644 .changeset/eight-rice-cross.md delete mode 100644 .changeset/fair-spies-rescue.md delete mode 100644 .changeset/fast-tables-hammer.md delete mode 100644 .changeset/flat-terms-provide.md delete mode 100644 .changeset/fresh-mirrors-shake.md delete mode 100644 .changeset/friendly-horses-kneel.md delete mode 100644 .changeset/funny-rings-fry.md delete mode 100644 .changeset/giant-fans-type.md delete mode 100644 .changeset/gold-pianos-worry.md delete mode 100644 .changeset/great-adults-begin.md delete mode 100644 .changeset/green-dolphins-cover.md delete mode 100644 .changeset/happy-forks-jam.md delete mode 100644 .changeset/heavy-moose-reflect.md delete mode 100644 .changeset/hip-dancers-pay.md delete mode 100644 .changeset/large-pens-cough.md delete mode 100644 .changeset/large-poets-buy.md delete mode 100644 .changeset/lazy-teachers-walk.md delete mode 100644 .changeset/many-peaches-dress.md delete mode 100644 .changeset/new-plants-sort.md delete mode 100644 .changeset/ninety-impalas-knock.md delete mode 100644 .changeset/odd-ligers-return.md delete mode 100644 .changeset/olive-walls-wonder.md delete mode 100644 .changeset/olive-walls-wonder2.md delete mode 100644 .changeset/orange-planets-suffer.md delete mode 100644 .changeset/pre.json delete mode 100644 .changeset/quiet-oranges-bake.md delete mode 100644 .changeset/renovate-126fde4.md delete mode 100644 .changeset/renovate-91133b2.md delete mode 100644 .changeset/renovate-9647667.md delete mode 100644 .changeset/rich-poets-stare.md delete mode 100644 .changeset/rotten-tools-clean.md delete mode 100644 .changeset/shaggy-coins-happen.md delete mode 100644 .changeset/silent-horses-raise.md delete mode 100644 .changeset/silver-countries-notice.md delete mode 100644 .changeset/sixty-plums-switch.md delete mode 100644 .changeset/smooth-pumas-fold.md delete mode 100644 .changeset/sour-taxis-rush.md delete mode 100644 .changeset/stale-cars-attack.md delete mode 100644 .changeset/stale-hairs-sparkle.md delete mode 100644 .changeset/tender-roses-teach.md delete mode 100644 .changeset/thirty-cats-help.md delete mode 100644 .changeset/tricky-pans-explain.md delete mode 100644 .changeset/unlucky-bottles-run.md delete mode 100644 .changeset/weak-pans-accept.md create mode 100644 docs/releases/v1.22.0-changelog.md create mode 100644 plugins/app-visualizer/CHANGELOG.md diff --git a/.changeset/afraid-mice-give.md b/.changeset/afraid-mice-give.md deleted file mode 100644 index 8d6424f536..0000000000 --- a/.changeset/afraid-mice-give.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -Fixed an issue where some Okta's resolvers were missing diff --git a/.changeset/beige-pillows-repeat.md b/.changeset/beige-pillows-repeat.md deleted file mode 100644 index 0c0eb3f4fa..0000000000 --- a/.changeset/beige-pillows-repeat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-codescene': patch ---- - -Updated Readme document in codescene plugin diff --git a/.changeset/blue-hats-admire.md b/.changeset/blue-hats-admire.md deleted file mode 100644 index 0be0c7d25f..0000000000 --- a/.changeset/blue-hats-admire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Fix custom http resolvers for AsyncAPI widget. diff --git a/.changeset/brave-ghosts-pay.md b/.changeset/brave-ghosts-pay.md deleted file mode 100644 index d8981fa53b..0000000000 --- a/.changeset/brave-ghosts-pay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-pinniped-provider': patch ---- - -Deprecated the `authModulePinnipedProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));` diff --git a/.changeset/brave-queens-crash.md b/.changeset/brave-queens-crash.md deleted file mode 100644 index c28e5975f3..0000000000 --- a/.changeset/brave-queens-crash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-compat-api': patch ---- - -Make `convertLegacyApp` wrap discovered routes with `compatWrapper`. diff --git a/.changeset/brave-shirts-hang.md b/.changeset/brave-shirts-hang.md deleted file mode 100644 index 4fa7e4ef77..0000000000 --- a/.changeset/brave-shirts-hang.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Adding support for removing file from git index diff --git a/.changeset/brown-planes-sort.md b/.changeset/brown-planes-sort.md deleted file mode 100644 index 2291f950c0..0000000000 --- a/.changeset/brown-planes-sort.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Scaffolder form now shows a list of errors at the top of the form. diff --git a/.changeset/calm-grapes-remember.md b/.changeset/calm-grapes-remember.md deleted file mode 100644 index f21a074c74..0000000000 --- a/.changeset/calm-grapes-remember.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch ---- - -Exposed `createComponentRef`, and ensured that produced refs and feature bits have a `toString` for easier debugging diff --git a/.changeset/chatty-rivers-hope.md b/.changeset/chatty-rivers-hope.md deleted file mode 100644 index 97fdd644fe..0000000000 --- a/.changeset/chatty-rivers-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-sonarqube-backend': patch ---- - -Updated README diff --git a/.changeset/chilled-seahorses-clean.md b/.changeset/chilled-seahorses-clean.md deleted file mode 100644 index aa3ae4d062..0000000000 --- a/.changeset/chilled-seahorses-clean.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Fixed bug in Link where it was possible to select and copy a hidden element into clipboard diff --git a/.changeset/chilled-zebras-wash.md b/.changeset/chilled-zebras-wash.md deleted file mode 100644 index 9597915ce5..0000000000 --- a/.changeset/chilled-zebras-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings': patch ---- - -add user-settings declarative integration core nav item diff --git a/.changeset/clean-mails-bathe.md b/.changeset/clean-mails-bathe.md deleted file mode 100644 index c9afc34f90..0000000000 --- a/.changeset/clean-mails-bathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-dynamic-feature-service': minor ---- - -New `backend-dynamic-feature-service` package, for the discovery of dynamic frontend and backend plugins (and modules) and the loading of the backend ones inside the backend application. diff --git a/.changeset/clever-meals-drop.md b/.changeset/clever-meals-drop.md deleted file mode 100644 index 63ceb1a4d3..0000000000 --- a/.changeset/clever-meals-drop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Add permission check to Register Existing API button diff --git a/.changeset/create-app-1703547661.md b/.changeset/create-app-1703547661.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1703547661.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/create-app-1704804195.md b/.changeset/create-app-1704804195.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1704804195.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/curvy-dingos-jump.md b/.changeset/curvy-dingos-jump.md deleted file mode 100644 index 6b1c827e88..0000000000 --- a/.changeset/curvy-dingos-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-azure-sites': patch ---- - -Show Azure site tags in `EntityAzureSitesOverviewWidget`. diff --git a/.changeset/eight-rice-cross.md b/.changeset/eight-rice-cross.md deleted file mode 100644 index 1628276817..0000000000 --- a/.changeset/eight-rice-cross.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Do not call fetch directly but rather use `fetchResponse` facility diff --git a/.changeset/fair-spies-rescue.md b/.changeset/fair-spies-rescue.md deleted file mode 100644 index d7f1ea5275..0000000000 --- a/.changeset/fair-spies-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Ensure `teamReviewers` list is unique before calling API diff --git a/.changeset/fast-tables-hammer.md b/.changeset/fast-tables-hammer.md deleted file mode 100644 index 9ed5915073..0000000000 --- a/.changeset/fast-tables-hammer.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Use sha256 instead of md5 in build script cache key calculation - -Makes it possible to build on FIPS nodejs. diff --git a/.changeset/flat-terms-provide.md b/.changeset/flat-terms-provide.md deleted file mode 100644 index f7a22fa7ea..0000000000 --- a/.changeset/flat-terms-provide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch ---- - -Add Scaffolder custom action that creates GitLab issues called `gitlab:issues:create` diff --git a/.changeset/fresh-mirrors-shake.md b/.changeset/fresh-mirrors-shake.md deleted file mode 100644 index a722182986..0000000000 --- a/.changeset/fresh-mirrors-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-common': patch ---- - -Updated Template.v1beta3.schema.json, added a missing "presentation" field diff --git a/.changeset/friendly-horses-kneel.md b/.changeset/friendly-horses-kneel.md deleted file mode 100644 index ebc11a7deb..0000000000 --- a/.changeset/friendly-horses-kneel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': patch ---- - -Removed unnecessary `i18next` dependency. diff --git a/.changeset/funny-rings-fry.md b/.changeset/funny-rings-fry.md deleted file mode 100644 index 66daec0ffb..0000000000 --- a/.changeset/funny-rings-fry.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Use sha256 instead of md5 for hash key calculation in caches - -This can have a side effect of invalidating caches (when cache key was >250 characters) -This improves compliance with FIPS nodejs diff --git a/.changeset/giant-fans-type.md b/.changeset/giant-fans-type.md deleted file mode 100644 index 64f32423d5..0000000000 --- a/.changeset/giant-fans-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Fix for a step with no properties diff --git a/.changeset/gold-pianos-worry.md b/.changeset/gold-pianos-worry.md deleted file mode 100644 index 39095dbbd7..0000000000 --- a/.changeset/gold-pianos-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Fixed an issue where not passing a `value` to any of the action's permission conditions caused an error. diff --git a/.changeset/great-adults-begin.md b/.changeset/great-adults-begin.md deleted file mode 100644 index 697613afc0..0000000000 --- a/.changeset/great-adults-begin.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-openapi': patch ---- - -Add support for the new backend system. - -A new backend module for the catalog backend -was added and exported as `default`. - -You can use it with the new backend system like - -```ts title="packages/backend/src/index.ts" -backend.add(import('@backstage/plugin-catalog-backend-module-openapi')); -``` diff --git a/.changeset/green-dolphins-cover.md b/.changeset/green-dolphins-cover.md deleted file mode 100644 index 77c90e72f5..0000000000 --- a/.changeset/green-dolphins-cover.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket': patch -'@backstage/plugin-scaffolder-backend': minor ---- - -The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API diff --git a/.changeset/happy-forks-jam.md b/.changeset/happy-forks-jam.md deleted file mode 100644 index 3f48853311..0000000000 --- a/.changeset/happy-forks-jam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-user-settings': minor ---- - -Updated the user settings selector to use a select component that displays native language names instead of language codes if possible. diff --git a/.changeset/heavy-moose-reflect.md b/.changeset/heavy-moose-reflect.md deleted file mode 100644 index 011d3fc023..0000000000 --- a/.changeset/heavy-moose-reflect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-microsoft-provider': patch ---- - -Deprecated the `authModuleMicrosoftProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));` diff --git a/.changeset/hip-dancers-pay.md b/.changeset/hip-dancers-pay.md deleted file mode 100644 index b05a291f85..0000000000 --- a/.changeset/hip-dancers-pay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-octopus-deploy': patch ---- - -added install path and fixed import on plugin-octopus-deploy diff --git a/.changeset/large-pens-cough.md b/.changeset/large-pens-cough.md deleted file mode 100644 index 631a20aee2..0000000000 --- a/.changeset/large-pens-cough.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch -'@backstage/frontend-app-api': patch ---- - -Accepts sub route refs on the new `createPlugin` routes map. diff --git a/.changeset/large-poets-buy.md b/.changeset/large-poets-buy.md deleted file mode 100644 index f22ca7c6b8..0000000000 --- a/.changeset/large-poets-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-client': patch ---- - -Fix a bug in `getLocationByRef` that led to invalid backend calls diff --git a/.changeset/lazy-teachers-walk.md b/.changeset/lazy-teachers-walk.md deleted file mode 100644 index 92f9a63d1e..0000000000 --- a/.changeset/lazy-teachers-walk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Updated the OpenAPI template to export the `TypedResponse` interface so that client code can leverage it diff --git a/.changeset/many-peaches-dress.md b/.changeset/many-peaches-dress.md deleted file mode 100644 index 42a4d86b68..0000000000 --- a/.changeset/many-peaches-dress.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': patch -'@backstage/config-loader': patch -'@backstage/create-app': patch -'@backstage/repo-tools': patch -'@backstage/cli-node': patch ---- - -Removed `mock-fs` dev dependency. diff --git a/.changeset/new-plants-sort.md b/.changeset/new-plants-sort.md deleted file mode 100644 index 16521df3c9..0000000000 --- a/.changeset/new-plants-sort.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch -'@backstage/plugin-kubernetes': patch ---- - -Add `authuser` search parameter to GKE cluster link formatter in k8s plugin - -Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. diff --git a/.changeset/ninety-impalas-knock.md b/.changeset/ninety-impalas-knock.md deleted file mode 100644 index 78bd55dc1c..0000000000 --- a/.changeset/ninety-impalas-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-events-backend': patch ---- - -Update `README.md` diff --git a/.changeset/odd-ligers-return.md b/.changeset/odd-ligers-return.md deleted file mode 100644 index 6b7cdff593..0000000000 --- a/.changeset/odd-ligers-return.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-events-backend-module-bitbucket-cloud': patch -'@backstage/plugin-events-backend-module-gerrit': patch -'@backstage/plugin-events-backend-module-azure': patch ---- - -Add default exports for the new backend system and documentation. diff --git a/.changeset/olive-walls-wonder.md b/.changeset/olive-walls-wonder.md deleted file mode 100644 index db67697567..0000000000 --- a/.changeset/olive-walls-wonder.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/frontend-app-api': minor -'@backstage/frontend-plugin-api': minor ---- - -**BREAKING**: Renamed the `app/router` extension to `app/root`. diff --git a/.changeset/olive-walls-wonder2.md b/.changeset/olive-walls-wonder2.md deleted file mode 100644 index 6b1c447b94..0000000000 --- a/.changeset/olive-walls-wonder2.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-test-utils': patch ---- - -Updates to reflect the `app/router` extension having been renamed to `app/root`. diff --git a/.changeset/orange-planets-suffer.md b/.changeset/orange-planets-suffer.md deleted file mode 100644 index bc14a8cf8f..0000000000 --- a/.changeset/orange-planets-suffer.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-stack-overflow-collator': patch -'@backstage/plugin-search-backend-module-techdocs': patch -'@backstage/plugin-search-backend-module-catalog': patch -'@backstage/plugin-search-backend-module-explore': patch ---- - -Update wording to show that the backend system no longer is in alpha diff --git a/.changeset/pre.json b/.changeset/pre.json deleted file mode 100644 index 2ca69b284d..0000000000 --- a/.changeset/pre.json +++ /dev/null @@ -1,297 +0,0 @@ -{ - "mode": "exit", - "tag": "next", - "initialVersions": { - "example-app": "0.2.90", - "@backstage/app-defaults": "1.4.6", - "example-app-next": "0.0.4", - "app-next-example-plugin": "0.0.4", - "example-backend": "0.2.90", - "@backstage/backend-app-api": "0.5.9", - "@backstage/backend-common": "0.20.0", - "@backstage/backend-defaults": "0.2.8", - "@backstage/backend-dev-utils": "0.1.2", - "example-backend-next": "0.0.18", - "@backstage/backend-openapi-utils": "0.1.1", - "@backstage/backend-plugin-api": "0.6.8", - "@backstage/backend-plugin-manager": "0.0.4", - "@backstage/backend-tasks": "0.5.13", - "@backstage/backend-test-utils": "0.2.9", - "@backstage/catalog-client": "1.5.0", - "@backstage/catalog-model": "1.4.3", - "@backstage/cli": "0.25.0", - "@backstage/cli-common": "0.1.13", - "@backstage/cli-node": "0.2.1", - "@backstage/codemods": "0.1.46", - "@backstage/config": "1.1.1", - "@backstage/config-loader": "1.6.0", - "@backstage/core-app-api": "1.11.2", - "@backstage/core-compat-api": "0.1.0", - "@backstage/core-components": "0.13.9", - "@backstage/core-plugin-api": "1.8.1", - "@backstage/create-app": "0.5.8", - "@backstage/dev-utils": "1.0.25", - "e2e-test": "0.2.10", - "@backstage/e2e-test-utils": "0.1.0", - "@backstage/errors": "1.2.3", - "@backstage/eslint-plugin": "0.1.4", - "@backstage/frontend-app-api": "0.4.0", - "@backstage/frontend-plugin-api": "0.4.0", - "@backstage/frontend-test-utils": "0.1.0", - "@backstage/integration": "1.8.0", - "@backstage/integration-aws-node": "0.1.8", - "@backstage/integration-react": "1.1.22", - "@backstage/release-manifests": "0.0.11", - "@backstage/repo-tools": "0.5.0", - "@techdocs/cli": "1.8.0", - "techdocs-cli-embedded-app": "0.2.89", - "@backstage/test-utils": "1.4.6", - "@backstage/theme": "0.5.0", - "@backstage/types": "1.1.1", - "@backstage/version-bridge": "1.0.7", - "@backstage/plugin-adr": "0.6.11", - "@backstage/plugin-adr-backend": "0.4.5", - "@backstage/plugin-adr-common": "0.2.18", - "@backstage/plugin-airbrake": "0.3.28", - "@backstage/plugin-airbrake-backend": "0.3.5", - "@backstage/plugin-allure": "0.1.44", - "@backstage/plugin-analytics-module-ga": "0.1.36", - "@backstage/plugin-analytics-module-ga4": "0.1.7", - "@backstage/plugin-analytics-module-newrelic-browser": "0.0.5", - "@backstage/plugin-apache-airflow": "0.2.18", - "@backstage/plugin-api-docs": "0.10.2", - "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.5", - "@backstage/plugin-apollo-explorer": "0.1.18", - "@backstage/plugin-app-backend": "0.3.56", - "@backstage/plugin-app-node": "0.1.8", - "@backstage/plugin-auth-backend": "0.20.1", - "@backstage/plugin-auth-backend-module-atlassian-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.2", - "@backstage/plugin-auth-backend-module-github-provider": "0.1.5", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.5", - "@backstage/plugin-auth-backend-module-google-provider": "0.1.5", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.3", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.5", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.0", - "@backstage/plugin-auth-backend-module-okta-provider": "0.0.1", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.2", - "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.1.0", - "@backstage/plugin-auth-node": "0.4.2", - "@backstage/plugin-azure-devops": "0.3.10", - "@backstage/plugin-azure-devops-backend": "0.5.0", - "@backstage/plugin-azure-devops-common": "0.3.2", - "@backstage/plugin-azure-sites": "0.1.17", - "@backstage/plugin-azure-sites-backend": "0.1.18", - "@backstage/plugin-azure-sites-common": "0.1.1", - "@backstage/plugin-badges": "0.2.52", - "@backstage/plugin-badges-backend": "0.3.5", - "@backstage/plugin-bazaar": "0.2.20", - "@backstage/plugin-bazaar-backend": "0.3.6", - "@backstage/plugin-bitbucket-cloud-common": "0.2.15", - "@backstage/plugin-bitrise": "0.1.55", - "@backstage/plugin-catalog": "1.16.0", - "@backstage/plugin-catalog-backend": "1.16.0", - "@backstage/plugin-catalog-backend-module-aws": "0.3.2", - "@backstage/plugin-catalog-backend-module-azure": "0.1.27", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.1.1", - "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.23", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.23", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.21", - "@backstage/plugin-catalog-backend-module-gcp": "0.1.8", - "@backstage/plugin-catalog-backend-module-gerrit": "0.1.24", - "@backstage/plugin-catalog-backend-module-github": "0.4.6", - "@backstage/plugin-catalog-backend-module-github-org": "0.1.2", - "@backstage/plugin-catalog-backend-module-gitlab": "0.3.5", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.12", - "@backstage/plugin-catalog-backend-module-ldap": "0.5.23", - "@backstage/plugin-catalog-backend-module-msgraph": "0.5.15", - "@backstage/plugin-catalog-backend-module-openapi": "0.1.25", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.13", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.5", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.3.5", - "@backstage/plugin-catalog-common": "1.0.19", - "@backstage/plugin-catalog-graph": "0.3.2", - "@backstage/plugin-catalog-import": "0.10.4", - "@backstage/plugin-catalog-node": "1.6.0", - "@backstage/plugin-catalog-react": "1.9.2", - "@backstage/plugin-catalog-unprocessed-entities": "0.1.6", - "@backstage/plugin-cicd-statistics": "0.1.30", - "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.24", - "@backstage/plugin-circleci": "0.3.28", - "@backstage/plugin-cloudbuild": "0.3.28", - "@backstage/plugin-code-climate": "0.1.28", - "@backstage/plugin-code-coverage": "0.2.21", - "@backstage/plugin-code-coverage-backend": "0.2.22", - "@backstage/plugin-codescene": "0.1.20", - "@backstage/plugin-config-schema": "0.1.48", - "@backstage/plugin-cost-insights": "0.12.17", - "@backstage/plugin-cost-insights-common": "0.1.2", - "@backstage/plugin-devtools": "0.1.7", - "@backstage/plugin-devtools-backend": "0.2.5", - "@backstage/plugin-devtools-common": "0.1.7", - "@backstage/plugin-dynatrace": "8.0.2", - "@backstage/plugin-entity-feedback": "0.2.11", - "@backstage/plugin-entity-feedback-backend": "0.2.5", - "@backstage/plugin-entity-feedback-common": "0.1.3", - "@backstage/plugin-entity-validation": "0.1.13", - "@backstage/plugin-events-backend": "0.2.17", - "@backstage/plugin-events-backend-module-aws-sqs": "0.2.11", - "@backstage/plugin-events-backend-module-azure": "0.1.18", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.18", - "@backstage/plugin-events-backend-module-gerrit": "0.1.18", - "@backstage/plugin-events-backend-module-github": "0.1.18", - "@backstage/plugin-events-backend-module-gitlab": "0.1.18", - "@backstage/plugin-events-backend-test-utils": "0.1.18", - "@backstage/plugin-events-node": "0.2.17", - "@internal/plugin-todo-list": "1.0.20", - "@internal/plugin-todo-list-backend": "1.0.20", - "@internal/plugin-todo-list-common": "1.0.16", - "@backstage/plugin-explore": "0.4.14", - "@backstage/plugin-explore-backend": "0.0.18", - "@backstage/plugin-explore-common": "0.0.2", - "@backstage/plugin-explore-react": "0.0.34", - "@backstage/plugin-firehydrant": "0.2.12", - "@backstage/plugin-fossa": "0.2.60", - "@backstage/plugin-gcalendar": "0.3.21", - "@backstage/plugin-gcp-projects": "0.3.44", - "@backstage/plugin-git-release-manager": "0.3.40", - "@backstage/plugin-github-actions": "0.6.9", - "@backstage/plugin-github-deployments": "0.1.59", - "@backstage/plugin-github-issues": "0.2.17", - "@backstage/plugin-github-pull-requests-board": "0.1.22", - "@backstage/plugin-gitops-profiles": "0.3.43", - "@backstage/plugin-gocd": "0.1.34", - "@backstage/plugin-graphiql": "0.3.1", - "@backstage/plugin-graphql-voyager": "0.1.10", - "@backstage/plugin-home": "0.6.0", - "@backstage/plugin-home-react": "0.1.6", - "@backstage/plugin-ilert": "0.2.17", - "@backstage/plugin-jenkins": "0.9.3", - "@backstage/plugin-jenkins-backend": "0.3.2", - "@backstage/plugin-jenkins-common": "0.1.22", - "@backstage/plugin-kafka": "0.3.28", - "@backstage/plugin-kafka-backend": "0.3.6", - "@backstage/plugin-kubernetes": "0.11.3", - "@backstage/plugin-kubernetes-backend": "0.14.0", - "@backstage/plugin-kubernetes-cluster": "0.0.4", - "@backstage/plugin-kubernetes-common": "0.7.2", - "@backstage/plugin-kubernetes-node": "0.1.2", - "@backstage/plugin-kubernetes-react": "0.2.0", - "@backstage/plugin-lighthouse": "0.4.13", - "@backstage/plugin-lighthouse-backend": "0.4.0", - "@backstage/plugin-lighthouse-common": "0.1.4", - "@backstage/plugin-linguist": "0.1.13", - "@backstage/plugin-linguist-backend": "0.5.5", - "@backstage/plugin-linguist-common": "0.1.2", - "@backstage/plugin-microsoft-calendar": "0.1.10", - "@backstage/plugin-newrelic": "0.3.43", - "@backstage/plugin-newrelic-dashboard": "0.3.3", - "@backstage/plugin-nomad": "0.1.9", - "@backstage/plugin-nomad-backend": "0.1.10", - "@backstage/plugin-octopus-deploy": "0.2.10", - "@backstage/plugin-opencost": "0.2.3", - "@backstage/plugin-org": "0.6.18", - "@backstage/plugin-org-react": "0.1.17", - "@backstage/plugin-pagerduty": "0.7.0", - "@backstage/plugin-periskop": "0.1.26", - "@backstage/plugin-periskop-backend": "0.2.6", - "@backstage/plugin-permission-backend": "0.5.31", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.5", - "@backstage/plugin-permission-common": "0.7.11", - "@backstage/plugin-permission-node": "0.7.19", - "@backstage/plugin-permission-react": "0.4.18", - "@backstage/plugin-playlist": "0.2.2", - "@backstage/plugin-playlist-backend": "0.3.12", - "@backstage/plugin-playlist-common": "0.1.13", - "@backstage/plugin-proxy-backend": "0.4.6", - "@backstage/plugin-puppetdb": "0.1.11", - "@backstage/plugin-rollbar": "0.4.28", - "@backstage/plugin-rollbar-backend": "0.1.53", - "@backstage/plugin-scaffolder": "1.17.0", - "@backstage/plugin-scaffolder-backend": "1.19.2", - "@backstage/plugin-scaffolder-backend-module-azure": "0.1.0", - "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.1.0", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.9", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.32", - "@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.0", - "@backstage/plugin-scaffolder-backend-module-github": "0.1.0", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.2.11", - "@backstage/plugin-scaffolder-backend-module-rails": "0.4.25", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.16", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.29", - "@backstage/plugin-scaffolder-common": "1.4.4", - "@backstage/plugin-scaffolder-node": "0.2.9", - "@backstage/plugin-scaffolder-react": "1.7.0", - "@backstage/plugin-search": "1.4.4", - "@backstage/plugin-search-backend": "1.4.8", - "@backstage/plugin-search-backend-module-catalog": "0.1.12", - "@backstage/plugin-search-backend-module-elasticsearch": "1.3.11", - "@backstage/plugin-search-backend-module-explore": "0.1.12", - "@backstage/plugin-search-backend-module-pg": "0.5.17", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.1", - "@backstage/plugin-search-backend-module-techdocs": "0.1.12", - "@backstage/plugin-search-backend-node": "1.2.12", - "@backstage/plugin-search-common": "1.2.9", - "@backstage/plugin-search-react": "1.7.4", - "@backstage/plugin-sentry": "0.5.13", - "@backstage/plugin-shortcuts": "0.3.17", - "@backstage/plugin-sonarqube": "0.7.10", - "@backstage/plugin-sonarqube-backend": "0.2.10", - "@backstage/plugin-sonarqube-react": "0.1.11", - "@backstage/plugin-splunk-on-call": "0.4.17", - "@backstage/plugin-stack-overflow": "0.1.23", - "@backstage/plugin-stack-overflow-backend": "0.2.12", - "@backstage/plugin-stackstorm": "0.1.9", - "@backstage/plugin-tech-insights": "0.3.20", - "@backstage/plugin-tech-insights-backend": "0.5.22", - "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.40", - "@backstage/plugin-tech-insights-common": "0.2.12", - "@backstage/plugin-tech-insights-node": "0.4.14", - "@backstage/plugin-tech-radar": "0.6.11", - "@backstage/plugin-techdocs": "1.9.2", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.25", - "@backstage/plugin-techdocs-backend": "1.9.1", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.3", - "@backstage/plugin-techdocs-node": "1.11.0", - "@backstage/plugin-techdocs-react": "1.1.14", - "@backstage/plugin-todo": "0.2.32", - "@backstage/plugin-todo-backend": "0.3.6", - "@backstage/plugin-user-settings": "0.7.14", - "@backstage/plugin-user-settings-backend": "0.2.7", - "@backstage/plugin-vault": "0.1.23", - "@backstage/plugin-vault-backend": "0.4.1", - "@backstage/plugin-vault-node": "0.1.1", - "@backstage/plugin-visualizer": "0.0.1", - "@backstage/plugin-xcmetrics": "0.2.46" - }, - "changesets": [ - "afraid-mice-give", - "brave-queens-crash", - "brown-planes-sort", - "chatty-rivers-hope", - "chilled-seahorses-clean", - "chilled-zebras-wash", - "create-app-1703547661", - "create-app-1704804195", - "curvy-dingos-jump", - "fast-tables-hammer", - "friendly-horses-kneel", - "funny-rings-fry", - "gold-pianos-worry", - "happy-forks-jam", - "hip-dancers-pay", - "large-poets-buy", - "lazy-teachers-walk", - "many-peaches-dress", - "new-plants-sort", - "orange-planets-suffer", - "quiet-oranges-bake", - "renovate-126fde4", - "renovate-91133b2", - "renovate-9647667", - "rotten-tools-clean", - "sour-taxis-rush", - "stale-hairs-sparkle", - "tricky-pans-explain" - ] -} diff --git a/.changeset/quiet-oranges-bake.md b/.changeset/quiet-oranges-bake.md deleted file mode 100644 index a7360c9e4a..0000000000 --- a/.changeset/quiet-oranges-bake.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch -'@backstage/frontend-test-utils': patch -'@backstage/backend-plugin-api': patch -'@backstage/backend-dev-utils': patch -'@backstage/backend-defaults': patch -'@backstage/frontend-app-api': patch -'@backstage/backend-app-api': patch ---- - -Updated README to reflect release status diff --git a/.changeset/renovate-126fde4.md b/.changeset/renovate-126fde4.md deleted file mode 100644 index 409d509e8b..0000000000 --- a/.changeset/renovate-126fde4.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-github-issues': patch -'@backstage/plugin-scaffolder-backend-module-github': patch ---- - -Updated dependency `octokit` to `^3.0.0`. diff --git a/.changeset/renovate-91133b2.md b/.changeset/renovate-91133b2.md deleted file mode 100644 index 6f5b1b1bee..0000000000 --- a/.changeset/renovate-91133b2.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/plugin-home-react': patch -'@backstage/plugin-home': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-scaffolder': patch ---- - -Updated dependency `@rjsf/utils` to `5.15.1`. -Updated dependency `@rjsf/core` to `5.15.1`. -Updated dependency `@rjsf/material-ui` to `5.15.1`. -Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. diff --git a/.changeset/renovate-9647667.md b/.changeset/renovate-9647667.md deleted file mode 100644 index 7d13035ecb..0000000000 --- a/.changeset/renovate-9647667.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-azure-devops-backend': patch -'@backstage/plugin-scaffolder-backend-module-azure': patch ---- - -Updated dependency `azure-devops-node-api` to `^12.0.0`. diff --git a/.changeset/rich-poets-stare.md b/.changeset/rich-poets-stare.md deleted file mode 100644 index 3c6f9a5035..0000000000 --- a/.changeset/rich-poets-stare.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch -'@backstage/plugin-scaffolder-backend': minor ---- - -Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request diff --git a/.changeset/rotten-tools-clean.md b/.changeset/rotten-tools-clean.md deleted file mode 100644 index 192c3a057b..0000000000 --- a/.changeset/rotten-tools-clean.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': patch -'@backstage/plugin-catalog-backend-module-scaffolder-entity-model': patch -'@backstage/plugin-permission-backend-module-allow-all-policy': patch -'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': patch -'@backstage/plugin-auth-backend-module-vmware-cloud-provider': patch -'@backstage/plugin-catalog-backend-module-backstage-openapi': patch -'@backstage/plugin-auth-backend-module-atlassian-provider': patch -'@backstage/plugin-auth-backend-module-microsoft-provider': patch -'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch -'@backstage/plugin-auth-backend-module-pinniped-provider': patch -'@backstage/plugin-events-backend-module-bitbucket-cloud': patch -'@backstage/plugin-auth-backend-module-gcp-iap-provider': patch -'@backstage/plugin-auth-backend-module-github-provider': patch -'@backstage/plugin-auth-backend-module-gitlab-provider': patch -'@backstage/plugin-auth-backend-module-google-provider': patch -'@backstage/plugin-auth-backend-module-oauth2-provider': patch -'@backstage/plugin-tech-insights-backend-module-jsonfc': patch -'@backstage/plugin-analytics-module-newrelic-browser': patch -'@backstage/plugin-auth-backend-module-okta-provider': patch -'@backstage/plugin-catalog-backend-module-bitbucket': patch -'@backstage/plugin-scaffolder-backend-module-yeoman': patch -'@backstage/plugin-techdocs-module-addons-contrib': patch -'@backstage/plugin-catalog-backend-module-gerrit': patch -'@backstage/plugin-catalog-backend-module-azure': patch -'@backstage/plugin-catalog-unprocessed-entities': patch -'@backstage/plugin-events-backend-module-gerrit': patch -'@backstage/plugin-events-backend-module-github': patch -'@backstage/plugin-events-backend-module-gitlab': patch -'@backstage/plugin-events-backend-module-azure': patch -'@backstage/plugin-catalog-backend-module-aws': patch -'@backstage/plugin-github-pull-requests-board': patch -'@backstage/plugin-techdocs-addons-test-utils': patch -'@backstage/plugin-entity-feedback-backend': patch -'@backstage/backend-openapi-utils': patch -'@backstage/plugin-stack-overflow-backend': patch -'@backstage/plugin-code-coverage-backend': patch -'@backstage/plugin-user-settings-backend': patch -'@backstage/frontend-plugin-api': patch -'@backstage/plugin-analytics-module-ga4': patch -'@backstage/plugin-azure-devops-backend': patch -'@backstage/plugin-analytics-module-ga': patch -'@backstage/plugin-azure-sites-backend': patch -'@backstage/plugin-git-release-manager': patch -'@backstage/plugin-github-deployments': patch -'@backstage/plugin-kubernetes-cluster': patch -'@backstage/plugin-microsoft-calendar': patch -'@backstage/plugin-newrelic-dashboard': patch -'@backstage/plugin-tech-insights-node': patch -'@backstage/plugin-entity-validation': patch -'@backstage/plugin-kubernetes-common': patch -'@backstage/plugin-airbrake-backend': patch -'@backstage/plugin-devtools-backend': patch -'@backstage/plugin-linguist-backend': patch -'@backstage/plugin-periskop-backend': patch -'@backstage/plugin-permission-react': patch -'@backstage/plugin-playlist-backend': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-techdocs-backend': patch -'@backstage/plugin-apollo-explorer': patch -'@backstage/plugin-entity-feedback': patch -'@backstage/plugin-explore-backend': patch -'@backstage/plugin-gitops-profiles': patch -'@backstage/plugin-graphql-voyager': patch -'@backstage/plugin-jenkins-backend': patch -'@backstage/plugin-apache-airflow': patch -'@backstage/plugin-badges-backend': patch -'@backstage/plugin-bazaar-backend': patch -'@backstage/plugin-github-actions': patch -'@backstage/plugin-octopus-deploy': patch -'@backstage/plugin-search-backend': patch -'@backstage/plugin-splunk-on-call': patch -'@backstage/plugin-stack-overflow': patch -'@backstage/plugin-techdocs-react': patch -'@backstage/plugin-catalog-graph': patch -'@backstage/plugin-catalog-react': patch -'@backstage/plugin-code-coverage': patch -'@backstage/plugin-config-schema': patch -'@backstage/plugin-cost-insights': patch -'@backstage/plugin-explore-react': patch -'@backstage/plugin-github-issues': patch -'@backstage/plugin-kafka-backend': patch -'@backstage/plugin-nomad-backend': patch -'@backstage/plugin-tech-insights': patch -'@backstage/plugin-user-settings': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-catalog-node': patch -'@backstage/plugin-code-climate': patch -'@backstage/plugin-gcp-projects': patch -'@backstage/plugin-todo-backend': patch -'@backstage/plugin-adr-backend': patch -'@backstage/plugin-app-backend': patch -'@backstage/plugin-azure-sites': patch -'@backstage/plugin-firehydrant': patch -'@backstage/plugin-cloudbuild': patch -'@backstage/plugin-home-react': patch -'@backstage/plugin-kubernetes': patch -'@backstage/plugin-lighthouse': patch -'@backstage/plugin-scaffolder': patch -'@backstage/plugin-stackstorm': patch -'@backstage/plugin-tech-radar': patch -'@backstage/plugin-codescene': patch -'@backstage/plugin-dynatrace': patch -'@backstage/plugin-gcalendar': patch -'@backstage/plugin-org-react': patch -'@backstage/plugin-pagerduty': patch -'@backstage/plugin-shortcuts': patch -'@backstage/plugin-sonarqube': patch -'@backstage/plugin-xcmetrics': patch -'@backstage/plugin-airbrake': patch -'@backstage/plugin-api-docs': patch -'@backstage/plugin-circleci': patch -'@backstage/plugin-devtools': patch -'@backstage/plugin-graphiql': patch -'@backstage/plugin-linguist': patch -'@backstage/plugin-newrelic': patch -'@backstage/plugin-opencost': patch -'@backstage/plugin-periskop': patch -'@backstage/plugin-playlist': patch -'@backstage/plugin-puppetdb': patch -'@backstage/plugin-techdocs': patch -'@backstage/plugin-bitrise': patch -'@backstage/plugin-catalog': patch -'@backstage/plugin-explore': patch -'@backstage/plugin-jenkins': patch -'@backstage/plugin-rollbar': patch -'@backstage/plugin-allure': patch -'@backstage/plugin-badges': patch -'@backstage/plugin-bazaar': patch -'@backstage/plugin-search': patch -'@backstage/plugin-sentry': patch -'@backstage/plugin-fossa': patch -'@backstage/plugin-ilert': patch -'@backstage/plugin-kafka': patch -'@backstage/plugin-nomad': patch -'@backstage/plugin-vault': patch -'@backstage/plugin-gocd': patch -'@backstage/plugin-home': patch -'@backstage/plugin-todo': patch -'@backstage/plugin-adr': patch -'@backstage/plugin-org': patch ---- - -Remove some unused dependencies diff --git a/.changeset/shaggy-coins-happen.md b/.changeset/shaggy-coins-happen.md deleted file mode 100644 index c20a8e0cb2..0000000000 --- a/.changeset/shaggy-coins-happen.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-events-backend-module-aws-sqs': patch ---- - -Fix errors when deleting SQS messages: - -- If zero messages were received, skip deletion to avoid `EmptyBatchRequest` error from the SQS client. -- If zero failures were returned from the SQS client during deletion, skip error logging. diff --git a/.changeset/silent-horses-raise.md b/.changeset/silent-horses-raise.md deleted file mode 100644 index a03d662b03..0000000000 --- a/.changeset/silent-horses-raise.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/frontend-plugin-api': patch -'@backstage/frontend-test-utils': patch -'@backstage/frontend-app-api': patch ---- - -Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). diff --git a/.changeset/silver-countries-notice.md b/.changeset/silver-countries-notice.md deleted file mode 100644 index 457042487b..0000000000 --- a/.changeset/silver-countries-notice.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': minor ---- - -Attaching extensions to an input that does not exist is now a warning rather than an error. diff --git a/.changeset/sixty-plums-switch.md b/.changeset/sixty-plums-switch.md deleted file mode 100644 index 8da07609c6..0000000000 --- a/.changeset/sixty-plums-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Show first scaffolder output text by default diff --git a/.changeset/smooth-pumas-fold.md b/.changeset/smooth-pumas-fold.md deleted file mode 100644 index 4a3540460b..0000000000 --- a/.changeset/smooth-pumas-fold.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Minor internal refactor diff --git a/.changeset/sour-taxis-rush.md b/.changeset/sour-taxis-rush.md deleted file mode 100644 index 1241cf3e8c..0000000000 --- a/.changeset/sour-taxis-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Removed unnecessary `history` and `immer` dependencies. diff --git a/.changeset/stale-cars-attack.md b/.changeset/stale-cars-attack.md deleted file mode 100644 index 431cc9232c..0000000000 --- a/.changeset/stale-cars-attack.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-events-backend-module-aws-sqs': patch -'@backstage/plugin-events-backend': patch ---- - -Add documentation on how to install the plugins with the new backend system. diff --git a/.changeset/stale-hairs-sparkle.md b/.changeset/stale-hairs-sparkle.md deleted file mode 100644 index 3db8e974ec..0000000000 --- a/.changeset/stale-hairs-sparkle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-aws': patch ---- - -Added status and e-mail as labels to the AWS Account Resource diff --git a/.changeset/tender-roses-teach.md b/.changeset/tender-roses-teach.md deleted file mode 100644 index 4d569917fb..0000000000 --- a/.changeset/tender-roses-teach.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-permission-backend': patch -'@backstage/plugin-permission-common': patch -'@backstage/plugin-permission-react': patch -'@backstage/plugin-permission-node': patch ---- - -Updated README diff --git a/.changeset/thirty-cats-help.md b/.changeset/thirty-cats-help.md deleted file mode 100644 index 9c5d24180d..0000000000 --- a/.changeset/thirty-cats-help.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Parse the URL using a different method rather than `git-url-parse` to support wildcards for URLs which are not VCS providers diff --git a/.changeset/tricky-pans-explain.md b/.changeset/tricky-pans-explain.md deleted file mode 100644 index 64b2bda1fe..0000000000 --- a/.changeset/tricky-pans-explain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-linguist': patch ---- - -Added alpha support for the New Frontend System (Declarative Integration) diff --git a/.changeset/unlucky-bottles-run.md b/.changeset/unlucky-bottles-run.md deleted file mode 100644 index 63c6ff1249..0000000000 --- a/.changeset/unlucky-bottles-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-app-visualizer': minor ---- - -Initial release of the app visualizer plugin. diff --git a/.changeset/weak-pans-accept.md b/.changeset/weak-pans-accept.md deleted file mode 100644 index 5e75f52058..0000000000 --- a/.changeset/weak-pans-accept.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/frontend-app-api': patch ---- - -add oauth dialog and alert display to the root elements diff --git a/docs/releases/v1.22.0-changelog.md b/docs/releases/v1.22.0-changelog.md new file mode 100644 index 0000000000..399d7e7016 --- /dev/null +++ b/docs/releases/v1.22.0-changelog.md @@ -0,0 +1,3239 @@ +# Release v1.22.0 + +## @backstage/backend-dynamic-feature-service@0.1.0 + +### Minor Changes + +- eb81f42: New `backend-dynamic-feature-service` package, for the discovery of dynamic frontend and backend plugins (and modules) and the loading of the backend ones inside the backend application. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/cli-node@0.2.2 + - @backstage/plugin-events-backend@0.2.18 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/frontend-app-api@0.5.0 + +### Minor Changes + +- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`. +- 074dfe3: Attaching extensions to an input that does not exist is now a warning rather than an error. + +### Patch Changes + +- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map. +- 516fd3e: Updated README to reflect release status +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- 5fe6600: add oauth dialog and alert display to the root elements +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/frontend-plugin-api@0.5.0 + +### Minor Changes + +- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`. + +### Patch Changes + +- b2d370e: Exposed `createComponentRef`, and ensured that produced refs and feature bits have a `toString` for easier debugging +- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map. +- 516fd3e: Updated README to reflect release status +- 4016f21: Remove some unused dependencies +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-app-visualizer@0.1.0 + +### Minor Changes + +- e57cc9f: Initial release of the app visualizer plugin. + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-scaffolder-backend@1.20.0 + +### Minor Changes + +- a694f71: The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API +- 7c522c5: Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request + +### Patch Changes + +- e9ab1c4: Fixed an issue where not passing a `value` to any of the action's permission conditions caused an error. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-user-settings@0.8.0 + +### Minor Changes + +- 56b2fb0: Updated the user settings selector to use a select component that displays native language names instead of language codes if possible. + +### Patch Changes + +- eea0849: add user-settings declarative integration core nav item +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/core-app-api@1.11.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/app-defaults@1.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## @backstage/backend-app-api@0.5.10 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/cli-node@0.2.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-common@0.20.1 + +### Patch Changes + +- 3b24eae: Adding support for removing file from git index + +- 454d17c: Do not call fetch directly but rather use `fetchResponse` facility + +- b6b15b2: Use sha256 instead of md5 for hash key calculation in caches + + This can have a side effect of invalidating caches (when cache key was >250 characters) + This improves compliance with FIPS nodejs + +- Updated dependencies + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-dev-utils@0.1.3 + - @backstage/backend-app-api@0.5.10 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + +## @backstage/backend-defaults@0.2.9 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-app-api@0.5.10 + +## @backstage/backend-dev-utils@0.1.3 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status + +## @backstage/backend-openapi-utils@0.1.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/errors@1.2.3 + +## @backstage/backend-plugin-api@0.6.9 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + +## @backstage/backend-tasks@0.5.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/backend-test-utils@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-app-api@0.5.10 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/catalog-client@1.5.2 + +### Patch Changes + +- 883782e: Fix a bug in `getLocationByRef` that led to invalid backend calls +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/cli@0.25.1 + +### Patch Changes + +- b6b15b2: Use sha256 instead of md5 in build script cache key calculation + + Makes it possible to build on FIPS nodejs. + +- Updated dependencies + - @backstage/config-loader@1.6.1 + - @backstage/cli-node@0.2.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4 + - @backstage/integration@1.8.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + +## @backstage/cli-node@0.2.2 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/config-loader@1.6.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/core-app-api@1.11.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-compat-api@0.1.1 + +### Patch Changes + +- 4c1f50c: Make `convertLegacyApp` wrap discovered routes with `compatWrapper`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-plugin-api@1.8.2 + - @backstage/core-app-api@1.11.3 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-components@0.13.10 + +### Patch Changes + +- d625f66: Fixed bug in Link where it was possible to select and copy a hidden element into clipboard +- 6878b1d: Removed unnecessary `history` and `immer` dependencies. +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/version-bridge@1.0.7 + +## @backstage/core-plugin-api@1.8.2 + +### Patch Changes + +- 6878b1d: Removed unnecessary `i18next` dependency. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/create-app@0.5.9 + +### Patch Changes + +- c9f71fb: Bumped create-app version. +- ac277f3: Bumped create-app version. +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + +## @backstage/dev-utils@1.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## @backstage/frontend-test-utils@0.1.1 + +### Patch Changes + +- f7566f9: Updates to reflect the `app/router` extension having been renamed to `app/root`. +- 516fd3e: Updated README to reflect release status +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/frontend-app-api@0.5.0 + - @backstage/test-utils@1.4.7 + - @backstage/types@1.1.1 + +## @backstage/integration-react@1.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + +## @backstage/repo-tools@0.5.2 + +### Patch Changes + +- 883782e: Updated the OpenAPI template to export the `TypedResponse` interface so that client code can leverage it +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/cli-node@0.2.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## @techdocs/cli@1.8.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + +## @backstage/test-utils@1.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-adr@0.6.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.19 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-adr-backend@0.4.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-adr-common@0.2.19 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-adr-common@0.2.19 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-airbrake@0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/dev-utils@1.0.26 + - @backstage/catalog-model@1.4.3 + - @backstage/test-utils@1.4.7 + +## @backstage/plugin-airbrake-backend@0.3.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## @backstage/plugin-allure@0.1.45 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-analytics-module-ga@0.1.37 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-ga4@0.1.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-analytics-module-newrelic-browser@0.0.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + +## @backstage/plugin-apache-airflow@0.2.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-api-docs@0.10.3 + +### Patch Changes + +- 8a69cc9: Fix custom http resolvers for AsyncAPI widget. +- 062b8f2: Add permission check to Register Existing API button +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-apollo-explorer@0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-app-backend@0.3.57 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.9 + +## @backstage/plugin-app-node@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + +## @backstage/plugin-auth-backend@0.20.3 + +### Patch Changes + +- 004499c: Fixed an issue where some Okta's resolvers were missing +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-auth-backend-module-github-provider@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-google-provider@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.1.4 + +### Patch Changes + +- 928efbc: Deprecated the `authModuleMicrosoftProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));` +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-auth-backend-module-okta-provider@0.0.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.1.3 + +### Patch Changes + +- 928efbc: Deprecated the `authModulePinnipedProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));` +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-auth-node@0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-azure-devops@0.3.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2 + +## @backstage/plugin-azure-devops-backend@0.5.1 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-azure-sites@0.1.18 + +### Patch Changes + +- a31f688: Show Azure site tags in `EntityAzureSitesOverviewWidget`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-azure-sites-backend@0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + +## @backstage/plugin-badges@0.2.53 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-badges-backend@0.3.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar@0.2.21 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-bazaar-backend@0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-bitrise@0.1.56 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog@1.16.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-catalog-backend@1.16.1 + +### Patch Changes + +- c3249d6: Parse the URL using a different method rather than `git-url-parse` to support wildcards for URLs which are not VCS providers +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-catalog-backend-module-aws@0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- 22e88d0: Added status and e-mail as labels to the AWS Account Resource +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-azure@0.1.28 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-catalog-backend-module-bitbucket@0.2.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.1.25 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-catalog-backend-module-github@0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-catalog-backend-module-github-org@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-catalog-backend-module-github@0.4.7 + - @backstage/config@1.1.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.4.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-catalog-backend-module-ldap@0.5.24 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-msgraph@0.5.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-openapi@0.1.26 + +### Patch Changes + +- 4ebf99b: Add support for the new backend system. + + A new backend module for the catalog backend + was added and exported as `default`. + + You can use it with the new backend system like + + ```ts title="packages/backend/src/index.ts" + backend.add(import('@backstage/plugin-catalog-backend-module-openapi')); + ``` + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-catalog-common@1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-catalog-graph@0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-catalog-import@0.10.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-node@1.6.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-react@1.9.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-catalog-unprocessed-entities@0.1.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-cicd-statistics@0.1.31 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cicd-statistics-module-gitlab@0.1.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-cicd-statistics@0.1.31 + +## @backstage/plugin-circleci@0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-cloudbuild@0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-climate@0.1.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-code-coverage@0.2.22 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-code-coverage-backend@0.2.23 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-codescene@0.1.21 + +### Patch Changes + +- d5eda61: Updated Readme document in codescene plugin +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-config-schema@0.1.49 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-cost-insights@0.12.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-cost-insights-common@0.1.2 + +## @backstage/plugin-devtools@0.1.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/errors@1.2.3 + - @backstage/plugin-devtools-common@0.1.8 + +## @backstage/plugin-devtools-backend@0.2.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.8 + +## @backstage/plugin-devtools-common@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/types@1.1.1 + +## @backstage/plugin-dynatrace@8.0.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-entity-feedback@0.2.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-feedback-backend@0.2.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + +## @backstage/plugin-entity-validation@0.1.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-events-backend@0.2.18 + +### Patch Changes + +- 92ea615: Update `README.md` +- d5ddc4e: Add documentation on how to install the plugins with the new backend system. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-aws-sqs@0.2.12 + +### Patch Changes + +- 7b8e551: Fix errors when deleting SQS messages: + + - If zero messages were received, skip deletion to avoid `EmptyBatchRequest` error from the SQS client. + - If zero failures were returned from the SQS client during deletion, skip error logging. + +- d5ddc4e: Add documentation on how to install the plugins with the new backend system. + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-azure@0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-gerrit@0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-github@0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-module-gitlab@0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-backend-test-utils@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18 + +## @backstage/plugin-events-node@0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + +## @backstage/plugin-explore@0.4.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-explore-react@0.0.35 + - @backstage/plugin-search-react@1.7.5 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-explore-backend@0.0.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-explore-react@0.0.35 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-explore-common@0.0.2 + +## @backstage/plugin-firehydrant@0.2.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-fossa@0.2.61 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcalendar@0.3.22 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## @backstage/plugin-gcp-projects@0.3.45 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-git-release-manager@0.3.41 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-actions@0.6.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-deployments@0.1.60 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-issues@0.2.18 + +### Patch Changes + +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-github-pull-requests-board@0.1.23 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-gitops-profiles@0.3.44 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-gocd@0.1.35 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-graphiql@0.3.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-graphql-voyager@0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-home@0.6.1 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + +## @backstage/plugin-home-react@0.1.7 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-ilert@0.2.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-jenkins@0.9.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.23 + +## @backstage/plugin-jenkins-backend@0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.23 + +## @backstage/plugin-jenkins-common@0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-kafka@0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kafka-backend@0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-kubernetes@0.11.4 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- 4016f21: Remove some unused dependencies + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-react@0.2.1 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kubernetes-backend@0.14.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-node@0.1.3 + +## @backstage/plugin-kubernetes-cluster@0.0.5 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-react@0.2.1 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-kubernetes-common@0.7.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-node@0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-kubernetes-react@0.2.1 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-lighthouse@0.4.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-lighthouse-backend@0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + +## @backstage/plugin-linguist@0.1.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- 4f42918: Added alpha support for the New Frontend System (Declarative Integration) +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-linguist-backend@0.5.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + +## @backstage/plugin-microsoft-calendar@0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## @backstage/plugin-newrelic@0.3.44 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-newrelic-dashboard@0.3.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-nomad@0.1.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-nomad-backend@0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-octopus-deploy@0.2.11 + +### Patch Changes + +- 7d96ba8: added install path and fixed import on plugin-octopus-deploy +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-opencost@0.2.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-org@0.6.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-org-react@0.1.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-pagerduty@0.7.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop@0.1.27 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-periskop-backend@0.2.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## @backstage/plugin-permission-backend@0.5.32 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + +## @backstage/plugin-permission-common@0.7.12 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-permission-node@0.7.20 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-permission-react@0.4.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- b1acd9b: Updated README +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/config@1.1.1 + +## @backstage/plugin-playlist@0.2.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-search-react@1.7.5 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-playlist-common@0.1.14 + +## @backstage/plugin-playlist-backend@0.3.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-playlist-common@0.1.14 + +## @backstage/plugin-playlist-common@0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + +## @backstage/plugin-proxy-backend@0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + +## @backstage/plugin-puppetdb@0.1.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-rollbar@0.4.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-rollbar-backend@0.1.54 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + +## @backstage/plugin-scaffolder@1.17.1 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- df4bc9d: Minor internal refactor +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-scaffolder-backend-module-azure@0.1.1 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1 + +### Patch Changes + +- a694f71: The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.2.33 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.1.1 + +### Patch Changes + +- 5470300: Ensure `teamReviewers` list is unique before calling API +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12 + +### Patch Changes + +- 604c9dd: Add Scaffolder custom action that creates GitLab issues called `gitlab:issues:create` +- 7c522c5: Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.4.26 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.2.30 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-common@1.4.5 + +### Patch Changes + +- 178b8d8: Updated Template.v1beta3.schema.json, added a missing "presentation" field +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-node@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-scaffolder-react@1.7.1 + +### Patch Changes + +- c28f281: Scaffolder form now shows a list of errors at the top of the form. +- 0b9ce2b: Fix for a step with no properties +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- d16f85f: Show first scaffolder output text by default +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-search@1.4.5 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend@1.4.9 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-catalog@0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-elasticsearch@1.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-explore@0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-pg@0.5.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-module-techdocs@0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-backend-node@1.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-search-common@1.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/types@1.1.1 + +## @backstage/plugin-search-react@1.7.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-sentry@0.5.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-shortcuts@0.3.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + +## @backstage/plugin-sonarqube@0.7.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-sonarqube-react@0.1.12 + +## @backstage/plugin-sonarqube-backend@0.2.11 + +### Patch Changes + +- 53445cd: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + +## @backstage/plugin-sonarqube-react@0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-splunk-on-call@0.4.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + +## @backstage/plugin-stack-overflow@0.1.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-search-react@1.7.5 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-stack-overflow-backend@0.2.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2 + +## @backstage/plugin-stackstorm@0.1.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## @backstage/plugin-tech-insights@0.3.21 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend@0.5.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-insights-node@0.4.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + +## @backstage/plugin-tech-radar@0.6.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @backstage/plugin-techdocs@1.9.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.26 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/core-app-api@1.11.3 + - @backstage/test-utils@1.4.7 + +## @backstage/plugin-techdocs-backend@1.9.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/integration-react@1.1.23 + - @backstage/integration@1.8.0 + +## @backstage/plugin-techdocs-node@1.11.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.10 + +## @backstage/plugin-techdocs-react@1.1.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/version-bridge@1.0.7 + +## @backstage/plugin-todo@0.2.33 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-todo-backend@0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + +## @backstage/plugin-user-settings-backend@0.2.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + +## @backstage/plugin-vault@0.1.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + +## @backstage/plugin-vault-backend@0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.2 + +## @backstage/plugin-vault-node@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + +## @backstage/plugin-xcmetrics@0.2.47 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + +## example-app@0.2.91 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.3 + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/core-components@0.13.10 + - @backstage/plugin-user-settings@0.8.0 + - @backstage/plugin-azure-sites@0.1.18 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-octopus-deploy@0.2.11 + - @backstage/frontend-app-api@0.5.0 + - @backstage/plugin-kubernetes@0.11.4 + - @backstage/plugin-home@0.6.1 + - @backstage/plugin-scaffolder@1.17.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7 + - @backstage/plugin-kubernetes-cluster@0.0.5 + - @backstage/plugin-microsoft-calendar@0.1.11 + - @backstage/plugin-newrelic-dashboard@0.3.4 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-entity-feedback@0.2.12 + - @backstage/plugin-apache-airflow@0.2.19 + - @backstage/plugin-github-actions@0.6.10 + - @backstage/plugin-stack-overflow@0.1.24 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-graph@0.3.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-code-coverage@0.2.22 + - @backstage/plugin-cost-insights@0.12.18 + - @backstage/plugin-tech-insights@0.3.21 + - @backstage/plugin-azure-devops@0.3.11 + - @backstage/plugin-gcp-projects@0.3.45 + - @backstage/plugin-cloudbuild@0.3.29 + - @backstage/plugin-lighthouse@0.4.14 + - @backstage/plugin-stackstorm@0.1.10 + - @backstage/plugin-tech-radar@0.6.12 + - @backstage/plugin-dynatrace@8.0.3 + - @backstage/plugin-gcalendar@0.3.22 + - @backstage/plugin-pagerduty@0.7.1 + - @backstage/plugin-shortcuts@0.3.18 + - @backstage/plugin-airbrake@0.3.29 + - @backstage/plugin-devtools@0.1.8 + - @backstage/plugin-graphiql@0.3.2 + - @backstage/plugin-linguist@0.1.14 + - @backstage/plugin-newrelic@0.3.44 + - @backstage/plugin-playlist@0.2.3 + - @backstage/plugin-puppetdb@0.1.12 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-explore@0.4.15 + - @backstage/plugin-jenkins@0.9.4 + - @backstage/plugin-rollbar@0.4.29 + - @backstage/plugin-badges@0.2.53 + - @backstage/plugin-search@1.4.5 + - @backstage/plugin-sentry@0.5.14 + - @backstage/plugin-kafka@0.3.29 + - @backstage/plugin-nomad@0.1.10 + - @backstage/plugin-gocd@0.1.35 + - @backstage/plugin-todo@0.2.33 + - @backstage/plugin-adr@0.6.12 + - @backstage/plugin-org@0.6.19 + - @backstage/plugin-catalog-import@0.10.5 + - @backstage/plugin-search-react@1.7.5 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.10 + +## example-app-next@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.3 + - @backstage/core-compat-api@0.1.1 + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/plugin-user-settings@0.8.0 + - @backstage/plugin-azure-sites@0.1.18 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-octopus-deploy@0.2.11 + - @backstage/frontend-app-api@0.5.0 + - @backstage/plugin-kubernetes@0.11.4 + - @backstage/plugin-home@0.6.1 + - @backstage/plugin-scaffolder@1.17.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7 + - @backstage/plugin-microsoft-calendar@0.1.11 + - @backstage/plugin-newrelic-dashboard@0.3.4 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-entity-feedback@0.2.12 + - @backstage/plugin-apache-airflow@0.2.19 + - @backstage/plugin-github-actions@0.6.10 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-graph@0.3.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-code-coverage@0.2.22 + - @backstage/plugin-cost-insights@0.12.18 + - @backstage/plugin-tech-insights@0.3.21 + - @backstage/plugin-azure-devops@0.3.11 + - @backstage/plugin-gcp-projects@0.3.45 + - @backstage/plugin-cloudbuild@0.3.29 + - @backstage/plugin-lighthouse@0.4.14 + - @backstage/plugin-stackstorm@0.1.10 + - @backstage/plugin-tech-radar@0.6.12 + - @backstage/plugin-dynatrace@8.0.3 + - @backstage/plugin-gcalendar@0.3.22 + - @backstage/plugin-pagerduty@0.7.1 + - @backstage/plugin-shortcuts@0.3.18 + - @backstage/plugin-airbrake@0.3.29 + - @backstage/plugin-devtools@0.1.8 + - @backstage/plugin-graphiql@0.3.2 + - @backstage/plugin-linguist@0.1.14 + - @backstage/plugin-newrelic@0.3.44 + - @backstage/plugin-playlist@0.2.3 + - @backstage/plugin-puppetdb@0.1.12 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-explore@0.4.15 + - @backstage/plugin-jenkins@0.9.4 + - @backstage/plugin-rollbar@0.4.29 + - @backstage/plugin-badges@0.2.53 + - @backstage/plugin-search@1.4.5 + - @backstage/plugin-sentry@0.5.14 + - @backstage/plugin-kafka@0.3.29 + - @backstage/plugin-gocd@0.1.35 + - @backstage/plugin-todo@0.2.33 + - @backstage/plugin-adr@0.6.12 + - @backstage/plugin-org@0.6.19 + - @backstage/plugin-app-visualizer@0.1.0 + - @backstage/plugin-catalog-import@0.10.5 + - app-next-example-plugin@0.0.5 + - @backstage/plugin-search-react@1.7.5 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.10 + +## app-next-example-plugin@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + +## example-backend@0.2.91 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.3 + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-backend@1.20.0 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10 + - @backstage/plugin-events-backend@0.2.18 + - @backstage/plugin-search-backend-module-techdocs@0.1.13 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/plugin-azure-devops-backend@0.5.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41 + - @backstage/plugin-entity-feedback-backend@0.2.6 + - @backstage/plugin-code-coverage-backend@0.2.23 + - @backstage/plugin-azure-sites-backend@0.1.19 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/plugin-devtools-backend@0.2.6 + - @backstage/plugin-linguist-backend@0.5.6 + - @backstage/plugin-playlist-backend@0.3.13 + - @backstage/plugin-techdocs-backend@1.9.2 + - @backstage/plugin-explore-backend@0.0.19 + - @backstage/plugin-jenkins-backend@0.3.3 + - @backstage/plugin-badges-backend@0.3.6 + - @backstage/plugin-search-backend@1.4.9 + - @backstage/plugin-kafka-backend@0.3.7 + - @backstage/plugin-nomad-backend@0.1.11 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-todo-backend@0.3.7 + - @backstage/plugin-adr-backend@0.4.6 + - @backstage/plugin-app-backend@0.3.57 + - @backstage/plugin-permission-backend@0.5.32 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-catalog-backend@1.16.1 + - example-app@0.2.91 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-kubernetes-backend@0.14.1 + - @backstage/plugin-lighthouse-backend@0.4.1 + - @backstage/plugin-proxy-backend@0.4.7 + - @backstage/plugin-rollbar-backend@0.1.54 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.26 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.12 + - @backstage/plugin-search-backend-module-pg@0.5.18 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/plugin-tech-insights-backend@0.5.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 + - @backstage/plugin-events-node@0.2.18 + - @backstage/plugin-search-common@1.2.10 + +## example-backend-next@0.0.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-sonarqube-backend@0.2.11 + - @backstage/plugin-scaffolder-backend@1.20.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.26 + - @backstage/plugin-search-backend-module-techdocs@0.1.13 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-defaults@0.2.9 + - @backstage/plugin-azure-devops-backend@0.5.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2 + - @backstage/plugin-entity-feedback-backend@0.2.6 + - @backstage/plugin-devtools-backend@0.2.6 + - @backstage/plugin-linguist-backend@0.5.6 + - @backstage/plugin-playlist-backend@0.3.13 + - @backstage/plugin-techdocs-backend@1.9.2 + - @backstage/plugin-jenkins-backend@0.3.3 + - @backstage/plugin-badges-backend@0.3.6 + - @backstage/plugin-search-backend@1.4.9 + - @backstage/plugin-nomad-backend@0.1.11 + - @backstage/plugin-todo-backend@0.3.7 + - @backstage/plugin-adr-backend@0.4.6 + - @backstage/plugin-app-backend@0.3.57 + - @backstage/plugin-permission-backend@0.5.32 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-kubernetes-backend@0.14.1 + - @backstage/plugin-lighthouse-backend@0.4.1 + - @backstage/plugin-proxy-backend@0.4.7 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 + +## e2e-test@0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + +## techdocs-cli-embedded-app@0.2.90 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/test-utils@1.4.7 + - @backstage/theme@0.5.0 + +## @internal/plugin-todo-list@1.0.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + +## @internal/plugin-todo-list-backend@1.0.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + +## @internal/plugin-todo-list-common@1.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 diff --git a/package.json b/package.json index 4d052f2ec5..483e02fdb5 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@material-ui/pickers@^3.3.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch", "@material-ui/pickers@^3.2.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch" }, - "version": "1.22.0-next.2", + "version": "1.22.0", "dependencies": { "@backstage/errors": "workspace:^", "@manypkg/get-packages": "^1.1.3", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 443c5fe4c6..5f815f4b0e 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/app-defaults +## 1.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + ## 1.4.7-next.1 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index 8634a73d47..bf7b56f8c2 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/app-defaults", "description": "Provides the default wiring of a Backstage App", - "version": "1.4.7-next.1", + "version": "1.4.7", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-next-example-plugin/CHANGELOG.md b/packages/app-next-example-plugin/CHANGELOG.md index a3c3157139..6f0545a801 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,13 @@ # app-next-example-plugin +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + ## 0.0.5-next.2 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index 3e7f665b77..c7669d93cb 100644 --- a/packages/app-next-example-plugin/package.json +++ b/packages/app-next-example-plugin/package.json @@ -1,7 +1,7 @@ { "name": "app-next-example-plugin", "description": "Backstage internal example plugin", - "version": "0.0.5-next.2", + "version": "0.0.5", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 3a4b1a2369..6272ef11df 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,81 @@ # example-app-next +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.3 + - @backstage/core-compat-api@0.1.1 + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/plugin-user-settings@0.8.0 + - @backstage/plugin-azure-sites@0.1.18 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-octopus-deploy@0.2.11 + - @backstage/frontend-app-api@0.5.0 + - @backstage/plugin-kubernetes@0.11.4 + - @backstage/plugin-home@0.6.1 + - @backstage/plugin-scaffolder@1.17.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7 + - @backstage/plugin-microsoft-calendar@0.1.11 + - @backstage/plugin-newrelic-dashboard@0.3.4 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-entity-feedback@0.2.12 + - @backstage/plugin-apache-airflow@0.2.19 + - @backstage/plugin-github-actions@0.6.10 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-graph@0.3.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-code-coverage@0.2.22 + - @backstage/plugin-cost-insights@0.12.18 + - @backstage/plugin-tech-insights@0.3.21 + - @backstage/plugin-azure-devops@0.3.11 + - @backstage/plugin-gcp-projects@0.3.45 + - @backstage/plugin-cloudbuild@0.3.29 + - @backstage/plugin-lighthouse@0.4.14 + - @backstage/plugin-stackstorm@0.1.10 + - @backstage/plugin-tech-radar@0.6.12 + - @backstage/plugin-dynatrace@8.0.3 + - @backstage/plugin-gcalendar@0.3.22 + - @backstage/plugin-pagerduty@0.7.1 + - @backstage/plugin-shortcuts@0.3.18 + - @backstage/plugin-airbrake@0.3.29 + - @backstage/plugin-devtools@0.1.8 + - @backstage/plugin-graphiql@0.3.2 + - @backstage/plugin-linguist@0.1.14 + - @backstage/plugin-newrelic@0.3.44 + - @backstage/plugin-playlist@0.2.3 + - @backstage/plugin-puppetdb@0.1.12 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-explore@0.4.15 + - @backstage/plugin-jenkins@0.9.4 + - @backstage/plugin-rollbar@0.4.29 + - @backstage/plugin-badges@0.2.53 + - @backstage/plugin-search@1.4.5 + - @backstage/plugin-sentry@0.5.14 + - @backstage/plugin-kafka@0.3.29 + - @backstage/plugin-gocd@0.1.35 + - @backstage/plugin-todo@0.2.33 + - @backstage/plugin-adr@0.6.12 + - @backstage/plugin-org@0.6.19 + - @backstage/plugin-app-visualizer@0.1.0 + - @backstage/plugin-catalog-import@0.10.5 + - app-next-example-plugin@0.0.5 + - @backstage/plugin-search-react@1.7.5 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.10 + ## 0.0.5-next.2 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index fe9b81f6db..c51631aaa3 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.5-next.2", + "version": "0.0.5", "private": true, "backstage": { "role": "frontend" diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 5cb183211c..6cf62774c1 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,81 @@ # example-app +## 0.2.91 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-api-docs@0.10.3 + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/core-components@0.13.10 + - @backstage/plugin-user-settings@0.8.0 + - @backstage/plugin-azure-sites@0.1.18 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-octopus-deploy@0.2.11 + - @backstage/frontend-app-api@0.5.0 + - @backstage/plugin-kubernetes@0.11.4 + - @backstage/plugin-home@0.6.1 + - @backstage/plugin-scaffolder@1.17.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.4 + - @backstage/plugin-catalog-unprocessed-entities@0.1.7 + - @backstage/plugin-kubernetes-cluster@0.0.5 + - @backstage/plugin-microsoft-calendar@0.1.11 + - @backstage/plugin-newrelic-dashboard@0.3.4 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-entity-feedback@0.2.12 + - @backstage/plugin-apache-airflow@0.2.19 + - @backstage/plugin-github-actions@0.6.10 + - @backstage/plugin-stack-overflow@0.1.24 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-graph@0.3.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-code-coverage@0.2.22 + - @backstage/plugin-cost-insights@0.12.18 + - @backstage/plugin-tech-insights@0.3.21 + - @backstage/plugin-azure-devops@0.3.11 + - @backstage/plugin-gcp-projects@0.3.45 + - @backstage/plugin-cloudbuild@0.3.29 + - @backstage/plugin-lighthouse@0.4.14 + - @backstage/plugin-stackstorm@0.1.10 + - @backstage/plugin-tech-radar@0.6.12 + - @backstage/plugin-dynatrace@8.0.3 + - @backstage/plugin-gcalendar@0.3.22 + - @backstage/plugin-pagerduty@0.7.1 + - @backstage/plugin-shortcuts@0.3.18 + - @backstage/plugin-airbrake@0.3.29 + - @backstage/plugin-devtools@0.1.8 + - @backstage/plugin-graphiql@0.3.2 + - @backstage/plugin-linguist@0.1.14 + - @backstage/plugin-newrelic@0.3.44 + - @backstage/plugin-playlist@0.2.3 + - @backstage/plugin-puppetdb@0.1.12 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-explore@0.4.15 + - @backstage/plugin-jenkins@0.9.4 + - @backstage/plugin-rollbar@0.4.29 + - @backstage/plugin-badges@0.2.53 + - @backstage/plugin-search@1.4.5 + - @backstage/plugin-sentry@0.5.14 + - @backstage/plugin-kafka@0.3.29 + - @backstage/plugin-nomad@0.1.10 + - @backstage/plugin-gocd@0.1.35 + - @backstage/plugin-todo@0.2.33 + - @backstage/plugin-adr@0.6.12 + - @backstage/plugin-org@0.6.19 + - @backstage/plugin-catalog-import@0.10.5 + - @backstage/plugin-search-react@1.7.5 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-linguist-common@0.1.2 + - @backstage/plugin-search-common@1.2.10 + ## 0.2.91-next.2 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 1d5ac94352..fbbe6ce09d 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.91-next.2", + "version": "0.2.91", "private": true, "backstage": { "role": "frontend" diff --git a/packages/backend-app-api/CHANGELOG.md b/packages/backend-app-api/CHANGELOG.md index 5790b020fb..16106ee354 100644 --- a/packages/backend-app-api/CHANGELOG.md +++ b/packages/backend-app-api/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/backend-app-api +## 0.5.10 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/cli-node@0.2.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.5.10-next.2 ### Patch Changes diff --git a/packages/backend-app-api/package.json b/packages/backend-app-api/package.json index 246da2e6a4..37fa2c5258 100644 --- a/packages/backend-app-api/package.json +++ b/packages/backend-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-app-api", "description": "Core API used by Backstage backend apps", - "version": "0.5.10-next.2", + "version": "0.5.10", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index b9a80e3841..de955b7ca1 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/backend-common +## 0.20.1 + +### Patch Changes + +- 3b24eae: Adding support for removing file from git index +- 454d17c: Do not call fetch directly but rather use `fetchResponse` facility +- b6b15b2: Use sha256 instead of md5 for hash key calculation in caches + + This can have a side effect of invalidating caches (when cache key was >250 characters) + This improves compliance with FIPS nodejs + +- Updated dependencies + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-dev-utils@0.1.3 + - @backstage/backend-app-api@0.5.10 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + ## 0.20.1-next.2 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 14670e42f8..3d746044b0 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-common", "description": "Common functionality library for Backstage backends", - "version": "0.20.1-next.2", + "version": "0.20.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index 7f8f81d706..b8bacd3732 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/backend-defaults +## 0.2.9 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-app-api@0.5.10 + ## 0.2.9-next.2 ### Patch Changes diff --git a/packages/backend-defaults/package.json b/packages/backend-defaults/package.json index 6315f2615a..73a54720f5 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-defaults", "description": "Backend defaults used by Backstage backend apps", - "version": "0.2.9-next.2", + "version": "0.2.9", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-dev-utils/CHANGELOG.md b/packages/backend-dev-utils/CHANGELOG.md index 0ff2ed6442..1c4deba50a 100644 --- a/packages/backend-dev-utils/CHANGELOG.md +++ b/packages/backend-dev-utils/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/backend-dev-utils +## 0.1.3 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status + ## 0.1.3-next.0 ### Patch Changes diff --git a/packages/backend-dev-utils/package.json b/packages/backend-dev-utils/package.json index a58c3ef6bd..67fd763dcd 100644 --- a/packages/backend-dev-utils/package.json +++ b/packages/backend-dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-dev-utils", - "version": "0.1.3-next.0", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index 07b118e771..4b80750865 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/backend-dynamic-feature-service +## 0.1.0 + +### Minor Changes + +- eb81f42: New `backend-dynamic-feature-service` package, for the discovery of dynamic frontend and backend plugins (and modules) and the loading of the backend ones inside the backend application. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/cli-node@0.2.2 + - @backstage/plugin-events-backend@0.2.18 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18 + - @backstage/plugin-search-common@1.2.10 + ## 0.0.5-next.2 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index cd95d6a5ae..18bbd58550 100644 --- a/packages/backend-dynamic-feature-service/package.json +++ b/packages/backend-dynamic-feature-service/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-dynamic-feature-service", "description": "Backstage dynamic feature service", - "version": "0.0.0", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-next/CHANGELOG.md b/packages/backend-next/CHANGELOG.md index 0cf0e0ec5c..96cb73808f 100644 --- a/packages/backend-next/CHANGELOG.md +++ b/packages/backend-next/CHANGELOG.md @@ -1,5 +1,46 @@ # example-backend-next +## 0.0.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-sonarqube-backend@0.2.11 + - @backstage/plugin-scaffolder-backend@1.20.0 + - @backstage/plugin-catalog-backend-module-openapi@0.1.26 + - @backstage/plugin-search-backend-module-techdocs@0.1.13 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-defaults@0.2.9 + - @backstage/plugin-azure-devops-backend@0.5.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.1.6 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.1.2 + - @backstage/plugin-entity-feedback-backend@0.2.6 + - @backstage/plugin-devtools-backend@0.2.6 + - @backstage/plugin-linguist-backend@0.5.6 + - @backstage/plugin-playlist-backend@0.3.13 + - @backstage/plugin-techdocs-backend@1.9.2 + - @backstage/plugin-jenkins-backend@0.3.3 + - @backstage/plugin-badges-backend@0.3.6 + - @backstage/plugin-search-backend@1.4.9 + - @backstage/plugin-nomad-backend@0.1.11 + - @backstage/plugin-todo-backend@0.3.7 + - @backstage/plugin-adr-backend@0.4.6 + - @backstage/plugin-app-backend@0.3.57 + - @backstage/plugin-permission-backend@0.5.32 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-kubernetes-backend@0.14.1 + - @backstage/plugin-lighthouse-backend@0.4.1 + - @backstage/plugin-proxy-backend@0.4.7 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 + ## 0.0.19-next.2 ### Patch Changes diff --git a/packages/backend-next/package.json b/packages/backend-next/package.json index a7bb842d76..d6908f6e78 100644 --- a/packages/backend-next/package.json +++ b/packages/backend-next/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-next", - "version": "0.0.19-next.2", + "version": "0.0.19", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index ab7900200a..9cbaa84947 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/backend-openapi-utils +## 0.1.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/errors@1.2.3 + ## 0.1.2-next.2 ### Patch Changes diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index 79c5d47bbd..2ca6c3b716 100644 --- a/packages/backend-openapi-utils/package.json +++ b/packages/backend-openapi-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-openapi-utils", "description": "OpenAPI typescript support.", - "version": "0.1.2-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index ff61277e52..80f9026e21 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/backend-plugin-api +## 0.6.9 + +### Patch Changes + +- 516fd3e: Updated README to reflect release status +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + ## 0.6.9-next.2 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 52ed558974..618a537bf5 100644 --- a/packages/backend-plugin-api/package.json +++ b/packages/backend-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-plugin-api", "description": "Core API used by Backstage backend plugins", - "version": "0.6.9-next.2", + "version": "0.6.9", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-tasks/CHANGELOG.md b/packages/backend-tasks/CHANGELOG.md index 8cf0bf8f5b..d107e5b51d 100644 --- a/packages/backend-tasks/CHANGELOG.md +++ b/packages/backend-tasks/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/backend-tasks +## 0.5.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.5.14-next.2 ### Patch Changes diff --git a/packages/backend-tasks/package.json b/packages/backend-tasks/package.json index 139c160bbf..4af6a3462a 100644 --- a/packages/backend-tasks/package.json +++ b/packages/backend-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-tasks", "description": "Common distributed task management library for Backstage backends", - "version": "0.5.14-next.2", + "version": "0.5.14", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index e9dbbaa15a..66870f7f01 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/backend-test-utils +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-app-api@0.5.10 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.10-next.2 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 00d4a98d40..8fcaff66ae 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/backend-test-utils", "description": "Test helpers library for Backstage backends", - "version": "0.2.10-next.2", + "version": "0.2.10", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index f333e0ee04..838b69f5ab 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,63 @@ # example-backend +## 0.2.91 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.20.3 + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-backend@1.20.0 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.2.10 + - @backstage/plugin-events-backend@0.2.18 + - @backstage/plugin-search-backend-module-techdocs@0.1.13 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/plugin-azure-devops-backend@0.5.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.41 + - @backstage/plugin-entity-feedback-backend@0.2.6 + - @backstage/plugin-code-coverage-backend@0.2.23 + - @backstage/plugin-azure-sites-backend@0.1.19 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/plugin-devtools-backend@0.2.6 + - @backstage/plugin-linguist-backend@0.5.6 + - @backstage/plugin-playlist-backend@0.3.13 + - @backstage/plugin-techdocs-backend@1.9.2 + - @backstage/plugin-explore-backend@0.0.19 + - @backstage/plugin-jenkins-backend@0.3.3 + - @backstage/plugin-badges-backend@0.3.6 + - @backstage/plugin-search-backend@1.4.9 + - @backstage/plugin-kafka-backend@0.3.7 + - @backstage/plugin-nomad-backend@0.1.11 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-todo-backend@0.3.7 + - @backstage/plugin-adr-backend@0.4.6 + - @backstage/plugin-app-backend@0.3.57 + - @backstage/plugin-permission-backend@0.5.32 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-catalog-backend@1.16.1 + - example-app@0.2.91 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-kubernetes-backend@0.14.1 + - @backstage/plugin-lighthouse-backend@0.4.1 + - @backstage/plugin-proxy-backend@0.4.7 + - @backstage/plugin-rollbar-backend@0.1.54 + - @backstage/plugin-scaffolder-backend-module-rails@0.4.26 + - @backstage/plugin-search-backend-module-elasticsearch@1.3.12 + - @backstage/plugin-search-backend-module-pg@0.5.18 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/plugin-tech-insights-backend@0.5.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.3.6 + - @backstage/plugin-events-node@0.2.18 + - @backstage/plugin-search-common@1.2.10 + ## 0.2.91-next.2 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index b5518dde56..4bcf627366 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.91-next.2", + "version": "0.2.91", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index b3e04958f9..78d126445e 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/catalog-client +## 1.5.2 + +### Patch Changes + +- 883782e: Fix a bug in `getLocationByRef` that led to invalid backend calls +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 1.5.2-next.0 ### Patch Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index f87d5aa221..cfa9399d97 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-client", "description": "An isomorphic client for the catalog backend", - "version": "1.5.2-next.0", + "version": "1.5.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index e7a70042c1..176785b2db 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/cli-node +## 0.2.2 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.2-next.0 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index 5d3fde9839..60ba687ddc 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-node", "description": "Node.js library for Backstage CLIs", - "version": "0.2.2-next.0", + "version": "0.2.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 13aa1c9a97..0c686ea8c4 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/cli +## 0.25.1 + +### Patch Changes + +- b6b15b2: Use sha256 instead of md5 in build script cache key calculation + + Makes it possible to build on FIPS nodejs. + +- Updated dependencies + - @backstage/config-loader@1.6.1 + - @backstage/cli-node@0.2.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/eslint-plugin@0.1.4 + - @backstage/integration@1.8.0 + - @backstage/release-manifests@0.0.11 + - @backstage/types@1.1.1 + ## 0.25.1-next.1 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 85de89c92a..a02e7474ff 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.25.1-next.1", + "version": "0.25.1", "publishConfig": { "access": "public" }, diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 7e2228f5a5..24f7a3addc 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/config-loader +## 1.6.1 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 1.6.1-next.0 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 17df3b1357..e26a54559c 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "1.6.1-next.0", + "version": "1.6.1", "publishConfig": { "access": "public", "main": "dist/index.cjs.js", diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index 7341335318..9e32db5016 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/core-app-api +## 1.11.3 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 1.11.3-next.0 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 05770f3eee..f0654f7596 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-app-api", "description": "Core app API used by Backstage apps", - "version": "1.11.3-next.0", + "version": "1.11.3", "publishConfig": { "access": "public" }, diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 50604d27db..21c7782627 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/core-compat-api +## 0.1.1 + +### Patch Changes + +- 4c1f50c: Make `convertLegacyApp` wrap discovered routes with `compatWrapper`. +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-plugin-api@1.8.2 + - @backstage/core-app-api@1.11.3 + - @backstage/version-bridge@1.0.7 + ## 0.1.1-next.2 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index 9869de1e60..99b705bfcf 100644 --- a/packages/core-compat-api/package.json +++ b/packages/core-compat-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-compat-api", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 2a84f778cb..c6ffec5679 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/core-components +## 0.13.10 + +### Patch Changes + +- d625f66: Fixed bug in Link where it was possible to select and copy a hidden element into clipboard +- 6878b1d: Removed unnecessary `history` and `immer` dependencies. +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/version-bridge@1.0.7 + ## 0.13.10-next.1 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index 25d7fe111c..70afda8983 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.13.10-next.1", + "version": "0.13.10", "publishConfig": { "access": "public" }, diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index bdc94c0f1e..4cb681e4aa 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/core-plugin-api +## 1.8.2 + +### Patch Changes + +- 6878b1d: Removed unnecessary `i18next` dependency. +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 1.8.2-next.0 ### Patch Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index b61bf9991d..d676260227 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-plugin-api", "description": "Core API used by Backstage plugins", - "version": "1.8.2-next.0", + "version": "1.8.2", "publishConfig": { "access": "public" }, diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 1c77f14254..3008a3a03d 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/create-app +## 0.5.9 + +### Patch Changes + +- c9f71fb: Bumped create-app version. +- ac277f3: Bumped create-app version. +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/cli-common@0.1.13 + ## 0.5.9-next.2 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index e68dea26f5..e9f73d6e1f 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.5.9-next.2", + "version": "0.5.9", "publishConfig": { "access": "public" }, diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index cbbd849093..602f2b563e 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/dev-utils +## 1.0.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + ## 1.0.26-next.2 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 74c548a5a4..40537c1a98 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "1.0.26-next.2", + "version": "1.0.26", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/packages/e2e-test/CHANGELOG.md b/packages/e2e-test/CHANGELOG.md index ef58183440..f130de43d4 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,14 @@ # e2e-test +## 0.2.11 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.9 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + ## 0.2.11-next.2 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 8999c53daa..40699588e2 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,7 +1,7 @@ { "name": "e2e-test", "description": "E2E test for verifying Backstage packages", - "version": "0.2.11-next.2", + "version": "0.2.11", "private": true, "backstage": { "role": "cli" diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index f6d98b7845..d7c7816449 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/frontend-app-api +## 0.5.0 + +### Minor Changes + +- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`. +- 074dfe3: Attaching extensions to an input that does not exist is now a warning rather than an error. + +### Patch Changes + +- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map. +- 516fd3e: Updated README to reflect release status +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- 5fe6600: add oauth dialog and alert display to the root elements +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 0.4.1-next.2 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index 25ab827d4a..440f0cdb3f 100644 --- a/packages/frontend-app-api/package.json +++ b/packages/frontend-app-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-app-api", - "version": "0.4.1-next.2", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index c02760f4e1..c6ae8056ec 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/frontend-plugin-api +## 0.5.0 + +### Minor Changes + +- d4149bf: **BREAKING**: Renamed the `app/router` extension to `app/root`. + +### Patch Changes + +- b2d370e: Exposed `createComponentRef`, and ensured that produced refs and feature bits have a `toString` for easier debugging +- 7d63b32: Accepts sub route refs on the new `createPlugin` routes map. +- 516fd3e: Updated README to reflect release status +- 4016f21: Remove some unused dependencies +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 0.4.1-next.2 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index 007d76764b..bc92f6f632 100644 --- a/packages/frontend-plugin-api/package.json +++ b/packages/frontend-plugin-api/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-plugin-api", - "version": "0.4.1-next.2", + "version": "0.5.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index 0d119d72fa..dc3555499e 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/frontend-test-utils +## 0.1.1 + +### Patch Changes + +- f7566f9: Updates to reflect the `app/router` extension having been renamed to `app/root`. +- 516fd3e: Updated README to reflect release status +- c97fa1c: Added `elements`, `wrappers`, and `router` inputs to `app/root`, that let you add things to the root of the React tree above the layout. You can use the `createAppRootElementExtension`, `createAppRootWrapperExtension`, and `createRouterExtension` extension creator, respectively, to conveniently create such extensions. These are all optional, and if you do not supply a router a default one will be used (`BrowserRouter` in regular runs, `MemoryRouter` in tests/CI). +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/frontend-app-api@0.5.0 + - @backstage/test-utils@1.4.7 + - @backstage/types@1.1.1 + ## 0.1.1-next.2 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index 141ce93e34..fbe9e3dec6 100644 --- a/packages/frontend-test-utils/package.json +++ b/packages/frontend-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-test-utils", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index cc58b79619..fd6a47e4e7 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/integration-react +## 1.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + ## 1.1.23-next.0 ### Patch Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index e916c24ed4..f1592628ab 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/integration-react", "description": "Frontend package for managing integrations towards external systems", - "version": "1.1.23-next.0", + "version": "1.1.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index a968648f1c..02ecf90bdc 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/repo-tools +## 0.5.2 + +### Patch Changes + +- 883782e: Updated the OpenAPI template to export the `TypedResponse` interface so that client code can leverage it +- 7acbb5a: Removed `mock-fs` dev dependency. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/cli-node@0.2.2 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/errors@1.2.3 + ## 0.5.2-next.2 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 1f46d1fe65..c8f832af01 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/repo-tools", "description": "CLI for Backstage repo tooling ", - "version": "0.5.2-next.2", + "version": "0.5.2", "publishConfig": { "access": "public" }, diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index ceacc30019..0e6163e1b7 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,24 @@ # techdocs-cli-embedded-app +## 0.2.90 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/cli@0.25.1 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/app-defaults@1.4.7 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/test-utils@1.4.7 + - @backstage/theme@0.5.0 + ## 0.2.90-next.2 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 2fb78763ac..8e30395052 100644 --- a/packages/techdocs-cli-embedded-app/package.json +++ b/packages/techdocs-cli-embedded-app/package.json @@ -1,6 +1,6 @@ { "name": "techdocs-cli-embedded-app", - "version": "0.2.90-next.2", + "version": "0.2.90", "private": true, "backstage": { "role": "frontend" diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index d0eddde367..f65ed4bd46 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,16 @@ # @techdocs/cli +## 1.8.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + ## 1.8.1-next.2 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 67d9de2012..4d4fc997b6 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.8.1-next.2", + "version": "1.8.1", "publishConfig": { "access": "public" }, diff --git a/packages/test-utils/CHANGELOG.md b/packages/test-utils/CHANGELOG.md index 9ab9643131..c4f342b554 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/test-utils +## 1.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/config@1.1.1 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + ## 1.4.7-next.1 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 5d3bb2ab4e..43b9c29a10 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "1.4.7-next.1", + "version": "1.4.7", "publishConfig": { "access": "public" }, diff --git a/plugins/adr-backend/CHANGELOG.md b/plugins/adr-backend/CHANGELOG.md index 81c3f3bce6..adc0cf284f 100644 --- a/plugins/adr-backend/CHANGELOG.md +++ b/plugins/adr-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-adr-backend +## 0.4.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-adr-common@0.2.19 + - @backstage/plugin-search-common@1.2.10 + ## 0.4.6-next.2 ### Patch Changes diff --git a/plugins/adr-backend/package.json b/plugins/adr-backend/package.json index cbd535acc0..24cebdff04 100644 --- a/plugins/adr-backend/package.json +++ b/plugins/adr-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr-backend", - "version": "0.4.6-next.2", + "version": "0.4.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr-common/CHANGELOG.md b/plugins/adr-common/CHANGELOG.md index 6f85feed2a..84c285a1a8 100644 --- a/plugins/adr-common/CHANGELOG.md +++ b/plugins/adr-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-adr-common +## 0.2.19 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-search-common@1.2.10 + ## 0.2.18 ### Patch Changes diff --git a/plugins/adr-common/package.json b/plugins/adr-common/package.json index 4e345cf19b..d05b585c7d 100644 --- a/plugins/adr-common/package.json +++ b/plugins/adr-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-adr-common", "description": "Common functionalities for the adr plugin", - "version": "0.2.18", + "version": "0.2.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/adr/CHANGELOG.md b/plugins/adr/CHANGELOG.md index 2d33b2db7c..8cf8b2c28e 100644 --- a/plugins/adr/CHANGELOG.md +++ b/plugins/adr/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-adr +## 0.6.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-adr-common@0.2.19 + - @backstage/plugin-search-common@1.2.10 + ## 0.6.12-next.2 ### Patch Changes diff --git a/plugins/adr/package.json b/plugins/adr/package.json index 6760c7b3a2..35c89ce255 100644 --- a/plugins/adr/package.json +++ b/plugins/adr/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-adr", - "version": "0.6.12-next.2", + "version": "0.6.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/airbrake-backend/CHANGELOG.md b/plugins/airbrake-backend/CHANGELOG.md index ccad48c17e..2a7c655a2d 100644 --- a/plugins/airbrake-backend/CHANGELOG.md +++ b/plugins/airbrake-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-airbrake-backend +## 0.3.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + ## 0.3.6-next.2 ### Patch Changes diff --git a/plugins/airbrake-backend/package.json b/plugins/airbrake-backend/package.json index a505c3d493..f424ba8ce7 100644 --- a/plugins/airbrake-backend/package.json +++ b/plugins/airbrake-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake-backend", - "version": "0.3.6-next.2", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/airbrake/CHANGELOG.md b/plugins/airbrake/CHANGELOG.md index 9df64be9aa..4636c27068 100644 --- a/plugins/airbrake/CHANGELOG.md +++ b/plugins/airbrake/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-airbrake +## 0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/dev-utils@1.0.26 + - @backstage/catalog-model@1.4.3 + - @backstage/test-utils@1.4.7 + ## 0.3.29-next.2 ### Patch Changes diff --git a/plugins/airbrake/package.json b/plugins/airbrake/package.json index 4d33c28633..3cf1107fe0 100644 --- a/plugins/airbrake/package.json +++ b/plugins/airbrake/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-airbrake", - "version": "0.3.29-next.2", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/allure/CHANGELOG.md b/plugins/allure/CHANGELOG.md index 554839eb83..bf9aaa61df 100644 --- a/plugins/allure/CHANGELOG.md +++ b/plugins/allure/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-allure +## 0.1.45 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.1.45-next.2 ### Patch Changes diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 6d8817def9..991c2a8944 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-allure", "description": "A Backstage plugin that integrates with Allure", - "version": "0.1.45-next.2", + "version": "0.1.45", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-ga/CHANGELOG.md b/plugins/analytics-module-ga/CHANGELOG.md index c77afd0bf4..5135b15ac1 100644 --- a/plugins/analytics-module-ga/CHANGELOG.md +++ b/plugins/analytics-module-ga/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-analytics-module-ga +## 0.1.37 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + ## 0.1.37-next.1 ### Patch Changes diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 1995731b01..3d367a5889 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga", - "version": "0.1.37-next.1", + "version": "0.1.37", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-ga4/CHANGELOG.md b/plugins/analytics-module-ga4/CHANGELOG.md index cc177dc290..6529fc3711 100644 --- a/plugins/analytics-module-ga4/CHANGELOG.md +++ b/plugins/analytics-module-ga4/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-analytics-module-ga4 +## 0.1.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + ## 0.1.8-next.1 ### Patch Changes diff --git a/plugins/analytics-module-ga4/package.json b/plugins/analytics-module-ga4/package.json index a4b459ba5b..97b610c2bf 100644 --- a/plugins/analytics-module-ga4/package.json +++ b/plugins/analytics-module-ga4/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-ga4", - "version": "0.1.8-next.1", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/analytics-module-newrelic-browser/CHANGELOG.md b/plugins/analytics-module-newrelic-browser/CHANGELOG.md index c687761295..0f9b210d9a 100644 --- a/plugins/analytics-module-newrelic-browser/CHANGELOG.md +++ b/plugins/analytics-module-newrelic-browser/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-analytics-module-newrelic-browser +## 0.0.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + ## 0.0.6-next.1 ### Patch Changes diff --git a/plugins/analytics-module-newrelic-browser/package.json b/plugins/analytics-module-newrelic-browser/package.json index 1448b1923a..0815b62b6c 100644 --- a/plugins/analytics-module-newrelic-browser/package.json +++ b/plugins/analytics-module-newrelic-browser/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-analytics-module-newrelic-browser", - "version": "0.0.6-next.1", + "version": "0.0.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md index ddd38838ba..9c2a434030 100644 --- a/plugins/apache-airflow/CHANGELOG.md +++ b/plugins/apache-airflow/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-apache-airflow +## 0.2.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.2.19-next.1 ### Patch Changes diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index d2241c820b..489fcde5e8 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apache-airflow", - "version": "0.2.19-next.1", + "version": "0.2.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index a8e4e81997..f801bf9ba2 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-api-docs +## 0.10.3 + +### Patch Changes + +- 8a69cc9: Fix custom http resolvers for AsyncAPI widget. +- 062b8f2: Add permission check to Register Existing API button +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.10.3-next.2 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 8f4db504f6..1819d80208 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.10.3-next.2", + "version": "0.10.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/apollo-explorer/CHANGELOG.md b/plugins/apollo-explorer/CHANGELOG.md index 77a44cd37d..1523721718 100644 --- a/plugins/apollo-explorer/CHANGELOG.md +++ b/plugins/apollo-explorer/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-apollo-explorer +## 0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.1.19-next.1 ### Patch Changes diff --git a/plugins/apollo-explorer/package.json b/plugins/apollo-explorer/package.json index 2b9fe695f5..37895e3343 100644 --- a/plugins/apollo-explorer/package.json +++ b/plugins/apollo-explorer/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apollo-explorer", - "version": "0.1.19-next.1", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 8d66e21c5c..8550264a15 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-app-backend +## 0.3.57 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-app-node@0.1.9 + ## 0.3.57-next.2 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index ec9fd3c805..0aecbec7f0 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-backend", "description": "A Backstage backend plugin that serves the Backstage frontend app", - "version": "0.3.57-next.2", + "version": "0.3.57", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index 9739a86adb..d396e40aba 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-app-node +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + ## 0.1.9-next.2 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index 772b7634cc..38c5eadacf 100644 --- a/plugins/app-node/package.json +++ b/plugins/app-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-node", "description": "Node.js library for the app plugin", - "version": "0.1.9-next.2", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/app-visualizer/CHANGELOG.md b/plugins/app-visualizer/CHANGELOG.md new file mode 100644 index 0000000000..a4ddea2590 --- /dev/null +++ b/plugins/app-visualizer/CHANGELOG.md @@ -0,0 +1,14 @@ +# @backstage/plugin-app-visualizer + +## 0.1.0 + +### Minor Changes + +- e57cc9f: Initial release of the app visualizer plugin. + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 2d220e7633..197e97c464 100644 --- a/plugins/app-visualizer/package.json +++ b/plugins/app-visualizer/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-app-visualizer", "description": "Visualizes the Backstage app structure", - "version": "0.0.0", + "version": "0.1.0", "publishConfig": { "access": "public" }, diff --git a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md index 53cb34d82c..22f61ff088 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index 1b23ec5b86..3d73de88fc 100644 --- a/plugins/auth-backend-module-atlassian-provider/package.json +++ b/plugins/auth-backend-module-atlassian-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-atlassian-provider", "description": "The atlassian-provider backend module for the auth plugin.", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index 506bd36057..e9e5d99224 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.2.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.3-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-gcp-iap-provider/package.json b/plugins/auth-backend-module-gcp-iap-provider/package.json index 21eb4fc51e..d167389b20 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/package.json +++ b/plugins/auth-backend-module-gcp-iap-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gcp-iap-provider", "description": "A GCP IAP auth provider module for the Backstage auth backend", - "version": "0.2.3-next.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-github-provider/CHANGELOG.md b/plugins/auth-backend-module-github-provider/CHANGELOG.md index cdfc128d85..ee59a1e269 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 7cd95fe0a0..bf84dc5ec7 100644 --- a/plugins/auth-backend-module-github-provider/package.json +++ b/plugins/auth-backend-module-github-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-github-provider", "description": "The github-provider backend module for the auth plugin.", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md index 9222ec93be..92acc636c1 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index bdf17c3c07..c7f4d5ef04 100644 --- a/plugins/auth-backend-module-gitlab-provider/package.json +++ b/plugins/auth-backend-module-gitlab-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-gitlab-provider", "description": "The gitlab-provider backend module for the auth plugin.", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-google-provider/CHANGELOG.md b/plugins/auth-backend-module-google-provider/CHANGELOG.md index 57127a7aea..b43722644b 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index eb8191090a..7528d9f8b6 100644 --- a/plugins/auth-backend-module-google-provider/package.json +++ b/plugins/auth-backend-module-google-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-google-provider", "description": "A Google auth provider module for the Backstage auth backend", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md index 61a4b756ab..496538fdf0 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.1.4 + +### Patch Changes + +- 928efbc: Deprecated the `authModuleMicrosoftProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));` +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + ## 0.1.4-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index 99e85bd8d8..9412575200 100644 --- a/plugins/auth-backend-module-microsoft-provider/package.json +++ b/plugins/auth-backend-module-microsoft-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-microsoft-provider", "description": "The microsoft-provider backend module for the auth plugin.", - "version": "0.1.4-next.2", + "version": "0.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index 46cee9f112..44cb96b97d 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index cf385237e5..5edc0be4b8 100644 --- a/plugins/auth-backend-module-oauth2-provider/package.json +++ b/plugins/auth-backend-module-oauth2-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-provider", "description": "The oauth2-provider backend module for the auth plugin.", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md index 7ecac42625..71c14a75e2 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-proxy-provider/package.json b/plugins/auth-backend-module-oauth2-proxy-provider/package.json index 7ed983ce0e..c3d49bfcd0 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/package.json +++ b/plugins/auth-backend-module-oauth2-proxy-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-oauth2-proxy-provider", "description": "The oauth2-proxy-provider backend module for the auth plugin.", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-okta-provider/CHANGELOG.md b/plugins/auth-backend-module-okta-provider/CHANGELOG.md index 5834ce13de..b059fa0bb4 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.0.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + ## 0.0.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index 68fa330c3c..7159ab1292 100644 --- a/plugins/auth-backend-module-okta-provider/package.json +++ b/plugins/auth-backend-module-okta-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-okta-provider", "description": "The okta-provider backend module for the auth plugin.", - "version": "0.0.2-next.2", + "version": "0.0.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md index 29f61ec259..147a13b97d 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.1.3 + +### Patch Changes + +- 928efbc: Deprecated the `authModulePinnipedProvider` export. A default export is now available and should be used like this in your backend: `backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));` +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index 6160708204..bda4cd9751 100644 --- a/plugins/auth-backend-module-pinniped-provider/package.json +++ b/plugins/auth-backend-module-pinniped-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-pinniped-provider", "description": "The pinniped-provider backend module for the auth plugin.", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md index c2f21ade42..8beb4ed11c 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.1.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-vmware-cloud-provider/package.json b/plugins/auth-backend-module-vmware-cloud-provider/package.json index 0d353a6b84..b9b6a3cdaf 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/package.json +++ b/plugins/auth-backend-module-vmware-cloud-provider/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend-module-vmware-cloud-provider", "description": "The vmware-cloud-provider backend module for the auth plugin.", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index 964b2e05e8..a65f0bdb61 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-auth-backend +## 0.20.3 + +### Patch Changes + +- 004499c: Fixed an issue where some Okta's resolvers were missing +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.1.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.1.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.2.3 + - @backstage/plugin-auth-backend-module-github-provider@0.1.6 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.1.6 + - @backstage/plugin-auth-backend-module-google-provider@0.1.6 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.1.6 + - @backstage/plugin-auth-backend-module-okta-provider@0.0.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.20.3-next.2 ### Patch Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index f05551736a..a2b4d01b6c 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.20.3-next.2", + "version": "0.20.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index f2bbe106a3..36d65e9fa3 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-auth-node +## 0.4.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.4.3-next.2 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index 1f11c7d0a7..fc8fb5b25c 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.4.3-next.2", + "version": "0.4.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index e63fd49793..7b0a081b34 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-azure-devops-backend +## 0.5.1 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-azure-devops-common@0.3.2 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.5.1-next.2 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index e0e3074701..12b598f7e9 100644 --- a/plugins/azure-devops-backend/package.json +++ b/plugins/azure-devops-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-backend", - "version": "0.5.1-next.2", + "version": "0.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index c4f5208d26..8d851523f6 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-azure-devops +## 0.3.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-azure-devops-common@0.3.2 + ## 0.3.11-next.2 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index c394bd8597..db744139ee 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.3.11-next.2", + "version": "0.3.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-sites-backend/CHANGELOG.md b/plugins/azure-sites-backend/CHANGELOG.md index 2d7744f9d9..c806c46925 100644 --- a/plugins/azure-sites-backend/CHANGELOG.md +++ b/plugins/azure-sites-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-azure-sites-backend +## 0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/azure-sites-backend/package.json b/plugins/azure-sites-backend/package.json index be5f7f47c9..ae3a849810 100644 --- a/plugins/azure-sites-backend/package.json +++ b/plugins/azure-sites-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites-backend", - "version": "0.1.19-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/azure-sites/CHANGELOG.md b/plugins/azure-sites/CHANGELOG.md index fa99632e82..dd706132a6 100644 --- a/plugins/azure-sites/CHANGELOG.md +++ b/plugins/azure-sites/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-azure-sites +## 0.1.18 + +### Patch Changes + +- a31f688: Show Azure site tags in `EntityAzureSitesOverviewWidget`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-azure-sites-common@0.1.1 + ## 0.1.18-next.2 ### Patch Changes diff --git a/plugins/azure-sites/package.json b/plugins/azure-sites/package.json index 3ca64a04e8..cc16ab9e47 100644 --- a/plugins/azure-sites/package.json +++ b/plugins/azure-sites/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-sites", - "version": "0.1.18-next.2", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges-backend/CHANGELOG.md b/plugins/badges-backend/CHANGELOG.md index ff7908984b..c0135f7ee8 100644 --- a/plugins/badges-backend/CHANGELOG.md +++ b/plugins/badges-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-badges-backend +## 0.3.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.3.6-next.2 ### Patch Changes diff --git a/plugins/badges-backend/package.json b/plugins/badges-backend/package.json index 3a3c229e7b..893a5b6969 100644 --- a/plugins/badges-backend/package.json +++ b/plugins/badges-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges-backend", "description": "A Backstage backend plugin that generates README badges for your entities", - "version": "0.3.6-next.2", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/badges/CHANGELOG.md b/plugins/badges/CHANGELOG.md index 2dd15e3d78..0897cf4caf 100644 --- a/plugins/badges/CHANGELOG.md +++ b/plugins/badges/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-badges +## 0.2.53 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.53-next.2 ### Patch Changes diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 4ca01e0312..688536d260 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-badges", "description": "A Backstage plugin that generates README badges for your entities", - "version": "0.2.53-next.2", + "version": "0.2.53", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bazaar-backend/CHANGELOG.md b/plugins/bazaar-backend/CHANGELOG.md index c476a90394..51dac2f648 100644 --- a/plugins/bazaar-backend/CHANGELOG.md +++ b/plugins/bazaar-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-bazaar-backend +## 0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + ## 0.3.7-next.2 ### Patch Changes diff --git a/plugins/bazaar-backend/package.json b/plugins/bazaar-backend/package.json index 5d650ab325..82f4c66a76 100644 --- a/plugins/bazaar-backend/package.json +++ b/plugins/bazaar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar-backend", - "version": "0.3.7-next.2", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bazaar/CHANGELOG.md b/plugins/bazaar/CHANGELOG.md index df27712931..5e048efb1b 100644 --- a/plugins/bazaar/CHANGELOG.md +++ b/plugins/bazaar/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-bazaar +## 0.2.21 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.21-next.2 ### Patch Changes diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index d00b018041..058ead5ca3 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bazaar", - "version": "0.2.21-next.2", + "version": "0.2.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/bitrise/CHANGELOG.md b/plugins/bitrise/CHANGELOG.md index bc60cb7323..efc87f6839 100644 --- a/plugins/bitrise/CHANGELOG.md +++ b/plugins/bitrise/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-bitrise +## 0.1.56 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.1.56-next.2 ### Patch Changes diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index dad18f8c8d..2dd804f746 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-bitrise", "description": "A Backstage plugin that integrates towards Bitrise", - "version": "0.1.56-next.2", + "version": "0.1.56", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 4b74bd929e..ff0c82bcc4 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- 22e88d0: Added status and e-mail as labels to the AWS Account Resource +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index b134e0ac63..af507e3c68 100644 --- a/plugins/catalog-backend-module-aws/package.json +++ b/plugins/catalog-backend-module-aws/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-aws", "description": "A Backstage catalog backend module that helps integrate towards AWS", - "version": "0.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-azure/CHANGELOG.md b/plugins/catalog-backend-module-azure/CHANGELOG.md index 41a3530478..e33d32aa36 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.1.28 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.1.28-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index 7729541f81..05d2587746 100644 --- a/plugins/catalog-backend-module-azure/package.json +++ b/plugins/catalog-backend-module-azure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-azure", "description": "A Backstage catalog backend module that helps integrate towards Azure", - "version": "0.1.28-next.2", + "version": "0.1.28", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index f85f00add2..28d4c10240 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.1.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index 728ff04920..ff331aeca5 100644 --- a/plugins/catalog-backend-module-backstage-openapi/package.json +++ b/plugins/catalog-backend-module-backstage-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-backstage-openapi", - "version": "0.1.2-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md index 7e28d5e4d8..0fb20563d0 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.1.24 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + ## 0.1.24-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index ba3b165d31..e1352c6363 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/package.json +++ b/plugins/catalog-backend-module-bitbucket-cloud/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud", - "version": "0.1.24-next.2", + "version": "0.1.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md index 3111f2cef3..d3abaf1608 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.1.22 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.1.22-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index 4e75fd71a7..00f8c6572f 100644 --- a/plugins/catalog-backend-module-bitbucket-server/package.json +++ b/plugins/catalog-backend-module-bitbucket-server/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket-server", - "version": "0.1.22-next.2", + "version": "0.1.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md index 37ea4f7179..b39778b2fb 100644 --- a/plugins/catalog-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-bitbucket +## 0.2.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.15 + ## 0.2.24-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket/package.json b/plugins/catalog-backend-module-bitbucket/package.json index 2241bcfeb0..2625835a5b 100644 --- a/plugins/catalog-backend-module-bitbucket/package.json +++ b/plugins/catalog-backend-module-bitbucket/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-bitbucket", "description": "A Backstage catalog backend module that helps integrate towards Bitbucket", - "version": "0.2.24-next.2", + "version": "0.2.24", "deprecated": true, "main": "src/index.ts", "types": "src/index.ts", diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index 737676e11d..aef3c0c14a 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.1.9 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + ## 0.1.9-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index 4d03df555e..5515feeb5b 100644 --- a/plugins/catalog-backend-module-gcp/package.json +++ b/plugins/catalog-backend-module-gcp/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gcp", "description": "A Backstage catalog backend module that helps integrate towards GCP", - "version": "0.1.9-next.2", + "version": "0.1.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gerrit/CHANGELOG.md b/plugins/catalog-backend-module-gerrit/CHANGELOG.md index ae9f0ac4e5..f43a1a7550 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.1.25 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.1.25-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 41786609c5..95f90287c3 100644 --- a/plugins/catalog-backend-module-gerrit/package.json +++ b/plugins/catalog-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend-module-gerrit", - "version": "0.1.25-next.2", + "version": "0.1.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 18ef030f1e..2dac3fa910 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-catalog-backend-module-github@0.4.7 + - @backstage/config@1.1.1 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index e817e33ffe..bd7e23f90d 100644 --- a/plugins/catalog-backend-module-github-org/package.json +++ b/plugins/catalog-backend-module-github-org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-github-org", "description": "The github-org backend module for the catalog plugin.", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-github/CHANGELOG.md b/plugins/catalog-backend-module-github/CHANGELOG.md index 88840caf17..6ea0c50666 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-catalog-backend-module-github +## 0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + ## 0.4.7-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index fbca514b3e..9231a0cd69 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.4.7-next.2", + "version": "0.4.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-gitlab/CHANGELOG.md b/plugins/catalog-backend-module-gitlab/CHANGELOG.md index eb0177d7b5..138796de12 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + ## 0.3.6-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index cf54123207..4092a1dab2 100644 --- a/plugins/catalog-backend-module-gitlab/package.json +++ b/plugins/catalog-backend-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-gitlab", "description": "A Backstage catalog backend module that helps integrate towards GitLab", - "version": "0.3.6-next.2", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index d66c32a438..24fd6a0b30 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.4.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-events-node@0.2.18 + ## 0.4.13-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index 95d4b3563a..41c0abd811 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-incremental-ingestion", "description": "An entity provider for streaming large asset sources into the catalog", - "version": "0.4.13-next.2", + "version": "0.4.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index e862e66a3b..5e01cf2f97 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.5.24 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.5.24-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index c82c45545d..6a16e89ff1 100644 --- a/plugins/catalog-backend-module-ldap/package.json +++ b/plugins/catalog-backend-module-ldap/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-ldap", "description": "A Backstage catalog backend module that helps integrate towards LDAP", - "version": "0.5.24-next.2", + "version": "0.5.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-msgraph/CHANGELOG.md b/plugins/catalog-backend-module-msgraph/CHANGELOG.md index dbb12e9ecc..8ea92b99b9 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.5.16 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.5.16-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 779550f849..1187c93262 100644 --- a/plugins/catalog-backend-module-msgraph/package.json +++ b/plugins/catalog-backend-module-msgraph/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-msgraph", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", - "version": "0.5.16-next.2", + "version": "0.5.16", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index cb12054932..ff1f865a28 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,31 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.1.26 + +### Patch Changes + +- 4ebf99b: Add support for the new backend system. + + A new backend module for the catalog backend + was added and exported as `default`. + + You can use it with the new backend system like + + ```ts title="packages/backend/src/index.ts" + backend.add(import('@backstage/plugin-catalog-backend-module-openapi')); + ``` + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-catalog-backend@1.16.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.1.26-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index b021ae11e2..1b3a2e46a0 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-openapi", "description": "A Backstage catalog backend module that helps with OpenAPI specifications", - "version": "0.1.26-next.2", + "version": "0.1.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md index 63c288768e..dbc84f46f7 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.1.14-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index 41cc2a0cc1..d9bdb74b16 100644 --- a/plugins/catalog-backend-module-puppetdb/package.json +++ b/plugins/catalog-backend-module-puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-puppetdb", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", - "version": "0.1.14-next.2", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 93fbd3ee37..4901341e46 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/package.json b/plugins/catalog-backend-module-scaffolder-entity-model/package.json index 7be1fb1ffc..3dc896f7c7 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/package.json +++ b/plugins/catalog-backend-module-scaffolder-entity-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-scaffolder-entity-model", "description": "Adds support for the scaffolder specific entity model (e.g. the Template kind) to the catalog backend plugin.", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md index 9c90b67b9f..947fdb5914 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.3.6 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + ## 0.3.6-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index 92b5755d07..4412c4ef7c 100644 --- a/plugins/catalog-backend-module-unprocessed/package.json +++ b/plugins/catalog-backend-module-unprocessed/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend-module-unprocessed", "description": "Backstage Catalog module to view unprocessed entities", - "version": "0.3.6-next.2", + "version": "0.3.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index 45b11bba63..3330de7fd3 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,29 @@ # @backstage/plugin-catalog-backend +## 1.16.1 + +### Patch Changes + +- c3249d6: Parse the URL using a different method rather than `git-url-parse` to support wildcards for URLs which are not VCS providers +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-search-backend-module-catalog@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-events-node@0.2.18 + ## 1.16.1-next.2 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index ad0ddcf767..42f40cccd2 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.16.1-next.2", + "version": "1.16.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index 92415ecff9..9f2b511676 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-common +## 1.0.20 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-search-common@1.2.10 + ## 1.0.19 ### Patch Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 3c4bc34997..9642746fd7 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.19", + "version": "1.0.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 1523fa602b..235e5c25fb 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-catalog-graph +## 0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index c19131325b..a38f1a4480 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graph", - "version": "0.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 7b60edc160..ea9d4cb61e 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-import +## 0.10.5 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.10.5-next.2 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 7f48d59f91..865f60a842 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-import", "description": "A Backstage plugin the helps you import entities into your catalog", - "version": "0.10.5-next.2", + "version": "0.10.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index 8da663cfa0..cda3c22b0f 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-catalog-node +## 1.6.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + ## 1.6.1-next.2 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index e09509d2b5..013577d0b9 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-node", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", - "version": "1.6.1-next.2", + "version": "1.6.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 62ce5b8337..9bd729a8e6 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-catalog-react +## 1.9.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-catalog-common@1.0.20 + ## 1.9.3-next.2 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 9ad06a3c98..93486c64db 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.9.3-next.2", + "version": "1.9.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index 7a45d8de79..9a2be34228 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.1.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.7-next.1 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 0312b589dc..d3b037788a 100644 --- a/plugins/catalog-unprocessed-entities/package.json +++ b/plugins/catalog-unprocessed-entities/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities", - "version": "0.1.7-next.1", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index 3f3996bc30..a34341d585 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-catalog +## 1.16.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + ## 1.16.1-next.2 ### Patch Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index fc097efc4f..4654a831f9 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.16.1-next.2", + "version": "1.16.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md index 22482f3fe7..79d8cda7bf 100644 --- a/plugins/cicd-statistics-module-gitlab/CHANGELOG.md +++ b/plugins/cicd-statistics-module-gitlab/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-cicd-statistics-module-gitlab +## 0.1.25 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-cicd-statistics@0.1.31 + ## 0.1.25-next.2 ### Patch Changes diff --git a/plugins/cicd-statistics-module-gitlab/package.json b/plugins/cicd-statistics-module-gitlab/package.json index 285dfb76a0..f84457a781 100644 --- a/plugins/cicd-statistics-module-gitlab/package.json +++ b/plugins/cicd-statistics-module-gitlab/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics-module-gitlab", "description": "CI/CD Statistics plugin module; Gitlab CICD", - "version": "0.1.25-next.2", + "version": "0.1.25", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cicd-statistics/CHANGELOG.md b/plugins/cicd-statistics/CHANGELOG.md index c5d6328c08..e80e9d5d68 100644 --- a/plugins/cicd-statistics/CHANGELOG.md +++ b/plugins/cicd-statistics/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-cicd-statistics +## 0.1.31 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.1.31-next.2 ### Patch Changes diff --git a/plugins/cicd-statistics/package.json b/plugins/cicd-statistics/package.json index 6e52536878..aaa271baa7 100644 --- a/plugins/cicd-statistics/package.json +++ b/plugins/cicd-statistics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cicd-statistics", "description": "A frontend plugin visualizing CI/CD pipeline statistics (build time)", - "version": "0.1.31-next.2", + "version": "0.1.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/circleci/CHANGELOG.md b/plugins/circleci/CHANGELOG.md index 6e1310932c..baabcaa66f 100644 --- a/plugins/circleci/CHANGELOG.md +++ b/plugins/circleci/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-circleci +## 0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.3.29-next.2 ### Patch Changes diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 92daf3e741..174dbda8d1 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-circleci", "description": "A Backstage plugin that integrates towards Circle CI", - "version": "0.3.29-next.2", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cloudbuild/CHANGELOG.md b/plugins/cloudbuild/CHANGELOG.md index 7e21005cf8..84cd321643 100644 --- a/plugins/cloudbuild/CHANGELOG.md +++ b/plugins/cloudbuild/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-cloudbuild +## 0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.3.29-next.2 ### Patch Changes diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 16ede212f9..8d7c9a3282 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cloudbuild", "description": "A Backstage plugin that integrates towards Google Cloud Build", - "version": "0.3.29-next.2", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-climate/CHANGELOG.md b/plugins/code-climate/CHANGELOG.md index c845623759..551e4fb262 100644 --- a/plugins/code-climate/CHANGELOG.md +++ b/plugins/code-climate/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-code-climate +## 0.1.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.1.29-next.2 ### Patch Changes diff --git a/plugins/code-climate/package.json b/plugins/code-climate/package.json index 02ef329e2f..1c9971f476 100644 --- a/plugins/code-climate/package.json +++ b/plugins/code-climate/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-code-climate", - "version": "0.1.29-next.2", + "version": "0.1.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage-backend/CHANGELOG.md b/plugins/code-coverage-backend/CHANGELOG.md index 8244c65125..e55df807d1 100644 --- a/plugins/code-coverage-backend/CHANGELOG.md +++ b/plugins/code-coverage-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-code-coverage-backend +## 0.2.23 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.2.23-next.2 ### Patch Changes diff --git a/plugins/code-coverage-backend/package.json b/plugins/code-coverage-backend/package.json index 3c214effce..4fa0a8e6ec 100644 --- a/plugins/code-coverage-backend/package.json +++ b/plugins/code-coverage-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage-backend", "description": "A Backstage backend plugin that helps you keep track of your code coverage", - "version": "0.2.23-next.2", + "version": "0.2.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/code-coverage/CHANGELOG.md b/plugins/code-coverage/CHANGELOG.md index 36d0cdf180..5155660c36 100644 --- a/plugins/code-coverage/CHANGELOG.md +++ b/plugins/code-coverage/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-code-coverage +## 0.2.22 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.22-next.2 ### Patch Changes diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index 1dd4adda0c..c37036f1ff 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-code-coverage", "description": "A Backstage plugin that helps you keep track of your code coverage", - "version": "0.2.22-next.2", + "version": "0.2.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/codescene/CHANGELOG.md b/plugins/codescene/CHANGELOG.md index 16665e7bcf..df9ed3199f 100644 --- a/plugins/codescene/CHANGELOG.md +++ b/plugins/codescene/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-codescene +## 0.1.21 + +### Patch Changes + +- d5eda61: Updated Readme document in codescene plugin +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.21-next.1 ### Patch Changes diff --git a/plugins/codescene/package.json b/plugins/codescene/package.json index 2727a055a8..f0dfd20394 100644 --- a/plugins/codescene/package.json +++ b/plugins/codescene/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-codescene", - "version": "0.1.21-next.1", + "version": "0.1.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 3f5050932e..0ed7d3afd5 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-config-schema +## 0.1.49 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.1.49-next.1 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 5f9b696f14..15860d4e89 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-config-schema", "description": "A Backstage plugin that lets you browse the configuration schema of your app", - "version": "0.1.49-next.1", + "version": "0.1.49", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/cost-insights/CHANGELOG.md b/plugins/cost-insights/CHANGELOG.md index 3d62339bc8..cd0c31e2f1 100644 --- a/plugins/cost-insights/CHANGELOG.md +++ b/plugins/cost-insights/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-cost-insights +## 0.12.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/theme@0.5.0 + - @backstage/plugin-cost-insights-common@0.1.2 + ## 0.12.18-next.2 ### Patch Changes diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index bf8f5ff02a..2db994d466 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-cost-insights", "description": "A Backstage plugin that helps you keep track of your cloud spend", - "version": "0.12.18-next.2", + "version": "0.12.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index 29ed53fae6..62e91cc50c 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-devtools-backend +## 0.2.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config-loader@1.6.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/cli-common@0.1.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-devtools-common@0.1.8 + ## 0.2.6-next.2 ### Patch Changes diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index d81b4538cf..4d56c3e9dd 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.2.6-next.2", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools-common/CHANGELOG.md b/plugins/devtools-common/CHANGELOG.md index 9ede428d75..3bbc48a585 100644 --- a/plugins/devtools-common/CHANGELOG.md +++ b/plugins/devtools-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-devtools-common +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/types@1.1.1 + ## 0.1.7 ### Patch Changes diff --git a/plugins/devtools-common/package.json b/plugins/devtools-common/package.json index 24884efed2..a488e997a1 100644 --- a/plugins/devtools-common/package.json +++ b/plugins/devtools-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-devtools-common", "description": "Common functionalities for the devtools plugin", - "version": "0.1.7", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 8b7a4376f3..4237bd149a 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-devtools +## 0.1.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/errors@1.2.3 + - @backstage/plugin-devtools-common@0.1.8 + ## 0.1.8-next.1 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 34ce5d7091..ece8fe89e3 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.8-next.1", + "version": "0.1.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md index 7e2ad6ab27..1cff141762 100644 --- a/plugins/dynatrace/CHANGELOG.md +++ b/plugins/dynatrace/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-dynatrace +## 8.0.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 8.0.3-next.2 ### Patch Changes diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json index a14915cebb..c82b8a4d5b 100644 --- a/plugins/dynatrace/package.json +++ b/plugins/dynatrace/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-dynatrace", - "version": "8.0.3-next.2", + "version": "8.0.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback-backend/CHANGELOG.md b/plugins/entity-feedback-backend/CHANGELOG.md index ccaeaf63eb..e9eec4b8f2 100644 --- a/plugins/entity-feedback-backend/CHANGELOG.md +++ b/plugins/entity-feedback-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-entity-feedback-backend +## 0.2.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.6-next.2 ### Patch Changes diff --git a/plugins/entity-feedback-backend/package.json b/plugins/entity-feedback-backend/package.json index 54cf74aa55..8e5deafdf1 100644 --- a/plugins/entity-feedback-backend/package.json +++ b/plugins/entity-feedback-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback-backend", - "version": "0.2.6-next.2", + "version": "0.2.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-feedback/CHANGELOG.md b/plugins/entity-feedback/CHANGELOG.md index 2d9bb0b57a..5cc2ae9468 100644 --- a/plugins/entity-feedback/CHANGELOG.md +++ b/plugins/entity-feedback/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-entity-feedback +## 0.2.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-entity-feedback-common@0.1.3 + ## 0.2.12-next.2 ### Patch Changes diff --git a/plugins/entity-feedback/package.json b/plugins/entity-feedback/package.json index 8d2b01dcfb..226c76c106 100644 --- a/plugins/entity-feedback/package.json +++ b/plugins/entity-feedback/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-feedback", - "version": "0.2.12-next.2", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/entity-validation/CHANGELOG.md b/plugins/entity-validation/CHANGELOG.md index 183cba125f..f1070960c8 100644 --- a/plugins/entity-validation/CHANGELOG.md +++ b/plugins/entity-validation/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-entity-validation +## 0.1.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.1.14-next.2 ### Patch Changes diff --git a/plugins/entity-validation/package.json b/plugins/entity-validation/package.json index bd3f6a1e38..316c9ec97f 100644 --- a/plugins/entity-validation/package.json +++ b/plugins/entity-validation/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-entity-validation", - "version": "0.1.14-next.2", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index fe483744a7..b77a2912ca 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.2.12 + +### Patch Changes + +- 7b8e551: Fix errors when deleting SQS messages: + + - If zero messages were received, skip deletion to avoid `EmptyBatchRequest` error from the SQS client. + - If zero failures were returned from the SQS client during deletion, skip error logging. + +- d5ddc4e: Add documentation on how to install the plugins with the new backend system. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-events-node@0.2.18 + ## 0.2.12-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 041647f503..6e0c986554 100644 --- a/plugins/events-backend-module-aws-sqs/package.json +++ b/plugins/events-backend-module-aws-sqs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-aws-sqs", - "version": "0.2.12-next.2", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index 9f590d48eb..233d9f6eb5 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend-module-azure +## 0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 56ffec5737..2530e2dfd9 100644 --- a/plugins/events-backend-module-azure/package.json +++ b/plugins/events-backend-module-azure/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-azure", - "version": "0.1.19-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md index 584963ce76..ae4db7e0fa 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index db5343536b..5dd1e3e00c 100644 --- a/plugins/events-backend-module-bitbucket-cloud/package.json +++ b/plugins/events-backend-module-bitbucket-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-bitbucket-cloud", - "version": "0.1.19-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-gerrit/CHANGELOG.md b/plugins/events-backend-module-gerrit/CHANGELOG.md index 8770dcf0a2..6af1070a1f 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.1.19 + +### Patch Changes + +- af76a95: Add default exports for the new backend system and documentation. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-events-node@0.2.18 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index 80d6e5b6b2..0593cd8664 100644 --- a/plugins/events-backend-module-gerrit/package.json +++ b/plugins/events-backend-module-gerrit/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gerrit", - "version": "0.1.19-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-github/CHANGELOG.md b/plugins/events-backend-module-github/CHANGELOG.md index 41d718d9fb..bff2a53470 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend-module-github +## 0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index c43468b8bf..97bd7b7cc6 100644 --- a/plugins/events-backend-module-github/package.json +++ b/plugins/events-backend-module-github/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-github", - "version": "0.1.19-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-module-gitlab/CHANGELOG.md b/plugins/events-backend-module-gitlab/CHANGELOG.md index 9858bfb44e..de697ee02c 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.1.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index cf5c9ff9d6..7eacb91a61 100644 --- a/plugins/events-backend-module-gitlab/package.json +++ b/plugins/events-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend-module-gitlab", - "version": "0.1.19-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 6cf527b228..2651cbeffe 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.2.18 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index cb9ec93a3d..aabd16558d 100644 --- a/plugins/events-backend-test-utils/package.json +++ b/plugins/events-backend-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-backend-test-utils", "description": "The plugin-events-backend-test-utils for @backstage/plugin-events-node", - "version": "0.1.19-next.2", + "version": "0.1.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-backend/CHANGELOG.md b/plugins/events-backend/CHANGELOG.md index 560ca79197..fb7607f8b1 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-events-backend +## 0.2.18 + +### Patch Changes + +- 92ea615: Update `README.md` +- d5ddc4e: Add documentation on how to install the plugins with the new backend system. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/plugin-events-node@0.2.18 + ## 0.2.18-next.2 ### Patch Changes diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 8c94fe5056..ec4a59f4e9 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.2.18-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index 095fe394e9..dd9844430c 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-events-node +## 0.2.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + ## 0.2.18-next.2 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 76cb9f731c..d2a9e5424d 100644 --- a/plugins/events-node/package.json +++ b/plugins/events-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-events-node", "description": "The plugin-events-node module for @backstage/plugin-events-backend", - "version": "0.2.18-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index 587238bf93..2f4a7fb873 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @internal/plugin-todo-list-backend +## 1.0.21 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/errors@1.2.3 + ## 1.0.21-next.2 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 091caf3c68..65241fd128 100644 --- a/plugins/example-todo-list-backend/package.json +++ b/plugins/example-todo-list-backend/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-backend", - "version": "1.0.21-next.2", + "version": "1.0.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index bef3cf1d40..98d6bafa7f 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @internal/plugin-todo-list-common +## 1.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + ## 1.0.16 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 6a3b2897eb..1d984812f9 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-common", - "version": "1.0.16", + "version": "1.0.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index eae25f89bd..8dfacdd105 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,13 @@ # @internal/plugin-todo-list +## 1.0.21 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 1.0.21-next.1 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index f38ba69a06..63634879df 100644 --- a/plugins/example-todo-list/package.json +++ b/plugins/example-todo-list/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list", - "version": "1.0.21-next.1", + "version": "1.0.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore-backend/CHANGELOG.md b/plugins/explore-backend/CHANGELOG.md index 0049c74da3..292a14f652 100644 --- a/plugins/explore-backend/CHANGELOG.md +++ b/plugins/explore-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-explore-backend +## 0.0.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-search-backend-module-explore@0.1.13 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + ## 0.0.19-next.2 ### Patch Changes diff --git a/plugins/explore-backend/package.json b/plugins/explore-backend/package.json index 7a1adfdd19..5af891fb02 100644 --- a/plugins/explore-backend/package.json +++ b/plugins/explore-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore-backend", - "version": "0.0.19-next.2", + "version": "0.0.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore-react/CHANGELOG.md b/plugins/explore-react/CHANGELOG.md index 87fa9eb1d7..d9668070c2 100644 --- a/plugins/explore-react/CHANGELOG.md +++ b/plugins/explore-react/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-explore-react +## 0.0.35 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-explore-common@0.0.2 + ## 0.0.35-next.1 ### Patch Changes diff --git a/plugins/explore-react/package.json b/plugins/explore-react/package.json index 4774eec397..a3128511ac 100644 --- a/plugins/explore-react/package.json +++ b/plugins/explore-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore-react", "description": "A frontend library for Backstage plugins that want to interact with the explore plugin", - "version": "0.0.35-next.1", + "version": "0.0.35", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/explore/CHANGELOG.md b/plugins/explore/CHANGELOG.md index bb83d2b568..b1cdac03d7 100644 --- a/plugins/explore/CHANGELOG.md +++ b/plugins/explore/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-explore +## 0.4.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-explore-react@0.0.35 + - @backstage/plugin-search-react@1.7.5 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.10 + ## 0.4.15-next.2 ### Patch Changes diff --git a/plugins/explore/package.json b/plugins/explore/package.json index be2d997932..500480c1ad 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-explore", "description": "A Backstage plugin for building an exploration page of your software ecosystem", - "version": "0.4.15-next.2", + "version": "0.4.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/firehydrant/CHANGELOG.md b/plugins/firehydrant/CHANGELOG.md index fdcd23958e..5272139970 100644 --- a/plugins/firehydrant/CHANGELOG.md +++ b/plugins/firehydrant/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-firehydrant +## 0.2.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.2.13-next.2 ### Patch Changes diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index be9f9e1165..9747592e0c 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-firehydrant", "description": "A Backstage plugin that integrates towards FireHydrant", - "version": "0.2.13-next.2", + "version": "0.2.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/fossa/CHANGELOG.md b/plugins/fossa/CHANGELOG.md index a369cd3122..61721a6600 100644 --- a/plugins/fossa/CHANGELOG.md +++ b/plugins/fossa/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-fossa +## 0.2.61 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.61-next.2 ### Patch Changes diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index 2aa82f79dd..83af637994 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-fossa", "description": "A Backstage plugin that integrates towards FOSSA", - "version": "0.2.61-next.2", + "version": "0.2.61", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gcalendar/CHANGELOG.md b/plugins/gcalendar/CHANGELOG.md index afb7239eeb..cb9865d96c 100644 --- a/plugins/gcalendar/CHANGELOG.md +++ b/plugins/gcalendar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-gcalendar +## 0.3.22 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + ## 0.3.22-next.1 ### Patch Changes diff --git a/plugins/gcalendar/package.json b/plugins/gcalendar/package.json index 0e22947f8d..c8a5b0bd0a 100644 --- a/plugins/gcalendar/package.json +++ b/plugins/gcalendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcalendar", - "version": "0.3.22-next.1", + "version": "0.3.22", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gcp-projects/CHANGELOG.md b/plugins/gcp-projects/CHANGELOG.md index 1fdd0d9246..bcdc653349 100644 --- a/plugins/gcp-projects/CHANGELOG.md +++ b/plugins/gcp-projects/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-gcp-projects +## 0.3.45 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.3.45-next.1 ### Patch Changes diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 28f6fc0b72..571267216c 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gcp-projects", "description": "A Backstage plugin that helps you manage projects in GCP", - "version": "0.3.45-next.1", + "version": "0.3.45", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/git-release-manager/CHANGELOG.md b/plugins/git-release-manager/CHANGELOG.md index 9d181b17ab..2ce671930b 100644 --- a/plugins/git-release-manager/CHANGELOG.md +++ b/plugins/git-release-manager/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-git-release-manager +## 0.3.41 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/integration@1.8.0 + ## 0.3.41-next.1 ### Patch Changes diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index 11e1b03c51..7fc2a142ab 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-git-release-manager", "description": "A Backstage plugin that helps you manage releases in git", - "version": "0.3.41-next.1", + "version": "0.3.41", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 9655ee39d4..89807a9f29 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-github-actions +## 0.6.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + ## 0.6.10-next.2 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index e8d93e7caf..b675315dae 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.6.10-next.2", + "version": "0.6.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-deployments/CHANGELOG.md b/plugins/github-deployments/CHANGELOG.md index 26b7d7f041..b09bb8d5db 100644 --- a/plugins/github-deployments/CHANGELOG.md +++ b/plugins/github-deployments/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-github-deployments +## 0.1.60 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.1.60-next.2 ### Patch Changes diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index d29e1b9a9f..1869e04595 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-deployments", "description": "A Backstage plugin that integrates towards GitHub Deployments", - "version": "0.1.60-next.2", + "version": "0.1.60", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-issues/CHANGELOG.md b/plugins/github-issues/CHANGELOG.md index 193b5d240f..3d15c6b6a9 100644 --- a/plugins/github-issues/CHANGELOG.md +++ b/plugins/github-issues/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-github-issues +## 0.2.18 + +### Patch Changes + +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.2.18-next.2 ### Patch Changes diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 9fb11fc9b9..de3b02f53b 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-issues", - "version": "0.2.18-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/github-pull-requests-board/CHANGELOG.md b/plugins/github-pull-requests-board/CHANGELOG.md index e6985932f4..8fc568d310 100644 --- a/plugins/github-pull-requests-board/CHANGELOG.md +++ b/plugins/github-pull-requests-board/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-github-pull-requests-board +## 0.1.23 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/integration@1.8.0 + ## 0.1.23-next.2 ### Patch Changes diff --git a/plugins/github-pull-requests-board/package.json b/plugins/github-pull-requests-board/package.json index e2fc39e328..aa086c0848 100644 --- a/plugins/github-pull-requests-board/package.json +++ b/plugins/github-pull-requests-board/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-pull-requests-board", "description": "A Backstage plugin that allows you to see all open Pull Requests for all the repositories owned by your team", - "version": "0.1.23-next.2", + "version": "0.1.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gitops-profiles/CHANGELOG.md b/plugins/gitops-profiles/CHANGELOG.md index 1a3372089c..cd312c04bf 100644 --- a/plugins/gitops-profiles/CHANGELOG.md +++ b/plugins/gitops-profiles/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-gitops-profiles +## 0.3.44 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.3.44-next.1 ### Patch Changes diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index dc999ea645..d9e509a49b 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gitops-profiles", "description": "A Backstage plugin that helps you manage GitOps profiles", - "version": "0.3.44-next.1", + "version": "0.3.44", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/gocd/CHANGELOG.md b/plugins/gocd/CHANGELOG.md index ebe8301a7e..884a6fc295 100644 --- a/plugins/gocd/CHANGELOG.md +++ b/plugins/gocd/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-gocd +## 0.1.35 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.35-next.2 ### Patch Changes diff --git a/plugins/gocd/package.json b/plugins/gocd/package.json index f35ab50eaa..ec25c9f7e0 100644 --- a/plugins/gocd/package.json +++ b/plugins/gocd/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-gocd", "description": "A Backstage plugin that integrates towards GoCD", - "version": "0.1.35-next.2", + "version": "0.1.35", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/graphiql/CHANGELOG.md b/plugins/graphiql/CHANGELOG.md index aaf0d835c5..14ce2b20fb 100644 --- a/plugins/graphiql/CHANGELOG.md +++ b/plugins/graphiql/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-graphiql +## 0.3.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.3.2-next.2 ### Patch Changes diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index 5db5a189cd..254356550f 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.3.2-next.2", + "version": "0.3.2", "publishConfig": { "access": "public" }, diff --git a/plugins/graphql-voyager/CHANGELOG.md b/plugins/graphql-voyager/CHANGELOG.md index ee57db87f6..f65e23b8bb 100644 --- a/plugins/graphql-voyager/CHANGELOG.md +++ b/plugins/graphql-voyager/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-graphql-voyager +## 0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.1.11-next.1 ### Patch Changes diff --git a/plugins/graphql-voyager/package.json b/plugins/graphql-voyager/package.json index 7e18c7a486..2a2941b033 100644 --- a/plugins/graphql-voyager/package.json +++ b/plugins/graphql-voyager/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphql-voyager", "description": "Backstage plugin for GraphQL Voyager", - "version": "0.1.11-next.1", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 883f847698..3e877e8a5d 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-home-react +## 0.1.7 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.1.7-next.2 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index eb4609c45f..896d9e46f2 100644 --- a/plugins/home-react/package.json +++ b/plugins/home-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home-react", "description": "A Backstage plugin that contains react components helps you build a home page", - "version": "0.1.7-next.2", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index fc4cb2c393..200ccd0aca 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-home +## 0.6.1 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/core-app-api@1.11.3 + - @backstage/theme@0.5.0 + ## 0.6.1-next.2 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index 0e14c193c9..9eff9d6110 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-home", "description": "A Backstage plugin that helps you build a home page", - "version": "0.6.1-next.2", + "version": "0.6.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/ilert/CHANGELOG.md b/plugins/ilert/CHANGELOG.md index 2dace2438d..e2a55dbc2a 100644 --- a/plugins/ilert/CHANGELOG.md +++ b/plugins/ilert/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-ilert +## 0.2.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.18-next.2 ### Patch Changes diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 66d98511c3..7ef998cc64 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-ilert", "description": "A Backstage plugin that integrates towards iLert", - "version": "0.2.18-next.2", + "version": "0.2.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins-backend/CHANGELOG.md b/plugins/jenkins-backend/CHANGELOG.md index 919d116b6b..04645c8b31 100644 --- a/plugins/jenkins-backend/CHANGELOG.md +++ b/plugins/jenkins-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-jenkins-backend +## 0.3.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.23 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/jenkins-backend/package.json b/plugins/jenkins-backend/package.json index 59a794f2be..0310169606 100644 --- a/plugins/jenkins-backend/package.json +++ b/plugins/jenkins-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins-backend", "description": "A Backstage backend plugin that integrates towards Jenkins", - "version": "0.3.3-next.2", + "version": "0.3.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins-common/CHANGELOG.md b/plugins/jenkins-common/CHANGELOG.md index 04fa14fedc..6d364dc40b 100644 --- a/plugins/jenkins-common/CHANGELOG.md +++ b/plugins/jenkins-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-jenkins-common +## 0.1.23 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.1.22 ### Patch Changes diff --git a/plugins/jenkins-common/package.json b/plugins/jenkins-common/package.json index 5c2d576e90..d61bd6cede 100644 --- a/plugins/jenkins-common/package.json +++ b/plugins/jenkins-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins-common", - "version": "0.1.22", + "version": "0.1.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/jenkins/CHANGELOG.md b/plugins/jenkins/CHANGELOG.md index 0e2d3c9e31..f69387fbdf 100644 --- a/plugins/jenkins/CHANGELOG.md +++ b/plugins/jenkins/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-jenkins +## 0.9.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-jenkins-common@0.1.23 + ## 0.9.4-next.2 ### Patch Changes diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index e3463a840e..87181ac37c 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-jenkins", "description": "A Backstage plugin that integrates towards Jenkins", - "version": "0.9.4-next.2", + "version": "0.9.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kafka-backend/CHANGELOG.md b/plugins/kafka-backend/CHANGELOG.md index b3a33d7a1a..17a3a277e9 100644 --- a/plugins/kafka-backend/CHANGELOG.md +++ b/plugins/kafka-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kafka-backend +## 0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.3.7-next.2 ### Patch Changes diff --git a/plugins/kafka-backend/package.json b/plugins/kafka-backend/package.json index ec5112cfc5..5b8130fa91 100644 --- a/plugins/kafka-backend/package.json +++ b/plugins/kafka-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka-backend", "description": "A Backstage backend plugin that integrates towards Kafka", - "version": "0.3.7-next.2", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kafka/CHANGELOG.md b/plugins/kafka/CHANGELOG.md index 92d2f5d429..4b6a8eda9b 100644 --- a/plugins/kafka/CHANGELOG.md +++ b/plugins/kafka/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kafka +## 0.3.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.3.29-next.2 ### Patch Changes diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index fc237fab6a..ffbeb1c761 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kafka", "description": "A Backstage plugin that integrates towards Kafka", - "version": "0.3.29-next.2", + "version": "0.3.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 0ecf5b915b..d19054eb6b 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/plugin-kubernetes-backend +## 0.14.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration-aws-node@0.1.8 + - @backstage/types@1.1.1 + - @backstage/plugin-kubernetes-node@0.1.3 + ## 0.14.1-next.2 ### Patch Changes diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 3e78f6c4e3..6e80fef004 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-backend", "description": "A Backstage backend plugin that integrates towards Kubernetes", - "version": "0.14.1-next.2", + "version": "0.14.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index 57453f97ec..e24b987e07 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.5 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-react@0.2.1 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.0.5-next.2 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 49e5efc969..cf4d5abdea 100644 --- a/plugins/kubernetes-cluster/package.json +++ b/plugins/kubernetes-cluster/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-cluster", "description": "A Backstage plugin that shows details of Kubernetes clusters", - "version": "0.0.5-next.2", + "version": "0.0.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index 725c5f7887..c49d14f2a8 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kubernetes-common +## 0.7.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + ## 0.7.3-next.0 ### Patch Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index e9f746f41a..994c8e3f88 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-common", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", - "version": "0.7.3-next.0", + "version": "0.7.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index a3e83a30cc..1de200a3f3 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-kubernetes-node +## 0.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + ## 0.1.3-next.2 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index 73e9b661f2..317f75063d 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-node", "description": "Node.js library for the kubernetes plugin", - "version": "0.1.3-next.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index 17f96217c4..12e4f42147 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-kubernetes-react +## 0.2.1 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.1-next.1 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 75a832876b..8389b4d2a9 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes-react", "description": "Web library for the kubernetes-react plugin", - "version": "0.2.1-next.1", + "version": "0.2.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 9a147ee6a5..6f2cc8a23d 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-kubernetes +## 0.11.4 + +### Patch Changes + +- d5d2c67: Add `authuser` search parameter to GKE cluster link formatter in k8s plugin + + Thanks to this, people with multiple simultaneously logged-in accounts in their GCP console will automatically view objects with the same email as the one signed in to the Google auth provider in Backstage. + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-kubernetes-react@0.2.1 + - @backstage/plugin-kubernetes-common@0.7.3 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.11.4-next.2 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 9ba26362fb..858cc7a3c4 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-kubernetes", "description": "A Backstage plugin that integrates towards Kubernetes", - "version": "0.11.4-next.2", + "version": "0.11.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/lighthouse-backend/CHANGELOG.md b/plugins/lighthouse-backend/CHANGELOG.md index 055c008062..c41667aab4 100644 --- a/plugins/lighthouse-backend/CHANGELOG.md +++ b/plugins/lighthouse-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-lighthouse-backend +## 0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-lighthouse-common@0.1.4 + ## 0.4.1-next.2 ### Patch Changes diff --git a/plugins/lighthouse-backend/package.json b/plugins/lighthouse-backend/package.json index 101fc79c21..ac9c844456 100644 --- a/plugins/lighthouse-backend/package.json +++ b/plugins/lighthouse-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse-backend", "description": "Backend functionalities for lighthouse", - "version": "0.4.1-next.2", + "version": "0.4.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/lighthouse/CHANGELOG.md b/plugins/lighthouse/CHANGELOG.md index 335e0190e4..92d919b657 100644 --- a/plugins/lighthouse/CHANGELOG.md +++ b/plugins/lighthouse/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-lighthouse +## 0.4.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-lighthouse-common@0.1.4 + ## 0.4.14-next.2 ### Patch Changes diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 08bbf3b9b0..b71039ce2e 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-lighthouse", "description": "A Backstage plugin that integrates towards Lighthouse", - "version": "0.4.14-next.2", + "version": "0.4.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/linguist-backend/CHANGELOG.md b/plugins/linguist-backend/CHANGELOG.md index ef82a7802f..439c15066a 100644 --- a/plugins/linguist-backend/CHANGELOG.md +++ b/plugins/linguist-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-linguist-backend +## 0.5.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.5.6-next.2 ### Patch Changes diff --git a/plugins/linguist-backend/package.json b/plugins/linguist-backend/package.json index fef88b342a..6f137ad5f6 100644 --- a/plugins/linguist-backend/package.json +++ b/plugins/linguist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist-backend", - "version": "0.5.6-next.2", + "version": "0.5.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/linguist/CHANGELOG.md b/plugins/linguist/CHANGELOG.md index ff4532678c..7e96d237e6 100644 --- a/plugins/linguist/CHANGELOG.md +++ b/plugins/linguist/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-linguist +## 0.1.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- 4f42918: Added alpha support for the New Frontend System (Declarative Integration) +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-linguist-common@0.1.2 + ## 0.1.14-next.2 ### Patch Changes diff --git a/plugins/linguist/package.json b/plugins/linguist/package.json index d3dc972c24..ed38f881de 100644 --- a/plugins/linguist/package.json +++ b/plugins/linguist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-linguist", - "version": "0.1.14-next.2", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/microsoft-calendar/CHANGELOG.md b/plugins/microsoft-calendar/CHANGELOG.md index f8c0239398..86ea39fcff 100644 --- a/plugins/microsoft-calendar/CHANGELOG.md +++ b/plugins/microsoft-calendar/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-microsoft-calendar +## 0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + ## 0.1.11-next.1 ### Patch Changes diff --git a/plugins/microsoft-calendar/package.json b/plugins/microsoft-calendar/package.json index 8ccff05f5b..aec094c029 100644 --- a/plugins/microsoft-calendar/package.json +++ b/plugins/microsoft-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-microsoft-calendar", - "version": "0.1.11-next.1", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/newrelic-dashboard/CHANGELOG.md b/plugins/newrelic-dashboard/CHANGELOG.md index 4a1895ccb5..8b5a6e560a 100644 --- a/plugins/newrelic-dashboard/CHANGELOG.md +++ b/plugins/newrelic-dashboard/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-newrelic-dashboard +## 0.3.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.3.4-next.2 ### Patch Changes diff --git a/plugins/newrelic-dashboard/package.json b/plugins/newrelic-dashboard/package.json index ec8d4ce758..981441b479 100644 --- a/plugins/newrelic-dashboard/package.json +++ b/plugins/newrelic-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic-dashboard", - "version": "0.3.4-next.2", + "version": "0.3.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/newrelic/CHANGELOG.md b/plugins/newrelic/CHANGELOG.md index dfe4f86fb9..8935f6c619 100644 --- a/plugins/newrelic/CHANGELOG.md +++ b/plugins/newrelic/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-newrelic +## 0.3.44 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.3.44-next.1 ### Patch Changes diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 28c7b48870..a67a2203d5 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-newrelic", "description": "A Backstage plugin that integrates towards New Relic", - "version": "0.3.44-next.1", + "version": "0.3.44", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/nomad-backend/CHANGELOG.md b/plugins/nomad-backend/CHANGELOG.md index 18758dda2f..786da63c37 100644 --- a/plugins/nomad-backend/CHANGELOG.md +++ b/plugins/nomad-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-nomad-backend +## 0.1.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.11-next.2 ### Patch Changes diff --git a/plugins/nomad-backend/package.json b/plugins/nomad-backend/package.json index 79938f713b..d206b12398 100644 --- a/plugins/nomad-backend/package.json +++ b/plugins/nomad-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad-backend", - "version": "0.1.11-next.2", + "version": "0.1.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/nomad/CHANGELOG.md b/plugins/nomad/CHANGELOG.md index c947027f20..2640dca7bc 100644 --- a/plugins/nomad/CHANGELOG.md +++ b/plugins/nomad/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-nomad +## 0.1.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.1.10-next.2 ### Patch Changes diff --git a/plugins/nomad/package.json b/plugins/nomad/package.json index b92d593c0e..90df893a93 100644 --- a/plugins/nomad/package.json +++ b/plugins/nomad/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-nomad", - "version": "0.1.10-next.2", + "version": "0.1.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/octopus-deploy/CHANGELOG.md b/plugins/octopus-deploy/CHANGELOG.md index 51a4c3a1f7..2acdc81710 100644 --- a/plugins/octopus-deploy/CHANGELOG.md +++ b/plugins/octopus-deploy/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-octopus-deploy +## 0.2.11 + +### Patch Changes + +- 7d96ba8: added install path and fixed import on plugin-octopus-deploy +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.2.11-next.2 ### Patch Changes diff --git a/plugins/octopus-deploy/package.json b/plugins/octopus-deploy/package.json index e232e608d9..03dd65d5e8 100644 --- a/plugins/octopus-deploy/package.json +++ b/plugins/octopus-deploy/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-octopus-deploy", - "version": "0.2.11-next.2", + "version": "0.2.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/opencost/CHANGELOG.md b/plugins/opencost/CHANGELOG.md index 01938b2d63..16d73b63d2 100644 --- a/plugins/opencost/CHANGELOG.md +++ b/plugins/opencost/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-opencost +## 0.2.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.2.4-next.1 ### Patch Changes diff --git a/plugins/opencost/package.json b/plugins/opencost/package.json index e6ab5dd553..1e1b4fb674 100644 --- a/plugins/opencost/package.json +++ b/plugins/opencost/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-opencost", - "version": "0.2.4-next.1", + "version": "0.2.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index d1e3e44c0e..b56074f2cd 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-org-react +## 0.1.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.1.18-next.2 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index ae3fb70ea8..07ae6b82b0 100644 --- a/plugins/org-react/package.json +++ b/plugins/org-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org-react", - "version": "0.1.18-next.2", + "version": "0.1.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 6c1706c46f..c36bf88714 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-org +## 0.6.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-catalog-common@1.0.20 + ## 0.6.19-next.2 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index a3494f1b8b..c4035a8498 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-org", "description": "A Backstage plugin that helps you create entity pages for your organization", - "version": "0.6.19-next.2", + "version": "0.6.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/pagerduty/CHANGELOG.md b/plugins/pagerduty/CHANGELOG.md index db12245793..8e48fcf210 100644 --- a/plugins/pagerduty/CHANGELOG.md +++ b/plugins/pagerduty/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-pagerduty +## 0.7.1 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.7.1-next.2 ### Patch Changes diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 6b6c921da6..2526d7ca99 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-pagerduty", "description": "This plugin has been deprecated, consider using [@pagerduty/backstage-plugin](https://github.com/pagerduty/backstage-plugin) instead.", - "version": "0.7.1-next.2", + "version": "0.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/periskop-backend/CHANGELOG.md b/plugins/periskop-backend/CHANGELOG.md index f22b5a12c7..2a94efd57e 100644 --- a/plugins/periskop-backend/CHANGELOG.md +++ b/plugins/periskop-backend/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-periskop-backend +## 0.2.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + ## 0.2.7-next.2 ### Patch Changes diff --git a/plugins/periskop-backend/package.json b/plugins/periskop-backend/package.json index bb19ff995f..992e047346 100644 --- a/plugins/periskop-backend/package.json +++ b/plugins/periskop-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop-backend", - "version": "0.2.7-next.2", + "version": "0.2.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/periskop/CHANGELOG.md b/plugins/periskop/CHANGELOG.md index 719ac2023d..b29b672e96 100644 --- a/plugins/periskop/CHANGELOG.md +++ b/plugins/periskop/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-periskop +## 0.1.27 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.27-next.2 ### Patch Changes diff --git a/plugins/periskop/package.json b/plugins/periskop/package.json index 7a96359c86..acb7a68241 100644 --- a/plugins/periskop/package.json +++ b/plugins/periskop/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-periskop", - "version": "0.1.27-next.2", + "version": "0.1.27", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index df80176895..e5e4d93fa3 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.1.6 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + ## 0.1.6-next.2 ### Patch Changes diff --git a/plugins/permission-backend-module-policy-allow-all/package.json b/plugins/permission-backend-module-policy-allow-all/package.json index 74a0ca58d2..f03a5481d3 100644 --- a/plugins/permission-backend-module-policy-allow-all/package.json +++ b/plugins/permission-backend-module-policy-allow-all/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-backend-module-allow-all-policy", "description": "Allow all policy backend module for the permission plugin.", - "version": "0.1.6-next.2", + "version": "0.1.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-backend/CHANGELOG.md b/plugins/permission-backend/CHANGELOG.md index fdf78f2004..43c5e85b4f 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-permission-backend +## 0.5.32 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.5.32-next.2 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index e867a4a69e..c8c908eccb 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.5.32-next.2", + "version": "0.5.32", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index 862e8db4a5..74bd6db59b 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-permission-common +## 0.7.12 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.7.11 ### Patch Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index 2907347889..b0ca7d74bf 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-common", "description": "Isomorphic types and client for Backstage permissions and authorization", - "version": "0.7.11", + "version": "0.7.12", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index b063aad38c..5f66d4a337 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-permission-node +## 0.7.20 + +### Patch Changes + +- b1acd9b: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.7.20-next.2 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 6742a43968..5ce7217d6c 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-permission-node", "description": "Common permission and authorization utilities for backend plugins", - "version": "0.7.20-next.2", + "version": "0.7.20", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index 81be97c58f..a432970e3f 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-permission-react +## 0.4.19 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- b1acd9b: Updated README +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/config@1.1.1 + ## 0.4.19-next.1 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index 10d0a8d3ae..7949433aa9 100644 --- a/plugins/permission-react/package.json +++ b/plugins/permission-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-react", - "version": "0.4.19-next.1", + "version": "0.4.19", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist-backend/CHANGELOG.md b/plugins/playlist-backend/CHANGELOG.md index 86dc5201a0..00e1c5be53 100644 --- a/plugins/playlist-backend/CHANGELOG.md +++ b/plugins/playlist-backend/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-playlist-backend +## 0.3.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-playlist-common@0.1.14 + ## 0.3.13-next.2 ### Patch Changes diff --git a/plugins/playlist-backend/package.json b/plugins/playlist-backend/package.json index 3d13d3049d..8b872b6e67 100644 --- a/plugins/playlist-backend/package.json +++ b/plugins/playlist-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist-backend", - "version": "0.3.13-next.2", + "version": "0.3.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist-common/CHANGELOG.md b/plugins/playlist-common/CHANGELOG.md index 3fcdbfc5bc..0b65ee551f 100644 --- a/plugins/playlist-common/CHANGELOG.md +++ b/plugins/playlist-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-playlist-common +## 0.1.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + ## 0.1.13 ### Patch Changes diff --git a/plugins/playlist-common/package.json b/plugins/playlist-common/package.json index 7d42844986..9ab95c4c8a 100644 --- a/plugins/playlist-common/package.json +++ b/plugins/playlist-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-playlist-common", "description": "Common functionalities for the playlist plugin", - "version": "0.1.13", + "version": "0.1.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/playlist/CHANGELOG.md b/plugins/playlist/CHANGELOG.md index f28d63c4fb..f35b2a149a 100644 --- a/plugins/playlist/CHANGELOG.md +++ b/plugins/playlist/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-playlist +## 0.2.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-search-react@1.7.5 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-playlist-common@0.1.14 + ## 0.2.3-next.2 ### Patch Changes diff --git a/plugins/playlist/package.json b/plugins/playlist/package.json index 622dab7346..34d2911685 100644 --- a/plugins/playlist/package.json +++ b/plugins/playlist/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-playlist", - "version": "0.2.3-next.2", + "version": "0.2.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index 6bfdbbe9fc..e6649758f7 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-proxy-backend +## 0.4.7 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + ## 0.4.7-next.2 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 5cc5f67973..1e042a1bdc 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-proxy-backend", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", - "version": "0.4.7-next.2", + "version": "0.4.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/puppetdb/CHANGELOG.md b/plugins/puppetdb/CHANGELOG.md index 808df46247..9e8b991e02 100644 --- a/plugins/puppetdb/CHANGELOG.md +++ b/plugins/puppetdb/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-puppetdb +## 0.1.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.12-next.2 ### Patch Changes diff --git a/plugins/puppetdb/package.json b/plugins/puppetdb/package.json index e1423121f8..0d1cc3d44e 100644 --- a/plugins/puppetdb/package.json +++ b/plugins/puppetdb/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-puppetdb", "description": "Backstage plugin to visualize resource information and Puppet facts from PuppetDB.", - "version": "0.1.12-next.2", + "version": "0.1.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar-backend/CHANGELOG.md b/plugins/rollbar-backend/CHANGELOG.md index c836e5f15d..4c14f2c9f9 100644 --- a/plugins/rollbar-backend/CHANGELOG.md +++ b/plugins/rollbar-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-rollbar-backend +## 0.1.54 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + ## 0.1.54-next.2 ### Patch Changes diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index 19b6177f15..730bc3e6f3 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar-backend", "description": "A Backstage backend plugin that integrates towards Rollbar", - "version": "0.1.54-next.2", + "version": "0.1.54", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/rollbar/CHANGELOG.md b/plugins/rollbar/CHANGELOG.md index 3400094c23..494dce0fe9 100644 --- a/plugins/rollbar/CHANGELOG.md +++ b/plugins/rollbar/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-rollbar +## 0.4.29 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.4.29-next.2 ### Patch Changes diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 4836a9d894..a49254e366 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-rollbar", "description": "A Backstage plugin that integrates towards Rollbar", - "version": "0.4.29-next.2", + "version": "0.4.29", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index 05bbe1446e..3f56f61339 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.1.1 + +### Patch Changes + +- d076ee4: Updated dependency `azure-devops-node-api` to `^12.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index f7a8e022f9..ce53811f15 100644 --- a/plugins/scaffolder-backend-module-azure/package.json +++ b/plugins/scaffolder-backend-module-azure/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-azure", "description": "The azure module for @backstage/plugin-scaffolder-backend", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 1207c09620..c94898c953 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.1.1 + +### Patch Changes + +- a694f71: The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index 358f95b740..03ebab43fc 100644 --- a/plugins/scaffolder-backend-module-bitbucket/package.json +++ b/plugins/scaffolder-backend-module-bitbucket/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-bitbucket", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index 648bdddb61..075d8db3b9 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.2.10 + +### Patch Changes + +- 7acbb5a: Removed `mock-fs` dev dependency. +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.2.10-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json index e429e615f1..2f0bd5188c 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/package.json +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", - "version": "0.2.10-next.2", + "version": "0.2.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 322004c912..541255a2d0 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.2.33 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + ## 0.2.33-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index dd3f1555cc..98e96a491d 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/package.json +++ b/plugins/scaffolder-backend-module-cookiecutter/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-cookiecutter", "description": "A module for the scaffolder backend that lets you template projects using cookiecutter", - "version": "0.2.33-next.2", + "version": "0.2.33", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md index aba1547066..361549275a 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 1ac8d71c3e..59159560b5 100644 --- a/plugins/scaffolder-backend-module-gerrit/package.json +++ b/plugins/scaffolder-backend-module-gerrit/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gerrit", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index 9f63b4ffae..0f0ce0a045 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.1.1 + +### Patch Changes + +- 5470300: Ensure `teamReviewers` list is unique before calling API +- bf92ae3: Updated dependency `octokit` to `^3.0.0`. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.1.1-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index 3231536901..b035096dad 100644 --- a/plugins/scaffolder-backend-module-github/package.json +++ b/plugins/scaffolder-backend-module-github/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-github", "description": "The github module for @backstage/plugin-scaffolder-backend", - "version": "0.1.1-next.2", + "version": "0.1.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 3968582cc5..9c7d462cda 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.2.12 + +### Patch Changes + +- 604c9dd: Add Scaffolder custom action that creates GitLab issues called `gitlab:issues:create` +- 7c522c5: Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.2.12-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index f6a15afa1a..ca7e90f8c8 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-gitlab", - "version": "0.2.12-next.2", + "version": "0.2.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-rails/CHANGELOG.md b/plugins/scaffolder-backend-module-rails/CHANGELOG.md index 476b7338fc..a923feec27 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.4.26 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + ## 0.4.26-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 44aa369aab..65969643c1 100644 --- a/plugins/scaffolder-backend-module-rails/package.json +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend-module-rails", "description": "A module for the scaffolder backend that lets you template projects using Rails", - "version": "0.4.26-next.2", + "version": "0.4.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md index 39579fd6f2..5ba8dd0f05 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.1.17-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index 62c38fc5ca..7828713d08 100644 --- a/plugins/scaffolder-backend-module-sentry/package.json +++ b/plugins/scaffolder-backend-module-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-sentry", - "version": "0.1.17-next.2", + "version": "0.1.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index a4236219e2..1b4858dec9 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.2.30 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/types@1.1.1 + ## 0.2.30-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index c230a97881..94883084e4 100644 --- a/plugins/scaffolder-backend-module-yeoman/package.json +++ b/plugins/scaffolder-backend-module-yeoman/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend-module-yeoman", - "version": "0.2.30-next.2", + "version": "0.2.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 2b62c627c2..2fb35e3d24 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-scaffolder-backend +## 1.20.0 + +### Minor Changes + +- a694f71: The Scaffolder builtin actions now contains an action for running pipelines from Bitbucket Cloud Rest API +- 7c522c5: Add `gitlab:repo:push` scaffolder action to push files to arbitrary branch without creating a Merge Request + +### Patch Changes + +- e9ab1c4: Fixed an issue where not passing a `value` to any of the action's permission conditions caused an error. +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-backend-module-github@0.1.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.2.12 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.1.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-scaffolder-backend-module-azure@0.1.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.1.6 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.1.1 + - @backstage/plugin-scaffolder-node@0.2.10 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + ## 1.19.3-next.2 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 55640ceff4..24325449b3 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "1.19.3-next.2", + "version": "1.20.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 35d5782df7..dfc6b310ed 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-scaffolder-common +## 1.4.5 + +### Patch Changes + +- 178b8d8: Updated Template.v1beta3.schema.json, added a missing "presentation" field +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/catalog-model@1.4.3 + - @backstage/types@1.1.1 + ## 1.4.4 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 73fa8e760e..699867fbb1 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-common", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", - "version": "1.4.4", + "version": "1.4.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 0ca6a7b633..49ea604b11 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-scaffolder-node +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + ## 0.2.10-next.2 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index e21f5d5214..b4c843ce65 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-node", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", - "version": "0.2.10-next.2", + "version": "0.2.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index ce01b049e2..89468800e8 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,28 @@ # @backstage/plugin-scaffolder-react +## 1.7.1 + +### Patch Changes + +- c28f281: Scaffolder form now shows a list of errors at the top of the form. +- 0b9ce2b: Fix for a step with no properties +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- d16f85f: Show first scaffolder output text by default +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 1.7.1-next.2 ### Patch Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index dee80c50c3..f8390667be 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-react", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", - "version": "1.7.1-next.2", + "version": "1.7.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 77aa66190f..8482d41538 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,30 @@ # @backstage/plugin-scaffolder +## 1.17.1 + +### Patch Changes + +- 98ac5ab: Updated dependency `@rjsf/utils` to `5.15.1`. + Updated dependency `@rjsf/core` to `5.15.1`. + Updated dependency `@rjsf/material-ui` to `5.15.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.15.1`. +- 4016f21: Remove some unused dependencies +- df4bc9d: Minor internal refactor +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.7.1 + - @backstage/core-components@0.13.10 + - @backstage/plugin-scaffolder-common@1.4.5 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-permission-react@0.4.19 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/types@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + ## 1.17.1-next.2 ### Patch Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index d6fd2b3f85..690af2f971 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder", "description": "The Backstage plugin that helps you create new things", - "version": "1.17.1-next.2", + "version": "1.17.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 4af9c4d5a3..23827255ac 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-search-backend-module-catalog +## 0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + ## 0.1.13-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 90c469e31d..0b70450eb3 100644 --- a/plugins/search-backend-module-catalog/package.json +++ b/plugins/search-backend-module-catalog/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-catalog", "description": "A module for the search backend that exports catalog modules", - "version": "0.1.13-next.2", + "version": "0.1.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 67c32fd11b..6fd51ed2c3 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.3.12 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.10 + ## 1.3.12-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 35cb46d9ef..3a902ef255 100644 --- a/plugins/search-backend-module-elasticsearch/package.json +++ b/plugins/search-backend-module-elasticsearch/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-elasticsearch", "description": "A module for the search backend that implements search using ElasticSearch", - "version": "1.3.12-next.2", + "version": "1.3.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 8af09c36b8..42465f4002 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-search-backend-module-explore +## 0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-explore-common@0.0.2 + - @backstage/plugin-search-common@1.2.10 + ## 0.1.13-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index 348c525b90..d238ca0c68 100644 --- a/plugins/search-backend-module-explore/package.json +++ b/plugins/search-backend-module-explore/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-explore", "description": "A module for the search backend that exports explore modules", - "version": "0.1.13-next.2", + "version": "0.1.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index e3b518242e..b186b5f409 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.18 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + ## 0.5.18-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index ca6e7fc4f0..17db1d9e38 100644 --- a/plugins/search-backend-module-pg/package.json +++ b/plugins/search-backend-module-pg/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-pg", "description": "A module for the search backend that implements search using PostgreSQL", - "version": "0.5.18-next.2", + "version": "0.5.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md index ed8740b1c0..49ddce1d45 100644 --- a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md +++ b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-backend-module-stack-overflow-collator +## 0.1.2 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-stack-overflow-collator/package.json b/plugins/search-backend-module-stack-overflow-collator/package.json index 9d523451e0..2c5508384c 100644 --- a/plugins/search-backend-module-stack-overflow-collator/package.json +++ b/plugins/search-backend-module-stack-overflow-collator/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-stack-overflow-collator", "description": "A module for the search backend that exports stack overflow modules", - "version": "0.1.2-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index 69654e06f6..48ca80346c 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.1.13 + +### Patch Changes + +- 2e6c56b: Update wording to show that the backend system no longer is in alpha +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/plugin-catalog-common@1.0.20 + - @backstage/plugin-search-common@1.2.10 + ## 0.1.13-next.2 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index 11f588842f..7db87300cf 100644 --- a/plugins/search-backend-module-techdocs/package.json +++ b/plugins/search-backend-module-techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-module-techdocs", "description": "A module for the search backend that exports techdocs modules", - "version": "0.1.13-next.2", + "version": "0.1.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index 47ff37deb5..d9ada5e4ed 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-backend-node +## 1.2.13 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-search-common@1.2.10 + ## 1.2.13-next.2 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 8f3e736e37..b598793b88 100644 --- a/plugins/search-backend-node/package.json +++ b/plugins/search-backend-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend-node", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", - "version": "1.2.13-next.2", + "version": "1.2.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index b63256ad36..334c303d03 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-search-backend +## 1.4.9 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-permission-node@0.7.20 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/plugin-search-backend-node@1.2.13 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-search-common@1.2.10 + ## 1.4.9-next.2 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 4b169aeaea..bea288f6b2 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-backend", "description": "The Backstage backend plugin that provides your backstage app with search", - "version": "1.4.9-next.2", + "version": "1.4.9", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search-common/CHANGELOG.md b/plugins/search-common/CHANGELOG.md index 3263e8305c..d14a8e37b3 100644 --- a/plugins/search-common/CHANGELOG.md +++ b/plugins/search-common/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-search-common +## 1.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.7.12 + - @backstage/types@1.1.1 + ## 1.2.9 ### Patch Changes diff --git a/plugins/search-common/package.json b/plugins/search-common/package.json index 7f02f8a359..e753ea764c 100644 --- a/plugins/search-common/package.json +++ b/plugins/search-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search-common", "description": "Common functionalities for Search, to be shared between various search-enabled plugins", - "version": "1.2.9", + "version": "1.2.10", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index 7a10ac97c3..08cb2bee1e 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-search-react +## 1.7.5 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.10 + ## 1.7.5-next.2 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index a2e8f4a1e9..c62e5e19b9 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.7.5-next.2", + "version": "1.7.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index a733ec9a46..5acf5eea57 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/plugin-search +## 1.4.5 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/version-bridge@1.0.7 + - @backstage/plugin-search-common@1.2.10 + ## 1.4.5-next.2 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 26f112a4fc..20ad8319e8 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-search", "description": "The Backstage plugin that provides your backstage app with search", - "version": "1.4.5-next.2", + "version": "1.4.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sentry/CHANGELOG.md b/plugins/sentry/CHANGELOG.md index 20368e375b..2ed4f848cf 100644 --- a/plugins/sentry/CHANGELOG.md +++ b/plugins/sentry/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-sentry +## 0.5.14 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.5.14-next.2 ### Patch Changes diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 2c1392df7a..f6bf651f69 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sentry", "description": "A Backstage plugin that integrates towards Sentry", - "version": "0.5.14-next.2", + "version": "0.5.14", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/shortcuts/CHANGELOG.md b/plugins/shortcuts/CHANGELOG.md index b8bf81789c..d819ae5921 100644 --- a/plugins/shortcuts/CHANGELOG.md +++ b/plugins/shortcuts/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-shortcuts +## 0.3.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + ## 0.3.18-next.1 ### Patch Changes diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index a1abfccc3c..867e28dfa4 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-shortcuts", "description": "A Backstage plugin that provides a shortcuts feature to the sidebar", - "version": "0.3.18-next.1", + "version": "0.3.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube-backend/CHANGELOG.md b/plugins/sonarqube-backend/CHANGELOG.md index 8a1b277e4c..87231ab9af 100644 --- a/plugins/sonarqube-backend/CHANGELOG.md +++ b/plugins/sonarqube-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-sonarqube-backend +## 0.2.11 + +### Patch Changes + +- 53445cd: Updated README +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + ## 0.2.11-next.2 ### Patch Changes diff --git a/plugins/sonarqube-backend/package.json b/plugins/sonarqube-backend/package.json index c151767bab..91f11aabfb 100644 --- a/plugins/sonarqube-backend/package.json +++ b/plugins/sonarqube-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-backend", - "version": "0.2.11-next.2", + "version": "0.2.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube-react/CHANGELOG.md b/plugins/sonarqube-react/CHANGELOG.md index aa62e7d7bf..b011d429fd 100644 --- a/plugins/sonarqube-react/CHANGELOG.md +++ b/plugins/sonarqube-react/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-sonarqube-react +## 0.1.12 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + ## 0.1.12-next.0 ### Patch Changes diff --git a/plugins/sonarqube-react/package.json b/plugins/sonarqube-react/package.json index 7ed2bd32f4..a2c3b8268d 100644 --- a/plugins/sonarqube-react/package.json +++ b/plugins/sonarqube-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sonarqube-react", - "version": "0.1.12-next.0", + "version": "0.1.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/sonarqube/CHANGELOG.md b/plugins/sonarqube/CHANGELOG.md index 8d16295cc9..36734946b6 100644 --- a/plugins/sonarqube/CHANGELOG.md +++ b/plugins/sonarqube/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-sonarqube +## 0.7.11 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/plugin-sonarqube-react@0.1.12 + ## 0.7.11-next.2 ### Patch Changes diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 473a543b0e..9d91262e01 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-sonarqube", "description": "", - "version": "0.7.11-next.2", + "version": "0.7.11", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/splunk-on-call/CHANGELOG.md b/plugins/splunk-on-call/CHANGELOG.md index 979e99cba2..ae6eba08f7 100644 --- a/plugins/splunk-on-call/CHANGELOG.md +++ b/plugins/splunk-on-call/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-splunk-on-call +## 0.4.18 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + ## 0.4.18-next.2 ### Patch Changes diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index cc4da14a72..ee5b1b17cd 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-splunk-on-call", "description": "A Backstage plugin that integrates towards Splunk On-Call", - "version": "0.4.18-next.2", + "version": "0.4.18", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stack-overflow-backend/CHANGELOG.md b/plugins/stack-overflow-backend/CHANGELOG.md index 9695482f01..ac375db564 100644 --- a/plugins/stack-overflow-backend/CHANGELOG.md +++ b/plugins/stack-overflow-backend/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/plugin-stack-overflow-backend +## 0.2.13 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/plugin-search-backend-module-stack-overflow-collator@0.1.2 + ## 0.2.13-next.2 ### Patch Changes diff --git a/plugins/stack-overflow-backend/package.json b/plugins/stack-overflow-backend/package.json index 77a1072150..9356be7bd2 100644 --- a/plugins/stack-overflow-backend/package.json +++ b/plugins/stack-overflow-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-stack-overflow-backend", "description": "Deprecated, consider using @backstage/plugin-search-backend-module-stack-overflow-collator instead", - "version": "0.2.13-next.2", + "version": "0.2.13", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stack-overflow/CHANGELOG.md b/plugins/stack-overflow/CHANGELOG.md index 7bef72cc3a..f13fefd91a 100644 --- a/plugins/stack-overflow/CHANGELOG.md +++ b/plugins/stack-overflow/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-stack-overflow +## 0.1.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-home-react@0.1.7 + - @backstage/plugin-search-react@1.7.5 + - @backstage/config@1.1.1 + - @backstage/plugin-search-common@1.2.10 + ## 0.1.24-next.2 ### Patch Changes diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json index 1b5da9ae13..dcce8e793f 100644 --- a/plugins/stack-overflow/package.json +++ b/plugins/stack-overflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-stack-overflow", - "version": "0.1.24-next.2", + "version": "0.1.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/stackstorm/CHANGELOG.md b/plugins/stackstorm/CHANGELOG.md index be02933ca6..dcade807b8 100644 --- a/plugins/stackstorm/CHANGELOG.md +++ b/plugins/stackstorm/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-stackstorm +## 0.1.10 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + ## 0.1.10-next.1 ### Patch Changes diff --git a/plugins/stackstorm/package.json b/plugins/stackstorm/package.json index f2c85ed5b9..d22b17be40 100644 --- a/plugins/stackstorm/package.json +++ b/plugins/stackstorm/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-stackstorm", "description": "A Backstage plugin that integrates towards StackStorm", - "version": "0.1.10-next.1", + "version": "0.1.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md index cc9313e90a..d90a7f158a 100644 --- a/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md +++ b/plugins/tech-insights-backend-module-jsonfc/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-backend-module-jsonfc +## 0.1.41 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/errors@1.2.3 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.1.41-next.2 ### Patch Changes diff --git a/plugins/tech-insights-backend-module-jsonfc/package.json b/plugins/tech-insights-backend-module-jsonfc/package.json index 89cc4031d8..3a17a952d8 100644 --- a/plugins/tech-insights-backend-module-jsonfc/package.json +++ b/plugins/tech-insights-backend-module-jsonfc/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend-module-jsonfc", - "version": "0.1.41-next.2", + "version": "0.1.41", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-backend/CHANGELOG.md b/plugins/tech-insights-backend/CHANGELOG.md index c9b59e5ad8..3812ef6d91 100644 --- a/plugins/tech-insights-backend/CHANGELOG.md +++ b/plugins/tech-insights-backend/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-tech-insights-backend +## 0.5.23 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-tech-insights-node@0.4.15 + - @backstage/backend-tasks@0.5.14 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.5.23-next.2 ### Patch Changes diff --git a/plugins/tech-insights-backend/package.json b/plugins/tech-insights-backend/package.json index 307e97c1ab..92a3399683 100644 --- a/plugins/tech-insights-backend/package.json +++ b/plugins/tech-insights-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-backend", - "version": "0.5.23-next.2", + "version": "0.5.23", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights-node/CHANGELOG.md b/plugins/tech-insights-node/CHANGELOG.md index 6a877f1177..a93118ad6a 100644 --- a/plugins/tech-insights-node/CHANGELOG.md +++ b/plugins/tech-insights-node/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-insights-node +## 0.4.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/config@1.1.1 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.4.15-next.2 ### Patch Changes diff --git a/plugins/tech-insights-node/package.json b/plugins/tech-insights-node/package.json index 469bfb5601..824b4cb752 100644 --- a/plugins/tech-insights-node/package.json +++ b/plugins/tech-insights-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights-node", - "version": "0.4.15-next.2", + "version": "0.4.15", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-insights/CHANGELOG.md b/plugins/tech-insights/CHANGELOG.md index afe3a21dec..81349dfe8f 100644 --- a/plugins/tech-insights/CHANGELOG.md +++ b/plugins/tech-insights/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-tech-insights +## 0.3.21 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + - @backstage/plugin-tech-insights-common@0.2.12 + ## 0.3.21-next.2 ### Patch Changes diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index 236ebd6b12..c37d516e06 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-insights", - "version": "0.3.21-next.2", + "version": "0.3.21", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/tech-radar/CHANGELOG.md b/plugins/tech-radar/CHANGELOG.md index 366ef940f6..073fe92739 100644 --- a/plugins/tech-radar/CHANGELOG.md +++ b/plugins/tech-radar/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-tech-radar +## 0.6.12 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + ## 0.6.12-next.2 ### Patch Changes diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 0536114019..b94382a239 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-tech-radar", "description": "A Backstage plugin that lets you display a Tech Radar for your organization", - "version": "0.6.12-next.2", + "version": "0.6.12", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-addons-test-utils/CHANGELOG.md b/plugins/techdocs-addons-test-utils/CHANGELOG.md index 2689d6ef64..9ceb5d0a09 100644 --- a/plugins/techdocs-addons-test-utils/CHANGELOG.md +++ b/plugins/techdocs-addons-test-utils/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-techdocs-addons-test-utils +## 1.0.26 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-techdocs@1.9.3 + - @backstage/plugin-catalog@1.16.1 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/core-app-api@1.11.3 + - @backstage/test-utils@1.4.7 + ## 1.0.26-next.2 ### Patch Changes diff --git a/plugins/techdocs-addons-test-utils/package.json b/plugins/techdocs-addons-test-utils/package.json index c46e3e679f..bd150c9326 100644 --- a/plugins/techdocs-addons-test-utils/package.json +++ b/plugins/techdocs-addons-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-addons-test-utils", - "version": "1.0.26-next.2", + "version": "1.0.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-backend/CHANGELOG.md b/plugins/techdocs-backend/CHANGELOG.md index 0f1e623fa9..25116c2810 100644 --- a/plugins/techdocs-backend/CHANGELOG.md +++ b/plugins/techdocs-backend/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-techdocs-backend +## 1.9.2 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/plugin-search-backend-module-techdocs@0.1.13 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-permission-common@0.7.12 + - @backstage/plugin-techdocs-node@1.11.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/plugin-catalog-common@1.0.20 + ## 1.9.2-next.2 ### Patch Changes diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index bcaf6ba079..1f13ed3d5c 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-backend", "description": "The Backstage backend plugin that renders technical documentation for your components", - "version": "1.9.2-next.2", + "version": "1.9.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index 7aa5393113..c6c4070487 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.4 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/integration-react@1.1.23 + - @backstage/integration@1.8.0 + ## 1.1.4-next.1 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index f29baf4c05..1d296eb158 100644 --- a/plugins/techdocs-module-addons-contrib/package.json +++ b/plugins/techdocs-module-addons-contrib/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-module-addons-contrib", "description": "Plugin module for contributed TechDocs Addons", - "version": "1.1.4-next.1", + "version": "1.1.4", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/techdocs-node/CHANGELOG.md b/plugins/techdocs-node/CHANGELOG.md index 770292f8c6..c4aeb5c4d7 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-techdocs-node +## 1.11.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/integration-aws-node@0.1.8 + - @backstage/plugin-search-common@1.2.10 + ## 1.11.1-next.2 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index e983e235c4..592ae94151 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-node", "description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli", - "version": "1.11.1-next.2", + "version": "1.11.1", "main": "src/index.ts", "types": "src/index.ts", "publishConfig": { diff --git a/plugins/techdocs-react/CHANGELOG.md b/plugins/techdocs-react/CHANGELOG.md index a6273af03c..7017882a65 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-techdocs-react +## 1.1.15 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/version-bridge@1.0.7 + ## 1.1.15-next.1 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index 3be8499a2d..1bdb2a29c8 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs-react", "description": "Shared frontend utilities for TechDocs and Addons", - "version": "1.1.15-next.1", + "version": "1.1.15", "publishConfig": { "access": "public", "main": "dist/index.esm.js", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 0410402b8d..9a982a80f5 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-techdocs +## 1.9.3 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-techdocs-react@1.1.15 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/plugin-search-react@1.7.5 + - @backstage/integration-react@1.1.23 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + - @backstage/theme@0.5.0 + - @backstage/plugin-search-common@1.2.10 + ## 1.9.3-next.2 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 1ea3cd3e5d..51c631e8ec 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "1.9.3-next.2", + "version": "1.9.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/todo-backend/CHANGELOG.md b/plugins/todo-backend/CHANGELOG.md index 8fba287cb4..bbda40e0a7 100644 --- a/plugins/todo-backend/CHANGELOG.md +++ b/plugins/todo-backend/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-todo-backend +## 0.3.7 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/catalog-client@1.5.2 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-openapi-utils@0.1.2 + - @backstage/plugin-catalog-node@1.6.1 + - @backstage/catalog-model@1.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/integration@1.8.0 + ## 0.3.7-next.2 ### Patch Changes diff --git a/plugins/todo-backend/package.json b/plugins/todo-backend/package.json index ed08369624..ddf3baac3d 100644 --- a/plugins/todo-backend/package.json +++ b/plugins/todo-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo-backend", "description": "A Backstage backend plugin that lets you browse TODO comments in your source code", - "version": "0.3.7-next.2", + "version": "0.3.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/todo/CHANGELOG.md b/plugins/todo/CHANGELOG.md index c477dd098f..bc736a73fc 100644 --- a/plugins/todo/CHANGELOG.md +++ b/plugins/todo/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-todo +## 0.2.33 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.2.33-next.2 ### Patch Changes diff --git a/plugins/todo/package.json b/plugins/todo/package.json index b06baf040b..d7ee6b83c0 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-todo", "description": "A Backstage plugin that lets you browse TODO comments in your source code", - "version": "0.2.33-next.2", + "version": "0.2.33", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 3b1d01c240..c9ab9a3263 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,18 @@ # @backstage/plugin-user-settings-backend +## 0.2.8 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/plugin-auth-node@0.4.3 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/types@1.1.1 + ## 0.2.8-next.2 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index 276a6eaa4a..d3c3abca49 100644 --- a/plugins/user-settings-backend/package.json +++ b/plugins/user-settings-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings-backend", "description": "The Backstage backend plugin to manage user settings", - "version": "0.2.8-next.2", + "version": "0.2.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/user-settings/CHANGELOG.md b/plugins/user-settings/CHANGELOG.md index 333f0f334c..e733ca5372 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,26 @@ # @backstage/plugin-user-settings +## 0.8.0 + +### Minor Changes + +- 56b2fb0: Updated the user settings selector to use a select component that displays native language names instead of language codes if possible. + +### Patch Changes + +- eea0849: add user-settings declarative integration core nav item +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-compat-api@0.1.1 + - @backstage/frontend-plugin-api@0.5.0 + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/core-app-api@1.11.3 + - @backstage/errors@1.2.3 + - @backstage/theme@0.5.0 + - @backstage/types@1.1.1 + ## 0.8.0-next.2 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 7f98fa8de9..c873786874 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-user-settings", "description": "A Backstage plugin that provides a settings page", - "version": "0.8.0-next.2", + "version": "0.8.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault-backend/CHANGELOG.md b/plugins/vault-backend/CHANGELOG.md index 8fd4b0e95f..efc029a962 100644 --- a/plugins/vault-backend/CHANGELOG.md +++ b/plugins/vault-backend/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-vault-backend +## 0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-common@0.20.1 + - @backstage/backend-plugin-api@0.6.9 + - @backstage/backend-tasks@0.5.14 + - @backstage/config@1.1.1 + - @backstage/errors@1.2.3 + - @backstage/plugin-vault-node@0.1.2 + ## 0.4.2-next.2 ### Patch Changes diff --git a/plugins/vault-backend/package.json b/plugins/vault-backend/package.json index e262825a48..ed98b0f441 100644 --- a/plugins/vault-backend/package.json +++ b/plugins/vault-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault-backend", "description": "A Backstage backend plugin that integrates towards Vault", - "version": "0.4.2-next.2", + "version": "0.4.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault-node/CHANGELOG.md b/plugins/vault-node/CHANGELOG.md index 901b22a638..7b7c8e0d6e 100644 --- a/plugins/vault-node/CHANGELOG.md +++ b/plugins/vault-node/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-vault-node +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@0.6.9 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/vault-node/package.json b/plugins/vault-node/package.json index 780d5ff5bb..b3977cf3a5 100644 --- a/plugins/vault-node/package.json +++ b/plugins/vault-node/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault-node", "description": "Node.js library for the vault plugin", - "version": "0.1.2-next.2", + "version": "0.1.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/vault/CHANGELOG.md b/plugins/vault/CHANGELOG.md index 93a69e5e76..bb5e881c8f 100644 --- a/plugins/vault/CHANGELOG.md +++ b/plugins/vault/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/plugin-vault +## 0.1.24 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/plugin-catalog-react@1.9.3 + - @backstage/catalog-model@1.4.3 + - @backstage/errors@1.2.3 + ## 0.1.24-next.2 ### Patch Changes diff --git a/plugins/vault/package.json b/plugins/vault/package.json index ce7b7a0dcb..2ad4f60d66 100644 --- a/plugins/vault/package.json +++ b/plugins/vault/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-vault", "description": "A Backstage plugin that integrates towards Vault", - "version": "0.1.24-next.2", + "version": "0.1.24", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/plugins/xcmetrics/CHANGELOG.md b/plugins/xcmetrics/CHANGELOG.md index 2a24ea4d43..1fc98ffa8b 100644 --- a/plugins/xcmetrics/CHANGELOG.md +++ b/plugins/xcmetrics/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-xcmetrics +## 0.2.47 + +### Patch Changes + +- 4016f21: Remove some unused dependencies +- Updated dependencies + - @backstage/core-components@0.13.10 + - @backstage/core-plugin-api@1.8.2 + - @backstage/errors@1.2.3 + ## 0.2.47-next.1 ### Patch Changes diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 538ed5f993..9ee51bb5c5 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-xcmetrics", "description": "A Backstage plugin that shows XCode build metrics for your components", - "version": "0.2.47-next.1", + "version": "0.2.47", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", diff --git a/yarn.lock b/yarn.lock index 662c9000a6..30474455e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3467,18 +3467,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@npm:^1.5.0": - version: 1.5.1 - resolution: "@backstage/catalog-client@npm:1.5.1" - dependencies: - "@backstage/catalog-model": ^1.4.3 - "@backstage/errors": ^1.2.3 - cross-fetch: ^4.0.0 - uri-template: ^2.0.0 - checksum: 786fa1bafba3d44d88855d8479879577e33816f1f9d2e110b275fc22ca4348f8dce0ebe789d580786a38e9986989c98172f7a07c1e2145b8da689608a2aa4ec2 - languageName: node - linkType: hard - "@backstage/catalog-client@workspace:^, @backstage/catalog-client@workspace:packages/catalog-client": version: 0.0.0-use.local resolution: "@backstage/catalog-client@workspace:packages/catalog-client" @@ -3741,7 +3729,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/config@^1.0.6, @backstage/config@^1.0.7, @backstage/config@^1.1.1, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@^1.0.6, @backstage/config@^1.0.7, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -3814,110 +3802,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-components@npm:^0.12.3": - version: 0.12.5 - resolution: "@backstage/core-components@npm:0.12.5" - dependencies: - "@backstage/config": ^1.0.7 - "@backstage/core-plugin-api": ^1.5.0 - "@backstage/errors": ^1.1.5 - "@backstage/theme": ^0.2.18 - "@backstage/version-bridge": ^1.0.3 - "@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": ^20.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.4.1 - react-helmet: 6.1.0 - react-hook-form: ^7.12.2 - react-markdown: ^8.0.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.10.0 - zod: ~3.18.0 - peerDependencies: - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 - react-dom: ^16.13.1 || ^17.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 8308c1b90247911f6cf22963b530cef169287f508ff29d159d0c83758134dd43bd5acd2113350690a46a02246bc05dca975bcc38325000aefb1c93c80e2f19c7 - languageName: node - linkType: hard - -"@backstage/core-components@npm:^0.13.8, @backstage/core-components@npm:^0.13.9": - version: 0.13.9 - resolution: "@backstage/core-components@npm:0.13.9" - dependencies: - "@backstage/config": ^1.1.1 - "@backstage/core-plugin-api": ^1.8.1 - "@backstage/errors": ^1.2.3 - "@backstage/theme": ^0.5.0 - "@backstage/version-bridge": ^1.0.7 - "@date-io/core": ^1.3.13 - "@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.61 - "@react-hookz/web": ^23.0.0 - "@types/react": ^16.13.1 || ^17.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 - linkify-react: 4.1.3 - linkifyjs: 4.1.3 - lodash: ^4.17.21 - pluralize: ^8.0.0 - qs: ^6.9.4 - rc-progress: 3.5.1 - react-helmet: 6.1.0 - react-hook-form: ^7.12.2 - react-idle-timer: 5.6.2 - react-markdown: ^8.0.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.11 - react-window: ^1.8.6 - remark-gfm: ^3.0.1 - zen-observable: ^0.10.0 - zod: ^3.22.4 - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 6674d70f5043cf2a6bca0097ce5fa2d1cb6594a4870c3c64e357ac9cc54b85e33502e9257918c9eebb3e87249d798ee9e223eacc5b02014b4196bd0f9804c2ac - languageName: node - linkType: hard - -"@backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": +"@backstage/core-components@^0.13.8, @backstage/core-components@workspace:^, @backstage/core-components@workspace:packages/core-components": version: 0.0.0-use.local resolution: "@backstage/core-components@workspace:packages/core-components" dependencies: @@ -3989,25 +3874,57 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@npm:^1.3.0, @backstage/core-plugin-api@npm:^1.5.0, @backstage/core-plugin-api@npm:^1.8.0, @backstage/core-plugin-api@npm:^1.8.1": - version: 1.8.1 - resolution: "@backstage/core-plugin-api@npm:1.8.1" +"@backstage/core-components@npm:^0.12.3": + version: 0.12.5 + resolution: "@backstage/core-components@npm:0.12.5" dependencies: - "@backstage/config": ^1.1.1 - "@backstage/types": ^1.1.1 - "@backstage/version-bridge": ^1.0.7 - "@types/react": ^16.13.1 || ^17.0.0 + "@backstage/config": ^1.0.7 + "@backstage/core-plugin-api": ^1.5.0 + "@backstage/errors": ^1.1.5 + "@backstage/theme": ^0.2.18 + "@backstage/version-bridge": ^1.0.3 + "@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": ^20.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 - i18next: ^22.4.15 + immer: ^9.0.1 + lodash: ^4.17.21 + pluralize: ^8.0.0 + prop-types: ^15.7.2 + qs: ^6.9.4 + rc-progress: 3.4.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-markdown: ^8.0.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.10.0 + zod: ~3.18.0 peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + "@types/react": ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 + react-dom: ^16.13.1 || ^17.0.0 react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 8fa85beb719f65b2dc2ab69df7e7354d280ce63ca163ce820dec43ac7ffe95ce1c3ae1175774f034ea3787cb997e0bc630f42b644b166b7f9929f6166e7c2607 + checksum: 8308c1b90247911f6cf22963b530cef169287f508ff29d159d0c83758134dd43bd5acd2113350690a46a02246bc05dca975bcc38325000aefb1c93c80e2f19c7 languageName: node linkType: hard -"@backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": +"@backstage/core-plugin-api@^1.3.0, @backstage/core-plugin-api@^1.5.0, @backstage/core-plugin-api@^1.8.0, @backstage/core-plugin-api@workspace:^, @backstage/core-plugin-api@workspace:packages/core-plugin-api": version: 0.0.0-use.local resolution: "@backstage/core-plugin-api@workspace:packages/core-plugin-api" dependencies: @@ -4103,7 +4020,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@^1.1.5, @backstage/errors@^1.2.3, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/errors@^1.1.5, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -4151,27 +4068,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-plugin-api@npm:^0.4.0": - version: 0.4.0 - resolution: "@backstage/frontend-plugin-api@npm:0.4.0" - dependencies: - "@backstage/config": ^1.1.1 - "@backstage/core-components": ^0.13.9 - "@backstage/core-plugin-api": ^1.8.1 - "@backstage/types": ^1.1.1 - "@backstage/version-bridge": ^1.0.7 - "@material-ui/core": ^4.12.4 - "@types/react": ^16.13.1 || ^17.0.0 - lodash: ^4.17.21 - zod: ^3.22.4 - zod-to-json-schema: ^3.21.4 - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 6b19944a070b8e0c0d9a33c39d50f0bf1a3dfb5884833bd96286508573528a4b254660f0044eeeeecf4f7d392b71a95e3b9665903d83cb27aa04625155284b2b - languageName: node - linkType: hard - "@backstage/frontend-plugin-api@workspace:^, @backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api": version: 0.0.0-use.local resolution: "@backstage/frontend-plugin-api@workspace:packages/frontend-plugin-api" @@ -4235,25 +4131,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@npm:^1.1.21, @backstage/integration-react@npm:^1.1.22": - version: 1.1.22 - resolution: "@backstage/integration-react@npm:1.1.22" - dependencies: - "@backstage/config": ^1.1.1 - "@backstage/core-plugin-api": ^1.8.1 - "@backstage/integration": ^1.8.0 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@types/react": ^16.13.1 || ^17.0.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: 76fb82f1f947574259d393406bdc30919636e451dbbab357b640f70b2b8b869564fad10da74088f12b497996b84b8e3f55ddea355a9ee61c27f549a2805773a5 - languageName: node - linkType: hard - -"@backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": +"@backstage/integration-react@^1.1.21, @backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": version: 0.0.0-use.local resolution: "@backstage/integration-react@workspace:packages/integration-react" dependencies: @@ -4277,7 +4155,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration@^1.8.0, @backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": +"@backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" dependencies: @@ -5689,7 +5567,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@^1.0.10, @backstage/plugin-catalog-common@^1.0.19, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": +"@backstage/plugin-catalog-common@^1.0.10, @backstage/plugin-catalog-common@workspace:^, @backstage/plugin-catalog-common@workspace:plugins/catalog-common": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-common@workspace:plugins/catalog-common" dependencies: @@ -5795,44 +5673,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-react@npm:^1.2.4, @backstage/plugin-catalog-react@npm:^1.9.1": - version: 1.9.2 - resolution: "@backstage/plugin-catalog-react@npm:1.9.2" - dependencies: - "@backstage/catalog-client": ^1.5.0 - "@backstage/catalog-model": ^1.4.3 - "@backstage/core-components": ^0.13.9 - "@backstage/core-plugin-api": ^1.8.1 - "@backstage/errors": ^1.2.3 - "@backstage/frontend-plugin-api": ^0.4.0 - "@backstage/integration-react": ^1.1.22 - "@backstage/plugin-catalog-common": ^1.0.19 - "@backstage/plugin-permission-common": ^0.7.11 - "@backstage/plugin-permission-react": ^0.4.18 - "@backstage/theme": ^0.5.0 - "@backstage/types": ^1.1.1 - "@backstage/version-bridge": ^1.0.7 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@material-ui/lab": 4.0.0-alpha.61 - "@react-hookz/web": ^23.0.0 - "@types/react": ^16.13.1 || ^17.0.0 - classnames: ^2.2.6 - lodash: ^4.17.21 - material-ui-popup-state: ^1.9.3 - qs: ^6.9.4 - react-use: ^17.2.4 - yaml: ^2.0.0 - zen-observable: ^0.10.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: e363db83bb85a6dac23616104aa52b019c4f32341fb757c40cf0321ad12427ffcad647b54b38d2d47a7299571e95c2cd226e01c6f9dde585d5377a4dc95a1df6 - languageName: node - linkType: hard - -"@backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": +"@backstage/plugin-catalog-react@^1.2.4, @backstage/plugin-catalog-react@^1.9.1, @backstage/plugin-catalog-react@workspace:^, @backstage/plugin-catalog-react@workspace:plugins/catalog-react": version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-react@workspace:plugins/catalog-react" dependencies: @@ -7023,25 +6864,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-home-react@npm:^0.1.5": - version: 0.1.6 - resolution: "@backstage/plugin-home-react@npm:0.1.6" - dependencies: - "@backstage/core-components": ^0.13.9 - "@backstage/core-plugin-api": ^1.8.1 - "@material-ui/core": ^4.12.2 - "@material-ui/icons": ^4.9.1 - "@rjsf/utils": 5.15.0 - "@types/react": ^16.13.1 || ^17.0.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: ecd2d6d6b2f0793bb0180b07ec7559230361eb3174d7a962bc08fabc2c29bf21f9705ae5b9a6977005ecac4009dc5806b0d8ecac67eecb6507141764a96d1def - languageName: node - linkType: hard - -"@backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": +"@backstage/plugin-home-react@^0.1.5, @backstage/plugin-home-react@workspace:^, @backstage/plugin-home-react@workspace:plugins/home-react": version: 0.0.0-use.local resolution: "@backstage/plugin-home-react@workspace:plugins/home-react" dependencies: @@ -7919,7 +7742,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-common@^0.7.11, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-common@workspace:plugins/permission-common" dependencies: @@ -7957,25 +7780,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-react@npm:^0.4.18": - version: 0.4.18 - resolution: "@backstage/plugin-permission-react@npm:0.4.18" - dependencies: - "@backstage/config": ^1.1.1 - "@backstage/core-plugin-api": ^1.8.1 - "@backstage/plugin-permission-common": ^0.7.11 - "@types/react": ^16.13.1 || ^17.0.0 - cross-fetch: ^4.0.0 - react-use: ^17.2.4 - swr: ^2.0.0 - peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-router-dom: 6.0.0-beta.0 || ^6.3.0 - checksum: da1386b814fcb0b7350cebc1975d88cdf4c97a474f292a56d4e15ce63bb25a54d34d17067865363fa051983d9fa5170afce6a38299bc7c3ab82f1e44c708b13b - languageName: node - linkType: hard - "@backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": version: 0.0.0-use.local resolution: "@backstage/plugin-permission-react@workspace:plugins/permission-react" @@ -9706,26 +9510,6 @@ __metadata: languageName: unknown linkType: soft -"@backstage/theme@^0.5.0, @backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": - version: 0.0.0-use.local - resolution: "@backstage/theme@workspace:packages/theme" - dependencies: - "@backstage/cli": "workspace:^" - "@emotion/react": ^11.10.5 - "@emotion/styled": ^11.10.5 - "@mui/material": ^5.12.2 - "@mui/styles": ^5.14.18 - "@testing-library/jest-dom": ^6.0.0 - "@testing-library/react": ^14.0.0 - "@types/react": ^16.13.1 || ^17.0.0 - peerDependencies: - "@material-ui/core": ^4.12.2 - "@types/react": ^16.13.1 || ^17.0.0 - react: ^16.13.1 || ^17.0.0 || ^18.0.0 - react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 - languageName: unknown - linkType: soft - "@backstage/theme@npm:^0.2.16, @backstage/theme@npm:^0.2.18": version: 0.2.19 resolution: "@backstage/theme@npm:0.2.19" @@ -9754,7 +9538,27 @@ __metadata: languageName: node linkType: hard -"@backstage/types@^1.0.2, @backstage/types@^1.1.1, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": +"@backstage/theme@workspace:^, @backstage/theme@workspace:packages/theme": + version: 0.0.0-use.local + resolution: "@backstage/theme@workspace:packages/theme" + dependencies: + "@backstage/cli": "workspace:^" + "@emotion/react": ^11.10.5 + "@emotion/styled": ^11.10.5 + "@mui/material": ^5.12.2 + "@mui/styles": ^5.14.18 + "@testing-library/jest-dom": ^6.0.0 + "@testing-library/react": ^14.0.0 + "@types/react": ^16.13.1 || ^17.0.0 + peerDependencies: + "@material-ui/core": ^4.12.2 + "@types/react": ^16.13.1 || ^17.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + languageName: unknown + linkType: soft + +"@backstage/types@^1.0.2, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@backstage/types@workspace:packages/types" dependencies: @@ -9765,7 +9569,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/version-bridge@^1.0.3, @backstage/version-bridge@^1.0.7, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": +"@backstage/version-bridge@^1.0.3, @backstage/version-bridge@workspace:^, @backstage/version-bridge@workspace:packages/version-bridge": version: 0.0.0-use.local resolution: "@backstage/version-bridge@workspace:packages/version-bridge" dependencies: @@ -14994,21 +14798,6 @@ __metadata: languageName: node linkType: hard -"@rjsf/utils@npm:5.15.0": - version: 5.15.0 - resolution: "@rjsf/utils@npm:5.15.0" - dependencies: - json-schema-merge-allof: ^0.8.1 - jsonpointer: ^5.0.1 - lodash: ^4.17.21 - lodash-es: ^4.17.21 - react-is: ^18.2.0 - peerDependencies: - react: ^16.14.0 || >=17 - checksum: 369de8620fdbd26aea074e0a33d5ea3b1bb89e3389d826a70612dbec8881617bb0dc8403ca6774d0def332ffe15d26bed133d6ff7361ff2978a4b024cea829c3 - languageName: node - linkType: hard - "@rjsf/utils@npm:5.15.1": version: 5.15.1 resolution: "@rjsf/utils@npm:5.15.1" From 172eda2d719d6390461bab49593ffc864ff52244 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Tue, 16 Jan 2024 14:35:44 +0100 Subject: [PATCH 107/241] Update publishing.md Signed-off-by: Philipp Hugenroth --- docs/publishing.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/publishing.md b/docs/publishing.md index 48e044d68c..15813275de 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -53,6 +53,7 @@ Additional steps for the main line release - Add the release note file as [`/docs/releases/vx.y.0.md`](./releases) - Add an entry to [`/microsite/sidebar.json`](https://github.com/backstage/backstage/blob/master/microsite/sidebars.json) for the release note - Update the navigation bar item in [`/microsite/docusaurus.config.js`](https://github.com/backstage/backstage/blob/master/microsite/docusaurus.config.js) to point to the new release note + - Finally copy the content, without the metadata header, into the description of the [`Version Packages` Pull Request](https://github.com/backstage/backstage/pulls?q=is%3Aopen+is%3Apr+in%3Atitle+%22Version+Packages) Once the release has been published edit the newly created release in the [GitHub repository](https://github.com/backstage/backstage/releases) and replace the text content with the release notes. From 80e3cbb266ef4f86115c6cc52d56d9d22f76155c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:11:32 +0000 Subject: [PATCH 108/241] chore(deps): update chromaui/action digest to 722516a Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/verify_storybook.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index 6219faf616..d7f90118de 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -51,7 +51,7 @@ jobs: - run: yarn build-storybook - - uses: chromaui/action@80bf5911f28005ed208f15b7268843b79ca0e23a # v1 + - uses: chromaui/action@722516a3934360dac82cdef8dbab38e824fc6fa1 # v1 with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks From 2f6300ba3a2b4d210bb1c5936d04f40f1396e588 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:11:40 +0000 Subject: [PATCH 109/241] chore(deps): update actions/cache action to v3.3.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/uffizzi-preview.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml index c1659097a7..9591af3a23 100644 --- a/.github/workflows/uffizzi-preview.yaml +++ b/.github/workflows/uffizzi-preview.yaml @@ -76,7 +76,7 @@ jobs: - name: Cache Manifests File if: ${{ steps.event.outputs.ACTION != 'closed' }} - uses: actions/cache@v3.3.2 + uses: actions/cache@v3.3.3 with: path: manifests.rendered.yml key: ${{ steps.hash.outputs.MANIFESTS_FILE_HASH }} From 23604434c15cb09067c8a92144dfa97e15290c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 16 Jan 2024 19:41:15 +0100 Subject: [PATCH 110/241] make vale happy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- docs/backend-system/building-backends/08-migrating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index 2514f0925e..45478d632e 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -757,7 +757,7 @@ implementations that they represent, and being exported from there. ### The Auth Plugin -A basic installation of the auth plugin with a microsoft provider will look as follows. +A basic installation of the auth plugin with a Microsoft provider will look as follows. ```ts title="packages/backend/src/index.ts" const backend = createBackend(); From 53f0404a319248ac591530a076f13f1e6cb02c47 Mon Sep 17 00:00:00 2001 From: Jake Taylor <147415933+jrtaylorJH@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:44:40 -0600 Subject: [PATCH 111/241] Update debugging.md to include debugging information for webstorm Signed-off-by: Jake Taylor <147415933+jrtaylorJH@users.noreply.github.com> --- docs/local-dev/debugging.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/local-dev/debugging.md b/docs/local-dev/debugging.md index 17a98b1c1c..3de09b0108 100644 --- a/docs/local-dev/debugging.md +++ b/docs/local-dev/debugging.md @@ -71,3 +71,20 @@ In your `launch.json`, add a new entry with the following, "console": "integratedTerminal" }, ``` + +### WebStorm + +This section describes the process for enabling run configurations for Backstage in WebStorm. +Run configurations enable the use of debugging functionality such as steppers and breakpoints. + +1. Select `Edit Configurations` in the `Run` dropdown menu. Click the plus sign to add a new + configuration, then select `Node.js`. +3. In `Working directory`, input `{PROJECT_DIR}/packages/backend`. + Replace `{PROJECT_DIR}` with the path to your Backstage repo. +4. In `JavaScript file`, input `{PROJECT_DIR}/node_modules/@backstage/cli/bin/backstage-cli`. + Replace `{PROJECT_DIR}` with the path to your Backstage repo. +5. In `Application parameters`, input `package start`. +6. Optionally, for `Environment Variables`, input `LOG_LEVEL=debug`. +7. Click `Apply` to save the changes. +8. With the newly-created configuration selected, use the `Run` or `Debug` icons on the + toolbar to execute the newly created configuration. From e0c18ef3b7fdef42f22ba73ec5c6b3ea5e9f4873 Mon Sep 17 00:00:00 2001 From: Patrick Jungermann Date: Tue, 16 Jan 2024 16:21:50 +0100 Subject: [PATCH 112/241] chore: improve backend init error message Include extension point ID and module ID in backend init error message. Signed-off-by: Patrick Jungermann --- .changeset/gorgeous-bobcats-press.md | 5 +++++ .../backend-app-api/src/wiring/BackendInitializer.test.ts | 2 +- packages/backend-app-api/src/wiring/BackendInitializer.ts | 4 +++- .../backend-test-utils/src/next/wiring/TestBackend.test.ts | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 .changeset/gorgeous-bobcats-press.md diff --git a/.changeset/gorgeous-bobcats-press.md b/.changeset/gorgeous-bobcats-press.md new file mode 100644 index 0000000000..6193918cb7 --- /dev/null +++ b/.changeset/gorgeous-bobcats-press.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Include the extension point ID and the module ID in the backend init error message. diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts index b5b53083a9..c025d19fa7 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts @@ -321,7 +321,7 @@ describe('BackendInitializer', () => { })(), ); await expect(init.start()).rejects.toThrow( - "Extension point registered for plugin 'test-a' may not be used by module for plugin 'test-b'", + "Illegal dependency: Module 'mod' for plugin 'test-b' attempted to depend on extension point 'a' for plugin 'test-a'. Extension points can only be used within their plugin's scope.", ); }); }); diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index 4969f82176..2da3a5a226 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -55,6 +55,7 @@ export class BackendInitializer { async #getInitDeps( deps: { [name: string]: ServiceOrExtensionPoint }, pluginId: string, + moduleId?: string, ) { const result = new Map(); const missingRefs = new Set(); @@ -64,7 +65,7 @@ export class BackendInitializer { if (ep) { if (ep.pluginId !== pluginId) { throw new Error( - `Extension point registered for plugin '${ep.pluginId}' may not be used by module for plugin '${pluginId}'`, + `Illegal dependency: Module '${moduleId}' for plugin '${pluginId}' attempted to depend on extension point '${ref.id}' for plugin '${ep.pluginId}'. Extension points can only be used within their plugin's scope.`, ); } result.set(name, ep.impl); @@ -260,6 +261,7 @@ export class BackendInitializer { const moduleDeps = await this.#getInitDeps( moduleInit.init.deps, pluginId, + moduleId, ); await moduleInit.init.func(moduleDeps).catch(error => { throw new ForwardedError( diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts index d71c774dd9..968237f11d 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -307,7 +307,7 @@ describe('TestBackend', () => { ], }), ).rejects.toThrow( - "Extension point registered for plugin 'testA' may not be used by module for plugin 'testB'", + "Illegal dependency: Module 'test' for plugin 'testB' attempted to depend on extension point 'a' for plugin 'testA'. Extension points can only be used within their plugin's scope.", ); }); From 356707690b391c4133906a2a0238b498bad8349c Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Wed, 17 Jan 2024 10:28:30 +0530 Subject: [PATCH 113/241] Updated readme Signed-off-by: AmbrishRamachandiran --- .changeset/curvy-ladybugs-impress.md | 2 +- docs/backend-system/building-backends/08-migrating.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/curvy-ladybugs-impress.md b/.changeset/curvy-ladybugs-impress.md index 3ea90f513a..ab799e4888 100644 --- a/.changeset/curvy-ladybugs-impress.md +++ b/.changeset/curvy-ladybugs-impress.md @@ -2,4 +2,4 @@ '@backstage/plugin-adr': patch --- -Updated README document in adr plugin +Updated README diff --git a/docs/backend-system/building-backends/08-migrating.md b/docs/backend-system/building-backends/08-migrating.md index 2514f0925e..45478d632e 100644 --- a/docs/backend-system/building-backends/08-migrating.md +++ b/docs/backend-system/building-backends/08-migrating.md @@ -757,7 +757,7 @@ implementations that they represent, and being exported from there. ### The Auth Plugin -A basic installation of the auth plugin with a microsoft provider will look as follows. +A basic installation of the auth plugin with a Microsoft provider will look as follows. ```ts title="packages/backend/src/index.ts" const backend = createBackend(); From de155ac19ede57ca46e2c7d8abacbd8dc3e92737 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 08:20:34 +0000 Subject: [PATCH 114/241] chore(deps): update dependency @types/node to v18.19.8 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 30474455e6..187fb120c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18243,11 +18243,11 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0, @types/node@npm:^20.1.1": - version: 20.10.6 - resolution: "@types/node@npm:20.10.6" + version: 20.11.5 + resolution: "@types/node@npm:20.11.5" dependencies: undici-types: ~5.26.4 - checksum: ada40e4ccbda3697dca88f8d13f4c996c493be6fbc15f5f5d3b91096d56bd700786a2c148a92a2b4c5d1f133379e63f754a786b3aebfc6a7d09fc7ea16dc017b + checksum: a542727de1334ae20a3ca034b0ecf4b464a57ca01efc4f9cf43bd9ab93896125ab3c2de060ecd8f6ae23b86c6bf3463f681b643e69c032c6a662d376c98a6092 languageName: node linkType: hard @@ -18266,9 +18266,9 @@ __metadata: linkType: hard "@types/node@npm:^16.11.26, @types/node@npm:^16.7.10, @types/node@npm:^16.9.2": - version: 16.18.69 - resolution: "@types/node@npm:16.18.69" - checksum: ac7076062e59169ac1907e9347d939ed5f79c6a3ec2a531fe7186caf2fcf8d66de9b87ad42d92c4dfa6cb44b1018ab89fef1e054a82af36deea04ba32a5a670a + version: 16.18.71 + resolution: "@types/node@npm:16.18.71" + checksum: 7b61ec0abd2a298518b562618ddbcc1704a6427c666c9512a0b12700a2b26cad151ccfd3c147c9ab77ac5e0bcb62bfbf67c48fa0ef812a00859a1e33368e8802 languageName: node linkType: hard @@ -18280,11 +18280,11 @@ __metadata: linkType: hard "@types/node@npm:^18.17.8": - version: 18.19.4 - resolution: "@types/node@npm:18.19.4" + version: 18.19.8 + resolution: "@types/node@npm:18.19.8" dependencies: undici-types: ~5.26.4 - checksum: 3a32a31b2df85d4bebb5e3c91ec1a0908d587a2a2fd31ab4eeebd609d1c04bbcc9ba97e290e3230f843c9f43f17efb9f5cde56412b4b0f5acbfe5577179b23c8 + checksum: fa291495d6157a9d9393b4c3bdbf1ce12a8f661dc9da6a4fa19bcdb19af1c62bb8dbf7fb66ae135f29cd788b618e9845b83e9c47edcf39f0953a8561fdacd9a3 languageName: node linkType: hard From 463cfa120bcbc74194937e4ce9ccf1ebdeeab416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 17 Jan 2024 10:17:13 +0100 Subject: [PATCH 115/241] enter pre mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/pre.json | 268 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..1e62c27268 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,268 @@ +{ + "mode": "pre", + "tag": "next", + "initialVersions": { + "example-app": "0.2.91", + "@backstage/app-defaults": "1.4.7", + "example-app-next": "0.0.5", + "app-next-example-plugin": "0.0.5", + "example-backend": "0.2.91", + "@backstage/backend-app-api": "0.5.10", + "@backstage/backend-common": "0.20.1", + "@backstage/backend-defaults": "0.2.9", + "@backstage/backend-dev-utils": "0.1.3", + "@backstage/backend-dynamic-feature-service": "0.1.0", + "example-backend-next": "0.0.19", + "@backstage/backend-openapi-utils": "0.1.2", + "@backstage/backend-plugin-api": "0.6.9", + "@backstage/backend-tasks": "0.5.14", + "@backstage/backend-test-utils": "0.2.10", + "@backstage/catalog-client": "1.5.2", + "@backstage/catalog-model": "1.4.3", + "@backstage/cli": "0.25.1", + "@backstage/cli-common": "0.1.13", + "@backstage/cli-node": "0.2.2", + "@backstage/codemods": "0.1.46", + "@backstage/config": "1.1.1", + "@backstage/config-loader": "1.6.1", + "@backstage/core-app-api": "1.11.3", + "@backstage/core-compat-api": "0.1.1", + "@backstage/core-components": "0.13.10", + "@backstage/core-plugin-api": "1.8.2", + "@backstage/create-app": "0.5.9", + "@backstage/dev-utils": "1.0.26", + "e2e-test": "0.2.11", + "@backstage/e2e-test-utils": "0.1.0", + "@backstage/errors": "1.2.3", + "@backstage/eslint-plugin": "0.1.4", + "@backstage/frontend-app-api": "0.5.0", + "@backstage/frontend-plugin-api": "0.5.0", + "@backstage/frontend-test-utils": "0.1.1", + "@backstage/integration": "1.8.0", + "@backstage/integration-aws-node": "0.1.8", + "@backstage/integration-react": "1.1.23", + "@backstage/release-manifests": "0.0.11", + "@backstage/repo-tools": "0.5.2", + "@techdocs/cli": "1.8.1", + "techdocs-cli-embedded-app": "0.2.90", + "@backstage/test-utils": "1.4.7", + "@backstage/theme": "0.5.0", + "@backstage/types": "1.1.1", + "@backstage/version-bridge": "1.0.7", + "@backstage/plugin-adr": "0.6.12", + "@backstage/plugin-adr-backend": "0.4.6", + "@backstage/plugin-adr-common": "0.2.19", + "@backstage/plugin-airbrake": "0.3.29", + "@backstage/plugin-airbrake-backend": "0.3.6", + "@backstage/plugin-allure": "0.1.45", + "@backstage/plugin-analytics-module-ga": "0.1.37", + "@backstage/plugin-analytics-module-ga4": "0.1.8", + "@backstage/plugin-analytics-module-newrelic-browser": "0.0.6", + "@backstage/plugin-apache-airflow": "0.2.19", + "@backstage/plugin-api-docs": "0.10.3", + "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.5", + "@backstage/plugin-apollo-explorer": "0.1.19", + "@backstage/plugin-app-backend": "0.3.57", + "@backstage/plugin-app-node": "0.1.9", + "@backstage/plugin-app-visualizer": "0.1.0", + "@backstage/plugin-auth-backend": "0.20.3", + "@backstage/plugin-auth-backend-module-atlassian-provider": "0.1.1", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.2.3", + "@backstage/plugin-auth-backend-module-github-provider": "0.1.6", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.1.6", + "@backstage/plugin-auth-backend-module-google-provider": "0.1.6", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.1.4", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.1.6", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.1.1", + "@backstage/plugin-auth-backend-module-okta-provider": "0.0.2", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.1.3", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.1.1", + "@backstage/plugin-auth-node": "0.4.3", + "@backstage/plugin-azure-devops": "0.3.11", + "@backstage/plugin-azure-devops-backend": "0.5.1", + "@backstage/plugin-azure-devops-common": "0.3.2", + "@backstage/plugin-azure-sites": "0.1.18", + "@backstage/plugin-azure-sites-backend": "0.1.19", + "@backstage/plugin-azure-sites-common": "0.1.1", + "@backstage/plugin-badges": "0.2.53", + "@backstage/plugin-badges-backend": "0.3.6", + "@backstage/plugin-bazaar": "0.2.21", + "@backstage/plugin-bazaar-backend": "0.3.7", + "@backstage/plugin-bitbucket-cloud-common": "0.2.15", + "@backstage/plugin-bitrise": "0.1.56", + "@backstage/plugin-catalog": "1.16.1", + "@backstage/plugin-catalog-backend": "1.16.1", + "@backstage/plugin-catalog-backend-module-aws": "0.3.3", + "@backstage/plugin-catalog-backend-module-azure": "0.1.28", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.1.2", + "@backstage/plugin-catalog-backend-module-bitbucket": "0.2.24", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.24", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.22", + "@backstage/plugin-catalog-backend-module-gcp": "0.1.9", + "@backstage/plugin-catalog-backend-module-gerrit": "0.1.25", + "@backstage/plugin-catalog-backend-module-github": "0.4.7", + "@backstage/plugin-catalog-backend-module-github-org": "0.1.3", + "@backstage/plugin-catalog-backend-module-gitlab": "0.3.6", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.4.13", + "@backstage/plugin-catalog-backend-module-ldap": "0.5.24", + "@backstage/plugin-catalog-backend-module-msgraph": "0.5.16", + "@backstage/plugin-catalog-backend-module-openapi": "0.1.26", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.1.14", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.1.6", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.3.6", + "@backstage/plugin-catalog-common": "1.0.20", + "@backstage/plugin-catalog-graph": "0.3.3", + "@backstage/plugin-catalog-import": "0.10.5", + "@backstage/plugin-catalog-node": "1.6.1", + "@backstage/plugin-catalog-react": "1.9.3", + "@backstage/plugin-catalog-unprocessed-entities": "0.1.7", + "@backstage/plugin-cicd-statistics": "0.1.31", + "@backstage/plugin-cicd-statistics-module-gitlab": "0.1.25", + "@backstage/plugin-circleci": "0.3.29", + "@backstage/plugin-cloudbuild": "0.3.29", + "@backstage/plugin-code-climate": "0.1.29", + "@backstage/plugin-code-coverage": "0.2.22", + "@backstage/plugin-code-coverage-backend": "0.2.23", + "@backstage/plugin-codescene": "0.1.21", + "@backstage/plugin-config-schema": "0.1.49", + "@backstage/plugin-cost-insights": "0.12.18", + "@backstage/plugin-cost-insights-common": "0.1.2", + "@backstage/plugin-devtools": "0.1.8", + "@backstage/plugin-devtools-backend": "0.2.6", + "@backstage/plugin-devtools-common": "0.1.8", + "@backstage/plugin-dynatrace": "8.0.3", + "@backstage/plugin-entity-feedback": "0.2.12", + "@backstage/plugin-entity-feedback-backend": "0.2.6", + "@backstage/plugin-entity-feedback-common": "0.1.3", + "@backstage/plugin-entity-validation": "0.1.14", + "@backstage/plugin-events-backend": "0.2.18", + "@backstage/plugin-events-backend-module-aws-sqs": "0.2.12", + "@backstage/plugin-events-backend-module-azure": "0.1.19", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.19", + "@backstage/plugin-events-backend-module-gerrit": "0.1.19", + "@backstage/plugin-events-backend-module-github": "0.1.19", + "@backstage/plugin-events-backend-module-gitlab": "0.1.19", + "@backstage/plugin-events-backend-test-utils": "0.1.19", + "@backstage/plugin-events-node": "0.2.18", + "@internal/plugin-todo-list": "1.0.21", + "@internal/plugin-todo-list-backend": "1.0.21", + "@internal/plugin-todo-list-common": "1.0.17", + "@backstage/plugin-explore": "0.4.15", + "@backstage/plugin-explore-backend": "0.0.19", + "@backstage/plugin-explore-common": "0.0.2", + "@backstage/plugin-explore-react": "0.0.35", + "@backstage/plugin-firehydrant": "0.2.13", + "@backstage/plugin-fossa": "0.2.61", + "@backstage/plugin-gcalendar": "0.3.22", + "@backstage/plugin-gcp-projects": "0.3.45", + "@backstage/plugin-git-release-manager": "0.3.41", + "@backstage/plugin-github-actions": "0.6.10", + "@backstage/plugin-github-deployments": "0.1.60", + "@backstage/plugin-github-issues": "0.2.18", + "@backstage/plugin-github-pull-requests-board": "0.1.23", + "@backstage/plugin-gitops-profiles": "0.3.44", + "@backstage/plugin-gocd": "0.1.35", + "@backstage/plugin-graphiql": "0.3.2", + "@backstage/plugin-graphql-voyager": "0.1.11", + "@backstage/plugin-home": "0.6.1", + "@backstage/plugin-home-react": "0.1.7", + "@backstage/plugin-ilert": "0.2.18", + "@backstage/plugin-jenkins": "0.9.4", + "@backstage/plugin-jenkins-backend": "0.3.3", + "@backstage/plugin-jenkins-common": "0.1.23", + "@backstage/plugin-kafka": "0.3.29", + "@backstage/plugin-kafka-backend": "0.3.7", + "@backstage/plugin-kubernetes": "0.11.4", + "@backstage/plugin-kubernetes-backend": "0.14.1", + "@backstage/plugin-kubernetes-cluster": "0.0.5", + "@backstage/plugin-kubernetes-common": "0.7.3", + "@backstage/plugin-kubernetes-node": "0.1.3", + "@backstage/plugin-kubernetes-react": "0.2.1", + "@backstage/plugin-lighthouse": "0.4.14", + "@backstage/plugin-lighthouse-backend": "0.4.1", + "@backstage/plugin-lighthouse-common": "0.1.4", + "@backstage/plugin-linguist": "0.1.14", + "@backstage/plugin-linguist-backend": "0.5.6", + "@backstage/plugin-linguist-common": "0.1.2", + "@backstage/plugin-microsoft-calendar": "0.1.11", + "@backstage/plugin-newrelic": "0.3.44", + "@backstage/plugin-newrelic-dashboard": "0.3.4", + "@backstage/plugin-nomad": "0.1.10", + "@backstage/plugin-nomad-backend": "0.1.11", + "@backstage/plugin-octopus-deploy": "0.2.11", + "@backstage/plugin-opencost": "0.2.4", + "@backstage/plugin-org": "0.6.19", + "@backstage/plugin-org-react": "0.1.18", + "@backstage/plugin-pagerduty": "0.7.1", + "@backstage/plugin-periskop": "0.1.27", + "@backstage/plugin-periskop-backend": "0.2.7", + "@backstage/plugin-permission-backend": "0.5.32", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.1.6", + "@backstage/plugin-permission-common": "0.7.12", + "@backstage/plugin-permission-node": "0.7.20", + "@backstage/plugin-permission-react": "0.4.19", + "@backstage/plugin-playlist": "0.2.3", + "@backstage/plugin-playlist-backend": "0.3.13", + "@backstage/plugin-playlist-common": "0.1.14", + "@backstage/plugin-proxy-backend": "0.4.7", + "@backstage/plugin-puppetdb": "0.1.12", + "@backstage/plugin-rollbar": "0.4.29", + "@backstage/plugin-rollbar-backend": "0.1.54", + "@backstage/plugin-scaffolder": "1.17.1", + "@backstage/plugin-scaffolder-backend": "1.20.0", + "@backstage/plugin-scaffolder-backend-module-azure": "0.1.1", + "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.1.1", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.2.10", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.33", + "@backstage/plugin-scaffolder-backend-module-gerrit": "0.1.1", + "@backstage/plugin-scaffolder-backend-module-github": "0.1.1", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.2.12", + "@backstage/plugin-scaffolder-backend-module-rails": "0.4.26", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.1.17", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.30", + "@backstage/plugin-scaffolder-common": "1.4.5", + "@backstage/plugin-scaffolder-node": "0.2.10", + "@backstage/plugin-scaffolder-react": "1.7.1", + "@backstage/plugin-search": "1.4.5", + "@backstage/plugin-search-backend": "1.4.9", + "@backstage/plugin-search-backend-module-catalog": "0.1.13", + "@backstage/plugin-search-backend-module-elasticsearch": "1.3.12", + "@backstage/plugin-search-backend-module-explore": "0.1.13", + "@backstage/plugin-search-backend-module-pg": "0.5.18", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.1.2", + "@backstage/plugin-search-backend-module-techdocs": "0.1.13", + "@backstage/plugin-search-backend-node": "1.2.13", + "@backstage/plugin-search-common": "1.2.10", + "@backstage/plugin-search-react": "1.7.5", + "@backstage/plugin-sentry": "0.5.14", + "@backstage/plugin-shortcuts": "0.3.18", + "@backstage/plugin-sonarqube": "0.7.11", + "@backstage/plugin-sonarqube-backend": "0.2.11", + "@backstage/plugin-sonarqube-react": "0.1.12", + "@backstage/plugin-splunk-on-call": "0.4.18", + "@backstage/plugin-stack-overflow": "0.1.24", + "@backstage/plugin-stack-overflow-backend": "0.2.13", + "@backstage/plugin-stackstorm": "0.1.10", + "@backstage/plugin-tech-insights": "0.3.21", + "@backstage/plugin-tech-insights-backend": "0.5.23", + "@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.41", + "@backstage/plugin-tech-insights-common": "0.2.12", + "@backstage/plugin-tech-insights-node": "0.4.15", + "@backstage/plugin-tech-radar": "0.6.12", + "@backstage/plugin-techdocs": "1.9.3", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.26", + "@backstage/plugin-techdocs-backend": "1.9.2", + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.4", + "@backstage/plugin-techdocs-node": "1.11.1", + "@backstage/plugin-techdocs-react": "1.1.15", + "@backstage/plugin-todo": "0.2.33", + "@backstage/plugin-todo-backend": "0.3.7", + "@backstage/plugin-user-settings": "0.8.0", + "@backstage/plugin-user-settings-backend": "0.2.8", + "@backstage/plugin-vault": "0.1.24", + "@backstage/plugin-vault-backend": "0.4.2", + "@backstage/plugin-vault-node": "0.1.2", + "@backstage/plugin-xcmetrics": "0.2.47" + }, + "changesets": [] +} From 477e98bbb693d2bbdb7408282ec3a4f83fb60842 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 10:38:06 +0000 Subject: [PATCH 116/241] chore(deps): update dependency @types/react to v18.2.48 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4776685b58..fa2e9a3850 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18596,13 +18596,13 @@ __metadata: linkType: hard "@types/react@npm:^18": - version: 18.2.46 - resolution: "@types/react@npm:18.2.46" + version: 18.2.48 + resolution: "@types/react@npm:18.2.48" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: cb0e4dc7f41988a059e1246a19ec377101f5b16097ec4bf7000ef3c431ec0c8c873f40e95075821f908db1f4e3352775f0f18cea53dcad14dce67c0f5110f2bd + checksum: c9ca43ed2995389b7e09492c24e6f911a8439bb8276dd17cc66a2fbebbf0b42daf7b2ad177043256533607c2ca644d7d928fdfce37a67af1f8646d2bac988900 languageName: node linkType: hard From c1831807c26f8c0a852ea0bdde29b31de8de8f5f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 10:38:38 +0000 Subject: [PATCH 117/241] chore(deps): update dependency nodemon to v3.0.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4776685b58..418240b1a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34936,8 +34936,8 @@ __metadata: linkType: hard "nodemon@npm:^3.0.1": - version: 3.0.2 - resolution: "nodemon@npm:3.0.2" + version: 3.0.3 + resolution: "nodemon@npm:3.0.3" dependencies: chokidar: ^3.5.2 debug: ^4 @@ -34951,7 +34951,7 @@ __metadata: undefsafe: ^2.0.5 bin: nodemon: bin/nodemon.js - checksum: 61f3dd207ad444f4a7a2f1aa44adc886605c96c7bc6286291c2360e5e2cd26c3828c90a1418a60783a9da2463593383149135a5a4c099918c54d34a611745499 + checksum: 121ebb6349167d87cefd5767ec453ceb49ec5a8d50146134a54b0e25502c29ad01caaa41460e303b35728439012564782d278b3fef3c615f3c278979c2b7d586 languageName: node linkType: hard From adca7294f29b823aa713667fbdd7787b62fb1885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 17 Jan 2024 12:06:41 +0100 Subject: [PATCH 118/241] Update plugins/azure-devops-backend/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/azure-devops-backend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure-devops-backend/README.md b/plugins/azure-devops-backend/README.md index b529faf8a6..bc23c58871 100644 --- a/plugins/azure-devops-backend/README.md +++ b/plugins/azure-devops-backend/README.md @@ -23,7 +23,7 @@ Configuration Details: - `AZURE_TOKEN` environment variable must be set to a [Personal Access Token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page) with read access to both Code and Build - `organization` is your Azure DevOps Services (cloud) Organization name or for Azure DevOps Server (on-premise) this will be your Collection name -#### Multi Organization & Service Principles +#### Multi Organization & Service Principals To support cases where you have multiple Azure DevOps organizations and/or you want to use a Service Principle you will want to make sure to configure them in the `integrations.azure` section of your `app-config.yaml` as detailed in the [Azure DevOps Locations](https://backstage.io/docs/integrations/azure/locations) documentation. From 3603867fdbb8d9f2c93f1f7e2a092d75ae8923d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 17 Jan 2024 12:06:46 +0100 Subject: [PATCH 119/241] Update plugins/azure-devops-backend/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/azure-devops-backend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/azure-devops-backend/README.md b/plugins/azure-devops-backend/README.md index bc23c58871..0066e43856 100644 --- a/plugins/azure-devops-backend/README.md +++ b/plugins/azure-devops-backend/README.md @@ -25,7 +25,7 @@ Configuration Details: #### Multi Organization & Service Principals -To support cases where you have multiple Azure DevOps organizations and/or you want to use a Service Principle you will want to make sure to configure them in the `integrations.azure` section of your `app-config.yaml` as detailed in the [Azure DevOps Locations](https://backstage.io/docs/integrations/azure/locations) documentation. +To support cases where you have multiple Azure DevOps organizations and/or you want to use a Service Principal you will want to make sure to configure them in the `integrations.azure` section of your `app-config.yaml` as detailed in the [Azure DevOps Locations](https://backstage.io/docs/integrations/azure/locations) documentation. **Note:** You will still need to define the [configuration above](#configuration). From 69cc5b113734faab53325743ace0cd6d71c1dc34 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:16:07 +0000 Subject: [PATCH 120/241] chore(deps): update dependency supertest to v6.3.4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4776685b58..9f1e0f35eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -41540,9 +41540,9 @@ __metadata: languageName: node linkType: hard -"superagent@npm:^8.0.5": - version: 8.0.9 - resolution: "superagent@npm:8.0.9" +"superagent@npm:^8.1.2": + version: 8.1.2 + resolution: "superagent@npm:8.1.2" dependencies: component-emitter: ^1.3.0 cookiejar: ^2.1.4 @@ -41554,17 +41554,17 @@ __metadata: mime: 2.6.0 qs: ^6.11.0 semver: ^7.3.8 - checksum: 5d00cdc7ceb5570663da80604965750e6b1b8d7d7442b7791e285c62bcd8d578a8ead0242a2426432b59a255fb42eb3a196d636157538a1392e7b6c5f1624810 + checksum: f3601c5ccae34d5ba684a03703394b5d25931f4ae2e1e31a1de809f88a9400e997ece037f9accf148a21c408f950dc829db1e4e23576a7f9fe0efa79fd5c9d2f languageName: node linkType: hard "supertest@npm:^6.1.3, supertest@npm:^6.1.6, supertest@npm:^6.2.4, supertest@npm:^6.3.3": - version: 6.3.3 - resolution: "supertest@npm:6.3.3" + version: 6.3.4 + resolution: "supertest@npm:6.3.4" dependencies: methods: ^1.1.2 - superagent: ^8.0.5 - checksum: 38239e517f7ba62b7a139a79c5c48d55f8d67b5ff4b6e51d5b07732ca8bbc4a28ffa1b10916fbb403dd013a054dbf028edc5850057d9a43aecbff439d494673e + superagent: ^8.1.2 + checksum: 875c6fa7940f21e5be9bb646579cdb030d4057bf2da643e125e1f0480add1200395d2b17e10b8e54e1009efc63e047422501e9eb30e12828668498c0910f295f languageName: node linkType: hard From e6a349c5796cc811d45e5a8573805cba83eff5ef Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:16:43 +0000 Subject: [PATCH 121/241] fix(deps): update dependency @google-cloud/container to v5.4.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4776685b58..c895431c7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10982,11 +10982,11 @@ __metadata: linkType: hard "@google-cloud/container@npm:^5.0.0": - version: 5.4.0 - resolution: "@google-cloud/container@npm:5.4.0" + version: 5.4.1 + resolution: "@google-cloud/container@npm:5.4.1" dependencies: google-gax: ^4.0.3 - checksum: ab6a6f0d6e6dc7feb30c848f40109ada5464c2594d9bbb467dbd522e097f0dc1108d366becfae268831d0ca203fa06dcedf28014d4d9161838bb2bb550162465 + checksum: 93f06b3171805c85d2ec8fa959e3caa147f1560da5c90082e23e1ccbd6ef88756e3271dbf3db139fefaa48874222f7e9e4a7dc5fb7da54a2e7ecd80db472ecf7 languageName: node linkType: hard From a7e2ec8752d2ef638e17164f89d92826a757bf07 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 12:14:21 +0000 Subject: [PATCH 122/241] fix(deps): update dependency @swc/core to v1.3.104 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- microsite/yarn.lock | 86 ++++++++++++++++++++++----------------------- storybook/yarn.lock | 86 ++++++++++++++++++++++----------------------- yarn.lock | 86 ++++++++++++++++++++++----------------------- 3 files changed, 129 insertions(+), 129 deletions(-) diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 36c4f4bdac..5e976cce69 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -2701,90 +2701,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-darwin-arm64@npm:1.3.102" +"@swc/core-darwin-arm64@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-darwin-arm64@npm:1.3.104" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-darwin-x64@npm:1.3.102" +"@swc/core-darwin-x64@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-darwin-x64@npm:1.3.104" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.102" +"@swc/core-linux-arm-gnueabihf@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.104" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.102" +"@swc/core-linux-arm64-gnu@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.104" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.102" +"@swc/core-linux-arm64-musl@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.104" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.102" +"@swc/core-linux-x64-gnu@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.104" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-x64-musl@npm:1.3.102" +"@swc/core-linux-x64-musl@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-x64-musl@npm:1.3.104" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.102" +"@swc/core-win32-arm64-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.104" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.102" +"@swc/core-win32-ia32-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.104" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.102" +"@swc/core-win32-x64-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.104" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.102 - resolution: "@swc/core@npm:1.3.102" + version: 1.3.104 + resolution: "@swc/core@npm:1.3.104" dependencies: - "@swc/core-darwin-arm64": 1.3.102 - "@swc/core-darwin-x64": 1.3.102 - "@swc/core-linux-arm-gnueabihf": 1.3.102 - "@swc/core-linux-arm64-gnu": 1.3.102 - "@swc/core-linux-arm64-musl": 1.3.102 - "@swc/core-linux-x64-gnu": 1.3.102 - "@swc/core-linux-x64-musl": 1.3.102 - "@swc/core-win32-arm64-msvc": 1.3.102 - "@swc/core-win32-ia32-msvc": 1.3.102 - "@swc/core-win32-x64-msvc": 1.3.102 + "@swc/core-darwin-arm64": 1.3.104 + "@swc/core-darwin-x64": 1.3.104 + "@swc/core-linux-arm-gnueabihf": 1.3.104 + "@swc/core-linux-arm64-gnu": 1.3.104 + "@swc/core-linux-arm64-musl": 1.3.104 + "@swc/core-linux-x64-gnu": 1.3.104 + "@swc/core-linux-x64-musl": 1.3.104 + "@swc/core-win32-arm64-msvc": 1.3.104 + "@swc/core-win32-ia32-msvc": 1.3.104 + "@swc/core-win32-x64-msvc": 1.3.104 "@swc/counter": ^0.1.1 "@swc/types": ^0.1.5 peerDependencies: @@ -2813,7 +2813,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 45c0edb06f87a811e28fb3ed587fbe6b7ca67ff2440fe15666d43729788903a4af61e3b57842aecc0b2b70e3c9981b698d8233746ba94dfb5a19e1c62eea33ad + checksum: 95fbf1412c8685d311cf2d7efbfa43e082d2d9e84ece48c4d8d96d6c67c5923569bfb26352451eb3e4d98adcb556dcfac65271c0fba77f078bb755fe2f64b295 languageName: node linkType: hard diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 5c3f333454..0be4de1f7f 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -2842,90 +2842,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-darwin-arm64@npm:1.3.102" +"@swc/core-darwin-arm64@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-darwin-arm64@npm:1.3.104" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-darwin-x64@npm:1.3.102" +"@swc/core-darwin-x64@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-darwin-x64@npm:1.3.104" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.102" +"@swc/core-linux-arm-gnueabihf@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.104" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.102" +"@swc/core-linux-arm64-gnu@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.104" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.102" +"@swc/core-linux-arm64-musl@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.104" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.102" +"@swc/core-linux-x64-gnu@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.104" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-x64-musl@npm:1.3.102" +"@swc/core-linux-x64-musl@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-x64-musl@npm:1.3.104" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.102" +"@swc/core-win32-arm64-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.104" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.102" +"@swc/core-win32-ia32-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.104" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.102" +"@swc/core-win32-x64-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.104" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.102 - resolution: "@swc/core@npm:1.3.102" + version: 1.3.104 + resolution: "@swc/core@npm:1.3.104" dependencies: - "@swc/core-darwin-arm64": 1.3.102 - "@swc/core-darwin-x64": 1.3.102 - "@swc/core-linux-arm-gnueabihf": 1.3.102 - "@swc/core-linux-arm64-gnu": 1.3.102 - "@swc/core-linux-arm64-musl": 1.3.102 - "@swc/core-linux-x64-gnu": 1.3.102 - "@swc/core-linux-x64-musl": 1.3.102 - "@swc/core-win32-arm64-msvc": 1.3.102 - "@swc/core-win32-ia32-msvc": 1.3.102 - "@swc/core-win32-x64-msvc": 1.3.102 + "@swc/core-darwin-arm64": 1.3.104 + "@swc/core-darwin-x64": 1.3.104 + "@swc/core-linux-arm-gnueabihf": 1.3.104 + "@swc/core-linux-arm64-gnu": 1.3.104 + "@swc/core-linux-arm64-musl": 1.3.104 + "@swc/core-linux-x64-gnu": 1.3.104 + "@swc/core-linux-x64-musl": 1.3.104 + "@swc/core-win32-arm64-msvc": 1.3.104 + "@swc/core-win32-ia32-msvc": 1.3.104 + "@swc/core-win32-x64-msvc": 1.3.104 "@swc/counter": ^0.1.1 "@swc/types": ^0.1.5 peerDependencies: @@ -2954,7 +2954,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 45c0edb06f87a811e28fb3ed587fbe6b7ca67ff2440fe15666d43729788903a4af61e3b57842aecc0b2b70e3c9981b698d8233746ba94dfb5a19e1c62eea33ad + checksum: 95fbf1412c8685d311cf2d7efbfa43e082d2d9e84ece48c4d8d96d6c67c5923569bfb26352451eb3e4d98adcb556dcfac65271c0fba77f078bb755fe2f64b295 languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index 4776685b58..5c78ed8aa6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16769,90 +16769,90 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-darwin-arm64@npm:1.3.102" +"@swc/core-darwin-arm64@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-darwin-arm64@npm:1.3.104" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-darwin-x64@npm:1.3.102" +"@swc/core-darwin-x64@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-darwin-x64@npm:1.3.104" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.102" +"@swc/core-linux-arm-gnueabihf@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.104" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm64-gnu@npm:1.3.102" +"@swc/core-linux-arm64-gnu@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm64-gnu@npm:1.3.104" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-arm64-musl@npm:1.3.102" +"@swc/core-linux-arm64-musl@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-arm64-musl@npm:1.3.104" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-x64-gnu@npm:1.3.102" +"@swc/core-linux-x64-gnu@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-x64-gnu@npm:1.3.104" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-linux-x64-musl@npm:1.3.102" +"@swc/core-linux-x64-musl@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-linux-x64-musl@npm:1.3.104" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-arm64-msvc@npm:1.3.102" +"@swc/core-win32-arm64-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-arm64-msvc@npm:1.3.104" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-ia32-msvc@npm:1.3.102" +"@swc/core-win32-ia32-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-ia32-msvc@npm:1.3.104" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.3.102": - version: 1.3.102 - resolution: "@swc/core-win32-x64-msvc@npm:1.3.102" +"@swc/core-win32-x64-msvc@npm:1.3.104": + version: 1.3.104 + resolution: "@swc/core-win32-x64-msvc@npm:1.3.104" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.3.46": - version: 1.3.102 - resolution: "@swc/core@npm:1.3.102" + version: 1.3.104 + resolution: "@swc/core@npm:1.3.104" dependencies: - "@swc/core-darwin-arm64": 1.3.102 - "@swc/core-darwin-x64": 1.3.102 - "@swc/core-linux-arm-gnueabihf": 1.3.102 - "@swc/core-linux-arm64-gnu": 1.3.102 - "@swc/core-linux-arm64-musl": 1.3.102 - "@swc/core-linux-x64-gnu": 1.3.102 - "@swc/core-linux-x64-musl": 1.3.102 - "@swc/core-win32-arm64-msvc": 1.3.102 - "@swc/core-win32-ia32-msvc": 1.3.102 - "@swc/core-win32-x64-msvc": 1.3.102 + "@swc/core-darwin-arm64": 1.3.104 + "@swc/core-darwin-x64": 1.3.104 + "@swc/core-linux-arm-gnueabihf": 1.3.104 + "@swc/core-linux-arm64-gnu": 1.3.104 + "@swc/core-linux-arm64-musl": 1.3.104 + "@swc/core-linux-x64-gnu": 1.3.104 + "@swc/core-linux-x64-musl": 1.3.104 + "@swc/core-win32-arm64-msvc": 1.3.104 + "@swc/core-win32-ia32-msvc": 1.3.104 + "@swc/core-win32-x64-msvc": 1.3.104 "@swc/counter": ^0.1.1 "@swc/types": ^0.1.5 peerDependencies: @@ -16881,7 +16881,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 45c0edb06f87a811e28fb3ed587fbe6b7ca67ff2440fe15666d43729788903a4af61e3b57842aecc0b2b70e3c9981b698d8233746ba94dfb5a19e1c62eea33ad + checksum: 95fbf1412c8685d311cf2d7efbfa43e082d2d9e84ece48c4d8d96d6c67c5923569bfb26352451eb3e4d98adcb556dcfac65271c0fba77f078bb755fe2f64b295 languageName: node linkType: hard From e7d516ef375314f7b9d022658cb0c8c816e1482c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 12:15:20 +0000 Subject: [PATCH 123/241] fix(deps): update dependency @types/node-fetch to v2.6.11 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4776685b58..b4e20d6361 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18224,12 +18224,12 @@ __metadata: linkType: hard "@types/node-fetch@npm:^2.5.0, @types/node-fetch@npm:^2.5.12, @types/node-fetch@npm:^2.5.7": - version: 2.6.10 - resolution: "@types/node-fetch@npm:2.6.10" + version: 2.6.11 + resolution: "@types/node-fetch@npm:2.6.11" dependencies: "@types/node": "*" form-data: ^4.0.0 - checksum: e0c9a6023752ff6c744a33a3045b9adb11fd1882997ef891bf7ce91f937ddab91c0acee4c8e806a8a5aec0e8d8c132709141e8512fec28030d7cc9ef92c7ff1e + checksum: 180e4d44c432839bdf8a25251ef8c47d51e37355ddd78c64695225de8bc5dc2b50b7bb855956d471c026bb84bd7295688a0960085e7158cbbba803053492568b languageName: node linkType: hard From 60d459822d327ac2ea95d3155c2e6cadb94b939c Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 17 Jan 2024 13:19:30 +0100 Subject: [PATCH 124/241] chore: fix prettier Signed-off-by: blam --- docs/local-dev/debugging.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/local-dev/debugging.md b/docs/local-dev/debugging.md index 3de09b0108..39981f2e54 100644 --- a/docs/local-dev/debugging.md +++ b/docs/local-dev/debugging.md @@ -79,12 +79,12 @@ Run configurations enable the use of debugging functionality such as steppers an 1. Select `Edit Configurations` in the `Run` dropdown menu. Click the plus sign to add a new configuration, then select `Node.js`. -3. In `Working directory`, input `{PROJECT_DIR}/packages/backend`. +2. In `Working directory`, input `{PROJECT_DIR}/packages/backend`. Replace `{PROJECT_DIR}` with the path to your Backstage repo. -4. In `JavaScript file`, input `{PROJECT_DIR}/node_modules/@backstage/cli/bin/backstage-cli`. +3. In `JavaScript file`, input `{PROJECT_DIR}/node_modules/@backstage/cli/bin/backstage-cli`. Replace `{PROJECT_DIR}` with the path to your Backstage repo. -5. In `Application parameters`, input `package start`. -6. Optionally, for `Environment Variables`, input `LOG_LEVEL=debug`. -7. Click `Apply` to save the changes. -8. With the newly-created configuration selected, use the `Run` or `Debug` icons on the +4. In `Application parameters`, input `package start`. +5. Optionally, for `Environment Variables`, input `LOG_LEVEL=debug`. +6. Click `Apply` to save the changes. +7. With the newly-created configuration selected, use the `Run` or `Debug` icons on the toolbar to execute the newly created configuration. From 545f90747fd13a2614042f6a3bea67a023e29719 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 13:11:42 +0000 Subject: [PATCH 125/241] fix(deps): update dependency axios to v1.6.5 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index b9ab306f65..05651b3509 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20812,13 +20812,13 @@ __metadata: linkType: hard "axios@npm:^1.4.0, axios@npm:^1.6.0": - version: 1.6.4 - resolution: "axios@npm:1.6.4" + version: 1.6.5 + resolution: "axios@npm:1.6.5" dependencies: follow-redirects: ^1.15.4 form-data: ^4.0.0 proxy-from-env: ^1.1.0 - checksum: 48d8af8488ac7402fae312437c0189b3b609a472fca2f7fc796129c804d98520589b6317096eba8509711d49f855a3f620b6a24ff23acd73ac26433d0383b8f9 + checksum: e28d67b2d9134cb4608c44d8068b0678cfdccc652742e619006f27264a30c7aba13b2cd19c6f1f52ae195b5232734925928fb192d5c85feea7edd2f273df206d languageName: node linkType: hard From b738048bb52ce8a731edd6504c6483568edb14df Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 13:12:16 +0000 Subject: [PATCH 126/241] fix(deps): update dependency eslint-plugin-jest to v27.6.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index b9ab306f65..350a7b6305 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25765,8 +25765,8 @@ __metadata: linkType: hard "eslint-plugin-jest@npm:^27.0.0": - version: 27.6.1 - resolution: "eslint-plugin-jest@npm:27.6.1" + version: 27.6.3 + resolution: "eslint-plugin-jest@npm:27.6.3" dependencies: "@typescript-eslint/utils": ^5.10.0 peerDependencies: @@ -25778,7 +25778,7 @@ __metadata: optional: true jest: optional: true - checksum: 03dc4784119a06504718b3ec1a5944c8d41fe73669d23433fa794e4059be857ec463da6d5982dcd2920da091fe7c5c033fa69a91f4dfbe3f41aac6db99b8c3d0 + checksum: e22e8dbd941b34bb95958f035ffabb94114506b294e74d6e411bc85bc9dc57888ffd3ebb5c28316a8b7cc9d391cca35557acc64bf815f48d1dcc5ea3d28fa43a languageName: node linkType: hard From f369994ef6569d05d790d9164da28d0cf2d9fc25 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 14 Dec 2023 16:12:18 +0100 Subject: [PATCH 127/241] docs: start drafting new route system Signed-off-by: Camila Belo --- .../frontend-system/architecture/07-routes.md | 457 ++++++++++++++---- 1 file changed, 367 insertions(+), 90 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 1402796077..b38ef9016c 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -8,143 +8,420 @@ description: Frontend routes > **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** -See [routing system docs](../../plugins/composability.md#routing-system) - ## Introduction - +The composability system isn't a single API surface. It is a collection of patterns, primitives, and APIs. At the core is the concept of extensions, which are exported by plugins for use in the app. One of the concepts is `RouteRef` which enables us route between pages in a flexible way, and it is especially important when bringing together different open source plugins. ## Route References - +There are 3 types of route references: regular route, sub route, and external route, and we will cover both the concept and code definition for each. Keep reading 🙂! ### Creating a Route Reference - +```tsx +// plugins/catalog/src/routes.ts +import { createRouteRef } from '@backstage/frontend-plugin-api'; -### Using a Route Reference +export const rootRouteRef = createRouteRef(); +``` - +Note that you almost always want to create the route references themselves in a different file than the one that creates the plugin instance, for example a top-level routes.ts. This is to avoid circular imports when you use the route references from other parts of the same plugin. ### Route Path Parameters - +The referenced route can also accepts `params`. Here is how you create a reference for a route that requires a kind, namespace and name `params`, like in this path `/entities/:name/:namespace/:kind`: + +```tsx +// plugins/catalog/src/routes.ts +import { createRouteRef } from '@backstage/frontend-plugin-api'; + +type DetailsRouteParams = { namespace: string; name: string; kind: string }; + +export const detailsRouteRef = createRouteRef({ + // A list of parameter names that the path that this route ref is bound to must contain + params: ['namespace', 'name', 'kind'], +}); +``` ### Providing Route References to Plugins - +Route refs do not have any behavior, in other words, they are an opaque type that represents route targets in an app, which are bound to specific paths at runtime, but they provide a level of indirection to help mix together different plugins that otherwise wouldn't know how to route to each other. + +The code snippet of the previous section does not indicate which plugin the route belongs to. To do so, we have to extend Backstage with a new page extension associated with the newly created `RouteRef` and provide the extension through our plugin. Here's what we need to do: + +```tsx +// plugins/catalog/src/routes.ts +import { createRouteRef } from '@backstage/frontend-plugin-api'; + +const rootRouteRef = createRouteRef(); // [1] + +// plugins/catalog/src/plugin.tsx +import { createPlugin, createPageExtension } from '@backstage/frontend-plugin-api'; +import { rootRouteRef } from './routes'; + +const rootPage = createPageExtension({ // [2] + // Ommiting name since it is the root page + defaultPath: '/' + routeRef: rootRouteRef, + loader: async () => Root Page +}); + +export default const createPlugin({ // [3] + id: 'catalog', + routes: { + root: rootRouteRef, + }, + extensions: [rootPage] +}); + +// plugins/catalog/src/index.ts +export { default } from './plugin' +``` + +We have completed our journey of creating a plugin page route. This is what the code does: + +- [1] The line 1 creates a route reference, which is not yet associated with any plugin page; +- [2] A route that renders nothing makes no sense, does it? So we are creating a page extension that associates a path and a component with the newly created route ref; +- [3] Finally, our plugin provides both routes and extensions. + +It's a smart question, and the answer can be found in the (Binding External Route References)[#building-external-route-references] section, wait a bit, keep reading and you'll understand why. + +### Using a Route Reference + +You can link to the routes from other pages in the same plugin or you can also link between different plugins pages. In this section we will cover the first scenario, if you are interested in link to a page of a plugin that isn't yours, please go to the [external routes](#external-router-references) section below. + +Alright, let's presume that we have a plugin that renders tow different pages, and these pages links to each other. + +First lets create the routes references: + +```tsx +// plugins/catalog/src/routes.ts +import { createRouteRef } from '@backstage/frontend-plugin-api'; + +const rootRouteRef = createRouteRef(); + +type DetailsRouteParams = { + namespace: string; + name: string; + kind: string; +}; + +export const detailsRouteRef = createRouteRef({ + // A list of parameter names that the path that this route ref is bound to must contain + params: ['namespace', 'name', 'kind'], +}); +``` + +Now we are ready to provide these routes via plugin extensions and link between pages: + +```tsx +// plugins/catalog/src/plugin.tsx +import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; +import { rootRouteRef, detailsRouteRef } from './routes'; + +const rootPage = createPageExtension({ + // Ommiting name since it is the root page + defaultPath: '/' + routeRef: rootRouteRef, + loader: async () => { + const href = useRouteRef(catalogEntityDetailsRouteRef)({ + kind: 'Component', + namespace: 'Default', + name: 'foo' + }); + + return ( +
+

Index Page

+ Entity Foo +
+ ); + } +}); + +const detailsPage = createPageExtension({ + name: 'details', + defaultPath: '/entities/:namespace/:kind/:name' + routeRef: detailsRouteRef, + loader: async () => ( +
+

Catalog Entities

+
+ ) +}); + +export default const createPlugin({ + id: 'catalog', + routes: { + list: catalogEntityListRouteRef, + details: catalogEntityDetailsRouteRef, + }, + extensions: [rootPage, detailsPage] +}); + +// plugins/catalog/src/index.ts +export { default } from './plugin' +``` + +During runtime, we used a hook `useRouteRef` to get the path to the details page. Because we are linking to pages of the same plugin, we are currently accessing the reference directly, but in the following sections, you will see how to link to pages of different plugins. ## External Router References - +```tsx +// plugins/catalog/src/routes.ts +import { + createRouteRef, + createExternalRouteRef, +} from '@backstage/frontend-plugin-api'; + +const rootRouteRef = createRouteRef(); +const createComponentRouteRef = createExternalRouteRef(); + +// plugins/catalog/src/plugin.tsx +import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; +import { rootRouteRef, createComponentRouteRef } from './routes'; + +const rootPage = createPageExtension({ + // Ommiting name since it is the root page + defaultPath: '/' + routeRef: rootRouteRef, + loader: async () => { + const href = useRouteRef(catalogCreateComponentRouteRef)(); + + return ( +
+

Catalog Entities

+ {/* Linking to a create component page without direct reference */} + Create Component +
+ ); + } +}); + +export default const createPlugin({ + id: 'catalog', + routes: { + entityList: entityListRouteRef + } + externalRoutes: { + createComponent: createComponentRouteRef, + }, + extensions: [rootPage] +}); + +// plugins/catalog/src/index.ts +export { default } from './plugin'; +``` + +```tsx +// plugins/scaffolder/src/routes.ts +import { createRouteRef } from '@backstage/frontend-plugin-api'; + +const createComponentRouteRef = createRouteRef(); + +// plugins/scaffolder/src/plugin.tsx +import { createPlugin, createPageExtension } from '@backstage/frontend-plugin-api'; +import { createComponentRouteRef } from './routes'; + +const createComponentPage = createPageExtension({ + defaultPath: '/' + routeRef: createComponentRouteRef, + loader: async () => ( +
+

Create Component

+
+ ) +}); + +export default const createPlugin({ + id: 'scaffolder', + routes: { + createComponent: createComponentRouteRef, + }, + extensions: [createComponentPage] +}); + +// plugins/scaffolder/src/index.ts +export { default } from './plugin'; +``` + +On important thing to highlight is that it is currently not possible to have parameterized `ExternalRouteRefs`, or to bind an external route to a parameterized route, although this may be added in the future if needed. + +Now let's move on and configure the app to point to the Scaffolder create component page when the catalog create component ref be used. ### Binding External Route References - +```yaml +# app-config.yaml +app: + routes: + bindings: + plugin.catalog.externalRoutes.createComponent: plugin.scaffolfer.routes.createComponent +``` + +Or via code, in the file where the app is created: + +```tsx +// packages/app/src/App.tsx +import { createApp } from '@backstage/frontend-app-api'; +import catalog from '@backstage/plugin-catalog'; +import scaffolder from '@backstage/plugin-scaffolder'; + +const app = createApp({ + bindRoutes({ bind }) { + bind(catalog.externalRoutes, { + createComponent: scaffolder.routes.createComponent, + }); + }, +}); + +export default app.createRoot(); + +// packages/app/src/index.ts +import ReactDOM from 'react-dom/client'; +import app from './App'; + +ReactDOM.createRoot(document.getElementById('root')!).render(app); +``` + +Given the above binding, using `useRouteRef(createComponentRouteRef)` within the Catalog plugin will let us create a link to whatever path the Scaffolder create component page is mounted at. + +Note that we are not importing and using the RouteRefs directly in the app, and instead rely on the plugin instance to access routes of the plugins. This is a new convention that was introduced to provide better namespacing and discoverability of routes, as well as reduce the number of separate exports from each plugin package. this his indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. + +Another thing to note is that this indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. For plugins that you build internally for your own Backstage application, you can choose to go the route of direct imports or even use concrete routes directly. Although there can be some benefits to using the full routing system even in internal plugins. It can help you structure your routes, and as you will see further down it also helps you manage route parameters.parameters. ### Optional External Route References - +```tsx +// plugins/catalog/src/routes.ts +import { + createRouteRef, + createExternalRouteRef, +} from '@backstage/frontend-plugin-api'; + +const rootRouteRef = createRouteRef(); +const createComponentRouteRef = createExternalRouteRef({ + optional: true, +}); +``` + +An external route that is marked as optional is not required to be bound in the app, allowing it to be used as a switch for whether a particular link should be displayed or action should be taken. + +When calling useRouteRef with an optional external route, its return signature is changed to RouteFunc | undefined, allowing for logic like this: + +```tsx +// plugins/catalog/src/plugin.tsx +import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; +import { rootRouteRef, createComponentRouteRef } from './routes'; + +const catalogEntityListPage = createPageExtension({ + defaultPath: '/' + routeRef: rootRouteRef, + loader: async () => { + const href = useRouteRef(catalogCreateComponentRouteRef)(); + + return ( +
+

Catalog Entities

+ {/* Since the route is optional, rendering the link only if the href is defined */} + {href && Create Component +
+ ); + } +}); + +export default const createPlugin({ + id: 'catalog', + routes: { + entityList: rootRouteRef + } + externalRoutes: { + createComponent: createComponentRouteRef, + }, + extensions: [catalogEntityListPage] +}); + +// index.ts +export { default } from './plugin'; +``` ## Sub Route References - +const rootRouteRef = createRouteRef(); +const detailsRouteRef = createSubRouteRef({ + parent: rootRouteRef, + path: '/details', +}); -```ts -/* +// plugins/catalog/src/plugin.ts +import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; +import { rootRouteRef, detailsRouteRef } from './routes.ts'; -Some examples +const DetailsPage = () => ( +
+

Entity Details

+
+); -export const indexPageRouteRef = createRouteRef() +const rootPage = createPageExtension({ + defaultPath: '/' + routeRef: rootRouteRef, + loader: async () => { + const { path } = useRouteRef(detailsRouteRef)(); -export const catalogPlugin = createPlugin({ - id: 'catalog, + return ( +
+

Index Page

+ + } /> + +
+ ); + } +}); + +export default createPlugin({ + id: 'catalog', routes: { - index: indexPageRouteRef, + root: rootRouteRef, + details: detailsRouteRef, }, -}) + extensions: [rootPage] +}); -// in catalog plugin - -import {indexPageRouteRef} from '../../routes - -const link = useRouteRef(indexPageRouteRef) - -// scaffolder - -export const catalogIndexPageRouteRef = createExternalRouteRef({ - defaultTarget: 'catalog/index', -}) - -export const scaffolderPlugin = createPlugin({ - id: 'scaffolder, - externalRoutes: { - catalogIndex: catalogIndexPageRouteRef, - }, -}) - - -import {catalogIndexPageRouteRef} from '../../routes - -const link = useRouteRef(catalogIndexPageRouteRef) - -// app - -import {catalogPlugin} from '@backstage/plugin-catalog' - -const app = createApp({ - bindRoutes({bind}) { - bind(scaffolderPlugin, { - catalogIndex: catalogPlugin.routes.index, - }) - }, -}) -*/ +// plugins/catalog/src/index.ts +export { default } from './plugin'; ``` From 21170a170969630b4be5aab671633ae832737516 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 09:46:16 +0100 Subject: [PATCH 128/241] docs(frontend-system): apply routes introduction suggestions Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index b38ef9016c..2280baba27 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -18,7 +18,7 @@ The composability system isn't a single API surface. It is a collection of patte ## Route References -In order to address the problem outlined above, we introduced the `RouteRefs` concept. `RouteRefs` abstract paths in a the Backstage app, and these paths can be configured both at the plugin level (by plugin developers) and at the instance level (by application integrators). +In order to address the problem outlined above, we introduced the concept of route references. A `RouteRef` is an abstract paths in a the Backstage app, and these paths can be configured both at the plugin level (by plugin developers) and at the instance level (by application integrators). Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at the app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, all that path can be changed, so app integrators can set a custom path to a route whenever they like to (more information in the following sessions). From 324cfdce7d6cec371f846b38d1fe8bc397db7a51 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 09:46:47 +0100 Subject: [PATCH 129/241] docs(frontend-system): apply external routes suggestions Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 2280baba27..8a33fb0f15 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -59,7 +59,7 @@ export const detailsRouteRef = createRouteRef({ Route refs do not have any behavior, in other words, they are an opaque type that represents route targets in an app, which are bound to specific paths at runtime, but they provide a level of indirection to help mix together different plugins that otherwise wouldn't know how to route to each other. -The code snippet of the previous section does not indicate which plugin the route belongs to. To do so, we have to extend Backstage with a new page extension associated with the newly created `RouteRef` and provide the extension through our plugin. Here's what we need to do: +The code snippet of the previous section does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension. When this extension is installed in the app it will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the the extension. Here's what we need to do: ```tsx // plugins/catalog/src/routes.ts From 103d2e11d1575f95a674b81b2de6bf0f10a9627b Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 09:47:20 +0100 Subject: [PATCH 130/241] docs(frontend-system): apply binding routes suggestions Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 8a33fb0f15..c8db088ed6 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -72,7 +72,7 @@ import { createPlugin, createPageExtension } from '@backstage/frontend-plugin-ap import { rootRouteRef } from './routes'; const rootPage = createPageExtension({ // [2] - // Ommiting name since it is the root page + // The `name` option is omitted since this is the root page defaultPath: '/' routeRef: rootRouteRef, loader: async () => Root Page From 4143a4d8452bc4b83e5b4e87820637aa16aac876 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 09:48:21 +0100 Subject: [PATCH 131/241] docs(frontend-system): replace page with div in route examples Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index c8db088ed6..fca9f35704 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -75,7 +75,7 @@ const rootPage = createPageExtension({ // [2] // The `name` option is omitted since this is the root page defaultPath: '/' routeRef: rootRouteRef, - loader: async () => Root Page + loader: async () =>
Root Page
}); export default const createPlugin({ // [3] From 1bb3addf16a3078fc12a30a29ca14372dd41e5d6 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 09:50:03 +0100 Subject: [PATCH 132/241] docs(frontend-system): fix using external route refs example Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index fca9f35704..0b08975ada 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -340,7 +340,7 @@ const catalogEntityListPage = createPageExtension({ defaultPath: '/' routeRef: rootRouteRef, loader: async () => { - const href = useRouteRef(catalogCreateComponentRouteRef)(); + const href = useRouteRef(catalogCreateComponentRouteRef); return (
From 76cbd8a54b098bce22c6bb7ccf97857bd2b46626 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 09:51:39 +0100 Subject: [PATCH 133/241] docs(frontend-system): fix route subpaths example Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 0b08975ada..422cecdf4d 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -400,13 +400,13 @@ const rootPage = createPageExtension({ defaultPath: '/' routeRef: rootRouteRef, loader: async () => { - const { path } = useRouteRef(detailsRouteRef)(); + const detailsRouteRef = useRouteRef(detailsRouteRef)(); return (

Index Page

- } /> + } />
); From 8a42e2248763019e11b0c0d0b881f67757989aad Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 09:54:20 +0100 Subject: [PATCH 134/241] docs(frontend-system): adjust subroute refs description Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 422cecdf4d..59785e1dfe 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -369,7 +369,7 @@ export { default } from './plugin'; ## Sub Route References -The last kind of route refs that can be created are `SubRouteRefs`, which can be used to create a route ref with a fixed path relative to an absolute `RouteRef`. They are useful if you have a page that internally is mounted at a sub route of a page extension component, and you want other plugins to be able to route to that page. +The last kind of route refs that can be created are `SubRouteRef`s, which can be used to create a route ref with a fixed path relative to an absolute `RouteRef`. They are useful if you have a page that internally is mounted at a sub route of a page extension component, and you want other plugins to be able to route to that page. And they can be a useful utility to handle routing within a plugin itself as well. For example: From 144f94ecbe14b2ee9687e9c7effb369d4396df6e Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 09:56:44 +0100 Subject: [PATCH 135/241] docs(frontend-system): replace routes composability with frontend system Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 59785e1dfe..ccc44967d2 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -10,11 +10,11 @@ description: Frontend routes ## Introduction -This page describes the composability system that helps bring together content from a multitude of plugins into one Backstage application. +This page describes the frontend system that helps bring together content from a multitude of plugins into one Backstage application. -The core principle of the composability system is that plugins should have clear boundaries and connections. It should isolate crashes within a plugin, but allow navigation between them. It should allow for plugins to be loaded only when needed, and enable plugins to provide extension points for other plugins to build upon. The composability system is also built with an app-first mindset, prioritizing simplicity and clarity in the app over that in the plugins and core APIs. +The core principle of the frontend system is that plugins should have clear boundaries and connections. It should isolate crashes within a plugin, but allow navigation between them. It should allow for plugins to be loaded only when needed, and enable plugins to provide extension points for other plugins to build upon. The frontend system is also built with an app-first mindset, prioritizing simplicity and clarity in the app over that in the plugins and core APIs. -The composability system isn't a single API surface. It is a collection of patterns, primitives, and APIs. At the core is the concept of extensions, which are exported by plugins for use in the app. One of the concepts is `RouteRef` which enables us route between pages in a flexible way, and it is especially important when bringing together different open source plugins. +The frontend system isn't a single API surface. It is a collection of patterns, primitives, and APIs. At the core is the concept of extensions, which are exported by plugins for use in the app. One of the concepts is `RouteRef` which enables us route between pages in a flexible way, and it is especially important when bringing together different open source plugins. ## Route References From 16a04419d2e6a24133b10354f5c182030c0a3bdd Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 9 Jan 2024 13:02:16 +0100 Subject: [PATCH 136/241] docs(frontend-system): combine optional external routes code snippets Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index ccc44967d2..1639c8ece9 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -312,7 +312,7 @@ Another thing to note is that this indirection in the routing is particularly us ### Optional External Route References -When creating an ExternalRouteRef it is possible to mark it as optional: +It is possible to define an `ExternalRouteRef` as optional, so it is not required to bind it in the app. When calling `useRouteRef` with an optional external route, its return signature is changed to `RouteFunc | undefined`, and the returned value can be used used to decide whether a certain link should be displayed or if an action should be taken: ```tsx // plugins/catalog/src/routes.ts @@ -325,13 +325,7 @@ const rootRouteRef = createRouteRef(); const createComponentRouteRef = createExternalRouteRef({ optional: true, }); -``` -An external route that is marked as optional is not required to be bound in the app, allowing it to be used as a switch for whether a particular link should be displayed or action should be taken. - -When calling useRouteRef with an optional external route, its return signature is changed to RouteFunc | undefined, allowing for logic like this: - -```tsx // plugins/catalog/src/plugin.tsx import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; import { rootRouteRef, createComponentRouteRef } from './routes'; From bba9de8e5cc2404bfb7c3cd268fd8aad45e8a58a Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 15:16:28 +0100 Subject: [PATCH 137/241] docs(frontend-system): add subroutes with params example Signed-off-by: Camila Belo --- .../frontend-system/architecture/07-routes.md | 104 ++++++++++++++++-- 1 file changed, 94 insertions(+), 10 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 1639c8ece9..1e81b8485f 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -381,6 +381,8 @@ const detailsRouteRef = createSubRouteRef({ }); // plugins/catalog/src/plugin.ts +import React from 'react'; +import { Routes, Route, Link } from 'react-router-dom'; import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; import { rootRouteRef, detailsRouteRef } from './routes.ts'; @@ -391,19 +393,27 @@ const DetailsPage = () => ( ); const rootPage = createPageExtension({ - defaultPath: '/' + defaultPath: '/', routeRef: rootRouteRef, loader: async () => { - const detailsRouteRef = useRouteRef(detailsRouteRef)(); + const Component = () => { + const to = useRouteRef(detailsRouteRef)(); - return ( -
-

Index Page

- - } /> - -
- ); + return ( +
+

Index Page

+ {/* Registering the details subroute */} + + } /> + + {/* Linking to the details subroute */} + Details Subpage +
+ ); + }; + + return ; + }, } }); @@ -419,3 +429,77 @@ export default createPlugin({ // plugins/catalog/src/index.ts export { default } from './plugin'; ``` + +Subroutes can also receive parameters, here is an example: + +```tsx +// plugins/catalog/src/routes.ts +import { + createRouteRef, + createSubRouteRef, +} from '@backstage/frontend-plugin-api'; + +const rootRouteRef = createRouteRef(); +const detailsRouteRef = createSubRouteRef({ + parent: rootRouteRef, + path: '/details/:name/:namespace/:kind', +}); + +// plugins/catalog/src/plugin.ts +import React from 'react'; +import { Routes, Route, Link } from 'react-router-dom'; +import { + createPlugin, + createPageExtension, + useRouteRef, +} from '@backstage/frontend-plugin-api'; +import { rootRouteRef, detailsRouteRef } from './routes.ts'; + +const DetailsPage = () => ( +
+

Entity Details

+ {/* can get the entity ref from URL and load the entity data here */} +
+); + +const rootPage = createPageExtension({ + defaultPath: '/subroutes', + routeRef: rootRouteRef, + loader: async () => { + const Component = () => { + const detailsRoutePath = useRouteRef(detailsRouteRef)({ + // Setting the details subroute params + name: 'entity1', + namespace: 'default', + kind: 'component', + }); + + return ( +
+

Index Page

+ {/* Registering the details subroute */} + + } /> + + {/* Linking to the details subroute */} + Entity 1 Details Subpage +
+ ); + }; + + return ; + }, +}); + +export default createPlugin({ + id: 'catalog', + routes: { + root: rootRouteRef, + details: detailsRouteRef, + }, + extensions: [rootPage], +}); + +// plugins/catalog/src/index.ts +export { default } from './plugin'; +``` From c0a0452bb81ab7d28f5d86624472077cb4d78202 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 16:45:52 +0100 Subject: [PATCH 138/241] docs(frontend-system): improve optional external route explanation Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 1e81b8485f..2eb10b7fc9 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -93,7 +93,7 @@ export { default } from './plugin' We have completed our journey of creating a plugin page route. This is what the code does: - [1] The line 1 creates a route reference, which is not yet associated with any plugin page; -- [2] A route that renders nothing makes no sense, does it? So we are creating a page extension that associates a path and a component with the newly created route ref; +- [2] We associate our route reference with our page by providing it as an option during creation of the page extension. - [3] Finally, our plugin provides both routes and extensions. It's a smart question, and the answer can be found in the (Binding External Route References)[#building-external-route-references] section, wait a bit, keep reading and you'll understand why. From 70fdbad26a1aa79378804706309b0fa821719f92 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 17:40:06 +0100 Subject: [PATCH 139/241] docs(frontend-system): export route when providing refs Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 2eb10b7fc9..52edea5de9 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -65,7 +65,7 @@ The code snippet of the previous section does not indicate which plugin the rout // plugins/catalog/src/routes.ts import { createRouteRef } from '@backstage/frontend-plugin-api'; -const rootRouteRef = createRouteRef(); // [1] +export const rootRouteRef = createRouteRef(); // [1] // plugins/catalog/src/plugin.tsx import { createPlugin, createPageExtension } from '@backstage/frontend-plugin-api'; From 2ae04c3c1d8d139dc8f964fb26cf52c037bc84c6 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 17:46:00 +0100 Subject: [PATCH 140/241] docs(frontend-system): fix dialogue on external routes binding Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 52edea5de9..2bc2792e89 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -96,7 +96,7 @@ We have completed our journey of creating a plugin page route. This is what the - [2] We associate our route reference with our page by providing it as an option during creation of the page extension. - [3] Finally, our plugin provides both routes and extensions. -It's a smart question, and the answer can be found in the (Binding External Route References)[#building-external-route-references] section, wait a bit, keep reading and you'll understand why. +It may be unclear why we need to pass the route to the plugin once it has already been passed to the extension. It's a good point, and the explanation can be found in the (Binding External Route References)[#building-external-route-references] section, wait a bit, keep reading and you'll understand why. ### Using a Route Reference From b0ee827e0068704722b049107495da5693c52b0e Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 17:51:06 +0100 Subject: [PATCH 141/241] docs(frontend-system): remove duplicated binding routes explanation Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 2bc2792e89..b76619f9c3 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -306,7 +306,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render(app); Given the above binding, using `useRouteRef(createComponentRouteRef)` within the Catalog plugin will let us create a link to whatever path the Scaffolder create component page is mounted at. -Note that we are not importing and using the RouteRefs directly in the app, and instead rely on the plugin instance to access routes of the plugins. This is a new convention that was introduced to provide better namespacing and discoverability of routes, as well as reduce the number of separate exports from each plugin package. this his indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. +Note that we are not importing and using the `RouteRef`s directly in the app, and instead rely on the plugin instance to access routes of the plugins. This is a new convention that was introduced to provide better namespacing and discoverability of routes, as well as reduce the number of separate exports from each plugin package. Another thing to note is that this indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. For plugins that you build internally for your own Backstage application, you can choose to go the route of direct imports or even use concrete routes directly. Although there can be some benefits to using the full routing system even in internal plugins. It can help you structure your routes, and as you will see further down it also helps you manage route parameters.parameters. From d0fda6d3e6959d97cb9c92bda9542cb1ed1e7521 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 17:52:04 +0100 Subject: [PATCH 142/241] docs(frontend-system): rephrase external routes description Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index b76619f9c3..04f6341e70 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -100,7 +100,7 @@ It may be unclear why we need to pass the route to the plugin once it has alread ### Using a Route Reference -You can link to the routes from other pages in the same plugin or you can also link between different plugins pages. In this section we will cover the first scenario, if you are interested in link to a page of a plugin that isn't yours, please go to the [external routes](#external-router-references) section below. +You can link to the routes from other pages in the same plugin or you can also link between different plugins pages. In this section we will cover the first scenario, if you are interested in link to a page of a different plugin, please go to the [external routes](#external-router-references) section below. Alright, let's presume that we have a plugin that renders tow different pages, and these pages links to each other. From 137c73ca535cc317db7836672ea5b599c4972661 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 18:00:09 +0100 Subject: [PATCH 143/241] docs(frontend-system): apply more routes suggestions Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 04f6341e70..0acbebb106 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -102,7 +102,7 @@ It may be unclear why we need to pass the route to the plugin once it has alread You can link to the routes from other pages in the same plugin or you can also link between different plugins pages. In this section we will cover the first scenario, if you are interested in link to a page of a different plugin, please go to the [external routes](#external-router-references) section below. -Alright, let's presume that we have a plugin that renders tow different pages, and these pages links to each other. +Alright, let's presume that we have a plugin that renders two different pages, and these pages link to each other. First lets create the routes references: @@ -110,7 +110,7 @@ First lets create the routes references: // plugins/catalog/src/routes.ts import { createRouteRef } from '@backstage/frontend-plugin-api'; -const rootRouteRef = createRouteRef(); +export const rootRouteRef = createRouteRef(); type DetailsRouteParams = { namespace: string; @@ -136,7 +136,7 @@ const rootPage = createPageExtension({ defaultPath: '/' routeRef: rootRouteRef, loader: async () => { - const href = useRouteRef(catalogEntityDetailsRouteRef)({ + const href = useRouteRef(detailsRouteRef)({ kind: 'Component', namespace: 'Default', name: 'foo' @@ -165,8 +165,8 @@ const detailsPage = createPageExtension({ export default const createPlugin({ id: 'catalog', routes: { - list: catalogEntityListRouteRef, - details: catalogEntityDetailsRouteRef, + root: rootRouteRef + details: detailsRouteRef, }, extensions: [rootPage, detailsPage] }); @@ -179,9 +179,9 @@ During runtime, we used a hook `useRouteRef` to get the path to the details page ## External Router References -Now let's assume that we want to link from the Catalog entity list page to the Scaffolder create component page. We don't want to reference the Scaffolder plugin directly, since that would create an unnecessary dependency. It would also provided little flexibility in allowing the app to tie plugins together, with the links instead being dictated by the plugins themselves. To solve this, we use ExternalRouteRefs. Much like regular route references, they can be passed to `useRouteRef` to create concrete URLs, but they can not be used in page extensions and instead have to be associated with a target route using route bindings in the app. +Now let's assume that we want to link from the Catalog entity list page to the Scaffolder create component page. We don't want to reference the Scaffolder plugin directly, since that would create an unnecessary dependency. It would also provided little flexibility in allowing the app to tie plugins together, with the links instead being dictated by the plugins themselves. To solve this, we use an `ExternalRouteRef`. Much like regular route references, they can be passed to `useRouteRef` to create concrete URLs, but they can not be used in page extensions and instead have to be associated with a target route using route bindings in the app. -We create a new ExternalRouteRef inside the Scaffolder plugin, using a neutral name that describes its role in the plugin rather than a specific plugin page that it might be linking to, allowing the app to decide the final target. If the Catalog entity list page for example wants to link the Scaffolder create component page in the header, it might declare an ExternalRouteRef similar to this: +We create a new `RouteRef` inside the Scaffolder plugin, using a neutral name that describes its role in the plugin rather than a specific plugin page that it might be linking to, allowing the app to decide the final target. If the Catalog entity list page for example wants to link the Scaffolder create component page in the header, it might declare an `ExternalRouteRef` similar to this: ```tsx // plugins/catalog/src/routes.ts @@ -217,7 +217,7 @@ const rootPage = createPageExtension({ export default const createPlugin({ id: 'catalog', routes: { - entityList: entityListRouteRef + root: rootRouteRef, } externalRoutes: { createComponent: createComponentRouteRef, From 472a39e1092026181daaa15329050ff908487e39 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 19:26:02 +0100 Subject: [PATCH 144/241] docs(frontend-system): more code snippet fixes Signed-off-by: Camila Belo --- .../frontend-system/architecture/07-routes.md | 341 +++++++++++------- 1 file changed, 202 insertions(+), 139 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 0acbebb106..f4cebe3dd1 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -26,15 +26,13 @@ There are 3 types of route references: regular route, sub route, and external ro ### Creating a Route Reference -Route references, also known as root plugin pages, are created as follows: - -_Catalog Plugin_ +Route references, also known as plugins' index pages, are created as follows: ```tsx // plugins/catalog/src/routes.ts import { createRouteRef } from '@backstage/frontend-plugin-api'; -export const rootRouteRef = createRouteRef(); +export const indexRouteRef = createRouteRef(); ``` Note that you almost always want to create the route references themselves in a different file than the one that creates the plugin instance, for example a top-level routes.ts. This is to avoid circular imports when you use the route references from other parts of the same plugin. @@ -47,10 +45,8 @@ The referenced route can also accepts `params`. Here is how you create a referen // plugins/catalog/src/routes.ts import { createRouteRef } from '@backstage/frontend-plugin-api'; -type DetailsRouteParams = { namespace: string; name: string; kind: string }; - -export const detailsRouteRef = createRouteRef({ - // A list of parameter names that the path that this route ref is bound to must contain +export const detailsRouteRef = createRouteRef({ + // The parameters that must be included in the path of this route reference params: ['namespace', 'name', 'kind'], }); ``` @@ -65,29 +61,35 @@ The code snippet of the previous section does not indicate which plugin the rout // plugins/catalog/src/routes.ts import { createRouteRef } from '@backstage/frontend-plugin-api'; -export const rootRouteRef = createRouteRef(); // [1] +export const indexRouteRef = createRouteRef(); // [1] // plugins/catalog/src/plugin.tsx -import { createPlugin, createPageExtension } from '@backstage/frontend-plugin-api'; -import { rootRouteRef } from './routes'; +import React from 'react'; +import { + createPlugin, + createPageExtension, +} from '@backstage/frontend-plugin-api'; +import { indexRouteRef } from './routes'; -const rootPage = createPageExtension({ // [2] - // The `name` option is omitted since this is the root page - defaultPath: '/' - routeRef: rootRouteRef, - loader: async () =>
Root Page
+const indexPage = createPageExtension({ + // [2] + // The `name` option is omitted since this is the index page + defaultPath: '/entities', + routeRef: indexRouteRef, + loader: async () =>
Root Page
, }); -export default const createPlugin({ // [3] +export default createPlugin({ + // [3] id: 'catalog', routes: { - root: rootRouteRef, + index: indexRouteRef, }, - extensions: [rootPage] + extensions: [indexPage], }); // plugins/catalog/src/index.ts -export { default } from './plugin' +export { default } from './plugin'; ``` We have completed our journey of creating a plugin page route. This is what the code does: @@ -110,16 +112,10 @@ First lets create the routes references: // plugins/catalog/src/routes.ts import { createRouteRef } from '@backstage/frontend-plugin-api'; -export const rootRouteRef = createRouteRef(); +export const indexRouteRef = createRouteRef(); -type DetailsRouteParams = { - namespace: string; - name: string; - kind: string; -}; - -export const detailsRouteRef = createRouteRef({ - // A list of parameter names that the path that this route ref is bound to must contain +export const detailsRouteRef = createRouteRef({ + // The parameters that must be included in the path of this route reference params: ['namespace', 'name', 'kind'], }); ``` @@ -128,51 +124,73 @@ Now we are ready to provide these routes via plugin extensions and link between ```tsx // plugins/catalog/src/plugin.tsx -import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; +import React from 'react'; +import { useParams } from 'react-router'; +import { + createPlugin, + createPageExtension, + useRouteRef, +} from '@backstage/frontend-plugin-api'; import { rootRouteRef, detailsRouteRef } from './routes'; -const rootPage = createPageExtension({ +const indexPage = createPageExtension({ // Ommiting name since it is the root page - defaultPath: '/' - routeRef: rootRouteRef, + defaultPath: '/entities', + routeRef: indexRouteRef, loader: async () => { - const href = useRouteRef(detailsRouteRef)({ - kind: 'Component', - namespace: 'Default', - name: 'foo' - }); + const Component = () => { + const href = useRouteRef(detailsRouteRef)({ + kind: 'component', + namespace: 'default', + name: 'foo', + }); - return ( -
-

Index Page

- Entity Foo -
- ); - } + return ( +
+

Index Page

+ Entity Foo +
+ ); + }; + + return ; + }, }); const detailsPage = createPageExtension({ name: 'details', - defaultPath: '/entities/:namespace/:kind/:name' + defaultPath: '/entities/:namespace/:kind/:name', routeRef: detailsRouteRef, - loader: async () => ( -
-

Catalog Entities

-
- ) + loader: async () => { + const Component = () => { + // Getting the parameters from the URL + const params = useParams(); + return ( +
+

Details Page

+
    +
  • Kind: {params.kind}
  • +
  • Namespace: {params.namespace}
  • +
  • Name: {params.name}
  • +
+
+ ); + }; + return ; + }, }); -export default const createPlugin({ +export default createPlugin({ id: 'catalog', routes: { - root: rootRouteRef + index: indexRouteRef, details: detailsRouteRef, }, - extensions: [rootPage, detailsPage] + extensions: [indexPage, detailsPage], }); // plugins/catalog/src/index.ts -export { default } from './plugin' +export { default } from './plugin'; ``` During runtime, we used a hook `useRouteRef` to get the path to the details page. Because we are linking to pages of the same plugin, we are currently accessing the reference directly, but in the following sections, you will see how to link to pages of different plugins. @@ -183,6 +201,8 @@ Now let's assume that we want to link from the Catalog entity list page to the S We create a new `RouteRef` inside the Scaffolder plugin, using a neutral name that describes its role in the plugin rather than a specific plugin page that it might be linking to, allowing the app to decide the final target. If the Catalog entity list page for example wants to link the Scaffolder create component page in the header, it might declare an `ExternalRouteRef` similar to this: +_Catalog Plugin_ + ```tsx // plugins/catalog/src/routes.ts import { @@ -190,19 +210,19 @@ import { createExternalRouteRef, } from '@backstage/frontend-plugin-api'; -const rootRouteRef = createRouteRef(); +const indexRouteRef = createRouteRef(); const createComponentRouteRef = createExternalRouteRef(); // plugins/catalog/src/plugin.tsx +import React from 'react'; import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; -import { rootRouteRef, createComponentRouteRef } from './routes'; +import { indexRouteRef, createComponentRouteRef } from './routes'; -const rootPage = createPageExtension({ - // Ommiting name since it is the root page - defaultPath: '/' - routeRef: rootRouteRef, +const indexPage = createPageExtension({ + defaultPath: '/entities', + routeRef: indexRouteRef, loader: async () => { - const href = useRouteRef(catalogCreateComponentRouteRef)(); + const href = useRouteRef(createComponentRouteRef)(); return (
@@ -214,47 +234,53 @@ const rootPage = createPageExtension({ } }); -export default const createPlugin({ +export default createPlugin({ id: 'catalog', routes: { - root: rootRouteRef, + index: indexRouteRef, } externalRoutes: { createComponent: createComponentRouteRef, }, - extensions: [rootPage] + extensions: [indexPage] }); // plugins/catalog/src/index.ts export { default } from './plugin'; ``` +_Scaffolder Plugin_ + ```tsx // plugins/scaffolder/src/routes.ts import { createRouteRef } from '@backstage/frontend-plugin-api'; -const createComponentRouteRef = createRouteRef(); +const indexRouteRef = createRouteRef(); // plugins/scaffolder/src/plugin.tsx -import { createPlugin, createPageExtension } from '@backstage/frontend-plugin-api'; -import { createComponentRouteRef } from './routes'; +import React from 'react'; +import { + createPlugin, + createPageExtension, +} from '@backstage/frontend-plugin-api'; +import { indexRouteRef } from './routes'; -const createComponentPage = createPageExtension({ - defaultPath: '/' - routeRef: createComponentRouteRef, +const indexPage = createPageExtension({ + defaultPath: '/create', + routeRef: indexRouteRef, loader: async () => (

Create Component

- ) + ), }); -export default const createPlugin({ +export default createPlugin({ id: 'scaffolder', routes: { - createComponent: createComponentRouteRef, + index: indexRouteRef, }, - extensions: [createComponentPage] + extensions: [indexPage], }); // plugins/scaffolder/src/index.ts @@ -276,7 +302,7 @@ Using the above example of the Catalog entities list page to the Scaffolder crea app: routes: bindings: - plugin.catalog.externalRoutes.createComponent: plugin.scaffolfer.routes.createComponent + plugin.catalog.externalRoutes.createComponent: plugin.scaffolder.routes.index ``` Or via code, in the file where the app is created: @@ -296,12 +322,6 @@ const app = createApp({ }); export default app.createRoot(); - -// packages/app/src/index.ts -import ReactDOM from 'react-dom/client'; -import app from './App'; - -ReactDOM.createRoot(document.getElementById('root')!).render(app); ``` Given the above binding, using `useRouteRef(createComponentRouteRef)` within the Catalog plugin will let us create a link to whatever path the Scaffolder create component page is mounted at. @@ -321,40 +341,45 @@ import { createExternalRouteRef, } from '@backstage/frontend-plugin-api'; -const rootRouteRef = createRouteRef(); +const indexRouteRef = createRouteRef(); const createComponentRouteRef = createExternalRouteRef({ optional: true, }); // plugins/catalog/src/plugin.tsx -import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; -import { rootRouteRef, createComponentRouteRef } from './routes'; +import React from 'react'; +import { + createPlugin, + createPageExtension, + useRouteRef, +} from '@backstage/frontend-plugin-api'; +import { indexRouteRef, createComponentRouteRef } from './routes'; -const catalogEntityListPage = createPageExtension({ - defaultPath: '/' - routeRef: rootRouteRef, +const indexPage = createPageExtension({ + defaultPath: '/entities', + routeRef: indexRouteRef, loader: async () => { - const href = useRouteRef(catalogCreateComponentRouteRef); + const link = useRouteRef(createComponentRouteRef); return (

Catalog Entities

{/* Since the route is optional, rendering the link only if the href is defined */} - {href && Create Component + {link && Create Component}
); - } + }, }); -export default const createPlugin({ +export default createPlugin({ id: 'catalog', routes: { - entityList: rootRouteRef - } + index: indexRouteRef, + }, externalRoutes: { createComponent: createComponentRouteRef, }, - extensions: [catalogEntityListPage] + extensions: [indexPage], }); // index.ts @@ -371,59 +396,66 @@ For example: // plugins/catalog/src/routes.ts import { createRouteRef, - createSubRouteRef + createSubRouteRef, } from '@backstage/frontend-plugin-api'; -const rootRouteRef = createRouteRef(); -const detailsRouteRef = createSubRouteRef({ - parent: rootRouteRef, +const indexRouteRef = createRouteRef(); +const detailsSubRouteRef = createSubRouteRef({ + parent: indexRouteRef, path: '/details', }); // plugins/catalog/src/plugin.ts import React from 'react'; -import { Routes, Route, Link } from 'react-router-dom'; -import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; -import { rootRouteRef, detailsRouteRef } from './routes.ts'; +import { Routes, Route, useLocation } from 'react-router-dom'; +import { + createPlugin, + createPageExtension, + useRouteRef, +} from '@backstage/frontend-plugin-api'; +import { indexRouteRef, detailsSubRouteRef } from './routes.ts'; const DetailsPage = () => (
-

Entity Details

+

Details Sub Page

); -const rootPage = createPageExtension({ - defaultPath: '/', - routeRef: rootRouteRef, +const indexPage = createPageExtension({ + defaultPath: '/entities', + routeRef: indexRouteRef, loader: async () => { const Component = () => { - const to = useRouteRef(detailsRouteRef)(); + const { pathname } = useLocation(); + const indexPath = useRouteRef(indexRouteRef)(); + const detailsPath = useRouteRef(detailsSubRouteRef)(); return (

Index Page

- {/* Registering the details subroute */} + {/* Linking to the index route */} + {pathname === detailsPath && Hide details} + {/* Linking to the details sub route */} + {pathname === indexPath && Show details} + {/* Registering the details sub route */} - } /> + } /> - {/* Linking to the details subroute */} - Details Subpage
); }; return ; }, - } }); export default createPlugin({ id: 'catalog', routes: { - root: rootRouteRef, - details: detailsRouteRef, + index: indexRouteRef, + details: detailsSubRouteRef, }, - extensions: [rootPage] + extensions: [indexPage], }); // plugins/catalog/src/index.ts @@ -439,50 +471,81 @@ import { createSubRouteRef, } from '@backstage/frontend-plugin-api'; -const rootRouteRef = createRouteRef(); -const detailsRouteRef = createSubRouteRef({ - parent: rootRouteRef, - path: '/details/:name/:namespace/:kind', +const indexRouteRef = createRouteRef(); +const detailsSubRouteRef = createSubRouteRef({ + parent: indexRouteRef, + path: '/:name/:namespace/:kind', }); // plugins/catalog/src/plugin.ts import React from 'react'; -import { Routes, Route, Link } from 'react-router-dom'; +import { Routes, Route, Link, useParams, useLocation } from 'react-router-dom'; import { createPlugin, createPageExtension, useRouteRef, } from '@backstage/frontend-plugin-api'; -import { rootRouteRef, detailsRouteRef } from './routes.ts'; +import { indexRouteRef, detailsSubRouteRef } from './routes.ts'; -const DetailsPage = () => ( -
-

Entity Details

- {/* can get the entity ref from URL and load the entity data here */} -
-); +const DetailsPage = () => { + // Getting the parameters from the URL + const params = useParams(); + return ( +
+

Details Sub Page

+
    +
  • Kind: {params.kind}
  • +
  • Namespace: {params.namespace}
  • +
  • Name: {params.name}
  • +
+
+ ); +}; -const rootPage = createPageExtension({ - defaultPath: '/subroutes', - routeRef: rootRouteRef, +const indexPage = createPageExtension({ + defaultPath: '/entities', + routeRef: indexRouteRef, loader: async () => { const Component = () => { - const detailsRoutePath = useRouteRef(detailsRouteRef)({ + const { pathname } = useLocation(); + const indexPath = useRouteRef(indexRouteRef)(); + const detailsPath = useRouteRef(detailsSubRouteRef)({ // Setting the details subroute params - name: 'entity1', - namespace: 'default', kind: 'component', + namespace: 'default', + name: 'foo', }); return (

Index Page

+ + + + + + + + + + + + + +
NameDetails
Foo + {/* Linking to the index route */} + {pathname === detailsPath && ( + Hide details + )} + {/* Linking to the details sub route */} + {pathname === indexPath && ( + Show details + )} +
{/* Registering the details subroute */} - } /> + } /> - {/* Linking to the details subroute */} - Entity 1 Details Subpage
); }; @@ -494,10 +557,10 @@ const rootPage = createPageExtension({ export default createPlugin({ id: 'catalog', routes: { - root: rootRouteRef, - details: detailsRouteRef, + index: indexRouteRef, + details: detailsSubRouteRef, }, - extensions: [rootPage], + extensions: [indexPage], }); // plugins/catalog/src/index.ts From 394b286aa56cd6c9262d5fc47dec5b83abd918ce Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 19:33:44 +0100 Subject: [PATCH 145/241] docs(frontend-system): remove parameterised external route note Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index f4cebe3dd1..8ffecaa827 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -287,7 +287,6 @@ export default createPlugin({ export { default } from './plugin'; ``` -On important thing to highlight is that it is currently not possible to have parameterized `ExternalRouteRefs`, or to bind an external route to a parameterized route, although this may be added in the future if needed. Now let's move on and configure the app to point to the Scaffolder create component page when the catalog create component ref be used. From 007003719a1bc82452744d6c38bf6e92627a01f3 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 19:36:30 +0100 Subject: [PATCH 146/241] docs(frontend-system): remove redundant page name comment Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 8ffecaa827..caa93eaf67 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -134,7 +134,6 @@ import { import { rootRouteRef, detailsRouteRef } from './routes'; const indexPage = createPageExtension({ - // Ommiting name since it is the root page defaultPath: '/entities', routeRef: indexRouteRef, loader: async () => { @@ -287,7 +286,6 @@ export default createPlugin({ export { default } from './plugin'; ``` - Now let's move on and configure the app to point to the Scaffolder create component page when the catalog create component ref be used. ### Binding External Route References From 6f1016a126cf7fff8b33341421eb9813b09f182c Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 11 Jan 2024 19:55:46 +0100 Subject: [PATCH 147/241] docs(frontend-system): more routes adjustments Signed-off-by: Camila Belo --- .../frontend-system/architecture/07-routes.md | 216 ++++++++++++------ 1 file changed, 151 insertions(+), 65 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index caa93eaf67..0fe2a8cc85 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -18,15 +18,15 @@ The frontend system isn't a single API surface. It is a collection of patterns, ## Route References -In order to address the problem outlined above, we introduced the concept of route references. A `RouteRef` is an abstract paths in a the Backstage app, and these paths can be configured both at the plugin level (by plugin developers) and at the instance level (by application integrators). +In order to address the problem outlined above, we introduced the concept of route references. A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at instance level (by application integrators). -Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at the app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, all that path can be changed, so app integrators can set a custom path to a route whenever they like to (more information in the following sessions). +Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sessions). There are 3 types of route references: regular route, sub route, and external route, and we will cover both the concept and code definition for each. Keep reading 🙂! ### Creating a Route Reference -Route references, also known as plugins' index pages, are created as follows: +Route references, also known as plugins' index pages or regular routes, are created as follows: ```tsx // plugins/catalog/src/routes.ts @@ -37,20 +37,6 @@ export const indexRouteRef = createRouteRef(); Note that you almost always want to create the route references themselves in a different file than the one that creates the plugin instance, for example a top-level routes.ts. This is to avoid circular imports when you use the route references from other parts of the same plugin. -### Route Path Parameters - -The referenced route can also accepts `params`. Here is how you create a reference for a route that requires a kind, namespace and name `params`, like in this path `/entities/:name/:namespace/:kind`: - -```tsx -// plugins/catalog/src/routes.ts -import { createRouteRef } from '@backstage/frontend-plugin-api'; - -export const detailsRouteRef = createRouteRef({ - // The parameters that must be included in the path of this route reference - params: ['namespace', 'name', 'kind'], -}); -``` - ### Providing Route References to Plugins Route refs do not have any behavior, in other words, they are an opaque type that represents route targets in an app, which are bound to specific paths at runtime, but they provide a level of indirection to help mix together different plugins that otherwise wouldn't know how to route to each other. @@ -71,12 +57,12 @@ import { } from '@backstage/frontend-plugin-api'; import { indexRouteRef } from './routes'; -const indexPage = createPageExtension({ +// The `name` option is omitted since this is the index page +const catalogIndexPage = createPageExtension({ // [2] - // The `name` option is omitted since this is the index page defaultPath: '/entities', routeRef: indexRouteRef, - loader: async () =>
Root Page
, + loader: async () =>
Index Page
, }); export default createPlugin({ @@ -85,7 +71,7 @@ export default createPlugin({ routes: { index: indexRouteRef, }, - extensions: [indexPage], + extensions: [catalogIndexPage], }); // plugins/catalog/src/index.ts @@ -98,7 +84,21 @@ We have completed our journey of creating a plugin page route. This is what the - [2] We associate our route reference with our page by providing it as an option during creation of the page extension. - [3] Finally, our plugin provides both routes and extensions. -It may be unclear why we need to pass the route to the plugin once it has already been passed to the extension. It's a good point, and the explanation can be found in the (Binding External Route References)[#building-external-route-references] section, wait a bit, keep reading and you'll understand why. +It may be unclear why we need to pass the route to the plugin once it has already been passed to the extension, but the explanation can be found in the (Binding External Route References)[#building-external-route-references] section, wait a bit, keep reading and you'll understand why. + +### Route Path Parameters + +The referenced route can also accepts `params`. Here is how you create a reference for a route that requires a `kind`, `namespace` and `name` params, like in this path `/entities/:kind/:namespace/:name`: + +```tsx +// plugins/catalog/src/routes.ts +import { createRouteRef } from '@backstage/frontend-plugin-api'; + +export const detailsRouteRef = createRouteRef({ + // The parameters that must be included in the path of this route reference + params: ['kind', 'namespace', 'name'], +}); +``` ### Using a Route Reference @@ -116,7 +116,7 @@ export const indexRouteRef = createRouteRef(); export const detailsRouteRef = createRouteRef({ // The parameters that must be included in the path of this route reference - params: ['namespace', 'name', 'kind'], + params: ['kind', 'namespace', 'name'], }); ``` @@ -133,12 +133,13 @@ import { } from '@backstage/frontend-plugin-api'; import { rootRouteRef, detailsRouteRef } from './routes'; -const indexPage = createPageExtension({ +const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, loader: async () => { const Component = () => { - const href = useRouteRef(detailsRouteRef)({ + const detailsLink = useRouteRef(detailsRouteRef); + const detailsPath = detailsLink({ kind: 'component', namespace: 'default', name: 'foo', @@ -147,7 +148,7 @@ const indexPage = createPageExtension({ return (

Index Page

- Entity Foo + See details
); }; @@ -156,8 +157,10 @@ const indexPage = createPageExtension({ }, }); -const detailsPage = createPageExtension({ +const catalogDetailsPage = createPageExtension({ name: 'details', + // It is important to mention here if an integrator configures a different path for this page via config file + // It will be their responsibility to make sure that it contains the same parameters, although they don't necessarily need to be in the same order. defaultPath: '/entities/:namespace/:kind/:name', routeRef: detailsRouteRef, loader: async () => { @@ -185,18 +188,18 @@ export default createPlugin({ index: indexRouteRef, details: detailsRouteRef, }, - extensions: [indexPage, detailsPage], + extensions: [catalogIndexPage, catalogDetailsPage], }); // plugins/catalog/src/index.ts export { default } from './plugin'; ``` -During runtime, we used a hook `useRouteRef` to get the path to the details page. Because we are linking to pages of the same plugin, we are currently accessing the reference directly, but in the following sections, you will see how to link to pages of different plugins. +During runtime, in the index page, we used a hook `useRouteRef` to get the path to the details page. Because we are linking to pages of the same plugin, we are currently accessing the reference directly, but in the following sections, you will see how to link to pages of different plugins. ## External Router References -Now let's assume that we want to link from the Catalog entity list page to the Scaffolder create component page. We don't want to reference the Scaffolder plugin directly, since that would create an unnecessary dependency. It would also provided little flexibility in allowing the app to tie plugins together, with the links instead being dictated by the plugins themselves. To solve this, we use an `ExternalRouteRef`. Much like regular route references, they can be passed to `useRouteRef` to create concrete URLs, but they can not be used in page extensions and instead have to be associated with a target route using route bindings in the app. +Now let's assume that we want to link from the Catalog entities list page to the Scaffolder create component page. We don't want to reference the Scaffolder plugin directly, since that would create an unnecessary dependency. It would also provided little flexibility in allowing the app to tie plugins together, with the links instead being dictated by the plugins themselves. To solve this, we use an `ExternalRouteRef`. Much like regular route references, they can be passed to `useRouteRef` to create concrete URLs, but they can not be used in page extensions and instead have to be associated with a target route using route bindings in the app. We create a new `RouteRef` inside the Scaffolder plugin, using a neutral name that describes its role in the plugin rather than a specific plugin page that it might be linking to, allowing the app to decide the final target. If the Catalog entity list page for example wants to link the Scaffolder create component page in the header, it might declare an `ExternalRouteRef` similar to this: @@ -209,39 +212,67 @@ import { createExternalRouteRef, } from '@backstage/frontend-plugin-api'; -const indexRouteRef = createRouteRef(); -const createComponentRouteRef = createExternalRouteRef(); +export const indexRouteRef = createRouteRef(); +export const detailsRouteRef = createRouteRef({ + // The parameters that must be included in the path of this route reference + params: ['kind', 'namespace', 'name'], +}); +export const createComponentRouteRef = createExternalRouteRef(); // plugins/catalog/src/plugin.tsx import React from 'react'; import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; -import { indexRouteRef, createComponentRouteRef } from './routes'; +import { indexRouteRef, detailsRouteRef, createComponentRouteRef } from './routes'; -const indexPage = createPageExtension({ +const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, loader: async () => { - const href = useRouteRef(createComponentRouteRef)(); + const createComponentLink = useRouteRef(createComponentRouteRef); return (
-

Catalog Entities

+

Index Page

{/* Linking to a create component page without direct reference */} - Create Component + Create Component
); } }); +const catalogDetailsPage = createPageExtension({ + name: 'details', + defaultPath: '/entities/:namespace/:kind/:name', + routeRef: detailsRouteRef, + loader: async () => { + const Component = () => { + // Getting the parameters from the URL + const params = useParams(); + return ( +
+

Details Page

+
    +
  • Kind: {params.kind}
  • +
  • Namespace: {params.namespace}
  • +
  • Name: {params.name}
  • +
+
+ ); + }; + return ; + }, +}); + export default createPlugin({ id: 'catalog', routes: { index: indexRouteRef, + details: detailsRouteRef, } externalRoutes: { createComponent: createComponentRouteRef, }, - extensions: [indexPage] + extensions: [catalogIndexPage] }); // plugins/catalog/src/index.ts @@ -254,7 +285,7 @@ _Scaffolder Plugin_ // plugins/scaffolder/src/routes.ts import { createRouteRef } from '@backstage/frontend-plugin-api'; -const indexRouteRef = createRouteRef(); +export const indexRouteRef = createRouteRef(); // plugins/scaffolder/src/plugin.tsx import React from 'react'; @@ -264,7 +295,7 @@ import { } from '@backstage/frontend-plugin-api'; import { indexRouteRef } from './routes'; -const indexPage = createPageExtension({ +const scaffolderIndexPage = createPageExtension({ defaultPath: '/create', routeRef: indexRouteRef, loader: async () => ( @@ -279,14 +310,62 @@ export default createPlugin({ routes: { index: indexRouteRef, }, - extensions: [indexPage], + extensions: [scaffolderIndexPage], }); // plugins/scaffolder/src/index.ts export { default } from './plugin'; ``` -Now let's move on and configure the app to point to the Scaffolder create component page when the catalog create component ref be used. +One last thing is that external routes can also be parametrize, so if Scaffolder wants to redirect to the Catalog entity details page whenever a new component is created, the Scaffolder plugin can also expose a external route like this: + +```ts +// plugins/scaffolder/src/routes.ts +import { + createRouteRef, + createExternalRouteRef, +} from '@backstage/frontend-plugin-api'; + +export const indexRouteRef = createRouteRef(); +export const entityDetailsExternalRouteRef = createExternalRouteRef({ + // The parameters that must be included in the path of this route reference + params: ['kind', 'namespace', 'name'], +}); + +// plugins/scaffolder/src/plugin.tsx +import React from 'react'; +import { + createPlugin, + createPageExtension, +} from '@backstage/frontend-plugin-api'; +import { indexRouteRef, entityDetailsExternalRouteRef } from './routes'; + +const scaffolderIndexPage = createPageExtension({ + defaultPath: '/create', + routeRef: indexRouteRef, + loader: async () => ( +
+

Create Component

+
+ ), +}); + +export default createPlugin({ + id: 'scaffolder', + routes: { + index: indexRouteRef, + }, + externalRoutes: { + entityDetails: entityDetailsExternalRouteRef, + }, + extensions: [scaffolderIndexPage], +}); + +// plugins/scaffolder/src/index.ts +export { default } from './plugin'; +``` + +Now let's move on and configure the app to point to the Scaffolder create component page when the Catalog create component ref be used and also to poin to the Catalog entity details page when the Scaffolder entity details ref be used. ### Binding External Route References @@ -300,6 +379,7 @@ app: routes: bindings: plugin.catalog.externalRoutes.createComponent: plugin.scaffolder.routes.index + plugin.scaffolder.externalRoutes.entityDetails: plugin.catalog.routes.details ``` Or via code, in the file where the app is created: @@ -315,6 +395,9 @@ const app = createApp({ bind(catalog.externalRoutes, { createComponent: scaffolder.routes.createComponent, }); + bind(scaffolder.externalRoutes, { + entityDetails: catalog.routes.details, + }); }, }); @@ -325,11 +408,11 @@ Given the above binding, using `useRouteRef(createComponentRouteRef)` within the Note that we are not importing and using the `RouteRef`s directly in the app, and instead rely on the plugin instance to access routes of the plugins. This is a new convention that was introduced to provide better namespacing and discoverability of routes, as well as reduce the number of separate exports from each plugin package. -Another thing to note is that this indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. For plugins that you build internally for your own Backstage application, you can choose to go the route of direct imports or even use concrete routes directly. Although there can be some benefits to using the full routing system even in internal plugins. It can help you structure your routes, and as you will see further down it also helps you manage route parameters.parameters. +Another thing to note is that this indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. For plugins that you build internally for your own Backstage application, you can choose to go the route of direct imports or even use concrete routes directly. Although there can be some benefits to using the full routing system even in internal plugins. It can help you structure your routes, and as you will see further down it also helps you manage route parameters. ### Optional External Route References -It is possible to define an `ExternalRouteRef` as optional, so it is not required to bind it in the app. When calling `useRouteRef` with an optional external route, its return signature is changed to `RouteFunc | undefined`, and the returned value can be used used to decide whether a certain link should be displayed or if an action should be taken: +It is possible to define an `ExternalRouteRef` as optional, so it is not required to bind it in the app. When calling `useRouteRef` with an optional external route, its return signature is changed to `RouteFunc | undefined`, and the returned value can be used to decide whether a certain link should be displayed or if an action should be taken: ```tsx // plugins/catalog/src/routes.ts @@ -338,8 +421,8 @@ import { createExternalRouteRef, } from '@backstage/frontend-plugin-api'; -const indexRouteRef = createRouteRef(); -const createComponentRouteRef = createExternalRouteRef({ +export const indexRouteRef = createRouteRef(); +export const createComponentRouteRef = createExternalRouteRef({ optional: true, }); @@ -352,17 +435,17 @@ import { } from '@backstage/frontend-plugin-api'; import { indexRouteRef, createComponentRouteRef } from './routes'; -const indexPage = createPageExtension({ +const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, loader: async () => { - const link = useRouteRef(createComponentRouteRef); + const createComponentLink = useRouteRef(createComponentRouteRef); return (
-

Catalog Entities

+

Index Page

{/* Since the route is optional, rendering the link only if the href is defined */} - {link && Create Component} + {link && Create Component}
); }, @@ -376,7 +459,7 @@ export default createPlugin({ externalRoutes: { createComponent: createComponentRouteRef, }, - extensions: [indexPage], + extensions: [catalogIndexPage], }); // index.ts @@ -396,8 +479,8 @@ import { createSubRouteRef, } from '@backstage/frontend-plugin-api'; -const indexRouteRef = createRouteRef(); -const detailsSubRouteRef = createSubRouteRef({ +export const indexRouteRef = createRouteRef(); +export const detailsSubRouteRef = createSubRouteRef({ parent: indexRouteRef, path: '/details', }); @@ -418,22 +501,22 @@ const DetailsPage = () => (
); -const indexPage = createPageExtension({ +const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, loader: async () => { const Component = () => { const { pathname } = useLocation(); - const indexPath = useRouteRef(indexRouteRef)(); - const detailsPath = useRouteRef(detailsSubRouteRef)(); + const indexLink = useRouteRef(indexRouteRef); + const detailsLink = useRouteRef(detailsSubRouteRef); return (

Index Page

{/* Linking to the index route */} - {pathname === detailsPath && Hide details} + {pathname === detailsLink() && Hide details} {/* Linking to the details sub route */} - {pathname === indexPath && Show details} + {pathname === indexLink() && Show details} {/* Registering the details sub route */} } /> @@ -452,7 +535,7 @@ export default createPlugin({ index: indexRouteRef, details: detailsSubRouteRef, }, - extensions: [indexPage], + extensions: [catalogIndexPage], }); // plugins/catalog/src/index.ts @@ -468,8 +551,8 @@ import { createSubRouteRef, } from '@backstage/frontend-plugin-api'; -const indexRouteRef = createRouteRef(); -const detailsSubRouteRef = createSubRouteRef({ +export const indexRouteRef = createRouteRef(); +export const detailsSubRouteRef = createSubRouteRef({ parent: indexRouteRef, path: '/:name/:namespace/:kind', }); @@ -499,14 +582,17 @@ const DetailsPage = () => { ); }; -const indexPage = createPageExtension({ +const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, loader: async () => { const Component = () => { const { pathname } = useLocation(); - const indexPath = useRouteRef(indexRouteRef)(); - const detailsPath = useRouteRef(detailsSubRouteRef)({ + const indexLink = useRouteRef(indexRouteRef)(); + const detailsLink = useRouteRef(detailsSubRouteRef); + + const indexPath = indexLink(); + const detailsPath = detailsLink({ // Setting the details subroute params kind: 'component', namespace: 'default', @@ -557,7 +643,7 @@ export default createPlugin({ index: indexRouteRef, details: detailsSubRouteRef, }, - extensions: [indexPage], + extensions: [catalogIndexPage], }); // plugins/catalog/src/index.ts From 07a79c695c147b2361dbcad62379083fc1927d74 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 10:32:54 +0100 Subject: [PATCH 148/241] docs(frontend-system): use promise resolve on the route examples Signed-off-by: Camila Belo --- .../frontend-system/architecture/07-routes.md | 149 +++++++++++------- 1 file changed, 96 insertions(+), 53 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 0fe2a8cc85..723649d7af 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -41,7 +41,7 @@ Note that you almost always want to create the route references themselves in a Route refs do not have any behavior, in other words, they are an opaque type that represents route targets in an app, which are bound to specific paths at runtime, but they provide a level of indirection to help mix together different plugins that otherwise wouldn't know how to route to each other. -The code snippet of the previous section does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension. When this extension is installed in the app it will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the the extension. Here's what we need to do: +The previous section code snippet does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension. When this extension is installed in the app it will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the extension. Here's what we need to do: ```tsx // plugins/catalog/src/routes.ts @@ -62,7 +62,8 @@ const catalogIndexPage = createPageExtension({ // [2] defaultPath: '/entities', routeRef: indexRouteRef, - loader: async () =>
Index Page
, + // Promise.resolve is a replacement for `import(...)` + loader: () => Promise.resolve(
Index Page
), }); export default createPlugin({ @@ -88,7 +89,7 @@ It may be unclear why we need to pass the route to the plugin once it has alread ### Route Path Parameters -The referenced route can also accepts `params`. Here is how you create a reference for a route that requires a `kind`, `namespace` and `name` params, like in this path `/entities/:kind/:namespace/:name`: +The referenced route can also accepts `params`. Here is how you create a reference for a route that requires a kind, namespace and name `params`, like in this path `/entities/:kind/:namespace/:name`: ```tsx // plugins/catalog/src/routes.ts @@ -136,7 +137,7 @@ import { rootRouteRef, detailsRouteRef } from './routes'; const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, - loader: async () => { + loader: () => { const Component = () => { const detailsLink = useRouteRef(detailsRouteRef); const detailsPath = detailsLink({ @@ -153,7 +154,7 @@ const catalogIndexPage = createPageExtension({ ); }; - return ; + return Promise.resolve(); }, }); @@ -163,7 +164,7 @@ const catalogDetailsPage = createPageExtension({ // It will be their responsibility to make sure that it contains the same parameters, although they don't necessarily need to be in the same order. defaultPath: '/entities/:namespace/:kind/:name', routeRef: detailsRouteRef, - loader: async () => { + loader: () => { const Component = () => { // Getting the parameters from the URL const params = useParams(); @@ -178,7 +179,8 @@ const catalogDetailsPage = createPageExtension({
); }; - return ; + + return Promise.resolve(); }, }); @@ -221,30 +223,42 @@ export const createComponentRouteRef = createExternalRouteRef(); // plugins/catalog/src/plugin.tsx import React from 'react'; -import { createPlugin, createPageExtension, useRouteRef } from '@backstage/frontend-plugin-api'; -import { indexRouteRef, detailsRouteRef, createComponentRouteRef } from './routes'; +import { + createPlugin, + createPageExtension, + useRouteRef, +} from '@backstage/frontend-plugin-api'; +import { + indexRouteRef, + detailsRouteRef, + createComponentRouteRef, +} from './routes'; const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, - loader: async () => { - const createComponentLink = useRouteRef(createComponentRouteRef); + loader: () => { + const Component = () => { + const createComponentLink = useRouteRef(createComponentRouteRef); - return ( -
-

Index Page

- {/* Linking to a create component page without direct reference */} - Create Component -
- ); - } + return ( +
+

Index Page

+ {/* Linking to a create component page without direct reference */} + Create Component +
+ ); + }; + + return Promise.resolve(); + }, }); const catalogDetailsPage = createPageExtension({ name: 'details', defaultPath: '/entities/:namespace/:kind/:name', routeRef: detailsRouteRef, - loader: async () => { + loader: () => { const Component = () => { // Getting the parameters from the URL const params = useParams(); @@ -259,7 +273,8 @@ const catalogDetailsPage = createPageExtension({
); }; - return ; + + return Promise.resolve(); }, }); @@ -268,11 +283,11 @@ export default createPlugin({ routes: { index: indexRouteRef, details: detailsRouteRef, - } + }, externalRoutes: { createComponent: createComponentRouteRef, }, - extensions: [catalogIndexPage] + extensions: [catalogIndexPage, catalogDetailsPage], }); // plugins/catalog/src/index.ts @@ -298,11 +313,12 @@ import { indexRouteRef } from './routes'; const scaffolderIndexPage = createPageExtension({ defaultPath: '/create', routeRef: indexRouteRef, - loader: async () => ( -
-

Create Component

-
- ), + loader: () => + Promise.resolve( +
+

Create Component

+
, + ), }); export default createPlugin({ @@ -317,7 +333,7 @@ export default createPlugin({ export { default } from './plugin'; ``` -One last thing is that external routes can also be parametrize, so if Scaffolder wants to redirect to the Catalog entity details page whenever a new component is created, the Scaffolder plugin can also expose a external route like this: +The Scaffolder plugin can also expose an external route that redirects to the Catalog entity details page whenever a new component is created, such as: ```ts // plugins/scaffolder/src/routes.ts @@ -327,7 +343,7 @@ import { } from '@backstage/frontend-plugin-api'; export const indexRouteRef = createRouteRef(); -export const entityDetailsExternalRouteRef = createExternalRouteRef({ +export const componentDetailsExternalRouteRef = createExternalRouteRef({ // The parameters that must be included in the path of this route reference params: ['kind', 'namespace', 'name'], }); @@ -337,17 +353,37 @@ import React from 'react'; import { createPlugin, createPageExtension, + useRouteRef, } from '@backstage/frontend-plugin-api'; -import { indexRouteRef, entityDetailsExternalRouteRef } from './routes'; +import { indexRouteRef, componentDetailsExternalRouteRef } from './routes'; const scaffolderIndexPage = createPageExtension({ defaultPath: '/create', routeRef: indexRouteRef, - loader: async () => ( -
-

Create Component

-
- ), + loader: () => { + const Component = () => { + const componentDetailsLink = useRouteRef( + componentDetailsExternalRouteRef, + ); + + return ( +
+

Create Component

+ + See component details + +
+ ); + }; + + return Promise.resolve(); + }, }); export default createPlugin({ @@ -356,7 +392,7 @@ export default createPlugin({ index: indexRouteRef, }, externalRoutes: { - entityDetails: entityDetailsExternalRouteRef, + componentDetails: componentDetailsExternalRouteRef, }, extensions: [scaffolderIndexPage], }); @@ -365,7 +401,8 @@ export default createPlugin({ export { default } from './plugin'; ``` -Now let's move on and configure the app to point to the Scaffolder create component page when the Catalog create component ref be used and also to poin to the Catalog entity details page when the Scaffolder entity details ref be used. +Note that external routes can also have path parameters! +Now let's move on and configure the app to point to the Scaffolder create component page when the Catalog create component ref be used and also point to the Catalog entity details page when the Scaffolder component details ref be used. ### Binding External Route References @@ -378,8 +415,10 @@ Using the above example of the Catalog entities list page to the Scaffolder crea app: routes: bindings: + # point to the Scaffolder create component page when the Catalog create component ref be used plugin.catalog.externalRoutes.createComponent: plugin.scaffolder.routes.index - plugin.scaffolder.externalRoutes.entityDetails: plugin.catalog.routes.details + # point to the Catalog details page when the Scaffolder component details ref be used + plugin.scaffolder.externalRoutes.componentDetails: plugin.catalog.routes.details ``` Or via code, in the file where the app is created: @@ -396,7 +435,7 @@ const app = createApp({ createComponent: scaffolder.routes.createComponent, }); bind(scaffolder.externalRoutes, { - entityDetails: catalog.routes.details, + componentDetails: catalog.routes.details, }); }, }); @@ -438,16 +477,20 @@ import { indexRouteRef, createComponentRouteRef } from './routes'; const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, - loader: async () => { - const createComponentLink = useRouteRef(createComponentRouteRef); + loader: () => { + const Component = () => { + const createComponentLink = useRouteRef(createComponentRouteRef); - return ( -
-

Index Page

- {/* Since the route is optional, rendering the link only if the href is defined */} - {link && Create Component} -
- ); + return ( +
+

Index Page

+ {/* Since the route is optional, rendering the link only if the href is defined */} + {link && Create Component} +
+ ); + }; + + return Promise.resolve(); }, }); @@ -504,7 +547,7 @@ const DetailsPage = () => ( const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, - loader: async () => { + loader: () => { const Component = () => { const { pathname } = useLocation(); const indexLink = useRouteRef(indexRouteRef); @@ -525,7 +568,7 @@ const catalogIndexPage = createPageExtension({ ); }; - return ; + return Promise.resolve(); }, }); @@ -585,7 +628,7 @@ const DetailsPage = () => { const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, - loader: async () => { + loader: () => { const Component = () => { const { pathname } = useLocation(); const indexLink = useRouteRef(indexRouteRef)(); @@ -633,7 +676,7 @@ const catalogIndexPage = createPageExtension({ ); }; - return ; + return Promise.resolve(); }, }); From 93fd34024280f612b11e024dc5bedc3ca06e44dc Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 14:24:44 +0100 Subject: [PATCH 149/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 723649d7af..305e200a24 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -18,7 +18,7 @@ The frontend system isn't a single API surface. It is a collection of patterns, ## Route References -In order to address the problem outlined above, we introduced the concept of route references. A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at instance level (by application integrators). +In order to address the problem outlined above, we introduced the concept of route references. A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sessions). From c16323db068dd05f8f1c8d38e7fe29fb6da73c15 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 14:24:52 +0100 Subject: [PATCH 150/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 305e200a24..ea839f27b4 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -20,7 +20,7 @@ The frontend system isn't a single API surface. It is a collection of patterns, In order to address the problem outlined above, we introduced the concept of route references. A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). -Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sessions). +Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sections). There are 3 types of route references: regular route, sub route, and external route, and we will cover both the concept and code definition for each. Keep reading 🙂! From ef87f165992be5a21dcaa056b4ad327a7832e94b Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 14:25:43 +0100 Subject: [PATCH 151/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index ea839f27b4..4b8b98a3e7 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -26,7 +26,7 @@ There are 3 types of route references: regular route, sub route, and external ro ### Creating a Route Reference -Route references, also known as plugins' index pages or regular routes, are created as follows: +Route references, also known as "absolute" or "regular" routes, are created as follows: ```tsx // plugins/catalog/src/routes.ts From ed670cec063f9ab7eaf5349b6113836f8670b08e Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 14:25:58 +0100 Subject: [PATCH 152/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 4b8b98a3e7..15bfe615ac 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -445,7 +445,7 @@ export default app.createRoot(); Given the above binding, using `useRouteRef(createComponentRouteRef)` within the Catalog plugin will let us create a link to whatever path the Scaffolder create component page is mounted at. -Note that we are not importing and using the `RouteRef`s directly in the app, and instead rely on the plugin instance to access routes of the plugins. This is a new convention that was introduced to provide better namespacing and discoverability of routes, as well as reduce the number of separate exports from each plugin package. +Note that we are not importing and using the `RouteRef`s directly in the app, and instead rely on the plugin instance to access routes of the plugins. This provides better namespacing and discoverability of routes, as well as reduce the number of separate exports from each plugin package. Another thing to note is that this indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. For plugins that you build internally for your own Backstage application, you can choose to go the route of direct imports or even use concrete routes directly. Although there can be some benefits to using the full routing system even in internal plugins. It can help you structure your routes, and as you will see further down it also helps you manage route parameters. From fa379b6333b60a7bd3987d70109f1c77f5562539 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:12:43 +0100 Subject: [PATCH 153/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 15bfe615ac..2f8d3a5b7a 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -421,7 +421,7 @@ app: plugin.scaffolder.externalRoutes.componentDetails: plugin.catalog.routes.details ``` -Or via code, in the file where the app is created: +We also have the ability to express this in code as an option to `createApp`, but you of course only need to use one of these two methods: ```tsx // packages/app/src/App.tsx From 6f4fbb06ea9d473c6ef697e75571918e4f16b198 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:50:48 +0100 Subject: [PATCH 154/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 2f8d3a5b7a..4dd06ffb90 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -35,7 +35,7 @@ import { createRouteRef } from '@backstage/frontend-plugin-api'; export const indexRouteRef = createRouteRef(); ``` -Note that you almost always want to create the route references themselves in a different file than the one that creates the plugin instance, for example a top-level routes.ts. This is to avoid circular imports when you use the route references from other parts of the same plugin. +Note that you often want to create the route references themselves in a different file than the one that creates the plugin instance, for example a top-level routes.ts. This is to avoid circular imports when you use the route references from other parts of the same plugin. ### Providing Route References to Plugins From 1c7ca6f643ab389e2f601c63eb9c04b6956b2175 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:51:10 +0100 Subject: [PATCH 155/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 4dd06ffb90..99438dc868 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -39,7 +39,7 @@ Note that you often want to create the route references themselves in a differen ### Providing Route References to Plugins -Route refs do not have any behavior, in other words, they are an opaque type that represents route targets in an app, which are bound to specific paths at runtime, but they provide a level of indirection to help mix together different plugins that otherwise wouldn't know how to route to each other. +Route refs do not have any behavior themselves. They are an opaque value that represents route targets in an app, which are bound to specific paths at runtime. Their role is to provide a level of indirection to help link together different pages that otherwise wouldn't know how to route to each other. The previous section code snippet does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension. When this extension is installed in the app it will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the extension. Here's what we need to do: From 88cf8a665ea82f60987b9e84e0c8367d644a8afe Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:51:56 +0100 Subject: [PATCH 156/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 99438dc868..efdebaebd0 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -85,7 +85,7 @@ We have completed our journey of creating a plugin page route. This is what the - [2] We associate our route reference with our page by providing it as an option during creation of the page extension. - [3] Finally, our plugin provides both routes and extensions. -It may be unclear why we need to pass the route to the plugin once it has already been passed to the extension, but the explanation can be found in the (Binding External Route References)[#building-external-route-references] section, wait a bit, keep reading and you'll understand why. +It may be unclear why we need to pass the route to the plugin when it has already been passed to the extension. We do that to make it possible for other plugins to route to our page, which is explained in detail in the (Binding External Route References)[#building-external-route-references] section. ### Route Path Parameters From c01052ec3278f349c600c3486fca454efd29b00d Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:52:16 +0100 Subject: [PATCH 157/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index efdebaebd0..b069743ef9 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -89,7 +89,7 @@ It may be unclear why we need to pass the route to the plugin when it has alread ### Route Path Parameters -The referenced route can also accepts `params`. Here is how you create a reference for a route that requires a kind, namespace and name `params`, like in this path `/entities/:kind/:namespace/:name`: +Route references optionally accept a `params` option, which will require the listed parameter names to be present in the route path. Here is how you create a reference for a route that requires a `kind`, `namespace` and `name` parameters, like in this path `/entities/:kind/:namespace/:name`: ```tsx // plugins/catalog/src/routes.ts From 6d88c626c0667109001582328d279363506bac52 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:52:32 +0100 Subject: [PATCH 158/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index b069743ef9..b4e562aca9 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -103,7 +103,7 @@ export const detailsRouteRef = createRouteRef({ ### Using a Route Reference -You can link to the routes from other pages in the same plugin or you can also link between different plugins pages. In this section we will cover the first scenario, if you are interested in link to a page of a different plugin, please go to the [external routes](#external-router-references) section below. +Route references can be used to link to page in the same plugin, or to pages in a different plugins. In this section we will cover the first scenario, if you are interested in link to a page of a different plugin, please go to the [external routes](#external-router-references) section below. Alright, let's presume that we have a plugin that renders two different pages, and these pages link to each other. From e083d88a23256e7cfccc10491f598902f4c526e3 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:52:58 +0100 Subject: [PATCH 159/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index b4e562aca9..3e8c29ddfb 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -105,7 +105,7 @@ export const detailsRouteRef = createRouteRef({ Route references can be used to link to page in the same plugin, or to pages in a different plugins. In this section we will cover the first scenario, if you are interested in link to a page of a different plugin, please go to the [external routes](#external-router-references) section below. -Alright, let's presume that we have a plugin that renders two different pages, and these pages link to each other. +Let's presume that we have a plugin that renders two different pages, and these pages link to each other. First lets create the routes references: From 513919d2669b0c8a30985194f1f340250ab3f47e Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:54:06 +0100 Subject: [PATCH 160/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 3e8c29ddfb..a07df23d70 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -402,7 +402,7 @@ export { default } from './plugin'; ``` Note that external routes can also have path parameters! -Now let's move on and configure the app to point to the Scaffolder create component page when the Catalog create component ref be used and also point to the Catalog entity details page when the Scaffolder component details ref be used. +Now let's move on and configure the app to resolve these external routes, so that the Scaffolder links to the Catalog entity page, and the Catalog links to the Scaffolder page. ### Binding External Route References From 9487a419139fbbdb79302fff1e42ee2eb40c6260 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:55:12 +0100 Subject: [PATCH 161/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index a07df23d70..c1fd424ae3 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -415,9 +415,9 @@ Using the above example of the Catalog entities list page to the Scaffolder crea app: routes: bindings: - # point to the Scaffolder create component page when the Catalog create component ref be used + # point to the Scaffolder create component page when the Catalog create component ref is used plugin.catalog.externalRoutes.createComponent: plugin.scaffolder.routes.index - # point to the Catalog details page when the Scaffolder component details ref be used + # point to the Catalog details page when the Scaffolder component details ref is used plugin.scaffolder.externalRoutes.componentDetails: plugin.catalog.routes.details ``` From 9f949e27ba57cb86d71a6ca6f1bb4c625aced087 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 17:03:22 +0100 Subject: [PATCH 162/241] docs(routing): try to reduce code snippets Signed-off-by: Camila Belo --- .../frontend-system/architecture/07-routes.md | 664 +++++------------- 1 file changed, 191 insertions(+), 473 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index c1fd424ae3..0aa6980713 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -10,46 +10,38 @@ description: Frontend routes ## Introduction -This page describes the frontend system that helps bring together content from a multitude of plugins into one Backstage application. +In Backstage, plug-in boundaries and connections must be clearly defined. The app should allow navigation between plug-ins while isolating faults within them. -The core principle of the frontend system is that plugins should have clear boundaries and connections. It should isolate crashes within a plugin, but allow navigation between them. It should allow for plugins to be loaded only when needed, and enable plugins to provide extension points for other plugins to build upon. The frontend system is also built with an app-first mindset, prioritizing simplicity and clarity in the app over that in the plugins and core APIs. - -The frontend system isn't a single API surface. It is a collection of patterns, primitives, and APIs. At the core is the concept of extensions, which are exported by plugins for use in the app. One of the concepts is `RouteRef` which enables us route between pages in a flexible way, and it is especially important when bringing together different open source plugins. +In order to address the problem outlined above, we introduced the concept of `RouteRef` which enables us route between pages in a flexible way, and it is especially important when bringing together different open source plugins. ## Route References -In order to address the problem outlined above, we introduced the concept of route references. A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). +A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sections). -There are 3 types of route references: regular route, sub route, and external route, and we will cover both the concept and code definition for each. Keep reading 🙂! +There are 3 types of route references: regular route, sub route, and external route, and we will cover both the concept and code definition for each. ### Creating a Route Reference Route references, also known as "absolute" or "regular" routes, are created as follows: -```tsx -// plugins/catalog/src/routes.ts +```tsx title="plugins/catalog/src/routes.ts" showLineNumbers import { createRouteRef } from '@backstage/frontend-plugin-api'; +// Creates a route reference, which is not yet associated with any plugin page export const indexRouteRef = createRouteRef(); ``` Note that you often want to create the route references themselves in a different file than the one that creates the plugin instance, for example a top-level routes.ts. This is to avoid circular imports when you use the route references from other parts of the same plugin. -### Providing Route References to Plugins - Route refs do not have any behavior themselves. They are an opaque value that represents route targets in an app, which are bound to specific paths at runtime. Their role is to provide a level of indirection to help link together different pages that otherwise wouldn't know how to route to each other. -The previous section code snippet does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension. When this extension is installed in the app it will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the extension. Here's what we need to do: +### Providing Route References to Plugins -```tsx -// plugins/catalog/src/routes.ts -import { createRouteRef } from '@backstage/frontend-plugin-api'; +The previous section code snippet does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension: -export const indexRouteRef = createRouteRef(); // [1] - -// plugins/catalog/src/plugin.tsx +```tsx title="plugins/catalog/src/plugin.tsx" {11,17-19} showLineNumbers import React from 'react'; import { createPlugin, @@ -57,42 +49,36 @@ import { } from '@backstage/frontend-plugin-api'; import { indexRouteRef } from './routes'; -// The `name` option is omitted since this is the index page const catalogIndexPage = createPageExtension({ - // [2] + // The `name` option is omitted because this is an index page defaultPath: '/entities', routeRef: indexRouteRef, - // Promise.resolve is a replacement for `import(...)` - loader: () => Promise.resolve(
Index Page
), + loader: () => import('./components').then(m => ), }); export default createPlugin({ - // [3] id: 'catalog', routes: { index: indexRouteRef, }, extensions: [catalogIndexPage], }); - -// plugins/catalog/src/index.ts -export { default } from './plugin'; ``` -We have completed our journey of creating a plugin page route. This is what the code does: +In the example above we have associated a route ref with an plugin page. This is what the code does: -- [1] The line 1 creates a route reference, which is not yet associated with any plugin page; -- [2] We associate our route reference with our page by providing it as an option during creation of the page extension. -- [3] Finally, our plugin provides both routes and extensions. +- Line 11: Associates the `indexRouteRef` with the `catalogIndexPage` extension; +- Line 17 to 19: Provides both the `indexRouteRef` and `catalogIndexPage` via the Catalog plugin. -It may be unclear why we need to pass the route to the plugin when it has already been passed to the extension. We do that to make it possible for other plugins to route to our page, which is explained in detail in the (Binding External Route References)[#building-external-route-references] section. +When this extension is installed in the app it will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the extension. -### Route Path Parameters +It may be unclear why we configure the routes option when creating a plugin as the route has already been passed to the extension. We do that to make it possible for other plugins to route to our page, which is explained in detail in the [binding routes](#binding-external-route-references) section. + +### Defining References with Path Parameters Route references optionally accept a `params` option, which will require the listed parameter names to be present in the route path. Here is how you create a reference for a route that requires a `kind`, `namespace` and `name` parameters, like in this path `/entities/:kind/:namespace/:name`: -```tsx -// plugins/catalog/src/routes.ts +```tsx title="plugins/catalog/src/routes.ts" {5} showLineNumbers import { createRouteRef } from '@backstage/frontend-plugin-api'; export const detailsRouteRef = createRouteRef({ @@ -105,303 +91,134 @@ export const detailsRouteRef = createRouteRef({ Route references can be used to link to page in the same plugin, or to pages in a different plugins. In this section we will cover the first scenario, if you are interested in link to a page of a different plugin, please go to the [external routes](#external-router-references) section below. -Let's presume that we have a plugin that renders two different pages, and these pages link to each other. +Suppose we are creating a plugin that renders a Catalog index page with a link to a "Foo" component details page. Here is the code for the index page: -First lets create the routes references: - -```tsx -// plugins/catalog/src/routes.ts -import { createRouteRef } from '@backstage/frontend-plugin-api'; - -export const indexRouteRef = createRouteRef(); - -export const detailsRouteRef = createRouteRef({ - // The parameters that must be included in the path of this route reference - params: ['kind', 'namespace', 'name'], -}); -``` - -Now we are ready to provide these routes via plugin extensions and link between pages: - -```tsx -// plugins/catalog/src/plugin.tsx +```tsx title="plugins/catalog/src/components/IndexPage.tsx" {6,11-15} showLineNumbers import React from 'react'; -import { useParams } from 'react-router'; -import { - createPlugin, - createPageExtension, - useRouteRef, -} from '@backstage/frontend-plugin-api'; -import { rootRouteRef, detailsRouteRef } from './routes'; +import { useRouteRef } from '@backstage/frontend-plugin-api'; +import { detailsRouteRef } from '../routes'; -const catalogIndexPage = createPageExtension({ - defaultPath: '/entities', - routeRef: indexRouteRef, - loader: () => { - const Component = () => { - const detailsLink = useRouteRef(detailsRouteRef); - const detailsPath = detailsLink({ - kind: 'component', - namespace: 'default', - name: 'foo', - }); - - return ( -
-

Index Page

- See details -
- ); - }; - - return Promise.resolve(); - }, -}); - -const catalogDetailsPage = createPageExtension({ - name: 'details', - // It is important to mention here if an integrator configures a different path for this page via config file - // It will be their responsibility to make sure that it contains the same parameters, although they don't necessarily need to be in the same order. - defaultPath: '/entities/:namespace/:kind/:name', - routeRef: detailsRouteRef, - loader: () => { - const Component = () => { - // Getting the parameters from the URL - const params = useParams(); - return ( -
-

Details Page

-
    -
  • Kind: {params.kind}
  • -
  • Namespace: {params.namespace}
  • -
  • Name: {params.name}
  • -
-
- ); - }; - - return Promise.resolve(); - }, -}); - -export default createPlugin({ - id: 'catalog', - routes: { - index: indexRouteRef, - details: detailsRouteRef, - }, - extensions: [catalogIndexPage, catalogDetailsPage], -}); - -// plugins/catalog/src/index.ts -export { default } from './plugin'; +export const IndexPage = () => { + const getDetailsPath = useRouteRef(detailsRouteRef); + return ( +
+

Index Page

+ + See "Foo" details + +
+ ); +}; ``` -During runtime, in the index page, we used a hook `useRouteRef` to get the path to the details page. Because we are linking to pages of the same plugin, we are currently accessing the reference directly, but in the following sections, you will see how to link to pages of different plugins. +Line 6 uses a hook called `useRouteRef` to access a getter function that returns the details page path. On line 11, we call the getter, passing it an object with the kind, namespace, and name. These parameters are used to construct a concrete path to details the "Foo" details page. + +Let's see how the details page can get the parameters from the URL: + +```tsx title="plugins/catalog/src/components/DetailsPage.tsx" {6,11-13} showLineNumbers +import React from 'react'; +import { useRouteRefParams } from '@backstage/frontend-plugin-api'; +import { detailsRouteRef } from '../routes'; + +export const DetailsPage = () => { + const params = useRouteRefParams(detailsRouteRef); + return ( +
+

Details Page

+
    +
  • Kind: {params.kind}
  • +
  • Namespace: {params.namespace}
  • +
  • Name: {params.name}
  • +
+
+ ); +}; +``` + +On line 6, we are using the `useRouteRefParams` hook to retrieve the entity-composed id from the URL. The parameter object contains three values: kind, namespace, and name. We can display these values or call an API using them. + +Since we are linking to pages of the same package, we are using a route ref directly. However, in the following sections, you will see how to link to pages of different plugins. ## External Router References -Now let's assume that we want to link from the Catalog entities list page to the Scaffolder create component page. We don't want to reference the Scaffolder plugin directly, since that would create an unnecessary dependency. It would also provided little flexibility in allowing the app to tie plugins together, with the links instead being dictated by the plugins themselves. To solve this, we use an `ExternalRouteRef`. Much like regular route references, they can be passed to `useRouteRef` to create concrete URLs, but they can not be used in page extensions and instead have to be associated with a target route using route bindings in the app. +External routes are made for linking to a page of an external plugin. +For this section example, let's assume that we want to link from the Catalog entities list page to the Scaffolder create component page. + +We don't want to reference the Scaffolder plugin directly, since that would create an unnecessary dependency. It would also provided little flexibility in allowing the app to tie plugins together, with the links instead being dictated by the plugins themselves. To solve this, we use an `ExternalRouteRef`. Much like regular route references, they can be passed to `useRouteRef` to create concrete URLs, but they can not be used in page extensions and instead have to be associated with a target route using route bindings in the app. We create a new `RouteRef` inside the Scaffolder plugin, using a neutral name that describes its role in the plugin rather than a specific plugin page that it might be linking to, allowing the app to decide the final target. If the Catalog entity list page for example wants to link the Scaffolder create component page in the header, it might declare an `ExternalRouteRef` similar to this: -_Catalog Plugin_ +```tsx title="plugins/catalog/src/routes.ts" showLineNumbers +import { createExternalRouteRef } from '@backstage/frontend-plugin-api'; -```tsx -// plugins/catalog/src/routes.ts -import { - createRouteRef, - createExternalRouteRef, -} from '@backstage/frontend-plugin-api'; +export const createComponentExternalRouteRef = createExternalRouteRef(); +``` -export const indexRouteRef = createRouteRef(); -export const detailsRouteRef = createRouteRef({ - // The parameters that must be included in the path of this route reference - params: ['kind', 'namespace', 'name'], -}); -export const createComponentRouteRef = createExternalRouteRef(); +External routes are also used in a similar way as regular routes: -// plugins/catalog/src/plugin.tsx +```tsx title="plugins/catalog/src/components/IndexPage.tsx" {6,10} showLineNumbers +import React from 'react'; +import { useRouteRef } from '@backstage/frontend-plugin-api'; +import { createComponentExternalRouteRef } from '../routes'; + +export const IndexPage = () => { + const getCreateComponentPath = useRouteRef(createComponentExternalRouteRef); + return ( +
+

Index Page

+ Create Component +
+ ); +}; +``` + +Given the above binding, using `useRouteRef(createComponentExternalRouteRef)` within the Catalog plugin will let us create a link to whatever path the Scaffolder create component page is mounted at. Note that there is no direct dependency between the Catalog plugin and Scaffolder, that is, we are not importing the `createComponentExternalRouteRef` from the Scaffolder package. + +Now the only thing left is to provide the page and external route via a plugin: + +```tsx title="plugins/catalog/src/plugin.tsx" {20-23} showLineNumbers import React from 'react'; import { createPlugin, createPageExtension, useRouteRef, } from '@backstage/frontend-plugin-api'; -import { - indexRouteRef, - detailsRouteRef, - createComponentRouteRef, -} from './routes'; +import { indexRouteRef, createComponentExternalRouteRef } from './routes'; const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, - loader: () => { - const Component = () => { - const createComponentLink = useRouteRef(createComponentRouteRef); - - return ( -
-

Index Page

- {/* Linking to a create component page without direct reference */} - Create Component -
- ); - }; - - return Promise.resolve(); - }, -}); - -const catalogDetailsPage = createPageExtension({ - name: 'details', - defaultPath: '/entities/:namespace/:kind/:name', - routeRef: detailsRouteRef, - loader: () => { - const Component = () => { - // Getting the parameters from the URL - const params = useParams(); - return ( -
-

Details Page

-
    -
  • Kind: {params.kind}
  • -
  • Namespace: {params.namespace}
  • -
  • Name: {params.name}
  • -
-
- ); - }; - - return Promise.resolve(); - }, + loader: () => import('./components').then(m => ), }); export default createPlugin({ id: 'catalog', routes: { index: indexRouteRef, - details: detailsRouteRef, }, externalRoutes: { - createComponent: createComponentRouteRef, + createComponent: createComponentExternalRouteRef, }, - extensions: [catalogIndexPage, catalogDetailsPage], + extensions: [catalogIndexPage], }); - -// plugins/catalog/src/index.ts -export { default } from './plugin'; ``` -_Scaffolder Plugin_ +External routes can also have parameters. For example, if you want to link to an entity's details page from Scaffolder, you'll need to create an external route that receives the same parameters the Catalog details page expects: -```tsx -// plugins/scaffolder/src/routes.ts -import { createRouteRef } from '@backstage/frontend-plugin-api'; +```tsx title="plugins/scaffolder/src/routes.ts" {4} showLineNumbers +import { createExternalRouteRef } from '@backstage/frontend-plugin-api'; -export const indexRouteRef = createRouteRef(); - -// plugins/scaffolder/src/plugin.tsx -import React from 'react'; -import { - createPlugin, - createPageExtension, -} from '@backstage/frontend-plugin-api'; -import { indexRouteRef } from './routes'; - -const scaffolderIndexPage = createPageExtension({ - defaultPath: '/create', - routeRef: indexRouteRef, - loader: () => - Promise.resolve( -
-

Create Component

-
, - ), -}); - -export default createPlugin({ - id: 'scaffolder', - routes: { - index: indexRouteRef, - }, - extensions: [scaffolderIndexPage], -}); - -// plugins/scaffolder/src/index.ts -export { default } from './plugin'; -``` - -The Scaffolder plugin can also expose an external route that redirects to the Catalog entity details page whenever a new component is created, such as: - -```ts -// plugins/scaffolder/src/routes.ts -import { - createRouteRef, - createExternalRouteRef, -} from '@backstage/frontend-plugin-api'; - -export const indexRouteRef = createRouteRef(); -export const componentDetailsExternalRouteRef = createExternalRouteRef({ - // The parameters that must be included in the path of this route reference +export const entityDetailsExternalRouteRef = createExternalRouteRef({ params: ['kind', 'namespace', 'name'], }); - -// plugins/scaffolder/src/plugin.tsx -import React from 'react'; -import { - createPlugin, - createPageExtension, - useRouteRef, -} from '@backstage/frontend-plugin-api'; -import { indexRouteRef, componentDetailsExternalRouteRef } from './routes'; - -const scaffolderIndexPage = createPageExtension({ - defaultPath: '/create', - routeRef: indexRouteRef, - loader: () => { - const Component = () => { - const componentDetailsLink = useRouteRef( - componentDetailsExternalRouteRef, - ); - - return ( -
-

Create Component

- - See component details - -
- ); - }; - - return Promise.resolve(); - }, -}); - -export default createPlugin({ - id: 'scaffolder', - routes: { - index: indexRouteRef, - }, - externalRoutes: { - componentDetails: componentDetailsExternalRouteRef, - }, - extensions: [scaffolderIndexPage], -}); - -// plugins/scaffolder/src/index.ts -export { default } from './plugin'; ``` -Note that external routes can also have path parameters! Now let's move on and configure the app to resolve these external routes, so that the Scaffolder links to the Catalog entity page, and the Catalog links to the Scaffolder page. ### Binding External Route References @@ -410,8 +227,7 @@ The association of external routes is controlled by the app. Each `ExternalRoute Using the above example of the Catalog entities list page to the Scaffolder create component page, we might do something like this in the app configuration file: -```yaml -# app-config.yaml +```yaml title="app-config.yaml" {5,7} showLineNumbers app: routes: bindings: @@ -423,8 +239,7 @@ app: We also have the ability to express this in code as an option to `createApp`, but you of course only need to use one of these two methods: -```tsx -// packages/app/src/App.tsx +```tsx title="packages/app/src/App.tsx" {6-13} showLineNumbers import { createApp } from '@backstage/frontend-app-api'; import catalog from '@backstage/plugin-catalog'; import scaffolder from '@backstage/plugin-scaffolder'; @@ -443,70 +258,41 @@ const app = createApp({ export default app.createRoot(); ``` -Given the above binding, using `useRouteRef(createComponentRouteRef)` within the Catalog plugin will let us create a link to whatever path the Scaffolder create component page is mounted at. - Note that we are not importing and using the `RouteRef`s directly in the app, and instead rely on the plugin instance to access routes of the plugins. This provides better namespacing and discoverability of routes, as well as reduce the number of separate exports from each plugin package. Another thing to note is that this indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. For plugins that you build internally for your own Backstage application, you can choose to go the route of direct imports or even use concrete routes directly. Although there can be some benefits to using the full routing system even in internal plugins. It can help you structure your routes, and as you will see further down it also helps you manage route parameters. ### Optional External Route References -It is possible to define an `ExternalRouteRef` as optional, so it is not required to bind it in the app. When calling `useRouteRef` with an optional external route, its return signature is changed to `RouteFunc | undefined`, and the returned value can be used to decide whether a certain link should be displayed or if an action should be taken: +It is possible to define an `ExternalRouteRef` as optional, so it is not required to bind it in the app. -```tsx -// plugins/catalog/src/routes.ts -import { - createRouteRef, - createExternalRouteRef, -} from '@backstage/frontend-plugin-api'; +```tsx title="plugins/catalog/src/routes.ts" {4} showLineNumbers +import { createExternalRouteRef } from '@backstage/frontend-plugin-api'; -export const indexRouteRef = createRouteRef(); -export const createComponentRouteRef = createExternalRouteRef({ +export const createComponentExternalRouteRef = createExternalRouteRef({ optional: true, }); +``` -// plugins/catalog/src/plugin.tsx +When calling `useRouteRef` with an optional external route, its return signature is changed to `RouteFunc | undefined`, and the returned value can be used to decide whether a certain link should be displayed or if an action should be taken: + +```tsx title="plugins/catalog/src/components/IndexPage.tsx" {11} showLineNumbers import React from 'react'; -import { - createPlugin, - createPageExtension, - useRouteRef, -} from '@backstage/frontend-plugin-api'; -import { indexRouteRef, createComponentRouteRef } from './routes'; +import { useRouteRef } from '@backstage/frontend-plugin-api'; +import { createComponentExternalRouteRef } from '../routes'; -const catalogIndexPage = createPageExtension({ - defaultPath: '/entities', - routeRef: indexRouteRef, - loader: () => { - const Component = () => { - const createComponentLink = useRouteRef(createComponentRouteRef); - - return ( -
-

Index Page

- {/* Since the route is optional, rendering the link only if the href is defined */} - {link && Create Component} -
- ); - }; - - return Promise.resolve(); - }, -}); - -export default createPlugin({ - id: 'catalog', - routes: { - index: indexRouteRef, - }, - externalRoutes: { - createComponent: createComponentRouteRef, - }, - extensions: [catalogIndexPage], -}); - -// index.ts -export { default } from './plugin'; +export const IndexPage = () => { + const getCreateComponentPath = useRouteRef(createComponentExternalRouteRef); + return ( +
+

Index Page

+ {/* Rendering the link only if the getCreateComponentPath is defined */} + {getCreateComponentPath && ( + Create Component + )} +
+ ); +}; ``` ## Sub Route References @@ -515,8 +301,7 @@ The last kind of route refs that can be created are `SubRouteRef`s, which can be For example: -```tsx -// plugins/catalog/src/routes.ts +```tsx title ="plugins/catalog/src/routes.ts" {4,7} showLineNumbers import { createRouteRef, createSubRouteRef, @@ -527,91 +312,65 @@ export const detailsSubRouteRef = createSubRouteRef({ parent: indexRouteRef, path: '/details', }); - -// plugins/catalog/src/plugin.ts -import React from 'react'; -import { Routes, Route, useLocation } from 'react-router-dom'; -import { - createPlugin, - createPageExtension, - useRouteRef, -} from '@backstage/frontend-plugin-api'; -import { indexRouteRef, detailsSubRouteRef } from './routes.ts'; - -const DetailsPage = () => ( -
-

Details Sub Page

-
-); - -const catalogIndexPage = createPageExtension({ - defaultPath: '/entities', - routeRef: indexRouteRef, - loader: () => { - const Component = () => { - const { pathname } = useLocation(); - const indexLink = useRouteRef(indexRouteRef); - const detailsLink = useRouteRef(detailsSubRouteRef); - - return ( -
-

Index Page

- {/* Linking to the index route */} - {pathname === detailsLink() && Hide details} - {/* Linking to the details sub route */} - {pathname === indexLink() && Show details} - {/* Registering the details sub route */} - - } /> - -
- ); - }; - - return Promise.resolve(); - }, -}); - -export default createPlugin({ - id: 'catalog', - routes: { - index: indexRouteRef, - details: detailsSubRouteRef, - }, - extensions: [catalogIndexPage], -}); - -// plugins/catalog/src/index.ts -export { default } from './plugin'; ``` -Subroutes can also receive parameters, here is an example: +There are substantial differences between creating subroutes and regular or external routes because subroutes are associated with regular routes, and the sub route path must be specified. The path string must include the parameters if this sub route has them: -```tsx -// plugins/catalog/src/routes.ts -import { - createRouteRef, - createSubRouteRef, -} from '@backstage/frontend-plugin-api'; - -export const indexRouteRef = createRouteRef(); +```tsx title ="plugins/catalog/src/routes.ts" {4} showLineNumbers +// Omitting rest of the previous example file export const detailsSubRouteRef = createSubRouteRef({ parent: indexRouteRef, path: '/:name/:namespace/:kind', }); +``` -// plugins/catalog/src/plugin.ts +Using subroutes in a page extension is as simple as this: + +```tsx title="plugins/catalog/src/components/IndexPage.ts" showLineNumbers import React from 'react'; -import { Routes, Route, Link, useParams, useLocation } from 'react-router-dom'; -import { - createPlugin, - createPageExtension, - useRouteRef, -} from '@backstage/frontend-plugin-api'; -import { indexRouteRef, detailsSubRouteRef } from './routes.ts'; +import { Routes, Route, useLocation } from 'react-router-dom'; +import { useRouteRef } from '@backstage/frontend-plugin-api'; +import { indexRouteRef, detailsSubRouteRef } from '../routes'; +import { DetailsPage } from './DetailsPage'; -const DetailsPage = () => { - // Getting the parameters from the URL +export const IndexPage = () => { + const { pathname } = useLocation(); + const getIndexPath = useRouteRef(indexRouteRef); + const getDetailsPath = useRouteRef(detailsSubRouteRef); + return ( +
+

Index Page

+ {/* Linking to the details sub route */} + {pathname === getIndexPath() ? ( + // Setting the details sub route params + + Show details + + ) : ( + Hide details + )} + {/* Registering the details sub route */} + + } /> + +
+ ); +}; +``` + +This is how you can get the parameters of a sub route URL: + +```tsx title="plugins/catalog/src/components/DetailsPage.ts" {5} showLineNumbers +import React from 'react'; +import { useParams } from 'react-router-dom'; + +export const DetailsPage = () => { const params = useParams(); return (
@@ -624,60 +383,22 @@ const DetailsPage = () => {
); }; +``` + +Finally, see how a plugin can provide subroutes: + +```tsx title="plugins/catalog/src/plugin.ts" {18} showLineNumbers +import React from 'react'; +import { + createPlugin, + createPageExtension, +} from '@backstage/frontend-plugin-api'; +import { indexRouteRef, detailsSubRouteRef } from './routes'; const catalogIndexPage = createPageExtension({ defaultPath: '/entities', routeRef: indexRouteRef, - loader: () => { - const Component = () => { - const { pathname } = useLocation(); - const indexLink = useRouteRef(indexRouteRef)(); - const detailsLink = useRouteRef(detailsSubRouteRef); - - const indexPath = indexLink(); - const detailsPath = detailsLink({ - // Setting the details subroute params - kind: 'component', - namespace: 'default', - name: 'foo', - }); - - return ( -
-

Index Page

- - - - - - - - - - - - - -
NameDetails
Foo - {/* Linking to the index route */} - {pathname === detailsPath && ( - Hide details - )} - {/* Linking to the details sub route */} - {pathname === indexPath && ( - Show details - )} -
- {/* Registering the details subroute */} - - } /> - -
- ); - }; - - return Promise.resolve(); - }, + loader: () => import('./components').then(m => ), }); export default createPlugin({ @@ -688,7 +409,4 @@ export default createPlugin({ }, extensions: [catalogIndexPage], }); - -// plugins/catalog/src/index.ts -export { default } from './plugin'; ``` From f7a737e52f678a921f975cb3a97b2587f7f726cf Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 17 Jan 2024 14:19:29 +0100 Subject: [PATCH 163/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 0aa6980713..631ea87f97 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -117,7 +117,7 @@ export const IndexPage = () => { }; ``` -Line 6 uses a hook called `useRouteRef` to access a getter function that returns the details page path. On line 11, we call the getter, passing it an object with the kind, namespace, and name. These parameters are used to construct a concrete path to details the "Foo" details page. +We use the `useRouteRef` hook to create a link generator function that returns the details page path. We then call the link generator, passing it an object with the kind, namespace, and name. These parameters are used to construct a concrete path to details the "Foo" details page. Let's see how the details page can get the parameters from the URL: From 6b022bf6c76e30073f2dfe547d98def5602c11c5 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 17 Jan 2024 14:20:37 +0100 Subject: [PATCH 164/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 631ea87f97..2585053683 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -10,9 +10,9 @@ description: Frontend routes ## Introduction -In Backstage, plug-in boundaries and connections must be clearly defined. The app should allow navigation between plug-ins while isolating faults within them. +Each Backstage plugin is an isolated piece of functionality that doesn't typically communicate directly with other plugins. In order to achieve this, there are many parts of the frontend system that provide a layer of indirection for cross-plugin communication, and they routing system is one of them. -In order to address the problem outlined above, we introduced the concept of `RouteRef` which enables us route between pages in a flexible way, and it is especially important when bringing together different open source plugins. +The Backstage routing system makes it possible to implement navigation across plugin boundaries, without each individual plugin knowing the concrete path or location of other plugins in the routing hierarchy, or even its own. This is achieved through the concept of route references, which are opaque reference values that can be shared and used to create concrete links to different parts of an app. ## Route References From 4082cd192a1a14c46208eeb60ba1c0b1c4df01fd Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 17 Jan 2024 14:21:09 +0100 Subject: [PATCH 165/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 2585053683..6326f848d5 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -39,7 +39,7 @@ Route refs do not have any behavior themselves. They are an opaque value that re ### Providing Route References to Plugins -The previous section code snippet does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension: +The code snippet in the previous section does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension: ```tsx title="plugins/catalog/src/plugin.tsx" {11,17-19} showLineNumbers import React from 'react'; From 01167e332dff4b27066517fc57fffcedce19e365 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 17 Jan 2024 14:31:32 +0100 Subject: [PATCH 166/241] Update docs/frontend-system/architecture/07-routes.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 6326f848d5..918fddb43c 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -16,7 +16,7 @@ The Backstage routing system makes it possible to implement navigation across pl ## Route References -A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). +A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). It is up to plugin developers to create route references for any page content in their plugin that they want it to be possible to link to or from. Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sections). From fffed2e4dadf0d0acf5f81cc5653e7f43165785d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 17 Jan 2024 14:39:50 +0100 Subject: [PATCH 167/241] Delete contrib/chart directory These charts are no longer maintained, backstage/charts should be used instead. Signed-off-by: Patrik Oldsberg --- contrib/chart/backstage/Chart.lock | 6 - contrib/chart/backstage/Chart.yaml | 30 -- contrib/chart/backstage/README.md | 282 ----------------- .../files/app-config.development.yaml.tpl | 51 ---- .../backstage/files/create-backend-dbs.sql | 13 - .../chart/backstage/templates/_helpers.tpl | 286 ------------------ .../templates/backend-deployment.yaml | 98 ------ .../backstage/templates/backend-secret.yaml | 24 -- .../templates/backstage-app-config.yaml | 27 -- .../templates/backstage-auth-config.yaml | 21 -- .../templates/frontend-deployment.yaml | 66 ---- .../chart/backstage/templates/ingress.yaml | 150 --------- contrib/chart/backstage/templates/issuer.yaml | 19 -- .../templates/lighthouse-config.yaml | 12 - .../templates/lighthouse-deployment.yaml | 86 ------ .../templates/postgresql-ca-config.yaml | 21 -- .../templates/postgresql-certs-secret.yaml | 16 - .../templates/postgresql-initdb-secret.yaml | 14 - .../postgresql-password-backend-secret.yaml | 15 - ...postgresql-password-lighthouse-secret.yaml | 17 -- .../templates/tests/test-app-connection.yaml | 23 -- .../templates/tests/test-postgresql.yaml | 33 -- contrib/chart/backstage/values.yaml | 216 ------------- 23 files changed, 1526 deletions(-) delete mode 100644 contrib/chart/backstage/Chart.lock delete mode 100644 contrib/chart/backstage/Chart.yaml delete mode 100644 contrib/chart/backstage/README.md delete mode 100644 contrib/chart/backstage/files/app-config.development.yaml.tpl delete mode 100644 contrib/chart/backstage/files/create-backend-dbs.sql delete mode 100644 contrib/chart/backstage/templates/_helpers.tpl delete mode 100644 contrib/chart/backstage/templates/backend-deployment.yaml delete mode 100644 contrib/chart/backstage/templates/backend-secret.yaml delete mode 100644 contrib/chart/backstage/templates/backstage-app-config.yaml delete mode 100644 contrib/chart/backstage/templates/backstage-auth-config.yaml delete mode 100644 contrib/chart/backstage/templates/frontend-deployment.yaml delete mode 100644 contrib/chart/backstage/templates/ingress.yaml delete mode 100644 contrib/chart/backstage/templates/issuer.yaml delete mode 100644 contrib/chart/backstage/templates/lighthouse-config.yaml delete mode 100644 contrib/chart/backstage/templates/lighthouse-deployment.yaml delete mode 100644 contrib/chart/backstage/templates/postgresql-ca-config.yaml delete mode 100644 contrib/chart/backstage/templates/postgresql-certs-secret.yaml delete mode 100644 contrib/chart/backstage/templates/postgresql-initdb-secret.yaml delete mode 100644 contrib/chart/backstage/templates/postgresql-password-backend-secret.yaml delete mode 100644 contrib/chart/backstage/templates/postgresql-password-lighthouse-secret.yaml delete mode 100644 contrib/chart/backstage/templates/tests/test-app-connection.yaml delete mode 100644 contrib/chart/backstage/templates/tests/test-postgresql.yaml delete mode 100644 contrib/chart/backstage/values.yaml diff --git a/contrib/chart/backstage/Chart.lock b/contrib/chart/backstage/Chart.lock deleted file mode 100644 index bd909c1071..0000000000 --- a/contrib/chart/backstage/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: postgresql - repository: https://charts.bitnami.com/bitnami - version: 13.2.30 -digest: sha256:7b558cf1628b8cce366c980f20bd80a3cd7685fe419e43ee9d6df75bc577ec20 -generated: "2024-01-15T11:57:35.306830879Z" diff --git a/contrib/chart/backstage/Chart.yaml b/contrib/chart/backstage/Chart.yaml deleted file mode 100644 index f926c1b0d7..0000000000 --- a/contrib/chart/backstage/Chart.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: v2 -name: backstage -description: A Helm chart for Backstage -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -version: 0.1.3 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. -appVersion: v0.1.1-alpha.23 - -sources: - - https://github.com/backstage/backstage - - https://github.com/spotify/lighthouse-audit-service - -dependencies: - - name: postgresql - condition: postgresql.enabled - version: 13.2.30 - repository: https://charts.bitnami.com/bitnami - -maintainers: - - name: Martina Iglesias Fernández - email: martina@roadie.io - url: https://roadie.io - - name: David Tuite - email: david@roadie.io - url: https://roadie.io diff --git a/contrib/chart/backstage/README.md b/contrib/chart/backstage/README.md deleted file mode 100644 index 40bb2666bc..0000000000 --- a/contrib/chart/backstage/README.md +++ /dev/null @@ -1,282 +0,0 @@ -# Backstage demo helm charts - -This folder contains Helm charts that can easily create a Kubernetes deployment of a demo Backstage app. - -### Pre-requisites - -These charts depend on the `nginx-ingress` controller being present in the cluster. If it's not already installed you -can run: - -```shell -helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx -helm install nginx-ingress ingress-nginx/ingress-nginx -``` - -### Installing the charts - -After choosing a DNS name where backstage will be hosted create a yaml file for your custom configuration. - -```yaml -appConfig: - app: - baseUrl: https://backstage.mydomain.com - title: Backstage - backend: - baseUrl: https://backstage.mydomain.com - cors: - origin: https://backstage.mydomain.com - lighthouse: - baseUrl: https://backstage.mydomain.com/lighthouse-api - techdocs: - storageUrl: https://backstage.mydomain.com/api/techdocs/static/docs - requestUrl: https://backstage.mydomain.com/api/techdocs -``` - -Then use it to run: - -```shell -git clone https://github.com/backstage/backstage.git -cd contrib/chart/backstage -helm dependency update -helm install -f backstage-mydomain.yaml backstage . -``` - -This command will deploy the following pieces: - -- Backstage frontend -- Backstage backend with scaffolder and auth plugins -- (optional) a PostgreSQL instance -- lighthouse plugin -- ingress - -After a few minutes Backstage should be up and running in your cluster under the DNS specified earlier. - -Make sure to create the appropriate DNS entry in your infrastructure. To find the public IP address run: - -```shell -$ kubectl get ingress -NAME HOSTS ADDRESS PORTS AGE -backstage-ingress * 123.1.2.3 80 17m -``` - -> **NOTE**: this is not a production ready deployment. - -## Customization - -### Issue certificates - -These charts can install or reuse a `clusterIssuer` to generate certificates for the backstage `ingress`. To do that: - -1. [Install][install-cert-manager] or make sure [cert-manager][cert-manager] is installed in the cluster. -2. Enable the issuer in the charts. This will first check if there is a `letsencrypt` issuer already deployed in your - cluster and deploy one if it doesn't exist. - -To enable it you need to provide a valid email address in the chart's values: - -```yaml -issuer: - email: me@example.com - clusterIssuer: 'letsencrypt-prod' -``` - -By default, the charts use `letsencrypt-staging` so in the above example we instruct helm to use the production issuer -instead. - -[cert-manager]: https://cert-manager.io/docs/ -[install-cert-manager]: https://cert-manager.io/docs/installation/kubernetes/#installing-with-helm - -### Custom PostgreSQL instance - -Configuring a connection to an existing PostgreSQL instance is possible through the chart's values. - -First create a yaml file with the configuration you want to override, for example `backstage-prod.yaml`: - -```yaml -postgresql: - enabled: false - -appConfig: - app: - baseUrl: https://backstage-demo.mydomain.com - title: Backstage - backend: - baseUrl: https://backstage-demo.mydomain.com - cors: - origin: https://backstage-demo.mydomain.com - database: - client: pg - connection: - database: backstage_plugin_catalog - host: - user: - password: - lighthouse: - baseUrl: https://backstage-demo.mydomain.com/lighthouse-api - -lighthouse: - database: - client: pg - connection: - host: - user: - password: - database: lighthouse_audit_service -``` - -For the CA, create a `configMap` named `--postgres-ca` with a file called `ca.crt`: - -```shell -kubectl create configmap my-company-backstage-postgres-ca --from-file=ca.crt" -``` - -or disable CA mount - -```yaml -backend: - postgresCertMountEnabled: false - -lighthouse: - postgresCertMountEnabled: false -``` - -> Where the release name contains the chart name "backstage" then only the release name will be used. - -Now install the helm chart: - -```shell -cd contrib/chart/backstage -helm install -f backstage-prod.yaml my-backstage . -``` - -### Use your own docker images - -The docker images used for the deployment can be configured through the charts values: - -```yaml -frontend: - image: - repository: - tag: - -backend: - image: - repository: - tag: - -lighthouse: - image: - repository: - tag: -``` - -### Use a private docker repo - -Create a docker-registry secret - -```shell -kubectl create secret docker-registry # args -``` - -> For private images on docker hub --docker-server can be set to docker.io - -Reference the secret in your chart values - -```yaml -dockerRegistrySecretName: -``` - -### Different namespace - -To install the charts a specific namespace use `--namespace `: - -```shell -helm install -f my_values.yaml --namespace demos backstage . -``` - -### Disable loading of demo data - -To deploy backstage with the pre-loaded demo data disable `backend.demoData`: - -```shell -helm install -f my_values.yaml --set backend.demoData=false backstage . -``` - -### Other options - -For more customization options take a look at the [values.yaml](/contrib/chart/backstage/values.yaml) file. - -## Troubleshooting - -Some resources created by these charts are meant to survive after upgrades and even after uninstalls. When -troubleshooting these charts it can be useful to delete these resources between re-installs. - -Secrets: - -``` --postgresql-certs -- contains the certificates used by the deployed PostgreSQL -``` - -Persistent volumes: - -``` -data--postgresql-0 -- this is the data volume used by PostgreSQL to store data and configuration -``` - -> **NOTE**: this volume also stores the configuration for PostgreSQL which includes things like the password for the -> `postgres` user. This means that uninstalling and re-installing the charts with `postgres.enabled` set to `true` and -> auto generated passwords will fail. The solution is to delete this volume with -> `kubectl delete pvc data--postgresql-0` - -ConfigMaps: - -``` --postgres-ca -- contains the generated CA certificate for PostgreSQL when `postgres` is enabled -``` - -#### Unable to verify signature - -``` -Backend failed to start up Error: unable to verify the first certificate - at TLSSocket.onConnectSecure (_tls_wrap.js:1501:34) - at TLSSocket.emit (events.js:315:20) - at TLSSocket._finishInit (_tls_wrap.js:936:8) - at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:710:12) { - code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' -``` - -This error happens in the backend when it tries to connect to the configured PostgreSQL database and the specified CA is not correct. The solution is to make sure that the contents of the `configMap` that holds the certificate match the CA for the PostgreSQL instance. A workaround is to set `appConfig.backend.database.connection.ssl.rejectUnauthorized` to `false` in the chart's values. - -#### Multi-Platform Kubernetes Services - -If you are running a multi-platform Kubernetes service with Windows and Linux nodes then you will need to apply a `nodeSelector` to the Helm chart to ensure that pods are scheduled onto the correct platform nodes. - -Add the following to your Helm values file: - -```yaml -global: - nodeSelector: - kubernetes.io/os: linux - -# If using Postgres Chart also add -postgresql: - master: - nodeSelector: - kubernetes.io/os: linux - slave: - nodeSelector: - kubernetes.io/os: linux -``` - - - -## Uninstalling Backstage - -To uninstall Backstage simply run: - -```shell -RELEASE_NAME= # use `helm list` to find out the name -helm uninstall ${RELEASE_NAME} -kubectl delete pvc data-${RELEASE_NAME}-postgresql-0 -kubectl delete secret ${RELEASE_NAME}-postgresql-certs -kubectl delete configMap ${RELEASE_NAME}-postgres-ca -``` diff --git a/contrib/chart/backstage/files/app-config.development.yaml.tpl b/contrib/chart/backstage/files/app-config.development.yaml.tpl deleted file mode 100644 index 105ba3b259..0000000000 --- a/contrib/chart/backstage/files/app-config.development.yaml.tpl +++ /dev/null @@ -1,51 +0,0 @@ -backend: - lighthouseHostname: {{ include "lighthouse.serviceName" . | quote }} - listen: - port: {{ .Values.appConfig.backend.listen.port | default 7007 }} - database: - client: {{ .Values.appConfig.backend.database.client | quote }} - connection: - host: {{ include "backend.postgresql.host" . | quote }} - port: {{ include "backend.postgresql.port" . | quote }} - user: {{ include "backend.postgresql.user" . | quote }} - database: {{ .Values.appConfig.backend.database.connection.database | quote }} - ssl: - rejectUnauthorized: {{ .Values.appConfig.backend.database.connection.ssl.rejectUnauthorized | quote }} - ca: {{ include "backstage.backend.postgresCaFilename" . | quote }} - -catalog: -{{- if .Values.backend.demoData }} - locations: - # Backstage example components - - type: github - target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all-components.yaml - # Example component for github-actions - - type: github - target: https://github.com/backstage/backstage/blob/master/plugins/github-actions/examples/sample.yaml - # Example component for techdocs - - type: github - target: https://github.com/backstage/backstage/blob/master/plugins/techdocs-backend/examples/documented-component/documented-component.yaml - # Backstage example APIs - - type: github - target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all-apis.yaml - # Backstage example templates - - type: github - target: https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/all-templates.yaml -{{- else }} - locations: [] -{{- end }} - -auth: - providers: - microsoft: null - -scaffolder: - azure: null - - -sentry: - organization: {{ .Values.appConfig.sentry.organization | quote }} - -techdocs: - generator: - runIn: 'local' \ No newline at end of file diff --git a/contrib/chart/backstage/files/create-backend-dbs.sql b/contrib/chart/backstage/files/create-backend-dbs.sql deleted file mode 100644 index 043ff7daf5..0000000000 --- a/contrib/chart/backstage/files/create-backend-dbs.sql +++ /dev/null @@ -1,13 +0,0 @@ -{{ $backendDb := .Values.appConfig.backend.database.connection.database }} -{{ $lighthouseDb := .Values.lighthouse.database.connection.database }} -{{ $user := .Values.global.postgresql.postgresqlUsername }} - -grant all privileges on database {{ $backendDb }} to {{ $user }}; - -create database backstage_plugin_auth; -grant all privileges on database backstage_plugin_auth to {{ $user }}; - -{{ if not (eq $backendDb $lighthouseDb) }} -create database {{ $lighthouseDb }}; -grant all privileges on database {{ $lighthouseDb }} to {{ $user }}; -{{ end }} diff --git a/contrib/chart/backstage/templates/_helpers.tpl b/contrib/chart/backstage/templates/_helpers.tpl deleted file mode 100644 index 123d4dba5b..0000000000 --- a/contrib/chart/backstage/templates/_helpers.tpl +++ /dev/null @@ -1,286 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "backstage.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "backstage.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "backstage.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Common App labels -*/}} -{{- define "backstage.app.labels" -}} -app.kubernetes.io/name: {{ include "backstage.name" . }}-app -helm.sh/chart: {{ include "backstage.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{/* -Common Backend labels -*/}} -{{- define "backstage.backend.labels" -}} -app.kubernetes.io/name: {{ include "backstage.name" . }}-backend -helm.sh/chart: {{ include "backstage.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{/* -Name for postgresql dependency -See https://github.com/helm/helm/issues/3920#issuecomment-686913512 -*/}} -{{- define "backstage.postgresql.fullname" -}} -{{ printf "%s-%s" .Release.Name .Values.postgresql.nameOverride }} -{{- end -}} - - -{{/* -Create the name of the service account to use for the app -*/}} -{{- define "backstage.app.serviceAccountName" -}} -{{- if .Values.app.serviceAccount.create -}} - {{ default "default" .Values.app.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.app.serviceAccount.name }} -{{- end -}} -{{- end -}} - -{{/* -Create the name of the service account to use for the backend -*/}} -{{- define "backstage.backend.serviceAccountName" -}} -{{- if .Values.backend.serviceAccount.create -}} - {{ default default .Values.backend.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.backend.serviceAccount.name }} -{{- end -}} -{{- end -}} - -{{/* -Path to the CA certificate file in the backend -*/}} -{{- define "backstage.backend.postgresCaFilename" -}} -{{ include "backstage.backend.postgresCaDir" . }}/{{- required "The name for the CA certificate file for postgresql is required" .Values.global.postgresql.caFilename }} -{{- end -}} -{{/* - -{{/* -Directory path to the CA certificate file in the backend -*/}} -{{- define "backstage.backend.postgresCaDir" -}} -{{- if .Values.appConfig.backend.database.connection.ssl.ca -}} - {{ .Values.appConfig.backend.database.connection.ssl.ca }} -{{- else -}} -/etc/postgresql -{{- end -}} -{{- end -}} -{{/* - -Path to the CA certificate file in lighthouse -*/}} -{{- define "backstage.lighthouse.postgresCaFilename" -}} -{{ include "backstage.lighthouse.postgresCaDir" . }}/{{- required "The name for the CA certificate file for postgresql is required" .Values.global.postgresql.caFilename }} -{{- end -}} - -{{/* -Directory path to the CA certificate file in lighthouse -*/}} -{{- define "backstage.lighthouse.postgresCaDir" -}} -{{- if .Values.lighthouse.database.pathToDatabaseCa -}} - {{ .Values.lighthouse.database.pathToDatabaseCa }} -{{- else -}} -/etc/postgresql -{{- end -}} -{{- end -}} -{{/* - -{{/* -Generate ca for postgresql -*/}} -{{- define "backstage.postgresql.generateCA" -}} -{{- $ca := .ca | default (genCA (include "backstage.postgresql.fullname" .) 365) -}} -{{- $_ := set . "ca" $ca -}} -{{- $ca.Cert -}} -{{- end -}} - -{{/* -Generate certificates for postgresql -*/}} -{{- define "generateCerts" -}} -{{- $postgresName := (include "backstage.postgresql.fullname" .) }} -{{- $altNames := list $postgresName ( printf "%s.%s" $postgresName .Release.Namespace ) ( printf "%s.%s.svc" ( $postgresName ) .Release.Namespace ) -}} -{{- $ca := .ca | default (genCA (include "backstage.postgresql.fullname" .) 365) -}} -{{- $_ := set . "ca" $ca -}} -{{- $cert := genSignedCert ( $postgresName ) nil $altNames 365 $ca -}} -tls.crt: {{ $cert.Cert | b64enc }} -tls.key: {{ $cert.Key | b64enc }} -{{- end -}} - -{{/* -Generate a password for the postgres user used for the connections from the backend and lighthouse -*/}} -{{- define "postgresql.generateUserPassword" -}} -{{- $pgPassword := .pgPassword | default ( randAlphaNum 12 ) -}} -{{- $_ := set . "pgPassword" $pgPassword -}} -{{ $pgPassword}} -{{- end -}} - -{{/* -Name of the backend service -*/}} -{{- define "backend.serviceName" -}} -{{ include "backstage.fullname" . }}-backend -{{- end -}} - -{{/* -Name of the frontend service -*/}} -{{- define "frontend.serviceName" -}} -{{ include "backstage.fullname" . }}-frontend -{{- end -}} - -{{/* -Name of the lighthouse backend service -*/}} -{{- define "lighthouse.serviceName" -}} -{{ include "backstage.fullname" . }}-lighthouse -{{- end -}} - -{{/* -Name of the postgresql service -*/}} -{{- define "postgresql.serviceName" -}} -{{- include "backstage.postgresql.fullname" . }} -{{- end -}} - -{{/* -Postgres host for lighthouse -*/}} -{{- define "lighthouse.postgresql.host" -}} -{{- if .Values.postgresql.enabled }} -{{- include "postgresql.serviceName" . }} -{{- else -}} -{{- required "A valid .Values.lighthouse.database.connection.host is required when postgresql is not enabled" .Values.lighthouse.database.connection.host -}} -{{- end -}} -{{- end -}} - -{{/* -Postgres host for the backend -*/}} -{{- define "backend.postgresql.host" -}} -{{- if .Values.postgresql.enabled }} -{{- include "postgresql.serviceName" . }} -{{- else -}} -{{- required "A valid .Values.appConfig.backend.database.connection.host is required when postgresql is not enabled" .Values.appConfig.backend.database.connection.host -}} -{{- end -}} -{{- end -}} - -{{/* -Postgres port for the backend -*/}} -{{- define "backend.postgresql.port" -}} -{{- if .Values.postgresql.enabled }} -{{- .Values.postgresql.service.port }} -{{- else if .Values.appConfig.backend.database.connection.port -}} -{{- .Values.appConfig.backend.database.connection.port }} -{{- else -}} -5432 -{{- end -}} -{{- end -}} - -{{/* -Postgres port for lighthouse -*/}} -{{- define "lighthouse.postgresql.port" -}} -{{- if .Values.postgresql.enabled }} -{{- .Values.postgresql.service.port }} -{{- else if .Values.lighthouse.database.connection.port -}} -{{- .Values.lighthouse.database.connection.port }} -{{- else -}} -5432 -{{- end -}} -{{- end -}} - -{{/* -Postgres user for backend -*/}} -{{- define "backend.postgresql.user" -}} -{{- if .Values.postgresql.enabled }} -{{- .Values.global.postgresql.postgresqlUsername }} -{{- else -}} -{{- required "A valid .Values.appConfig.backend.database.connection.user is required when postgresql is not enabled" .Values.appConfig.backend.database.connection.user -}} -{{- end -}} -{{- end -}} - -{{/* -Postgres user for lighthouse -*/}} -{{- define "lighthouse.postgresql.user" -}} -{{- if .Values.postgresql.enabled }} -{{- .Values.global.postgresql.postgresqlUsername }} -{{- else -}} -{{- required "A valid .Values.lighthouse.database.connection.user is required when postgresql is not enabled" .Values.lighthouse.database.connection.user -}} -{{- end -}} -{{- end -}} - -{{/* -Postgres password secret for backend -*/}} -{{- define "backend.postgresql.passwordSecret" -}} -{{- if .Values.postgresql.enabled }} -{{- template "backstage.postgresql.fullname" . }} -{{- else -}} -{{ $secretName := (printf "%s-backend-postgres" (include "backstage.fullname" . )) }} -{{- required "A valid .Values.appConfig.backend.database.connection.password is required when postgresql is not enabled" $secretName -}} -{{- end -}} -{{- end -}} - -{{/* -Postgres password for lighthouse -*/}} -{{- define "lighthouse.postgresql.passwordSecret" -}} -{{- if .Values.postgresql.enabled }} -{{- template "backstage.postgresql.fullname" . }} -{{- else -}} -{{ $secretName := (printf "%s-lighthouse-postgres" (include "backstage.fullname" . )) }} -{{- required "A valid .Values.lighthouse.database.connection.password is required when postgresql is not enabled" $secretName -}} -{{- end -}} -{{- end -}} - -{{/* -app-config file name -*/}} -{{- define "backstage.appConfigFilename" -}} -{{- "app-config.development.yaml" -}} -{{- end -}} diff --git a/contrib/chart/backstage/templates/backend-deployment.yaml b/contrib/chart/backstage/templates/backend-deployment.yaml deleted file mode 100644 index 0fa6b7fbe2..0000000000 --- a/contrib/chart/backstage/templates/backend-deployment.yaml +++ /dev/null @@ -1,98 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "backstage.fullname" . }}-backend - -spec: - replicas: {{ .Values.backend.replicaCount }} - - selector: - matchLabels: - app: backstage - component: backend - - template: - metadata: - annotations: - ad.datadoghq.com/backstage.logs: '[{"source":"backstage","service":"backend"}]' - labels: - app: backstage - component: backend - - spec: - {{- if .Values.dockerRegistrySecretName }} - imagePullSecrets: - - name: {{ .Values.dockerRegistrySecretName }} - {{- end}} - containers: - - name: {{ .Chart.Name }}-backend - command: ["node"] - args: - - "packages/backend" - - "--config" - - "app-config.yaml" - - "--config" - - {{ printf "/usr/src/app/%s" (include "backstage.appConfigFilename" .) | quote }} - image: {{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }} - imagePullPolicy: {{ .Values.backend.image.pullPolicy }} - ports: - - containerPort: {{ .Values.backend.containerPort }} - resources: - {{- toYaml .Values.backend.resources | nindent 12 }} - - envFrom: - - secretRef: - name: {{ include "backstage.fullname" . }}-backend - - configMapRef: - name: {{ include "backstage.fullname" . }}-app-env - - configMapRef: - name: {{ include "backstage.fullname" . }}-auth - env: - - name: NODE_ENV - value: {{ .Values.backend.nodeEnv | default "development" }} - - name: APP_CONFIG_backend_database_connection_password - valueFrom: - secretKeyRef: - name: {{ include "backend.postgresql.passwordSecret" .}} - key: postgresql-password - volumeMounts: - {{- if .Values.backend.postgresCertMountEnabled }} - - name: postgres-ca - mountPath: {{ include "backstage.backend.postgresCaDir" . }} - {{- end }} - - name: app-config - mountPath: {{ printf "/usr/src/app/%s" (include "backstage.appConfigFilename" .) }} - subPath: {{ include "backstage.appConfigFilename" . }} - - volumes: - {{- if .Values.backend.postgresCertMountEnabled }} - - name: postgres-ca - configMap: - name: {{ include "backstage.fullname" . }}-postgres-ca - {{- end }} - - name: app-config - configMap: - name: {{ include "backstage.fullname" . }}-app-config - - {{- if .Values.global.nodeSelector }} - nodeSelector: {{- toYaml .Values.global.nodeSelector | nindent 8 }} - {{- end }} - -{{- if .Values.backend.enabled }} ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "backend.serviceName" . }} - -spec: - ports: - - port: 80 - targetPort: {{ .Values.backend.containerPort }} - - selector: - app: backstage - component: backend - - type: {{ .Values.backend.serviceType }} -{{- end }} diff --git a/contrib/chart/backstage/templates/backend-secret.yaml b/contrib/chart/backstage/templates/backend-secret.yaml deleted file mode 100644 index 299d893ec4..0000000000 --- a/contrib/chart/backstage/templates/backend-secret.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if .Values.backend.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "backstage.fullname" . }}-backend -type: Opaque -stringData: - AUTH_GOOGLE_CLIENT_SECRET: {{ .Values.auth.google.clientSecret }} - AUTH_GITHUB_CLIENT_SECRET: {{ .Values.auth.github.clientSecret }} - AUTH_GITLAB_CLIENT_SECRET: {{ .Values.auth.gitlab.clientSecret }} - AUTH_OKTA_CLIENT_SECRET: {{ .Values.auth.okta.clientSecret }} - AUTH_OAUTH2_CLIENT_SECRET: {{ .Values.auth.oauth2.clientSecret }} - AUTH_AUTH0_CLIENT_SECRET: {{ .Values.auth.auth0.clientSecret }} - AUTH_MICROSOFT_CLIENT_SECRET: {{ .Values.auth.microsoft.clientSecret }} - SENTRY_TOKEN: {{ .Values.auth.sentryToken }} - ROLLBAR_ACCOUNT_TOKEN: {{ .Values.auth.rollbarAccountToken }} - CIRCLECI_AUTH_TOKEN: {{ .Values.auth.circleciAuthToken }} - GITHUB_TOKEN: {{ .Values.auth.githubToken }} - GITLAB_TOKEN: {{ .Values.auth.gitlabToken }} - AZURE_TOKEN: {{ .Values.auth.azure.api.token }} - NEW_RELIC_REST_API_KEY: {{ .Values.auth.newRelicRestApiKey }} - TRAVISCI_AUTH_TOKEN: {{ .Values.auth.travisciAuthToken }} - PAGERDUTY_TOKEN: {{ .Values.auth.pagerdutyToken }} -{{- end }} diff --git a/contrib/chart/backstage/templates/backstage-app-config.yaml b/contrib/chart/backstage/templates/backstage-app-config.yaml deleted file mode 100644 index 061fc3285b..0000000000 --- a/contrib/chart/backstage/templates/backstage-app-config.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "backstage.fullname" . }}-app-config -data: -{{ include "backstage.appConfigFilename" . | indent 2 }}: | -{{ tpl (.Files.Get "files/app-config.development.yaml.tpl") . | indent 4 }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "backstage.fullname" . }}-app-env -data: - APP_CONFIG_app_baseUrl: {{ .Values.appConfig.app.baseUrl | quote | quote }} - APP_CONFIG_app_title: {{ .Values.appConfig.app.title | quote | quote }} - APP_CONFIG_backend_baseUrl: {{ .Values.appConfig.backend.baseUrl | quote | quote }} - APP_CONFIG_backend_cors_origin: {{ .Values.appConfig.backend.cors.origin | quote | quote }} - APP_CONFIG_techdocs_storageUrl: {{ .Values.appConfig.techdocs.storageUrl | quote | quote }} - APP_CONFIG_techdocs_requestUrl: {{ .Values.appConfig.techdocs.requestUrl | quote | quote }} - APP_CONFIG_lighthouse_baseUrl: {{ .Values.appConfig.lighthouse.baseUrl | quote | quote }} - APP_CONFIG_backend_database_connection_ssl_rejectUnauthorized: "false" - APP_CONFIG_auth_providers_github_development_appOrigin: {{ .Values.appConfig.auth.providers.github.development.appOrigin | quote | quote }} - APP_CONFIG_auth_providers_google_development_appOrigin: {{ .Values.appConfig.auth.providers.google.development.appOrigin | quote | quote }} - APP_CONFIG_auth_providers_gitlab_development_appOrigin: {{ .Values.appConfig.auth.providers.gitlab.development.appOrigin | quote | quote }} - APP_CONFIG_auth_providers_okta_development_appOrigin: {{ .Values.appConfig.auth.providers.okta.development.appOrigin | quote | quote }} - APP_CONFIG_auth_providers_oauth2_development_appOrigin: {{ .Values.appConfig.auth.providers.oauth2.development.appOrigin | quote | quote }} - diff --git a/contrib/chart/backstage/templates/backstage-auth-config.yaml b/contrib/chart/backstage/templates/backstage-auth-config.yaml deleted file mode 100644 index 7dcf8379aa..0000000000 --- a/contrib/chart/backstage/templates/backstage-auth-config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "backstage.fullname" . }}-auth -data: - AUTH_GOOGLE_CLIENT_ID: {{ .Values.auth.google.clientId }} - AUTH_GITHUB_CLIENT_ID: {{ .Values.auth.github.clientId }} - AUTH_GITLAB_CLIENT_ID: {{ .Values.auth.gitlab.clientId }} - # This should not be prefixed with AUTH_. This could be a typo in the Backstage app config. - # Regardless, it is not decided by me. - GITLAB_BASE_URL: {{ .Values.auth.gitlab.baseUrl }} - AUTH_OKTA_CLIENT_ID: {{ .Values.auth.okta.clientId }} - AUTH_OKTA_AUDIENCE: {{ .Values.auth.okta.audience }} - AUTH_OAUTH2_CLIENT_ID: {{ .Values.auth.oauth2.clientId }} - AUTH_OAUTH2_AUTH_URL: {{ .Values.auth.oauth2.authUrl }} - AUTH_OAUTH2_TOKEN_URL: {{ .Values.auth.oauth2.tokenUrl }} - AUTH_AUTH0_CLIENT_ID: {{ .Values.auth.auth0.clientId }} - AUTH_AUTH0_DOMAIN: {{ .Values.auth.auth0.domain }} - AUTH_MICROSOFT_CLIENT_ID: {{ .Values.auth.microsoft.clientId }} - AUTH_MICROSOFT_TENANT_ID: {{ .Values.auth.microsoft.tenantId }} - diff --git a/contrib/chart/backstage/templates/frontend-deployment.yaml b/contrib/chart/backstage/templates/frontend-deployment.yaml deleted file mode 100644 index dba4e2c96a..0000000000 --- a/contrib/chart/backstage/templates/frontend-deployment.yaml +++ /dev/null @@ -1,66 +0,0 @@ -{{- if .Values.frontend.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "backstage.fullname" . }}-frontend - -spec: - replicas: {{ .Values.frontend.replicaCount }} - - selector: - matchLabels: - app: backstage - component: frontend - - template: - metadata: - annotations: - ad.datadoghq.com/backstage.logs: '[{"source":"backstage","service":"frontend"}]' - labels: - app: backstage - component: frontend - - spec: - {{- if .Values.dockerRegistrySecretName }} - imagePullSecrets: - - name: {{ .Values.dockerRegistrySecretName }} - {{- end}} - containers: - - name: {{ .Chart.Name }}-frontend - image: {{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }} - imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} - ports: - - containerPort: {{ .Values.frontend.containerPort }} - resources: - {{- toYaml .Values.frontend.resources | nindent 12 }} - envFrom: - - configMapRef: - name: {{ include "backstage.fullname" . }}-app-env - volumeMounts: - - name: app-config - mountPath: {{ printf "/usr/share/nginx/html/static/%s" (include "backstage.appConfigFilename" .) }} - subPath: {{ include "backstage.appConfigFilename" . }} - volumes: - - name: app-config - configMap: - name: {{ include "backstage.fullname" . }}-app-config - {{- if .Values.global.nodeSelector }} - nodeSelector: {{- toYaml .Values.global.nodeSelector | nindent 8 }} - {{- end }} ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "frontend.serviceName" . }} - -spec: - ports: - - port: 80 - targetPort: {{ .Values.frontend.containerPort }} - - selector: - app: backstage - component: frontend - - type: {{ .Values.frontend.serviceType }} -{{- end }} diff --git a/contrib/chart/backstage/templates/ingress.yaml b/contrib/chart/backstage/templates/ingress.yaml deleted file mode 100644 index 7e008c5d9d..0000000000 --- a/contrib/chart/backstage/templates/ingress.yaml +++ /dev/null @@ -1,150 +0,0 @@ -{{- $frontendUrl := urlParse .Values.appConfig.app.baseUrl}} -{{- $backendUrl := urlParse .Values.appConfig.backend.baseUrl}} -{{- $lighthouseUrl := urlParse .Values.appConfig.lighthouse.baseUrl}} - -{{/* Determine the api type for the ingress */}} -{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} -apiVersion: networking.k8s.io/v1 -{{- else -}} -apiVersion: networking.k8s.io/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ include "backstage.fullname" . }}-ingress - annotations: - {{- if .Values.issuer.email }} - cert-manager.io/cluster-issuer: {{ .Values.issuer.clusterIssuer }} - {{- end }} - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/configuration-snippet: | - if ($scheme = https) { - add_header Strict-Transport-Security "max-age=0;"; - } - {{- toYaml .Values.ingress.annotations | nindent 4 }} -spec: - tls: - - secretName: {{ include "backstage.fullname" . }}-tls - hosts: - - {{ $frontendUrl.host }} - - {{ $backendUrl.host }} - - {{ $lighthouseUrl.host }} - rules: - - host: {{ $frontendUrl.host }} - http: - paths: - - path: / - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - pathType: Prefix - {{- end }} - backend: - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - service: - name: {{ include "frontend.serviceName" . }} - port: - number: 80 - {{- else -}} - serviceName: {{ include "frontend.serviceName" . }} - servicePort: 80 - {{- end }} - {{/* Route the backend inside the same hostname as the frontend when they are the same */}} - {{- if eq $frontendUrl.host $backendUrl.host}} - - path: /api/ - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - pathType: Prefix - {{- end }} - backend: - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - service: - name: {{ include "backend.serviceName" . }} - port: - number: 80 - {{- else -}} - serviceName: {{ include "backend.serviceName" . }} - servicePort: 80 - {{- end }} - {{/* Route the backend through a different host */}} - {{- else -}} - - host: {{ $backendUrl.host }} - http: - paths: - - path: {{ $backendUrl.path | default "/" }} - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - pathType: Prefix - {{- end }} - backend: - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - service: - name: {{ include "backend.serviceName" . }} - port: - number: 80 - {{- else -}} - serviceName: {{ include "backend.serviceName" . }} - servicePort: 80 - {{- end }} - {{- end }} - -{{/* Route lighthouse through a different host */}} -{{- if not ( eq $frontendUrl.host $lighthouseUrl.host ) }} - - host: {{ $lighthouseUrl.host }} - http: - paths: - - path: {{ $lighthouseUrl.path | default "/" }} - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - pathType: Prefix - {{- end }} - backend: - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - service: - name: {{ include "lighthouse.serviceName" . }} - port: - number: 80 - {{- else -}} - serviceName: {{ include "lighthouse.serviceName" . }} - servicePort: 80 - {{- end }} -{{- else }} -{{/* Route lighthouse by path with re-write rules when it is hosted under the same hostname */}} ---- -{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} -apiVersion: networking.k8s.io/v1 -{{- else -}} -apiVersion: networking.k8s.io/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ include "backstage.fullname" . }}-ingress-lighthouse - annotations: - {{- if .Values.issuer.email }} - cert-manager.io/cluster-issuer: {{ .Values.issuer.clusterIssuer }} - {{- end }} - nginx.ingress.kubernetes.io/rewrite-target: /$2 - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/configuration-snippet: | - if ($scheme = https) { - add_header Strict-Transport-Security "max-age=0;"; - } - {{- toYaml .Values.ingress.annotations | nindent 4 }} -spec: - tls: - - secretName: {{ include "backstage.fullname" . }}-tls - hosts: - - {{ $lighthouseUrl.host }} - rules: - - host: {{ $frontendUrl.host }} - http: - paths: - - path: {{$lighthouseUrl.path}}(/|$)(.*) - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - pathType: Prefix - {{- end }} - backend: - {{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }} - service: - name: {{ include "lighthouse.serviceName" . }} - port: - number: 80 - {{- else -}} - serviceName: {{ include "lighthouse.serviceName" . }} - servicePort: 80 - {{- end }} -{{- end }} diff --git a/contrib/chart/backstage/templates/issuer.yaml b/contrib/chart/backstage/templates/issuer.yaml deleted file mode 100644 index d129c8c701..0000000000 --- a/contrib/chart/backstage/templates/issuer.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if (and (.Capabilities.APIVersions.Has "cert-manager.io/v1alpha2") .Values.issuer.email ) -}} -{{/* Only install issuer if it doesn't already exist in the cluster */}} -{{- if not ( lookup "cert-manager.io/v1alpha2" "ClusterIssuer" "" .Values.issuer.clusterIssuer ) }} -apiVersion: cert-manager.io/v1alpha2 -kind: ClusterIssuer -metadata: - name: {{ .Values.issuer.clusterIssuer }} -spec: - acme: - server: https://acme-v02.api.letsencrypt.org/directory - email: {{ required "expected a valid .Values.issuer.email to enable ClusterIssuer" .Values.issuer.email }} - privateKeySecretRef: - name: {{ required "expected .Values.issuer.cluster-issuer to not be empty (letsencrypt-prod | letsencrypt-staging)" .Values.issuer.clusterIssuer }} - solvers: - - http01: - ingress: - class: nginx -{{- end -}} -{{- end -}} diff --git a/contrib/chart/backstage/templates/lighthouse-config.yaml b/contrib/chart/backstage/templates/lighthouse-config.yaml deleted file mode 100644 index 7b8cad42dc..0000000000 --- a/contrib/chart/backstage/templates/lighthouse-config.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.lighthouse.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "backstage.fullname" . -}}-lighthouse -data: - PGDATABASE: {{ .Values.lighthouse.database.connection.database | quote }} - PGUSER: {{ include "lighthouse.postgresql.user" . | quote }} - PGPORT: {{ include "lighthouse.postgresql.port" . | quote }} - PGHOST: {{ include "lighthouse.postgresql.host" . | quote }} - PGPATH_TO_CA: {{ include "backstage.lighthouse.postgresCaFilename" . | quote }} -{{- end }} \ No newline at end of file diff --git a/contrib/chart/backstage/templates/lighthouse-deployment.yaml b/contrib/chart/backstage/templates/lighthouse-deployment.yaml deleted file mode 100644 index 849c48d7a6..0000000000 --- a/contrib/chart/backstage/templates/lighthouse-deployment.yaml +++ /dev/null @@ -1,86 +0,0 @@ -{{- if .Values.lighthouse.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "backstage.fullname" . }}-lighthouse - -spec: - replicas: {{ .Values.lighthouse.replicaCount }} - - selector: - matchLabels: - app: backstage - component: lighthouse-audit-service - - template: - metadata: - annotations: - ad.datadoghq.com/backstage.logs: '[{"source":"backstage","service":"lighthouse"}]' - labels: - app: backstage - component: lighthouse-audit-service - - spec: - {{- if .Values.dockerRegistrySecretName }} - imagePullSecrets: - - name: {{ .Values.dockerRegistrySecretName }} - {{- end}} - containers: - - name: lighthouse-audit-service - image: {{ .Values.lighthouse.image.repository }}:{{ .Values.lighthouse.image.tag }} - imagePullPolicy: {{ .Values.lighthouse.image.pullPolicy }} - ports: - - containerPort: {{ .Values.lighthouse.containerPort }} - resources: - {{- toYaml .Values.lighthouse.resources | nindent 12 }} - - envFrom: - - configMapRef: - name: {{ include "backstage.fullname" . -}}-lighthouse - - configMapRef: - name: {{ include "backstage.fullname" . }}-app-env - - env: - - name: LAS_PORT - value: {{ .Values.lighthouse.containerPort | quote }} - - name: LAS_CORS - value: "true" - - name: PGPASSWORD - valueFrom: - secretKeyRef: - name: {{ include "lighthouse.postgresql.passwordSecret" . }} - key: postgresql-password - - {{- if .Values.lighthouse.postgresCertMountEnabled }} - volumeMounts: - - name: postgres-ca - mountPath: {{ include "backstage.lighthouse.postgresCaDir" . }} - {{- end }} - - {{- if .Values.lighthouse.postgresCertMountEnabled }} - volumes: - - name: postgres-ca - configMap: - name: {{ include "backstage.fullname" . }}-postgres-ca - {{- end }} - - {{- if .Values.global.nodeSelector }} - nodeSelector: {{- toYaml .Values.global.nodeSelector | nindent 8 }} - {{- end }} ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "lighthouse.serviceName" . }} - -spec: - ports: - - port: 80 - targetPort: {{ .Values.lighthouse.containerPort }} - - selector: - app: backstage - component: lighthouse-audit-service - - type: {{ .Values.lighthouse.serviceType }} -{{- end }} diff --git a/contrib/chart/backstage/templates/postgresql-ca-config.yaml b/contrib/chart/backstage/templates/postgresql-ca-config.yaml deleted file mode 100644 index 2631989f4e..0000000000 --- a/contrib/chart/backstage/templates/postgresql-ca-config.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if .Values.postgresql.enabled }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "backstage.fullname" . }}-postgres-ca - labels: - app: {{ include "backstage.postgresql.fullname" . }} - release: {{ .Release.Name }} - annotations: - "helm.sh/hook": "pre-install" - "helm.sh/hook-delete-policy": "before-hook-creation" -data: - {{ .Values.global.postgresql.caFilename }}: | -{{ include "backstage.postgresql.generateCA" . | indent 4}} -{{- else }} -{{- $caConfig := printf "%s-postgres-ca" (include "backstage.fullname" .) }} -{{- if not ( lookup "v1" "ConfigMap" .Release.Namespace $caConfig ) }} -{{- fail (printf "\n\nPlease create the '%s' configmap with the CA certificate for your existing postgresql: kubectl create configmap %s --from-file=ca.crt" $caConfig $caConfig) }} -{{- end }} -{{- end }} \ No newline at end of file diff --git a/contrib/chart/backstage/templates/postgresql-certs-secret.yaml b/contrib/chart/backstage/templates/postgresql-certs-secret.yaml deleted file mode 100644 index c6845caa7e..0000000000 --- a/contrib/chart/backstage/templates/postgresql-certs-secret.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if .Values.postgresql.enabled }} ---- -apiVersion: v1 -kind: Secret -type: kubernetes.io/tls -metadata: - name: {{ required ".Values.postgresql.tls.certificatesSecret is required" .Values.postgresql.tls.certificatesSecret }} - labels: - app: {{ include "backstage.postgresql.fullname" . }} - release: {{ .Release.Name }} - annotations: - "helm.sh/hook": "pre-install" - "helm.sh/hook-delete-policy": "before-hook-creation" -data: -{{ include "generateCerts" . | indent 2 }} -{{- end }} diff --git a/contrib/chart/backstage/templates/postgresql-initdb-secret.yaml b/contrib/chart/backstage/templates/postgresql-initdb-secret.yaml deleted file mode 100644 index d1c446f79f..0000000000 --- a/contrib/chart/backstage/templates/postgresql-initdb-secret.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if .Values.postgresql.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ required ".Values.postgresql.initdbScriptsSecret is required" .Values.postgresql.initdbScriptsSecret }} - annotations: - "helm.sh/hook": "pre-install" - "helm.sh/hook-delete-policy": "before-hook-creation" -type: Opaque -data: - create-backend-dbs.sql: | - {{ tpl (.Files.Get "files/create-backend-dbs.sql") . | b64enc }} -{{- end }} - diff --git a/contrib/chart/backstage/templates/postgresql-password-backend-secret.yaml b/contrib/chart/backstage/templates/postgresql-password-backend-secret.yaml deleted file mode 100644 index a71cef7b21..0000000000 --- a/contrib/chart/backstage/templates/postgresql-password-backend-secret.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- if not .Values.postgresql.enabled }} ---- -apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: {{ include "backend.postgresql.passwordSecret" . }} - labels: - release: {{ .Release.Name }} - annotations: - "helm.sh/hook": "pre-install,pre-upgrade" - "helm.sh/hook-delete-policy": "before-hook-creation" -data: - postgresql-password: {{ .Values.appConfig.backend.database.connection.password | b64enc }} -{{- end }} diff --git a/contrib/chart/backstage/templates/postgresql-password-lighthouse-secret.yaml b/contrib/chart/backstage/templates/postgresql-password-lighthouse-secret.yaml deleted file mode 100644 index e7374e70db..0000000000 --- a/contrib/chart/backstage/templates/postgresql-password-lighthouse-secret.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- if .Values.lighthouse.enabled }} -{{- if not .Values.postgresql.enabled }} ---- -apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: {{ include "lighthouse.postgresql.passwordSecret" . }} - labels: - release: {{ .Release.Name }} - annotations: - "helm.sh/hook": "pre-install,pre-upgrade" - "helm.sh/hook-delete-policy": "before-hook-creation" -data: - postgresql-password: {{ .Values.lighthouse.database.connection.password | b64enc }} -{{- end }} -{{- end }} diff --git a/contrib/chart/backstage/templates/tests/test-app-connection.yaml b/contrib/chart/backstage/templates/tests/test-app-connection.yaml deleted file mode 100644 index 93f51f3f09..0000000000 --- a/contrib/chart/backstage/templates/tests/test-app-connection.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -apiVersion: v1 -kind: Pod -metadata: - name: {{ include "backstage.fullname" . -}}-test-app-connection - annotations: - "helm.sh/hook": test -spec: - containers: - - name: test-app - image: busybox - command: - - /bin/sh - - -ecx - - | - echo -e "===== Testing the connection with the frontend...\n" - wget -q -O - {{ printf "%s.%s" (include "frontend.serviceName" .) .Release.Namespace | quote }} - echo -e "\n\n===== Testing the connection with the backend...\n" - wget -q -O - {{ printf "http://%s.%s/catalog/entities" (include "backend.serviceName" .) .Release.Namespace | quote }} - echo -e "\n\n===== Testing the connection with the lighthouse plugin...\n" - wget -q -O - {{ printf "%s.%s/v1/audits" (include "lighthouse.serviceName" .) .Release.Namespace | quote }} - echo -e "\n" - restartPolicy: Never \ No newline at end of file diff --git a/contrib/chart/backstage/templates/tests/test-postgresql.yaml b/contrib/chart/backstage/templates/tests/test-postgresql.yaml deleted file mode 100644 index 8eec1db452..0000000000 --- a/contrib/chart/backstage/templates/tests/test-postgresql.yaml +++ /dev/null @@ -1,33 +0,0 @@ -{{- if .Values.postgresql.enabled}} ---- -apiVersion: v1 -kind: Pod -metadata: - name: {{ include "backstage.name" . -}}-test-postgres - annotations: - "helm.sh/hook": test -spec: - containers: - - name: postgresql-client - image: bitnami/postgresql - env: - - name: PG_HOST - value: {{ include "postgresql.serviceName" . | quote }} - - name: PG_PORT - value: {{ .Values.postgresql.service.port | quote }} - - name: PG_USER - value: {{ .Values.global.postgresql.postgresqlUsername | quote }} - - name: PGPASSWORD - valueFrom: - secretKeyRef: - name: {{ include "backend.postgresql.passwordSecret" .}} - key: postgresql-password - - name: PG_DBNAME - value: {{ .Values.appConfig.backend.database.connection.database }} - command: - - /bin/bash - - -ecx - - | - psql --host=$PG_HOST --port=$PG_PORT --username=$PG_USER --dbname=$PG_DBNAME --no-password - restartPolicy: Never -{{- end }} \ No newline at end of file diff --git a/contrib/chart/backstage/values.yaml b/contrib/chart/backstage/values.yaml deleted file mode 100644 index cd80fd954b..0000000000 --- a/contrib/chart/backstage/values.yaml +++ /dev/null @@ -1,216 +0,0 @@ -# Default values for backstage. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -frontend: - enabled: false - replicaCount: 1 - image: - repository: martinaif/backstage-k8s-demo-frontend - tag: test1 - pullPolicy: IfNotPresent - containerPort: 80 - serviceType: ClusterIP - resources: - requests: - memory: 128Mi - limits: - memory: 256Mi - -backend: - enabled: true - nodeEnv: development - demoData: true - replicaCount: 1 - image: - repository: martinaif/backstage-k8s-demo-backend - tag: 20210423T1550 - pullPolicy: IfNotPresent - containerPort: 7007 - serviceType: ClusterIP - postgresCertMountEnabled: true - resources: - requests: - memory: 512Mi - limits: - memory: 1024Mi - -lighthouse: - enabled: true - replicaCount: 1 - image: - repository: roadiehq/lighthouse-audit-service - tag: latest - pullPolicy: IfNotPresent - containerPort: 3003 - serviceType: ClusterIP - postgresCertMountEnabled: true - resources: - requests: - memory: 128Mi - limits: - memory: 256Mi - database: - connection: - port: - host: - user: - password: - database: lighthouse_audit_service - pathToDatabaseCa: - -nameOverride: '' -fullnameOverride: '' - -ingress: - annotations: - kubernetes.io/ingress.class: nginx - -issuer: - email: - clusterIssuer: 'letsencrypt-staging' - -global: - postgresql: - postgresqlUsername: backend-user - caFilename: ca.crt - nodeSelector: {} - -postgresql: - enabled: true - nameOverride: postgresql - tls: - enabled: true - certificatesSecret: backstage-postgresql-certs - certFilename: tls.crt - certKeyFilename: tls.key - volumePermissions: - enabled: true - initdbScriptsSecret: backstage-postgresql-initdb - -appConfig: - app: - baseUrl: https://demo.example.com - title: Backstage - backend: - baseUrl: https://demo.example.com - listen: - port: 7007 - cors: - origin: https://demo.example.com - database: - client: pg - connection: - database: backstage_plugin_catalog - host: - user: - port: - password: - ssl: - rejectUnauthorized: false - ca: - sentry: - organization: example-org-name - techdocs: - storageUrl: https://demo.example.com/api/techdocs/static/docs - requestUrl: https://demo.example.com/api/techdocs - lighthouse: - baseUrl: https://demo.example.com/lighthouse-api - rollbar: - organization: example-org-name - - # Auth config has recently moved into the app config file in upstream Backstage. However, - # most of this config simply mandates that items like the client id and client secret should - # be picked up from the environment variables named below. Those environment variables are - # set in this helm controlled environment by the 'auth' configuration below this section. - # Thus, the only key in this config which directly controls an app config is the - # auth.providers.github.development.appOrigin property. - auth: - providers: - google: - development: - appOrigin: 'http://localhost:3000/' - secure: false - clientId: ${AUTH_GOOGLE_CLIENT_ID} - clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET} - github: - development: - appOrigin: 'http://localhost:3000/' - secure: false - clientId: ${AUTH_GITHUB_CLIENT_ID} - clientSecret: ${AUTH_GITHUB_CLIENT_SECRET} - enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL} - gitlab: - development: - appOrigin: 'http://localhost:3000/' - secure: false - clientId: ${AUTH_GITLAB_CLIENT_ID} - clientSecret: ${AUTH_GITLAB_CLIENT_SECRET} - audience: ${GITLAB_BASE_URL} - okta: - development: - appOrigin: 'http://localhost:3000/' - secure: false - clientId: ${AUTH_OKTA_CLIENT_ID} - clientSecret: ${AUTH_OKTA_CLIENT_SECRET} - audience: ${AUTH_OKTA_AUDIENCE} - oauth2: - development: - appOrigin: 'http://localhost:3000/' - secure: false - clientId: ${AUTH_OAUTH2_CLIENT_ID} - clientSecret: ${AUTH_OAUTH2_CLIENT_SECRET} - authorizationURL: ${AUTH_OAUTH2_AUTH_URL} - tokenURL: ${AUTH_OAUTH2_TOKEN_URL} - auth0: - development: - clientId: ${AUTH_AUTH0_CLIENT_ID} - clientSecret: ${AUTH_AUTH0_CLIENT_SECRET} - domain: ${AUTH_AUTH0_DOMAIN} - microsoft: - development: - clientId: ${AUTH_MICROSOFT_CLIENT_ID} - clientSecret: ${AUTH_MICROSOFT_CLIENT_SECRET} - tenantId: ${AUTH_MICROSOFT_TENANT_ID} - -auth: - google: - clientId: a - clientSecret: a - github: - clientId: c - clientSecret: c - gitlab: - clientId: b - clientSecret: b - baseUrl: b - okta: - clientId: b - clientSecret: b - audience: b - oauth2: - clientId: b - clientSecret: b - authUrl: b - tokenUrl: b - auth0: - clientId: b - clientSecret: b - domain: b - microsoft: - clientId: f - clientSecret: f - tenantId: f - azure: - api: - token: h - sentryToken: e - rollbarAccountToken: f - # This is a 'Personal Access Token' - circleciAuthToken: r - # Used by the scaffolder to create GitHub repos. Must have 'repo' scope. - githubToken: g - gitlabToken: g - newRelicRestApiKey: r - travisciAuthToken: fake-travis-ci-auth-token - pagerdutyToken: h From 85313970b7f490c4b12bfc236edb116e99fb9a2a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:04:51 +0000 Subject: [PATCH 168/241] chore(deps): update snyk/actions digest to 1d672a4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/sync_snyk-github-issues.yml | 2 +- .github/workflows/sync_snyk-monitor.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index f1a91ed7e6..ec7c00111d 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -29,7 +29,7 @@ jobs: cache-prefix: ${{ runner.os }}-v18.x - name: Create Snyk report - uses: snyk/actions/node@3e2680e8df93a24b52d119b1305fb7cedc60ceae # master + uses: snyk/actions/node@1d672a455ab3339ef0a0021e1ec809165ee12fad # master continue-on-error: true # Snyk CLI exits with error when vulnerabilities are found with: args: > diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index c3f7af1550..04367c2639 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@v4.1.1 - name: Monitor and Synchronize Snyk Policies - uses: snyk/actions/node@3e2680e8df93a24b52d119b1305fb7cedc60ceae # master + uses: snyk/actions/node@1d672a455ab3339ef0a0021e1ec809165ee12fad # master with: command: monitor args: > @@ -46,7 +46,7 @@ jobs: # Above we run the `monitor` command, this runs the `test` command which is # the one that generates the SARIF report that we can upload to GitHub. - name: Create Snyk report - uses: snyk/actions/node@3e2680e8df93a24b52d119b1305fb7cedc60ceae # master + uses: snyk/actions/node@1d672a455ab3339ef0a0021e1ec809165ee12fad # master continue-on-error: true # To make sure that SARIF upload gets called with: args: > From 3bca2252d8a610a9ceaa01997727740689e503e1 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 17 Jan 2024 15:13:57 +0100 Subject: [PATCH 169/241] refactor(docs-frontend): do not show line numbers Signed-off-by: Camila Belo --- .../frontend-system/architecture/07-routes.md | 79 +++++++++++++------ 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 918fddb43c..1cf5ed8c68 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -26,7 +26,7 @@ There are 3 types of route references: regular route, sub route, and external ro Route references, also known as "absolute" or "regular" routes, are created as follows: -```tsx title="plugins/catalog/src/routes.ts" showLineNumbers +```tsx title="plugins/catalog/src/routes.ts" import { createRouteRef } from '@backstage/frontend-plugin-api'; // Creates a route reference, which is not yet associated with any plugin page @@ -41,7 +41,7 @@ Route refs do not have any behavior themselves. They are an opaque value that re The code snippet in the previous section does not indicate which plugin the route belongs to. To do so, you have to use it in the creation of any kind of routable extension, such as a page extension: -```tsx title="plugins/catalog/src/plugin.tsx" {11,17-19} showLineNumbers +```tsx title="plugins/catalog/src/plugin.tsx" import React from 'react'; import { createPlugin, @@ -52,25 +52,23 @@ import { indexRouteRef } from './routes'; const catalogIndexPage = createPageExtension({ // The `name` option is omitted because this is an index page defaultPath: '/entities', + // highlight-next-line routeRef: indexRouteRef, loader: () => import('./components').then(m => ), }); export default createPlugin({ id: 'catalog', + // highlight-start routes: { index: indexRouteRef, }, + // highlight-end extensions: [catalogIndexPage], }); ``` -In the example above we have associated a route ref with an plugin page. This is what the code does: - -- Line 11: Associates the `indexRouteRef` with the `catalogIndexPage` extension; -- Line 17 to 19: Provides both the `indexRouteRef` and `catalogIndexPage` via the Catalog plugin. - -When this extension is installed in the app it will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the extension. +In the example above we associated the `indexRouteRef` with the `catalogIndexPage` extension and provided both the route ref and page via the Catalog plugin. So, When this plugin is installed in the app, the index page will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the page extension. It may be unclear why we configure the routes option when creating a plugin as the route has already been passed to the extension. We do that to make it possible for other plugins to route to our page, which is explained in detail in the [binding routes](#binding-external-route-references) section. @@ -78,11 +76,12 @@ It may be unclear why we configure the routes option when creating a plugin as t Route references optionally accept a `params` option, which will require the listed parameter names to be present in the route path. Here is how you create a reference for a route that requires a `kind`, `namespace` and `name` parameters, like in this path `/entities/:kind/:namespace/:name`: -```tsx title="plugins/catalog/src/routes.ts" {5} showLineNumbers +```tsx title="plugins/catalog/src/routes.ts" import { createRouteRef } from '@backstage/frontend-plugin-api'; export const detailsRouteRef = createRouteRef({ // The parameters that must be included in the path of this route reference + // highlight-next-line params: ['kind', 'namespace', 'name'], }); ``` @@ -93,22 +92,25 @@ Route references can be used to link to page in the same plugin, or to pages in Suppose we are creating a plugin that renders a Catalog index page with a link to a "Foo" component details page. Here is the code for the index page: -```tsx title="plugins/catalog/src/components/IndexPage.tsx" {6,11-15} showLineNumbers +```tsx title="plugins/catalog/src/components/IndexPage.tsx" import React from 'react'; import { useRouteRef } from '@backstage/frontend-plugin-api'; import { detailsRouteRef } from '../routes'; export const IndexPage = () => { + // highlight-next-line const getDetailsPath = useRouteRef(detailsRouteRef); return (

Index Page

See "Foo" details @@ -121,27 +123,30 @@ We use the `useRouteRef` hook to create a link generator function that returns t Let's see how the details page can get the parameters from the URL: -```tsx title="plugins/catalog/src/components/DetailsPage.tsx" {6,11-13} showLineNumbers +```tsx title="plugins/catalog/src/components/DetailsPage.tsx" import React from 'react'; import { useRouteRefParams } from '@backstage/frontend-plugin-api'; import { detailsRouteRef } from '../routes'; export const DetailsPage = () => { + // highlight-next-line const params = useRouteRefParams(detailsRouteRef); return (

Details Page

    + {/* highlight-start */}
  • Kind: {params.kind}
  • Namespace: {params.namespace}
  • Name: {params.name}
  • + {/* highlight-end */}
); }; ``` -On line 6, we are using the `useRouteRefParams` hook to retrieve the entity-composed id from the URL. The parameter object contains three values: kind, namespace, and name. We can display these values or call an API using them. +In the code above, we are using the `useRouteRefParams` hook to retrieve the entity-composed id from the URL. The parameter object contains three values: kind, namespace, and name. We can display these values or call an API using them. Since we are linking to pages of the same package, we are using a route ref directly. However, in the following sections, you will see how to link to pages of different plugins. @@ -154,7 +159,7 @@ We don't want to reference the Scaffolder plugin directly, since that would crea We create a new `RouteRef` inside the Scaffolder plugin, using a neutral name that describes its role in the plugin rather than a specific plugin page that it might be linking to, allowing the app to decide the final target. If the Catalog entity list page for example wants to link the Scaffolder create component page in the header, it might declare an `ExternalRouteRef` similar to this: -```tsx title="plugins/catalog/src/routes.ts" showLineNumbers +```tsx title="plugins/catalog/src/routes.ts" import { createExternalRouteRef } from '@backstage/frontend-plugin-api'; export const createComponentExternalRouteRef = createExternalRouteRef(); @@ -162,16 +167,18 @@ export const createComponentExternalRouteRef = createExternalRouteRef(); External routes are also used in a similar way as regular routes: -```tsx title="plugins/catalog/src/components/IndexPage.tsx" {6,10} showLineNumbers +```tsx title="plugins/catalog/src/components/IndexPage.tsx" import React from 'react'; import { useRouteRef } from '@backstage/frontend-plugin-api'; import { createComponentExternalRouteRef } from '../routes'; export const IndexPage = () => { + // highlight-next-line const getCreateComponentPath = useRouteRef(createComponentExternalRouteRef); return (

Index Page

+ {/* highlight-next-line */} Create Component
); @@ -182,7 +189,7 @@ Given the above binding, using `useRouteRef(createComponentExternalRouteRef)` wi Now the only thing left is to provide the page and external route via a plugin: -```tsx title="plugins/catalog/src/plugin.tsx" {20-23} showLineNumbers +```tsx title="plugins/catalog/src/plugin.tsx" import React from 'react'; import { createPlugin, @@ -202,19 +209,22 @@ export default createPlugin({ routes: { index: indexRouteRef, }, + // highlight-start externalRoutes: { createComponent: createComponentExternalRouteRef, }, extensions: [catalogIndexPage], + // highlight-end }); ``` External routes can also have parameters. For example, if you want to link to an entity's details page from Scaffolder, you'll need to create an external route that receives the same parameters the Catalog details page expects: -```tsx title="plugins/scaffolder/src/routes.ts" {4} showLineNumbers +```tsx title="plugins/scaffolder/src/routes.ts" import { createExternalRouteRef } from '@backstage/frontend-plugin-api'; export const entityDetailsExternalRouteRef = createExternalRouteRef({ + // highlight-next-line params: ['kind', 'namespace', 'name'], }); ``` @@ -227,24 +237,27 @@ The association of external routes is controlled by the app. Each `ExternalRoute Using the above example of the Catalog entities list page to the Scaffolder create component page, we might do something like this in the app configuration file: -```yaml title="app-config.yaml" {5,7} showLineNumbers +```yaml title="app-config.yaml" app: routes: bindings: # point to the Scaffolder create component page when the Catalog create component ref is used + # highlight-next-line plugin.catalog.externalRoutes.createComponent: plugin.scaffolder.routes.index # point to the Catalog details page when the Scaffolder component details ref is used + # highlight-next-line plugin.scaffolder.externalRoutes.componentDetails: plugin.catalog.routes.details ``` We also have the ability to express this in code as an option to `createApp`, but you of course only need to use one of these two methods: -```tsx title="packages/app/src/App.tsx" {6-13} showLineNumbers +```tsx title="packages/app/src/App.tsx" import { createApp } from '@backstage/frontend-app-api'; import catalog from '@backstage/plugin-catalog'; import scaffolder from '@backstage/plugin-scaffolder'; const app = createApp({ + // highlight-start bindRoutes({ bind }) { bind(catalog.externalRoutes, { createComponent: scaffolder.routes.createComponent, @@ -253,6 +266,7 @@ const app = createApp({ componentDetails: catalog.routes.details, }); }, + // highlight-end }); export default app.createRoot(); @@ -266,17 +280,18 @@ Another thing to note is that this indirection in the routing is particularly us It is possible to define an `ExternalRouteRef` as optional, so it is not required to bind it in the app. -```tsx title="plugins/catalog/src/routes.ts" {4} showLineNumbers +```tsx title="plugins/catalog/src/routes.ts" import { createExternalRouteRef } from '@backstage/frontend-plugin-api'; export const createComponentExternalRouteRef = createExternalRouteRef({ + // highlight-next-line optional: true, }); ``` When calling `useRouteRef` with an optional external route, its return signature is changed to `RouteFunc | undefined`, and the returned value can be used to decide whether a certain link should be displayed or if an action should be taken: -```tsx title="plugins/catalog/src/components/IndexPage.tsx" {11} showLineNumbers +```tsx title="plugins/catalog/src/components/IndexPage.tsx" import React from 'react'; import { useRouteRef } from '@backstage/frontend-plugin-api'; import { createComponentExternalRouteRef } from '../routes'; @@ -287,9 +302,11 @@ export const IndexPage = () => {

Index Page

{/* Rendering the link only if the getCreateComponentPath is defined */} + {/* highlight-start */} {getCreateComponentPath && ( Create Component )} + {/* highlight-end */}
); }; @@ -301,32 +318,35 @@ The last kind of route refs that can be created are `SubRouteRef`s, which can be For example: -```tsx title ="plugins/catalog/src/routes.ts" {4,7} showLineNumbers +```tsx title ="plugins/catalog/src/routes.ts" import { createRouteRef, createSubRouteRef, } from '@backstage/frontend-plugin-api'; export const indexRouteRef = createRouteRef(); +// highlight-start export const detailsSubRouteRef = createSubRouteRef({ parent: indexRouteRef, path: '/details', }); +// highlight-end ``` There are substantial differences between creating subroutes and regular or external routes because subroutes are associated with regular routes, and the sub route path must be specified. The path string must include the parameters if this sub route has them: -```tsx title ="plugins/catalog/src/routes.ts" {4} showLineNumbers +```tsx title ="plugins/catalog/src/routes.ts" // Omitting rest of the previous example file export const detailsSubRouteRef = createSubRouteRef({ parent: indexRouteRef, + // highlight-next-line path: '/:name/:namespace/:kind', }); ``` Using subroutes in a page extension is as simple as this: -```tsx title="plugins/catalog/src/components/IndexPage.ts" showLineNumbers +```tsx title="plugins/catalog/src/components/IndexPage.ts" import React from 'react'; import { Routes, Route, useLocation } from 'react-router-dom'; import { useRouteRef } from '@backstage/frontend-plugin-api'; @@ -342,8 +362,9 @@ export const IndexPage = () => {

Index Page

{/* Linking to the details sub route */} {pathname === getIndexPath() ? ( - // Setting the details sub route params + // highlight-start { > Show details + // highlight-end ) : ( + // highlight-next-line Hide details )} {/* Registering the details sub route */} @@ -366,19 +389,22 @@ export const IndexPage = () => { This is how you can get the parameters of a sub route URL: -```tsx title="plugins/catalog/src/components/DetailsPage.ts" {5} showLineNumbers +```tsx title="plugins/catalog/src/components/DetailsPage.ts" import React from 'react'; import { useParams } from 'react-router-dom'; export const DetailsPage = () => { + // highlight-next-line const params = useParams(); return (

Details Sub Page

    + {/* highlight-start */}
  • Kind: {params.kind}
  • Namespace: {params.namespace}
  • Name: {params.name}
  • + {/* highlight-end */}
); @@ -387,7 +413,7 @@ export const DetailsPage = () => { Finally, see how a plugin can provide subroutes: -```tsx title="plugins/catalog/src/plugin.ts" {18} showLineNumbers +```tsx title="plugins/catalog/src/plugin.ts" import React from 'react'; import { createPlugin, @@ -405,6 +431,7 @@ export default createPlugin({ id: 'catalog', routes: { index: indexRouteRef, + // highlight-next-line details: detailsSubRouteRef, }, extensions: [catalogIndexPage], From f37ba7c0b5407d12954387c2528d80ec109c0107 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:14:24 +0000 Subject: [PATCH 170/241] fix(deps): update dependency isomorphic-git to v1.25.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index b9ab306f65..ccfd1ec70b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30340,8 +30340,8 @@ __metadata: linkType: hard "isomorphic-git@npm:^1.23.0": - version: 1.25.2 - resolution: "isomorphic-git@npm:1.25.2" + version: 1.25.3 + resolution: "isomorphic-git@npm:1.25.3" dependencies: async-lock: ^1.1.0 clean-git-ref: ^2.0.1 @@ -30356,7 +30356,7 @@ __metadata: simple-get: ^4.0.1 bin: isogit: cli.cjs - checksum: b8e7a1b66c393ac1ab30fd0deb561b97e4ca249aad97367f11be8ed18b20132460bec89451752e3533e64a5a8c47b3509dc5a7dee2eea266c812b45df633b441 + checksum: 747da1bd0435898a02f8c1ba07ce66c704ea311338b66a44830a5ce1fe9a256a3ea1ec9be5baa087f88134aa686b5d0c6dc2b9338b1fd523f2869ef2480e4d4e languageName: node linkType: hard From a66ae33632d33343c3204ceb3afb31c5e089d4f6 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 17 Jan 2024 15:20:25 +0100 Subject: [PATCH 171/241] refactor(docs-frontend): update intro section Signed-off-by: Camila Belo --- docs/frontend-system/architecture/07-routes.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 1cf5ed8c68..60bf335158 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -12,12 +12,10 @@ description: Frontend routes Each Backstage plugin is an isolated piece of functionality that doesn't typically communicate directly with other plugins. In order to achieve this, there are many parts of the frontend system that provide a layer of indirection for cross-plugin communication, and they routing system is one of them. -The Backstage routing system makes it possible to implement navigation across plugin boundaries, without each individual plugin knowing the concrete path or location of other plugins in the routing hierarchy, or even its own. This is achieved through the concept of route references, which are opaque reference values that can be shared and used to create concrete links to different parts of an app. +The Backstage routing system makes it possible to implement navigation across plugin boundaries, without each individual plugin knowing the concrete path or location of other plugins in the routing hierarchy, or even its own. This is achieved through the concept of route references, which are opaque reference values that can be shared and used to create concrete links to different parts of an app. The route ref paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). It is up to plugin developers to create route references for any page content in their plugin that they want it to be possible to link to or from. ## Route References -A `RouteRef` is an abstract path in a Backstage app, and these paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). It is up to plugin developers to create route references for any page content in their plugin that they want it to be possible to link to or from. - Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sections). There are 3 types of route references: regular route, sub route, and external route, and we will cover both the concept and code definition for each. From bd0e1f062763e409f27b0c1e698fb2b568b58b64 Mon Sep 17 00:00:00 2001 From: Philipp Hugenroth Date: Wed, 17 Jan 2024 15:59:18 +0100 Subject: [PATCH 172/241] Update adr011-plugin-package-structure.md Signed-off-by: Philipp Hugenroth --- docs/architecture-decisions/adr011-plugin-package-structure.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/architecture-decisions/adr011-plugin-package-structure.md b/docs/architecture-decisions/adr011-plugin-package-structure.md index 2def903dfc..8e4b5435f9 100644 --- a/docs/architecture-decisions/adr011-plugin-package-structure.md +++ b/docs/architecture-decisions/adr011-plugin-package-structure.md @@ -7,8 +7,7 @@ description: Architecture Decision Record (ADR) for Plugin Package Structure ## Context -A core feature of Backstage is the extensibility via plugins. The Backstage -repository is open for contributions of plugins. Even most of the core features +A core feature of Backstage is the extensibility via plugins. Even most of the core features are implemented as plugins. A plugin consists of one or multiple packages in the `plugins/` directory. Up till now, we have a simple conventions for naming plugin packages: Plugins are named `x`, with the option of having a related From e7e542bd0519cb6ade61b7e37b7c41f72b924dc3 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 18 Dec 2023 15:40:25 +0100 Subject: [PATCH 173/241] docs: draft extension overrides arch Signed-off-by: Camila Belo --- .../architecture/05-extension-overrides.md | 105 +++++++++++++++--- 1 file changed, 87 insertions(+), 18 deletions(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index e722145552..20476c24b0 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -10,38 +10,107 @@ description: Frontend extension overrides ## Introduction - +- When you just want to configure a plugin, such as changing the attachment point, a path or any other setting. Be sure to read the extension documentation before overriding an extension to make sure you cannot configure it to work the way you want; +- It is already possible to enable an extension that is already provided by the plugin. Imagine we have a Search plugin that provides a default search result item extension for rendering search results. Consider also that we have a Catalog plugin with a disabled Catalog search result item extension. To change the way Catalog search result items are rendered, you don't need to override the default result item extension. The only thing you need to do is enable the Catalog search result extension via the config file. For other types of search results, the default Search result item will continue to be used. -## Creating a Extension Override +## Creating an Extension Override - +For this example, we are creating overrides for the light and dark theme extensions and exporting the overrides from the plugin index file. Now we are able to use the overrides in a Backstage app: + +```tsx +// packages/app/src/App.tsx +import { createApp } from '@backstage/frontend-app-api'; +import apertureOverrides from ‘@backstage/plugin-aperture-overrides’ + +const app = createApp({ + features: [ apertureOverrides ], +}); + +export default app.createRoot(). +``` + +If the plugin you want to change is internal to your company or you just want to replace one of the application's core extensions, you can decide to create replacements directly in the application for local replacements. See an example below: + +```tsx +// packages/app/src/themes.ts +import { createExtensionOverrides } from from '@backstage/frontend-plugin-api'; + +// Creating the light theme extension; +export const apertureLightTheme = createThemeApi({ … }); + +// Creating the light theme extension; +const apertureDarkTheme = createThemeApi({ … }); + +// Exporting your custom extensions +export default [apertureLightTheme, apertureDarkTheme]; + +// packages/app/src/App.tsx +import { createApp } from '@backstage/frontend-app-api'; +import themes from ‘./themes’ + +const app = createApp({ + features: [ + createExtensionOverrides({ + extensions: [ + ...themes, + ], + }), + ], +}); + +export default app.createRoot(); +``` + +Note that it can still be a good idea to split your overrides out into separate packages in large projects. But it's up to you to decide how to group the extensions into extension overrides. ## Overriding Existing Extensions - +We recommend that plugin developes share the extension ids in their plugin documentations, but usually you can infer the id by following the (Naming pattern)[./08-naming-patterns] standars. From f6909fee983aaf2961b63086e724a545b1bba734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 22 Dec 2023 14:34:08 +0100 Subject: [PATCH 174/241] Update docs/frontend-system/architecture/05-extension-overrides.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Signed-off-by: Fredrik Adelöw --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 20476c24b0..2bceab52d9 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -42,7 +42,7 @@ const apertureDarkTheme = createThemeApi({ … }); // Creating an extension overrides preset export createExtensionOverrides({ - Extensions: [apertureLightTheme, apertureDarkTheme] + extensions: [apertureLightTheme, apertureDarkTheme] }); // plugins/aperture-overrides/src/index.ts From 27aa7dc95780976723e18b101db889fd19e32fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 22 Dec 2023 14:34:15 +0100 Subject: [PATCH 175/241] Update docs/frontend-system/architecture/05-extension-overrides.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Signed-off-by: Fredrik Adelöw --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 2bceab52d9..cfb590d217 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -37,7 +37,7 @@ import { // Creating a light theme extension; const apertureLightTheme = createThemeApi({ … }); -// Creating a light theme extension; +// Creating a dark theme extension; const apertureDarkTheme = createThemeApi({ … }); // Creating an extension overrides preset From 2827fc2ba91fda463b90fcfac65c3e8022166ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 22 Dec 2023 14:34:39 +0100 Subject: [PATCH 176/241] Update docs/frontend-system/architecture/05-extension-overrides.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Signed-off-by: Fredrik Adelöw --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index cfb590d217..facae81e21 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -101,7 +101,7 @@ Note that it can still be a good idea to split your overrides out into separate To override an existing extension (which is already provided by a plugin), you need to provide an extension that has the same ID as the existing extension. That is, all kind, namespaces, and name must match the extension you want to replace. This means that you typically need to provide an explicit namespace when overriding extensions from a plugin. -Imagine that we have a plugin with search id and the plugin provides a search page extension that you want to fully override with your own custom component. To do so, you have to create your page extension and inform to the extension factory that the extension namespace is search to make sure you are overriding the search page of the plugin with id 'search' and not creating a anonymous page that will not override thesearch plugin one. +Imagine you have a plugin with the ID `'search'`, and the plugin provides a page extension that you want to fully override with your own custom component. To do so, you need to create your page extension with an explicit `namespace` option that matches that of the plugin that you want to override, in this case `'search'`. If the existing extension also has an explicit `name` you'd need to set the `name` of your override extension to the same value as well. ```tsx // packages/app/src/search.ts From 564f731e964e960d2e1bd4970d687e88345113b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 22 Dec 2023 14:34:47 +0100 Subject: [PATCH 177/241] Update docs/frontend-system/architecture/05-extension-overrides.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patrik Oldsberg Signed-off-by: Fredrik Adelöw --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index facae81e21..4ee859709b 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -113,4 +113,4 @@ const customSearchPage = createPageExtension({ }); ``` -We recommend that plugin developes share the extension ids in their plugin documentations, but usually you can infer the id by following the (Naming pattern)[./08-naming-patterns] standars. +We recommend that plugin developes share the extension IDs in their plugin documentations, but usually you can infer the id by following the (Naming pattern)[./08-naming-patterns] standars. From ebc63612ace1318e5a51d44f187a9191245cf93e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 22 Dec 2023 15:15:13 +0100 Subject: [PATCH 178/241] address some of the comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .github/vale/Vocab/Backstage/accept.txt | 4 +++- .../architecture/05-extension-overrides.md | 15 +++------------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/Vocab/Backstage/accept.txt index d557434d78..dc0b74b98c 100644 --- a/.github/vale/Vocab/Backstage/accept.txt +++ b/.github/vale/Vocab/Backstage/accept.txt @@ -312,6 +312,8 @@ rebase rebasing Recharts Redash +renderer +renderers replicasets repo Repo @@ -463,4 +465,4 @@ zod Zolotusky zoomable zsh -scrollable \ No newline at end of file +scrollable diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 4ee859709b..6317783347 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -10,18 +10,9 @@ description: Frontend extension overrides ## Introduction -An extension override is another building block in the Frontend System that allows you to programmatically override app or plugin extensions. Extension overrides are recommended in the following cases: +An extension override is a building block of the Frontend System that allows you to programmatically override app or plugin extensions anywhere in your application. Since the entire application is built mostly out of extensions from the bottom up, this is a powerful feature. You can use it for example to provide your own app root layout, to replace the implementation of a Utility API with your a custom one, to override how the catalog page renders itself, and much more. -- Override the app skeleton layout; -- Override a default api implementation; -- Override a default app component; -- Override a plugin's default page; -- Etc. - -It is also important to clarify when an override isn't needed. Creating an extension override is not recommended when: - -- When you just want to configure a plugin, such as changing the attachment point, a path or any other setting. Be sure to read the extension documentation before overriding an extension to make sure you cannot configure it to work the way you want; -- It is already possible to enable an extension that is already provided by the plugin. Imagine we have a Search plugin that provides a default search result item extension for rendering search results. Consider also that we have a Catalog plugin with a disabled Catalog search result item extension. To change the way Catalog search result items are rendered, you don't need to override the default result item extension. The only thing you need to do is enable the Catalog search result extension via the config file. For other types of search results, the default Search result item will continue to be used. +Note that in general, most features should have a good level of customizability built into themselves, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has app-config settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should be taken advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation if available for guidance. ## Creating an Extension Override @@ -113,4 +104,4 @@ const customSearchPage = createPageExtension({ }); ``` -We recommend that plugin developes share the extension IDs in their plugin documentations, but usually you can infer the id by following the (Naming pattern)[./08-naming-patterns] standars. +We recommend that plugin developes share the extension IDs in their plugin documentation, but usually you can infer the ID by following the (naming patterns)[./08-naming-patterns] documentation. From 445a8dc1d31d783fab5dc505d63f92a84a42f6d1 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Fri, 12 Jan 2024 15:05:05 +0100 Subject: [PATCH 179/241] refactor: apply review sugggestions Signed-off-by: Camila Belo --- .../architecture/05-extension-overrides.md | 89 +++++++++---------- 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 6317783347..17daef6b6c 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -14,38 +14,63 @@ An extension override is a building block of the Frontend System that allows you Note that in general, most features should have a good level of customizability built into themselves, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has app-config settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should be taken advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation if available for guidance. -## Creating an Extension Override +## Overriding App Extensions -The following steps should be followed to override extensions: +If you want to override an app extension, you will need to create a new extension to replace the existing one and add it to the list of overridden features. The steps are: + +1. Create your extension overrides + +In this example below, we are going to create custom extensions for the app light and dark themes: ```tsx -// plugins/aperture-overrides/src/overrides.ts +// packages/app/src/themes.ts import { - createThemeApi, + createThemeExtension, createExtensionOverrides } from '@backstage/frontend-plugin-api'; +import { apertureThemes } from './themes'; +import { ApertureLightIcon, ApertureDarkIcon } from './icons'; // Creating a light theme extension; -const apertureLightTheme = createThemeApi({ … }); +const apertureLightTheme = createThemeExtension({ + namespace: 'app', + name: 'light', + title: 'Aperture Light Theme', + variant: 'light', + icon: , + Provider: ({ children }) => ( + + ), +}); // Creating a dark theme extension; -const apertureDarkTheme = createThemeApi({ … }); +const apertureDarkTheme = createThemeExtension({ + namespace: 'app', + name: 'dark', + title: 'Aperture Dark Theme', + variant: 'dark', + icon: , + Provider: ({ children }) => ( + + ), +}); // Creating an extension overrides preset export createExtensionOverrides({ extensions: [apertureLightTheme, apertureDarkTheme] }); - -// plugins/aperture-overrides/src/index.ts -export { default } from './overrides'; ``` -For this example, we are creating overrides for the light and dark theme extensions and exporting the overrides from the plugin index file. Now we are able to use the overrides in a Backstage app: +We exported the overrides for the light and dark app theme extensions from a separate file in the code snippet above. To override the default app's light and dark theme extensions, we must ensure that the extension namespace and name match the ones in the default app themes extension definitions. + +2. Use the overrides in your Backstage App + +Now we are able to use the overrides in a Backstage app: ```tsx // packages/app/src/App.tsx import { createApp } from '@backstage/frontend-app-api'; -import apertureOverrides from ‘@backstage/plugin-aperture-overrides’ +import apertureOverrides from '@backstage/plugin-aperture-overrides' const app = createApp({ features: [ apertureOverrides ], @@ -54,43 +79,13 @@ const app = createApp({ export default app.createRoot(). ``` -If the plugin you want to change is internal to your company or you just want to replace one of the application's core extensions, you can decide to create replacements directly in the application for local replacements. See an example below: - -```tsx -// packages/app/src/themes.ts -import { createExtensionOverrides } from from '@backstage/frontend-plugin-api'; - -// Creating the light theme extension; -export const apertureLightTheme = createThemeApi({ … }); - -// Creating the light theme extension; -const apertureDarkTheme = createThemeApi({ … }); - -// Exporting your custom extensions -export default [apertureLightTheme, apertureDarkTheme]; - -// packages/app/src/App.tsx -import { createApp } from '@backstage/frontend-app-api'; -import themes from ‘./themes’ - -const app = createApp({ - features: [ - createExtensionOverrides({ - extensions: [ - ...themes, - ], - }), - ], -}); - -export default app.createRoot(); -``` +If the plugin you want to change is internal to your company or you just want to replace one of the application's core extensions, you can decide to store the overrides code directly in the app package or extract them to a separate package. Note that it can still be a good idea to split your overrides out into separate packages in large projects. But it's up to you to decide how to group the extensions into extension overrides. -## Overriding Existing Extensions +## Overriding Plugin Extensions -To override an existing extension (which is already provided by a plugin), you need to provide an extension that has the same ID as the existing extension. That is, all kind, namespaces, and name must match the extension you want to replace. This means that you typically need to provide an explicit namespace when overriding extensions from a plugin. +To override an extension that is provided by a plugin, you need to provide an new extension that has the same ID as the existing extension. That is, all kind, namespace, and name options must match the extension you want to replace. This means that you typically need to provide an explicit namespace when overriding extensions from a plugin. Imagine you have a plugin with the ID `'search'`, and the plugin provides a page extension that you want to fully override with your own custom component. To do so, you need to create your page extension with an explicit `namespace` option that matches that of the plugin that you want to override, in this case `'search'`. If the existing extension also has an explicit `name` you'd need to set the `name` of your override extension to the same value as well. @@ -98,9 +93,9 @@ Imagine you have a plugin with the ID `'search'`, and the plugin provides a page // packages/app/src/search.ts const customSearchPage = createPageExtension({ namespace: 'search', - // Omitting name since it is the root plugin page - defaultPath: 'search' - loader: async () =>
My custom search page + // Omitting name since it is the index plugin page + defaultPath: 'search', + loader: () => Promise.resolve(
My custom search page
), }); ``` From deeb5f70fda95b10fc412d82d4aa78b94fd48426 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 15 Jan 2024 22:41:57 +0100 Subject: [PATCH 180/241] Update docs/frontend-system/architecture/05-extension-overrides.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 17daef6b6c..53f5ad8b1d 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -12,7 +12,7 @@ description: Frontend extension overrides An extension override is a building block of the Frontend System that allows you to programmatically override app or plugin extensions anywhere in your application. Since the entire application is built mostly out of extensions from the bottom up, this is a powerful feature. You can use it for example to provide your own app root layout, to replace the implementation of a Utility API with your a custom one, to override how the catalog page renders itself, and much more. -Note that in general, most features should have a good level of customizability built into themselves, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has app-config settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should be taken advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation if available for guidance. +Note that in general, most features should have a good level of customizability built into themselves, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has app-config settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should take advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation if available for guidance. ## Overriding App Extensions From 147d7a4067a5b112dcbb7a208fc77c0baa3e16ad Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 15 Jan 2024 22:42:32 +0100 Subject: [PATCH 181/241] Update docs/frontend-system/architecture/05-extension-overrides.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 53f5ad8b1d..03ead23537 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -22,8 +22,7 @@ If you want to override an app extension, you will need to create a new extensio In this example below, we are going to create custom extensions for the app light and dark themes: -```tsx -// packages/app/src/themes.ts +```tsx title="packages/app/src/themes.ts" import { createThemeExtension, createExtensionOverrides From 7066b00773acf715a51e7694205e4ec8c95f9289 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 15 Jan 2024 22:42:38 +0100 Subject: [PATCH 182/241] Update docs/frontend-system/architecture/05-extension-overrides.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 03ead23537..5dff6a3ccd 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -93,7 +93,7 @@ Imagine you have a plugin with the ID `'search'`, and the plugin provides a page const customSearchPage = createPageExtension({ namespace: 'search', // Omitting name since it is the index plugin page - defaultPath: 'search', + defaultPath: '/search', loader: () => Promise.resolve(
My custom search page
), }); ``` From d45d5bc879ab128e11d2c5cf081cb989ff709fdd Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Mon, 15 Jan 2024 23:50:34 +0100 Subject: [PATCH 183/241] docs(frontend-system): add orphan extension overrides section Signed-off-by: Camila Belo --- .../architecture/05-extension-overrides.md | 91 +++++++++++++++---- 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 5dff6a3ccd..572018606e 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -16,13 +16,13 @@ Note that in general, most features should have a good level of customizability ## Overriding App Extensions -If you want to override an app extension, you will need to create a new extension to replace the existing one and add it to the list of overridden features. The steps are: +In order to override an app extension, you must create a new extension and add it to the list of overridden features. The steps are: create your extension overrides and use them in Backstage. -1. Create your extension overrides +### Example -In this example below, we are going to create custom extensions for the app light and dark themes: +In the example below, we create a file that exports custom extensions for the app's `light` and `dark` themes: -```tsx title="packages/app/src/themes.ts" +```tsx title="packages/app/src/themes.ts" {10-11,22-23} showLineNumbers import { createThemeExtension, createExtensionOverrides @@ -30,7 +30,7 @@ import { import { apertureThemes } from './themes'; import { ApertureLightIcon, ApertureDarkIcon } from './icons'; -// Creating a light theme extension; +// Creating a light theme extension const apertureLightTheme = createThemeExtension({ namespace: 'app', name: 'light', @@ -42,7 +42,7 @@ const apertureLightTheme = createThemeExtension({ ), }); -// Creating a dark theme extension; +// Creating a dark theme extension const apertureDarkTheme = createThemeExtension({ namespace: 'app', name: 'dark', @@ -60,16 +60,13 @@ export createExtensionOverrides({ }); ``` -We exported the overrides for the light and dark app theme extensions from a separate file in the code snippet above. To override the default app's light and dark theme extensions, we must ensure that the extension namespace and name match the ones in the default app themes extension definitions. - -2. Use the overrides in your Backstage App +Lines `10` and `22` should be highlighted because they declare `namespace` as `'app'`, so the system knows we are overriding app extensions. Additionally, to specifically override the `light` and `dark` theme extensions, we set the `name` option to `light` and `dark` respectively on lines `11` and `23`. Therefore, to override app theme extensions, we ensure that the extension `namespace` and `name` match those of the default app theme extension definitions. Now we are able to use the overrides in a Backstage app: -```tsx -// packages/app/src/App.tsx +```tsx title="packages/app/src/App.tsx" {5} showLineNumbers import { createApp } from '@backstage/frontend-app-api'; -import apertureOverrides from '@backstage/plugin-aperture-overrides' +import apertureOverrides from './themes'; const app = createApp({ features: [ apertureOverrides ], @@ -84,18 +81,78 @@ Note that it can still be a good idea to split your overrides out into separate ## Overriding Plugin Extensions -To override an extension that is provided by a plugin, you need to provide an new extension that has the same ID as the existing extension. That is, all kind, namespace, and name options must match the extension you want to replace. This means that you typically need to provide an explicit namespace when overriding extensions from a plugin. +To override an extension that is provided by a plugin, you need to provide an new extension that has the same ID as the existing extension. That is, all kind, namespace, and name options must match the extension you want to replace. This means that you typically need to provide an explicit `namespace` when overriding extensions from a plugin. + +:::info +We recommend that plugin developers share the extension IDs in their plugin documentation, but usually you can infer the ID by following the [naming patterns](./08-naming-patterns.md) documentation. +::: + +### Example Imagine you have a plugin with the ID `'search'`, and the plugin provides a page extension that you want to fully override with your own custom component. To do so, you need to create your page extension with an explicit `namespace` option that matches that of the plugin that you want to override, in this case `'search'`. If the existing extension also has an explicit `name` you'd need to set the `name` of your override extension to the same value as well. -```tsx -// packages/app/src/search.ts +```tsx title="packages/app/src/search.ts" showLineNumbers +import { createPageExtension } from '@backstage/frontend-plugin-api'; + +// Creating a custom search page extension const customSearchPage = createPageExtension({ namespace: 'search', // Omitting name since it is the index plugin page defaultPath: '/search', - loader: () => Promise.resolve(
My custom search page
), + loader: () => import('./SearchPage').then(m => m.), +}); + +export createExtensionOverrides({ + extensions: [customSearchPage] }); ``` -We recommend that plugin developes share the extension IDs in their plugin documentation, but usually you can infer the ID by following the (naming patterns)[./08-naming-patterns] documentation. +Don't forget to configure your overrides in the `createApp` function: + +```tsx title="packages/app/src/App.tsx" {5} showLineNumbers +import { createApp } from '@backstage/frontend-app-api'; +import searchOverrides from './search'; + +const app = createApp({ + features: [searchOverrides], +}); + +export default app.createRoot(); +``` + +Now let's talk about the last override case, orphan extensions. + +## Creating Orphan Extensions + +Sometimes you just need to quickly create a new extension and not overwrite an app extension or plugin. You can also use overrides to create extensions, but remember that if you want to make this extension available for installation by other users, we recommend providing it via a plugin in a separate package. + +### Example + +Imagine you want to create a page that is currently only used by your application, like an Institutional page for example, you can use overrides to extend the Backstage app to render it. To do so, simply create a page extension and pass it to the app as an override: + +```tsx title="packages/app/src/App.ts" showLineNumbers +import { createApp } from '@backstage/frontend-app-api'; +import { + createPageExtension, + createExtensionOverrides, +} from '@backstage/frontend-plugin-api'; + +const app = createApp({ + features: [ + createExtensionOverrides({ + extensions: [ + createPageExtension({ + name: 'institutional', + defaultPath: '/institutional', + loader: () => + import('./institutional').then(m => ), + }), + ], + }), + ], +}); + +export default app.createRoot(); +``` + +Note that we are omitting `namespace` when creating the page extension. When we omit `namespace`, we are telling the system the new extension is orphaned (not an application or plugin extension) and this is all about orphaned extensions! From 6d1d2967b313728f9d92939242edeb9870877d2a Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 16 Jan 2024 12:26:30 +0100 Subject: [PATCH 184/241] Update docs/frontend-system/architecture/05-extension-overrides.md Co-authored-by: Philipp Hugenroth Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 572018606e..5a40bd079c 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -12,7 +12,7 @@ description: Frontend extension overrides An extension override is a building block of the Frontend System that allows you to programmatically override app or plugin extensions anywhere in your application. Since the entire application is built mostly out of extensions from the bottom up, this is a powerful feature. You can use it for example to provide your own app root layout, to replace the implementation of a Utility API with your a custom one, to override how the catalog page renders itself, and much more. -Note that in general, most features should have a good level of customizability built into themselves, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has app-config settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should take advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation if available for guidance. +In general, most features should have a good level of customization built into them, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has `app-config` settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin, which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should take advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation for guidance. ## Overriding App Extensions From e0e6e853b2953f8146b5abdd6843879bb90e78d0 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 16 Jan 2024 12:27:03 +0100 Subject: [PATCH 185/241] Update docs/frontend-system/architecture/05-extension-overrides.md Co-authored-by: Philipp Hugenroth Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 5a40bd079c..52c76a4673 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -128,7 +128,7 @@ Sometimes you just need to quickly create a new extension and not overwrite an a ### Example -Imagine you want to create a page that is currently only used by your application, like an Institutional page for example, you can use overrides to extend the Backstage app to render it. To do so, simply create a page extension and pass it to the app as an override: +Imagine you want to create a page that is currently only used by your application, like an Institutional page, for example. You can use overrides to extend the Backstage app to render it. To do so, simply create a page extension and pass it to the app as an override: ```tsx title="packages/app/src/App.ts" showLineNumbers import { createApp } from '@backstage/frontend-app-api'; From e761ab547116b26853c51ff1aee122dd37ae8d78 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 16 Jan 2024 12:27:19 +0100 Subject: [PATCH 186/241] Update docs/frontend-system/architecture/05-extension-overrides.md Co-authored-by: Philipp Hugenroth Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 52c76a4673..618efefc56 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -155,4 +155,4 @@ const app = createApp({ export default app.createRoot(); ``` -Note that we are omitting `namespace` when creating the page extension. When we omit `namespace`, we are telling the system the new extension is orphaned (not an application or plugin extension) and this is all about orphaned extensions! +Note that we are omitting `namespace` when creating the page extension. When we omit `namespace`, we are telling the system the new extension is orphaned and not an application or plugin extension! From bf48a5bb8f7d25dd38df5dab734cf781395bc0b4 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 16 Jan 2024 12:27:39 +0100 Subject: [PATCH 187/241] Update docs/frontend-system/architecture/05-extension-overrides.md Co-authored-by: Philipp Hugenroth Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 618efefc56..996f60f77d 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -81,7 +81,7 @@ Note that it can still be a good idea to split your overrides out into separate ## Overriding Plugin Extensions -To override an extension that is provided by a plugin, you need to provide an new extension that has the same ID as the existing extension. That is, all kind, namespace, and name options must match the extension you want to replace. This means that you typically need to provide an explicit `namespace` when overriding extensions from a plugin. +To override an extension that is provided by a plugin, you need to provide a new extension that has the same ID as the existing extension. That is, all kind, namespace, and name options must match the extension you want to replace. This means that you typically need to provide an explicit `namespace` when overriding extensions from a plugin. :::info We recommend that plugin developers share the extension IDs in their plugin documentation, but usually you can infer the ID by following the [naming patterns](./08-naming-patterns.md) documentation. From b144eba4a536e259f667433fe40a0855caf2ee19 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 16 Jan 2024 12:28:52 +0100 Subject: [PATCH 188/241] Update docs/frontend-system/architecture/05-extension-overrides.md Co-authored-by: Philipp Hugenroth Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 996f60f77d..d51ebcea93 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -14,7 +14,7 @@ An extension override is a building block of the Frontend System that allows you In general, most features should have a good level of customization built into them, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has `app-config` settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin, which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should take advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation for guidance. -## Overriding App Extensions +## Override App Extensions In order to override an app extension, you must create a new extension and add it to the list of overridden features. The steps are: create your extension overrides and use them in Backstage. From 012b38c8812745bd07c5896bb0af4905bdd6fb3f Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 16 Jan 2024 12:29:01 +0100 Subject: [PATCH 189/241] Update docs/frontend-system/architecture/05-extension-overrides.md Co-authored-by: Philipp Hugenroth Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index d51ebcea93..ffe8ff11c4 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -10,7 +10,7 @@ description: Frontend extension overrides ## Introduction -An extension override is a building block of the Frontend System that allows you to programmatically override app or plugin extensions anywhere in your application. Since the entire application is built mostly out of extensions from the bottom up, this is a powerful feature. You can use it for example to provide your own app root layout, to replace the implementation of a Utility API with your a custom one, to override how the catalog page renders itself, and much more. +An extension override is a building block of the frontend system that allows you to programmatically override app or plugin extensions anywhere in your application. Since the entire application is built mostly out of extensions from the bottom up, this is a powerful feature. You can use it for example to provide your own app root layout, to replace the implementation of a Utility API with a custom one, to override how the catalog page renders itself, and much more. In general, most features should have a good level of customization built into them, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has `app-config` settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin, which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should take advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation for guidance. From 1c0c187d6ac9fe6eef4ebbc70fcf1562ea647a79 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 16 Jan 2024 13:01:33 +0100 Subject: [PATCH 190/241] Update docs/frontend-system/architecture/05-extension-overrides.md Co-authored-by: Philipp Hugenroth Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index ffe8ff11c4..6921315d5a 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -79,7 +79,7 @@ If the plugin you want to change is internal to your company or you just want to Note that it can still be a good idea to split your overrides out into separate packages in large projects. But it's up to you to decide how to group the extensions into extension overrides. -## Overriding Plugin Extensions +## Override Plugin Extensions To override an extension that is provided by a plugin, you need to provide a new extension that has the same ID as the existing extension. That is, all kind, namespace, and name options must match the extension you want to replace. This means that you typically need to provide an explicit `namespace` when overriding extensions from a plugin. From 17b2750329136dccf61c066823eeb4c3e69fb307 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Tue, 16 Jan 2024 13:12:09 +0100 Subject: [PATCH 191/241] docs(frontend-system): update orphan extensions section title Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 6921315d5a..3791ee43b1 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -122,7 +122,7 @@ export default app.createRoot(); Now let's talk about the last override case, orphan extensions. -## Creating Orphan Extensions +## Create Orphan Extensions Sometimes you just need to quickly create a new extension and not overwrite an app extension or plugin. You can also use overrides to create extensions, but remember that if you want to make this extension available for installation by other users, we recommend providing it via a plugin in a separate package. From fbe52d23cff83f2f639f89baa8508cd1baee0bdc Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 17 Jan 2024 15:22:41 +0100 Subject: [PATCH 192/241] Update docs/frontend-system/architecture/05-extension-overrides.md Co-authored-by: Patrik Oldsberg Signed-off-by: Camila Belo --- docs/frontend-system/architecture/05-extension-overrides.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 3791ee43b1..bb177cd703 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -122,7 +122,7 @@ export default app.createRoot(); Now let's talk about the last override case, orphan extensions. -## Create Orphan Extensions +## Create Standalone Extensions Sometimes you just need to quickly create a new extension and not overwrite an app extension or plugin. You can also use overrides to create extensions, but remember that if you want to make this extension available for installation by other users, we recommend providing it via a plugin in a separate package. From 51d351cd6d1611d7be686214c3d6d2aa3b4fede0 Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Wed, 17 Jan 2024 16:08:28 +0100 Subject: [PATCH 193/241] refactor(frontend-system/overrides): apply docs suggestions Signed-off-by: Camila Belo --- .../architecture/05-extension-overrides.md | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index bb177cd703..6a1037341e 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -22,7 +22,7 @@ In order to override an app extension, you must create a new extension and add i In the example below, we create a file that exports custom extensions for the app's `light` and `dark` themes: -```tsx title="packages/app/src/themes.ts" {10-11,22-23} showLineNumbers +```tsx title="packages/app/src/themes.ts" import { createThemeExtension, createExtensionOverrides @@ -32,8 +32,10 @@ import { ApertureLightIcon, ApertureDarkIcon } from './icons'; // Creating a light theme extension const apertureLightTheme = createThemeExtension({ + // highlight-start namespace: 'app', name: 'light', + // highlight-end title: 'Aperture Light Theme', variant: 'light', icon: , @@ -44,8 +46,10 @@ const apertureLightTheme = createThemeExtension({ // Creating a dark theme extension const apertureDarkTheme = createThemeExtension({ + // highlight-start namespace: 'app', name: 'dark', + // highlight-end title: 'Aperture Dark Theme', variant: 'dark', icon: , @@ -60,16 +64,17 @@ export createExtensionOverrides({ }); ``` -Lines `10` and `22` should be highlighted because they declare `namespace` as `'app'`, so the system knows we are overriding app extensions. Additionally, to specifically override the `light` and `dark` theme extensions, we set the `name` option to `light` and `dark` respectively on lines `11` and `23`. Therefore, to override app theme extensions, we ensure that the extension `namespace` and `name` match those of the default app theme extension definitions. +Note that we declare `namespace` as `'app'` while creating the themes, so the system knows we are overriding app extensions. Additionally, to specifically override the `light` and `dark` theme extensions, we set the `name` option to `light` and `dark`. Therefore, to override app theme extensions, we ensure that the extension `namespace` and `name` match those of the default app theme extension definitions. Now we are able to use the overrides in a Backstage app: -```tsx title="packages/app/src/App.tsx" {5} showLineNumbers +```tsx title="packages/app/src/App.tsx" import { createApp } from '@backstage/frontend-app-api'; -import apertureOverrides from './themes'; +import themeOverrides from './themes'; const app = createApp({ - features: [ apertureOverrides ], + // highlight-next-line + features: [ themeOverrides ], }); export default app.createRoot(). @@ -91,11 +96,12 @@ We recommend that plugin developers share the extension IDs in their plugin docu Imagine you have a plugin with the ID `'search'`, and the plugin provides a page extension that you want to fully override with your own custom component. To do so, you need to create your page extension with an explicit `namespace` option that matches that of the plugin that you want to override, in this case `'search'`. If the existing extension also has an explicit `name` you'd need to set the `name` of your override extension to the same value as well. -```tsx title="packages/app/src/search.ts" showLineNumbers +```tsx title="packages/app/src/search.ts" import { createPageExtension } from '@backstage/frontend-plugin-api'; // Creating a custom search page extension const customSearchPage = createPageExtension({ + // highlight-next-line namespace: 'search', // Omitting name since it is the index plugin page defaultPath: '/search', @@ -109,11 +115,12 @@ export createExtensionOverrides({ Don't forget to configure your overrides in the `createApp` function: -```tsx title="packages/app/src/App.tsx" {5} showLineNumbers +```tsx title="packages/app/src/App.tsx" import { createApp } from '@backstage/frontend-app-api'; import searchOverrides from './search'; const app = createApp({ + // highlight-next-line features: [searchOverrides], }); @@ -130,7 +137,7 @@ Sometimes you just need to quickly create a new extension and not overwrite an a Imagine you want to create a page that is currently only used by your application, like an Institutional page, for example. You can use overrides to extend the Backstage app to render it. To do so, simply create a page extension and pass it to the app as an override: -```tsx title="packages/app/src/App.ts" showLineNumbers +```tsx title="packages/app/src/App.ts" import { createApp } from '@backstage/frontend-app-api'; import { createPageExtension, @@ -141,12 +148,14 @@ const app = createApp({ features: [ createExtensionOverrides({ extensions: [ + // highlight-start createPageExtension({ name: 'institutional', defaultPath: '/institutional', loader: () => import('./institutional').then(m => ), }), + // highlight-end ], }), ], @@ -155,4 +164,4 @@ const app = createApp({ export default app.createRoot(); ``` -Note that we are omitting `namespace` when creating the page extension. When we omit `namespace`, we are telling the system the new extension is orphaned and not an application or plugin extension! +Note that we are omitting `namespace` when creating the page extension. When we omit `namespace`, we are telling the system the new extension is standalone and not an application or plugin extension! From 943ac7a6cdb464d32de7cdf1aa614d73c566c74d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 15:42:05 +0000 Subject: [PATCH 194/241] chore(deps): update chromaui/action digest to 7fb6b04 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/verify_storybook.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index d7f90118de..29d86e913a 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -51,7 +51,7 @@ jobs: - run: yarn build-storybook - - uses: chromaui/action@722516a3934360dac82cdef8dbab38e824fc6fa1 # v1 + - uses: chromaui/action@7fb6b0407c69171ce521d08355a825958a5ef81a # v1 with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks From 375dd30fa33f4be26e1c7c49a4d4eb1ee9e19657 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 8 Jan 2024 13:43:36 +0100 Subject: [PATCH 195/241] docs/frontend-system: add missing sorting prefix Signed-off-by: Patrik Oldsberg --- .../building-plugins/{testing.md => 02-testing.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/frontend-system/building-plugins/{testing.md => 02-testing.md} (100%) diff --git a/docs/frontend-system/building-plugins/testing.md b/docs/frontend-system/building-plugins/02-testing.md similarity index 100% rename from docs/frontend-system/building-plugins/testing.md rename to docs/frontend-system/building-plugins/02-testing.md From 39a1dbd9d837e0479b24438ec265f35b38b3d8ea Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 9 Jan 2024 21:02:42 +0100 Subject: [PATCH 196/241] docs/frontend-system: initial plugin index docs Signed-off-by: Patrik Oldsberg --- .../building-plugins/01-index.md | 201 ++++++++++++++++++ microsite/sidebars.json | 5 +- 2 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 docs/frontend-system/building-plugins/01-index.md diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md new file mode 100644 index 0000000000..730dd58156 --- /dev/null +++ b/docs/frontend-system/building-plugins/01-index.md @@ -0,0 +1,201 @@ +--- +id: index +title: Building Frontend Plugins +sidebar_label: Overview +# prettier-ignore +description: Building frontend plugins using the new frontend system +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +This section covers how to build your own frontend [plugins](../architecture/04-plugins.md) and +[overrides](../architecture/05-extension-overrides.md). They are sometimes collectively referred to as +frontend _features_, and what you install to build up a Backstage frontend [app](../architecture/02-app.md). + +## Creating a new plugin + +This guide assumes that you already have a Backstage project set up. Even if you only want to develop a single plugin for publishing, we still recommend that you do so in a standard Backstage monorepo project, as you often end up needing multiple packages. For instructions on how to set up a new project, see our [getting started](../../getting-started/index.md#prerequisites) documentation. + +To create a frontend plugin, run `yarn new`, select `plugin`, and fill out the rest of the prompts. This will create a new package at `plugins/`, which will be the main entrypoint for your plugin. + +> **NOT: The created plugin will currently be templated for use in the legacy frontend system, and you will need to replace the existing plugin wiring code.** + +## The plugin instance + +The starting point of a frontend plugin is the `createPlugin` function, which accepts a single options object as its only parameter. It is imported from `@backstage/frontend-plugin-api`, which is where you will find most of the common APIs for building plugins. + +This is how to create a minimal plugin: + +```tsx title="in src/plugin.ts" +import { createPlugin } from '@backstage/frontend-plugin-api'; + +export const examplePlugin = createPlugin({ + id: 'example', + extensions: [], +}); +``` + +```tsx title="in src/index.ts" +export { examplePlugin as default } from './plugin'; +``` + +Note that we export the plugin as the default export of our package from `src/index.ts`. This is important, as it is how users of our plugin are able to seamlessly install the plugin package in a Backstage app without having to reference the plugin instance through code. + +The plugin ID should be a lowercase dash-separated string, while the plugin instance variable should be the camelCase version of the ID with a `Plugin` suffix. For more details on naming patterns within the frontend system, see [the article on naming patterns](../architecture/08-naming-patterns.md). By sticking to these naming patterns you ensure that users of your plugin more easily recognize the exports and features provided by your plugin. + +## Adding extensions + +The plugin that we created above is empty, and does't provide any actual functionality. To add functionality to a plugin you need to create and provide it with one or more [extensions](../architecture/03-extensions.md). Let's continue by adding a standalone page to our plugin, as well as a navigation item that allows users to navigate to the page. + +To create a new extension you typically use pre-defined [extension creators](../architecture/03-extensions.md#extension-creators), provided either by the framework itself or by other plugins. In this case we'll need to use `createPageExtension` and `createNavItemExtension`, both from `@backstage/frontend-plugin-api`. We will also need to [create a route reference](../architecture/07-routes.md#creating-a-route-reference) to use as a reference for out page, allowing us to dynamically create URLs that link to our page. + +```tsx title="in src/routes.ts" +import { createRouteRef } from '@backstage/frontend-plugin-api'; + +// Typically all routes are defined in src/routes.ts, in order to avoid circular imports. + +// This will be the route reference for our example page. If you want to link +// to the page from somewhere else, you can use this reference to generate the target path. +export const rootRouteRef = createRouteRef(); +``` + +```tsx title="in src/plugin.ts" +import { + createPlugin, + createPageExtension, + createNavItemExtension, +} from '@backstage/frontend-plugin-api'; +import { rootRouteRef } from './routes'; + +// Note that these extensions aren't exported, only the plugin itself it. +// You can export it locally for testing purposes, but don't export it from the plugin package. +const examplePage = createPageExtension({ + routeRef: rootRouteRef, + + // This is the default path of this page, but integrators are free to override it + defaultPath: '/example', + + // Page extensions are always dynamically loaded using React.lazy(). + // [1] All of the functionality of this page is implemented in the + // ExamplePage component, which is a regular React component. + loader: () => import('./components/ExamplePage').then(m => m.ExamplePage), +}); + +// This nav item is provided to the app.nav extension, and will by default be rendered as a sidebar item +const exampleNavItem = createNavItemExtension({ + routeRef: rootRouteRef, + title: 'Example', + icon: ExampleIcon, // Custom SvgIcon, or one from the Material UI icon library +}); + +// The same plugin as above, now with the extensions added +export const examplePlugin = createPlugin({ + id: 'example', + extensions: [examplePage, exampleNavItem], + // [2] We can also make routes available to other plugins. + routes: { + root: rootRouteRef, + }, +}); +``` + +What we've built here is a very common type of plugin. It's a top-level tool that provides a single page, along with a method for navigating to that page. The implementation of the page component at `[1]` can be arbitrarily complex, anything from a single simple information page, to a full-blown application with multiple sub-pages. + +We have also made the route reference available to other plugins at `[2]`. This makes it possible for app integrators to bind an external link from a different plugin to our plugin page. You can read more about how this works in the [External Route References](../architecture/07-routes.md#external-route-references) section. + +## Utility APIs + +Another type of extensions that is commonly used are [Utility APIs](../utility-apis/01-index.md). They can encapsulate shared pieces of functionality of your plugin, for example an API client for a backend service. You can optionally export your Utility API for other plugins to use, or allow integrators to replace the implementation of your Utility API with their own. For details on how to define and provide your own Utility API in your plugin, see the section on [creating Utility APIs](../utility-apis/02-creating.md). + +What we'll show here is a complete example of a simple Utility API used only within the plugin itself: + +```tsx title="src/api.ts - Defining an interface, API reference, and default implementation" +import { createApiRef } from '@backstage/frontend-plugin-api'; + +export interface ExampleApi { + getExample(): { example: string }; +} + +export const exampleApiRef = createApiRef({ + id: 'plugin.example', +}); + +export class DefaultExampleApi implements ExampleApi { + getExample(): { example: string } { + return { example: 'Hello World!' }; + } +} +``` + +```tsx title="src/components/ExamplePage.tsx - Using the API in our page component" +import { useApi } from '@backstage/frontend-plugin-api'; +import { exampleApiRef } from '../api'; + +export function ExamplePage() { + // highlight-next-line + const exampleApi = useApi(exampleApiRef); + + return ( +
+

Example Page

+

Example: {exampleApi.getExample()}

+
+ ); +} +``` + +```tsx title="in src/plugin.ts - Registering a factory for our API" +import { + createApiFactory, + createApiExtension, +} from '@backstage/frontend-plugin-api'; +import { exampleApiRef, DefaultExampleApi } from './api'; + +// highlight-add-start +const exampleApi = createApiExtension({ + factory: createApiFactory({ + api: exampleApiRef, + deps: {}, + factory: () => new DefaultExampleApi(), + }), +}); +// highlight-add-end + +/* Omitted definitions for examplePage, exampleNavItem, and rootRouteRef. */ + +export const examplePlugin = createPlugin({ + id: 'example', + extensions: [ + // highlight-add-next-line + exampleApi, + examplePage, + exampleNavItem, + ], + routes: { + root: rootRouteRef, + }, +}); +``` + +## Plugin specific extensions + +There are many different plugins that you can extend with additional functionality through extensions. One such plugin is the catalog plugin, one of the core features of Backstage. It lets you catalog the software in your organization, where each item in the catalog has its own page that can be populated with tools and information relating to that catalog entity. In this example we will explore how our plugin can provide such a tool to display on an entity page. + +```tsx title="in src/plugin.ts - An example entity content extension" +import { createEntityContentExtension } from '@backstage/plugin-catalog-react'; + +// Entity content extension are similar to page extensions in that they are rendered at a route, +// although they also have a title to support in-line navigation between the different content. +// Just like a page extensions the content is lazy loaded, and you can also provide a +// route reference if you want to be able to generate a URL that links to the content. +const exampleEntityContent = createEntityContentExtension({ + defaultPath: 'example', + defaultTitle: 'Example', + loader: () => + import('./components/ExampleEntityContent').then(m => ( + + )), +}); +``` + +The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of API provided by the catalog React library in [the API reference](../../reference/plugin-catalog-react.md). diff --git a/microsite/sidebars.json b/microsite/sidebars.json index c54e59f45c..c34598376f 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -411,7 +411,10 @@ { "type": "category", "label": "Building Plugins", - "items": ["frontend-system/building-plugins/testing"] + "items": [ + "frontend-system/building-plugins/index", + "frontend-system/building-plugins/testing" + ] }, { "type": "category", From 07b40ecb87909aff23e1c67e917ad7d9b15ea4fb Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 9 Jan 2024 22:51:49 +0100 Subject: [PATCH 197/241] docs/frontend-system: add extenison types doc Signed-off-by: Patrik Oldsberg --- .../building-plugins/03-extension-types.md | 43 +++++++++++++++++++ microsite/sidebars.json | 3 +- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 docs/frontend-system/building-plugins/03-extension-types.md diff --git a/docs/frontend-system/building-plugins/03-extension-types.md b/docs/frontend-system/building-plugins/03-extension-types.md new file mode 100644 index 0000000000..36eda55112 --- /dev/null +++ b/docs/frontend-system/building-plugins/03-extension-types.md @@ -0,0 +1,43 @@ +--- +id: index +title: Frontend System Extension Types +sidebar_label: Extension Types +# prettier-ignore +description: Extension types provided by the frontend system and core features +--- + +> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.** + +This section covers many of the [extension types](../architecture/03-extensions.md#extension-creators) available at your disposal when building Backstage frontend plugins. + +## Built-in extension types + +These are the extension types provided by the Backstage frontend framework itself. + +### Api - [Reference](../../reference/frontend-plugin-api.createapiextension.md) + +An API extension is used to add or override [Utility API factories](../utility-apis/01-index.md) in the app. They are commonly used by plugins for both internal and shared APIs. There are also many built-in Api extensions provided by the framework that you are able to override. + +### Component - [Reference](../../reference/frontend-plugin-api.createcomponentextension.md) + +Components extensions are used to override the component associated with a component reference throughout the app. + +### NavItem - [Reference](../../reference/frontend-plugin-api.createnavitemextension.md) + +Navigation item extensions are used to provide menu items that link to different parts of the app. By default nav items are attached to the app nav extension, which by default is rendered as the left sidebar in the app. + +### Page - [Reference](../../reference/frontend-plugin-api.createpageextension.md) + +Page extensions provide content for a particular route in the app. By default pages are attached to the app routes extensions, which renders the root routes. + +### SignInPage - [Reference](../../reference/frontend-plugin-api.createsigninpageextension.md) + +Sign-in page extension have a single purpose - to implement a custom sign-in page. They are always attached to the app root extension and are rendered before the rest of the app until the user is signed in. + +### Theme - [Reference](../../reference/frontend-plugin-api.createthemeextension.md) + +Theme extensions provide custom themes for the app. They are always attached to the app extension and you can have any number of themes extensions installed in an app at once, letting the user choose which theme to use. + +### Translation - [Reference](../../reference/frontend-plugin-api.createtranslationextension.md) + +Translation extension provide custom translation messages for the app. They can be used both to override the default english messages to custom ones, as well as provide translations for additional languages. diff --git a/microsite/sidebars.json b/microsite/sidebars.json index c34598376f..234afd78d6 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -413,7 +413,8 @@ "label": "Building Plugins", "items": [ "frontend-system/building-plugins/index", - "frontend-system/building-plugins/testing" + "frontend-system/building-plugins/testing", + "frontend-system/building-plugins/extension-types" ] }, { From 894497677b81d1dc9cf65743189c315df3ea4486 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 9 Jan 2024 23:15:53 +0100 Subject: [PATCH 198/241] docs/frontend-system: add core feature extension types Signed-off-by: Patrik Oldsberg --- .../frontend-system/building-plugins/01-index.md | 2 ++ .../building-plugins/03-extension-types.md | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index 730dd58156..80182126be 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -199,3 +199,5 @@ const exampleEntityContent = createEntityContentExtension({ ``` The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of API provided by the catalog React library in [the API reference](../../reference/plugin-catalog-react.md). + +For a more complete list of the different types of extensions that you can create for your plugin, see the [extension types](./03-extension-types.md) section. diff --git a/docs/frontend-system/building-plugins/03-extension-types.md b/docs/frontend-system/building-plugins/03-extension-types.md index 36eda55112..1d59c60545 100644 --- a/docs/frontend-system/building-plugins/03-extension-types.md +++ b/docs/frontend-system/building-plugins/03-extension-types.md @@ -41,3 +41,19 @@ Theme extensions provide custom themes for the app. They are always attached to ### Translation - [Reference](../../reference/frontend-plugin-api.createtranslationextension.md) Translation extension provide custom translation messages for the app. They can be used both to override the default english messages to custom ones, as well as provide translations for additional languages. + +## Core feature extension types + +These are the extension types provided by the Backstage core feature plugins. + +### EntityCard - [Reference](../../reference/plugin-catalog-react.createentitycardextension.md) + +Creates entity cards to be displayed on the entity pages of the catalog plugin. + +### EntityContent - [Reference](../../reference/plugin-catalog-react.createentitycontentextension.md) + +Creates entity content to be displayed on the entity pages of the catalog plugin. + +### SearchResultListItem - [Reference](../../reference/plugin-search-react.createsearchresultlistitemextension.md) + +Creates search result list items for different types of search results, to be displayed in search result lists. From 22940cb56165167d63f06b5dd98a8ab0a53de9d1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jan 2024 10:30:18 +0100 Subject: [PATCH 199/241] docs/frontend-system: update extension type links to use alpha API report Signed-off-by: Patrik Oldsberg --- docs/frontend-system/building-plugins/03-extension-types.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/frontend-system/building-plugins/03-extension-types.md b/docs/frontend-system/building-plugins/03-extension-types.md index 1d59c60545..1db99a78b9 100644 --- a/docs/frontend-system/building-plugins/03-extension-types.md +++ b/docs/frontend-system/building-plugins/03-extension-types.md @@ -46,14 +46,14 @@ Translation extension provide custom translation messages for the app. They can These are the extension types provided by the Backstage core feature plugins. -### EntityCard - [Reference](../../reference/plugin-catalog-react.createentitycardextension.md) +### EntityCard - [Reference](https://github.com/backstage/backstage/blob/master/plugins/catalog-react/api-report-alpha.md) Creates entity cards to be displayed on the entity pages of the catalog plugin. -### EntityContent - [Reference](../../reference/plugin-catalog-react.createentitycontentextension.md) +### EntityContent - [Reference](https://github.com/backstage/backstage/blob/master/plugins/catalog-react/api-report-alpha.md) Creates entity content to be displayed on the entity pages of the catalog plugin. -### SearchResultListItem - [Reference](../../reference/plugin-search-react.createsearchresultlistitemextension.md) +### SearchResultListItem - [Reference](https://github.com/backstage/backstage/blob/master/plugins/search-react/api-report-alpha.md) Creates search result list items for different types of search results, to be displayed in search result lists. From f26024be00a7d34c03973f97007d79e11c56a6f0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 12 Jan 2024 14:17:38 +0100 Subject: [PATCH 200/241] docs/frontend-system: plugin index vale fixes Signed-off-by: Patrik Oldsberg --- docs/frontend-system/building-plugins/01-index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index 80182126be..afdc9546dd 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -41,11 +41,11 @@ export { examplePlugin as default } from './plugin'; Note that we export the plugin as the default export of our package from `src/index.ts`. This is important, as it is how users of our plugin are able to seamlessly install the plugin package in a Backstage app without having to reference the plugin instance through code. -The plugin ID should be a lowercase dash-separated string, while the plugin instance variable should be the camelCase version of the ID with a `Plugin` suffix. For more details on naming patterns within the frontend system, see [the article on naming patterns](../architecture/08-naming-patterns.md). By sticking to these naming patterns you ensure that users of your plugin more easily recognize the exports and features provided by your plugin. +The plugin ID should be a lowercase dash-separated string, while the plugin instance variable should be the camel case version of the ID with a `Plugin` suffix. For more details on naming patterns within the frontend system, see [the article on naming patterns](../architecture/08-naming-patterns.md). By sticking to these naming patterns you ensure that users of your plugin more easily recognize the exports and features provided by your plugin. ## Adding extensions -The plugin that we created above is empty, and does't provide any actual functionality. To add functionality to a plugin you need to create and provide it with one or more [extensions](../architecture/03-extensions.md). Let's continue by adding a standalone page to our plugin, as well as a navigation item that allows users to navigate to the page. +The plugin that we created above is empty, and doesn't provide any actual functionality. To add functionality to a plugin you need to create and provide it with one or more [extensions](../architecture/03-extensions.md). Let's continue by adding a standalone page to our plugin, as well as a navigation item that allows users to navigate to the page. To create a new extension you typically use pre-defined [extension creators](../architecture/03-extensions.md#extension-creators), provided either by the framework itself or by other plugins. In this case we'll need to use `createPageExtension` and `createNavItemExtension`, both from `@backstage/frontend-plugin-api`. We will also need to [create a route reference](../architecture/07-routes.md#creating-a-route-reference) to use as a reference for out page, allowing us to dynamically create URLs that link to our page. From 9cab5ad7f069135aaa62449e197eebb92457d72d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 15:48:40 +0000 Subject: [PATCH 201/241] fix(deps): update dependency mini-css-extract-plugin to v2.7.7 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 41218e601c..e69b573700 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34022,13 +34022,13 @@ __metadata: linkType: hard "mini-css-extract-plugin@npm:^2.4.2": - version: 2.7.6 - resolution: "mini-css-extract-plugin@npm:2.7.6" + version: 2.7.7 + resolution: "mini-css-extract-plugin@npm:2.7.7" dependencies: schema-utils: ^4.0.0 peerDependencies: webpack: ^5.0.0 - checksum: be6f7cefc6275168eb0a6b8fe977083a18c743c9612c9f00e6c1a62c3393ca7960e93fba1a7ebb09b75f36a0204ad087d772c1ef574bc29c90c0e8175a3c0b83 + checksum: 04af0e7d8c1a4ff31c70ac2d0895837dae3d51cce3bfd90e3c1d90d50eef7de21778361a3064531df046d775d80b3bf056324dddea93831c7def2047c5aa8718 languageName: node linkType: hard From 28248998b0af56699a00bbb4c43e7ab97a56307a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 17 Jan 2024 17:28:25 +0100 Subject: [PATCH 202/241] docs/frontend-system: plugin building review fixes Signed-off-by: Patrik Oldsberg --- docs/frontend-system/building-plugins/01-index.md | 13 ++++++++----- .../building-plugins/03-extension-types.md | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index afdc9546dd..cb29b3518a 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -76,9 +76,10 @@ const examplePage = createPageExtension({ defaultPath: '/example', // Page extensions are always dynamically loaded using React.lazy(). - // [1] All of the functionality of this page is implemented in the + // All of the functionality of this page is implemented in the // ExamplePage component, which is a regular React component. - loader: () => import('./components/ExamplePage').then(m => m.ExamplePage), + // highlight-next-line + loader: () => import('./components/ExamplePage').then(m => ), }); // This nav item is provided to the app.nav extension, and will by default be rendered as a sidebar item @@ -92,16 +93,18 @@ const exampleNavItem = createNavItemExtension({ export const examplePlugin = createPlugin({ id: 'example', extensions: [examplePage, exampleNavItem], - // [2] We can also make routes available to other plugins. + // We can also make routes available to other plugins. + // highlight-start routes: { root: rootRouteRef, }, + // highlight-end }); ``` -What we've built here is a very common type of plugin. It's a top-level tool that provides a single page, along with a method for navigating to that page. The implementation of the page component at `[1]` can be arbitrarily complex, anything from a single simple information page, to a full-blown application with multiple sub-pages. +What we've built here is a very common type of plugin. It's a top-level tool that provides a single page, along with a method for navigating to that page. The implementation of the page component, in this case the highlighted `ExamplePage`, can be arbitrarily complex. It can be anything from a single simple information page, to a full-blown application with multiple sub-pages. -We have also made the route reference available to other plugins at `[2]`. This makes it possible for app integrators to bind an external link from a different plugin to our plugin page. You can read more about how this works in the [External Route References](../architecture/07-routes.md#external-route-references) section. +We have also provided external access to our route reference by passing it to the plugin `routes` option. This makes it possible for app integrators to bind an external link from a different plugin to our plugin page. You can read more about how this works in the [External Route References](../architecture/07-routes.md#external-router-references) section. ## Utility APIs diff --git a/docs/frontend-system/building-plugins/03-extension-types.md b/docs/frontend-system/building-plugins/03-extension-types.md index 1db99a78b9..2bea073ed6 100644 --- a/docs/frontend-system/building-plugins/03-extension-types.md +++ b/docs/frontend-system/building-plugins/03-extension-types.md @@ -1,5 +1,5 @@ --- -id: index +id: extension-types title: Frontend System Extension Types sidebar_label: Extension Types # prettier-ignore From 2a0c08f4d992f584a3b78d32509c18cad49c8f4f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 16:36:13 +0000 Subject: [PATCH 203/241] fix(deps): update dependency react-use to v17.4.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 41218e601c..ebe16e1906 100644 --- a/yarn.lock +++ b/yarn.lock @@ -38716,8 +38716,8 @@ __metadata: linkType: hard "react-use@npm:^17.2.4, react-use@npm:^17.3.1, react-use@npm:^17.3.2, react-use@npm:^17.4.0": - version: 17.4.2 - resolution: "react-use@npm:17.4.2" + version: 17.4.3 + resolution: "react-use@npm:17.4.3" dependencies: "@types/js-cookie": ^2.2.6 "@xobotyi/scrollbar-width": ^1.9.5 @@ -38736,7 +38736,7 @@ __metadata: peerDependencies: react: "*" react-dom: "*" - checksum: 1b15add951a80eee637045e5e769dd565edde47838da3d8d0e9a4a2cfd547eb59626b5c5b020ba3c067c01356d2042c5948c534a90729114a7fc7d1e18763d0c + checksum: efa54c795ca900902022096c4c87b2a8c2290fe1748f3b2bf4d31ad40bfa35c1520f67e3da5f0a227a6429256df7bca251d9323487652debc924de5208a9cedd languageName: node linkType: hard From d4ef6e7a0116840c66187b3da4df9bd24126bc62 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 16:36:52 +0000 Subject: [PATCH 204/241] fix(deps): update dependency react-virtualized-auto-sizer to v1.0.21 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 41218e601c..1041c132a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18668,11 +18668,11 @@ __metadata: linkType: hard "@types/react-virtualized-auto-sizer@npm:^1.0.1": - version: 1.0.3 - resolution: "@types/react-virtualized-auto-sizer@npm:1.0.3" + version: 1.0.4 + resolution: "@types/react-virtualized-auto-sizer@npm:1.0.4" dependencies: "@types/react": "*" - checksum: 7fcc516241903b937481b567a560c75cd23d27e63222938db725972d93cde0c07f846f98e104c78edcaa765608be156a9d08cf24e2261a3e11463b11343d964c + checksum: e0d41ac6cf0f48dfef45c0cd70146578f42ad83dad90911aa0dfe72b0e1ea62ca9ff56d4f43f322ec6dae2e7cb4d025aefe0e85241f7782c249aeface1050512 languageName: node linkType: hard @@ -38741,12 +38741,12 @@ __metadata: linkType: hard "react-virtualized-auto-sizer@npm:^1.0.11, react-virtualized-auto-sizer@npm:^1.0.6": - version: 1.0.20 - resolution: "react-virtualized-auto-sizer@npm:1.0.20" + version: 1.0.21 + resolution: "react-virtualized-auto-sizer@npm:1.0.21" peerDependencies: - react: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc - react-dom: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc - checksum: 2c616ec7587de64a46aa8c6c301e75fee87eb7a39013f25d940b0fe95eee5e8a8a3c109923e241b427752d71fba80f44cd2c8557750967df0777d99ebd16ba24 + react: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 + react-dom: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 + checksum: 9c0929a0363b3b3b10ad65ac57d7562a20966a9c38c28c10dfd296d0a6a3e678319dce2384c5177f43965c2b7f226f5766deffc4b7eaaab0ee7c2cfe0c7d6b48 languageName: node linkType: hard From e2fd9f3d1a71a3ac130ead4c94a3d083f90d7495 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 17:27:48 +0000 Subject: [PATCH 205/241] fix(deps): update dependency recharts to v2.10.4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 41218e601c..c7ebe2dfce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -38946,8 +38946,8 @@ __metadata: linkType: hard "recharts@npm:^2.5.0": - version: 2.10.3 - resolution: "recharts@npm:2.10.3" + version: 2.10.4 + resolution: "recharts@npm:2.10.4" dependencies: clsx: ^2.0.0 eventemitter3: ^4.0.1 @@ -38961,7 +38961,7 @@ __metadata: prop-types: ^15.6.0 react: ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 - checksum: 503c9fefa8648e0e8834a11ccc09fdcc310d391807438f4c0567b1888d7cd5f7a1f65f020afb981ec54ad6f96d31ebe757ab9025e93782edabc5c741f1aa946a + checksum: f283a21367aa675af83ada6d92ebd7bfa8931ba805bba34ee6247f74cba1b5d37c5fd48d20baa3533bbd3f0a98a1566e5d3733d23825caee8b256dd66ae5ff2c languageName: node linkType: hard From 9e7418aaaea501b52ad055b35d8a56665288ec6f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 17:28:25 +0000 Subject: [PATCH 206/241] fix(deps): update dependency style-loader to v3.3.4 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 41218e601c..4cd293ec8c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -41518,11 +41518,11 @@ __metadata: linkType: hard "style-loader@npm:^3.3.1": - version: 3.3.3 - resolution: "style-loader@npm:3.3.3" + version: 3.3.4 + resolution: "style-loader@npm:3.3.4" peerDependencies: webpack: ^5.0.0 - checksum: f59c953f56f6a935bd6a1dfa409f1128fed2b66b48ce4a7a75b85862a7156e5e90ab163878962762f528ec4d510903d828da645e143fbffd26f055dc1c094078 + checksum: caac3f2fe2c3c89e49b7a2a9329e1cfa515ecf5f36b9c4885f9b218019fda207a9029939b2c35821dec177a264a007e7c391ccdd3ff7401881ce6287b9c8f38b languageName: node linkType: hard From 846a8ef59c5931291f7e6c5d4fb1df39df1aab34 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 18:31:53 +0000 Subject: [PATCH 207/241] fix(deps): update material-ui monorepo to v5.15.5 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 184 +++++++++++++++++++++++++++--------------------------- 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/yarn.lock b/yarn.lock index 41218e601c..b495a65a3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3119,12 +3119,12 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.6, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.23.6 - resolution: "@babel/runtime@npm:7.23.6" +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.1, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": + version: 7.23.8 + resolution: "@babel/runtime@npm:7.23.8" dependencies: regenerator-runtime: ^0.14.0 - checksum: 1a8eaf3d3a103ef5227b60ca7ab5c589118c36ca65ef2d64e65380b32a98a3f3b5b3ef96660fa0471b079a18b619a8317f3e7f03ab2b930c45282a8b69ed9a16 + checksum: 0bd5543c26811153822a9f382fd39886f66825ff2a397a19008011376533747cd05c33a91f6248c0b8b0edf0448d7c167ebfba34786088f1b7eb11c65be7dfc3 languageName: node linkType: hard @@ -10943,41 +10943,41 @@ __metadata: languageName: node linkType: hard -"@floating-ui/core@npm:^1.4.2": - version: 1.5.0 - resolution: "@floating-ui/core@npm:1.5.0" - dependencies: - "@floating-ui/utils": ^0.1.3 - checksum: 54b4fe26b3c228746ac5589f97303abf158b80aa5f8b99027259decd68d1c2030c4c637648ebd33dfe78a4212699453bc2bd7537fd5a594d3bd3e63d362f666f - languageName: node - linkType: hard - -"@floating-ui/dom@npm:^1.5.1": +"@floating-ui/core@npm:^1.5.3": version: 1.5.3 - resolution: "@floating-ui/dom@npm:1.5.3" + resolution: "@floating-ui/core@npm:1.5.3" dependencies: - "@floating-ui/core": ^1.4.2 - "@floating-ui/utils": ^0.1.3 - checksum: 00053742064aac70957f0bd5c1542caafb3bfe9716588bfe1d409fef72a67ed5e60450d08eb492a77f78c22ed1ce4f7955873cc72bf9f9caf2b0f43ae3561c21 + "@floating-ui/utils": ^0.2.0 + checksum: 72af8563e1742791acee82e86f82a0fbca7445809988d31eea3fd5771909463aa7655a6cb001cc244f8fe3a9de600420257e4dfb887ca33e2a31ac47b52e39a2 languageName: node linkType: hard -"@floating-ui/react-dom@npm:^2.0.0, @floating-ui/react-dom@npm:^2.0.4": - version: 2.0.4 - resolution: "@floating-ui/react-dom@npm:2.0.4" +"@floating-ui/dom@npm:^1.5.4": + version: 1.5.4 + resolution: "@floating-ui/dom@npm:1.5.4" dependencies: - "@floating-ui/dom": ^1.5.1 + "@floating-ui/core": ^1.5.3 + "@floating-ui/utils": ^0.2.0 + checksum: 5e6f05532ff4e6daf9f2d91534184d8f942ddb8fd260c2543a49bdf0c0ff69fd0867937ce1d023126008724ac238f8fc89b5e48f82cdf9f8355a1d04edd085bd + languageName: node + linkType: hard + +"@floating-ui/react-dom@npm:^2.0.0, @floating-ui/react-dom@npm:^2.0.5": + version: 2.0.6 + resolution: "@floating-ui/react-dom@npm:2.0.6" + dependencies: + "@floating-ui/dom": ^1.5.4 peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 91b2369e25f84888486e48c1656117468248906034ed482d411bb9ed1061b908dd32435b4ca3d0cd0ca6083291510a98ce74d76c671d5cc25b0c41e5fa824bae + checksum: 3608537be6cae5f0442d3f826379b8e4a9ce5c4bdecf1d2b34e6709842d80444be1a00eca3641d680e2e6405d833092f58005d1b120a9d39ffd341c60b0c017c languageName: node linkType: hard -"@floating-ui/utils@npm:^0.1.3": - version: 0.1.4 - resolution: "@floating-ui/utils@npm:0.1.4" - checksum: e6195ded5b3a6fd38411a833605184c31f24609b08feab2615e90ccc063bf4d3965383d817642fc7e8ca5ab6a54c29c71103e874f3afb0518595c8bd3390ba16 +"@floating-ui/utils@npm:^0.2.0": + version: 0.2.1 + resolution: "@floating-ui/utils@npm:0.2.1" + checksum: 9ed4380653c7c217cd6f66ae51f20fdce433730dbc77f95b5abfb5a808f5fdb029c6ae249b4e0490a816f2453aa6e586d9a873cd157fdba4690f65628efc6e06 languageName: node linkType: hard @@ -12762,16 +12762,16 @@ __metadata: languageName: node linkType: hard -"@mui/base@npm:5.0.0-beta.29": - version: 5.0.0-beta.29 - resolution: "@mui/base@npm:5.0.0-beta.29" +"@mui/base@npm:5.0.0-beta.32": + version: 5.0.0-beta.32 + resolution: "@mui/base@npm:5.0.0-beta.32" dependencies: - "@babel/runtime": ^7.23.6 - "@floating-ui/react-dom": ^2.0.4 - "@mui/types": ^7.2.11 - "@mui/utils": ^5.15.2 + "@babel/runtime": ^7.23.8 + "@floating-ui/react-dom": ^2.0.5 + "@mui/types": ^7.2.13 + "@mui/utils": ^5.15.5 "@popperjs/core": ^2.11.8 - clsx: ^2.0.0 + clsx: ^2.1.0 prop-types: ^15.8.1 peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -12780,29 +12780,29 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 40481f18d5b4c560e0f9868876727203af76954b5b8b208bfc01da666229f8eef45852b5d87403aa42b4c8515a5b9d2e99d4ae40446289d7456c56310fce72c7 + checksum: 5f27be8914c072ffcbe6720de9aa6129180e68927657e8bcbc03a6f322d1ee6c6740a199d72ed0b490a7b29b79cc0c59d1e05a427089b17f4cbc9cc756e67506 languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^5.15.2": - version: 5.15.2 - resolution: "@mui/core-downloads-tracker@npm:5.15.2" - checksum: 8c88ac73a1d87c8ce565f6295dcd084c643580848e8f59159402e9db89975263da06305a0e605d3744479e917c2d297319496534bca9df8338e203162f1e7c33 +"@mui/core-downloads-tracker@npm:^5.15.5": + version: 5.15.5 + resolution: "@mui/core-downloads-tracker@npm:5.15.5" + checksum: 4c9b1281ebe8d17d402e22f7f50c347c0b3918b1ed17af721f4de5ce282d90bc6d90fe9730595998b2bbb2f7ebe57fc55d4c858f31754fccdb606af472a59dc8 languageName: node linkType: hard "@mui/material@npm:^5.12.2": - version: 5.15.2 - resolution: "@mui/material@npm:5.15.2" + version: 5.15.5 + resolution: "@mui/material@npm:5.15.5" dependencies: - "@babel/runtime": ^7.23.6 - "@mui/base": 5.0.0-beta.29 - "@mui/core-downloads-tracker": ^5.15.2 - "@mui/system": ^5.15.2 - "@mui/types": ^7.2.11 - "@mui/utils": ^5.15.2 + "@babel/runtime": ^7.23.8 + "@mui/base": 5.0.0-beta.32 + "@mui/core-downloads-tracker": ^5.15.5 + "@mui/system": ^5.15.5 + "@mui/types": ^7.2.13 + "@mui/utils": ^5.15.5 "@types/react-transition-group": ^4.4.10 - clsx: ^2.0.0 + clsx: ^2.1.0 csstype: ^3.1.2 prop-types: ^15.8.1 react-is: ^18.2.0 @@ -12820,16 +12820,16 @@ __metadata: optional: true "@types/react": optional: true - checksum: 7586b0160c686214c4d3a6f8af76306413bfe13286a4679ca7696b764615f511b5d5b27a8129e15ae81856492317e7f139f4bd075f6b2dfe6e60de46755d7dbc + checksum: dbfcb31810c674d9ab3b9145752433de3917d9c0d1b491bdff84c44b8f1124e8fe8ab04fa09b974b497983b7bd3011b86fb441ad365f979f971d3ddb46712060 languageName: node linkType: hard -"@mui/private-theming@npm:^5.15.2": - version: 5.15.2 - resolution: "@mui/private-theming@npm:5.15.2" +"@mui/private-theming@npm:^5.15.5": + version: 5.15.5 + resolution: "@mui/private-theming@npm:5.15.5" dependencies: - "@babel/runtime": ^7.23.6 - "@mui/utils": ^5.15.2 + "@babel/runtime": ^7.23.8 + "@mui/utils": ^5.15.5 prop-types: ^15.8.1 peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 @@ -12837,15 +12837,15 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 63cc69adc3eca03533dd72296aac6449abe133522f6f5c62c8497e57dbd092c131cba3488ee8d97dfb76c31a194df014f4da3b2d30027614e987ed72581a4acf + checksum: 3a5f7f190aa69a0ad69a34f77e54ee2fdcb088d21a61d4720b76d098d178e1c3f6a470fc5e7a30d351db10efbc062cb11af75b8789e2f38eaa2ca612bcb0f851 languageName: node linkType: hard -"@mui/styled-engine@npm:^5.15.2": - version: 5.15.2 - resolution: "@mui/styled-engine@npm:5.15.2" +"@mui/styled-engine@npm:^5.15.5": + version: 5.15.5 + resolution: "@mui/styled-engine@npm:5.15.5" dependencies: - "@babel/runtime": ^7.23.6 + "@babel/runtime": ^7.23.8 "@emotion/cache": ^11.11.0 csstype: ^3.1.2 prop-types: ^15.8.1 @@ -12858,20 +12858,20 @@ __metadata: optional: true "@emotion/styled": optional: true - checksum: daa15b61be2e785c9719e091047a5900aa5aa0b6a9dfbc2ea373f6718f6ec3485f44e05596cd9506a90a7c55d8d372233a80cbeca4d81ceb8d5e6a10ce0f8292 + checksum: 42bb7f50ed33ec88f799bd90a00337689837ee0b2d603681fe69c9a14850e5ae1d037505365ce78cd564307cc2c0654c46cece8d9250adb21c77b1de316e3c45 languageName: node linkType: hard "@mui/styles@npm:^5.14.18": - version: 5.15.2 - resolution: "@mui/styles@npm:5.15.2" + version: 5.15.5 + resolution: "@mui/styles@npm:5.15.5" dependencies: - "@babel/runtime": ^7.23.6 + "@babel/runtime": ^7.23.8 "@emotion/hash": ^0.9.1 - "@mui/private-theming": ^5.15.2 - "@mui/types": ^7.2.11 - "@mui/utils": ^5.15.2 - clsx: ^2.0.0 + "@mui/private-theming": ^5.15.5 + "@mui/types": ^7.2.13 + "@mui/utils": ^5.15.5 + clsx: ^2.1.0 csstype: ^3.1.2 hoist-non-react-statics: ^3.3.2 jss: ^10.10.0 @@ -12889,20 +12889,20 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 53ee6fb6c1114469dfeacbf5d26fc6ef7bc897428258301515012fcea95f5abcc73d5b70d1ea1da9382f7742aa7da7a9749a7594331e78f85b6b4cd8f8216d11 + checksum: dc131c0e7763f7ac4fd96a1db3dd85abf59de5429a73f7cf9ed15d423fb9bb5883835c1951d36e8804da9ab2ed13d603ed349f12e7cd15885f8279d90d13511b languageName: node linkType: hard -"@mui/system@npm:^5.15.2": - version: 5.15.2 - resolution: "@mui/system@npm:5.15.2" +"@mui/system@npm:^5.15.5": + version: 5.15.5 + resolution: "@mui/system@npm:5.15.5" dependencies: - "@babel/runtime": ^7.23.6 - "@mui/private-theming": ^5.15.2 - "@mui/styled-engine": ^5.15.2 - "@mui/types": ^7.2.11 - "@mui/utils": ^5.15.2 - clsx: ^2.0.0 + "@babel/runtime": ^7.23.8 + "@mui/private-theming": ^5.15.5 + "@mui/styled-engine": ^5.15.5 + "@mui/types": ^7.2.13 + "@mui/utils": ^5.15.5 + clsx: ^2.1.0 csstype: ^3.1.2 prop-types: ^15.8.1 peerDependencies: @@ -12917,27 +12917,27 @@ __metadata: optional: true "@types/react": optional: true - checksum: ce6297a4cfa6f91891fa84679e05e40e12c4a27fe4fb34d78cbcbae172da293c05fa6f07c24fec66c864eac64179aeec1f7a70358e376b8c16ffc8e91f93a904 + checksum: 3f736f120d65fa14588cd7554a9ef63c9d4480716807d7ee5543b9f25d936b5ac0396a51a565c53b2905114fed5f94880c896f091e8d269260bfc53e8a8e2fb5 languageName: node linkType: hard -"@mui/types@npm:^7.2.11": - version: 7.2.11 - resolution: "@mui/types@npm:7.2.11" +"@mui/types@npm:^7.2.13": + version: 7.2.13 + resolution: "@mui/types@npm:7.2.13" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: ce6bbe8ba963af218bf86797f4c8adbf0f294047adeaf6596d3bb4a96f1b01701f1b1ae7dcfe2f7972f6e23c85eee4187e496fb481541713ed8bf12e96f3c34f + checksum: 58dfc96f9654288519ff01d6b54e6a242f05cadad51210deb85710a81be4fa1501a116c8968e2614b16c748fc1f407dc23beeeeae70fa37fceb6c6de876ff70d languageName: node linkType: hard -"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.15.2": - version: 5.15.2 - resolution: "@mui/utils@npm:5.15.2" +"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.15.5": + version: 5.15.5 + resolution: "@mui/utils@npm:5.15.5" dependencies: - "@babel/runtime": ^7.23.6 + "@babel/runtime": ^7.23.8 "@types/prop-types": ^15.7.11 prop-types: ^15.8.1 react-is: ^18.2.0 @@ -12947,7 +12947,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: c78ad9fb1a5fa1dc5955cada77227c605f1e5bf45503bf2bb0080bc92cf28bdcf1cbb83322d19162c5424ec245a66cef849603c7681fa1ec89093e0b1922dc58 + checksum: fe71ce69e23cb4c00886138da1422e4baa66959cd10f97b2aa00f7324a038b13084ea4a0da123774c0018f48ddb6ce4f3cb20a915ec3c5c1ff5495bf337f665f languageName: node linkType: hard @@ -22475,10 +22475,10 @@ __metadata: languageName: node linkType: hard -"clsx@npm:^2.0.0": - version: 2.0.0 - resolution: "clsx@npm:2.0.0" - checksum: a2cfb2351b254611acf92faa0daf15220f4cd648bdf96ce369d729813b85336993871a4bf6978ddea2b81b5a130478339c20d9d0b5c6fc287e5147f0c059276e +"clsx@npm:^2.0.0, clsx@npm:^2.1.0": + version: 2.1.0 + resolution: "clsx@npm:2.1.0" + checksum: 43fefc29b6b49c9476fbce4f8b1cc75c27b67747738e598e6651dd40d63692135dc60b18fa1c5b78a2a9ba8ae6fd2055a068924b94e20b42039bd53b78b98e1d languageName: node linkType: hard From 63617ad9e162a539db249dce3407d22d1b1a1558 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 17 Jan 2024 20:52:41 +0100 Subject: [PATCH 208/241] docs/tutorials: add migration guide for React 18 Signed-off-by: Patrik Oldsberg --- docs/tutorials/react18-migration.md | 106 ++++++++++++++++++++++++++++ microsite/sidebars.json | 1 + 2 files changed, 107 insertions(+) create mode 100644 docs/tutorials/react18-migration.md diff --git a/docs/tutorials/react18-migration.md b/docs/tutorials/react18-migration.md new file mode 100644 index 0000000000..deb8518550 --- /dev/null +++ b/docs/tutorials/react18-migration.md @@ -0,0 +1,106 @@ +--- +id: react18-migration +title: Migrating to React 18 +description: Additional resources for the Material UI v5 migration guide specifically for Backstage +--- + +The Backstage core libraries and plugins are compatible with all versions of React from v16.8 to v18. This means that you can migrate projects at your own pace. We do however encourage you to do so sooner rather than later, both to keep up with the evolving ecosystem, but also because React 18 brings performance improvements, in particular in tests. + +## Migration + +_Before diving in, this is a heads-up that for large projects this can be a tricky migration due to the fact that it is hard to break down into a gradual migration. In practice the difficult part of this migration is switching to the new version of the `@testing-library/react` package for tests, since there is no overlapping support across major React versions, more on that later._ + +### Switching to React 18 + +To switch a project to React 18, there are generally three changes that need to be made. + +1. Update the resolutions in your root `package.json` to the new versions of `@types/react` and `@types/react-dom`: + +```json title="package.json" + "resolutions": { + // highlight-remove-next-line + "@types/react": "^17", + // highlight-remove-next-line + "@types/react": "^17", + // highlight-add-next-line + "@types/react-dom": "^18", + // highlight-add-next-line + "@types/react-dom": "^18", + }, +``` + +2. Update the `react` and `react-dom` dependencies in your `packages/app/package.json` to the new versions: + +```json title="packages/app/package.json" + "dependencies": { + ... + // highlight-remove-next-line + "react": "^17.0.2", + // highlight-remove-next-line + "react-dom": "^17.0.2", + // highlight-add-next-line + "react": "^18.0.2", + // highlight-add-next-line + "react-dom": "^18.0.2", + ... + }, +``` + +3. Update `packages/app/src/index.tsx` to use the new `react-dom/client` API to render the app: + +```tsx title="packages/app/src/index.tsx" +import '@backstage/cli/asset-types'; +import React from 'react'; +// highlight-remove-next-line +import ReactDOM from 'react-dom'; +// highlight-add-next-line +import ReactDOM from 'react-dom/client'; +import App from './App'; + +// highlight-remove-next-line +ReactDOM.render(, document.getElementById('root')); +// highlight-add-next-line +ReactDOM.createRoot(document.getElementById('root')!).render(); +``` + +Once these steps are done you should be able to run your app and see it working as before, except now using React 18. + +### Migrating Tests + +At this point the app hopefully works, but if you run your tests you may see that a lot of them are failing. This is because the current version of the `@testing-library/react` package does not support React 18. Unfortunately the new version that we will be moving to does not support React 17, which is why we need to do this all at once. + +:::info +If migrating your entire project at once is not feasible, you can try to add `devDependencies` for `react` and `react-dom` v17 to individual plugins to be migrated later. This is not something we have tried ourselves in practice, so let us know in the community Discord if you attempt this and how it goes. +::: + +#### Dependency Upgrades + +To get the tests working again we need to update `@testing-library/react` to at least v13, although while at it is sensible to move at least all the way to v14 since the additional breaking changes have low impact. For more information on the changes in v13, see the [release notes](https://github.com/testing-library/react-testing-library/releases/tag/v13.0.0). + +In addition to bumping `@testing-library/react` you also need to remove the `@testing-library/react-hooks` package, since it is now included in `@testing-library/react` itself. You can find more information on this change in the `@testing-library/react-hooks` [README.md](https://github.com/testing-library/react-hooks-testing-library?tab=readme-ov-file#a-note-about-react-18-support). + +The following search-and-replace RegEx patterns may by helpful in updating your `package.json` files: + +Find: `"@testing-library/react": ".*"`
+Replace: `"@testing-library/react": "^14.0.0"` + +Find: `"@testing-library/react-hooks": ".*",?`
+Replace: `` + +#### Test Updates + +Once you have installed the new versions of the dependencies this turns into a fairly mechanical process of updating the tests. Use your own favorite method for this, running all tests once to find the breakages and then focusing on one test file at a time was fairly smooth. + +When updating the tests in the Backstage project we found the following patterns to be useful: + +- Many existing `act(...)` calls can be removed, it is built into most testing utilities like `waitFor`, `.findBy*`, and `@testing-library/user-event`. +- Use `.findBy*` to wait for elements to appear. +- Use `waitFor(...)` to wait for any other expected state changes or multiple elements. +- Use `@testing-library/user-event` for user interactions. +- `renderHook` no longer forwards initial props to `wrapper`, they may need to be moved to a wrapper for the `wrapper` instead. +- Waiting for mock functions to be called by a component and then expecting render state to be updated is no longer reliable. +- Rendered components often don't immediately update on user input, it's more common to need to use `waitFor` or other utilities to wait for the expected state to be reached. + +You can also refer to the test changes in this [PR](https://github.com/backstage/backstage/pull/20598/files?file-filters%5B%5D=.ts&file-filters%5B%5D=.tsx), which was the migration to React 18 for the Backstage project itself. + +Best of luck! For question please join the [community Discord](https://discord.gg/backstage-687207715902193673). If you think this documentation could be improved we welcome you to [open an issue](https://github.com/backstage/backstage/issues/new/choose) or submit a pull request. diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 234afd78d6..187c41ad75 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -452,6 +452,7 @@ "tutorials/journey", "tutorials/quickstart-app-plugin", "tutorials/react-router-stable-migration", + "tutorials/react18-migration", "tutorials/package-role-migration", "tutorials/migrating-away-from-core", "tutorials/configuring-plugin-databases", From c043396c27ce869185a06d287065213be628cb48 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 17 Jan 2024 21:27:08 +0100 Subject: [PATCH 209/241] e2e-test: removed outdated unhandled rejection handler that would ignore errors Signed-off-by: Patrik Oldsberg --- packages/e2e-test/src/index.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/e2e-test/src/index.ts b/packages/e2e-test/src/index.ts index 92adc24b1e..f3c63ae175 100644 --- a/packages/e2e-test/src/index.ts +++ b/packages/e2e-test/src/index.ts @@ -36,23 +36,4 @@ async function main(argv: string[]) { program.parse(argv); } -process.on('unhandledRejection', (rejection: unknown) => { - // Try to avoid exiting if the unhandled error is coming from jsdom, i.e. zombie. - // Those are typically errors on the page that should be benign, at least in the - // context of this test. We have other ways of asserting that the page is being - // rendered correctly. - if ( - rejection instanceof Error && - rejection?.stack?.includes('node_modules/jsdom/lib') - ) { - console.log(`Ignored error inside jsdom, ${rejection?.stack ?? rejection}`); - } else { - if (rejection instanceof Error) { - exitWithError(rejection); - } else { - exitWithError(new Error(`Unknown rejection: '${rejection}'`)); - } - } -}); - main(process.argv).catch(exitWithError); From aeec29caf07e96f947049bb698ad5c3f4f42900e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 17 Jan 2024 20:53:19 +0100 Subject: [PATCH 210/241] create-app: migrate to React 18 Signed-off-by: Patrik Oldsberg --- .changeset/sour-rivers-fry.md | 9 +++++++++ packages/app/src/App.test.tsx | 9 ++++++--- .../create-app/templates/default-app/package.json.hbs | 4 ++-- .../default-app/packages/app/package.json.hbs | 10 +++++----- .../default-app/packages/app/src/App.test.tsx | 9 ++++++--- .../templates/default-app/packages/app/src/index.tsx | 4 ++-- 6 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 .changeset/sour-rivers-fry.md diff --git a/.changeset/sour-rivers-fry.md b/.changeset/sour-rivers-fry.md new file mode 100644 index 0000000000..1b74850614 --- /dev/null +++ b/.changeset/sour-rivers-fry.md @@ -0,0 +1,9 @@ +--- +'@backstage/create-app': patch +--- + +Updated `packages/app` as well as the root `package.json` type resolutions to use React v18. + +The `@testing-library/*` dependencies have also been updated to the ones compatible with React v18, and the test at `packages/app/src/App.test.tsx` had been updated to use more modern patterns that work better with these new versions. + +For information on how to migrate existing apps to React v18, see the [migration guide](https://backstage.io/docs/tutorials/react18-migration) diff --git a/packages/app/src/App.test.tsx b/packages/app/src/App.test.tsx index 8c7cefeb2c..919a60e53d 100644 --- a/packages/app/src/App.test.tsx +++ b/packages/app/src/App.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { renderWithEffects } from '@backstage/test-utils'; +import { render, waitFor } from '@testing-library/react'; import App from './App'; describe('App', () => { @@ -42,7 +42,10 @@ describe('App', () => { ] as any, }; - const rendered = await renderWithEffects(); - expect(rendered.baseElement).toBeInTheDocument(); + const rendered = render(); + + await waitFor(() => { + expect(rendered.baseElement).toBeInTheDocument(); + }); }); }); diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index b74957dd56..40cc8282d9 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -42,8 +42,8 @@ "typescript": "~5.2.0" }, "resolutions": { - "@types/react": "^17", - "@types/react-dom": "^17" + "@types/react": "^18", + "@types/react-dom": "^18" }, "prettier": "@spotify/prettier-config", "lint-staged": { diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index 598f049a4c..b403295b09 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -42,8 +42,8 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "history": "^5.0.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.2", + "react-dom": "^18.0.2", "react-router": "^6.3.0", "react-router-dom": "^6.3.0", "react-use": "^17.2.4" @@ -51,10 +51,10 @@ "devDependencies": { "@backstage/test-utils": "^{{version '@backstage/test-utils'}}", "@playwright/test": "^1.32.3", - "@testing-library/jest-dom": "^5.10.1", - "@testing-library/react": "^12.1.3", + "@testing-library/jest-dom": "^6.0.0", + "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.0.0", - "@testing-library/dom": "^8.0.0", + "@testing-library/dom": "^9.0.0", "@types/react-dom": "*", "cross-env": "^7.0.0" }, diff --git a/packages/create-app/templates/default-app/packages/app/src/App.test.tsx b/packages/create-app/templates/default-app/packages/app/src/App.test.tsx index b94cac73b3..ec8ba1d714 100644 --- a/packages/create-app/templates/default-app/packages/app/src/App.test.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/App.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { renderWithEffects } from '@backstage/test-utils'; +import { render, waitFor } from '@testing-library/react'; import App from './App'; describe('App', () => { @@ -20,7 +20,10 @@ describe('App', () => { ] as any, }; - const rendered = await renderWithEffects(); - expect(rendered.baseElement).toBeInTheDocument(); + const rendered = render(); + + await waitFor(() => { + expect(rendered.baseElement).toBeInTheDocument(); + }); }); }); diff --git a/packages/create-app/templates/default-app/packages/app/src/index.tsx b/packages/create-app/templates/default-app/packages/app/src/index.tsx index b16aaf7cd2..d875c774c8 100644 --- a/packages/create-app/templates/default-app/packages/app/src/index.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/index.tsx @@ -1,6 +1,6 @@ import '@backstage/cli/asset-types'; import React from 'react'; -import ReactDOM from 'react-dom'; +import ReactDOM from 'react-dom/client'; import App from './App'; -ReactDOM.render(, document.getElementById('root')); +ReactDOM.createRoot(document.getElementById('root')!).render(); From dc13f436197742e25807f4e59834f398778e8874 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 17 Jan 2024 22:19:50 +0100 Subject: [PATCH 211/241] docs/tutorials/react18: add type errors step Signed-off-by: Patrik Oldsberg --- docs/tutorials/react18-migration.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/react18-migration.md b/docs/tutorials/react18-migration.md index deb8518550..a3412b5105 100644 --- a/docs/tutorials/react18-migration.md +++ b/docs/tutorials/react18-migration.md @@ -65,9 +65,17 @@ ReactDOM.createRoot(document.getElementById('root')!).render(); Once these steps are done you should be able to run your app and see it working as before, except now using React 18. +### TypeScript Errors + +When upgrading to React 18 you are likely to see a fair number of TypeScript type errors. A summary of the breaking changes can be found in the [Pull Request that introduced them](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/56210). A codemod is also provided to help with the migration. + +Run `yarn tsc:full` to asses the damage. + +The good news is that these errors can be fixed while still staying on React 17. If you have a large number of errors to fix you can address as few or many is you like at a time and merge them into your main branch **without** the version bumps from step 1. This lets you gradually migrate the types in your project while not yet fully moving over to React 18. Once all type breakages are fixed you can move on to the next step of migrating tests. + ### Migrating Tests -At this point the app hopefully works, but if you run your tests you may see that a lot of them are failing. This is because the current version of the `@testing-library/react` package does not support React 18. Unfortunately the new version that we will be moving to does not support React 17, which is why we need to do this all at once. +At this point the app hopefully works and you have no type errors, but if you run your tests you may see that a lot of them are failing. This is because the current version of the `@testing-library/react` package does not support React 18. Unfortunately the new version that we will be moving to does not support React 17, which is why we need to do this all at once. :::info If migrating your entire project at once is not feasible, you can try to add `devDependencies` for `react` and `react-dom` v17 to individual plugins to be migrated later. This is not something we have tried ourselves in practice, so let us know in the community Discord if you attempt this and how it goes. From 98d0ac461cc691d1aa05e835ed8c681bcfc8538e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 17 Jan 2024 22:33:47 +0100 Subject: [PATCH 212/241] docs/tutorials/react18: some more details on how to migrate renderHook Signed-off-by: Patrik Oldsberg --- docs/tutorials/react18-migration.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/react18-migration.md b/docs/tutorials/react18-migration.md index a3412b5105..2d3b3a961a 100644 --- a/docs/tutorials/react18-migration.md +++ b/docs/tutorials/react18-migration.md @@ -105,7 +105,10 @@ When updating the tests in the Backstage project we found the following patterns - Use `.findBy*` to wait for elements to appear. - Use `waitFor(...)` to wait for any other expected state changes or multiple elements. - Use `@testing-library/user-event` for user interactions. -- `renderHook` no longer forwards initial props to `wrapper`, they may need to be moved to a wrapper for the `wrapper` instead. +- The `renderHook` API has changes in several ways: + - It no longer returns `waitForValueToChange` or `waitForNextUpdate`, you'll likely want to use `waitFor` instead. + - It now throws errors rather than returns them as part of the result. + - It no longer forwards `initialProps` to the `wrapper`, a workaround for this is provided in the [docs](https://testing-library.com/docs/react-testing-library/api/#renderhook-options-initialprops). - Waiting for mock functions to be called by a component and then expecting render state to be updated is no longer reliable. - Rendered components often don't immediately update on user input, it's more common to need to use `waitFor` or other utilities to wait for the expected state to be reached. From 762809def515faf01f05fbe40faca5885a9efd29 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Fri, 12 Jan 2024 10:50:07 -0500 Subject: [PATCH 213/241] clean up KubernetesBuilder tests * reduce whitespace * reduce duplication * simplify stubs (mostly using `mockResolvedValue`) * non-exhaustive attempt to ensure test backends get cleaned up Signed-off-by: Jamie Klassen --- .../src/service/KubernetesBuilder.test.ts | 453 +++++------------- 1 file changed, 125 insertions(+), 328 deletions(-) diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 5719a9392a..a35e488b50 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; import { ANNOTATION_KUBERNETES_AUTH_PROVIDER, ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER, @@ -24,10 +23,8 @@ import { import request from 'supertest'; import { ClusterDetails, - FetchResponseWrapper, KubernetesFetcher, KubernetesServiceLocator, - ObjectFetchParams, } from '../types/types'; import { KubernetesCredential } from '../auth/types'; import { @@ -64,95 +61,65 @@ describe('KubernetesBuilder', () => { let app: ExtendedHttpServer; let objectsProviderMock: KubernetesObjectsProvider; const happyK8SResult = { - items: [ - { - clusterOne: { - pods: [ - { - metadata: { - name: 'pod1', - }, - }, - ], - }, - }, - ], - } as any; - const policyMock: jest.Mocked = { - authorize: jest.fn(), - authorizeConditional: jest.fn(), + items: [{ clusterOne: { pods: [{ metadata: { name: 'pod1' } }] } }], }; const permissionsMock: ServiceMock = - mockServices.permissions.mock(policyMock); + mockServices.permissions.mock({ + authorize: jest.fn(), + authorizeConditional: jest.fn(), + }); + const minimalValidConfigService = mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { type: 'multiTenant' }, + clusterLocatorMethods: [], + }, + }, + }); + const withClusters = (clusters: ClusterDetails[]) => + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testClusterSupplier', + register(env) { + env.registerInit({ + deps: { extension: kubernetesClusterSupplierExtensionPoint }, + async init({ extension }) { + extension.addClusterSupplier({ + getClusters: jest.fn().mockResolvedValue(clusters), + }); + }, + }); + }, + }); beforeEach(async () => { jest.resetAllMocks(); objectsProviderMock = { - getKubernetesObjectsByEntity: jest.fn().mockImplementation(_ => { - return Promise.resolve(happyK8SResult); - }), - getCustomResourcesByEntity: jest.fn().mockImplementation(_ => { - return Promise.resolve(happyK8SResult); - }), - }; - - const clusterSupplierMock = { - getClusters: jest.fn().mockImplementation(_ => { - return Promise.resolve([ - { - name: 'some-cluster', - url: 'https://localhost:1234', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', - }, - }, - { - name: 'some-other-cluster', - url: 'https://localhost:1235', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'oidc', - [ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google', - }, - }, - ]); - }), + getKubernetesObjectsByEntity: jest.fn().mockResolvedValue(happyK8SResult), + getCustomResourcesByEntity: jest.fn().mockResolvedValue(happyK8SResult), }; jest.mock('@backstage/catalog-client', () => ({ - CatalogClient: jest.fn().mockImplementation(() => ({ - getEntityByRef: jest.fn().mockImplementation(entityRef => { + CatalogClient: jest.fn().mockReturnValue({ + getEntityByRef: jest.fn().mockImplementation(async entityRef => { if (entityRef.name === 'noentity') { - return Promise.resolve(undefined); + return undefined; } - return Promise.resolve({ + return { kind: entityRef.kind, metadata: { name: entityRef.name, namespace: entityRef.namespace, }, - } as Entity); + }; }), - })), + }), })); const { server } = await startTestBackend({ features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { - type: 'multiTenant', - }, - clusterLocatorMethods: [ - { - type: 'config', - clusters: [], - }, - ], - }, - }, - }), + minimalValidConfigService, import('@backstage/plugin-kubernetes-backend/alpha'), import('@backstage/plugin-permission-backend/alpha'), import('@backstage/plugin-permission-backend-module-allow-all-policy'), @@ -168,24 +135,33 @@ describe('KubernetesBuilder', () => { }); }, }), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testClusterSupplier', - register(env) { - env.registerInit({ - deps: { extension: kubernetesClusterSupplierExtensionPoint }, - async init({ extension }) { - extension.addClusterSupplier(clusterSupplierMock); - }, - }); + withClusters([ + { + name: 'some-cluster', + url: 'https://localhost:1234', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', + }, }, - }), + { + name: 'some-other-cluster', + url: 'https://localhost:1235', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'oidc', + [ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]: 'google', + }, + }, + ]), ], }); app = server; }); + afterEach(() => { + app.stop(); + }); + describe('get /clusters', () => { it('happy path: lists clusters', async () => { const response = await request(app).get('/api/kubernetes/clusters'); @@ -219,20 +195,16 @@ describe('KubernetesBuilder', () => { it('happy path: lists kubernetes objects with auth in request body', async () => { const response = await request(app) .post('/api/kubernetes/services/test-service') - .send({ - auth: { - google: 'google_token_123', - }, - }) + .send({ auth: { google: 'google_token_123' } }) .set('Content-Type', 'application/json'); expect(response.status).toEqual(200); expect(response.body).toEqual(happyK8SResult); }); it('internal error: lists kubernetes objects', async () => { - objectsProviderMock.getKubernetesObjectsByEntity = jest - .fn() - .mockRejectedValue(Error('some internal error')); + objectsProviderMock.getKubernetesObjectsByEntity.mockRejectedValue( + Error('some internal error'), + ); const response = await request(app).post( '/api/kubernetes/services/test-service', @@ -260,96 +232,29 @@ describe('KubernetesBuilder', () => { }, ]; - const clusterSupplierMock = { - getClusters: jest.fn().mockImplementation(_ => { - return Promise.resolve(clusters); + const pod = { metadata: { name: 'pod1' } }; + + const mockServiceLocator: jest.Mocked = { + getClustersByEntity: jest.fn().mockResolvedValue({ + clusters: [someCluster], }), }; - const pod = { - metadata: { - name: 'pod1', - }, - }; - const result: ObjectsByEntityResponse = { - items: [ - { - cluster: { - name: someCluster.name, - }, - errors: [], - podMetrics: [], - resources: [ - { - type: 'pods', - resources: [pod], - }, - ], - }, - ], - }; - - const mockServiceLocator: KubernetesServiceLocator = { - getClustersByEntity( - _entity: Entity, - ): Promise<{ clusters: ClusterDetails[] }> { - return Promise.resolve({ clusters: [someCluster] }); - }, - }; - - const mockFetcher: KubernetesFetcher = { - fetchPodMetricsByNamespaces( - _clusterDetails: ClusterDetails, - _credential: KubernetesCredential, - _namespaces: Set, - ): Promise { - return Promise.resolve({ errors: [], responses: [] }); - }, - fetchObjectsForService( - _params: ObjectFetchParams, - ): Promise { - return Promise.resolve({ - errors: [], - responses: [ - { - type: 'pods', - resources: [pod], - }, - ], - }); - }, + const mockFetcher: jest.Mocked = { + fetchPodMetricsByNamespaces: jest + .fn() + .mockResolvedValue({ errors: [], responses: [] }), + fetchObjectsForService: jest.fn().mockResolvedValue({ + errors: [], + responses: [{ type: 'pods', resources: [pod] }], + }), }; const { server } = await startTestBackend({ features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { - type: 'multiTenant', - }, - clusterLocatorMethods: [ - { - type: 'config', - clusters: [], - }, - ], - }, - }, - }), + minimalValidConfigService, import('@backstage/plugin-kubernetes-backend/alpha'), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testClusterSupplier', - register(env) { - env.registerInit({ - deps: { extension: kubernetesClusterSupplierExtensionPoint }, - async init({ extension }) { - extension.addClusterSupplier(clusterSupplierMock); - }, - }); - }, - }), + withClusters(clusters), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testFetcher', @@ -376,20 +281,22 @@ describe('KubernetesBuilder', () => { }), ], }); - app = server; const response = await request(app) .post('/api/kubernetes/services/test-service') - .send({ - entity: { - metadata: { - name: 'thing', - }, - }, - }); + .send({ entity: { metadata: { name: 'thing' } } }); - expect(response.body).toEqual(result); + expect(response.body).toEqual({ + items: [ + { + cluster: { name: someCluster.name }, + errors: [], + podMetrics: [], + resources: [{ type: 'pods', resources: [pod] }], + }, + ], + }); expect(response.status).toEqual(200); }); @@ -406,9 +313,11 @@ describe('KubernetesBuilder', () => { }), }; - const clusterSupplierMock = { - getClusters: jest.fn().mockImplementation(_ => { - return Promise.resolve([ + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + import('@backstage/plugin-kubernetes-backend/alpha'), + withClusters([ { name: 'custom-cluster', url: 'http://my.cluster.url', @@ -416,40 +325,7 @@ describe('KubernetesBuilder', () => { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', }, }, - ]); - }), - }; - - const { server } = await startTestBackend({ - features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { - type: 'multiTenant', - }, - clusterLocatorMethods: [ - { - type: 'config', - clusters: [], - }, - ], - }, - }, - }), - import('@backstage/plugin-kubernetes-backend/alpha'), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testClusterSupplier', - register(env) { - env.registerInit({ - deps: { extension: kubernetesClusterSupplierExtensionPoint }, - async init({ extension }) { - extension.addClusterSupplier(clusterSupplierMock); - }, - }); - }, - }), + ]), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testAuthStrategy', @@ -493,11 +369,7 @@ describe('KubernetesBuilder', () => { await request(app) .post('/api/kubernetes/services/test-service') .send({ - entity: { - metadata: { - name: 'thing', - }, - }, + entity: { metadata: { name: 'thing' } }, auth: { custom: 'custom-token' }, }); @@ -534,30 +406,26 @@ describe('KubernetesBuilder', () => { ); }); - it('returns the given request body with permission set to allow', async () => { - const requestBody = { + it('forwards request body to k8s', async () => { + const namespaceManifest = { kind: 'Namespace', apiVersion: 'v1', - metadata: { - name: 'new-ns', - }, + metadata: { name: 'new-ns' }, }; const proxyEndpointRequest = request(app) .post('/api/kubernetes/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') .set(HEADER_KUBERNETES_AUTH, 'randomtoken') - .send(requestBody); - + .send(namespaceManifest); worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); - const response = await proxyEndpointRequest; - expect(response.body).toStrictEqual(requestBody); + expect(response.body).toStrictEqual(namespaceManifest); }); - it('supports yaml content type with permission set to allow', async () => { - const requestBody = `--- + it('supports yaml content type', async () => { + const yamlManifest = `--- kind: Namespace apiVersion: v1 metadata: @@ -569,55 +437,37 @@ metadata: .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') .set(HEADER_KUBERNETES_AUTH, 'randomtoken') .set('content-type', 'application/yaml') - .send(requestBody); + .send(yamlManifest); worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); const response = await proxyEndpointRequest; - expect(response.text).toEqual(requestBody); + expect(response.text).toEqual(yamlManifest); }); - it('returns a 403 response if Permission Policy is in place that blocks endpoint', async () => { - const requestBody = { - kind: 'Namespace', - apiVersion: 'v1', - metadata: { - name: 'new-ns', - }, - }; - + it('returns 403 response when permission blocks endpoint', async () => { permissionsMock.authorize.mockResolvedValue([ { result: AuthorizeResult.DENY }, ]); const { server } = await startTestBackend({ features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { - type: 'multiTenant', - }, - clusterLocatorMethods: [ - { - type: 'config', - clusters: [], - }, - ], - }, - }, - }), + minimalValidConfigService, permissionsMock.factory, import('@backstage/plugin-kubernetes-backend/alpha'), - // import('@backstage/plugin-permission-backend/alpha'), ], }); + app = server; - const proxyEndpointRequest = request(server) + const proxyEndpointRequest = request(app) .post('/api/kubernetes/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') .set(HEADER_KUBERNETES_AUTH, 'randomtoken') - .send(requestBody); + .send({ + kind: 'Namespace', + apiVersion: 'v1', + metadata: { name: 'new-ns' }, + }); worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); @@ -636,62 +486,17 @@ metadata: }), ); - const clusterSupplierMock = { - getClusters: jest.fn().mockImplementation(_ => { - return Promise.resolve([ + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + import('@backstage/plugin-kubernetes-backend/alpha'), + withClusters([ { name: 'custom-cluster', url: 'http://my.cluster.url', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', - }, + authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom' }, }, - ]); - }), - }; - - const { server } = await startTestBackend({ - features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { - type: 'multiTenant', - }, - clusterLocatorMethods: [ - { - type: 'config', - clusters: [], - }, - ], - }, - }, - }), - import('@backstage/plugin-kubernetes-backend/alpha'), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testObjectsProvider', - register(env) { - env.registerInit({ - deps: { extension: kubernetesObjectsProviderExtensionPoint }, - async init({ extension }) { - extension.addObjectsProvider(objectsProviderMock); - }, - }); - }, - }), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testClusterSupplier', - register(env) { - env.registerInit({ - deps: { extension: kubernetesClusterSupplierExtensionPoint }, - async init({ extension }) { - extension.addClusterSupplier(clusterSupplierMock); - }, - }); - }, - }), + ]), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testAuthStrategy', @@ -715,9 +520,7 @@ metadata: ], }); - app = server; - - const proxyEndpointRequest = request(app) + const proxyEndpointRequest = request(server) .get('/api/kubernetes/proxy/api/v1/namespaces') .set(HEADER_KUBERNETES_CLUSTER, 'custom-cluster') .set(HEADER_KUBERNETES_AUTH, 'custom-token'); @@ -727,9 +530,9 @@ metadata: expect(response.body).toStrictEqual({ items: [] }); }); - it('should not permit custom auth strategies with dashes', async () => { - const throwError = async () => { - await startTestBackend({ + it('should not permit custom auth strategies with dashes', () => { + const throwError = () => + startTestBackend({ features: [ import('@backstage/plugin-kubernetes-backend/alpha'), createBackendModule({ @@ -754,9 +557,7 @@ metadata: }), ], }); - }; - - await expect(throwError).rejects.toThrow( + return expect(throwError).rejects.toThrow( 'Strategy name can not include dashes', ); }); @@ -771,11 +572,7 @@ metadata: expect(response.status).toEqual(200); expect(response.body).toMatchObject({ permissions: [ - { - type: 'basic', - name: 'kubernetes.proxy', - attributes: {}, - }, + { type: 'basic', name: 'kubernetes.proxy', attributes: {} }, ], rules: [], }); From 7f6ff255f1b2af507941577a8dfc4de1f9e7b874 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Fri, 12 Jan 2024 12:40:40 -0500 Subject: [PATCH 214/241] enable custom auth metadata in config Signed-off-by: Jamie Klassen --- .changeset/ten-numbers-happen.md | 5 + plugins/kubernetes-backend/config.d.ts | 11 +- .../ConfigClusterLocator.test.ts | 61 +++++++ .../cluster-locator/ConfigClusterLocator.ts | 8 +- .../src/service/KubernetesBuilder.test.ts | 150 ++++++++++++------ 5 files changed, 185 insertions(+), 50 deletions(-) create mode 100644 .changeset/ten-numbers-happen.md diff --git a/.changeset/ten-numbers-happen.md b/.changeset/ten-numbers-happen.md new file mode 100644 index 0000000000..73397d4568 --- /dev/null +++ b/.changeset/ten-numbers-happen.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +Custom per-cluster auth metadata (mainly for use with custom `AuthenticationStrategy` implementations) can now be specified in the `authMetadata` property of clusters in the app-config. diff --git a/plugins/kubernetes-backend/config.d.ts b/plugins/kubernetes-backend/config.d.ts index e9b5878920..9c5417a00e 100644 --- a/plugins/kubernetes-backend/config.d.ts +++ b/plugins/kubernetes-backend/config.d.ts @@ -46,13 +46,16 @@ export interface Config { /** @visibility secret */ serviceAccountToken?: string; /** @visibility frontend */ - authProvider: + authProvider?: + | 'aks' | 'aws' - | 'google' - | 'serviceAccount' | 'azure' + | 'google' + | 'googleServiceAccount' | 'oidc' - | 'googleServiceAccount'; + | 'serviceAccount'; + /** @visibility secret */ + authMetadata?: object; /** @visibility frontend */ oidcTokenProvider?: string; /** @visibility frontend */ diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts index 258cddcd66..cca2b28fcf 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts @@ -177,6 +177,67 @@ describe('ConfigClusterLocator', () => { ]); }); + it('reads custom authMetadata', async () => { + const config: Config = new ConfigReader({ + clusters: [ + { + name: 'cluster', + url: 'http://url', + authProvider: 'authProvider', + authMetadata: { 'custom-key': 'custom-value' }, + }, + ], + }); + + const result = await ConfigClusterLocator.fromConfig( + config, + authStrategy, + ).getClusters(); + + expect(result).toMatchObject([ + { + authMetadata: expect.objectContaining({ 'custom-key': 'custom-value' }), + }, + ]); + }); + + it('reads authProvider from metadata block', async () => { + const config: Config = new ConfigReader({ + clusters: [ + { + name: 'cluster', + url: 'http://url', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', + }, + }, + ], + }); + + const result = await ConfigClusterLocator.fromConfig( + config, + authStrategy, + ).getClusters(); + + expect(result).toMatchObject([ + { + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', + }, + }, + ]); + }); + + it('forbids cluster without auth provider', () => { + const config: Config = new ConfigReader({ + clusters: [{ name: 'cluster', url: 'http://url' }], + }); + + expect(() => ConfigClusterLocator.fromConfig(config, authStrategy)).toThrow( + 'Missing required config value', + ); + }); + it('one cluster with dashboardParameters', async () => { const config: Config = new ConfigReader({ clusters: [ diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts index 7899d7762d..816a9da0a6 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts @@ -37,7 +37,12 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier { ): ConfigClusterLocator { return new ConfigClusterLocator( config.getConfigArray('clusters').map(c => { - const authProvider = c.getString('authProvider'); + const authMetadataBlock = c.getOptional<{ + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]?: string; + }>('authMetadata'); + const authProvider = + authMetadataBlock?.[ANNOTATION_KUBERNETES_AUTH_PROVIDER] ?? + c.getString('authProvider'); const clusterDetails: ClusterDetails = { name: c.getString('name'), url: c.getString('url'), @@ -48,6 +53,7 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier { authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: authProvider, ...ConfigClusterLocator.parseAuthMetadata(c), + ...authMetadataBlock, }, }; diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index a35e488b50..42f953a2fe 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -17,7 +17,6 @@ import { ANNOTATION_KUBERNETES_AUTH_PROVIDER, ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER, - ObjectsByEntityResponse, KubernetesRequestAuth, } from '@backstage/plugin-kubernetes-common'; import request from 'supertest'; @@ -39,10 +38,7 @@ import { startTestBackend, } from '@backstage/backend-test-utils'; import { rest } from 'msw'; -import { - AuthorizeResult, - PermissionEvaluator, -} from '@backstage/plugin-permission-common'; +import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { PermissionsService, createBackendModule, @@ -57,9 +53,9 @@ import { } from '@backstage/plugin-kubernetes-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; -describe('KubernetesBuilder', () => { +describe('API integration tests', () => { let app: ExtendedHttpServer; - let objectsProviderMock: KubernetesObjectsProvider; + let objectsProviderMock: jest.Mocked; const happyK8SResult = { items: [{ clusterOne: { pods: [{ metadata: { name: 'pod1' } }] } }], }; @@ -530,52 +526,116 @@ metadata: expect(response.body).toStrictEqual({ items: [] }); }); - it('should not permit custom auth strategies with dashes', () => { - const throwError = () => - startTestBackend({ - features: [ - import('@backstage/plugin-kubernetes-backend/alpha'), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testAuthStrategy', - register(env) { - env.registerInit({ - deps: { extension: kubernetesAuthStrategyExtensionPoint }, - async init({ extension }) { - extension.addAuthStrategy('custom-strategy', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), - }); + it('reads custom auth metadata from config', async () => { + const authStrategy = { + getCredential: jest.fn().mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + }; + worker.use( + rest.get('http://my.cluster/api', (_req, res, ctx) => + res(ctx.json({})), + ), + ); + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { type: 'multiTenant' }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [ + { + name: 'cluster', + url: 'http://my.cluster', + authProvider: 'custom', + authMetadata: { 'custom-key': 'custom-value' }, + }, + ], }, - }); + ], }, - }), - ], - }); - return expect(throwError).rejects.toThrow( - 'Strategy name can not include dashes', + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', authStrategy); + }, + }); + }, + }), + ], + }); + app = server; + + const proxyEndpointRequest = request(app).get( + '/api/kubernetes/proxy/api', + ); + worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); + const response = await proxyEndpointRequest; + + expect(response.body).toStrictEqual({}); + expect(authStrategy.getCredential).toHaveBeenCalledWith( + expect.objectContaining({ + authMetadata: expect.objectContaining({ + 'custom-key': 'custom-value', + }), + }), + expect.anything(), ); }); }); - describe('get /.well-known/backstage/permissions/metadata', () => { - it('lists permissions supported by the kubernetes plugin', async () => { - const response = await request(app).get( - '/api/kubernetes/.well-known/backstage/permissions/metadata', - ); - - expect(response.status).toEqual(200); - expect(response.body).toMatchObject({ - permissions: [ - { type: 'basic', name: 'kubernetes.proxy', attributes: {} }, + it('forbids custom auth strategies with dashes', () => { + const throwError = () => + startTestBackend({ + features: [ + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom-strategy', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + }); + }, + }); + }, + }), ], - rules: [], }); + return expect(throwError).rejects.toThrow( + 'Strategy name can not include dashes', + ); + }); + + it('serves permission integration endpoint', async () => { + const response = await request(app).get( + '/api/kubernetes/.well-known/backstage/permissions/metadata', + ); + + expect(response.status).toEqual(200); + expect(response.body).toMatchObject({ + permissions: [ + { type: 'basic', name: 'kubernetes.proxy', attributes: {} }, + ], + rules: [], }); }); From 7125d9c4329542544cc9413c3a435573dec4691a Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Fri, 12 Jan 2024 17:41:49 -0500 Subject: [PATCH 215/241] regression test for parameter precedence Signed-off-by: Jamie Klassen --- .../ConfigClusterLocator.test.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts index cca2b28fcf..6fb33d8b3a 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts @@ -228,6 +228,34 @@ describe('ConfigClusterLocator', () => { ]); }); + it('prefers authMetadata block to top-level keys', async () => { + const sut = ConfigClusterLocator.fromConfig( + new ConfigReader({ + clusters: [ + { + name: 'cluster', + url: 'http://url', + authProvider: 'aws', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', + }, + }, + ], + }), + authStrategy, + ); + + const result = await sut.getClusters(); + + expect(result).toMatchObject([ + { + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', + }, + }, + ]); + }); + it('forbids cluster without auth provider', () => { const config: Config = new ConfigReader({ clusters: [{ name: 'cluster', url: 'http://url' }], From 413f08ddcc5dd156eb77c22b4ab7e69300cce70d Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Fri, 12 Jan 2024 17:42:23 -0500 Subject: [PATCH 216/241] improve error message on missing authProvider Signed-off-by: Jamie Klassen --- .../src/cluster-locator/ConfigClusterLocator.test.ts | 4 +++- .../src/cluster-locator/ConfigClusterLocator.ts | 12 ++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts index 6fb33d8b3a..1720ef5ed6 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts @@ -262,7 +262,9 @@ describe('ConfigClusterLocator', () => { }); expect(() => ConfigClusterLocator.fromConfig(config, authStrategy)).toThrow( - 'Missing required config value', + `cluster 'cluster' has no auth provider configured; this must be specified` + + ` via the 'authProvider' or ` + + `'authMetadata.${ANNOTATION_KUBERNETES_AUTH_PROVIDER}' parameter`, ); }); diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts index 816a9da0a6..19ba8634ad 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.ts @@ -40,11 +40,19 @@ export class ConfigClusterLocator implements KubernetesClustersSupplier { const authMetadataBlock = c.getOptional<{ [ANNOTATION_KUBERNETES_AUTH_PROVIDER]?: string; }>('authMetadata'); + const name = c.getString('name'); const authProvider = authMetadataBlock?.[ANNOTATION_KUBERNETES_AUTH_PROVIDER] ?? - c.getString('authProvider'); + c.getOptionalString('authProvider'); + if (!authProvider) { + throw new Error( + `cluster '${name}' has no auth provider configured; this must be ` + + `specified via the 'authProvider' or ` + + `'authMetadata.${ANNOTATION_KUBERNETES_AUTH_PROVIDER}' parameter`, + ); + } const clusterDetails: ClusterDetails = { - name: c.getString('name'), + name, url: c.getString('url'), skipTLSVerify: c.getOptionalBoolean('skipTLSVerify') ?? false, skipMetricsLookup: c.getOptionalBoolean('skipMetricsLookup') ?? false, From 8eb00c076799072b49a830e1da7fd43ec5c9cbd6 Mon Sep 17 00:00:00 2001 From: geon hyeon Date: Thu, 18 Jan 2024 10:07:30 +0900 Subject: [PATCH 217/241] Update README-ko_kr.md Signed-off-by: geon hyeon --- README-ko_kr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README-ko_kr.md b/README-ko_kr.md index f7bcba144b..0544304cea 100644 --- a/README-ko_kr.md +++ b/README-ko_kr.md @@ -22,10 +22,10 @@ Backstage 는 모든 인프라 도구, 서비스 및 문서를 통합하여 처 ![software-catalog](docs/assets/header.png) -Backstage 다음을 포함합니다: +Backstage는 다음을 포함합니다: - [Backstage Software Catalog](https://backstage.io/docs/features/software-catalog/) 마이크로 서비스, 라이브러리, 데이터 파이프라인, 웹 사이트, ML 모델 등 모든 소프트웨어 관리 -- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/) 새로운 프로젝트를 신속하게 시작하고 조직의 모밤 사례에따라 도구를 표준화 +- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/) 새로운 프로젝트를 신속하게 시작하고 조직의 모범 사례에따라 도구를 표준화 - [Backstage TechDocs](https://backstage.io/docs/features/techdocs/) "docs like code" 접근 방식을 사용하여 기술 문서를 쉽게 작성, 유지 관리, 검색 및 사용 - [open source plugins](https://github.com/backstage/backstage/tree/master/plugins) Backstage의 사용자 정의 가능성과 기능을 확장 From 0d526c85549081647abe0f3c50d3b91e163f7998 Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Date: Mon, 18 Dec 2023 17:22:30 -0500 Subject: [PATCH 218/241] feat: Make PodExecTerminal UI OptIn Signed-off-by: Carlos Esteban Lopez --- .changeset/sixty-shoes-prove.md | 6 ++ plugins/kubernetes-react/config.d.ts | 31 +++++++++ plugins/kubernetes-react/package.json | 4 +- .../Pods/PodDrawer/ContainerCard.tsx | 17 +++-- plugins/kubernetes-react/src/hooks/index.ts | 1 + .../useIsPodExecTerminalEnabled.test.tsx | 64 +++++++++++++++++++ .../src/hooks/useIsPodExecTerminalEnabled.ts | 27 ++++++++ .../useIsPodExecTerminalSupported.test.ts | 2 +- .../hooks/useIsPodExecTerminalSupported.ts | 1 + 9 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 .changeset/sixty-shoes-prove.md create mode 100644 plugins/kubernetes-react/config.d.ts create mode 100644 plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx create mode 100644 plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts diff --git a/.changeset/sixty-shoes-prove.md b/.changeset/sixty-shoes-prove.md new file mode 100644 index 0000000000..67a019f1ea --- /dev/null +++ b/.changeset/sixty-shoes-prove.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-react': patch +--- + +Make PodExecTerminal UI OptIn diff --git a/plugins/kubernetes-react/config.d.ts b/plugins/kubernetes-react/config.d.ts new file mode 100644 index 0000000000..d8f6ba8ca9 --- /dev/null +++ b/plugins/kubernetes-react/config.d.ts @@ -0,0 +1,31 @@ +import { PodExecTerminal } from './src/components/PodExecTerminal/PodExecTerminal'; +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface Config { + kubernetes?: { + /** + * Pod Exec Terminal config + */ + podExecTerminal?: { + /** + * Enable `PodExecTerminal` UI feature + * @visibility frontend + */ + enable?: boolean; + }; + }; +} diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 8389b4d2a9..d85cb7ba35 100644 --- a/plugins/kubernetes-react/package.json +++ b/plugins/kubernetes-react/package.json @@ -14,6 +14,7 @@ "role": "web-library" }, "sideEffects": false, + "configSchema": "config.d.ts", "scripts": { "start": "backstage-cli package start", "build": "backstage-cli package build", @@ -60,6 +61,7 @@ "msw": "^1.3.1" }, "files": [ - "dist" + "dist", + "config.d.ts" ] } diff --git a/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx b/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx index db70f92160..592a93e3ea 100644 --- a/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx +++ b/plugins/kubernetes-react/src/components/Pods/PodDrawer/ContainerCard.tsx @@ -27,6 +27,7 @@ import { IContainer, IContainerStatus } from 'kubernetes-models/v1'; import { DateTime } from 'luxon'; import React from 'react'; +import { useIsPodExecTerminalEnabled } from '../../../hooks'; import { bytesToMiB, formatMillicores } from '../../../utils/resources'; import { PodExecTerminalDialog } from '../../PodExecTerminal/PodExecTerminalDialog'; import { ResourceUtilization } from '../../ResourceUtilization'; @@ -108,6 +109,8 @@ export const ContainerCard: React.FC = ({ containerStatus, containerMetrics, }: ContainerCardProps) => { + const isPodExecTerminalEnabled = useIsPodExecTerminalEnabled(); + // This should never be undefined if (containerSpec === undefined) { return error reading pod from cluster; @@ -228,12 +231,14 @@ export const ContainerCard: React.FC = ({ ...podScope, }} /> - + {isPodExecTerminalEnabled && ( + + )} ); diff --git a/plugins/kubernetes-react/src/hooks/index.ts b/plugins/kubernetes-react/src/hooks/index.ts index 141bc3815b..2bc519d69a 100644 --- a/plugins/kubernetes-react/src/hooks/index.ts +++ b/plugins/kubernetes-react/src/hooks/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export * from './useIsPodExecTerminalEnabled'; export * from './useIsPodExecTerminalSupported'; export * from './useKubernetesObjects'; export * from './useCustomResources'; diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx new file mode 100644 index 0000000000..3faf81d9ae --- /dev/null +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx @@ -0,0 +1,64 @@ +/* + * Copyright 2023 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/core-app-api'; +import { configApiRef } from '@backstage/core-plugin-api'; +import { TestApiProvider } from '@backstage/test-utils'; +import { renderHook } from '@testing-library/react'; +import { PropsWithChildren } from 'react'; +import React from 'react'; + +import { useIsPodExecTerminalEnabled } from './useIsPodExecTerminalEnabled'; + +describe('useIsPodExecTerminalEnabled', () => { + let isPodExecTerminalEnabled: boolean | undefined; + + const apiWrapper = ({ children }: PropsWithChildren) => ( + + {children} + + ); + + it.each([ + { + condition: 'missing config', + returnValue: undefined, + }, + { condition: 'disabled', returnValue: false }, + { + condition: 'enabled', + returnValue: true, + }, + ])('Should return $returnValue if $condition', async ({ returnValue }) => { + isPodExecTerminalEnabled = returnValue; + + const { result } = renderHook(() => useIsPodExecTerminalEnabled(), { + wrapper: apiWrapper, + }); + + expect(result.current).toEqual(returnValue); + }); +}); diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts new file mode 100644 index 0000000000..683b9b9a5a --- /dev/null +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2023 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 { configApiRef, useApi } from '@backstage/core-plugin-api'; + +/** + * Check if conditions for a pod exec call through the proxy endpoint are met + * + * @internal + */ +export const useIsPodExecTerminalEnabled = (): boolean | undefined => { + const configApi = useApi(configApiRef); + + return configApi.getOptionalBoolean('kubernetes.podExecTerminal.enable'); +}; diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts index 93bfb6dd4d..c4df347c6f 100644 --- a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.test.ts @@ -20,7 +20,7 @@ import { useIsPodExecTerminalSupported } from './useIsPodExecTerminalSupported'; jest.mock('@backstage/core-plugin-api'); -describe('useIsClusterShellEnabled', () => { +describe('useIsPodExecTerminalSupported', () => { let clusters: { authProvider: string }[] = []; beforeEach(() => { diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts index e881951059..2483bb9412 100644 --- a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalSupported.ts @@ -15,6 +15,7 @@ */ import { useApi } from '@backstage/core-plugin-api'; import useAsync, { AsyncState } from 'react-use/lib/useAsync'; + import { kubernetesApiRef } from '../api/types'; /** From 8ed83b5b1023790d9085cae343878e947e590ba9 Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Date: Mon, 18 Dec 2023 17:26:55 -0500 Subject: [PATCH 219/241] chore: Remove unnecesary changeset package Signed-off-by: Carlos Esteban Lopez --- .changeset/sixty-shoes-prove.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/sixty-shoes-prove.md b/.changeset/sixty-shoes-prove.md index 67a019f1ea..5db1586ae0 100644 --- a/.changeset/sixty-shoes-prove.md +++ b/.changeset/sixty-shoes-prove.md @@ -1,5 +1,4 @@ --- -'@backstage/plugin-kubernetes-backend': patch '@backstage/plugin-kubernetes-react': patch --- From 3b84b4b9e48be9160a0e52e7b5b383bc4b819daa Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Jaramillo Date: Thu, 4 Jan 2024 15:31:42 -0500 Subject: [PATCH 220/241] Update .changeset/sixty-shoes-prove.md Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo --- .changeset/sixty-shoes-prove.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/sixty-shoes-prove.md b/.changeset/sixty-shoes-prove.md index 5db1586ae0..92edbcc079 100644 --- a/.changeset/sixty-shoes-prove.md +++ b/.changeset/sixty-shoes-prove.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-kubernetes-react': patch +'@backstage/plugin-kubernetes-react': minor --- Make PodExecTerminal UI OptIn From 7133da27dc67bfd3f4adeae0bf28a2658f1b3d0a Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Jaramillo Date: Thu, 4 Jan 2024 15:32:45 -0500 Subject: [PATCH 221/241] Update .changeset/sixty-shoes-prove.md Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo --- .changeset/sixty-shoes-prove.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/sixty-shoes-prove.md b/.changeset/sixty-shoes-prove.md index 92edbcc079..fe9438eeb2 100644 --- a/.changeset/sixty-shoes-prove.md +++ b/.changeset/sixty-shoes-prove.md @@ -2,4 +2,4 @@ '@backstage/plugin-kubernetes-react': minor --- -Make PodExecTerminal UI OptIn +**BREAKING** The pod exec terminal is now disabled by default since there are several scenarios where it is known not to work. It can be re-enabled at your own risk by setting the config parameter `kubernetes.podExecTerminal.enabled` to `true`. From d98604b667b561d2c7f5b15456a549137158e291 Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Jaramillo Date: Thu, 4 Jan 2024 15:33:19 -0500 Subject: [PATCH 222/241] Apply suggestions from code review Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo --- plugins/kubernetes-react/config.d.ts | 2 +- .../src/hooks/useIsPodExecTerminalEnabled.test.tsx | 2 +- .../kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/kubernetes-react/config.d.ts b/plugins/kubernetes-react/config.d.ts index d8f6ba8ca9..2d2b790d05 100644 --- a/plugins/kubernetes-react/config.d.ts +++ b/plugins/kubernetes-react/config.d.ts @@ -25,7 +25,7 @@ export interface Config { * Enable `PodExecTerminal` UI feature * @visibility frontend */ - enable?: boolean; + enabled?: boolean; }; }; } diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx index 3faf81d9ae..84e75ce529 100644 --- a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.test.tsx @@ -32,7 +32,7 @@ describe('useIsPodExecTerminalEnabled', () => { configApiRef, new ConfigReader({ kubernetes: { - podExecTerminal: { enable: isPodExecTerminalEnabled }, + podExecTerminal: { enabled: isPodExecTerminalEnabled }, }, }), ], diff --git a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts index 683b9b9a5a..7598e1c570 100644 --- a/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts +++ b/plugins/kubernetes-react/src/hooks/useIsPodExecTerminalEnabled.ts @@ -23,5 +23,5 @@ import { configApiRef, useApi } from '@backstage/core-plugin-api'; export const useIsPodExecTerminalEnabled = (): boolean | undefined => { const configApi = useApi(configApiRef); - return configApi.getOptionalBoolean('kubernetes.podExecTerminal.enable'); + return configApi.getOptionalBoolean('kubernetes.podExecTerminal.enabled'); }; From 536f67dd3d09403cfea37aed990524efd160f874 Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Date: Wed, 3 Jan 2024 18:05:23 -0500 Subject: [PATCH 223/241] fix: Revert broken xterm css import Signed-off-by: Carlos Esteban Lopez --- .changeset/funny-timers-visit.md | 5 +++++ .../PodExecTerminal/PodExecTerminal.tsx | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 .changeset/funny-timers-visit.md diff --git a/.changeset/funny-timers-visit.md b/.changeset/funny-timers-visit.md new file mode 100644 index 0000000000..3d802328b5 --- /dev/null +++ b/.changeset/funny-timers-visit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-react': patch +--- + +Fix broken XtermJS CSS import diff --git a/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx index f8106bd011..f67d79abb8 100644 --- a/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx +++ b/plugins/kubernetes-react/src/components/PodExecTerminal/PodExecTerminal.tsx @@ -13,9 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import 'xterm'; +import 'xterm/css/xterm.css'; import { discoveryApiRef, useApi } from '@backstage/core-plugin-api'; +import { createStyles, makeStyles, Theme } from '@material-ui/core'; import React, { useEffect, useMemo, useState } from 'react'; import { Terminal } from 'xterm'; import { FitAddon } from 'xterm-addon-fit'; @@ -37,12 +38,23 @@ export interface PodExecTerminalProps { const hasSocketProtocol = (url: string | URL) => /wss?:\/\//.test(url.toString()); +const useStyles = makeStyles((theme: Theme) => + createStyles({ + podExecTerminal: { + width: '100%', + height: '100%', + '& .xterm-screen': { padding: theme.spacing(1) }, + }, + }), +); + /** * Executes a `/bin/sh` process in the given pod's container and opens a terminal connected to it * * @public */ export const PodExecTerminal = (props: PodExecTerminalProps) => { + const classes = useStyles(); const { containerName, podNamespace, podName } = props; const [baseUrl, setBaseUrl] = useState(window.location.host); @@ -122,10 +134,7 @@ export const PodExecTerminal = (props: PodExecTerminalProps) => {
); }; From b92105443c1785fb969362bb85c4076e9662a737 Mon Sep 17 00:00:00 2001 From: Adam Vollrath Date: Wed, 17 Jan 2024 21:53:00 -0600 Subject: [PATCH 224/241] Include cluster name in initial "deploying" comment. This ensures the initial comment is discovered by the `find-comment` step. See line 114. This should prevent duplicate comments if the deployment fails. Signed-off-by: Adam Vollrath --- .github/workflows/uffizzi-preview.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uffizzi-preview.yaml b/.github/workflows/uffizzi-preview.yaml index 9591af3a23..2c1c353847 100644 --- a/.github/workflows/uffizzi-preview.yaml +++ b/.github/workflows/uffizzi-preview.yaml @@ -124,7 +124,7 @@ jobs: body: | ## Uffizzi Ephemeral Environment - Virtual Cluster - :cloud: deploying ... + :cloud: deploying cluster `pr-${{ needs.cache-manifests-file.outputs.pr-number }}` :gear: Updating now by workflow run [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}). From 109e0fc0c31f43174945e8310c5fced2e516e3dd Mon Sep 17 00:00:00 2001 From: Camila Belo Date: Thu, 18 Jan 2024 08:46:31 +0100 Subject: [PATCH 225/241] docs(frontend-system): fix building plugins typo Signed-off-by: Camila Belo --- docs/frontend-system/building-plugins/01-index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index cb29b3518a..eea2351977 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -18,7 +18,7 @@ This guide assumes that you already have a Backstage project set up. Even if you To create a frontend plugin, run `yarn new`, select `plugin`, and fill out the rest of the prompts. This will create a new package at `plugins/`, which will be the main entrypoint for your plugin. -> **NOT: The created plugin will currently be templated for use in the legacy frontend system, and you will need to replace the existing plugin wiring code.** +> **NOTE: The created plugin will currently be templated for use in the legacy frontend system, and you will need to replace the existing plugin wiring code.** ## The plugin instance From b1ed0ebe2971709864273bbefebb321b440f7739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 16 Jan 2024 14:24:07 +0100 Subject: [PATCH 226/241] bump to vale 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../vale/{Vocab => config/vocabularies}/Backstage/accept.txt | 0 .github/workflows/verify_docs-quality.yml | 2 +- CONTRIBUTING.md | 2 +- scripts/check-docs-quality.js | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename .github/vale/{Vocab => config/vocabularies}/Backstage/accept.txt (100%) diff --git a/.github/vale/Vocab/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt similarity index 100% rename from .github/vale/Vocab/Backstage/accept.txt rename to .github/vale/config/vocabularies/Backstage/accept.txt diff --git a/.github/workflows/verify_docs-quality.yml b/.github/workflows/verify_docs-quality.yml index 8e3b333dd3..d4b83ccefc 100644 --- a/.github/workflows/verify_docs-quality.yml +++ b/.github/workflows/verify_docs-quality.yml @@ -30,6 +30,6 @@ jobs: with: # This also contains --config=.github/vale/config.ini ... :/ files: '${{ steps.generate.outputs.args }}' - version: 2.30.0 # TODO: migrate to v3 + version: latest env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 527957677b..be88ed2249 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -386,7 +386,7 @@ Here are a few things that can help as you go through the review process: - PRs get automatically assigned so you don't need to ping people, they will be notified and have a process of their own for this - If you are waiting for a review or mid-review and your PR goes stale one of the easiest ways to clear the stale bot is by simply rebasing your PR - There are times where you might run into conflict with the `yarn.lock` during a rebase, to help with that make sure your `master` branch is up to date and then in your branch run `git checkout master yarn.lock` and then run `yarn install`, this will get you a conflict free `yarn.lock` file you can commit -- If Vale finds issues with your documentation but it's a code reference you can fix it by putting backticks (`) around it. Now if it is a special word or maybe a name there are two ways you can fix that by adding it to the list of accepted words in the [accept.txt file](https://github.com/backstage/backstage/blob/master/.github/vale/Vocab/Backstage/accept.txt) and them committing that change +- If Vale finds issues with your documentation but it's a code reference you can fix it by putting backticks (`) around it. Now if it is a special word or maybe a name there are two ways you can fix that by adding it to the list of accepted words in the [accept.txt file](https://github.com/backstage/backstage/blob/master/.github/vale/config/vocabularies/Backstage/accept.txt) and them committing that change ### Merging to Master diff --git a/scripts/check-docs-quality.js b/scripts/check-docs-quality.js index d3b51a49a3..7960ff72bb 100755 --- a/scripts/check-docs-quality.js +++ b/scripts/check-docs-quality.js @@ -70,7 +70,7 @@ async function exitIfMissingVale() { process.exit(1); } console.log(`Language linter (vale) generated errors. Please check the errors and review any markdown files that you changed. - Possibly update .github/vale/Vocab/Backstage/accept.txt to add new valid words.\n`); + Possibly update .github/vale/config/vocabularies/Backstage/accept.txt to add new valid words.\n`); process.exit(0); } } @@ -89,7 +89,7 @@ async function runVale(files) { // If it contains system level error. In this case vale does not exist. if (process.platform !== 'win32' || result.error) { console.log(`Language linter (vale) generated errors. Please check the errors and review any markdown files that you changed. - Possibly update .github/vale/Vocab/Backstage/accept.txt to add new valid words.\n`); + Possibly update .github/vale/config/vocabularies/Backstage/accept.txt to add new valid words.\n`); } return false; } From 49b3b5ef9907c1157aad49620bd6c43602d01b1d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 09:22:49 +0000 Subject: [PATCH 227/241] fix(deps): update dependency @asyncapi/react-component to v1.2.13 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .changeset/renovate-fb2e0b9.md | 5 +++ plugins/api-docs/package.json | 2 +- yarn.lock | 66 +++++++++++++++++----------------- 3 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 .changeset/renovate-fb2e0b9.md diff --git a/.changeset/renovate-fb2e0b9.md b/.changeset/renovate-fb2e0b9.md new file mode 100644 index 0000000000..39277aaa2a --- /dev/null +++ b/.changeset/renovate-fb2e0b9.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Updated dependency `@asyncapi/react-component` to `1.2.13`. diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 1819d80208..7159aec206 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -33,7 +33,7 @@ "clean": "backstage-cli package clean" }, "dependencies": { - "@asyncapi/react-component": "1.2.6", + "@asyncapi/react-component": "1.2.13", "@backstage/catalog-model": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", diff --git a/yarn.lock b/yarn.lock index 53cd19f848..04e255eadc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -138,35 +138,35 @@ __metadata: languageName: node linkType: hard -"@asyncapi/avro-schema-parser@npm:^3.0.7": - version: 3.0.7 - resolution: "@asyncapi/avro-schema-parser@npm:3.0.7" +"@asyncapi/avro-schema-parser@npm:^3.0.9": + version: 3.0.9 + resolution: "@asyncapi/avro-schema-parser@npm:3.0.9" dependencies: - "@asyncapi/parser": ^3.0.1 + "@asyncapi/parser": ^3.0.2 "@types/json-schema": ^7.0.11 avsc: ^5.7.6 - checksum: c7755708161f41812ebee90c92fb721176230f0006ddd01683b72c7c1d484a6c5cbe7d7e59c54a5c7221f5f722388642ec26b19a67adc9d30059067cc4276d69 + checksum: db451bc9413a9caef2e45f577dbc04c0e2f94183793ab791979384e900716b2af9d77db15251128b4316b6a87bdb4be6405fb12d3712a21a6f6d3e71256a18e4 languageName: node linkType: hard -"@asyncapi/openapi-schema-parser@npm:^3.0.8": - version: 3.0.8 - resolution: "@asyncapi/openapi-schema-parser@npm:3.0.8" +"@asyncapi/openapi-schema-parser@npm:^3.0.10": + version: 3.0.10 + resolution: "@asyncapi/openapi-schema-parser@npm:3.0.10" dependencies: - "@asyncapi/parser": ^3.0.1 + "@asyncapi/parser": ^3.0.2 "@openapi-contrib/openapi-schema-to-json-schema": ~3.2.0 ajv: ^8.11.0 ajv-errors: ^3.0.0 ajv-formats: ^2.1.1 - checksum: 9c3f49d1a826818b864b2a0b16144d88eb2ecf7ca1d9c1e8554eac30d9875619638924892d093f0270b6b9a04efca1a8918dd5a7eb13fd88c14183d467af5ceb + checksum: ddab8b38b86a2ca12dc9345e1a911cfd63bd537524bbb3bc804a137947381eb97e287c6383cf3575a46cadb73f60c2a826a589c54b15ef3881e5a2bb499d2f4c languageName: node linkType: hard -"@asyncapi/parser@npm:^3.0.1": - version: 3.0.1 - resolution: "@asyncapi/parser@npm:3.0.1" +"@asyncapi/parser@npm:^3.0.2": + version: 3.0.2 + resolution: "@asyncapi/parser@npm:3.0.2" dependencies: - "@asyncapi/specs": ^6.1.0 + "@asyncapi/specs": ^6.2.0 "@openapi-contrib/openapi-schema-to-json-schema": ~3.2.0 "@stoplight/json": ^3.20.2 "@stoplight/json-ref-readers": ^1.2.2 @@ -185,29 +185,29 @@ __metadata: js-yaml: ^4.1.0 jsonpath-plus: ^7.2.0 node-fetch: 2.6.7 - checksum: 6dce457e58dcf9dab8bfb945a7cb9507a2fb686c143d04b77f2f1fe1c1247f9fa76134c872203c3e10398005155f4b9bb4b5e43edfb956c1e9ae4d3d95b6ceb3 + checksum: 07c82c5fddbc97f5f53a7ab29e0e8b538d325bbd2a15c9f130b79d7f0d253af001207ea9121b7de88d672f23514bdf33d327bb322653281f0cd582ea9f15e962 languageName: node linkType: hard -"@asyncapi/protobuf-schema-parser@npm:^3.0.4": - version: 3.0.4 - resolution: "@asyncapi/protobuf-schema-parser@npm:3.0.4" +"@asyncapi/protobuf-schema-parser@npm:^3.0.6": + version: 3.0.6 + resolution: "@asyncapi/protobuf-schema-parser@npm:3.0.6" dependencies: - "@asyncapi/parser": ^3.0.1 + "@asyncapi/parser": ^3.0.2 "@types/protocol-buffers-schema": ^3.4.1 protocol-buffers-schema: ^3.6.0 - checksum: c176e6d86e53f342ac91067279fb6e1ac3ed9d7f36de197fc723a2ceaf2a2588267c445203d67edcb3cd75308c0c0d6ea401ad69508bfe378c9194420702d3db + checksum: 9e185734971c10bcc5155b734939a74f3b87b4fe6173c8e4d404c723611b0257a67e4728c3999ea5d37d9ae89608026f73a9bdc4fb51bfa958eb5eece418aee3 languageName: node linkType: hard -"@asyncapi/react-component@npm:1.2.6": - version: 1.2.6 - resolution: "@asyncapi/react-component@npm:1.2.6" +"@asyncapi/react-component@npm:1.2.13": + version: 1.2.13 + resolution: "@asyncapi/react-component@npm:1.2.13" dependencies: - "@asyncapi/avro-schema-parser": ^3.0.7 - "@asyncapi/openapi-schema-parser": ^3.0.8 - "@asyncapi/parser": ^3.0.1 - "@asyncapi/protobuf-schema-parser": ^3.0.4 + "@asyncapi/avro-schema-parser": ^3.0.9 + "@asyncapi/openapi-schema-parser": ^3.0.10 + "@asyncapi/parser": ^3.0.2 + "@asyncapi/protobuf-schema-parser": ^3.0.6 highlight.js: ^10.7.2 isomorphic-dompurify: ^0.13.0 marked: ^4.0.14 @@ -216,7 +216,7 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 4afb34562767771048d0848323adea8d498dc555cc529947d4a45f3ec8d7f172bb454814bcf9c4419e105a743736368b56b3ed54d09b60addc06a287ca0e82b9 + checksum: 1e870caa07a3507685ab52af7e34f31c47b31464159f435f29b0be68adf1c110dc0c9196d8f20ab1d6b998500bbac821181477897636322c0c29fe2708284871 languageName: node linkType: hard @@ -229,12 +229,12 @@ __metadata: languageName: node linkType: hard -"@asyncapi/specs@npm:^6.1.0": - version: 6.1.0 - resolution: "@asyncapi/specs@npm:6.1.0" +"@asyncapi/specs@npm:^6.2.0": + version: 6.2.0 + resolution: "@asyncapi/specs@npm:6.2.0" dependencies: "@types/json-schema": ^7.0.11 - checksum: d4ad199ef58b8ef6be081e2e71fd172fdf6720479f3ae6f9b1e58037f833ca177c8af1dadeab4525c2c07e68ea0a4832e0d3dd67c3b033b988ca2435245f6aa6 + checksum: 9fa959350a75d9d9ab886436720d59bbf1c7bff16ed657fa34cce3a006136d2d853264366c8eee5abf4761f611c305acd5d7fb17e6de92fdc573b32e08f94912 languageName: node linkType: hard @@ -4425,7 +4425,7 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-api-docs@workspace:plugins/api-docs" dependencies: - "@asyncapi/react-component": 1.2.6 + "@asyncapi/react-component": 1.2.13 "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" From ff57376959c93a9131298606e302b55cc19b4232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 18 Jan 2024 10:02:09 +0100 Subject: [PATCH 228/241] some minor doc tweaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../architecture/05-extension-overrides.md | 4 +-- .../frontend-system/architecture/07-routes.md | 22 ++++++------- .../building-plugins/01-index.md | 32 ++++++++++++++----- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/docs/frontend-system/architecture/05-extension-overrides.md b/docs/frontend-system/architecture/05-extension-overrides.md index 6a1037341e..21028627bc 100644 --- a/docs/frontend-system/architecture/05-extension-overrides.md +++ b/docs/frontend-system/architecture/05-extension-overrides.md @@ -12,7 +12,7 @@ description: Frontend extension overrides An extension override is a building block of the frontend system that allows you to programmatically override app or plugin extensions anywhere in your application. Since the entire application is built mostly out of extensions from the bottom up, this is a powerful feature. You can use it for example to provide your own app root layout, to replace the implementation of a Utility API with a custom one, to override how the catalog page renders itself, and much more. -In general, most features should have a good level of customization built into them, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has `app-config` settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin, which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should take advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation for guidance. +In general, most features should have a good level of customization built into them, so that users do not have to leverage extension overrides to achieve common goals. A well written feature often has [configuration](../../conf/) settings, or uses extension inputs for extensibility where applicable. An example of this is the search plugin, which allows you to provide result renderers as inputs rather than replacing the result page wholesale just to tweak how results are shown. Adopters should take advantage of those when possible, and only use extension overrides when it's necessary to entirely replace the extension. Check the respective extension documentation for guidance. ## Override App Extensions @@ -74,7 +74,7 @@ import themeOverrides from './themes'; const app = createApp({ // highlight-next-line - features: [ themeOverrides ], + features: [themeOverrides], }); export default app.createRoot(). diff --git a/docs/frontend-system/architecture/07-routes.md b/docs/frontend-system/architecture/07-routes.md index 60bf335158..8351a864ba 100644 --- a/docs/frontend-system/architecture/07-routes.md +++ b/docs/frontend-system/architecture/07-routes.md @@ -10,15 +10,15 @@ description: Frontend routes ## Introduction -Each Backstage plugin is an isolated piece of functionality that doesn't typically communicate directly with other plugins. In order to achieve this, there are many parts of the frontend system that provide a layer of indirection for cross-plugin communication, and they routing system is one of them. +Each Backstage plugin is an isolated piece of functionality that doesn't typically communicate directly with other plugins. In order to achieve this, there are many parts of the frontend system that provide a layer of indirection for cross-plugin communication, and the routing system is one of them. The Backstage routing system makes it possible to implement navigation across plugin boundaries, without each individual plugin knowing the concrete path or location of other plugins in the routing hierarchy, or even its own. This is achieved through the concept of route references, which are opaque reference values that can be shared and used to create concrete links to different parts of an app. The route ref paths can be configured both at plugin level (by plugin developers) and at the app level (by integrators). It is up to plugin developers to create route references for any page content in their plugin that they want it to be possible to link to or from. ## Route References -Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sections). +Plugin developers create a `RouteRef` to expose a path in Backstage's routing system. You will see below how routes are defined programmatically, but before diving into code, let us explain how to configure them at the app level. In spite of the fact that plugin developers choose a default route path for the routes their plugin provides, paths are configurable, so app integrators can set a custom path to a route whenever they like to (more information in the following sections). -There are 3 types of route references: regular route, sub route, and external route, and we will cover both the concept and code definition for each. +There are three types of route references: regular route, sub route, and external route, and we will cover both the concept and code definition for each. ### Creating a Route Reference @@ -31,7 +31,7 @@ import { createRouteRef } from '@backstage/frontend-plugin-api'; export const indexRouteRef = createRouteRef(); ``` -Note that you often want to create the route references themselves in a different file than the one that creates the plugin instance, for example a top-level routes.ts. This is to avoid circular imports when you use the route references from other parts of the same plugin. +Note that you often want to create the route references themselves in a different file than the one that creates the plugin instance, for example a top-level `routes.ts`. This is to avoid circular imports when you use the route references from other parts of the same plugin. Route refs do not have any behavior themselves. They are an opaque value that represents route targets in an app, which are bound to specific paths at runtime. Their role is to provide a level of indirection to help link together different pages that otherwise wouldn't know how to route to each other. @@ -68,7 +68,7 @@ export default createPlugin({ In the example above we associated the `indexRouteRef` with the `catalogIndexPage` extension and provided both the route ref and page via the Catalog plugin. So, When this plugin is installed in the app, the index page will become associated with the newly created `RouteRef`, making it possible to use the route ref to navigate the page extension. -It may be unclear why we configure the routes option when creating a plugin as the route has already been passed to the extension. We do that to make it possible for other plugins to route to our page, which is explained in detail in the [binding routes](#binding-external-route-references) section. +It may seem unclear why we configure the `routes` option when creating a plugin as the route has already been passed to the extension. We do that to make it possible for other plugins to route to our page, which is explained in detail in the [binding routes](#binding-external-route-references) section. ### Defining References with Path Parameters @@ -86,7 +86,7 @@ export const detailsRouteRef = createRouteRef({ ### Using a Route Reference -Route references can be used to link to page in the same plugin, or to pages in a different plugins. In this section we will cover the first scenario, if you are interested in link to a page of a different plugin, please go to the [external routes](#external-router-references) section below. +Route references can be used to link to page in the same plugin, or to pages in different plugins. In this section we will cover the first scenario. If you are interested in linking to a page of a different plugin, please go to the [external routes](#external-route-references) section below. Suppose we are creating a plugin that renders a Catalog index page with a link to a "Foo" component details page. Here is the code for the index page: @@ -117,7 +117,7 @@ export const IndexPage = () => { }; ``` -We use the `useRouteRef` hook to create a link generator function that returns the details page path. We then call the link generator, passing it an object with the kind, namespace, and name. These parameters are used to construct a concrete path to details the "Foo" details page. +We use the `useRouteRef` hook to create a link generator function that returns the details page path. We then call the link generator, passing it an object with the kind, namespace, and name. These parameters are used to construct a concrete path to the "Foo" details page. Let's see how the details page can get the parameters from the URL: @@ -148,12 +148,12 @@ In the code above, we are using the `useRouteRefParams` hook to retrieve the ent Since we are linking to pages of the same package, we are using a route ref directly. However, in the following sections, you will see how to link to pages of different plugins. -## External Router References +## External Route References External routes are made for linking to a page of an external plugin. For this section example, let's assume that we want to link from the Catalog entities list page to the Scaffolder create component page. -We don't want to reference the Scaffolder plugin directly, since that would create an unnecessary dependency. It would also provided little flexibility in allowing the app to tie plugins together, with the links instead being dictated by the plugins themselves. To solve this, we use an `ExternalRouteRef`. Much like regular route references, they can be passed to `useRouteRef` to create concrete URLs, but they can not be used in page extensions and instead have to be associated with a target route using route bindings in the app. +We don't want to reference the Scaffolder plugin directly, since that would create an unnecessary dependency. It would also provide little flexibility in allowing the app to tie plugins together, with the links instead being dictated by the plugins themselves. To solve this, we use an `ExternalRouteRef`. Much like regular route references, they can be passed to `useRouteRef` to create concrete URLs, but they can not be used in page extensions and instead have to be associated with a target route using route bindings in the app. We create a new `RouteRef` inside the Scaffolder plugin, using a neutral name that describes its role in the plugin rather than a specific plugin page that it might be linking to, allowing the app to decide the final target. If the Catalog entity list page for example wants to link the Scaffolder create component page in the header, it might declare an `ExternalRouteRef` similar to this: @@ -272,7 +272,7 @@ export default app.createRoot(); Note that we are not importing and using the `RouteRef`s directly in the app, and instead rely on the plugin instance to access routes of the plugins. This provides better namespacing and discoverability of routes, as well as reduce the number of separate exports from each plugin package. -Another thing to note is that this indirection in the routing is particularly useful for open source plugins that need to leave flexibility in how they are integrated. For plugins that you build internally for your own Backstage application, you can choose to go the route of direct imports or even use concrete routes directly. Although there can be some benefits to using the full routing system even in internal plugins. It can help you structure your routes, and as you will see further down it also helps you manage route parameters. +Another thing to note is that this indirection in the routing is particularly useful for open source plugins that need to provide flexibility in how they are integrated. For plugins that you build internally for your own Backstage application, you can choose to use direct imports or even concrete route path strings directly. Although there can be some benefits to using the full routing system even in internal plugins: it can help you structure your routes, and as you will see further down it also helps you manage route parameters. ### Optional External Route References @@ -312,7 +312,7 @@ export const IndexPage = () => { ## Sub Route References -The last kind of route refs that can be created are `SubRouteRef`s, which can be used to create a route ref with a fixed path relative to an absolute `RouteRef`. They are useful if you have a page that internally is mounted at a sub route of a page extension component, and you want other plugins to be able to route to that page. And they can be a useful utility to handle routing within a plugin itself as well. +The last kind of route ref that can be created is a `SubRouteRef`, which can be used to create a route ref with a fixed path relative to an absolute `RouteRef`. They are useful if you have a page that internally is mounted at a sub route of a page extension component, and you want other plugins to be able to route to that page. And they can be a useful utility to handle routing within a plugin itself as well. For example: diff --git a/docs/frontend-system/building-plugins/01-index.md b/docs/frontend-system/building-plugins/01-index.md index eea2351977..f8d80f9382 100644 --- a/docs/frontend-system/building-plugins/01-index.md +++ b/docs/frontend-system/building-plugins/01-index.md @@ -18,7 +18,9 @@ This guide assumes that you already have a Backstage project set up. Even if you To create a frontend plugin, run `yarn new`, select `plugin`, and fill out the rest of the prompts. This will create a new package at `plugins/`, which will be the main entrypoint for your plugin. -> **NOTE: The created plugin will currently be templated for use in the legacy frontend system, and you will need to replace the existing plugin wiring code.** +:::info +The created plugin will currently be templated for use in the legacy frontend system, and you will need to replace the existing plugin wiring code. +::: ## The plugin instance @@ -67,7 +69,7 @@ import { } from '@backstage/frontend-plugin-api'; import { rootRouteRef } from './routes'; -// Note that these extensions aren't exported, only the plugin itself it. +// Note that these extensions aren't exported, only the plugin itself is. // You can export it locally for testing purposes, but don't export it from the plugin package. const examplePage = createPageExtension({ routeRef: rootRouteRef, @@ -104,7 +106,7 @@ export const examplePlugin = createPlugin({ What we've built here is a very common type of plugin. It's a top-level tool that provides a single page, along with a method for navigating to that page. The implementation of the page component, in this case the highlighted `ExamplePage`, can be arbitrarily complex. It can be anything from a single simple information page, to a full-blown application with multiple sub-pages. -We have also provided external access to our route reference by passing it to the plugin `routes` option. This makes it possible for app integrators to bind an external link from a different plugin to our plugin page. You can read more about how this works in the [External Route References](../architecture/07-routes.md#external-router-references) section. +We have also provided external access to our route reference by passing it to the plugin `routes` option. This makes it possible for app integrators to bind an external link from a different plugin to our plugin page. You can read more about how this works in the [External Route References](../architecture/07-routes.md#external-route-references) section. ## Utility APIs @@ -141,7 +143,7 @@ export function ExamplePage() { return (

Example Page

-

Example: {exampleApi.getExample()}

+

Example: {exampleApi.getExample().example}

); } @@ -182,14 +184,14 @@ export const examplePlugin = createPlugin({ ## Plugin specific extensions -There are many different plugins that you can extend with additional functionality through extensions. One such plugin is the catalog plugin, one of the core features of Backstage. It lets you catalog the software in your organization, where each item in the catalog has its own page that can be populated with tools and information relating to that catalog entity. In this example we will explore how our plugin can provide such a tool to display on an entity page. +There are many different plugins that you can extend with additional functionality through extensions. One such plugin is [the catalog plugin](../../features/software-catalog/), one of the core features of Backstage. It lets you catalog the software in your organization, where each item in the catalog has its own page that can be populated with tools and information relating to that catalog entity. In this example we will explore how our plugin can provide such a tool to display on an entity page. ```tsx title="in src/plugin.ts - An example entity content extension" import { createEntityContentExtension } from '@backstage/plugin-catalog-react'; -// Entity content extension are similar to page extensions in that they are rendered at a route, +// Entity content extensions are similar to page extensions in that they are rendered at a route, // although they also have a title to support in-line navigation between the different content. -// Just like a page extensions the content is lazy loaded, and you can also provide a +// Just like a page extension the content is lazy loaded, and you can also provide a // route reference if you want to be able to generate a URL that links to the content. const exampleEntityContent = createEntityContentExtension({ defaultPath: 'example', @@ -199,8 +201,22 @@ const exampleEntityContent = createEntityContentExtension({ )), }); + +export const examplePlugin = createPlugin({ + id: 'example', + extensions: [ + // highlight-add-next-line + exampleEntityContent + exampleApi, + examplePage, + exampleNavItem, + ], + routes: { + root: rootRouteRef, + }, +}); ``` -The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of API provided by the catalog React library in [the API reference](../../reference/plugin-catalog-react.md). +The `ExampleEntityContent` itself is again a regular React component where you can implement any functionality you want. To access the entity that the content is being rendered for, you can use the `useEntity` hook from `@backstage/plugin-catalog-react`. You can see a full list of APIs provided by the catalog React library in [the API reference](../../reference/plugin-catalog-react.md). For a more complete list of the different types of extensions that you can create for your plugin, see the [extension types](./03-extension-types.md) section. From 2aef2c951cba58366f24ae50ee2ad69adf21da59 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 10:03:43 +0000 Subject: [PATCH 229/241] chore(deps): update dependency vite-plugin-html to v3.2.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 04e255eadc..335a01e55a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -43811,8 +43811,8 @@ __metadata: linkType: hard "vite-plugin-html@npm:^3.2.0": - version: 3.2.1 - resolution: "vite-plugin-html@npm:3.2.1" + version: 3.2.2 + resolution: "vite-plugin-html@npm:3.2.2" dependencies: "@rollup/pluginutils": ^4.2.0 colorette: ^2.0.16 @@ -43828,7 +43828,7 @@ __metadata: pathe: ^0.2.0 peerDependencies: vite: ">=2.0.0" - checksum: 6add7cd7a8f9e83b0c58b20cde2d4da7e132ef56db6a60f3d4cc7022c944896236aeca6bde4c6dc2da3d506f756f63de56251adc47f0ae359c07485b24dd64db + checksum: 2fd6e1f91f74a4432222ed28e68d5f27e58ccbc9ad44e71ff9d02b684b358b0c634bdb4dd32e9d93d09e88d83c3b7b74b89698e25510bc5b94173cdc067b3ac2 languageName: node linkType: hard From ca7ce199d61bae00bb552f89ea60185b02ac7d68 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 11:04:38 +0000 Subject: [PATCH 230/241] chore(deps): update dependency @openapitools/openapi-generator-cli to v2.8.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 145 ++++++++++++++++++++++++------------------------------ 1 file changed, 64 insertions(+), 81 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4cdd331ec2..834786fa6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12959,58 +12959,54 @@ __metadata: languageName: node linkType: hard -"@nestjs/axios@npm:0.1.0": - version: 0.1.0 - resolution: "@nestjs/axios@npm:0.1.0" - dependencies: - axios: 0.27.2 +"@nestjs/axios@npm:3.0.1": + version: 3.0.1 + resolution: "@nestjs/axios@npm:3.0.1" peerDependencies: - "@nestjs/common": ^7.0.0 || ^8.0.0 || ^9.0.0 + "@nestjs/common": ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + axios: ^1.3.1 reflect-metadata: ^0.1.12 rxjs: ^6.0.0 || ^7.0.0 - checksum: 72929b25caacb85517bae962b13d865a31aa3984aa9e55305e0a2306e54338fe51a7eb38ca38cab0fe8b4116fb35219bd02c8b0c4cac70e7b5aeb84d03a1db3f + checksum: 01cebc64efa7a1d9df7a9053fbc5124986a95078789a0f280a2a61c31601a70a35745e07fc385497b4f85c7bdb6216a3575728646f1e6e684c038ac31900129c languageName: node linkType: hard -"@nestjs/common@npm:9.3.11": - version: 9.3.11 - resolution: "@nestjs/common@npm:9.3.11" +"@nestjs/common@npm:10.3.0": + version: 10.3.0 + resolution: "@nestjs/common@npm:10.3.0" dependencies: iterare: 1.2.1 - tslib: 2.5.0 - uid: 2.0.1 + tslib: 2.6.2 + uid: 2.0.2 peerDependencies: - cache-manager: <=5 class-transformer: "*" class-validator: "*" reflect-metadata: ^0.1.12 rxjs: ^7.1.0 peerDependenciesMeta: - cache-manager: - optional: true class-transformer: optional: true class-validator: optional: true - checksum: c39dfa9f02268e3f7fa22c4e9eecff0cfbee39c4d4dd0efc757a52117696dc9aec1f87588252b8b267a18469a6c12987707708b44f97ccbb5c6297396c0d9c00 + checksum: c5444cb46bd4f4a4d28b5031f7c28a0cf9863bc2d5518910bfed6a49734f59e1ea08dd4651e2117ae82df81c933ef84f0963c5cdeee5ef1608cf1bd36ee291c5 languageName: node linkType: hard -"@nestjs/core@npm:9.3.11": - version: 9.3.11 - resolution: "@nestjs/core@npm:9.3.11" +"@nestjs/core@npm:10.3.0": + version: 10.3.0 + resolution: "@nestjs/core@npm:10.3.0" dependencies: "@nuxtjs/opencollective": 0.3.2 fast-safe-stringify: 2.1.1 iterare: 1.2.1 path-to-regexp: 3.2.0 - tslib: 2.5.0 - uid: 2.0.1 + tslib: 2.6.2 + uid: 2.0.2 peerDependencies: - "@nestjs/common": ^9.0.0 - "@nestjs/microservices": ^9.0.0 - "@nestjs/platform-express": ^9.0.0 - "@nestjs/websockets": ^9.0.0 + "@nestjs/common": ^10.0.0 + "@nestjs/microservices": ^10.0.0 + "@nestjs/platform-express": ^10.0.0 + "@nestjs/websockets": ^10.0.0 reflect-metadata: ^0.1.12 rxjs: ^7.1.0 peerDependenciesMeta: @@ -13020,7 +13016,7 @@ __metadata: optional: true "@nestjs/websockets": optional: true - checksum: 39d49e5b16cc260887233dd6701dbc53c073dc7522975d592f6c355db1f42fcf31eeaf300b9d03c63943f7330ecee910281cb78bb66d1c2d938d9b13491e70b4 + checksum: 7677b9fb97c8dec512c2a736c273ef08698b377af8c046bc5aad442ba3d35acbc17d177e76bf44a66678cae2ced2d265183e85be4190c501a195f16496df6396 languageName: node linkType: hard @@ -13980,28 +13976,29 @@ __metadata: linkType: hard "@openapitools/openapi-generator-cli@npm:^2.4.26, @openapitools/openapi-generator-cli@npm:^2.7.0": - version: 2.7.0 - resolution: "@openapitools/openapi-generator-cli@npm:2.7.0" + version: 2.8.0 + resolution: "@openapitools/openapi-generator-cli@npm:2.8.0" dependencies: - "@nestjs/axios": 0.1.0 - "@nestjs/common": 9.3.11 - "@nestjs/core": 9.3.11 + "@nestjs/axios": 3.0.1 + "@nestjs/common": 10.3.0 + "@nestjs/core": 10.3.0 "@nuxtjs/opencollective": 0.3.2 + axios: 1.6.5 chalk: 4.1.2 commander: 8.3.0 compare-versions: 4.1.4 concurrently: 6.5.1 console.table: 0.10.0 fs-extra: 10.1.0 - glob: 7.1.6 + glob: 7.2.3 inquirer: 8.2.5 lodash: 4.17.21 reflect-metadata: 0.1.13 rxjs: 7.8.0 - tslib: 2.0.3 + tslib: 2.6.2 bin: openapi-generator-cli: main.js - checksum: 92ca36779b43fe1e4868cd89bde4cb96918868aa62c8a69a9e199711d8e7093bab67f484d266fcbf37ca4ad87e4e91ea5759fb322c7999a299f5bfdc179065b8 + checksum: 76a43d3087b2a4eb521814369ce99ade622fc146bb2414f52c01a7565f81fa94a6d42f2bf6889a4b25814744f0462613853a609d97c12a608c5717aed2e3898a languageName: node linkType: hard @@ -20882,13 +20879,14 @@ __metadata: languageName: node linkType: hard -"axios@npm:0.27.2, axios@npm:^0.27.2": - version: 0.27.2 - resolution: "axios@npm:0.27.2" +"axios@npm:1.6.5, axios@npm:^1.4.0, axios@npm:^1.6.0": + version: 1.6.5 + resolution: "axios@npm:1.6.5" dependencies: - follow-redirects: ^1.14.9 + follow-redirects: ^1.15.4 form-data: ^4.0.0 - checksum: 38cb7540465fe8c4102850c4368053c21683af85c5fdf0ea619f9628abbcb59415d1e22ebc8a6390d2bbc9b58a9806c874f139767389c862ec9b772235f06854 + proxy-from-env: ^1.1.0 + checksum: e28d67b2d9134cb4608c44d8068b0678cfdccc652742e619006f27264a30c7aba13b2cd19c6f1f52ae195b5232734925928fb192d5c85feea7edd2f273df206d languageName: node linkType: hard @@ -20901,14 +20899,13 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.4.0, axios@npm:^1.6.0": - version: 1.6.5 - resolution: "axios@npm:1.6.5" +"axios@npm:^0.27.2": + version: 0.27.2 + resolution: "axios@npm:0.27.2" dependencies: - follow-redirects: ^1.15.4 + follow-redirects: ^1.14.9 form-data: ^4.0.0 - proxy-from-env: ^1.1.0 - checksum: e28d67b2d9134cb4608c44d8068b0678cfdccc652742e619006f27264a30c7aba13b2cd19c6f1f52ae195b5232734925928fb192d5c85feea7edd2f273df206d + checksum: 38cb7540465fe8c4102850c4368053c21683af85c5fdf0ea619f9628abbcb59415d1e22ebc8a6390d2bbc9b58a9806c874f139767389c862ec9b772235f06854 languageName: node linkType: hard @@ -28102,6 +28099,20 @@ __metadata: languageName: node linkType: hard +"glob@npm:7.2.3, glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7, glob@npm:^7.2.0": + version: 7.2.3 + resolution: "glob@npm:7.2.3" + dependencies: + fs.realpath: ^1.0.0 + inflight: ^1.0.4 + inherits: 2 + minimatch: ^3.1.1 + once: ^1.3.0 + path-is-absolute: ^1.0.0 + checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 + languageName: node + linkType: hard + "glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.3.10 resolution: "glob@npm:10.3.10" @@ -28117,20 +28128,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7, glob@npm:^7.2.0": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.1.1 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 - languageName: node - linkType: hard - "glob@npm:^8.0.0, glob@npm:^8.0.1, glob@npm:^8.0.3": version: 8.1.0 resolution: "glob@npm:8.1.0" @@ -42543,17 +42540,10 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.0.3": - version: 2.0.3 - resolution: "tslib@npm:2.0.3" - checksum: 00fcdd1f9995c9f8eb6a4a1ad03f55bc95946321b7f55434182dddac259d4e095fedf78a84f73b6e32dd3f881d9281f09cb583123d3159ed4bdac9ad7393ef8b - languageName: node - linkType: hard - -"tslib@npm:2.5.0": - version: 2.5.0 - resolution: "tslib@npm:2.5.0" - checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1 +"tslib@npm:2.6.2, tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.4.1, tslib@npm:^2.4.1 || ^1.9.3, tslib@npm:^2.5.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad languageName: node linkType: hard @@ -42564,13 +42554,6 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.4.1, tslib@npm:^2.4.1 || ^1.9.3, tslib@npm:^2.5.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2": - version: 2.6.2 - resolution: "tslib@npm:2.6.2" - checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad - languageName: node - linkType: hard - "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -42964,12 +42947,12 @@ __metadata: languageName: node linkType: hard -"uid@npm:2.0.1": - version: 2.0.1 - resolution: "uid@npm:2.0.1" +"uid@npm:2.0.2": + version: 2.0.2 + resolution: "uid@npm:2.0.2" dependencies: "@lukeed/csprng": ^1.0.0 - checksum: 0a3c697d8dd1f3b647afa35c411b11fd8fa2fb6dbd8a49fe109a4aa5214068c2c58781aa6e4516dfd16f0fc524fb7bba0833e9c1dc1ed3f1965b520349be9ad5 + checksum: 98aabddcd6fe46f9b331b0378a93ee9cc51474348ada02006df9d10b4abc783ed596748ed9f20d7f6c5ff395dbcd1e764a65a68db6f39a31c95ae85ef13fe979 languageName: node linkType: hard From e24e4d36b9d4dcbaa746765a94cba1c54ae5aa21 Mon Sep 17 00:00:00 2001 From: AmbrishRamachandiran Date: Thu, 18 Jan 2024 16:39:30 +0530 Subject: [PATCH 231/241] Updated readme document of bitrise plugin Signed-off-by: AmbrishRamachandiran --- .changeset/sharp-pandas-hunt.md | 5 +++++ plugins/bitrise/README.md | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 .changeset/sharp-pandas-hunt.md diff --git a/.changeset/sharp-pandas-hunt.md b/.changeset/sharp-pandas-hunt.md new file mode 100644 index 0000000000..1c69c02a0b --- /dev/null +++ b/.changeset/sharp-pandas-hunt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-bitrise': patch +--- + +Update README diff --git a/plugins/bitrise/README.md b/plugins/bitrise/README.md index 9c99f28568..e5d5c2122c 100644 --- a/plugins/bitrise/README.md +++ b/plugins/bitrise/README.md @@ -28,9 +28,8 @@ const websiteEntityPage = ( ``` -Now your plugin should be visible as a tab at the top of the entity pages, -specifically for components that are of the type `website`. -However, it warns of a missing `bitrise.io/app` annotation. +Your plugin should now appear as a tab at the top of entity pages, particularly for `website` component types. +However, it alerts you to a missing `bitrise.io/app` annotation. Add the annotation to your component [catalog-info.yaml](https://github.com/backstage/backstage/blob/master/catalog-info.yaml) as shown in the highlighted example below: @@ -51,4 +50,4 @@ proxy: Authorization: ${BITRISE_AUTH_TOKEN} ``` -Learn on https://devcenter.bitrise.io/api/authentication how to create a new Bitrise token. +Learn how to generate a new Bitrise token at https://devcenter.bitrise.io/api/authentication. From 7c490bd54ad7ee6ed1bf4d6e199de3082b18a8d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 11:16:16 +0000 Subject: [PATCH 232/241] chore(deps): update dependency @playwright/test to v1.41.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index bcc184718d..a2bb4835e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14113,13 +14113,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.40.1 - resolution: "@playwright/test@npm:1.40.1" + version: 1.41.0 + resolution: "@playwright/test@npm:1.41.0" dependencies: - playwright: 1.40.1 + playwright: 1.41.0 bin: playwright: cli.js - checksum: ae094e6cb809365c0707ee2b184e42d2a2542569ada020d2d44ca5866066941262bd9a67af185f86c2fb0133c9b712ea8cb73e2959a289e4261c5fd17077283c + checksum: 3a7039f8cd14dd242154255417c100a99c3254a3c1fd26df2a11be24c10b06ef77d2736336d7743dedc5e1a6a52748e58ced730b6048f8bd75d8867ce81661e0 languageName: node linkType: hard @@ -36778,27 +36778,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.40.1": - version: 1.40.1 - resolution: "playwright-core@npm:1.40.1" +"playwright-core@npm:1.41.0": + version: 1.41.0 + resolution: "playwright-core@npm:1.41.0" bin: playwright-core: cli.js - checksum: 84d92fb9b86e3c225b16b6886bf858eb5059b4e60fa1205ff23336e56a06dcb2eac62650992dede72f406c8e70a7b6a5303e511f9b4bc0b85022ede356a01ee0 + checksum: 14671265916a1fd0c71d94640de19c48bcce3f7dec35530f10e349e97030ea44ffa8ee518cbf811501e3ab2b74874aecf917e46bf40fea0570db1d4bea1fe7ac languageName: node linkType: hard -"playwright@npm:1.40.1": - version: 1.40.1 - resolution: "playwright@npm:1.40.1" +"playwright@npm:1.41.0": + version: 1.41.0 + resolution: "playwright@npm:1.41.0" dependencies: fsevents: 2.3.2 - playwright-core: 1.40.1 + playwright-core: 1.41.0 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 9e36791c1b4a649c104aa365fdd9d049924eeb518c5967c0e921aa38b9b00994aa6ee54784d6c2af194b3b494b6f69772673081ef53c6c4a4b2065af9955c4ba + checksum: e7c32136911c58e06b964fe7d33f8b3d8f6a067ae5218662a0811dd6c90e007db1774eb7e161f4aa748d760f404f4c066b7b7303c2b617f7448b6ee4b86c9999 languageName: node linkType: hard From e0cad28ae112f29f2b4404b39bc7b545111ad62a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 11:17:21 +0000 Subject: [PATCH 233/241] chore(deps): update dependency @testing-library/jest-dom to v6.2.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index bcc184718d..747ef72671 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17106,15 +17106,15 @@ __metadata: linkType: hard "@testing-library/jest-dom@npm:^6.0.0": - version: 6.1.6 - resolution: "@testing-library/jest-dom@npm:6.1.6" + version: 6.2.0 + resolution: "@testing-library/jest-dom@npm:6.2.0" dependencies: "@adobe/css-tools": ^4.3.2 "@babel/runtime": ^7.9.2 aria-query: ^5.0.0 chalk: ^3.0.0 css.escape: ^1.5.1 - dom-accessibility-api: ^0.5.6 + dom-accessibility-api: ^0.6.3 lodash: ^4.17.15 redent: ^3.0.0 peerDependencies: @@ -17131,7 +17131,7 @@ __metadata: optional: true vitest: optional: true - checksum: 8d1a80678027915228b483a116fb9e358d25e2faffcd9a2c40b371752fbd53b5cb87351215866a43dd09393e7d364c46fc43923566b00ef63bbf3576d47da940 + checksum: 3d46e36b1b7c2cb3c92f64d55d458aab44ae135ac77299df14d14dcf567a286590de58b2f140011b8f7a343f0703ff88f144f27c6ae4921fd612741771d8ee2c languageName: node linkType: hard @@ -24684,13 +24684,20 @@ __metadata: languageName: node linkType: hard -"dom-accessibility-api@npm:^0.5.6, dom-accessibility-api@npm:^0.5.9": +"dom-accessibility-api@npm:^0.5.9": version: 0.5.13 resolution: "dom-accessibility-api@npm:0.5.13" checksum: a5a5f14c01e466d424750aaac9225f1dc43cf16d101a1c40e01a554abce63c48084707002c39b805f2ce212273c179dd6d2258175997cd06d5f79851bf52dd40 languageName: node linkType: hard +"dom-accessibility-api@npm:^0.6.3": + version: 0.6.3 + resolution: "dom-accessibility-api@npm:0.6.3" + checksum: c325b5144bb406df23f4affecffc117dbaec9af03daad9ee6b510c5be647b14d28ef0a4ea5ca06d696d8ab40bb777e5fed98b985976fdef9d8790178fa1d573f + languageName: node + linkType: hard + "dom-converter@npm:^0.2.0": version: 0.2.0 resolution: "dom-converter@npm:0.2.0" From a77559663cef96841dca535514836614658c6c29 Mon Sep 17 00:00:00 2001 From: Andres Mauricio Gomez P Date: Tue, 9 Jan 2024 18:45:25 -0500 Subject: [PATCH 234/241] Enabled a way to include custom auth metadata info on the clusters endpoint Signed-off-by: Andres Mauricio Gomez P --- .changeset/kind-clouds-fly.md | 6 + plugins/kubernetes-backend/api-report.md | 106 +- .../src/auth/AksStrategy.ts | 13 +- .../src/auth/AnonymousStrategy.ts | 10 +- .../src/auth/AwsIamStrategy.ts | 12 +- .../src/auth/AzureIdentityStrategy.ts | 10 +- .../src/auth/DispatchStrategy.test.ts | 1 + .../src/auth/DispatchStrategy.ts | 12 +- .../src/auth/GoogleServiceAccountStrategy.ts | 11 +- .../src/auth/GoogleStrategy.ts | 13 +- .../src/auth/OidcStrategy.ts | 12 +- .../src/auth/ServiceAccountStrategy.ts | 12 +- .../ConfigClusterLocator.test.ts | 1 + .../src/cluster-locator/index.test.ts | 1 + .../src/service/KubernetesBuilder.test.ts | 966 ++++++++++-------- .../src/service/KubernetesBuilder.ts | 22 +- .../service/KubernetesFanOutHandler.test.ts | 2 + .../src/service/KubernetesProxy.test.ts | 2 + plugins/kubernetes-node/api-report.md | 2 + plugins/kubernetes-node/src/types/types.ts | 1 + 20 files changed, 743 insertions(+), 472 deletions(-) create mode 100644 .changeset/kind-clouds-fly.md diff --git a/.changeset/kind-clouds-fly.md b/.changeset/kind-clouds-fly.md new file mode 100644 index 0000000000..7d8d7c4a0e --- /dev/null +++ b/.changeset/kind-clouds-fly.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-node': patch +--- + +Enabled a way to include custom auth metadata info on the clusters endpoint diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index e6996484dd..afdb3bcf9a 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -4,6 +4,7 @@ ```ts import { AuthenticationStrategy as AuthenticationStrategy_2 } from '@backstage/plugin-kubernetes-node'; +import { AuthMetadata as AuthMetadata_2 } from '@backstage/plugin-kubernetes-node'; import { CatalogApi } from '@backstage/catalog-client'; import { ClusterDetails as ClusterDetails_2 } from '@backstage/plugin-kubernetes-node'; import { Config } from '@backstage/config'; @@ -12,9 +13,12 @@ import { Duration } from 'luxon'; import express from 'express'; import * as k8sAuthTypes from '@backstage/plugin-kubernetes-node'; import { KubernetesClustersSupplier as KubernetesClustersSupplier_2 } from '@backstage/plugin-kubernetes-node'; +import { KubernetesCredential as KubernetesCredential_2 } from '@backstage/plugin-kubernetes-node'; +import { KubernetesFetcher as KubernetesFetcher_2 } from '@backstage/plugin-kubernetes-node'; import { KubernetesObjectsProvider as KubernetesObjectsProvider_2 } from '@backstage/plugin-kubernetes-node'; import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; import type { KubernetesRequestBody } from '@backstage/plugin-kubernetes-common'; +import { KubernetesServiceLocator as KubernetesServiceLocator_2 } from '@backstage/plugin-kubernetes-node'; import { Logger } from 'winston'; import { ObjectToFetch as ObjectToFetch_2 } from '@backstage/plugin-kubernetes-node'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; @@ -23,20 +27,24 @@ import { RequestHandler } from 'http-proxy-middleware'; import { TokenCredential } from '@azure/identity'; // @public (undocumented) -export class AksStrategy implements AuthenticationStrategy { +export class AksStrategy implements AuthenticationStrategy_2 { // (undocumented) getCredential( - _: ClusterDetails, + _: ClusterDetails_2, requestAuth: KubernetesRequestAuth, - ): Promise; + ): Promise; + // (undocumented) + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; // (undocumented) validateCluster(): Error[]; } // @public (undocumented) -export class AnonymousStrategy implements AuthenticationStrategy { +export class AnonymousStrategy implements AuthenticationStrategy_2 { // (undocumented) - getCredential(): Promise; + getCredential(): Promise; + // (undocumented) + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; // (undocumented) validateCluster(): Error[]; } @@ -48,19 +56,25 @@ export type AuthenticationStrategy = k8sAuthTypes.AuthenticationStrategy; export type AuthMetadata = k8sAuthTypes.AuthMetadata; // @public (undocumented) -export class AwsIamStrategy implements AuthenticationStrategy { +export class AwsIamStrategy implements AuthenticationStrategy_2 { constructor(opts: { config: Config }); // (undocumented) - getCredential(clusterDetails: ClusterDetails): Promise; + getCredential( + clusterDetails: ClusterDetails_2, + ): Promise; + // (undocumented) + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; // (undocumented) validateCluster(): Error[]; } // @public (undocumented) -export class AzureIdentityStrategy implements AuthenticationStrategy { +export class AzureIdentityStrategy implements AuthenticationStrategy_2 { constructor(logger: Logger, tokenCredential?: TokenCredential); // (undocumented) - getCredential(): Promise; + getCredential(): Promise; + // (undocumented) + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; // (undocumented) validateCluster(): Error[]; } @@ -81,21 +95,23 @@ export type CustomResourcesByEntity = k8sAuthTypes.CustomResourcesByEntity; export const DEFAULT_OBJECTS: ObjectToFetch[]; // @public -export class DispatchStrategy implements AuthenticationStrategy { +export class DispatchStrategy implements AuthenticationStrategy_2 { constructor(options: DispatchStrategyOptions); // (undocumented) getCredential( - clusterDetails: ClusterDetails, + clusterDetails: ClusterDetails_2, auth: KubernetesRequestAuth, - ): Promise; + ): Promise; // (undocumented) - validateCluster(authMetadata: AuthMetadata): Error[]; + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; + // (undocumented) + validateCluster(authMetadata: AuthMetadata_2): Error[]; } // @public (undocumented) export type DispatchStrategyOptions = { authStrategyMap: { - [key: string]: AuthenticationStrategy; + [key: string]: AuthenticationStrategy_2; }; }; @@ -103,20 +119,24 @@ export type DispatchStrategyOptions = { export type FetchResponseWrapper = k8sAuthTypes.FetchResponseWrapper; // @public (undocumented) -export class GoogleServiceAccountStrategy implements AuthenticationStrategy { +export class GoogleServiceAccountStrategy implements AuthenticationStrategy_2 { // (undocumented) - getCredential(): Promise; + getCredential(): Promise; + // (undocumented) + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; // (undocumented) validateCluster(): Error[]; } // @public (undocumented) -export class GoogleStrategy implements AuthenticationStrategy { +export class GoogleStrategy implements AuthenticationStrategy_2 { // (undocumented) getCredential( - _: ClusterDetails, + _: ClusterDetails_2, requestAuth: KubernetesRequestAuth, - ): Promise; + ): Promise; + // (undocumented) + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; // (undocumented) validateCluster(): Error[]; } @@ -131,7 +151,7 @@ export const HEADER_KUBERNETES_CLUSTER: string; export class KubernetesBuilder { constructor(env: KubernetesEnvironment); // (undocumented) - addAuthStrategy(key: string, strategy: AuthenticationStrategy): this; + addAuthStrategy(key: string, strategy: AuthenticationStrategy_2): this; // (undocumented) build(): KubernetesBuilderReturn; // (undocumented) @@ -145,15 +165,15 @@ export class KubernetesBuilder { // (undocumented) protected buildCustomResources(): CustomResource_2[]; // (undocumented) - protected buildFetcher(): KubernetesFetcher; + protected buildFetcher(): KubernetesFetcher_2; // (undocumented) protected buildHttpServiceLocator( _clusterSupplier: KubernetesClustersSupplier_2, - ): KubernetesServiceLocator; + ): KubernetesServiceLocator_2; // (undocumented) protected buildMultiTenantServiceLocator( clusterSupplier: KubernetesClustersSupplier_2, - ): KubernetesServiceLocator; + ): KubernetesServiceLocator_2; // (undocumented) protected buildObjectsProvider( options: KubernetesObjectsProviderOptions, @@ -175,11 +195,11 @@ export class KubernetesBuilder { protected buildServiceLocator( method: ServiceLocatorMethod, clusterSupplier: KubernetesClustersSupplier_2, - ): KubernetesServiceLocator; + ): KubernetesServiceLocator_2; // (undocumented) protected buildSingleTenantServiceLocator( clusterSupplier: KubernetesClustersSupplier_2, - ): KubernetesServiceLocator; + ): KubernetesServiceLocator_2; // (undocumented) static createBuilder(env: KubernetesEnvironment): KubernetesBuilder; // (undocumented) @@ -195,7 +215,7 @@ export class KubernetesBuilder { // (undocumented) protected getClusterSupplier(): KubernetesClustersSupplier_2; // (undocumented) - protected getFetcher(): KubernetesFetcher; + protected getFetcher(): KubernetesFetcher_2; // (undocumented) protected getObjectsProvider( options: KubernetesObjectsProviderOptions, @@ -208,38 +228,38 @@ export class KubernetesBuilder { clusterSupplier: KubernetesClustersSupplier_2, ): KubernetesProxy; // (undocumented) - protected getServiceLocator(): KubernetesServiceLocator; + protected getServiceLocator(): KubernetesServiceLocator_2; // (undocumented) protected getServiceLocatorMethod(): ServiceLocatorMethod; // (undocumented) setAuthStrategyMap(authStrategyMap: { - [key: string]: AuthenticationStrategy; + [key: string]: AuthenticationStrategy_2; }): void; // (undocumented) setClusterSupplier(clusterSupplier?: KubernetesClustersSupplier_2): this; // (undocumented) setDefaultClusterRefreshInterval(refreshInterval: Duration): this; // (undocumented) - setFetcher(fetcher?: KubernetesFetcher): this; + setFetcher(fetcher?: KubernetesFetcher_2): this; // (undocumented) setObjectsProvider(objectsProvider?: KubernetesObjectsProvider_2): this; // (undocumented) setProxy(proxy?: KubernetesProxy): this; // (undocumented) - setServiceLocator(serviceLocator?: KubernetesServiceLocator): this; + setServiceLocator(serviceLocator?: KubernetesServiceLocator_2): this; } // @public export type KubernetesBuilderReturn = Promise<{ router: express.Router; clusterSupplier: KubernetesClustersSupplier_2; - customResources: CustomResource[]; - fetcher: KubernetesFetcher; + customResources: CustomResource_2[]; + fetcher: KubernetesFetcher_2; proxy: KubernetesProxy; objectsProvider: KubernetesObjectsProvider_2; - serviceLocator: KubernetesServiceLocator; + serviceLocator: KubernetesServiceLocator_2; authStrategyMap: { - [key: string]: AuthenticationStrategy; + [key: string]: AuthenticationStrategy_2; }; }>; @@ -321,14 +341,16 @@ export type ObjectsByEntityRequest = KubernetesRequestBody; export type ObjectToFetch = k8sAuthTypes.ObjectToFetch; // @public (undocumented) -export class OidcStrategy implements AuthenticationStrategy { +export class OidcStrategy implements AuthenticationStrategy_2 { // (undocumented) getCredential( - clusterDetails: ClusterDetails, + clusterDetails: ClusterDetails_2, authConfig: KubernetesRequestAuth, - ): Promise; + ): Promise; // (undocumented) - validateCluster(authMetadata: AuthMetadata): Error[]; + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; + // (undocumented) + validateCluster(authMetadata: AuthMetadata_2): Error[]; } // @public (undocumented) @@ -348,9 +370,13 @@ export interface RouterOptions { } // @public (undocumented) -export class ServiceAccountStrategy implements AuthenticationStrategy { +export class ServiceAccountStrategy implements AuthenticationStrategy_2 { // (undocumented) - getCredential(clusterDetails: ClusterDetails): Promise; + getCredential( + clusterDetails: ClusterDetails_2, + ): Promise; + // (undocumented) + presentAuthMetadata(_authMetadata: AuthMetadata_2): AuthMetadata_2; // (undocumented) validateCluster(): Error[]; } diff --git a/plugins/kubernetes-backend/src/auth/AksStrategy.ts b/plugins/kubernetes-backend/src/auth/AksStrategy.ts index 07bdf2efe0..40151314a8 100644 --- a/plugins/kubernetes-backend/src/auth/AksStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/AksStrategy.ts @@ -13,8 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ClusterDetails } from '../types/types'; -import { AuthenticationStrategy, KubernetesCredential } from './types'; +import { + AuthMetadata, + AuthenticationStrategy, + ClusterDetails, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; /** @@ -31,7 +35,12 @@ export class AksStrategy implements AuthenticationStrategy { ? { type: 'bearer token', token: token as string } : { type: 'anonymous' }; } + public validateCluster(): Error[] { return []; } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/auth/AnonymousStrategy.ts b/plugins/kubernetes-backend/src/auth/AnonymousStrategy.ts index 30a9593773..0f1aad398a 100644 --- a/plugins/kubernetes-backend/src/auth/AnonymousStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/AnonymousStrategy.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { AuthenticationStrategy, KubernetesCredential } from './types'; +import { + AuthMetadata, + AuthenticationStrategy, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; /** * @@ -28,4 +32,8 @@ export class AnonymousStrategy implements AuthenticationStrategy { public validateCluster(): Error[] { return []; } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/auth/AwsIamStrategy.ts b/plugins/kubernetes-backend/src/auth/AwsIamStrategy.ts index 53b880d60c..942b93615f 100644 --- a/plugins/kubernetes-backend/src/auth/AwsIamStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/AwsIamStrategy.ts @@ -25,8 +25,12 @@ import { ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE, ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID, } from '@backstage/plugin-kubernetes-common'; -import { ClusterDetails } from '../types/types'; -import { AuthenticationStrategy, KubernetesCredential } from './types'; +import { + AuthMetadata, + AuthenticationStrategy, + ClusterDetails, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; /** * @@ -128,4 +132,8 @@ export class AwsIamStrategy implements AuthenticationStrategy { return `k8s-aws-v1.${Buffer.from(url).toString('base64url')}`; } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/auth/AzureIdentityStrategy.ts b/plugins/kubernetes-backend/src/auth/AzureIdentityStrategy.ts index d0eea3c13c..a1b29a10a1 100644 --- a/plugins/kubernetes-backend/src/auth/AzureIdentityStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/AzureIdentityStrategy.ts @@ -15,12 +15,16 @@ */ import { Logger } from 'winston'; -import { AuthenticationStrategy, KubernetesCredential } from './types'; import { AccessToken, DefaultAzureCredential, TokenCredential, } from '@azure/identity'; +import { + AuthMetadata, + AuthenticationStrategy, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; const aksScope = '6dae42f8-4368-4678-94ff-3960e28e3630/.default'; // This scope is the same for all Azure Managed Kubernetes @@ -89,4 +93,8 @@ export class AzureIdentityStrategy implements AuthenticationStrategy { private tokenExpired(): boolean { return Date.now() >= this.accessToken.expiresOnTimestamp; } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/auth/DispatchStrategy.test.ts b/plugins/kubernetes-backend/src/auth/DispatchStrategy.test.ts index 7202311d6f..773e464168 100644 --- a/plugins/kubernetes-backend/src/auth/DispatchStrategy.test.ts +++ b/plugins/kubernetes-backend/src/auth/DispatchStrategy.test.ts @@ -31,6 +31,7 @@ describe('getCredential', () => { mockStrategy = { getCredential: jest.fn(), validateCluster: jest.fn(), + presentAuthMetadata: jest.fn(), }; strategy = new DispatchStrategy({ authStrategyMap: { google: mockStrategy }, diff --git a/plugins/kubernetes-backend/src/auth/DispatchStrategy.ts b/plugins/kubernetes-backend/src/auth/DispatchStrategy.ts index f12e49b577..14a3009a65 100644 --- a/plugins/kubernetes-backend/src/auth/DispatchStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/DispatchStrategy.ts @@ -14,12 +14,16 @@ * limitations under the License. */ -import { AuthenticationStrategy, KubernetesCredential } from './types'; -import { AuthMetadata, ClusterDetails } from '../types'; import { ANNOTATION_KUBERNETES_AUTH_PROVIDER, KubernetesRequestAuth, } from '@backstage/plugin-kubernetes-common'; +import { + AuthMetadata, + AuthenticationStrategy, + ClusterDetails, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; /** * @@ -67,4 +71,8 @@ export class DispatchStrategy implements AuthenticationStrategy { } return strategy.validateCluster(authMetadata); } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/auth/GoogleServiceAccountStrategy.ts b/plugins/kubernetes-backend/src/auth/GoogleServiceAccountStrategy.ts index 2a44a31d6c..f6757d6a64 100644 --- a/plugins/kubernetes-backend/src/auth/GoogleServiceAccountStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/GoogleServiceAccountStrategy.ts @@ -13,7 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { AuthenticationStrategy, KubernetesCredential } from './types'; + +import { + AuthMetadata, + AuthenticationStrategy, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; import * as container from '@google-cloud/container'; /** @@ -36,4 +41,8 @@ export class GoogleServiceAccountStrategy implements AuthenticationStrategy { public validateCluster(): Error[] { return []; } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/auth/GoogleStrategy.ts b/plugins/kubernetes-backend/src/auth/GoogleStrategy.ts index c1290dc1fe..c48086f7f8 100644 --- a/plugins/kubernetes-backend/src/auth/GoogleStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/GoogleStrategy.ts @@ -14,9 +14,13 @@ * limitations under the License. */ -import { AuthenticationStrategy, KubernetesCredential } from './types'; -import { ClusterDetails } from '../types/types'; import { KubernetesRequestAuth } from '@backstage/plugin-kubernetes-common'; +import { + AuthMetadata, + AuthenticationStrategy, + ClusterDetails, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; /** * @@ -35,7 +39,12 @@ export class GoogleStrategy implements AuthenticationStrategy { } return { type: 'bearer token', token: token as string }; } + public validateCluster(): Error[] { return []; } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/auth/OidcStrategy.ts b/plugins/kubernetes-backend/src/auth/OidcStrategy.ts index 445799cbb8..1039f1d40c 100644 --- a/plugins/kubernetes-backend/src/auth/OidcStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/OidcStrategy.ts @@ -18,8 +18,12 @@ import { ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER, KubernetesRequestAuth, } from '@backstage/plugin-kubernetes-common'; -import { AuthenticationStrategy, KubernetesCredential } from './types'; -import { AuthMetadata, ClusterDetails } from '../types/types'; +import { + AuthMetadata, + AuthenticationStrategy, + ClusterDetails, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; /** * @@ -57,4 +61,8 @@ export class OidcStrategy implements AuthenticationStrategy { } return []; } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/auth/ServiceAccountStrategy.ts b/plugins/kubernetes-backend/src/auth/ServiceAccountStrategy.ts index 714b2a94d1..aff6e61a64 100644 --- a/plugins/kubernetes-backend/src/auth/ServiceAccountStrategy.ts +++ b/plugins/kubernetes-backend/src/auth/ServiceAccountStrategy.ts @@ -14,10 +14,14 @@ * limitations under the License. */ +import { + AuthMetadata, + AuthenticationStrategy, + ClusterDetails, + KubernetesCredential, +} from '@backstage/plugin-kubernetes-node'; import { KubeConfig, User } from '@kubernetes/client-node'; import fs from 'fs-extra'; -import { AuthenticationStrategy, KubernetesCredential } from './types'; -import { ClusterDetails } from '../types/types'; /** * @@ -45,4 +49,8 @@ export class ServiceAccountStrategy implements AuthenticationStrategy { public validateCluster(): Error[] { return []; } + + public presentAuthMetadata(_authMetadata: AuthMetadata): AuthMetadata { + return {}; + } } diff --git a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts index 1720ef5ed6..ad3203a16d 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/ConfigClusterLocator.test.ts @@ -32,6 +32,7 @@ describe('ConfigClusterLocator', () => { authStrategy = { getCredential: jest.fn(), validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn(), }; }); diff --git a/plugins/kubernetes-backend/src/cluster-locator/index.test.ts b/plugins/kubernetes-backend/src/cluster-locator/index.test.ts index ded0faac5b..beb9fc9cfe 100644 --- a/plugins/kubernetes-backend/src/cluster-locator/index.test.ts +++ b/plugins/kubernetes-backend/src/cluster-locator/index.test.ts @@ -53,6 +53,7 @@ describe('getCombinedClusterSupplier', () => { const mockStrategy: jest.Mocked = { getCredential: jest.fn(), validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn(), }; const clusterSupplier = getCombinedClusterSupplier( diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 42f953a2fe..5030adaa81 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -16,6 +16,9 @@ import { ANNOTATION_KUBERNETES_AUTH_PROVIDER, + ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE, + ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID, + ANNOTATION_KUBERNETES_DASHBOARD_URL, ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER, KubernetesRequestAuth, } from '@backstage/plugin-kubernetes-common'; @@ -50,6 +53,7 @@ import { kubernetesObjectsProviderExtensionPoint, kubernetesFetcherExtensionPoint, kubernetesServiceLocatorExtensionPoint, + AuthMetadata, } from '@backstage/plugin-kubernetes-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; @@ -177,151 +181,75 @@ describe('API integration tests', () => { ], }); }); - }); - describe('post /services/:serviceId', () => { - it('happy path: lists kubernetes objects without auth in request body', async () => { - const response = await request(app).post( - '/api/kubernetes/services/test-service', - ); - expect(response.status).toEqual(200); - expect(response.body).toEqual(happyK8SResult); - }); - - it('happy path: lists kubernetes objects with auth in request body', async () => { - const response = await request(app) - .post('/api/kubernetes/services/test-service') - .send({ auth: { google: 'google_token_123' } }) - .set('Content-Type', 'application/json'); - expect(response.status).toEqual(200); - expect(response.body).toEqual(happyK8SResult); - }); - - it('internal error: lists kubernetes objects', async () => { - objectsProviderMock.getKubernetesObjectsByEntity.mockRejectedValue( - Error('some internal error'), - ); - - const response = await request(app).post( - '/api/kubernetes/services/test-service', - ); - - expect(response.status).toEqual(500); - expect(response.body).toEqual({ error: 'some internal error' }); - }); - - it('custom service locator', async () => { - const someCluster = { - name: 'some-cluster', - url: 'https://localhost:1234', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', - serviceAccountToken: 'placeholder-token', - }, - }; - const clusters: ClusterDetails[] = [ - someCluster, - { - name: 'some-other-cluster', - url: 'https://localhost:1235', - authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' }, - }, - ]; - - const pod = { metadata: { name: 'pod1' } }; - - const mockServiceLocator: jest.Mocked = { - getClustersByEntity: jest.fn().mockResolvedValue({ - clusters: [someCluster], - }), - }; - - const mockFetcher: jest.Mocked = { - fetchPodMetricsByNamespaces: jest + it('happy path: lists clusters with custom AuthStrategy and custom auth metadata', async () => { + objectsProviderMock = { + getKubernetesObjectsByEntity: jest .fn() - .mockResolvedValue({ errors: [], responses: [] }), - fetchObjectsForService: jest.fn().mockResolvedValue({ - errors: [], - responses: [{ type: 'pods', resources: [pod] }], - }), + .mockResolvedValue(happyK8SResult), + getCustomResourcesByEntity: jest.fn().mockResolvedValue(happyK8SResult), }; - const { server } = await startTestBackend({ - features: [ - minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), - withClusters(clusters), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testFetcher', - register(env) { - env.registerInit({ - deps: { extension: kubernetesFetcherExtensionPoint }, - async init({ extension }) { - extension.addFetcher(mockFetcher); - }, - }); - }, - }), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testServiceLocator', - register(env) { - env.registerInit({ - deps: { extension: kubernetesServiceLocatorExtensionPoint }, - async init({ extension }) { - extension.addServiceLocator(mockServiceLocator); - }, - }); - }, - }), - ], - }); - app = server; - - const response = await request(app) - .post('/api/kubernetes/services/test-service') - .send({ entity: { metadata: { name: 'thing' } } }); - - expect(response.body).toEqual({ - items: [ - { - cluster: { name: someCluster.name }, - errors: [], - podMetrics: [], - resources: [{ type: 'pods', resources: [pod] }], - }, - ], - }); - expect(response.status).toEqual(200); - }); - - it('reads auth data for custom strategy', async () => { - const mockFetcher = { - fetchPodMetricsByNamespaces: jest - .fn() - .mockResolvedValue({ errors: [], responses: [] }), - fetchObjectsForService: jest.fn().mockResolvedValue({ - errors: [], - responses: [ - { type: 'pods', resources: [{ metadata: { name: 'pod1' } }] }, - ], - }), - }; - - const { server } = await startTestBackend({ - features: [ - minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), - withClusters([ + const clusterSupplierMock = { + getClusters: jest.fn().mockResolvedValue( + Promise.resolve([ { - name: 'custom-cluster', - url: 'http://my.cluster.url', + name: 'some-cluster', + url: 'https://localhost:1234', authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'customAuth', + [ANNOTATION_KUBERNETES_DASHBOARD_URL]: + 'https://127.0.0.1:8443/dashboard', + [ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID]: '12650152165654', + [ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE]: 'my_aws_role', }, }, ]), + ), + }; + + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { + type: 'multiTenant', + }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [], + }, + ], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testObjectsProvider', + register(env) { + env.registerInit({ + deps: { extension: kubernetesObjectsProviderExtensionPoint }, + async init({ extension }) { + extension.addObjectsProvider(objectsProviderMock); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testClusterSupplier', + register(env) { + env.registerInit({ + deps: { extension: kubernetesClusterSupplierExtensionPoint }, + async init({ extension }) { + extension.addClusterSupplier(clusterSupplierMock); + }, + }); + }, + }), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testAuthStrategy', @@ -329,7 +257,7 @@ describe('API integration tests', () => { env.registerInit({ deps: { extension: kubernetesAuthStrategyExtensionPoint }, async init({ extension }) { - extension.addAuthStrategy('custom', { + extension.addAuthStrategy('customAuth', { getCredential: jest .fn< Promise, @@ -340,322 +268,538 @@ describe('API integration tests', () => { token: requestAuth.custom as string, })), validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: ( + authMetadata: AuthMetadata, + ): AuthMetadata => { + const authMetadataFilter = Object.entries(authMetadata) + .filter(([key, _value]) => { + return [ + ANNOTATION_KUBERNETES_DASHBOARD_URL, + ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE, + ].includes(key); + }) + .reduce( + ( + accumulator: AuthMetadata, + currentValue: [string, string], + ) => { + accumulator[currentValue[0]] = currentValue[1]; + return accumulator; + }, + {}, + ); + + return authMetadataFilter; + }, }); }, }); }, }), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testFetcher', - register(env) { - env.registerInit({ - deps: { extension: kubernetesFetcherExtensionPoint }, - async init({ extension }) { - extension.addFetcher(mockFetcher); - }, - }); - }, - }), ], }); + }); - app = server; + describe('post /services/:serviceId', () => { + it('happy path: lists kubernetes objects without auth in request body', async () => { + const response = await request(app).post( + '/api/kubernetes/services/test-service', + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(happyK8SResult); + }); - await request(app) - .post('/api/kubernetes/services/test-service') - .send({ - entity: { metadata: { name: 'thing' } }, - auth: { custom: 'custom-token' }, + it('happy path: lists kubernetes objects with auth in request body', async () => { + const response = await request(app) + .post('/api/kubernetes/services/test-service') + .send({ auth: { google: 'google_token_123' } }) + .set('Content-Type', 'application/json'); + expect(response.status).toEqual(200); + expect(response.body).toEqual(happyK8SResult); + }); + + it('internal error: lists kubernetes objects', async () => { + objectsProviderMock.getKubernetesObjectsByEntity.mockRejectedValue( + Error('some internal error'), + ); + + const response = await request(app).post( + '/api/kubernetes/services/test-service', + ); + + expect(response.status).toEqual(500); + expect(response.body).toEqual({ error: 'some internal error' }); + }); + + it('custom service locator', async () => { + const someCluster = { + name: 'some-cluster', + url: 'https://localhost:1234', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', + serviceAccountToken: 'placeholder-token', + }, + }; + const clusters: ClusterDetails[] = [ + someCluster, + { + name: 'some-other-cluster', + url: 'https://localhost:1235', + authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' }, + }, + ]; + + const pod = { metadata: { name: 'pod1' } }; + + const mockServiceLocator: jest.Mocked = { + getClustersByEntity: jest.fn().mockResolvedValue({ + clusters: [someCluster], + }), + }; + + const mockFetcher: jest.Mocked = { + fetchPodMetricsByNamespaces: jest + .fn() + .mockResolvedValue({ errors: [], responses: [] }), + fetchObjectsForService: jest.fn().mockResolvedValue({ + errors: [], + responses: [{ type: 'pods', resources: [pod] }], + }), + }; + + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + import('@backstage/plugin-kubernetes-backend/alpha'), + withClusters(clusters), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testFetcher', + register(env) { + env.registerInit({ + deps: { extension: kubernetesFetcherExtensionPoint }, + async init({ extension }) { + extension.addFetcher(mockFetcher); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testServiceLocator', + register(env) { + env.registerInit({ + deps: { extension: kubernetesServiceLocatorExtensionPoint }, + async init({ extension }) { + extension.addServiceLocator(mockServiceLocator); + }, + }); + }, + }), + ], + }); + app = server; + + const response = await request(app) + .post('/api/kubernetes/services/test-service') + .send({ entity: { metadata: { name: 'thing' } } }); + + expect(response.body).toEqual({ + items: [ + { + cluster: { name: someCluster.name }, + errors: [], + podMetrics: [], + resources: [{ type: 'pods', resources: [pod] }], + }, + ], + }); + expect(response.status).toEqual(200); + }); + + it('reads auth data for custom strategy', async () => { + const mockFetcher = { + fetchPodMetricsByNamespaces: jest + .fn() + .mockResolvedValue({ errors: [], responses: [] }), + fetchObjectsForService: jest.fn().mockResolvedValue({ + errors: [], + responses: [ + { type: 'pods', resources: [{ metadata: { name: 'pod1' } }] }, + ], + }), + }; + + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + import('@backstage/plugin-kubernetes-backend/alpha'), + withClusters([ + { + name: 'custom-cluster', + url: 'http://my.cluster.url', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', + }, + }, + ]), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockImplementation(async (_, requestAuth) => ({ + type: 'bearer token', + token: requestAuth.custom as string, + })), + validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn().mockReturnValue({}), + }); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testFetcher', + register(env) { + env.registerInit({ + deps: { extension: kubernetesFetcherExtensionPoint }, + async init({ extension }) { + extension.addFetcher(mockFetcher); + }, + }); + }, + }), + ], }); - expect(mockFetcher.fetchObjectsForService).toHaveBeenCalledWith( - expect.objectContaining({ - credential: { type: 'bearer token', token: 'custom-token' }, - }), - ); - }); - }); + app = server; - describe('/proxy', () => { - const worker = setupServer(); - setupRequestMockHandlers(worker); + await request(app) + .post('/api/kubernetes/services/test-service') + .send({ + entity: { metadata: { name: 'thing' } }, + auth: { custom: 'custom-token' }, + }); - beforeEach(() => { - worker.use( - rest.post( - 'https://localhost:1234/api/v1/namespaces', - (req, res, ctx) => { - if (!req.headers.get('Authorization')) { - return res(ctx.status(401)); - } - return req - .arrayBuffer() - .then(body => - res( - ctx.set('content-type', `${req.headers.get('content-type')}`), - ctx.body(body), - ), - ); - }, - ), - ); + expect(mockFetcher.fetchObjectsForService).toHaveBeenCalledWith( + expect.objectContaining({ + credential: { type: 'bearer token', token: 'custom-token' }, + }), + ); + }); }); - it('forwards request body to k8s', async () => { - const namespaceManifest = { - kind: 'Namespace', - apiVersion: 'v1', - metadata: { name: 'new-ns' }, - }; + describe('/proxy', () => { + const worker = setupServer(); + setupRequestMockHandlers(worker); - const proxyEndpointRequest = request(app) - .post('/api/kubernetes/proxy/api/v1/namespaces') - .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') - .set(HEADER_KUBERNETES_AUTH, 'randomtoken') - .send(namespaceManifest); - worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); - const response = await proxyEndpointRequest; + beforeEach(() => { + worker.use( + rest.post( + 'https://localhost:1234/api/v1/namespaces', + (req, res, ctx) => { + if (!req.headers.get('Authorization')) { + return res(ctx.status(401)); + } + return req + .arrayBuffer() + .then(body => + res( + ctx.set( + 'content-type', + `${req.headers.get('content-type')}`, + ), + ctx.body(body), + ), + ); + }, + ), + ); + }); - expect(response.body).toStrictEqual(namespaceManifest); - }); + it('forwards request body to k8s', async () => { + const namespaceManifest = { + kind: 'Namespace', + apiVersion: 'v1', + metadata: { name: 'new-ns' }, + }; - it('supports yaml content type', async () => { - const yamlManifest = `--- + const proxyEndpointRequest = request(app) + .post('/api/kubernetes/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') + .send(namespaceManifest); + worker.use( + rest.all(proxyEndpointRequest.url, req => req.passthrough()), + ); + const response = await proxyEndpointRequest; + + expect(response.body).toStrictEqual(namespaceManifest); + }); + + it('supports yaml content type', async () => { + const yamlManifest = `--- kind: Namespace apiVersion: v1 metadata: name: new-ns `; - const proxyEndpointRequest = request(app) - .post('/api/kubernetes/proxy/api/v1/namespaces') - .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') - .set(HEADER_KUBERNETES_AUTH, 'randomtoken') - .set('content-type', 'application/yaml') - .send(yamlManifest); + const proxyEndpointRequest = request(app) + .post('/api/kubernetes/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') + .set('content-type', 'application/yaml') + .send(yamlManifest); - worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); + worker.use( + rest.all(proxyEndpointRequest.url, req => req.passthrough()), + ); - const response = await proxyEndpointRequest; - expect(response.text).toEqual(yamlManifest); - }); - - it('returns 403 response when permission blocks endpoint', async () => { - permissionsMock.authorize.mockResolvedValue([ - { result: AuthorizeResult.DENY }, - ]); - - const { server } = await startTestBackend({ - features: [ - minimalValidConfigService, - permissionsMock.factory, - import('@backstage/plugin-kubernetes-backend/alpha'), - ], + const response = await proxyEndpointRequest; + expect(response.text).toEqual(yamlManifest); }); - app = server; - const proxyEndpointRequest = request(app) - .post('/api/kubernetes/proxy/api/v1/namespaces') - .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') - .set(HEADER_KUBERNETES_AUTH, 'randomtoken') - .send({ - kind: 'Namespace', - apiVersion: 'v1', - metadata: { name: 'new-ns' }, + it('returns 403 response when permission blocks endpoint', async () => { + permissionsMock.authorize.mockResolvedValue([ + { result: AuthorizeResult.DENY }, + ]); + + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + permissionsMock.factory, + import('@backstage/plugin-kubernetes-backend/alpha'), + ], + }); + app = server; + + const proxyEndpointRequest = request(app) + .post('/api/kubernetes/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') + .send({ + kind: 'Namespace', + apiVersion: 'v1', + metadata: { name: 'new-ns' }, + }); + + worker.use( + rest.all(proxyEndpointRequest.url, req => req.passthrough()), + ); + + const response = await proxyEndpointRequest; + + expect(response.status).toEqual(403); + }); + + it('permits custom client-side auth strategy', async () => { + worker.use( + rest.get( + 'http://my.cluster.url/api/v1/namespaces', + (req, res, ctx) => { + if (req.headers.get('Authorization') !== 'custom-token') { + return res(ctx.status(401)); + } + return res(ctx.json({ items: [] })); + }, + ), + ); + + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + import('@backstage/plugin-kubernetes-backend/alpha'), + withClusters([ + { + name: 'custom-cluster', + url: 'http://my.cluster.url', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', + }, + }, + ]), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn().mockReturnValue({}), + }); + }, + }); + }, + }), + ], }); - worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); + const proxyEndpointRequest = request(server) + .get('/api/kubernetes/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'custom-cluster') + .set(HEADER_KUBERNETES_AUTH, 'custom-token'); + worker.use( + rest.all(proxyEndpointRequest.url, req => req.passthrough()), + ); + const response = await proxyEndpointRequest; - const response = await proxyEndpointRequest; - - expect(response.status).toEqual(403); - }); - - it('permits custom client-side auth strategy', async () => { - worker.use( - rest.get('http://my.cluster.url/api/v1/namespaces', (req, res, ctx) => { - if (req.headers.get('Authorization') !== 'custom-token') { - return res(ctx.status(401)); - } - return res(ctx.json({ items: [] })); - }), - ); - - const { server } = await startTestBackend({ - features: [ - minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), - withClusters([ - { - name: 'custom-cluster', - url: 'http://my.cluster.url', - authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom' }, - }, - ]), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testAuthStrategy', - register(env) { - env.registerInit({ - deps: { extension: kubernetesAuthStrategyExtensionPoint }, - async init({ extension }) { - extension.addAuthStrategy('custom', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), - }); - }, - }); - }, - }), - ], + expect(response.body).toStrictEqual({ items: [] }); }); - const proxyEndpointRequest = request(server) - .get('/api/kubernetes/proxy/api/v1/namespaces') - .set(HEADER_KUBERNETES_CLUSTER, 'custom-cluster') - .set(HEADER_KUBERNETES_AUTH, 'custom-token'); - worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); - const response = await proxyEndpointRequest; - - expect(response.body).toStrictEqual({ items: [] }); - }); - - it('reads custom auth metadata from config', async () => { - const authStrategy = { - getCredential: jest.fn().mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), - }; - worker.use( - rest.get('http://my.cluster/api', (_req, res, ctx) => - res(ctx.json({})), - ), - ); - const { server } = await startTestBackend({ - features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { type: 'multiTenant' }, - clusterLocatorMethods: [ - { - type: 'config', - clusters: [ - { - name: 'cluster', - url: 'http://my.cluster', - authProvider: 'custom', - authMetadata: { 'custom-key': 'custom-value' }, - }, - ], + it('reads custom auth metadata from config', async () => { + const authStrategy = { + getCredential: jest.fn().mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn().mockReturnValue({}), + }; + worker.use( + rest.get('http://my.cluster/api', (_req, res, ctx) => + res(ctx.json({})), + ), + ); + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { type: 'multiTenant' }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [ + { + name: 'cluster', + url: 'http://my.cluster', + authProvider: 'custom', + authMetadata: { 'custom-key': 'custom-value' }, + }, + ], + }, + ], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', authStrategy); }, - ], + }); }, - }, + }), + ], + }); + app = server; + + const proxyEndpointRequest = request(app).get( + '/api/kubernetes/proxy/api', + ); + worker.use( + rest.all(proxyEndpointRequest.url, req => req.passthrough()), + ); + const response = await proxyEndpointRequest; + + expect(response.body).toStrictEqual({}); + expect(authStrategy.getCredential).toHaveBeenCalledWith( + expect.objectContaining({ + authMetadata: expect.objectContaining({ + 'custom-key': 'custom-value', + }), }), - import('@backstage/plugin-kubernetes-backend/alpha'), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testAuthStrategy', - register(env) { - env.registerInit({ - deps: { extension: kubernetesAuthStrategyExtensionPoint }, - async init({ extension }) { - extension.addAuthStrategy('custom', authStrategy); - }, - }); - }, - }), - ], + expect.anything(), + ); }); - app = server; + }); - const proxyEndpointRequest = request(app).get( - '/api/kubernetes/proxy/api', + it('forbids custom auth strategies with dashes', () => { + const throwError = () => + startTestBackend({ + features: [ + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom-strategy', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn().mockReturnValue({}), + }); + }, + }); + }, + }), + ], + }); + return expect(throwError).rejects.toThrow( + 'Strategy name can not include dashes', ); - worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); - const response = await proxyEndpointRequest; + }); - expect(response.body).toStrictEqual({}); - expect(authStrategy.getCredential).toHaveBeenCalledWith( - expect.objectContaining({ - authMetadata: expect.objectContaining({ - 'custom-key': 'custom-value', - }), + it('serves permission integration endpoint', async () => { + const response = await request(app).get( + '/api/kubernetes/.well-known/backstage/permissions/metadata', + ); + + expect(response.status).toEqual(200); + expect(response.body).toMatchObject({ + permissions: [ + { type: 'basic', name: 'kubernetes.proxy', attributes: {} }, + ], + rules: [], + }); + }); + + it('fails when an unsupported serviceLocator type is specified', () => { + return expect(() => + startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { type: 'unsupported' }, + clusterLocatorMethods: [{ type: 'config', clusters: [] }], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + ], }), - expect.anything(), + ).rejects.toThrow( + 'Unsupported kubernetes.serviceLocatorMethod "unsupported"', ); }); }); - - it('forbids custom auth strategies with dashes', () => { - const throwError = () => - startTestBackend({ - features: [ - import('@backstage/plugin-kubernetes-backend/alpha'), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testAuthStrategy', - register(env) { - env.registerInit({ - deps: { extension: kubernetesAuthStrategyExtensionPoint }, - async init({ extension }) { - extension.addAuthStrategy('custom-strategy', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), - }); - }, - }); - }, - }), - ], - }); - return expect(throwError).rejects.toThrow( - 'Strategy name can not include dashes', - ); - }); - - it('serves permission integration endpoint', async () => { - const response = await request(app).get( - '/api/kubernetes/.well-known/backstage/permissions/metadata', - ); - - expect(response.status).toEqual(200); - expect(response.body).toMatchObject({ - permissions: [ - { type: 'basic', name: 'kubernetes.proxy', attributes: {} }, - ], - rules: [], - }); - }); - - it('fails when an unsupported serviceLocator type is specified', () => { - return expect(() => - startTestBackend({ - features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { type: 'unsupported' }, - clusterLocatorMethods: [{ type: 'config', clusters: [] }], - }, - }, - }), - import('@backstage/plugin-kubernetes-backend/alpha'), - ], - }), - ).rejects.toThrow( - 'Unsupported kubernetes.serviceLocatorMethod "unsupported"', - ); - }); }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts index a4a577db85..81cc3d471d 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.ts @@ -29,7 +29,6 @@ import { Logger } from 'winston'; import { getCombinedClusterSupplier } from '../cluster-locator'; import { - AuthenticationStrategy, AnonymousStrategy, DispatchStrategy, GoogleStrategy, @@ -45,17 +44,19 @@ import { addResourceRoutesToRouter } from '../routes/resourcesRoutes'; import { MultiTenantServiceLocator } from '../service-locator/MultiTenantServiceLocator'; import { SingleTenantServiceLocator } from '../service-locator/SingleTenantServiceLocator'; import { - CustomResource, - KubernetesFetcher, KubernetesObjectsProviderOptions, - KubernetesObjectTypes, - KubernetesServiceLocator, ObjectsByEntityRequest, ServiceLocatorMethod, } from '../types/types'; import { + AuthenticationStrategy, + AuthMetadata, + CustomResource, KubernetesClustersSupplier, + KubernetesFetcher, KubernetesObjectsProvider, + KubernetesObjectTypes, + KubernetesServiceLocator, } from '@backstage/plugin-kubernetes-node'; import { DEFAULT_OBJECTS, @@ -369,11 +370,20 @@ export class KubernetesBuilder { items: clusterDetails.map(cd => { const oidcTokenProvider = cd.authMetadata[ANNOTATION_KUBERNETES_OIDC_TOKEN_PROVIDER]; + const authProvider = + cd.authMetadata[ANNOTATION_KUBERNETES_AUTH_PROVIDER]; + const strategy = this.getAuthStrategyMap()[authProvider]; + let auth: AuthMetadata = {}; + if (strategy) { + auth = strategy.presentAuthMetadata(cd.authMetadata); + } + return { name: cd.name, dashboardUrl: cd.dashboardUrl, - authProvider: cd.authMetadata[ANNOTATION_KUBERNETES_AUTH_PROVIDER], + authProvider, ...(oidcTokenProvider && { oidcTokenProvider }), + ...(auth && Object.keys(auth).length !== 0 && { auth }), }; }), }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts index 1faf2f0673..a50d0b37a2 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts @@ -196,6 +196,7 @@ describe('KubernetesFanOutHandler', () => { >() .mockResolvedValue({ type: 'anonymous' }), validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn(), }, config, }); @@ -1147,6 +1148,7 @@ describe('KubernetesFanOutHandler', () => { >() .mockResolvedValue({ type: 'bearer token', token: 'token' }), validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn(), }, config, }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts index 9bee21867d..a9f49be780 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesProxy.test.ts @@ -131,6 +131,7 @@ describe('KubernetesProxy', () => { >() .mockResolvedValue({ type: 'anonymous' }), validateCluster: jest.fn(), + presentAuthMetadata: jest.fn(), }; proxy = new KubernetesProxy({ logger, clusterSupplier, authStrategy }); permissionApi.authorize.mockResolvedValue([ @@ -514,6 +515,7 @@ describe('KubernetesProxy', () => { .fn() .mockReturnValue({ type: 'bearer token', token: 'MY_TOKEN3' }), validateCluster: jest.fn(), + presentAuthMetadata: jest.fn(), }; proxy = new KubernetesProxy({ diff --git a/plugins/kubernetes-node/api-report.md b/plugins/kubernetes-node/api-report.md index 2272035742..aba1cdd1ae 100644 --- a/plugins/kubernetes-node/api-report.md +++ b/plugins/kubernetes-node/api-report.md @@ -25,6 +25,8 @@ export interface AuthenticationStrategy { authConfig: KubernetesRequestAuth, ): Promise; // (undocumented) + presentAuthMetadata(authMetadata: AuthMetadata): AuthMetadata; + // (undocumented) validateCluster(authMetadata: AuthMetadata): Error[]; } diff --git a/plugins/kubernetes-node/src/types/types.ts b/plugins/kubernetes-node/src/types/types.ts index a0f48d0c26..34a3286eb7 100644 --- a/plugins/kubernetes-node/src/types/types.ts +++ b/plugins/kubernetes-node/src/types/types.ts @@ -151,6 +151,7 @@ export interface AuthenticationStrategy { authConfig: KubernetesRequestAuth, ): Promise; validateCluster(authMetadata: AuthMetadata): Error[]; + presentAuthMetadata(authMetadata: AuthMetadata): AuthMetadata; } /** From d158a7afe865c4e398c78858f89448298b571978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Mauricio=20G=C3=B3mez=20P?= Date: Wed, 10 Jan 2024 15:10:25 -0500 Subject: [PATCH 235/241] Update plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jamie Klassen Signed-off-by: Andrés Mauricio Gómez P Signed-off-by: Andres Mauricio Gomez P --- .changeset/kind-clouds-fly.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/kind-clouds-fly.md b/.changeset/kind-clouds-fly.md index 7d8d7c4a0e..2cb04b520d 100644 --- a/.changeset/kind-clouds-fly.md +++ b/.changeset/kind-clouds-fly.md @@ -3,4 +3,4 @@ '@backstage/plugin-kubernetes-node': patch --- -Enabled a way to include custom auth metadata info on the clusters endpoint +Enabled a way to include custom auth metadata info on the clusters endpoint. Ff you want to implement a Kubernetes auth strategy which requires surfacing custom auth metadata to the frontend, use the new presentAuthMetadata method on the AuthenticationStrategy interface From 9d7cae0fafbeb4655a300229665e91453b64a60b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 13:35:51 +0000 Subject: [PATCH 236/241] fix(deps): update dependency @swc/jest to v0.2.30 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/yarn.lock b/yarn.lock index ef4f1cbc43..d1d0a23206 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11754,12 +11754,12 @@ __metadata: languageName: node linkType: hard -"@jest/create-cache-key-function@npm:^27.4.2": - version: 27.5.1 - resolution: "@jest/create-cache-key-function@npm:27.5.1" +"@jest/create-cache-key-function@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/create-cache-key-function@npm:29.7.0" dependencies: - "@jest/types": ^27.5.1 - checksum: a6c3a8c769aca6f66f5dc80f1c77e66980b4f213a6b2a15a92ba3595f032848a1261c06c9c798dcf2b672b1ffbefad5085af89d130548741c85ddbe0cf4284e7 + "@jest/types": ^29.6.3 + checksum: 681bc761fa1d6fa3dd77578d444f97f28296ea80755e90e46d1c8fa68661b9e67f54dd38b988742db636d26cf160450dc6011892cec98b3a7ceb58cad8ff3aae languageName: node linkType: hard @@ -11942,19 +11942,6 @@ __metadata: languageName: node linkType: hard -"@jest/types@npm:^27.5.1": - version: 27.5.1 - resolution: "@jest/types@npm:27.5.1" - dependencies: - "@types/istanbul-lib-coverage": ^2.0.0 - "@types/istanbul-reports": ^3.0.0 - "@types/node": "*" - "@types/yargs": ^16.0.0 - chalk: ^4.0.0 - checksum: d1f43cc946d87543ddd79d49547aab2399481d34025d5c5f2025d3d99c573e1d9832fa83cef25e9d9b07a8583500229d15bbb07b8e233d127d911d133e2f14b1 - languageName: node - linkType: hard - "@jest/types@npm:^28.1.3": version: 28.1.3 resolution: "@jest/types@npm:28.1.3" @@ -16993,14 +16980,14 @@ __metadata: linkType: hard "@swc/jest@npm:^0.2.22": - version: 0.2.29 - resolution: "@swc/jest@npm:0.2.29" + version: 0.2.30 + resolution: "@swc/jest@npm:0.2.30" dependencies: - "@jest/create-cache-key-function": ^27.4.2 + "@jest/create-cache-key-function": ^29.7.0 jsonc-parser: ^3.2.0 peerDependencies: "@swc/core": "*" - checksum: 9eaad322310f34e81f67d41411a7d60663341af1bd9fb65456faa914c936d849d6f643fa3b942a187d52e71e62c33097098c639d25c2047fa874f49bf51cec76 + checksum: 8ce25300949b8dfedaadec866d056a511ae2791e5cbbc8008b7d086c9c29b1b727c3f42aade88e824aa8205616e9aab812f9fa83ab4384e72f49a469f503256b languageName: node linkType: hard @@ -19147,15 +19134,6 @@ __metadata: languageName: node linkType: hard -"@types/yargs@npm:^16.0.0": - version: 16.0.4 - resolution: "@types/yargs@npm:16.0.4" - dependencies: - "@types/yargs-parser": "*" - checksum: caa21d2c957592fe2184a8368c8cbe5a82a6c2e2f2893722e489f842dc5963293d2f3120bc06fe3933d60a3a0d1e2eb269649fd6b1947fe1820f8841ba611dd9 - languageName: node - linkType: hard - "@types/yargs@npm:^17.0.8": version: 17.0.12 resolution: "@types/yargs@npm:17.0.12" From 3abcc134bd296cd320f51e60ba1c691cc402bb45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Mauricio=20G=C3=B3mez=20P?= Date: Fri, 12 Jan 2024 10:55:20 -0500 Subject: [PATCH 237/241] Update .changeset/kind-clouds-fly.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jamie Klassen Signed-off-by: Andrés Mauricio Gómez P Signed-off-by: Andres Mauricio Gomez P --- .changeset/kind-clouds-fly.md | 2 +- .../src/service/KubernetesBuilder.test.ts | 1007 ++++++++--------- 2 files changed, 485 insertions(+), 524 deletions(-) diff --git a/.changeset/kind-clouds-fly.md b/.changeset/kind-clouds-fly.md index 2cb04b520d..22aa7cda33 100644 --- a/.changeset/kind-clouds-fly.md +++ b/.changeset/kind-clouds-fly.md @@ -3,4 +3,4 @@ '@backstage/plugin-kubernetes-node': patch --- -Enabled a way to include custom auth metadata info on the clusters endpoint. Ff you want to implement a Kubernetes auth strategy which requires surfacing custom auth metadata to the frontend, use the new presentAuthMetadata method on the AuthenticationStrategy interface +Enabled a way to include custom auth metadata info on the clusters endpoint. If you want to implement a Kubernetes auth strategy which requires surfacing custom auth metadata to the frontend, use the new presentAuthMetadata method on the AuthenticationStrategy interface. diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 5030adaa81..5d19c6d94d 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -47,13 +47,13 @@ import { createBackendModule, } from '@backstage/backend-plugin-api'; import { + AuthMetadata, KubernetesObjectsProvider, kubernetesAuthStrategyExtensionPoint, kubernetesClusterSupplierExtensionPoint, kubernetesObjectsProviderExtensionPoint, kubernetesFetcherExtensionPoint, kubernetesServiceLocatorExtensionPoint, - AuthMetadata, } from '@backstage/plugin-kubernetes-node'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; @@ -183,48 +183,9 @@ describe('API integration tests', () => { }); it('happy path: lists clusters with custom AuthStrategy and custom auth metadata', async () => { - objectsProviderMock = { - getKubernetesObjectsByEntity: jest - .fn() - .mockResolvedValue(happyK8SResult), - getCustomResourcesByEntity: jest.fn().mockResolvedValue(happyK8SResult), - }; - - const clusterSupplierMock = { - getClusters: jest.fn().mockResolvedValue( - Promise.resolve([ - { - name: 'some-cluster', - url: 'https://localhost:1234', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'customAuth', - [ANNOTATION_KUBERNETES_DASHBOARD_URL]: - 'https://127.0.0.1:8443/dashboard', - [ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID]: '12650152165654', - [ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE]: 'my_aws_role', - }, - }, - ]), - ), - }; - const { server } = await startTestBackend({ features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { - type: 'multiTenant', - }, - clusterLocatorMethods: [ - { - type: 'config', - clusters: [], - }, - ], - }, - }, - }), + minimalValidConfigService, import('@backstage/plugin-kubernetes-backend/alpha'), createBackendModule({ pluginId: 'kubernetes', @@ -238,18 +199,19 @@ describe('API integration tests', () => { }); }, }), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testClusterSupplier', - register(env) { - env.registerInit({ - deps: { extension: kubernetesClusterSupplierExtensionPoint }, - async init({ extension }) { - extension.addClusterSupplier(clusterSupplierMock); - }, - }); + withClusters([ + { + name: 'some-cluster', + url: 'https://localhost:1234', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'customAuth', + [ANNOTATION_KUBERNETES_DASHBOARD_URL]: + 'https://127.0.0.1:8443/dashboard', + [ANNOTATION_KUBERNETES_AWS_EXTERNAL_ID]: '12650152165654', + [ANNOTATION_KUBERNETES_AWS_ASSUME_ROLE]: 'my_aws_role', + }, }, - }), + ]), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testAuthStrategy', @@ -298,508 +260,507 @@ describe('API integration tests', () => { }), ], }); - }); + app = server; - describe('post /services/:serviceId', () => { - it('happy path: lists kubernetes objects without auth in request body', async () => { - const response = await request(app).post( - '/api/kubernetes/services/test-service', - ); - expect(response.status).toEqual(200); - expect(response.body).toEqual(happyK8SResult); - }); + const response = await request(app).get('/api/kubernetes/clusters'); - it('happy path: lists kubernetes objects with auth in request body', async () => { - const response = await request(app) - .post('/api/kubernetes/services/test-service') - .send({ auth: { google: 'google_token_123' } }) - .set('Content-Type', 'application/json'); - expect(response.status).toEqual(200); - expect(response.body).toEqual(happyK8SResult); - }); - - it('internal error: lists kubernetes objects', async () => { - objectsProviderMock.getKubernetesObjectsByEntity.mockRejectedValue( - Error('some internal error'), - ); - - const response = await request(app).post( - '/api/kubernetes/services/test-service', - ); - - expect(response.status).toEqual(500); - expect(response.body).toEqual({ error: 'some internal error' }); - }); - - it('custom service locator', async () => { - const someCluster = { - name: 'some-cluster', - url: 'https://localhost:1234', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', - serviceAccountToken: 'placeholder-token', - }, - }; - const clusters: ClusterDetails[] = [ - someCluster, + expect(response.status).toEqual(200); + expect(response.body).toStrictEqual({ + items: [ { - name: 'some-other-cluster', - url: 'https://localhost:1235', - authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' }, - }, - ]; - - const pod = { metadata: { name: 'pod1' } }; - - const mockServiceLocator: jest.Mocked = { - getClustersByEntity: jest.fn().mockResolvedValue({ - clusters: [someCluster], - }), - }; - - const mockFetcher: jest.Mocked = { - fetchPodMetricsByNamespaces: jest - .fn() - .mockResolvedValue({ errors: [], responses: [] }), - fetchObjectsForService: jest.fn().mockResolvedValue({ - errors: [], - responses: [{ type: 'pods', resources: [pod] }], - }), - }; - - const { server } = await startTestBackend({ - features: [ - minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), - withClusters(clusters), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testFetcher', - register(env) { - env.registerInit({ - deps: { extension: kubernetesFetcherExtensionPoint }, - async init({ extension }) { - extension.addFetcher(mockFetcher); - }, - }); - }, - }), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testServiceLocator', - register(env) { - env.registerInit({ - deps: { extension: kubernetesServiceLocatorExtensionPoint }, - async init({ extension }) { - extension.addServiceLocator(mockServiceLocator); - }, - }); - }, - }), - ], - }); - app = server; - - const response = await request(app) - .post('/api/kubernetes/services/test-service') - .send({ entity: { metadata: { name: 'thing' } } }); - - expect(response.body).toEqual({ - items: [ - { - cluster: { name: someCluster.name }, - errors: [], - podMetrics: [], - resources: [{ type: 'pods', resources: [pod] }], + name: 'some-cluster', + authProvider: 'customAuth', + auth: { + 'kubernetes.io/aws-assume-role': 'my_aws_role', + 'kubernetes.io/dashboard-url': 'https://127.0.0.1:8443/dashboard', }, - ], - }); - expect(response.status).toEqual(200); - }); - - it('reads auth data for custom strategy', async () => { - const mockFetcher = { - fetchPodMetricsByNamespaces: jest - .fn() - .mockResolvedValue({ errors: [], responses: [] }), - fetchObjectsForService: jest.fn().mockResolvedValue({ - errors: [], - responses: [ - { type: 'pods', resources: [{ metadata: { name: 'pod1' } }] }, - ], - }), - }; - - const { server } = await startTestBackend({ - features: [ - minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), - withClusters([ - { - name: 'custom-cluster', - url: 'http://my.cluster.url', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', - }, - }, - ]), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testAuthStrategy', - register(env) { - env.registerInit({ - deps: { extension: kubernetesAuthStrategyExtensionPoint }, - async init({ extension }) { - extension.addAuthStrategy('custom', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockImplementation(async (_, requestAuth) => ({ - type: 'bearer token', - token: requestAuth.custom as string, - })), - validateCluster: jest.fn().mockReturnValue([]), - presentAuthMetadata: jest.fn().mockReturnValue({}), - }); - }, - }); - }, - }), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testFetcher', - register(env) { - env.registerInit({ - deps: { extension: kubernetesFetcherExtensionPoint }, - async init({ extension }) { - extension.addFetcher(mockFetcher); - }, - }); - }, - }), - ], - }); - - app = server; - - await request(app) - .post('/api/kubernetes/services/test-service') - .send({ - entity: { metadata: { name: 'thing' } }, - auth: { custom: 'custom-token' }, - }); - - expect(mockFetcher.fetchObjectsForService).toHaveBeenCalledWith( - expect.objectContaining({ - credential: { type: 'bearer token', token: 'custom-token' }, - }), - ); + }, + ], }); }); + }); - describe('/proxy', () => { - const worker = setupServer(); - setupRequestMockHandlers(worker); + describe('post /services/:serviceId', () => { + it('happy path: lists kubernetes objects without auth in request body', async () => { + const response = await request(app).post( + '/api/kubernetes/services/test-service', + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(happyK8SResult); + }); - beforeEach(() => { - worker.use( - rest.post( - 'https://localhost:1234/api/v1/namespaces', - (req, res, ctx) => { - if (!req.headers.get('Authorization')) { - return res(ctx.status(401)); - } - return req - .arrayBuffer() - .then(body => - res( - ctx.set( - 'content-type', - `${req.headers.get('content-type')}`, - ), - ctx.body(body), - ), - ); + it('happy path: lists kubernetes objects with auth in request body', async () => { + const response = await request(app) + .post('/api/kubernetes/services/test-service') + .send({ auth: { google: 'google_token_123' } }) + .set('Content-Type', 'application/json'); + expect(response.status).toEqual(200); + expect(response.body).toEqual(happyK8SResult); + }); + + it('internal error: lists kubernetes objects', async () => { + objectsProviderMock.getKubernetesObjectsByEntity.mockRejectedValue( + Error('some internal error'), + ); + + const response = await request(app).post( + '/api/kubernetes/services/test-service', + ); + + expect(response.status).toEqual(500); + expect(response.body).toEqual({ error: 'some internal error' }); + }); + + it('custom service locator', async () => { + const someCluster = { + name: 'some-cluster', + url: 'https://localhost:1234', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'serviceAccount', + serviceAccountToken: 'placeholder-token', + }, + }; + const clusters: ClusterDetails[] = [ + someCluster, + { + name: 'some-other-cluster', + url: 'https://localhost:1235', + authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'google' }, + }, + ]; + + const pod = { metadata: { name: 'pod1' } }; + + const mockServiceLocator: jest.Mocked = { + getClustersByEntity: jest.fn().mockResolvedValue({ + clusters: [someCluster], + }), + }; + + const mockFetcher: jest.Mocked = { + fetchPodMetricsByNamespaces: jest + .fn() + .mockResolvedValue({ errors: [], responses: [] }), + fetchObjectsForService: jest.fn().mockResolvedValue({ + errors: [], + responses: [{ type: 'pods', resources: [pod] }], + }), + }; + + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + import('@backstage/plugin-kubernetes-backend/alpha'), + withClusters(clusters), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testFetcher', + register(env) { + env.registerInit({ + deps: { extension: kubernetesFetcherExtensionPoint }, + async init({ extension }) { + extension.addFetcher(mockFetcher); + }, + }); }, - ), - ); + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testServiceLocator', + register(env) { + env.registerInit({ + deps: { extension: kubernetesServiceLocatorExtensionPoint }, + async init({ extension }) { + extension.addServiceLocator(mockServiceLocator); + }, + }); + }, + }), + ], + }); + app = server; + + const response = await request(app) + .post('/api/kubernetes/services/test-service') + .send({ entity: { metadata: { name: 'thing' } } }); + + expect(response.body).toEqual({ + items: [ + { + cluster: { name: someCluster.name }, + errors: [], + podMetrics: [], + resources: [{ type: 'pods', resources: [pod] }], + }, + ], + }); + expect(response.status).toEqual(200); + }); + + it('reads auth data for custom strategy', async () => { + const mockFetcher = { + fetchPodMetricsByNamespaces: jest + .fn() + .mockResolvedValue({ errors: [], responses: [] }), + fetchObjectsForService: jest.fn().mockResolvedValue({ + errors: [], + responses: [ + { type: 'pods', resources: [{ metadata: { name: 'pod1' } }] }, + ], + }), + }; + + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + import('@backstage/plugin-kubernetes-backend/alpha'), + withClusters([ + { + name: 'custom-cluster', + url: 'http://my.cluster.url', + authMetadata: { + [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', + }, + }, + ]), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockImplementation(async (_, requestAuth) => ({ + type: 'bearer token', + token: requestAuth.custom as string, + })), + validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn().mockReturnValue({}), + }); + }, + }); + }, + }), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testFetcher', + register(env) { + env.registerInit({ + deps: { extension: kubernetesFetcherExtensionPoint }, + async init({ extension }) { + extension.addFetcher(mockFetcher); + }, + }); + }, + }), + ], }); - it('forwards request body to k8s', async () => { - const namespaceManifest = { - kind: 'Namespace', - apiVersion: 'v1', - metadata: { name: 'new-ns' }, - }; + app = server; - const proxyEndpointRequest = request(app) - .post('/api/kubernetes/proxy/api/v1/namespaces') - .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') - .set(HEADER_KUBERNETES_AUTH, 'randomtoken') - .send(namespaceManifest); - worker.use( - rest.all(proxyEndpointRequest.url, req => req.passthrough()), - ); - const response = await proxyEndpointRequest; + await request(app) + .post('/api/kubernetes/services/test-service') + .send({ + entity: { metadata: { name: 'thing' } }, + auth: { custom: 'custom-token' }, + }); - expect(response.body).toStrictEqual(namespaceManifest); - }); + expect(mockFetcher.fetchObjectsForService).toHaveBeenCalledWith( + expect.objectContaining({ + credential: { type: 'bearer token', token: 'custom-token' }, + }), + ); + }); + }); - it('supports yaml content type', async () => { - const yamlManifest = `--- + describe('/proxy', () => { + const worker = setupServer(); + setupRequestMockHandlers(worker); + + beforeEach(() => { + worker.use( + rest.post( + 'https://localhost:1234/api/v1/namespaces', + (req, res, ctx) => { + if (!req.headers.get('Authorization')) { + return res(ctx.status(401)); + } + return req + .arrayBuffer() + .then(body => + res( + ctx.set('content-type', `${req.headers.get('content-type')}`), + ctx.body(body), + ), + ); + }, + ), + ); + }); + + it('forwards request body to k8s', async () => { + const namespaceManifest = { + kind: 'Namespace', + apiVersion: 'v1', + metadata: { name: 'new-ns' }, + }; + + const proxyEndpointRequest = request(app) + .post('/api/kubernetes/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') + .send(namespaceManifest); + worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); + const response = await proxyEndpointRequest; + + expect(response.body).toStrictEqual(namespaceManifest); + }); + + it('supports yaml content type', async () => { + const yamlManifest = `--- kind: Namespace apiVersion: v1 metadata: name: new-ns `; - const proxyEndpointRequest = request(app) - .post('/api/kubernetes/proxy/api/v1/namespaces') - .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') - .set(HEADER_KUBERNETES_AUTH, 'randomtoken') - .set('content-type', 'application/yaml') - .send(yamlManifest); + const proxyEndpointRequest = request(app) + .post('/api/kubernetes/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') + .set('content-type', 'application/yaml') + .send(yamlManifest); - worker.use( - rest.all(proxyEndpointRequest.url, req => req.passthrough()), - ); + worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); - const response = await proxyEndpointRequest; - expect(response.text).toEqual(yamlManifest); - }); - - it('returns 403 response when permission blocks endpoint', async () => { - permissionsMock.authorize.mockResolvedValue([ - { result: AuthorizeResult.DENY }, - ]); - - const { server } = await startTestBackend({ - features: [ - minimalValidConfigService, - permissionsMock.factory, - import('@backstage/plugin-kubernetes-backend/alpha'), - ], - }); - app = server; - - const proxyEndpointRequest = request(app) - .post('/api/kubernetes/proxy/api/v1/namespaces') - .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') - .set(HEADER_KUBERNETES_AUTH, 'randomtoken') - .send({ - kind: 'Namespace', - apiVersion: 'v1', - metadata: { name: 'new-ns' }, - }); - - worker.use( - rest.all(proxyEndpointRequest.url, req => req.passthrough()), - ); - - const response = await proxyEndpointRequest; - - expect(response.status).toEqual(403); - }); - - it('permits custom client-side auth strategy', async () => { - worker.use( - rest.get( - 'http://my.cluster.url/api/v1/namespaces', - (req, res, ctx) => { - if (req.headers.get('Authorization') !== 'custom-token') { - return res(ctx.status(401)); - } - return res(ctx.json({ items: [] })); - }, - ), - ); - - const { server } = await startTestBackend({ - features: [ - minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), - withClusters([ - { - name: 'custom-cluster', - url: 'http://my.cluster.url', - authMetadata: { - [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom', - }, - }, - ]), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testAuthStrategy', - register(env) { - env.registerInit({ - deps: { extension: kubernetesAuthStrategyExtensionPoint }, - async init({ extension }) { - extension.addAuthStrategy('custom', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), - presentAuthMetadata: jest.fn().mockReturnValue({}), - }); - }, - }); - }, - }), - ], - }); - - const proxyEndpointRequest = request(server) - .get('/api/kubernetes/proxy/api/v1/namespaces') - .set(HEADER_KUBERNETES_CLUSTER, 'custom-cluster') - .set(HEADER_KUBERNETES_AUTH, 'custom-token'); - worker.use( - rest.all(proxyEndpointRequest.url, req => req.passthrough()), - ); - const response = await proxyEndpointRequest; - - expect(response.body).toStrictEqual({ items: [] }); - }); - - it('reads custom auth metadata from config', async () => { - const authStrategy = { - getCredential: jest.fn().mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), - presentAuthMetadata: jest.fn().mockReturnValue({}), - }; - worker.use( - rest.get('http://my.cluster/api', (_req, res, ctx) => - res(ctx.json({})), - ), - ); - const { server } = await startTestBackend({ - features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { type: 'multiTenant' }, - clusterLocatorMethods: [ - { - type: 'config', - clusters: [ - { - name: 'cluster', - url: 'http://my.cluster', - authProvider: 'custom', - authMetadata: { 'custom-key': 'custom-value' }, - }, - ], - }, - ], - }, - }, - }), - import('@backstage/plugin-kubernetes-backend/alpha'), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testAuthStrategy', - register(env) { - env.registerInit({ - deps: { extension: kubernetesAuthStrategyExtensionPoint }, - async init({ extension }) { - extension.addAuthStrategy('custom', authStrategy); - }, - }); - }, - }), - ], - }); - app = server; - - const proxyEndpointRequest = request(app).get( - '/api/kubernetes/proxy/api', - ); - worker.use( - rest.all(proxyEndpointRequest.url, req => req.passthrough()), - ); - const response = await proxyEndpointRequest; - - expect(response.body).toStrictEqual({}); - expect(authStrategy.getCredential).toHaveBeenCalledWith( - expect.objectContaining({ - authMetadata: expect.objectContaining({ - 'custom-key': 'custom-value', - }), - }), - expect.anything(), - ); - }); + const response = await proxyEndpointRequest; + expect(response.text).toEqual(yamlManifest); }); - it('forbids custom auth strategies with dashes', () => { - const throwError = () => - startTestBackend({ - features: [ - import('@backstage/plugin-kubernetes-backend/alpha'), - createBackendModule({ - pluginId: 'kubernetes', - moduleId: 'testAuthStrategy', - register(env) { - env.registerInit({ - deps: { extension: kubernetesAuthStrategyExtensionPoint }, - async init({ extension }) { - extension.addAuthStrategy('custom-strategy', { - getCredential: jest - .fn< - Promise, - [ClusterDetails, KubernetesRequestAuth] - >() - .mockResolvedValue({ type: 'anonymous' }), - validateCluster: jest.fn().mockReturnValue([]), - presentAuthMetadata: jest.fn().mockReturnValue({}), - }); - }, - }); - }, - }), - ], - }); - return expect(throwError).rejects.toThrow( - 'Strategy name can not include dashes', - ); - }); + it('returns 403 response when permission blocks endpoint', async () => { + permissionsMock.authorize.mockResolvedValue([ + { result: AuthorizeResult.DENY }, + ]); - it('serves permission integration endpoint', async () => { - const response = await request(app).get( - '/api/kubernetes/.well-known/backstage/permissions/metadata', - ); - - expect(response.status).toEqual(200); - expect(response.body).toMatchObject({ - permissions: [ - { type: 'basic', name: 'kubernetes.proxy', attributes: {} }, + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + permissionsMock.factory, + import('@backstage/plugin-kubernetes-backend/alpha'), ], - rules: [], }); + app = server; + + const proxyEndpointRequest = request(app) + .post('/api/kubernetes/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'some-cluster') + .set(HEADER_KUBERNETES_AUTH, 'randomtoken') + .send({ + kind: 'Namespace', + apiVersion: 'v1', + metadata: { name: 'new-ns' }, + }); + + worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); + + const response = await proxyEndpointRequest; + + expect(response.status).toEqual(403); }); - it('fails when an unsupported serviceLocator type is specified', () => { - return expect(() => - startTestBackend({ - features: [ - mockServices.rootConfig.factory({ - data: { - kubernetes: { - serviceLocatorMethod: { type: 'unsupported' }, - clusterLocatorMethods: [{ type: 'config', clusters: [] }], - }, - }, - }), - import('@backstage/plugin-kubernetes-backend/alpha'), - ], + it('permits custom client-side auth strategy', async () => { + worker.use( + rest.get('http://my.cluster.url/api/v1/namespaces', (req, res, ctx) => { + if (req.headers.get('Authorization') !== 'custom-token') { + return res(ctx.status(401)); + } + return res(ctx.json({ items: [] })); }), - ).rejects.toThrow( - 'Unsupported kubernetes.serviceLocatorMethod "unsupported"', + ); + + const { server } = await startTestBackend({ + features: [ + minimalValidConfigService, + import('@backstage/plugin-kubernetes-backend/alpha'), + withClusters([ + { + name: 'custom-cluster', + url: 'http://my.cluster.url', + authMetadata: { [ANNOTATION_KUBERNETES_AUTH_PROVIDER]: 'custom' }, + }, + ]), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn().mockReturnValue({}), + }); + }, + }); + }, + }), + ], + }); + + const proxyEndpointRequest = request(server) + .get('/api/kubernetes/proxy/api/v1/namespaces') + .set(HEADER_KUBERNETES_CLUSTER, 'custom-cluster') + .set(HEADER_KUBERNETES_AUTH, 'custom-token'); + worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); + const response = await proxyEndpointRequest; + + expect(response.body).toStrictEqual({ items: [] }); + }); + + it('reads custom auth metadata from config', async () => { + const authStrategy = { + getCredential: jest.fn().mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn().mockReturnValue({}), + }; + worker.use( + rest.get('http://my.cluster/api', (_req, res, ctx) => + res(ctx.json({})), + ), + ); + const { server } = await startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { type: 'multiTenant' }, + clusterLocatorMethods: [ + { + type: 'config', + clusters: [ + { + name: 'cluster', + url: 'http://my.cluster', + authProvider: 'custom', + authMetadata: { 'custom-key': 'custom-value' }, + }, + ], + }, + ], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom', authStrategy); + }, + }); + }, + }), + ], + }); + app = server; + + const proxyEndpointRequest = request(app).get( + '/api/kubernetes/proxy/api', + ); + worker.use(rest.all(proxyEndpointRequest.url, req => req.passthrough())); + const response = await proxyEndpointRequest; + + expect(response.body).toStrictEqual({}); + expect(authStrategy.getCredential).toHaveBeenCalledWith( + expect.objectContaining({ + authMetadata: expect.objectContaining({ + 'custom-key': 'custom-value', + }), + }), + expect.anything(), ); }); }); + + it('forbids custom auth strategies with dashes', () => { + const throwError = () => + startTestBackend({ + features: [ + import('@backstage/plugin-kubernetes-backend/alpha'), + createBackendModule({ + pluginId: 'kubernetes', + moduleId: 'testAuthStrategy', + register(env) { + env.registerInit({ + deps: { extension: kubernetesAuthStrategyExtensionPoint }, + async init({ extension }) { + extension.addAuthStrategy('custom-strategy', { + getCredential: jest + .fn< + Promise, + [ClusterDetails, KubernetesRequestAuth] + >() + .mockResolvedValue({ type: 'anonymous' }), + validateCluster: jest.fn().mockReturnValue([]), + presentAuthMetadata: jest.fn().mockReturnValue({}), + }); + }, + }); + }, + }), + ], + }); + return expect(throwError).rejects.toThrow( + 'Strategy name can not include dashes', + ); + }); + + it('serves permission integration endpoint', async () => { + const response = await request(app).get( + '/api/kubernetes/.well-known/backstage/permissions/metadata', + ); + + expect(response.status).toEqual(200); + expect(response.body).toMatchObject({ + permissions: [ + { type: 'basic', name: 'kubernetes.proxy', attributes: {} }, + ], + rules: [], + }); + }); + + it('fails when an unsupported serviceLocator type is specified', () => { + return expect(() => + startTestBackend({ + features: [ + mockServices.rootConfig.factory({ + data: { + kubernetes: { + serviceLocatorMethod: { type: 'unsupported' }, + clusterLocatorMethods: [{ type: 'config', clusters: [] }], + }, + }, + }), + import('@backstage/plugin-kubernetes-backend/alpha'), + ], + }), + ).rejects.toThrow( + 'Unsupported kubernetes.serviceLocatorMethod "unsupported"', + ); + }); }); From 8c8b6a019715b1f8008d655e34a93c52a907a753 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:17:19 +0000 Subject: [PATCH 238/241] chore(deps): update dependency better-sqlite3 to v9.3.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0342b37b52..ace835f1d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21221,13 +21221,13 @@ __metadata: linkType: hard "better-sqlite3@npm:^9.0.0": - version: 9.2.2 - resolution: "better-sqlite3@npm:9.2.2" + version: 9.3.0 + resolution: "better-sqlite3@npm:9.3.0" dependencies: bindings: ^1.5.0 node-gyp: latest prebuild-install: ^7.1.1 - checksum: 11d78ed15c8f059c5b58845c40b921692468cef291975ad9f9395278c6ba3005ae2aceb20175fe18e901983ed68c785fdd39c729dc789d72be4184a406bd9a2c + checksum: 03dedaeef92aaa5e963e9fad5849afca3568c987b4d6f36957f9879137c994aa18f9654fe7bcc3804620ede55eabd19ff9bcba03ad0bf985aa8bd5561e4aaa43 languageName: node linkType: hard From b0d1d809e6c096ebabeb42884d5bddc5c7cc8e95 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 18 Jan 2024 15:48:18 +0100 Subject: [PATCH 239/241] scaffolder: initial support for new frontend system Signed-off-by: Patrik Oldsberg --- .changeset/grumpy-poets-study.md | 5 ++ plugins/scaffolder/api-report-alpha.md | 31 ++++++++ plugins/scaffolder/package.json | 6 +- plugins/scaffolder/src/alpha.ts | 23 ------ plugins/scaffolder/src/alpha.tsx | 103 +++++++++++++++++++++++++ yarn.lock | 2 + 6 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 .changeset/grumpy-poets-study.md delete mode 100644 plugins/scaffolder/src/alpha.ts create mode 100644 plugins/scaffolder/src/alpha.tsx diff --git a/.changeset/grumpy-poets-study.md b/.changeset/grumpy-poets-study.md new file mode 100644 index 0000000000..9925f2f87a --- /dev/null +++ b/.changeset/grumpy-poets-study.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Added basic support for the new frontend system, exported from the `/alpha` subpath. diff --git a/plugins/scaffolder/api-report-alpha.md b/plugins/scaffolder/api-report-alpha.md index 6a1e0648a4..c8824d42da 100644 --- a/plugins/scaffolder/api-report-alpha.md +++ b/plugins/scaffolder/api-report-alpha.md @@ -5,19 +5,50 @@ ```ts /// +import { BackstagePlugin } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; import { Entity } from '@backstage/catalog-model'; +import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import type { FormProps as FormProps_2 } from '@rjsf/core'; import { FormProps as FormProps_3 } from '@backstage/plugin-scaffolder-react'; import { JSX as JSX_2 } from 'react'; import { LayoutOptions } from '@backstage/plugin-scaffolder-react'; +import { PathParams } from '@backstage/core-plugin-api'; import { PropsWithChildren } from 'react'; import { default as React_2 } from 'react'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; +import { RouteRef } from '@backstage/frontend-plugin-api'; +import { SubRouteRef } from '@backstage/frontend-plugin-api'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; +// @alpha (undocumented) +const _default: BackstagePlugin< + { + root: RouteRef; + selectedTemplate: SubRouteRef< + PathParams<'/templates/:namespace/:templateName'> + >; + ongoingTask: SubRouteRef>; + actions: SubRouteRef; + listTasks: SubRouteRef; + edit: SubRouteRef; + }, + { + registerComponent: ExternalRouteRef; + viewTechDoc: ExternalRouteRef< + { + name: string; + kind: string; + namespace: string; + }, + true + >; + } +>; +export default _default; + // @alpha @deprecated export type FormProps = Pick< FormProps_2, diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 690af2f971..8652c380ba 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -10,13 +10,13 @@ }, "exports": { ".": "./src/index.ts", - "./alpha": "./src/alpha.ts", + "./alpha": "./src/alpha.tsx", "./package.json": "./package.json" }, "typesVersions": { "*": { "alpha": [ - "src/alpha.ts" + "src/alpha.tsx" ], "package.json": [ "package.json" @@ -48,9 +48,11 @@ "dependencies": { "@backstage/catalog-client": "workspace:^", "@backstage/catalog-model": "workspace:^", + "@backstage/core-compat-api": "workspace:^", "@backstage/core-components": "workspace:^", "@backstage/core-plugin-api": "workspace:^", "@backstage/errors": "workspace:^", + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/integration-react": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", diff --git a/plugins/scaffolder/src/alpha.ts b/plugins/scaffolder/src/alpha.ts deleted file mode 100644 index 92ec945de4..0000000000 --- a/plugins/scaffolder/src/alpha.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2023 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { - type FormProps, - type TemplateListPageProps, - type TemplateWizardPageProps, -} from './next'; - -export * from './legacy'; diff --git a/plugins/scaffolder/src/alpha.tsx b/plugins/scaffolder/src/alpha.tsx new file mode 100644 index 0000000000..152745eec1 --- /dev/null +++ b/plugins/scaffolder/src/alpha.tsx @@ -0,0 +1,103 @@ +/* + * Copyright 2023 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 { + createApiExtension, + createApiFactory, + createNavItemExtension, + createPageExtension, + createPlugin, + discoveryApiRef, + fetchApiRef, + identityApiRef, +} from '@backstage/frontend-plugin-api'; +import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; +import { + compatWrapper, + convertLegacyRouteRef, +} from '@backstage/core-compat-api'; +import { scmIntegrationsApiRef } from '@backstage/integration-react'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderClient } from './api'; +import { + registerComponentRouteRef, + rootRouteRef, + viewTechDocRouteRef, + selectedTemplateRouteRef, + scaffolderTaskRouteRef, + scaffolderListTaskRouteRef, + actionsRouteRef, + editRouteRef, +} from './routes'; + +export { + type FormProps, + type TemplateListPageProps, + type TemplateWizardPageProps, +} from './next'; + +export * from './legacy'; + +const scaffolderApi = createApiExtension({ + factory: createApiFactory({ + api: scaffolderApiRef, + deps: { + discoveryApi: discoveryApiRef, + scmIntegrationsApi: scmIntegrationsApiRef, + fetchApi: fetchApiRef, + identityApi: identityApiRef, + }, + factory: ({ discoveryApi, scmIntegrationsApi, fetchApi, identityApi }) => + new ScaffolderClient({ + discoveryApi, + scmIntegrationsApi, + fetchApi, + identityApi, + }), + }), +}); + +const scaffolderPage = createPageExtension({ + routeRef: convertLegacyRouteRef(rootRouteRef), + defaultPath: '/create', + loader: () => + import('./components/Router').then(m => compatWrapper()), +}); + +const scaffolderNavItem = createNavItemExtension({ + routeRef: convertLegacyRouteRef(rootRouteRef), + title: 'Create...', + icon: CreateComponentIcon, +}); + +/** @alpha */ +export default createPlugin({ + id: 'scaffolder', + routes: { + root: convertLegacyRouteRef(rootRouteRef), + selectedTemplate: convertLegacyRouteRef(selectedTemplateRouteRef), + ongoingTask: convertLegacyRouteRef(scaffolderTaskRouteRef), + actions: convertLegacyRouteRef(actionsRouteRef), + listTasks: convertLegacyRouteRef(scaffolderListTaskRouteRef), + edit: convertLegacyRouteRef(editRouteRef), + }, + externalRoutes: { + registerComponent: convertLegacyRouteRef(registerComponentRouteRef), + viewTechDoc: convertLegacyRouteRef(viewTechDocRouteRef), + }, + extensions: [scaffolderApi, scaffolderPage, scaffolderNavItem], +}); diff --git a/yarn.lock b/yarn.lock index ef4f1cbc43..41d7365fe7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8328,10 +8328,12 @@ __metadata: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" "@backstage/core-app-api": "workspace:^" + "@backstage/core-compat-api": "workspace:^" "@backstage/core-components": "workspace:^" "@backstage/core-plugin-api": "workspace:^" "@backstage/dev-utils": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/integration-react": "workspace:^" "@backstage/plugin-catalog": "workspace:^" From ef18e8b484d24803b161de025164e5eb743d6954 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 15:15:23 +0000 Subject: [PATCH 240/241] chore(deps): update dependency eslint to v8.56.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index ace835f1d0..d7544bafc4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10873,10 +10873,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:8.55.0": - version: 8.55.0 - resolution: "@eslint/js@npm:8.55.0" - checksum: fa33ef619f0646ed15649b0c2e313e4d9ccee8425884bdbfc78020d6b6b64c0c42fa9d83061d0e6158e1d4274f03f0f9008786540e2efab8fcdc48082259908c +"@eslint/js@npm:8.56.0": + version: 8.56.0 + resolution: "@eslint/js@npm:8.56.0" + checksum: 5804130574ef810207bdf321c265437814e7a26f4e6fac9b496de3206afd52f533e09ec002a3be06cd9adcc9da63e727f1883938e663c4e4751c007d5b58e539 languageName: node linkType: hard @@ -26005,13 +26005,13 @@ __metadata: linkType: hard "eslint@npm:^8.33.0, eslint@npm:^8.6.0": - version: 8.55.0 - resolution: "eslint@npm:8.55.0" + version: 8.56.0 + resolution: "eslint@npm:8.56.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@eslint-community/regexpp": ^4.6.1 "@eslint/eslintrc": ^2.1.4 - "@eslint/js": 8.55.0 + "@eslint/js": 8.56.0 "@humanwhocodes/config-array": ^0.11.13 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 @@ -26048,7 +26048,7 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 83f82a604559dc1faae79d28fdf3dfc9e592ca221052e2ea516e1b379b37e77e4597705a16880e2f5ece4f79087c1dd13fd7f6e9746f794a401175519db18b41 + checksum: 883436d1e809b4a25d9eb03d42f584b84c408dbac28b0019f6ea07b5177940bf3cca86208f749a6a1e0039b63e085ee47aca1236c30721e91f0deef5cc5a5136 languageName: node linkType: hard From 3dd117d7cce6666bf72d80a0a5bc32f0edabd812 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 16:29:11 +0000 Subject: [PATCH 241/241] chore(deps): update dependency msw to v2.1.2 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 70 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/yarn.lock b/yarn.lock index d7544bafc4..8e503b3047 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12736,9 +12736,9 @@ __metadata: languageName: node linkType: hard -"@mswjs/interceptors@npm:^0.25.13": - version: 0.25.13 - resolution: "@mswjs/interceptors@npm:0.25.13" +"@mswjs/interceptors@npm:^0.25.14": + version: 0.25.14 + resolution: "@mswjs/interceptors@npm:0.25.14" dependencies: "@open-draft/deferred-promise": ^2.2.0 "@open-draft/logger": ^0.3.0 @@ -12746,7 +12746,7 @@ __metadata: is-node-process: ^1.2.0 outvariant: ^1.2.1 strict-event-emitter: ^0.5.1 - checksum: 21eaefbd66dc2c3bbeec5b6a2fdc714f6a0967158c0137cd1e4b875284e55d358b4a032030d5e0783e5826cdb27918086d1fd8412f3cbcc70e5368554f678d46 + checksum: caf9513cf6848ff0c3f1402abf881d3c1333f68fae54076cfd3fd919b7edb709769342bd3afd2a60ef4ae698ef47776b6203e0ea6a5d8e788e97eda7ed9dbbd4 languageName: node linkType: hard @@ -17537,6 +17537,13 @@ __metadata: languageName: node linkType: hard +"@types/cookie@npm:^0.6.0": + version: 0.6.0 + resolution: "@types/cookie@npm:0.6.0" + checksum: 5edce7995775b0b196b142883e4d4f71fd93c294eaec973670f1fa2540b70ea7390408ed513ddefef5fcb12a578100c76596e8f2a714b0c2ae9f70ee773f4510 + languageName: node + linkType: hard + "@types/cookiejar@npm:*": version: 2.1.1 resolution: "@types/cookiejar@npm:2.1.1" @@ -18066,10 +18073,10 @@ __metadata: languageName: node linkType: hard -"@types/js-levenshtein@npm:^1.1.1": - version: 1.1.1 - resolution: "@types/js-levenshtein@npm:1.1.1" - checksum: 1d1ff1ee2ad551909e47f3ce19fcf85b64dc5146d3b531c8d26fc775492d36e380b32cf5ef68ff301e812c3b00282f37aac579ebb44498b94baff0ace7509769 +"@types/js-levenshtein@npm:^1.1.1, @types/js-levenshtein@npm:^1.1.3": + version: 1.1.3 + resolution: "@types/js-levenshtein@npm:1.1.3" + checksum: eb338696da976925ea8448a42d775d7615a14323dceeb08909f187d0b3d3b4c1f67a1c36ef586b1c2318b70ab141bba8fc58311ba1c816711704605aec09db8b languageName: node linkType: hard @@ -18905,7 +18912,7 @@ __metadata: languageName: node linkType: hard -"@types/statuses@npm:^2.0.1": +"@types/statuses@npm:^2.0.4": version: 2.0.4 resolution: "@types/statuses@npm:2.0.4" checksum: 3a806c3b96d1845e3e7441fbf0839037e95f717334760ddb7c29223c9a34a7206b68e2998631f89f1a1e3ef5b67b15652f6e8fa14987ebd7f6d38587c1bffd18 @@ -28777,7 +28784,7 @@ __metadata: languageName: node linkType: hard -"headers-polyfill@npm:^4.0.1": +"headers-polyfill@npm:^4.0.2": version: 4.0.2 resolution: "headers-polyfill@npm:4.0.2" checksum: a95280ed58df429fc86c4f49b21596be3ea3f5f3d790e7d75238668df9b90b292f15a968c7c19ae1db88c0ae036dd1bf363a71b8e771199d82848e2d8b3c6c2e @@ -34457,38 +34464,38 @@ __metadata: linkType: hard "msw@npm:^2.0.0, msw@npm:^2.0.8": - version: 2.0.11 - resolution: "msw@npm:2.0.11" + version: 2.1.2 + resolution: "msw@npm:2.1.2" dependencies: "@bundled-es-modules/cookie": ^2.0.0 "@bundled-es-modules/js-levenshtein": ^2.0.1 "@bundled-es-modules/statuses": ^1.0.1 "@mswjs/cookies": ^1.1.0 - "@mswjs/interceptors": ^0.25.13 + "@mswjs/interceptors": ^0.25.14 "@open-draft/until": ^2.1.0 - "@types/cookie": ^0.4.1 - "@types/js-levenshtein": ^1.1.1 - "@types/statuses": ^2.0.1 + "@types/cookie": ^0.6.0 + "@types/js-levenshtein": ^1.1.3 + "@types/statuses": ^2.0.4 chalk: ^4.1.2 chokidar: ^3.4.2 graphql: ^16.8.1 - headers-polyfill: ^4.0.1 + headers-polyfill: ^4.0.2 inquirer: ^8.2.0 is-node-process: ^1.2.0 js-levenshtein: ^1.1.6 - outvariant: ^1.4.0 + outvariant: ^1.4.2 path-to-regexp: ^6.2.0 - strict-event-emitter: ^0.5.0 - type-fest: ^2.19.0 - yargs: ^17.3.1 + strict-event-emitter: ^0.5.1 + type-fest: ^4.9.0 + yargs: ^17.7.2 peerDependencies: - typescript: ">= 4.7.x <= 5.2.x" + typescript: ">= 4.7.x <= 5.3.x" peerDependenciesMeta: typescript: optional: true bin: msw: cli/index.js - checksum: a87175f53e3b510dfdfb16e11f2b0d399a9859ce1f249a70741045ce6325b3512075878921d4bd30ad6cb0789cd6fc4f9eac5db68ae425777e96ad208285242d + checksum: 58b6e9ad480f5a3e7b7f6d32e9ea87a4b8b4940614991d8762f4b8a319f9d04fef8db4207bb427450f033cdade9495ef5b87dde91e26ded257c98e3544529cef languageName: node linkType: hard @@ -35693,10 +35700,10 @@ __metadata: languageName: node linkType: hard -"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0": - version: 1.4.0 - resolution: "outvariant@npm:1.4.0" - checksum: ec32dfc315c464bb6e4906b2f450d259ce0b86caf70b70b249054359d9af21a7fccf53a8b6aa232f8d718449e31c1cfa594e6ebffaafe7bf908b502495256d7b +"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0, outvariant@npm:^1.4.2": + version: 1.4.2 + resolution: "outvariant@npm:1.4.2" + checksum: 5d9e2b3edb1cc8be9cbfc1c8c97e8b05137c4384bbfc56e0a465de26c5d2f023e65732ddcda9d46599b06d667fbc0de32c30d2ecd11f6f3f43bcf8ce0d320918 languageName: node linkType: hard @@ -41215,7 +41222,7 @@ __metadata: languageName: node linkType: hard -"strict-event-emitter@npm:^0.5.0, strict-event-emitter@npm:^0.5.1": +"strict-event-emitter@npm:^0.5.1": version: 0.5.1 resolution: "strict-event-emitter@npm:0.5.1" checksum: 350480431bc1c28fdb601ef4976c2f8155fc364b4740f9692dd03e5bdd48aafc99a5e021fe655fbd986d0b803e9f3fc5c4b018b35cb838c4690d60f2a26f1cf3 @@ -42694,6 +42701,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^4.9.0": + version: 4.9.0 + resolution: "type-fest@npm:4.9.0" + checksum: 73383de23237b399a70397a53101152548846d919aebcc7d8733000c6c354dc2632fe37c4a70b8571b79fdbfa099e2d8304c5ac56b3254780acff93e4c7a797f + languageName: node + linkType: hard + "type-is@npm:^1.6.4, type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18"