From 776180b7403de070415291362ceaea77a673148f Mon Sep 17 00:00:00 2001 From: Praveen Ranjan Keshri Date: Thu, 25 Nov 2021 01:59:54 +0530 Subject: [PATCH 001/189] Fixed bug in backend-common to allow passing of remote option in order to enable passing remote url in --config option. The remote option should be passed along with reloadIntervalSeconds from packages/backend/src/index.ts (Updated the file as well) Signed-off-by: Praveen Ranjan Keshri --- .changeset/brave-impalas-switch.md | 24 ++++++++++++++++++++++++ docs/conf/writing.md | 22 ++++++++++++++++++++-- packages/backend-common/src/config.ts | 3 +++ packages/backend/src/index.ts | 4 ++++ packages/config-loader/src/loader.ts | 14 +++++++++++--- 5 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 .changeset/brave-impalas-switch.md diff --git a/.changeset/brave-impalas-switch.md b/.changeset/brave-impalas-switch.md new file mode 100644 index 0000000000..058e2dbf8d --- /dev/null +++ b/.changeset/brave-impalas-switch.md @@ -0,0 +1,24 @@ +--- +'example-backend': patch +'@backstage/backend-common': patch +'@backstage/config-loader': patch +--- + +Fixed bug in backend-common to allow passing of remote option in order to enable passing remote url in --config option. The remote option should be passed along with reloadIntervalSeconds from packages/backend/src/index.ts (Updated the file as well) + +These changes are needed in `packages/backend/src/index.ts` if remote urls are desired to be passed in --config option and read and watch remote files for config. + +```diff +@@ -86,7 +86,11 @@ async function main() { + const config = await loadBackendConfig({ + argv: process.argv, + logger, ++ remote: { ++ reloadIntervalSeconds: 60 * 60 * 12 // Check remote config changes every 12 hours. Change to your desired interval in seconds ++ } + }); ++ + const createEnv = makeCreateEnv(config); + + const healthcheckEnv = useHotMemoize(module, () => createEnv('healthcheck')); +``` diff --git a/docs/conf/writing.md b/docs/conf/writing.md index 7945d6c980..afd86955fa 100644 --- a/docs/conf/writing.md +++ b/docs/conf/writing.md @@ -67,7 +67,7 @@ production build. ## Configuration Files -It is possible to have multiple configuration files (bundled and/or remote), +It is possible to have multiple configuration files (bundled and/or remote\*), both to support different environments, but also to define configuration that is local to specific packages. The configuration files to load are selected using a `--config ` flag, and it is possible to load any number of @@ -75,7 +75,25 @@ files. Paths are relative to the working directory of the executed process, for example `package/backend`. This means that to select a config file in the repo root when running the backend, you would use `--config ../../my-config.yaml`, and for config file on a config server you would use -`--config https://some.domain.io/app-config.yaml` +`--config https://some.domain.io/app-config.yaml`
+ +**\*Note**: In order to use remote urls, ensure that the option 'remote' is +passed in `loadBackendConfig(...)` call (See below) inside +`packages/backend/src/index.ts`, with the option of +reloadIntervalSeconds(required) as given below. This will allow the usage of +remote configs and also, will ensure that this config is checked for any changes +every 12 hours. (This can be any desired value in seconds, here 60 _ 60 _ 12 = +12 hours!): + +```ts +const config = await loadBackendConfig({ + argv: process.argv, + logger, + remote: { + reloadIntervalSeconds: 60 * 60 * 12, // Check remote config changes every 12 hours. Change to your desired interval in seconds + }, +}); +``` If no `config` flags are specified, the default behavior is to load `app-config.yaml` and, if it exists, `app-config.local.yaml` from the repo root. diff --git a/packages/backend-common/src/config.ts b/packages/backend-common/src/config.ts index 941ad26e65..1ede91dbe5 100644 --- a/packages/backend-common/src/config.ts +++ b/packages/backend-common/src/config.ts @@ -23,6 +23,7 @@ import { loadConfig, ConfigSchema, ConfigTarget, + LoadConfigOptionsRemote, } from '@backstage/config-loader'; import { AppConfig, Config, ConfigReader } from '@backstage/config'; import { JsonValue } from '@backstage/types'; @@ -178,6 +179,7 @@ let currentCancelFunc: () => void; export async function loadBackendConfig(options: { logger: Logger; // process.argv or any other overrides + remote?: LoadConfigOptionsRemote; argv: string[]; }): Promise { const args = parseArgs(options.argv); @@ -204,6 +206,7 @@ export async function loadBackendConfig(options: { configRoot: paths.targetRoot, configPaths: [], configTargets: configTargets, + remote: options.remote, watch: { onChange(newConfigs) { options.logger.info( diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index f978e84da9..ea1d643187 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -86,7 +86,11 @@ async function main() { const config = await loadBackendConfig({ argv: process.argv, logger, + remote: { + reloadIntervalSeconds: 60 * 60 * 12, // Check remote config changes every 12 hours. Change to your desired interval in seconds + }, }); + const createEnv = makeCreateEnv(config); const healthcheckEnv = useHotMemoize(module, () => createEnv('healthcheck')); diff --git a/packages/config-loader/src/loader.ts b/packages/config-loader/src/loader.ts index 6a92ed519d..388017318f 100644 --- a/packages/config-loader/src/loader.ts +++ b/packages/config-loader/src/loader.ts @@ -45,7 +45,7 @@ export type LoadConfigOptionsWatch = { export type LoadConfigOptionsRemote = { /** - * An optional remote config reloading period, in seconds + * A remote config reloading period, in seconds */ reloadIntervalSeconds: number; }; @@ -126,8 +126,16 @@ export async function loadConfig( .filter((e): e is { url: string } => e.hasOwnProperty('url')) .map(configTarget => configTarget.url); - if (remote === undefined && configUrls.length > 0) { - throw new Error(`Remote config detected but this feature is turned off`); + if (remote === undefined) { + if (configUrls.length > 0) { + throw new Error( + `Remote config detected but this feature is turned off. Please enable by passing remote option in loadBackendConfig() call inside packages/backend/src/index.ts. See https://backstage.io/docs/conf/writing#configuration-files for detailed info.`, + ); + } + } else if (remote.reloadIntervalSeconds === undefined) { + throw new Error( + `Remote config must be contain reloadIntervalSeconds: value`, + ); } // If no paths are provided, we default to reading From 8183a407b07e79d7dd4595a14d4d8f89bae5bd63 Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Mon, 29 Nov 2021 12:15:02 -0500 Subject: [PATCH 002/189] Adding changes for creating action for gitlab MR request during component registration similar to github Signed-off-by: Balasundaram --- .../actions/builtin/createBuiltinActions.ts | 4 + .../builtin/publish/gitlabMergeRequest.ts | 174 ++++++++++++++++++ .../actions/builtin/publish/index.ts | 1 + 3 files changed, 179 insertions(+) create mode 100644 plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index d38dfe3cdc..2d916af77e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -36,6 +36,7 @@ import { createPublishGithubAction, createPublishGithubPullRequestAction, createPublishGitlabAction, + createPublishGitlabMergeRequestAction, } from './publish'; import { createGithubActionsDispatchAction, @@ -77,6 +78,9 @@ export const createBuiltinActions = (options: { integrations, config, }), + createPublishGitlabMergeRequestAction({ + integrations, + }), createPublishBitbucketAction({ integrations, config, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts new file mode 100644 index 0000000000..6ff10deb96 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -0,0 +1,174 @@ +/* + * 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 { createTemplateAction } from '../../createTemplateAction'; +import { readFile } from 'fs-extra'; +import { Gitlab } from '@gitbeaker/node'; +import path from 'path'; +import globby from 'globby'; +import { CommitAction } from '@gitbeaker/core/dist/types/services/Commits'; +import { CreateMergeRequestOptions } from '@gitbeaker/core/dist/types/services/MergeRequests'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { InputError } from '@backstage/errors'; +import { parseRepoUrl } from './util'; + +export type GitlabMergeRequestActionInput = { + projectid: string; + repoUrl: string; + title: string; + description: string; + destinationBranch: string; + targetPath: string; + }; + +export const createPublishGitlabMergeRequestAction = (options: { + integrations: ScmIntegrationRegistry; + }) => { + const { integrations } = options; + + return createTemplateAction({ + id: 'publish:gitlab-merge-request', + schema: { + input: { + required: ['projectid', 'repoUrl', 'targetPath'], + type: 'object', + properties: { + repoUrl: { + type: 'string', + title: 'Repository Location', + description: `Accepts the format 'gitlab.com/group_name/project_name' where 'project_name' is the repository name and 'group_name' is a group or username`, + }, + projectid: { + type: 'string', + title: 'projectid', + description: 'Project ID of the Gitlab Project', + }, + title: { + type: 'string', + title: 'Merge Request Name', + description: 'The name for the merge request', + }, + description: { + type: 'string', + title: 'Merge Request Description', + description: 'The description of the merge request', + }, + destinationBranch: { + type: 'string', + title: 'Destination Branch name', + description: 'The description of the merge request', + }, + targetPath: { + type: 'string', + title: 'Repository Subdirectory', + description: 'Subdirectory of repository to apply changes to', + } + }, + }, + output: { + type: 'object', + properties: { + projectid : { + title: 'Gitlab Project id', + type: 'string', + }, + mergeRequestURL: { + title: 'MergeRequest(MR) URL', + type: 'string', + description: 'Link to the merge request in GitLab', + }, + }, + }, + }, + async handler(ctx) { + const repoUrl = ctx.input.repoUrl; + const { host } = parseRepoUrl(repoUrl, integrations); + const integrationConfig = integrations.gitlab.byHost(host); + + let actions: CommitAction[] = []; + const formatedTimestamp = ()=> { + const d = new Date() + const date = d.toISOString().split('T')[0]; + const time = d.toTimeString().split(' ')[0].replace(/:/g, "_"); + return `${date}_${time}` + } + const destinationBranch = ctx.input.destinationBranch? ctx.input.destinationBranch + formatedTimestamp(): `backstage_${formatedTimestamp()}`; + + if (!integrationConfig) { + throw new InputError( + `No matching integration configuration for host ${host}, please check your integrations config`, + ); + } + + if (!integrationConfig.config.token) { + throw new InputError(`No token available for host ${host}`); + } + + const api = new Gitlab({ + host: integrationConfig.config.baseUrl, + token: integrationConfig.config.token, + }); + + const fileRoot = ctx.workspacePath; + const localFilePaths = await globby([`${ctx.input.targetPath}'/**'`], { + cwd: fileRoot, + gitignore: true, + dot: true, + }); + + const fileContents = await Promise.all( + localFilePaths.map(p => readFile(path.resolve(fileRoot, p))), + ); + + const repoFilePaths = localFilePaths.map(repoFilePath => { + return repoFilePath; + }); + + for(let i=0; i { + return projectJSON?.default_branch; + }); + + try { + await api.Branches.create(ctx.input.projectid, destinationBranch, defaultBranch).then((branchResponse) => { + return branchResponse; + }); + } catch(e) { + throw new InputError(`The branch creation failed ` + e); + } + + try { + await api.Commits.create(ctx.input.projectid, destinationBranch, ctx.input.title, actions); + } catch(e) { + throw new InputError(`Committing the changes to ` + destinationBranch + ` failed ` + e); + } + + try { + let mergeRequestUrl: any = await api.MergeRequests.create(ctx.input.projectid, destinationBranch, defaultBranch, ctx.input.title, { description: ctx.input.description }).then((mergeRequest) => { + return mergeRequest.web_url + }); + ctx.output('projectid', ctx.input.projectid); + ctx.output('mergeRequestUrl', mergeRequestUrl); + } + catch(e) { + throw new InputError(`Merge request creation failed` + e); + } + }, + }); +}; \ No newline at end of file diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts index a292438d3a..75af6e190f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts @@ -20,3 +20,4 @@ export { createPublishFileAction } from './file'; export { createPublishGithubAction } from './github'; export { createPublishGithubPullRequestAction } from './githubPullRequest'; export { createPublishGitlabAction } from './gitlab'; +export { createPublishGitlabMergeRequestAction } from './gitlabMergeRequest'; \ No newline at end of file From 86ac8d6cdb6fe45b9f2f434bedcc96863288b014 Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Mon, 29 Nov 2021 13:43:47 -0500 Subject: [PATCH 003/189] Adding prettier changes Signed-off-by: Balasundaram --- .../builtin/publish/gitlabMergeRequest.ts | 289 ++++++++++-------- 1 file changed, 156 insertions(+), 133 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts index 6ff10deb96..19aeabefdd 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -19,156 +19,179 @@ import { Gitlab } from '@gitbeaker/node'; import path from 'path'; import globby from 'globby'; import { CommitAction } from '@gitbeaker/core/dist/types/services/Commits'; -import { CreateMergeRequestOptions } from '@gitbeaker/core/dist/types/services/MergeRequests'; +import { CreateMergeRequestOptions } from '@gitbeaker/core/dist/types/services/MergeRequests'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { InputError } from '@backstage/errors'; import { parseRepoUrl } from './util'; export type GitlabMergeRequestActionInput = { - projectid: string; - repoUrl: string; - title: string; - description: string; - destinationBranch: string; - targetPath: string; - }; + projectid: string; + repoUrl: string; + title: string; + description: string; + destinationBranch: string; + targetPath: string; +}; export const createPublishGitlabMergeRequestAction = (options: { - integrations: ScmIntegrationRegistry; - }) => { - const { integrations } = options; + integrations: ScmIntegrationRegistry; +}) => { + const { integrations } = options; - return createTemplateAction({ - id: 'publish:gitlab-merge-request', - schema: { - input: { - required: ['projectid', 'repoUrl', 'targetPath'], - type: 'object', - properties: { - repoUrl: { - type: 'string', - title: 'Repository Location', - description: `Accepts the format 'gitlab.com/group_name/project_name' where 'project_name' is the repository name and 'group_name' is a group or username`, - }, - projectid: { - type: 'string', - title: 'projectid', - description: 'Project ID of the Gitlab Project', - }, - title: { - type: 'string', - title: 'Merge Request Name', - description: 'The name for the merge request', - }, - description: { - type: 'string', - title: 'Merge Request Description', - description: 'The description of the merge request', - }, - destinationBranch: { - type: 'string', - title: 'Destination Branch name', - description: 'The description of the merge request', - }, - targetPath: { - type: 'string', - title: 'Repository Subdirectory', - description: 'Subdirectory of repository to apply changes to', - } - }, - }, - output: { - type: 'object', - properties: { - projectid : { - title: 'Gitlab Project id', - type: 'string', - }, - mergeRequestURL: { - title: 'MergeRequest(MR) URL', - type: 'string', - description: 'Link to the merge request in GitLab', - }, - }, - }, - }, - async handler(ctx) { - const repoUrl = ctx.input.repoUrl; - const { host } = parseRepoUrl(repoUrl, integrations); - const integrationConfig = integrations.gitlab.byHost(host); + return createTemplateAction({ + id: 'publish:gitlab-merge-request', + schema: { + input: { + required: ['projectid', 'repoUrl', 'targetPath'], + type: 'object', + properties: { + repoUrl: { + type: 'string', + title: 'Repository Location', + description: `Accepts the format 'gitlab.com/group_name/project_name' where 'project_name' is the repository name and 'group_name' is a group or username`, + }, + projectid: { + type: 'string', + title: 'projectid', + description: 'Project ID of the Gitlab Project', + }, + title: { + type: 'string', + title: 'Merge Request Name', + description: 'The name for the merge request', + }, + description: { + type: 'string', + title: 'Merge Request Description', + description: 'The description of the merge request', + }, + destinationBranch: { + type: 'string', + title: 'Destination Branch name', + description: 'The description of the merge request', + }, + targetPath: { + type: 'string', + title: 'Repository Subdirectory', + description: 'Subdirectory of repository to apply changes to', + }, + }, + }, + output: { + type: 'object', + properties: { + projectid: { + title: 'Gitlab Project id', + type: 'string', + }, + mergeRequestURL: { + title: 'MergeRequest(MR) URL', + type: 'string', + description: 'Link to the merge request in GitLab', + }, + }, + }, + }, + async handler(ctx) { + const repoUrl = ctx.input.repoUrl; + const { host } = parseRepoUrl(repoUrl, integrations); + const integrationConfig = integrations.gitlab.byHost(host); - let actions: CommitAction[] = []; - const formatedTimestamp = ()=> { - const d = new Date() - const date = d.toISOString().split('T')[0]; - const time = d.toTimeString().split(' ')[0].replace(/:/g, "_"); - return `${date}_${time}` - } - const destinationBranch = ctx.input.destinationBranch? ctx.input.destinationBranch + formatedTimestamp(): `backstage_${formatedTimestamp()}`; + const actions: CommitAction[] = []; + const formatedTimestamp = () => { + const d = new Date(); + const date = d.toISOString().split('T')[0]; + const time = d.toTimeString().split(' ')[0].replace(/:/g, '_'); + return `${date}_${time}`; + }; + const destinationBranch = ctx.input.destinationBranch + ? ctx.input.destinationBranch + formatedTimestamp() + : `backstage_${formatedTimestamp()}`; - if (!integrationConfig) { - throw new InputError( - `No matching integration configuration for host ${host}, please check your integrations config`, - ); - } + if (!integrationConfig) { + throw new InputError( + `No matching integration configuration for host ${host}, please check your integrations config`, + ); + } - if (!integrationConfig.config.token) { - throw new InputError(`No token available for host ${host}`); - } + if (!integrationConfig.config.token) { + throw new InputError(`No token available for host ${host}`); + } - const api = new Gitlab({ - host: integrationConfig.config.baseUrl, - token: integrationConfig.config.token, - }); + const api = new Gitlab({ + host: integrationConfig.config.baseUrl, + token: integrationConfig.config.token, + }); - const fileRoot = ctx.workspacePath; - const localFilePaths = await globby([`${ctx.input.targetPath}'/**'`], { - cwd: fileRoot, - gitignore: true, - dot: true, - }); + const fileRoot = ctx.workspacePath; + const localFilePaths = await globby([`${ctx.input.targetPath}'/**'`], { + cwd: fileRoot, + gitignore: true, + dot: true, + }); - const fileContents = await Promise.all( - localFilePaths.map(p => readFile(path.resolve(fileRoot, p))), - ); + const fileContents = await Promise.all( + localFilePaths.map(p => readFile(path.resolve(fileRoot, p))), + ); - const repoFilePaths = localFilePaths.map(repoFilePath => { - return repoFilePath; - }); + const repoFilePaths = localFilePaths.map(repoFilePath => { + return repoFilePath; + }); - for(let i=0; i { + return projectJSON?.default_branch; + }); - const defaultBranch: any = await api.Projects.show(ctx.input.projectid).then((projectJSON) => { - return projectJSON?.default_branch; - }); + try { + await api.Branches.create( + ctx.input.projectid, + destinationBranch, + defaultBranch, + ).then(branchResponse => { + return branchResponse; + }); + } catch (e) { + throw new InputError(`The branch creation failed ${e}`); + } - try { - await api.Branches.create(ctx.input.projectid, destinationBranch, defaultBranch).then((branchResponse) => { - return branchResponse; - }); - } catch(e) { - throw new InputError(`The branch creation failed ` + e); - } + try { + await api.Commits.create( + ctx.input.projectid, + destinationBranch, + ctx.input.title, + actions, + ); + } catch (e) { + throw new InputError( + `Committing the changes to ${destinationBranch} failed ${e}`, + ); + } - try { - await api.Commits.create(ctx.input.projectid, destinationBranch, ctx.input.title, actions); - } catch(e) { - throw new InputError(`Committing the changes to ` + destinationBranch + ` failed ` + e); - } - - try { - let mergeRequestUrl: any = await api.MergeRequests.create(ctx.input.projectid, destinationBranch, defaultBranch, ctx.input.title, { description: ctx.input.description }).then((mergeRequest) => { - return mergeRequest.web_url - }); - ctx.output('projectid', ctx.input.projectid); - ctx.output('mergeRequestUrl', mergeRequestUrl); - } - catch(e) { - throw new InputError(`Merge request creation failed` + e); - } - }, - }); -}; \ No newline at end of file + try { + const mergeRequestUrl: any = await api.MergeRequests.create( + ctx.input.projectid, + destinationBranch, + defaultBranch, + ctx.input.title, + { description: ctx.input.description }, + ).then(mergeRequest => { + return mergeRequest.web_url; + }); + ctx.output('projectid', ctx.input.projectid); + ctx.output('mergeRequestUrl', mergeRequestUrl); + } catch (e) { + throw new InputError(`Merge request creation failed${e}`); + } + }, + }); +}; From d9d2ff253d40098c8230d0509e67185a6a5f1f0e Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Tue, 30 Nov 2021 06:44:27 -0500 Subject: [PATCH 004/189] Adding prettier for index.ts Signed-off-by: Balasundaram --- .../src/scaffolder/actions/builtin/publish/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts index 75af6e190f..c42b04e55e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/index.ts @@ -20,4 +20,4 @@ export { createPublishFileAction } from './file'; export { createPublishGithubAction } from './github'; export { createPublishGithubPullRequestAction } from './githubPullRequest'; export { createPublishGitlabAction } from './gitlab'; -export { createPublishGitlabMergeRequestAction } from './gitlabMergeRequest'; \ No newline at end of file +export { createPublishGitlabMergeRequestAction } from './gitlabMergeRequest'; From 89599a43c628b6b7004fe7aa8301b40f2597b744 Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Wed, 1 Dec 2021 12:50:16 -0500 Subject: [PATCH 005/189] Adding changes for PR review comments Signed-off-by: Balasundaram --- .../builtin/publish/gitlabMergeRequest.ts | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts index 19aeabefdd..0928ff3b6d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -16,20 +16,19 @@ import { createTemplateAction } from '../../createTemplateAction'; import { readFile } from 'fs-extra'; import { Gitlab } from '@gitbeaker/node'; -import path from 'path'; import globby from 'globby'; import { CommitAction } from '@gitbeaker/core/dist/types/services/Commits'; -import { CreateMergeRequestOptions } from '@gitbeaker/core/dist/types/services/MergeRequests'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { InputError } from '@backstage/errors'; import { parseRepoUrl } from './util'; +import { resolveSafeChildPath } from '@backstage/backend-common'; export type GitlabMergeRequestActionInput = { projectid: string; repoUrl: string; title: string; description: string; - destinationBranch: string; + branchName: string; targetPath: string; }; @@ -39,10 +38,10 @@ export const createPublishGitlabMergeRequestAction = (options: { const { integrations } = options; return createTemplateAction({ - id: 'publish:gitlab-merge-request', + id: 'publish:gitlab:merge-request', schema: { input: { - required: ['projectid', 'repoUrl', 'targetPath'], + required: ['projectid', 'repoUrl', 'targetPath', 'branchName'], type: 'object', properties: { repoUrl: { @@ -65,7 +64,7 @@ export const createPublishGitlabMergeRequestAction = (options: { title: 'Merge Request Description', description: 'The description of the merge request', }, - destinationBranch: { + branchName: { type: 'string', title: 'Destination Branch name', description: 'The description of the merge request', @@ -98,15 +97,8 @@ export const createPublishGitlabMergeRequestAction = (options: { const integrationConfig = integrations.gitlab.byHost(host); const actions: CommitAction[] = []; - const formatedTimestamp = () => { - const d = new Date(); - const date = d.toISOString().split('T')[0]; - const time = d.toTimeString().split(' ')[0].replace(/:/g, '_'); - return `${date}_${time}`; - }; - const destinationBranch = ctx.input.destinationBranch - ? ctx.input.destinationBranch + formatedTimestamp() - : `backstage_${formatedTimestamp()}`; + + const destinationBranch = ctx.input.branchName; if (!integrationConfig) { throw new InputError( @@ -124,14 +116,14 @@ export const createPublishGitlabMergeRequestAction = (options: { }); const fileRoot = ctx.workspacePath; - const localFilePaths = await globby([`${ctx.input.targetPath}'/**'`], { + const localFilePaths = await globby([`${ctx.input.targetPath}/**`], { cwd: fileRoot, gitignore: true, dot: true, }); const fileContents = await Promise.all( - localFilePaths.map(p => readFile(path.resolve(fileRoot, p))), + localFilePaths.map(p => readFile(resolveSafeChildPath(fileRoot, p))), ); const repoFilePaths = localFilePaths.map(repoFilePath => { @@ -146,11 +138,9 @@ export const createPublishGitlabMergeRequestAction = (options: { }); } - const defaultBranch: any = await api.Projects.show( + const { default_branch: defaultBranch }: any = await api.Projects.show( ctx.input.projectid, - ).then(projectJSON => { - return projectJSON?.default_branch; - }); + ); try { await api.Branches.create( From d76ee63f8533ab0eecc129070b1175f4cb914d51 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Thu, 2 Dec 2021 11:37:43 +0000 Subject: [PATCH 006/189] feat: Created types for filters. Signed-off-by: Marley Powell --- .../PullRequestsPage/lib/filters/types.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts new file mode 100644 index 0000000000..1e6d9fe30e --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export enum FilterType { + All = 'All', + AssignedToUser = 'AssignedToUser', + CreatedByUser = 'CreatedByUser', + AssignedToCurrentUser = 'AssignedToCurrentUser', + CreatedByCurrentUser = 'CreatedByCurrentUser', + AssignedToTeam = 'AssignedToTeam', + CreatedByTeam = 'CreatedByTeam', + AssignedToTeams = 'AssignedToTeams', + CreatedByTeams = 'CreatedByTeams', + AssignedToCurrentUsersTeams = 'AssignedToCurrentUsersTeams', + CreatedByCurrentUsersTeams = 'CreatedByCurrentUsersTeams', +} + +export const FilterTypes = [ + FilterType.All, + FilterType.AssignedToUser, + FilterType.CreatedByUser, + FilterType.AssignedToCurrentUser, + FilterType.CreatedByCurrentUser, + FilterType.AssignedToTeam, + FilterType.CreatedByTeam, + FilterType.AssignedToTeams, + FilterType.CreatedByTeams, + FilterType.CreatedByCurrentUsersTeams, +] as const; + +export type BaseFilter = { + type: FilterType; +}; From 256d4983013ac3ada51ab03c6b9312e01ec20a2a Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Thu, 2 Dec 2021 11:38:14 +0000 Subject: [PATCH 007/189] feat: Created `allFilter`. Signed-off-by: Marley Powell --- .../PullRequestsPage/lib/filters/allFilter.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts new file mode 100644 index 0000000000..0ec7fc36af --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts @@ -0,0 +1,28 @@ +/* + * 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 { BaseFilter, FilterType } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { PullRequestFilter } from '../types'; + +export type AllFilter = BaseFilter & { + type: FilterType.All; +}; + +export function createAllFilter(): PullRequestFilter { + return (_pullRequest: DashboardPullRequest): boolean => true; +} From 8e2d3c9d548e1aada4decdb03fce784f7147fff5 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Thu, 2 Dec 2021 11:55:43 +0000 Subject: [PATCH 008/189] feat: Created `assignedToTeamFilter`, `assignedToTeamsFilter` and `assignedToUserFilter`. Signed-off-by: Marley Powell --- .../lib/filters/assignedToTeamFilter.ts | 40 ++++++++++++++ .../lib/filters/assignedToTeamsFilter.ts | 52 +++++++++++++++++++ .../lib/filters/assignedToUserFilter.ts | 51 ++++++++++++++++++ .../PullRequestsPage/lib/filters/types.ts | 21 +++++--- 4 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts new file mode 100644 index 0000000000..a15895e08f --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts @@ -0,0 +1,40 @@ +/* + * 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 { BaseFilter, FilterType } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { PullRequestFilter } from '../types'; +import { stringArrayHas } from '../utils'; + +export type AssignedToTeamFilter = BaseFilter & { + type: FilterType.AssignedToTeam; + teamId: string; +}; + +export function createAssignedToTeamFilter( + filter: AssignedToTeamFilter, +): PullRequestFilter { + return (pullRequest: DashboardPullRequest): boolean => { + const reviewerIds = pullRequest.reviewers?.map(reviewer => reviewer.id); + + if (!reviewerIds) { + return false; + } + + return stringArrayHas(reviewerIds, filter.teamId, true); + }; +} diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts new file mode 100644 index 0000000000..0cc347e0ea --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts @@ -0,0 +1,52 @@ +/* + * 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 { BaseFilter, FilterType } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { PullRequestFilter } from '../types'; +import { createAssignedToTeamFilter } from './assignedToTeamFilter'; + +export type AssignedToTeamsFilter = BaseFilter & + ( + | { + type: FilterType.AssignedToTeams; + teamIds: string[]; + } + | { + type: FilterType.AssignedToCurrentUsersTeams; + teamIds?: string[]; + } + ); + +export function createAssignedToTeamsFilter( + filter: AssignedToTeamsFilter, +): PullRequestFilter { + const teamIds = filter.teamIds; + + return (pullRequest: DashboardPullRequest): boolean => { + if (!teamIds) { + return false; + } + + return teamIds.some(teamId => { + return createAssignedToTeamFilter({ + type: FilterType.AssignedToTeam, + teamId, + })(pullRequest); + }); + }; +} diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts new file mode 100644 index 0000000000..9e6cbe4c38 --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts @@ -0,0 +1,51 @@ +/* + * 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 { BaseFilter, FilterType } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { PullRequestFilter } from '../types'; +import { stringArrayHas } from '../utils'; + +export type AssignedToUserFilter = BaseFilter & + ( + | { + type: FilterType.AssignedToUser; + email: string; + } + | { + type: FilterType.AssignedToCurrentUser; + email?: string; + } + ); + +export function createAssignedToUserFilter( + filter: AssignedToUserFilter, +): PullRequestFilter { + const email = filter.email; + + return (pullRequest: DashboardPullRequest): boolean => { + const uniqueNames = pullRequest.reviewers?.map( + reviewer => reviewer.uniqueName, + ); + + if (!email || !uniqueNames) { + return false; + } + + return stringArrayHas(uniqueNames, email, true); + }; +} diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts index 1e6d9fe30e..37870703af 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts @@ -16,27 +16,34 @@ export enum FilterType { All = 'All', + + // Assigned To AssignedToUser = 'AssignedToUser', - CreatedByUser = 'CreatedByUser', AssignedToCurrentUser = 'AssignedToCurrentUser', - CreatedByCurrentUser = 'CreatedByCurrentUser', AssignedToTeam = 'AssignedToTeam', - CreatedByTeam = 'CreatedByTeam', AssignedToTeams = 'AssignedToTeams', - CreatedByTeams = 'CreatedByTeams', AssignedToCurrentUsersTeams = 'AssignedToCurrentUsersTeams', + + // Created By + CreatedByUser = 'CreatedByUser', + CreatedByCurrentUser = 'CreatedByCurrentUser', + CreatedByTeam = 'CreatedByTeam', + CreatedByTeams = 'CreatedByTeams', CreatedByCurrentUsersTeams = 'CreatedByCurrentUsersTeams', } export const FilterTypes = [ FilterType.All, + FilterType.AssignedToUser, - FilterType.CreatedByUser, FilterType.AssignedToCurrentUser, - FilterType.CreatedByCurrentUser, FilterType.AssignedToTeam, - FilterType.CreatedByTeam, FilterType.AssignedToTeams, + FilterType.AssignedToCurrentUsersTeams, + + FilterType.CreatedByUser, + FilterType.CreatedByCurrentUser, + FilterType.CreatedByTeam, FilterType.CreatedByTeams, FilterType.CreatedByCurrentUsersTeams, ] as const; From 50b3d1737dab6b17a0890d2144c991dc97758f39 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Thu, 2 Dec 2021 12:14:42 +0000 Subject: [PATCH 009/189] feat: Created `createdByTeamFilter`, `createdByTeamsFilter` and `createdByUserFilter`. Signed-off-by: Marley Powell --- .../lib/filters/createdByTeamFilter.ts | 43 ++++++++++++ .../lib/filters/createdByTeamsFilter.ts | 66 +++++++++++++++++++ .../lib/filters/createdByUserFilter.ts | 49 ++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts new file mode 100644 index 0000000000..e0fca3a75f --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts @@ -0,0 +1,43 @@ +/* + * 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 { BaseFilter, FilterType } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { PullRequestFilter } from '../types'; +import { stringArrayHas } from '../utils'; + +export type CreatedByTeamFilter = BaseFilter & + ({ + type: FilterType.CreatedByTeam; + } & ({ teamId: string } | { teamName: string })); + +export function createCreatedByTeamFilter( + filter: CreatedByTeamFilter, +): PullRequestFilter { + return (pullRequest: DashboardPullRequest): boolean => { + const [createdByTeams, team] = + 'teamId' in filter + ? [pullRequest.createdBy?.teamIds, filter.teamId] + : [pullRequest.createdBy?.teamNames, filter.teamName]; + + if (!createdByTeams) { + return false; + } + + return stringArrayHas(createdByTeams, team, true); + }; +} diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts new file mode 100644 index 0000000000..ff10deaa14 --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts @@ -0,0 +1,66 @@ +/* + * 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 { BaseFilter, FilterType } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { PullRequestFilter } from '../types'; +import { createCreatedByTeamFilter } from './createdByTeamFilter'; + +export type CreatedByTeamsFilter = BaseFilter & + ( + | ({ + type: FilterType.CreatedByTeams; + } & ({ teamIds: string[] } | { teamNames: string[] })) + | { + type: FilterType.CreatedByCurrentUsersTeams; + teamIds?: string[]; + } + ); + +export function createCreatedByTeamsFilter( + filter: CreatedByTeamsFilter, +): PullRequestFilter { + return (pullRequest: DashboardPullRequest): boolean => { + if ('teamNames' in filter) { + const teamNames = filter.teamNames; + + if (!teamNames) { + return false; + } + + return teamNames.some(teamName => { + return createCreatedByTeamFilter({ + type: FilterType.CreatedByTeam, + teamName, + })(pullRequest); + }); + } + + const teamIds = filter.teamIds; + + if (!teamIds) { + return false; + } + + return teamIds.some(teamId => { + return createCreatedByTeamFilter({ + type: FilterType.CreatedByTeam, + teamId, + })(pullRequest); + }); + }; +} diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts new file mode 100644 index 0000000000..19c5cbc1b1 --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts @@ -0,0 +1,49 @@ +/* + * 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 { BaseFilter, FilterType } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { PullRequestFilter } from '../types'; +import { equalsIgnoreCase } from '../utils'; + +export type CreatedByUserFilter = BaseFilter & + ( + | { + type: FilterType.CreatedByUser; + email: string; + } + | { + type: FilterType.CreatedByCurrentUser; + email?: string; + } + ); + +export function createCreatedByUserFilter( + filter: CreatedByUserFilter, +): PullRequestFilter { + const email = filter.email; + + return (pullRequest: DashboardPullRequest): boolean => { + const uniqueName = pullRequest.createdBy?.uniqueName; + + if (!email || !uniqueName) { + return false; + } + + return equalsIgnoreCase(email, uniqueName); + }; +} From 2a02690b1154a6484d275147b2f229a9ee2ac4b4 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Thu, 2 Dec 2021 13:34:14 +0000 Subject: [PATCH 010/189] refactor: Moved around filter types. Signed-off-by: Marley Powell --- .../lib/filters/assignedToTeamFilter.ts | 3 +- .../lib/filters/assignedToTeamsFilter.ts | 3 +- .../lib/filters/assignedToUserFilter.ts | 3 +- .../lib/filters/createFilter.ts | 71 +++++++++++++++++++ .../lib/filters/createdByTeamFilter.ts | 3 +- .../lib/filters/createdByTeamsFilter.ts | 3 +- .../lib/filters/createdByUserFilter.ts | 3 +- .../PullRequestsPage/lib/filters/index.ts | 19 +++++ .../PullRequestsPage/lib/filters/types.ts | 20 ++++++ .../components/PullRequestsPage/lib/types.ts | 21 +++--- 10 files changed, 127 insertions(+), 22 deletions(-) create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.ts create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts index a15895e08f..3c48f04541 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { BaseFilter, FilterType } from './types'; +import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { PullRequestFilter } from '../types'; import { stringArrayHas } from '../utils'; export type AssignedToTeamFilter = BaseFilter & { diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts index 0cc347e0ea..ce5e5bcc11 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamsFilter.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { BaseFilter, FilterType } from './types'; +import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { PullRequestFilter } from '../types'; import { createAssignedToTeamFilter } from './assignedToTeamFilter'; export type AssignedToTeamsFilter = BaseFilter & diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts index 9e6cbe4c38..128c9103ab 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { BaseFilter, FilterType } from './types'; +import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { PullRequestFilter } from '../types'; import { stringArrayHas } from '../utils'; export type AssignedToUserFilter = BaseFilter & diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.ts new file mode 100644 index 0000000000..492d0539c5 --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.ts @@ -0,0 +1,71 @@ +/* + * 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 { Filter, FilterType, PullRequestFilter } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { createAllFilter } from './allFilter'; +import { createAssignedToTeamFilter } from './assignedToTeamFilter'; +import { createAssignedToTeamsFilter } from './assignedToTeamsFilter'; +import { createAssignedToUserFilter } from './assignedToUserFilter'; +import { createCreatedByTeamFilter } from './createdByTeamFilter'; +import { createCreatedByTeamsFilter } from './createdByTeamsFilter'; +import { createCreatedByUserFilter } from './createdByUserFilter'; + +export function createFilter(filters: Filter | Filter[]): PullRequestFilter { + const mapFilter = (filter: Filter): PullRequestFilter => { + switch (filter.type) { + case FilterType.AssignedToUser: + case FilterType.AssignedToCurrentUser: + return createAssignedToUserFilter(filter); + + case FilterType.CreatedByUser: + case FilterType.CreatedByCurrentUser: + return createCreatedByUserFilter(filter); + + case FilterType.AssignedToTeam: + return createAssignedToTeamFilter(filter); + + case FilterType.CreatedByTeam: + return createCreatedByTeamFilter(filter); + + case FilterType.AssignedToTeams: + case FilterType.AssignedToCurrentUsersTeams: + return createAssignedToTeamsFilter(filter); + + case FilterType.CreatedByTeams: + case FilterType.CreatedByCurrentUsersTeams: + return createCreatedByTeamsFilter(filter); + + case FilterType.All: + return createAllFilter(); + + default: + return _ => false; + } + }; + + if (Array.isArray(filters)) { + if (filters.length === 1) { + return mapFilter(filters[0]); + } + + return (pullRequest: DashboardPullRequest): boolean => + filters.every(filter => mapFilter(filter)(pullRequest)); + } + + return mapFilter(filters); +} diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts index e0fca3a75f..0d476af9b9 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { BaseFilter, FilterType } from './types'; +import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { PullRequestFilter } from '../types'; import { stringArrayHas } from '../utils'; export type CreatedByTeamFilter = BaseFilter & diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts index ff10deaa14..34ed81db5d 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamsFilter.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { BaseFilter, FilterType } from './types'; +import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { PullRequestFilter } from '../types'; import { createCreatedByTeamFilter } from './createdByTeamFilter'; export type CreatedByTeamsFilter = BaseFilter & diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts index 19c5cbc1b1..e0a1a2b535 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { BaseFilter, FilterType } from './types'; +import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { PullRequestFilter } from '../types'; import { equalsIgnoreCase } from '../utils'; export type CreatedByUserFilter = BaseFilter & diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts new file mode 100644 index 0000000000..e20dfdbd18 --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { createFilter } from './createFilter'; +export { FilterTypes } from './types'; +export type { Filter, PullRequestFilter, FilterType } from './types'; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts index 37870703af..085f38cb30 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts @@ -14,6 +14,15 @@ * limitations under the License. */ +import { AllFilter } from './allFilter'; +import { AssignedToTeamFilter } from './assignedToTeamFilter'; +import { AssignedToTeamsFilter } from './assignedToTeamsFilter'; +import { AssignedToUserFilter } from './assignedToUserFilter'; +import { CreatedByTeamFilter } from './createdByTeamFilter'; +import { CreatedByTeamsFilter } from './createdByTeamsFilter'; +import { CreatedByUserFilter } from './createdByUserFilter'; +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; + export enum FilterType { All = 'All', @@ -51,3 +60,14 @@ export const FilterTypes = [ export type BaseFilter = { type: FilterType; }; + +export type Filter = + | AssignedToUserFilter + | CreatedByUserFilter + | AssignedToTeamFilter + | CreatedByTeamFilter + | AssignedToTeamsFilter + | CreatedByTeamsFilter + | AllFilter; + +export type PullRequestFilter = (pullRequest: DashboardPullRequest) => boolean; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/types.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/types.ts index 2d936f7b64..74c8ebe605 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/types.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/types.ts @@ -14,23 +14,24 @@ * limitations under the License. */ -import { - DashboardPullRequest, - Team, -} from '@backstage/plugin-azure-devops-common'; +import { Filter, PullRequestFilter } from './filters'; -export interface PullRequestGroup { +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; + +export interface PullRequestColumnConfig { title: string; - pullRequests: DashboardPullRequest[]; + filters: Filter[]; simplified?: boolean; } -export type PullRequestFilter = (pullRequest: DashboardPullRequest) => boolean; - -export type TeamFilter = (team: Team) => boolean; - export interface PullRequestGroupConfig { title: string; filter: PullRequestFilter; simplified?: boolean; } + +export interface PullRequestGroup { + title: string; + pullRequests: DashboardPullRequest[]; + simplified?: boolean; +} From a955e16875ca60e4a8ffe954704528fb64909d7a Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Thu, 2 Dec 2021 10:49:14 -0500 Subject: [PATCH 011/189] Adding changes for PR review comments II Signed-off-by: Balasundaram --- .../actions/builtin/publish/gitlabMergeRequest.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts index 0928ff3b6d..8238d040b2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -138,15 +138,15 @@ export const createPublishGitlabMergeRequestAction = (options: { }); } - const { default_branch: defaultBranch }: any = await api.Projects.show( - ctx.input.projectid, - ); + const projects = await api.Projects.show(ctx.input.projectid); + + const { default_branch: defaultBranch } = projects; try { await api.Branches.create( ctx.input.projectid, destinationBranch, - defaultBranch, + String(defaultBranch), ).then(branchResponse => { return branchResponse; }); @@ -171,7 +171,7 @@ export const createPublishGitlabMergeRequestAction = (options: { const mergeRequestUrl: any = await api.MergeRequests.create( ctx.input.projectid, destinationBranch, - defaultBranch, + String(defaultBranch), ctx.input.title, { description: ctx.input.description }, ).then(mergeRequest => { From ad7338bb48703ce84b49b41f15363d71255f063a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 2 Dec 2021 19:33:22 +0100 Subject: [PATCH 012/189] catalog-model: add presence field to locations Signed-off-by: Patrik Oldsberg --- .changeset/sweet-camels-learn.md | 5 +++++ packages/catalog-model/api-report.md | 1 + .../src/kinds/LocationEntityV1alpha1.test.ts | 19 +++++++++++++++++++ .../src/kinds/LocationEntityV1alpha1.ts | 1 + .../kinds/Location.v1alpha1.schema.json | 7 +++++++ 5 files changed, 33 insertions(+) create mode 100644 .changeset/sweet-camels-learn.md diff --git a/.changeset/sweet-camels-learn.md b/.changeset/sweet-camels-learn.md new file mode 100644 index 0000000000..60481b9363 --- /dev/null +++ b/.changeset/sweet-camels-learn.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-model': patch +--- + +Added an optional `presence` field to Location spec, which describes whether the target of a location is required to exist or not. It defaults to `'required'`, which is the current behaviour of the catalog. diff --git a/packages/catalog-model/api-report.md b/packages/catalog-model/api-report.md index 52f36493b5..9c0c33fa0e 100644 --- a/packages/catalog-model/api-report.md +++ b/packages/catalog-model/api-report.md @@ -325,6 +325,7 @@ interface LocationEntityV1alpha1 extends Entity { type?: string; target?: string; targets?: string[]; + presence?: 'required' | 'optional'; }; } export { LocationEntityV1alpha1 as LocationEntity }; diff --git a/packages/catalog-model/src/kinds/LocationEntityV1alpha1.test.ts b/packages/catalog-model/src/kinds/LocationEntityV1alpha1.test.ts index 7efec38395..6e78c1b96e 100644 --- a/packages/catalog-model/src/kinds/LocationEntityV1alpha1.test.ts +++ b/packages/catalog-model/src/kinds/LocationEntityV1alpha1.test.ts @@ -102,4 +102,23 @@ describe('LocationV1alpha1Validator', () => { (entity as any).spec.targets = 7; await expect(validator.check(entity)).rejects.toThrow(/targets/); }); + + it('accepts good presence', async () => { + (entity as any).spec.presence = 'required'; + await expect(validator.check(entity)).resolves.toBe(true); + (entity as any).spec.presence = 'optional'; + await expect(validator.check(entity)).resolves.toBe(true); + }); + + it('rejects empty presence', async () => { + (entity as any).spec.presence = ''; + await expect(validator.check(entity)).rejects.toThrow(/presence/); + }); + + it('rejects wrong presence', async () => { + (entity as any).spec.presence = 7; + await expect(validator.check(entity)).rejects.toThrow(/presence/); + (entity as any).spec.presence = 'nope'; + await expect(validator.check(entity)).rejects.toThrow(/presence/); + }); }); diff --git a/packages/catalog-model/src/kinds/LocationEntityV1alpha1.ts b/packages/catalog-model/src/kinds/LocationEntityV1alpha1.ts index 1872e43526..93a218aa2d 100644 --- a/packages/catalog-model/src/kinds/LocationEntityV1alpha1.ts +++ b/packages/catalog-model/src/kinds/LocationEntityV1alpha1.ts @@ -30,6 +30,7 @@ export interface LocationEntityV1alpha1 extends Entity { type?: string; target?: string; targets?: string[]; + presence?: 'required' | 'optional'; }; } diff --git a/packages/catalog-model/src/schema/kinds/Location.v1alpha1.schema.json b/packages/catalog-model/src/schema/kinds/Location.v1alpha1.schema.json index d633d30229..b70df9e70e 100644 --- a/packages/catalog-model/src/schema/kinds/Location.v1alpha1.schema.json +++ b/packages/catalog-model/src/schema/kinds/Location.v1alpha1.schema.json @@ -59,6 +59,13 @@ ], "minLength": 1 } + }, + "presence": { + "type": "string", + "description": "Whether the presence of the location target is required and it should be considered an error if it can not be found", + "default": "required", + "examples": ["required"], + "enum": ["required", "optional"] } } } From 3368f27aef46b2e8198f3b8a2805f890c2f1aecc Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 2 Dec 2021 19:53:59 +0100 Subject: [PATCH 013/189] catalog-backend: fix handling of optional locations Signed-off-by: Patrik Oldsberg --- .changeset/five-cats-hunt.md | 5 +++++ .../AzureDevOpsDiscoveryProcessor.test.ts | 4 ++++ .../processors/AzureDevOpsDiscoveryProcessor.ts | 1 + .../BitbucketDiscoveryProcessor.test.ts | 15 +++++++++++++++ .../processors/GitLabDiscoveryProcessor.test.ts | 3 +++ .../processors/GitLabDiscoveryProcessor.ts | 1 + .../processors/GithubDiscoveryProcessor.test.ts | 7 +++++++ .../processors/GithubDiscoveryProcessor.ts | 1 + .../bitbucket/BitbucketRepositoryParser.test.ts | 1 + .../bitbucket/BitbucketRepositoryParser.ts | 1 + .../DefaultCatalogProcessingOrchestrator.ts | 6 +++--- .../src/processing/ProcessorOutputCollector.ts | 3 ++- plugins/catalog-backend/src/util/conversion.ts | 1 + 13 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 .changeset/five-cats-hunt.md diff --git a/.changeset/five-cats-hunt.md b/.changeset/five-cats-hunt.md new file mode 100644 index 0000000000..cf3364a23a --- /dev/null +++ b/.changeset/five-cats-hunt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Fixed the handling of optional locations so that the catalog no longer logs `NotFoundError`s for missing optional locations. diff --git a/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.test.ts index ab053e8748..463d982ca2 100644 --- a/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.test.ts @@ -165,6 +165,7 @@ describe('AzureDevOpsDiscoveryProcessor', () => { type: 'url', target: 'https://dev.azure.com/shopify/engineering/_git/backstage?path=/catalog-info.yaml', + presence: 'optional', }, optional: true, }); @@ -174,6 +175,7 @@ describe('AzureDevOpsDiscoveryProcessor', () => { type: 'url', target: 'https://dev.azure.com/shopify/engineering/_git/ios-app?path=/src/catalog-info.yaml', + presence: 'optional', }, optional: true, }); @@ -211,6 +213,7 @@ describe('AzureDevOpsDiscoveryProcessor', () => { type: 'url', target: 'https://dev.azure.com/shopify/engineering/_git/backstage?path=/catalog-info.yaml', + presence: 'optional', }, optional: true, }); @@ -249,6 +252,7 @@ describe('AzureDevOpsDiscoveryProcessor', () => { type: 'url', target: 'https://dev.azure.com/shopify/engineering/_git/backstage?path=/src/main/catalog.yaml', + presence: 'optional', }, optional: true, }); diff --git a/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.ts index 58ee2155e9..aeac64f54d 100644 --- a/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/AzureDevOpsDiscoveryProcessor.ts @@ -95,6 +95,7 @@ export class AzureDevOpsDiscoveryProcessor implements CatalogProcessor { { type: 'url', target: `${baseUrl}/${org}/${project}/_git/${file.repository.name}?path=${file.path}`, + presence: 'optional', }, // Not all locations may actually exist, since the user defined them as a wildcard pattern. // Thus, we emit them as optional and let the downstream processor find them while not outputting diff --git a/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.test.ts index 2a63605b0d..3f8d0ba0fb 100644 --- a/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/BitbucketDiscoveryProcessor.test.ts @@ -208,6 +208,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.mycompany.com/projects/backstage/repos/backstage/browse/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -217,6 +218,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.mycompany.com/projects/demo/repos/demo/browse/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -242,6 +244,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.mycompany.com/projects/backstage/repos/techdocs-cli/browse/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -263,6 +266,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.mycompany.com/projects/backstage/repos/test/browse/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -291,6 +295,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.mycompany.com/projects/backstage/repos/techdocs-cli/browse/catalog-info.yaml', + presence: 'optional', }, optional: true, }); @@ -334,6 +339,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-one/src/master/catalog-info.yaml', + presence: 'optional', }, optional: true, }); @@ -343,6 +349,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-two/src/master/catalog-info.yaml', + presence: 'optional', }, optional: true, }); @@ -370,6 +377,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-one/src/master/my/nested/path/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -379,6 +387,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-two/src/master/my/nested/path/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -406,6 +415,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-one/src/master/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -415,6 +425,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-two/src/master/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -441,6 +452,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-one/src/master/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -468,6 +480,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-three/src/master/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -493,6 +506,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-one/src/master/catalog-info.yaml', + presence: 'optional', }, optional: true, }); @@ -528,6 +542,7 @@ describe('BitbucketDiscoveryProcessor', () => { type: 'url', target: 'https://bitbucket.org/myworkspace/repository-one/src/master/catalog-info.yaml', + presence: 'optional', }, optional: true, }); diff --git a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.test.ts index a0e44d7648..311de05673 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.test.ts @@ -201,6 +201,7 @@ describe('GitlabDiscoveryProcessor', () => { location: { type: 'url', target: 'https://gitlab.fake/1/-/blob/main/catalog-info.yaml', + presence: 'optional', }, optional: true, }, @@ -209,6 +210,7 @@ describe('GitlabDiscoveryProcessor', () => { location: { type: 'url', target: 'https://gitlab.fake/2/-/blob/master/catalog-info.yaml', + presence: 'optional', }, optional: true, }, @@ -246,6 +248,7 @@ describe('GitlabDiscoveryProcessor', () => { location: { type: 'url', target: 'https://gitlab.fake/1/-/blob/master/catalog-info.yaml', + presence: 'optional', }, optional: true, }, diff --git a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts index 445f02829e..70ccd44793 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GitLabDiscoveryProcessor.ts @@ -113,6 +113,7 @@ export class GitLabDiscoveryProcessor implements CatalogProcessor { // The alternative is using the `buildRawUrl` function, which does not support subgroups, so providing a raw // URL here won't work either. target: `${project.web_url}/-/blob/${project_branch}/${catalogPath}`, + presence: 'optional', }, true, ), diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.test.ts index 12d9e66659..59c25bb051 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.test.ts @@ -157,6 +157,7 @@ describe('GithubDiscoveryProcessor', () => { type: 'url', target: 'https://github.com/backstage/backstage/blob/master/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -165,6 +166,7 @@ describe('GithubDiscoveryProcessor', () => { location: { type: 'url', target: 'https://github.com/backstage/demo/blob/master/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -197,6 +199,7 @@ describe('GithubDiscoveryProcessor', () => { type: 'url', target: 'https://github.com/backstage/tech-docs/blob/main/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -251,6 +254,7 @@ describe('GithubDiscoveryProcessor', () => { type: 'url', target: 'https://github.com/backstage/backstage/blob/master/catalog-info.yaml', + presence: 'optional', }, optional: true, }); @@ -306,6 +310,7 @@ describe('GithubDiscoveryProcessor', () => { type: 'url', target: 'https://github.com/backstage/techdocs-cli/blob/master/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -315,6 +320,7 @@ describe('GithubDiscoveryProcessor', () => { type: 'url', target: 'https://github.com/backstage/techdocs-container/blob/master/catalog.yaml', + presence: 'optional', }, optional: true, }); @@ -370,6 +376,7 @@ describe('GithubDiscoveryProcessor', () => { location: { type: 'url', target: 'https://github.com/backstage/test/blob/master/catalog.yaml', + presence: 'optional', }, optional: true, }); diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts index b104d87542..9bd6cc775e 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/GithubDiscoveryProcessor.ts @@ -125,6 +125,7 @@ export class GithubDiscoveryProcessor implements CatalogProcessor { { type: 'url', target: `${repository.url}${path}`, + presence: 'optional', }, // Not all locations may actually exist, since the user defined them as a wildcard pattern. // Thus, we emit them as optional and let the downstream processor find them while not outputting diff --git a/plugins/catalog-backend/src/ingestion/processors/bitbucket/BitbucketRepositoryParser.test.ts b/plugins/catalog-backend/src/ingestion/processors/bitbucket/BitbucketRepositoryParser.test.ts index bc6c5a540f..397d259bae 100644 --- a/plugins/catalog-backend/src/ingestion/processors/bitbucket/BitbucketRepositoryParser.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/bitbucket/BitbucketRepositoryParser.test.ts @@ -29,6 +29,7 @@ describe('BitbucketRepositoryParser', () => { { type: 'url', target: `${browseUrl}${path}`, + presence: 'optional', }, true, ), diff --git a/plugins/catalog-backend/src/ingestion/processors/bitbucket/BitbucketRepositoryParser.ts b/plugins/catalog-backend/src/ingestion/processors/bitbucket/BitbucketRepositoryParser.ts index 27f07d58a2..34a9284b3e 100644 --- a/plugins/catalog-backend/src/ingestion/processors/bitbucket/BitbucketRepositoryParser.ts +++ b/plugins/catalog-backend/src/ingestion/processors/bitbucket/BitbucketRepositoryParser.ts @@ -30,6 +30,7 @@ export const defaultRepositoryParser: BitbucketRepositoryParser = { type: 'url', target: target, + presence: 'optional', }, // Not all locations may actually exist, since the user defined them as a wildcard pattern. // Thus, we emit them as optional and let the downstream processor find them while not outputting diff --git a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts index b42c8839cf..756b6a3639 100644 --- a/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts +++ b/plugins/catalog-backend/src/processing/DefaultCatalogProcessingOrchestrator.ts @@ -284,7 +284,7 @@ export class DefaultCatalogProcessingOrchestrator entity: LocationEntity, context: Context, ): Promise { - const { type = context.location.type } = entity.spec; + const { type = context.location.type, presence = 'required' } = entity.spec; const targets = new Array(); if (entity.spec.target) { targets.push(entity.spec.target); @@ -318,9 +318,9 @@ export class DefaultCatalogProcessingOrchestrator { type, target, - presence: 'required', + presence, }, - false, + presence === 'optional', context.collector.onEmit, this.options.parser, context.cache.forProcessor(processor, target), diff --git a/plugins/catalog-backend/src/processing/ProcessorOutputCollector.ts b/plugins/catalog-backend/src/processing/ProcessorOutputCollector.ts index 436038db66..b0c46b4b9f 100644 --- a/plugins/catalog-backend/src/processing/ProcessorOutputCollector.ts +++ b/plugins/catalog-backend/src/processing/ProcessorOutputCollector.ts @@ -105,8 +105,9 @@ export class ProcessorOutputCollector { this.deferredEntities.push({ entity, locationKey: location }); } else if (i.type === 'location') { + const presence = i.optional ? 'optional' : 'required'; const entity = locationSpecToLocationEntity( - i.location, + { presence, ...i.location }, this.parentEntity, ); const locationKey = getEntityLocationRef(entity); diff --git a/plugins/catalog-backend/src/util/conversion.ts b/plugins/catalog-backend/src/util/conversion.ts index a834f81255..559a472c25 100644 --- a/plugins/catalog-backend/src/util/conversion.ts +++ b/plugins/catalog-backend/src/util/conversion.ts @@ -81,6 +81,7 @@ export function locationSpecToLocationEntity( spec: { type: location.type, target: location.target, + presence: location.presence, }, }; From 25dfc2d483bf46be57fa05b74dceab91f79cab0f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 2 Dec 2021 22:48:07 +0100 Subject: [PATCH 014/189] add more explicit support for .mjs and .cjs extensions Signed-off-by: Patrik Oldsberg --- .changeset/spicy-parents-fold.md | 13 +++++++++++++ .changeset/strong-doors-destroy.md | 5 +++++ package.json | 2 +- packages/cli/config/jest.js | 8 +++++--- packages/cli/src/commands/lint.ts | 2 +- packages/cli/src/lib/bundler/transforms.ts | 4 ++-- .../templates/default-app/package.json.hbs | 2 +- packages/storybook/.storybook/main.js | 2 +- scripts/list-deprecations.js | 2 +- 9 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 .changeset/spicy-parents-fold.md create mode 100644 .changeset/strong-doors-destroy.md diff --git a/.changeset/spicy-parents-fold.md b/.changeset/spicy-parents-fold.md new file mode 100644 index 0000000000..0fad18f31a --- /dev/null +++ b/.changeset/spicy-parents-fold.md @@ -0,0 +1,13 @@ +--- +'@backstage/create-app': patch +--- + +Updated the root `package.json` to include files with `.cjs` and `.mjs` extensions in the `"lint-staged"` configuration. + +The make this change to an existing app, apply the following changes to the `package.json` file: + +```diff + "lint-staged": { +- "*.{js,jsx,ts,tsx}": [ ++ "*.{js,jsx,ts,tsx,mjs,cjs}": [ +``` diff --git a/.changeset/strong-doors-destroy.md b/.changeset/strong-doors-destroy.md new file mode 100644 index 0000000000..d568ed4e07 --- /dev/null +++ b/.changeset/strong-doors-destroy.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Add support for `.cjs` and `.mjs` extensions in local and dependency modules. diff --git a/package.json b/package.json index 8298508d06..bed17d2b5a 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ }, "prettier": "@spotify/prettier-config", "lint-staged": { - "*.{js,jsx,ts,tsx}": [ + "*.{js,jsx,ts,tsx,mjs,cjs}": [ "eslint --fix", "prettier --write" ], diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index 1d33372c60..978c598584 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -96,20 +96,22 @@ async function getProjectConfig(targetPath, displayName) { rootDir: path.resolve(targetPath, 'src'), coverageDirectory: path.resolve(targetPath, 'coverage'), coverageProvider: 'v8', - collectCoverageFrom: ['**/*.{js,jsx,ts,tsx}', '!**/*.d.ts'], + collectCoverageFrom: ['**/*.{js,jsx,ts,tsx,mjs,cjs}', '!**/*.d.ts'], moduleNameMapper: { '\\.(css|less|scss|sss|styl)$': require.resolve('jest-css-modules'), }, transform: { - '\\.(js|jsx|ts|tsx)$': require.resolve('./jestSucraseTransform.js'), + '\\.(js|jsx|ts|tsx|mjs|cjs)$': require.resolve( + './jestSucraseTransform.js', + ), '\\.(bmp|gif|jpg|jpeg|png|frag|xml|svg|eot|woff|woff2|ttf)$': require.resolve('./jestFileTransform.js'), '\\.(yaml)$': require.resolve('jest-transform-yaml'), }, // A bit more opinionated - testMatch: ['**/?(*.)test.{js,jsx,mjs,ts,tsx}'], + testMatch: ['**/?(*.)test.{js,jsx,ts,tsx,mjs,cjs}'], transformIgnorePatterns: [`/node_modules/(?:${transformIgnorePattern})/`], }; diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts index 41b454ffff..5c3e0a88e3 100644 --- a/packages/cli/src/commands/lint.ts +++ b/packages/cli/src/commands/lint.ts @@ -20,7 +20,7 @@ import { paths } from '../lib/paths'; export default async (cmd: Command, cmdArgs: string[]) => { const args = [ - '--ext=js,jsx,ts,tsx', + '--ext=js,jsx,ts,tsx,mjs,cjs', '--max-warnings=0', `--format=${cmd.format}`, ...(cmdArgs ?? [paths.targetDir]), diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts index 863728b8f8..d1d26f383d 100644 --- a/packages/cli/src/lib/bundler/transforms.ts +++ b/packages/cli/src/lib/bundler/transforms.ts @@ -61,7 +61,7 @@ export const transforms = (options: TransformOptions): Transforms => { }, }, { - test: /\.(jsx?|mjs)$/, + test: /\.(jsx?|mjs|cjs)$/, exclude: /node_modules/, loader: require.resolve('@sucrase/webpack-loader'), options: { @@ -71,7 +71,7 @@ export const transforms = (options: TransformOptions): Transforms => { }, }, { - test: /\.m?js/, + test: /\.(js|mjs|cjs)/, resolve: { fullySpecified: false, }, diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index bdae71d9e3..92f56bb236 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -38,7 +38,7 @@ }, "prettier": "@spotify/prettier-config", "lint-staged": { - "*.{js,jsx,ts,tsx}": [ + "*.{js,jsx,ts,tsx,mjs,cjs}": [ "eslint --fix", "prettier --write" ], diff --git a/packages/storybook/.storybook/main.js b/packages/storybook/.storybook/main.js index 72ff42311d..f5852b0164 100644 --- a/packages/storybook/.storybook/main.js +++ b/packages/storybook/.storybook/main.js @@ -59,7 +59,7 @@ module.exports = ({ args }) => { }, }, { - test: /\.(jsx?|mjs)$/, + test: /\.(jsx?|mjs|cjs)$/, exclude: /node_modules/, loader: require.resolve('@sucrase/webpack-loader'), options: { diff --git a/scripts/list-deprecations.js b/scripts/list-deprecations.js index 920b01c7b5..9a159927fc 100755 --- a/scripts/list-deprecations.js +++ b/scripts/list-deprecations.js @@ -129,7 +129,7 @@ async function main() { const srcDir = resolvePath(rootPath, packageDir, 'src'); if (await fs.pathExists(srcDir)) { - const files = await globby(['**/*.{js,jsx,ts,tsx}'], { + const files = await globby(['**/*.{js,jsx,ts,tsx,mjs,cjs}'], { cwd: srcDir, }); fileQueue.push( From 2c17e5b073ad6fa65825fee105765b626b73ad50 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 6 Dec 2021 11:33:00 +0000 Subject: [PATCH 015/189] Fix active submenu items Signed-off-by: hiba-aldalaty --- .changeset/eight-insects-kiss.md | 5 +++++ .../src/layout/Sidebar/SidebarSubmenuItem.tsx | 12 +++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 .changeset/eight-insects-kiss.md diff --git a/.changeset/eight-insects-kiss.md b/.changeset/eight-insects-kiss.md new file mode 100644 index 0000000000..e42a1b7c27 --- /dev/null +++ b/.changeset/eight-insects-kiss.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Bug fix - items in sidebar submenu are only active when full path is active (including search parameters) diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index 2bb8a13592..4e2fff169c 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -116,14 +116,13 @@ export type SidebarSubmenuItemProps = { export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { const { title, to, icon: Icon, dropdownItems } = props; const classes = useStyles(); - const { pathname: locationPathname } = useLocation(); - const { pathname: toPathname } = useResolvedPath(to); + const { pathname: locationPathname, search: locationSearch } = useLocation(); + const { pathname: toPathname, search: toSearch } = useResolvedPath(to ?? ''); const { setIsHoveredOn } = useContext(SidebarItemWithSubmenuContext); const closeSubmenu = () => { setIsHoveredOn(false); }; - - let isActive = locationPathname === toPathname; + let isActive = locationPathname === toPathname && toSearch === locationSearch; const [showDropDown, setShowDropDown] = useState(false); const handleClickDropdown = () => { @@ -132,7 +131,10 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { if (dropdownItems !== undefined) { dropdownItems.some(item => { const resolvedPath = resolvePath(item.to); - isActive = locationPathname === resolvedPath.pathname; + isActive = + locationPathname === resolvedPath.pathname && + locationSearch === toSearch; + return isActive; }); return (
From ec20755eda86b91f59d0db1a893598f7f9a13911 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 6 Dec 2021 11:45:14 +0000 Subject: [PATCH 016/189] Remove unnecessary ternary operator Signed-off-by: hiba-aldalaty --- .../core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index 4e2fff169c..3d17a67a49 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -117,7 +117,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { const { title, to, icon: Icon, dropdownItems } = props; const classes = useStyles(); const { pathname: locationPathname, search: locationSearch } = useLocation(); - const { pathname: toPathname, search: toSearch } = useResolvedPath(to ?? ''); + const { pathname: toPathname, search: toSearch } = useResolvedPath(to); const { setIsHoveredOn } = useContext(SidebarItemWithSubmenuContext); const closeSubmenu = () => { setIsHoveredOn(false); From d76184a53a536a9115419cdcc7293377dc78fc93 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 6 Dec 2021 11:49:23 +0000 Subject: [PATCH 017/189] Fix changeset Signed-off-by: hiba-aldalaty --- .changeset/eight-insects-kiss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eight-insects-kiss.md b/.changeset/eight-insects-kiss.md index e42a1b7c27..d44fbd3577 100644 --- a/.changeset/eight-insects-kiss.md +++ b/.changeset/eight-insects-kiss.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- -Bug fix - items in sidebar submenu are only active when full path is active (including search parameters) +Items in are now only active when their full path is active (including search parameters). From f85fb5b140128e054d6afb30451ba6babe2f1288 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 6 Dec 2021 12:40:53 +0000 Subject: [PATCH 018/189] Update .changeset/eight-insects-kiss.md Signed-off-by: hiba-aldalaty --- .changeset/eight-insects-kiss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eight-insects-kiss.md b/.changeset/eight-insects-kiss.md index d44fbd3577..4b09829bf3 100644 --- a/.changeset/eight-insects-kiss.md +++ b/.changeset/eight-insects-kiss.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- -Items in are now only active when their full path is active (including search parameters). +Items in `` are now only active when their full path is active (including search parameters). From 4e50a33f8edd713ba78f93b0678d16f8e3ffe78b Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Mon, 6 Dec 2021 14:21:45 +0000 Subject: [PATCH 019/189] refactor: Update import references. Signed-off-by: Marley Powell --- .../src/components/PullRequestsPage/lib/filters/allFilter.ts | 3 +-- .../PullRequestsPage/lib/filters/assignedToTeamFilter.ts | 2 +- .../PullRequestsPage/lib/filters/assignedToUserFilter.ts | 2 +- .../PullRequestsPage/lib/filters/createdByTeamFilter.ts | 2 +- .../PullRequestsPage/lib/filters/createdByUserFilter.ts | 2 +- .../src/components/PullRequestsPage/lib/filters/index.ts | 4 ++-- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts index 0ec7fc36af..90ec822ef6 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/allFilter.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { BaseFilter, FilterType } from './types'; +import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { PullRequestFilter } from '../types'; export type AllFilter = BaseFilter & { type: FilterType.All; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts index 3c48f04541..8e816db2c3 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToTeamFilter.ts @@ -17,7 +17,7 @@ import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { stringArrayHas } from '../utils'; +import { stringArrayHas } from '../../../../utils'; export type AssignedToTeamFilter = BaseFilter & { type: FilterType.AssignedToTeam; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts index 128c9103ab..95ee3d5a59 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/assignedToUserFilter.ts @@ -17,7 +17,7 @@ import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { stringArrayHas } from '../utils'; +import { stringArrayHas } from '../../../../utils'; export type AssignedToUserFilter = BaseFilter & ( diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts index 0d476af9b9..70a388b540 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByTeamFilter.ts @@ -17,7 +17,7 @@ import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { stringArrayHas } from '../utils'; +import { stringArrayHas } from '../../../../utils'; export type CreatedByTeamFilter = BaseFilter & ({ diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts index e0a1a2b535..69d4f23db5 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createdByUserFilter.ts @@ -17,7 +17,7 @@ import { BaseFilter, FilterType, PullRequestFilter } from './types'; import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; -import { equalsIgnoreCase } from '../utils'; +import { equalsIgnoreCase } from '../../../../utils'; export type CreatedByUserFilter = BaseFilter & ( diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts index e20dfdbd18..5470b349cf 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts @@ -15,5 +15,5 @@ */ export { createFilter } from './createFilter'; -export { FilterTypes } from './types'; -export type { Filter, PullRequestFilter, FilterType } from './types'; +export { FilterTypes, FilterType } from './types'; +export type { Filter, PullRequestFilter } from './types'; From 72bd5eb0753105e51459a71784891bbd435e69a2 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Mon, 6 Dec 2021 14:43:23 +0000 Subject: [PATCH 020/189] feat: Created `arrayHas` and `stringArrayHas` util functions. Signed-off-by: Marley Powell --- plugins/azure-devops/src/utils/arrayHas.ts | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 plugins/azure-devops/src/utils/arrayHas.ts diff --git a/plugins/azure-devops/src/utils/arrayHas.ts b/plugins/azure-devops/src/utils/arrayHas.ts new file mode 100644 index 0000000000..8dac8b8ec9 --- /dev/null +++ b/plugins/azure-devops/src/utils/arrayHas.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function arrayHas(arr: T[], value: T): boolean { + return new Set(arr).has(value); +} + +export function stringArrayHas( + arr: Array, + value: string | undefined, + ignoreCase: boolean = false, +): boolean { + if (ignoreCase) { + return arrayHas( + arr.map(a => a?.toLocaleLowerCase('en-US')), + value?.toLocaleLowerCase('en-US'), + ); + } + + return arrayHas(arr, value); +} From 362998f62eefadbe3744f39501f3d09cbefe6a88 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Mon, 6 Dec 2021 14:44:03 +0000 Subject: [PATCH 021/189] feat: Created `equalsIgnoreCase` util function. Signed-off-by: Marley Powell --- .../src/utils/equalsIgnoreCase.ts | 19 +++++++++++++++++++ plugins/azure-devops/src/utils/index.ts | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 plugins/azure-devops/src/utils/equalsIgnoreCase.ts create mode 100644 plugins/azure-devops/src/utils/index.ts diff --git a/plugins/azure-devops/src/utils/equalsIgnoreCase.ts b/plugins/azure-devops/src/utils/equalsIgnoreCase.ts new file mode 100644 index 0000000000..12b058e6ae --- /dev/null +++ b/plugins/azure-devops/src/utils/equalsIgnoreCase.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function equalsIgnoreCase(str1: string, str2: string): boolean { + return str1.toLocaleLowerCase('en-US') === str2.toLocaleLowerCase('en-US'); +} diff --git a/plugins/azure-devops/src/utils/index.ts b/plugins/azure-devops/src/utils/index.ts new file mode 100644 index 0000000000..f2214e8106 --- /dev/null +++ b/plugins/azure-devops/src/utils/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './arrayHas'; +export * from './equalsIgnoreCase'; +export * from './getDurationFromDates'; From ed133e68cbf14bff9a17410ab84000e9cf75e817 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Mon, 6 Dec 2021 14:55:23 +0000 Subject: [PATCH 022/189] feat: Updated `PullRequestsPage` to use new column config approach. Signed-off-by: Marley Powell --- .../PullRequestsPage/PullRequestsPage.tsx | 88 ++++++++----------- 1 file changed, 37 insertions(+), 51 deletions(-) diff --git a/plugins/azure-devops/src/components/PullRequestsPage/PullRequestsPage.tsx b/plugins/azure-devops/src/components/PullRequestsPage/PullRequestsPage.tsx index 9f21c4b81b..158c4bca5b 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/PullRequestsPage.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/PullRequestsPage.tsx @@ -21,56 +21,17 @@ import { Progress, ResponseErrorPanel, } from '@backstage/core-components'; -import { PullRequestGroup, PullRequestGroupConfig } from './lib/types'; -import React, { useEffect, useState } from 'react'; -import { getCreatedByUserFilter, getPullRequestGroups } from './lib/utils'; -import { useDashboardPullRequests, useUserEmail } from '../../hooks'; +import { PullRequestColumnConfig, PullRequestGroup } from './lib/types'; +import React, { useState } from 'react'; +import { getPullRequestGroupConfigs, getPullRequestGroups } from './lib/utils'; -import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { FilterType } from './lib/filters'; import { PullRequestGrid } from './lib/PullRequestGrid'; - -function usePullRequestGroupConfigs( - userEmail: string | undefined, -): PullRequestGroupConfig[] { - const [pullRequestGroupConfigs, setPullRequestGroupConfigs] = useState< - PullRequestGroupConfig[] - >([]); - - useEffect(() => { - const prGroupConfigs: PullRequestGroupConfig[] = [ - { title: 'Created by me', filter: getCreatedByUserFilter(userEmail) }, - { title: 'Other PRs', filter: _ => true, simplified: false }, - ]; - - setPullRequestGroupConfigs(prGroupConfigs); - }, [userEmail]); - - return pullRequestGroupConfigs; -} - -function usePullRequestGroups( - pullRequests: DashboardPullRequest[] | undefined, - pullRequestGroupConfigs: PullRequestGroupConfig[], -): PullRequestGroup[] { - const [pullRequestGroups, setPullRequestGroups] = useState< - PullRequestGroup[] - >([]); - - useEffect(() => { - if (pullRequests) { - const groups = getPullRequestGroups( - pullRequests, - pullRequestGroupConfigs, - ); - setPullRequestGroups(groups); - } - }, [pullRequests, pullRequestGroupConfigs]); - - return pullRequestGroups; -} +import { useDashboardPullRequests } from '../../hooks'; +import { useFilterProcessor } from './lib/hooks'; type PullRequestsPageContentProps = { - pullRequestGroups: PullRequestGroup[]; + pullRequestGroups: PullRequestGroup[] | undefined; loading: boolean; error?: Error; }; @@ -80,7 +41,7 @@ const PullRequestsPageContent = ({ loading, error, }: PullRequestsPageContentProps) => { - if (loading && pullRequestGroups.length <= 0) { + if (loading && (!pullRequestGroups || pullRequestGroups.length <= 0)) { return ; } @@ -88,25 +49,50 @@ const PullRequestsPageContent = ({ return ; } - return ; + return ; }; +const DEFAULT_COLUMN_CONFIGS: PullRequestColumnConfig[] = [ + { + title: 'Created by me', + filters: [{ type: FilterType.CreatedByCurrentUser }], + simplified: false, + }, + { + title: 'Other PRs', + filters: [{ type: FilterType.All }], + simplified: true, + }, +]; + type PullRequestsPageProps = { projectName?: string; pollingInterval?: number; + defaultColumnConfigs?: PullRequestColumnConfig[]; }; export const PullRequestsPage = ({ projectName, pollingInterval, + defaultColumnConfigs, }: PullRequestsPageProps) => { const { pullRequests, loading, error } = useDashboardPullRequests( projectName, pollingInterval, ); - const userEmail = useUserEmail(); - const pullRequestGroupConfigs = usePullRequestGroupConfigs(userEmail); - const pullRequestGroups = usePullRequestGroups( + + const [columnConfigs] = useState( + defaultColumnConfigs ?? DEFAULT_COLUMN_CONFIGS, + ); + + const filterProcessor = useFilterProcessor(); + + const pullRequestGroupConfigs = getPullRequestGroupConfigs( + columnConfigs, + filterProcessor, + ); + + const pullRequestGroups = getPullRequestGroups( pullRequests, pullRequestGroupConfigs, ); From 949e73e125651ff629b8bf5c65a4940b158114b9 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Mon, 6 Dec 2021 14:56:37 +0000 Subject: [PATCH 023/189] feat: Created new `getPullRequestGroupConfigs` function. Signed-off-by: Marley Powell --- .../PullRequestsPage/lib/utils.test.ts | 2 +- .../components/PullRequestsPage/lib/utils.ts | 38 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts index da27b2e06e..ffe58e2918 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts @@ -132,7 +132,7 @@ describe('getPullRequestGroups', () => { { title: 'Other PRs', filter: (_: unknown) => true, simplified: true }, ]; - const result = getPullRequestGroups(pullRequests, configs); + const result = getPullRequestGroups(pullRequests, configs) ?? []; expect(result.length).toBe(2); diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.ts index c9cf866010..c4fcdc9f7e 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.ts @@ -19,25 +19,13 @@ import { PullRequestVoteStatus, Reviewer, } from '@backstage/plugin-azure-devops-common'; +import { Filter, createFilter } from './filters'; import { - PullRequestFilter, + PullRequestColumnConfig, PullRequestGroup, PullRequestGroupConfig, } from './types'; -/** - * Creates a filter that matches pull requests created by `userEmail`. - * @param userEmail an email to filter by. - * @returns a filter for pull requests created by `userEmail`. - */ -export function getCreatedByUserFilter( - userEmail: string | undefined, -): PullRequestFilter { - return (pullRequest: DashboardPullRequest): boolean => - pullRequest.createdBy?.uniqueName?.toLocaleLowerCase() === - userEmail?.toLocaleLowerCase(); -} - /** * Filters a reviewer based on vote status and if the reviewer is required. * @param reviewer a reviewer to filter. @@ -97,9 +85,13 @@ export function arrayExtract(arr: T[], filter: (value: T) => unknown): T[] { * @returns a list of pull request groups. */ export function getPullRequestGroups( - pullRequests: DashboardPullRequest[], + pullRequests: DashboardPullRequest[] | undefined, configs: PullRequestGroupConfig[], -): PullRequestGroup[] { +): PullRequestGroup[] | undefined { + if (!pullRequests) { + return undefined; + } + const remainingPullRequests: DashboardPullRequest[] = [...pullRequests]; const pullRequestGroups: PullRequestGroup[] = []; @@ -115,3 +107,17 @@ export function getPullRequestGroups( return pullRequestGroups; } + +export function getPullRequestGroupConfigs( + columnConfigs: PullRequestColumnConfig[], + filterProcessor: (filters: Filter[]) => Filter[], +): PullRequestGroupConfig[] { + return columnConfigs.map(columnConfig => { + const filters = filterProcessor(columnConfig.filters); + return { + title: columnConfig.title, + filter: createFilter(filters), + simplified: columnConfig.simplified, + }; + }); +} From 6c77a8ccf510807ae13814da06838621d1eec142 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Mon, 6 Dec 2021 14:58:09 +0000 Subject: [PATCH 024/189] feat: Created `useFilterProcessor` hook for populating filter values. Signed-off-by: Marley Powell --- .../PullRequestsPage/lib/hooks/index.ts | 17 ++++++++ .../lib/hooks/useFilterProcessor.ts | 39 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/index.ts create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/index.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/index.ts new file mode 100644 index 0000000000..2e87dfea0c --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './useFilterProcessor'; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts new file mode 100644 index 0000000000..546b23430d --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/hooks/useFilterProcessor.ts @@ -0,0 +1,39 @@ +/* + * 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 { Filter, FilterType } from '../filters'; + +import { useUserEmail } from '../../../../hooks'; + +export function useFilterProcessor(): (filters: Filter[]) => Filter[] { + const userEmail = useUserEmail(); + + return (filters: Filter[]): Filter[] => { + for (const filter of filters) { + switch (filter.type) { + case FilterType.AssignedToCurrentUser: + case FilterType.CreatedByCurrentUser: + filter.email = userEmail; + break; + + default: + break; + } + } + + return filters; + }; +} From c0ac89d531a877da2f2654899dcfb0bcdda9c810 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Mon, 6 Dec 2021 15:12:15 +0000 Subject: [PATCH 025/189] feat: Added additional types. Signed-off-by: Marley Powell --- .../src/utils/azure-devops-utils.ts | 1 + plugins/azure-devops-common/src/types.ts | 3 ++ .../PullRequestsPage/lib/utils.test.ts | 34 ++++--------------- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts index aa843e9c17..7a0d0a279e 100644 --- a/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts +++ b/plugins/azure-devops-backend/src/utils/azure-devops-utils.ts @@ -215,6 +215,7 @@ function convertReviewer( return { id: identityRef.id, displayName: identityRef.displayName, + uniqueName: identityRef.uniqueName, imageUrl: getAvatarUrl(identityRef), isRequired: identityRef.isRequired, isContainer: identityRef.isContainer, diff --git a/plugins/azure-devops-common/src/types.ts b/plugins/azure-devops-common/src/types.ts index da41e08d1f..c87d8641ad 100644 --- a/plugins/azure-devops-common/src/types.ts +++ b/plugins/azure-devops-common/src/types.ts @@ -145,6 +145,7 @@ export interface DashboardPullRequest { export interface Reviewer { id?: string; displayName?: string; + uniqueName?: string; imageUrl?: string; isRequired?: boolean; isContainer?: boolean; @@ -164,6 +165,8 @@ export interface CreatedBy { displayName?: string; uniqueName?: string; imageUrl?: string; + teamIds?: string[]; + teamNames?: string[]; } export interface Repository { diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts index ffe58e2918..d128cbd1db 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/utils.test.ts @@ -19,33 +19,7 @@ import { PullRequestVoteStatus, Reviewer, } from '@backstage/plugin-azure-devops-common'; -import { - arrayExtract, - getCreatedByUserFilter, - getPullRequestGroups, - reviewerFilter, -} from './utils'; - -describe('getCreatedByUserFilter', () => { - it('should filter if pull request is created by user', () => { - const userEmail = 'user1@backstage.com'; - const pr = { - createdBy: { uniqueName: userEmail }, - } as DashboardPullRequest; - const result = getCreatedByUserFilter(userEmail)(pr); - expect(result).toBe(true); - }); - - it('should not filter if pull request is not created by user', () => { - const userEmail1 = 'user1@backstage.com'; - const userEmail2 = 'user2@backstage.com'; - const pr = { - createdBy: { uniqueName: userEmail1 }, - } as DashboardPullRequest; - const result = getCreatedByUserFilter(userEmail2)(pr); - expect(result).toBe(false); - }); -}); +import { arrayExtract, getPullRequestGroups, reviewerFilter } from './utils'; describe('reviewerFilter', () => { it('should return false if reviewer has no vote and is not required', () => { @@ -128,7 +102,11 @@ describe('getPullRequestGroups', () => { ]; const configs = [ - { title: 'Created by me', filter: getCreatedByUserFilter(userEmail) }, + { + title: 'Created by me', + filter: (pullRequest: DashboardPullRequest): boolean => + pullRequest.createdBy?.uniqueName === userEmail, + }, { title: 'Other PRs', filter: (_: unknown) => true, simplified: true }, ]; From 1e7070443decf3004eaec10c8ba30e8fa15fd591 Mon Sep 17 00:00:00 2001 From: Praveen Ranjan Keshri Date: Wed, 8 Dec 2021 00:21:53 +0530 Subject: [PATCH 026/189] Fixes post review by Rugvip: 1. Ensuring that reloadIntervals, if present, is a valid positive number 2. Remote config error message fix 3. Removed remote config from example backend 4. Lessened the writing.md 5. Multiple changesets Signed-off-by: Praveen Ranjan Keshri --- .changeset/brave-impalas-switch.md | 2 -- .changeset/cuddly-cooks-enjoy.md | 5 +++++ docs/conf/writing.md | 21 +++------------------ packages/backend/src/index.ts | 3 --- packages/config-loader/src/loader.ts | 6 +++--- 5 files changed, 11 insertions(+), 26 deletions(-) create mode 100644 .changeset/cuddly-cooks-enjoy.md diff --git a/.changeset/brave-impalas-switch.md b/.changeset/brave-impalas-switch.md index 058e2dbf8d..de7e2ee528 100644 --- a/.changeset/brave-impalas-switch.md +++ b/.changeset/brave-impalas-switch.md @@ -1,7 +1,5 @@ --- -'example-backend': patch '@backstage/backend-common': patch -'@backstage/config-loader': patch --- Fixed bug in backend-common to allow passing of remote option in order to enable passing remote url in --config option. The remote option should be passed along with reloadIntervalSeconds from packages/backend/src/index.ts (Updated the file as well) diff --git a/.changeset/cuddly-cooks-enjoy.md b/.changeset/cuddly-cooks-enjoy.md new file mode 100644 index 0000000000..d39844e7a9 --- /dev/null +++ b/.changeset/cuddly-cooks-enjoy.md @@ -0,0 +1,5 @@ +--- +'@backstage/config-loader': patch +--- + +In case remote.reloadIntervalSeconds is passed, it must be a valid positive value diff --git a/docs/conf/writing.md b/docs/conf/writing.md index afd86955fa..a4da1e3df0 100644 --- a/docs/conf/writing.md +++ b/docs/conf/writing.md @@ -75,25 +75,10 @@ files. Paths are relative to the working directory of the executed process, for example `package/backend`. This means that to select a config file in the repo root when running the backend, you would use `--config ../../my-config.yaml`, and for config file on a config server you would use -`--config https://some.domain.io/app-config.yaml`
+`--config https://some.domain.io/app-config.yaml` -**\*Note**: In order to use remote urls, ensure that the option 'remote' is -passed in `loadBackendConfig(...)` call (See below) inside -`packages/backend/src/index.ts`, with the option of -reloadIntervalSeconds(required) as given below. This will allow the usage of -remote configs and also, will ensure that this config is checked for any changes -every 12 hours. (This can be any desired value in seconds, here 60 _ 60 _ 12 = -12 hours!): - -```ts -const config = await loadBackendConfig({ - argv: process.argv, - logger, - remote: { - reloadIntervalSeconds: 60 * 60 * 12, // Check remote config changes every 12 hours. Change to your desired interval in seconds - }, -}); -``` +**Note**: In case URLs are passed, it is also needed to set the remote option in +the loadBackendConfig call. If no `config` flags are specified, the default behavior is to load `app-config.yaml` and, if it exists, `app-config.local.yaml` from the repo root. diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index e3c15b95b6..7a79c278ff 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -88,9 +88,6 @@ async function main() { const config = await loadBackendConfig({ argv: process.argv, logger, - remote: { - reloadIntervalSeconds: 60 * 60 * 12, // Check remote config changes every 12 hours. Change to your desired interval in seconds - }, }); const createEnv = makeCreateEnv(config); diff --git a/packages/config-loader/src/loader.ts b/packages/config-loader/src/loader.ts index 388017318f..e7aa3d4c10 100644 --- a/packages/config-loader/src/loader.ts +++ b/packages/config-loader/src/loader.ts @@ -129,12 +129,12 @@ export async function loadConfig( if (remote === undefined) { if (configUrls.length > 0) { throw new Error( - `Remote config detected but this feature is turned off. Please enable by passing remote option in loadBackendConfig() call inside packages/backend/src/index.ts. See https://backstage.io/docs/conf/writing#configuration-files for detailed info.`, + `Please make sure you are passing the remote option when loading the configuration. See https://backstage.io/docs/conf/writing#configuration-files for detailed info.`, ); } - } else if (remote.reloadIntervalSeconds === undefined) { + } else if (remote.reloadIntervalSeconds <= 0) { throw new Error( - `Remote config must be contain reloadIntervalSeconds: value`, + `Remote config must be contain a non zero reloadIntervalSeconds: value`, ); } From b3de772e22eeba51cc85cf21056dd48f78f7cc18 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Wed, 8 Dec 2021 12:42:59 +0000 Subject: [PATCH 027/189] Create isLocationMatch function for location matching and setting active sidebar items Signed-off-by: hiba-aldalaty --- .../src/layout/Sidebar/Items.tsx | 11 +++--- .../src/layout/Sidebar/Sidebar.stories.tsx | 16 +------- .../src/layout/Sidebar/SidebarSubmenuItem.tsx | 11 +++--- .../src/layout/Sidebar/utils.ts | 38 +++++++++++++++++++ 4 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 packages/core-components/src/layout/Sidebar/utils.ts diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index a41c3e4bdd..e1dcd4a15e 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -46,6 +46,7 @@ import { SidebarItemWithSubmenuContext, } from './config'; import { SidebarSubmenu } from './SidebarSubmenu'; +import { isLocationMatch } from './utils'; export type SidebarItemClassKey = | 'root' @@ -172,7 +173,7 @@ const useStyles = makeStyles( function isSidebarItemWithSubmenuActive( submenu: ReactNode, - locationPathname: string, + currentLocation: any, ) { // Item is active if any of submenu items have active paths const toPathnames: string[] = []; @@ -193,8 +194,8 @@ function isSidebarItemWithSubmenuActive( } }); isActive = toPathnames.some(to => { - const toPathname = resolvePath(to); - return locationPathname === toPathname.pathname; + const toLocation = resolvePath(to); + return isLocationMatch(currentLocation, toLocation); }); return isActive; } @@ -207,8 +208,8 @@ const SidebarItemWithSubmenu = ({ }: PropsWithChildren) => { const classes = useStyles(); const [isHoveredOn, setIsHoveredOn] = useState(false); - const { pathname: locationPathname } = useLocation(); - const isActive = isSidebarItemWithSubmenuActive(children, locationPathname); + const currentLocation = useLocation(); + const isActive = isSidebarItemWithSubmenuActive(children, currentLocation); const handleMouseEnter = () => { setIsHoveredOn(true); diff --git a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx index 5e68aa8d62..6afd0bf157 100644 --- a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx +++ b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx @@ -17,8 +17,6 @@ import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import HomeOutlinedIcon from '@material-ui/icons/HomeOutlined'; import BuildRoundedIcon from '@material-ui/icons/BuildRounded'; -import LibraryBooksOutlinedIcon from '@material-ui/icons/LibraryBooksOutlined'; -import WebOutlinedIcon from '@material-ui/icons/WebOutlined'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; import { @@ -34,7 +32,7 @@ import { import { SidebarSubmenuItem } from './SidebarSubmenuItem'; import MenuBookIcon from '@material-ui/icons/MenuBook'; import CloudQueueIcon from '@material-ui/icons/CloudQueue'; -import SettingsApplications from '@material-ui/icons/SettingsApplications'; +import AppsIcon from '@material-ui/icons/Apps'; import AcUnitIcon from '@material-ui/icons/AcUnit'; import { SidebarSubmenu } from './SidebarSubmenu'; @@ -76,17 +74,7 @@ export const SampleScalableSidebar = () => ( - - - + (theme => ({ item: { @@ -116,13 +117,13 @@ export type SidebarSubmenuItemProps = { export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { const { title, to, icon: Icon, dropdownItems } = props; const classes = useStyles(); - const { pathname: locationPathname, search: locationSearch } = useLocation(); - const { pathname: toPathname, search: toSearch } = useResolvedPath(to); const { setIsHoveredOn } = useContext(SidebarItemWithSubmenuContext); const closeSubmenu = () => { setIsHoveredOn(false); }; - let isActive = locationPathname === toPathname && toSearch === locationSearch; + const toLocation = useResolvedPath(to); + const currentLocation = useLocation(); + let isActive = isLocationMatch(currentLocation, toLocation); const [showDropDown, setShowDropDown] = useState(false); const handleClickDropdown = () => { @@ -131,9 +132,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { if (dropdownItems !== undefined) { dropdownItems.some(item => { const resolvedPath = resolvePath(item.to); - isActive = - locationPathname === resolvedPath.pathname && - locationSearch === toSearch; + isActive = isLocationMatch(currentLocation, resolvedPath); return isActive; }); return ( diff --git a/packages/core-components/src/layout/Sidebar/utils.ts b/packages/core-components/src/layout/Sidebar/utils.ts new file mode 100644 index 0000000000..8fefb77bd9 --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/utils.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Location, State, Path } from 'history'; +import { isEqual, isMatch } from 'lodash'; +import qs from 'qs'; + +export function isLocationMatch( + currentLocation: Location, + toLocation: Path, +) { + const toDecodedSearch = new URLSearchParams(toLocation.search).toString(); + const toQueryParameters = qs.parse(toDecodedSearch); + + const currentDecodedSearch = new URLSearchParams( + currentLocation.search, + ).toString(); + const currentQueryParameters = qs.parse(currentDecodedSearch); + + const matching = + isEqual(toLocation.pathname, currentLocation.pathname) && + isMatch(currentQueryParameters, toQueryParameters); + + return matching; +} From 67688f46016c1435114d6d5ab81fb92b7d10b759 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Wed, 8 Dec 2021 13:11:22 +0000 Subject: [PATCH 028/189] fix generic type error Signed-off-by: hiba-aldalaty --- packages/core-components/src/layout/Sidebar/utils.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/utils.ts b/packages/core-components/src/layout/Sidebar/utils.ts index 8fefb77bd9..1afebe796d 100644 --- a/packages/core-components/src/layout/Sidebar/utils.ts +++ b/packages/core-components/src/layout/Sidebar/utils.ts @@ -14,14 +14,11 @@ * limitations under the License. */ -import { Location, State, Path } from 'history'; +import { Location, Path } from 'history'; import { isEqual, isMatch } from 'lodash'; import qs from 'qs'; -export function isLocationMatch( - currentLocation: Location, - toLocation: Path, -) { +export function isLocationMatch(currentLocation: Location, toLocation: Path) { const toDecodedSearch = new URLSearchParams(toLocation.search).toString(); const toQueryParameters = qs.parse(toDecodedSearch); From 8f253285a1b37db4e253fe6f8a16259e596075a9 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 8 Dec 2021 15:56:36 +0100 Subject: [PATCH 029/189] chore(deps-dev): bump @types/tar from 4.0.5 to 6.1.1 Signed-off-by: Johan Haals --- packages/backend-common/package.json | 2 +- packages/cli/package.json | 2 +- yarn.lock | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index e46d659175..8296f59ef5 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -94,7 +94,7 @@ "@types/recursive-readdir": "^2.2.0", "@types/stoppable": "^1.1.0", "@types/supertest": "^2.0.8", - "@types/tar": "^4.0.3", + "@types/tar": "^6.1.1", "@types/unzipper": "^0.10.3", "@types/webpack-env": "^1.15.2", "aws-sdk-mock": "^5.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 0a6b2b934a..7804623b50 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -134,7 +134,7 @@ "@types/recursive-readdir": "^2.2.0", "@types/rollup-plugin-peer-deps-external": "^2.2.0", "@types/rollup-plugin-postcss": "^2.0.0", - "@types/tar": "^4.0.3", + "@types/tar": "^6.1.1", "@types/terser-webpack-plugin": "^5.0.4", "@types/webpack": "^5.28.0", "@types/webpack-dev-server": "^3.11.5", diff --git a/yarn.lock b/yarn.lock index f1c17c0022..6f4aab1631 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8330,6 +8330,14 @@ "@types/minipass" "*" "@types/node" "*" +"@types/tar@^6.1.1": + version "6.1.1" + resolved "https://registry.npmjs.org/@types/tar/-/tar-6.1.1.tgz#ab341ec1f149d7eb2a4f4ded56ff85f0d4fe7cb5" + integrity sha512-8mto3YZfVpqB1CHMaYz1TUYIQfZFbh/QbEq5Hsn6D0ilCfqRVCdalmc89B7vi3jhl9UYIk+dWDABShNfOkv5HA== + dependencies: + "@types/minipass" "*" + "@types/node" "*" + "@types/tern@*": version "0.23.3" resolved "https://registry.npmjs.org/@types/tern/-/tern-0.23.3.tgz#4b54538f04a88c9ff79de1f6f94f575a7f339460" From c7930a7330bec25540642227e662de845d75831c Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 8 Dec 2021 16:00:00 +0100 Subject: [PATCH 030/189] add changeset Signed-off-by: Johan Haals --- .changeset/cold-otters-prove.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/cold-otters-prove.md diff --git a/.changeset/cold-otters-prove.md b/.changeset/cold-otters-prove.md new file mode 100644 index 0000000000..5b41f8906c --- /dev/null +++ b/.changeset/cold-otters-prove.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-common': patch +'@backstage/cli': patch +--- + +chore(deps-dev): bump @types/tar from 4.0.5 to 6.1.1 From 9b093a488adf4e9b556c9f0503c7642e1eef5cf1 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 8 Dec 2021 16:15:41 +0100 Subject: [PATCH 031/189] Update .changeset/cold-otters-prove.md Signed-off-by: Johan Haals Co-authored-by: Ben Lambert --- .changeset/cold-otters-prove.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/cold-otters-prove.md b/.changeset/cold-otters-prove.md index 5b41f8906c..37438b333e 100644 --- a/.changeset/cold-otters-prove.md +++ b/.changeset/cold-otters-prove.md @@ -3,4 +3,4 @@ '@backstage/cli': patch --- -chore(deps-dev): bump @types/tar from 4.0.5 to 6.1.1 +chore(deps-dev): bump `@types/tar` from 4.0.5 to 6.1.1 From 8ee5b6f3dd7da14a8f0495a31ab7fe38cd4bad46 Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Wed, 8 Dec 2021 16:34:09 -0500 Subject: [PATCH 032/189] Adding changes for PR review comments III Signed-off-by: Balasundaram --- plugins/scaffolder-backend/package.json | 4 ++-- .../builtin/publish/gitlabMergeRequest.ts | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index fe5d61d4d3..21f554779f 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -40,8 +40,8 @@ "@backstage/plugin-scaffolder-common": "^0.1.1", "@backstage/plugin-scaffolder-backend-module-cookiecutter": "^0.1.3", "@backstage/types": "^0.1.1", - "@gitbeaker/core": "^30.2.0", - "@gitbeaker/node": "^30.2.0", + "@gitbeaker/core": "^35.1.0", + "@gitbeaker/node": "^35.1.0", "@octokit/rest": "^18.5.3", "@octokit/webhooks": "^9.14.1", "@types/express": "^4.17.6", diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts index 8238d040b2..b333b5234d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -17,7 +17,8 @@ import { createTemplateAction } from '../../createTemplateAction'; import { readFile } from 'fs-extra'; import { Gitlab } from '@gitbeaker/node'; import globby from 'globby'; -import { CommitAction } from '@gitbeaker/core/dist/types/services/Commits'; +import { Types } from '@gitbeaker/core'; + import { ScmIntegrationRegistry } from '@backstage/integration'; import { InputError } from '@backstage/errors'; import { parseRepoUrl } from './util'; @@ -96,7 +97,11 @@ export const createPublishGitlabMergeRequestAction = (options: { const { host } = parseRepoUrl(repoUrl, integrations); const integrationConfig = integrations.gitlab.byHost(host); - const actions: CommitAction[] = []; + /* const a : Types.CommitAction = { + action: 'create', + filePath: '' + };*/ + const actions: Types.CommitAction[] = []; const destinationBranch = ctx.input.branchName; @@ -147,9 +152,7 @@ export const createPublishGitlabMergeRequestAction = (options: { ctx.input.projectid, destinationBranch, String(defaultBranch), - ).then(branchResponse => { - return branchResponse; - }); + ); } catch (e) { throw new InputError(`The branch creation failed ${e}`); } @@ -168,13 +171,13 @@ export const createPublishGitlabMergeRequestAction = (options: { } try { - const mergeRequestUrl: any = await api.MergeRequests.create( + const mergeRequestUrl = await api.MergeRequests.create( ctx.input.projectid, destinationBranch, String(defaultBranch), ctx.input.title, { description: ctx.input.description }, - ).then(mergeRequest => { + ).then((mergeRequest: { web_url: string }) => { return mergeRequest.web_url; }); ctx.output('projectid', ctx.input.projectid); From 8e3363a1d82940a53934737e02141382066afb94 Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Thu, 9 Dec 2021 11:46:36 +0100 Subject: [PATCH 033/189] export typescript types for OIDC provider Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- .../auth-backend/src/providers/oidc/index.ts | 7 ++- .../src/providers/oidc/provider.ts | 53 ++++++++++--------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/plugins/auth-backend/src/providers/oidc/index.ts b/plugins/auth-backend/src/providers/oidc/index.ts index 20d014a783..1d0f592359 100644 --- a/plugins/auth-backend/src/providers/oidc/index.ts +++ b/plugins/auth-backend/src/providers/oidc/index.ts @@ -13,5 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +export type { + OidcSignInResolver, + OidcAuthHandler, + OidcAuthResult, + OidcProviderOptions, +} from './provider'; export { createOidcProvider } from './provider'; diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index 158af6f830..b9ae15f370 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -56,18 +56,21 @@ type OidcImpl = { client: Client; }; -type AuthResult = { +export type OidcAuthResult = { tokenset: TokenSet; userinfo: UserinfoResponse; }; +export type OidcSignInResolver = SignInResolver; +export type OidcAuthHandler = AuthHandler; + export type Options = OAuthProviderOptions & { metadataUrl: string; scope?: string; prompt?: string; tokenSignedResponseAlg?: string; - signInResolver?: SignInResolver; - authHandler: AuthHandler; + signInResolver?: OidcSignInResolver; + authHandler: OidcAuthHandler; tokenIssuer: TokenIssuer; catalogIdentityClient: CatalogIdentityClient; logger: Logger; @@ -78,8 +81,8 @@ export class OidcAuthProvider implements OAuthHandlers { private readonly scope?: string; private readonly prompt?: string; - private readonly signInResolver?: SignInResolver; - private readonly authHandler: AuthHandler; + private readonly signInResolver?: SignInResolver; + private readonly authHandler: AuthHandler; private readonly tokenIssuer: TokenIssuer; private readonly catalogIdentityClient: CatalogIdentityClient; private readonly logger: Logger; @@ -113,7 +116,7 @@ export class OidcAuthProvider implements OAuthHandlers { ): Promise<{ response: OAuthResponse; refreshToken?: string }> { const { strategy } = await this.implementation; const strategyResponse = await executeFrameHandlerStrategy< - AuthResult, + OidcAuthResult, PrivateInfo >(req, strategy); const { @@ -158,7 +161,7 @@ export class OidcAuthProvider implements OAuthHandlers { ( tokenset: TokenSet, userinfo: UserinfoResponse, - done: PassportDoneCallback, + done: PassportDoneCallback, ) => { if (typeof done !== 'function') { throw new Error( @@ -180,7 +183,7 @@ export class OidcAuthProvider implements OAuthHandlers { // Use this function to grab the user profile info from the token // Then populate the profile with it - private async handleResult(result: AuthResult): Promise { + private async handleResult(result: OidcAuthResult): Promise { const { profile } = await this.authHandler(result); const response: OAuthResponse = { providerInfo: { @@ -210,27 +213,25 @@ export class OidcAuthProvider implements OAuthHandlers { } } -export const oAuth2DefaultSignInResolver: SignInResolver = async ( - info, - ctx, -) => { - const { profile } = info; +export const oAuth2DefaultSignInResolver: SignInResolver = + async (info, ctx) => { + const { profile } = info; - if (!profile.email) { - throw new Error('Profile contained no email'); - } - const userId = profile.email.split('@')[0]; - const token = await ctx.tokenIssuer.issueToken({ - claims: { sub: userId, ent: [`user:default/${userId}`] }, - }); - return { id: userId, token }; -}; + if (!profile.email) { + throw new Error('Profile contained no email'); + } + const userId = profile.email.split('@')[0]; + const token = await ctx.tokenIssuer.issueToken({ + claims: { sub: userId, ent: [`user:default/${userId}`] }, + }); + return { id: userId, token }; + }; export type OidcProviderOptions = { - authHandler?: AuthHandler; + authHandler?: AuthHandler; signIn?: { - resolver?: SignInResolver; + resolver?: SignInResolver; }; }; @@ -260,7 +261,7 @@ export const createOidcProvider = ( tokenIssuer, }); - const authHandler: AuthHandler = options?.authHandler + const authHandler: AuthHandler = options?.authHandler ? options.authHandler : async ({ userinfo }) => ({ profile: { @@ -271,7 +272,7 @@ export const createOidcProvider = ( }); const signInResolverFn = options?.signIn?.resolver ?? oAuth2DefaultSignInResolver; - const signInResolver: SignInResolver = info => + const signInResolver: SignInResolver = info => signInResolverFn(info, { catalogIdentityClient, tokenIssuer, From 699c2e9ddcd78a07811aae8c31008019a689ca25 Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Thu, 9 Dec 2021 12:33:18 +0100 Subject: [PATCH 034/189] added a changeset and generate api reports Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- .changeset/strong-paws-laugh.md | 5 +++++ plugins/auth-backend/api-report.md | 29 ++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .changeset/strong-paws-laugh.md diff --git a/.changeset/strong-paws-laugh.md b/.changeset/strong-paws-laugh.md new file mode 100644 index 0000000000..de39440e34 --- /dev/null +++ b/.changeset/strong-paws-laugh.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +export minimal typescript types for OIDC provider diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index a637118130..ca212e0ad8 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -258,7 +258,6 @@ export const createOAuth2Provider: ( options?: OAuth2ProviderOptions | undefined, ) => AuthProviderFactory; -// Warning: (ae-forgotten-export) The symbol "OidcProviderOptions" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "createOidcProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -534,6 +533,34 @@ export type OAuthState = { origin?: string; }; +// Warning: (ae-missing-release-tag) "OidcAuthHandler" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type OidcAuthHandler = AuthHandler; + +// Warning: (ae-missing-release-tag) "OidcAuthResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type OidcAuthResult = { + tokenset: TokenSet; + userinfo: UserinfoResponse; +}; + +// Warning: (ae-missing-release-tag) "OidcProviderOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type OidcProviderOptions = { + authHandler?: AuthHandler; + signIn?: { + resolver?: SignInResolver; + }; +}; + +// Warning: (ae-missing-release-tag) "OidcSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type OidcSignInResolver = SignInResolver; + // Warning: (ae-missing-release-tag) "oktaEmailSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) From 90f8f33355fd3a15fe68fcc08eb4d3c409dc1db8 Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Thu, 9 Dec 2021 12:57:18 -0500 Subject: [PATCH 035/189] Adding changes for PR review comments to add description for projectname Signed-off-by: Balasundaram --- .../scaffolder/actions/builtin/publish/gitlabMergeRequest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts index b333b5234d..b64ec1a83d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -53,7 +53,7 @@ export const createPublishGitlabMergeRequestAction = (options: { projectid: { type: 'string', title: 'projectid', - description: 'Project ID of the Gitlab Project', + description: 'Project ID/Name(slug) of the Gitlab Project', }, title: { type: 'string', @@ -81,7 +81,7 @@ export const createPublishGitlabMergeRequestAction = (options: { type: 'object', properties: { projectid: { - title: 'Gitlab Project id', + title: 'Gitlab Project id/Name(slug)', type: 'string', }, mergeRequestURL: { From ed52f74ab3c2dceb27f07bd0ba509fdcf732a673 Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Thu, 9 Dec 2021 13:06:04 -0500 Subject: [PATCH 036/189] Adding changeset for the #8277 Signed-off-by: Balasundaram --- .changeset/nervous-hounds-attend.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nervous-hounds-attend.md diff --git a/.changeset/nervous-hounds-attend.md b/.changeset/nervous-hounds-attend.md new file mode 100644 index 0000000000..a9eed8422d --- /dev/null +++ b/.changeset/nervous-hounds-attend.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Adding changes to create Gitlab Merge Request using custom action From 646e5d01d8baff61429be714451528bc0d7fa81d Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Thu, 9 Dec 2021 13:13:04 -0500 Subject: [PATCH 037/189] Changing minor to patch changeset for the #8277 Signed-off-by: Balasundaram --- .changeset/nervous-hounds-attend.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/nervous-hounds-attend.md b/.changeset/nervous-hounds-attend.md index a9eed8422d..15ca4aa085 100644 --- a/.changeset/nervous-hounds-attend.md +++ b/.changeset/nervous-hounds-attend.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder-backend': minor +'@backstage/plugin-scaffolder-backend': patch --- Adding changes to create Gitlab Merge Request using custom action From ccf48de9ba82aa62d23b4e3f4aa0a4dcc66b660a Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Thu, 9 Dec 2021 13:16:48 -0500 Subject: [PATCH 038/189] Adding changes to remove comments Signed-off-by: Balasundaram --- .../scaffolder/actions/builtin/publish/gitlabMergeRequest.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts index b64ec1a83d..2ac369249b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/gitlabMergeRequest.ts @@ -97,10 +97,6 @@ export const createPublishGitlabMergeRequestAction = (options: { const { host } = parseRepoUrl(repoUrl, integrations); const integrationConfig = integrations.gitlab.byHost(host); - /* const a : Types.CommitAction = { - action: 'create', - filePath: '' - };*/ const actions: Types.CommitAction[] = []; const destinationBranch = ctx.input.branchName; From a516412bb3777ea59af09a995cdb6fb4df0b8e33 Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Thu, 9 Dec 2021 14:50:19 -0500 Subject: [PATCH 039/189] Adding public api report Signed-off-by: Balasundaram --- plugins/scaffolder-backend/api-report.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 6ed4625f66..bf03443419 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -179,6 +179,13 @@ export function createPublishGitlabAction(options: { config: Config; }): TemplateAction; +// Warning: (ae-missing-release-tag) "createPublishGitlabMergeRequestAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const createPublishGitlabMergeRequestAction: (options: { + integrations: ScmIntegrationRegistry; +}) => TemplateAction; + // Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) From abd6ff3430bfb55aab65a420310bb45c25c76658 Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Thu, 9 Dec 2021 21:32:31 +0100 Subject: [PATCH 040/189] improve exported type to include resolver and handlers for auth providers, add additional types to fix api-doc related warnings Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- plugins/auth-backend/api-report.md | 42 ++++++++++++------- plugins/auth-backend/src/providers/index.ts | 4 ++ .../auth-backend/src/providers/oidc/index.ts | 7 +--- .../src/providers/oidc/provider.ts | 19 ++++++--- plugins/auth-backend/src/providers/types.ts | 15 +++++++ 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index ca212e0ad8..c076058a0c 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -47,6 +47,16 @@ export type AtlassianProviderOptions = { }; }; +// @public +export type AuthHandler = ( + input: AuthResult, +) => Promise; + +// @public +export type AuthHandlerResult = { + profile: ProfileInfo; +}; + // Warning: (ae-missing-release-tag) "AuthProviderFactory" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -533,11 +543,6 @@ export type OAuthState = { origin?: string; }; -// Warning: (ae-missing-release-tag) "OidcAuthHandler" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type OidcAuthHandler = AuthHandler; - // Warning: (ae-missing-release-tag) "OidcAuthResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -546,9 +551,9 @@ export type OidcAuthResult = { userinfo: UserinfoResponse; }; -// Warning: (ae-missing-release-tag) "OidcProviderOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (tsdoc-undefined-tag) The TSDoc tag "@BackstageSignInResult" is not defined in this configuration // -// @public (undocumented) +// @public export type OidcProviderOptions = { authHandler?: AuthHandler; signIn?: { @@ -556,11 +561,6 @@ export type OidcProviderOptions = { }; }; -// Warning: (ae-missing-release-tag) "OidcSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type OidcSignInResolver = SignInResolver; - // Warning: (ae-missing-release-tag) "oktaEmailSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -633,6 +633,22 @@ export type SamlProviderOptions = { }; }; +// @public +export type SignInInfo = { + profile: ProfileInfo; + result: AuthResult; +}; + +// @public +export type SignInResolver = ( + info: SignInInfo, + context: { + tokenIssuer: TokenIssuer; + catalogIdentityClient: CatalogIdentityClient; + logger: Logger_2; + }, +) => Promise; + // Warning: (ae-missing-release-tag) "TokenIssuer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -664,8 +680,6 @@ export type WebMessageResponse = // Warnings were encountered during analysis: // // src/identity/types.d.ts:31:9 - (ae-forgotten-export) The symbol "AnyJWK" needs to be exported by the entry point index.d.ts -// src/providers/atlassian/provider.d.ts:37:5 - (ae-forgotten-export) The symbol "AuthHandler" needs to be exported by the entry point index.d.ts -// src/providers/atlassian/provider.d.ts:42:9 - (ae-forgotten-export) The symbol "SignInResolver" needs to be exported by the entry point index.d.ts // src/providers/aws-alb/provider.d.ts:77:5 - (ae-forgotten-export) The symbol "AwsAlbResult" needs to be exported by the entry point index.d.ts // src/providers/github/provider.d.ts:71:58 - (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag // src/providers/github/provider.d.ts:71:90 - (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag diff --git a/plugins/auth-backend/src/providers/index.ts b/plugins/auth-backend/src/providers/index.ts index 4ecbb98fd2..9589e97265 100644 --- a/plugins/auth-backend/src/providers/index.ts +++ b/plugins/auth-backend/src/providers/index.ts @@ -34,6 +34,10 @@ export type { AuthProviderRouteHandlers, AuthProviderFactoryOptions, AuthProviderFactory, + AuthHandler, + AuthHandlerResult, + SignInResolver, + SignInInfo, } from './types'; // These types are needed for a postMessage from the login pop-up diff --git a/plugins/auth-backend/src/providers/oidc/index.ts b/plugins/auth-backend/src/providers/oidc/index.ts index 1d0f592359..39bd02928d 100644 --- a/plugins/auth-backend/src/providers/oidc/index.ts +++ b/plugins/auth-backend/src/providers/oidc/index.ts @@ -13,10 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export type { - OidcSignInResolver, - OidcAuthHandler, - OidcAuthResult, - OidcProviderOptions, -} from './provider'; +export type { OidcAuthResult, OidcProviderOptions } from './provider'; export { createOidcProvider } from './provider'; diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index b9ae15f370..347820d2d6 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -61,16 +61,13 @@ export type OidcAuthResult = { userinfo: UserinfoResponse; }; -export type OidcSignInResolver = SignInResolver; -export type OidcAuthHandler = AuthHandler; - export type Options = OAuthProviderOptions & { metadataUrl: string; scope?: string; prompt?: string; tokenSignedResponseAlg?: string; - signInResolver?: OidcSignInResolver; - authHandler: OidcAuthHandler; + signInResolver?: SignInResolver; + authHandler: AuthHandler; tokenIssuer: TokenIssuer; catalogIdentityClient: CatalogIdentityClient; logger: Logger; @@ -227,6 +224,18 @@ export const oAuth2DefaultSignInResolver: SignInResolver = return { id: userId, token }; }; +/** + * OIDC provider callback options. An auth handler and a sign in resolver + * can be passed while creating a OIDC provider. + * + * authHandler : called after sign in was successful, a new object must be returned which includes a profile + * signInResolver: called after sign in was successful, expects to return a new @BackstageSignInResult + * + * Both options are optional. There is fallback for authHandler where the default handler expect an e-mail explicitly + * otherwise it throws an error + * + * @public + */ export type OidcProviderOptions = { authHandler?: AuthHandler; diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index dafa52163c..6e61682f86 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -240,6 +240,10 @@ export type ProfileInfo = { picture?: string; }; +/** + * type of sign in information context, includes the profile information and authentication result which contains auth. related information + * @public + */ export type SignInInfo = { /** * The simple profile passed down for use in the frontend. @@ -252,6 +256,11 @@ export type SignInInfo = { result: AuthResult; }; +/** + * Sign in resolver type describes the function which handles the result of a successful authentication + * and must return a valid BackStageSignInResult + * @public + */ export type SignInResolver = ( info: SignInInfo, context: { @@ -261,6 +270,10 @@ export type SignInResolver = ( }, ) => Promise; +/** + * The return type of authentication handler which must contain a valid profile information + * @public + */ export type AuthHandlerResult = { profile: ProfileInfo }; /** @@ -270,6 +283,8 @@ export type AuthHandlerResult = { profile: ProfileInfo }; * * Throwing an error in the function will cause the authentication to fail, making it * possible to use this function as a way to limit access to a certain group of users. + * + * @public */ export type AuthHandler = ( input: AuthResult, From e0c63b37db172ed75ddf88ec158e2de8f114758d Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Thu, 9 Dec 2021 21:37:57 +0100 Subject: [PATCH 041/189] add missing documentation for OidcAuthResult Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- plugins/auth-backend/api-report.md | 4 +--- plugins/auth-backend/src/providers/oidc/provider.ts | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index c076058a0c..fd8d357a09 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -543,9 +543,7 @@ export type OAuthState = { origin?: string; }; -// Warning: (ae-missing-release-tag) "OidcAuthResult" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public export type OidcAuthResult = { tokenset: TokenSet; userinfo: UserinfoResponse; diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index 347820d2d6..98988ae6f7 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -56,6 +56,10 @@ type OidcImpl = { client: Client; }; +/** + * authentication result for the OIDC which includes the token set and user information (a profile response sent by OIDC server) + * @public + */ export type OidcAuthResult = { tokenset: TokenSet; userinfo: UserinfoResponse; From 0f645a7947e42437349b35981c1f0d5636b2a485 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Fri, 10 Dec 2021 02:47:21 +0530 Subject: [PATCH 042/189] add OwnedEntityPicker field Signed-off-by: mufaddal motiwala --- .changeset/perfect-buses-collect.md | 5 + .../OwnedEntityPicker.test.tsx | 137 ++++++++++++++++++ .../OwnedEntityPicker/OwnedEntityPicker.tsx | 86 +++++++++++ .../fields/OwnedEntityPicker/index.ts | 16 ++ .../scaffolder/src/components/fields/index.ts | 1 + plugins/scaffolder/src/extensions/default.ts | 5 + plugins/scaffolder/src/index.ts | 2 + plugins/scaffolder/src/plugin.ts | 8 + 8 files changed, 260 insertions(+) create mode 100644 .changeset/perfect-buses-collect.md create mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx create mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx create mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts diff --git a/.changeset/perfect-buses-collect.md b/.changeset/perfect-buses-collect.md new file mode 100644 index 0000000000..cd7b8164cf --- /dev/null +++ b/.changeset/perfect-buses-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Added OwnedEntityPicker field which displays Owned Entities in options diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx new file mode 100644 index 0000000000..ef6fc1b648 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx @@ -0,0 +1,137 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Entity } from '@backstage/catalog-model'; +import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { FieldProps } from '@rjsf/core'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { OwnedEntityPicker } from './OwnedEntityPicker'; + +const makeEntity = (kind: string, namespace: string, name: string): Entity => ({ + apiVersion: 'backstage.io/v1beta1', + kind, + metadata: { namespace, name }, +}); + +describe('', () => { + let entities: Entity[]; + const onChange = jest.fn(); + const schema = {}; + const required = false; + let uiSchema: { + 'ui:options': { allowedKinds?: string[]; defaultKind?: string }; + }; + const rawErrors: string[] = []; + const formData = undefined; + + let props: FieldProps; + + const catalogApi: jest.Mocked = { + getLocationById: jest.fn(), + getEntityByName: jest.fn(), + getEntities: jest.fn(async () => ({ items: entities })), + addLocation: jest.fn(), + getLocationByEntity: jest.fn(), + removeEntityByUid: jest.fn(), + } as any; + let Wrapper: React.ComponentType; + + beforeEach(() => { + entities = [ + makeEntity('Group', 'default', 'team-a'), + makeEntity('Group', 'default', 'squad-b'), + ]; + + Wrapper = ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ); + }); + + afterEach(() => jest.resetAllMocks()); + + describe('without allowedKinds', () => { + beforeEach(() => { + uiSchema = { 'ui:options': {} }; + props = { + onChange, + schema, + required, + uiSchema, + rawErrors, + formData, + } as unknown as FieldProps; + + catalogApi.getEntities.mockResolvedValue({ items: entities }); + }); + + it('searches for all entities', async () => { + await renderInTestApp( + + + , + ); + + expect(catalogApi.getEntities).toHaveBeenCalledWith(undefined); + }); + + it('updates even if there is not an exact match', async () => { + const { getByLabelText } = await renderInTestApp( + + + , + ); + const input = getByLabelText('Entity'); + + userEvent.type(input, 'squ'); + input.blur(); + + expect(onChange).toHaveBeenCalledWith('squ'); + }); + }); + + describe('with allowedKinds', () => { + beforeEach(() => { + uiSchema = { 'ui:options': { allowedKinds: ['User'] } }; + props = { + onChange, + schema, + required, + uiSchema, + rawErrors, + formData, + } as unknown as FieldProps; + + catalogApi.getEntities.mockResolvedValue({ items: entities }); + }); + + it('searches for users and groups', async () => { + await renderInTestApp( + + + , + ); + + expect(catalogApi.getEntities).toHaveBeenCalledWith({ + filter: { + kind: ['User'], + }, + }); + }); + }); +}); diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx new file mode 100644 index 0000000000..b73158ac60 --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -0,0 +1,86 @@ +/* + * 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 { useApi } from '@backstage/core-plugin-api'; +import { + catalogApiRef, + formatEntityRefTitle, + useEntityOwnership, +} from '@backstage/plugin-catalog-react'; +import { TextField } from '@material-ui/core'; +import FormControl from '@material-ui/core/FormControl'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import { FieldProps } from '@rjsf/core'; +import React from 'react'; +import { useAsync } from 'react-use'; + +export const OwnedEntityPicker = ({ + onChange, + schema: { title = 'Entity', description = 'An entity from the catalog' }, + required, + uiSchema, + rawErrors, + formData, + idSchema, +}: FieldProps) => { + const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[]; + const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined; + const catalogApi = useApi(catalogApiRef); + const { isOwnedEntity } = useEntityOwnership(); + + const { value: entities, loading } = useAsync(() => + catalogApi.getEntities( + allowedKinds ? { filter: { kind: allowedKinds } } : undefined, + ), + ); + + const entityRefs = entities?.items + .map(e => + isOwnedEntity(e) ? formatEntityRefTitle(e, { defaultKind }) : null, + ) + .filter(n => n); + + const onSelect = (_: any, value: string | null) => { + onChange(value || ''); + }; + return ( + 0 && !formData} + > + ( + + )} + /> + + ); +}; diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts new file mode 100644 index 0000000000..7cf5add6eb --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { OwnedEntityPicker } from './OwnedEntityPicker'; diff --git a/plugins/scaffolder/src/components/fields/index.ts b/plugins/scaffolder/src/components/fields/index.ts index 5adc3d3141..299470e220 100644 --- a/plugins/scaffolder/src/components/fields/index.ts +++ b/plugins/scaffolder/src/components/fields/index.ts @@ -18,3 +18,4 @@ export * from './EntityPicker'; export * from './OwnerPicker'; export * from './RepoUrlPicker'; export * from './TextValuePicker'; +export * from './OwnedEntityPicker'; diff --git a/plugins/scaffolder/src/extensions/default.ts b/plugins/scaffolder/src/extensions/default.ts index be934546b3..12a29809e0 100644 --- a/plugins/scaffolder/src/extensions/default.ts +++ b/plugins/scaffolder/src/extensions/default.ts @@ -24,6 +24,7 @@ import { RepoUrlPicker, } from '../components/fields/RepoUrlPicker'; import { FieldExtensionOptions } from './types'; +import { OwnedEntityPicker } from '../components/fields/OwnedEntityPicker'; export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = [ { @@ -44,4 +45,8 @@ export const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions[] = [ component: OwnerPicker, name: 'OwnerPicker', }, + { + component: OwnedEntityPicker, + name: 'OwnedEntityPicker', + }, ]; diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index 0180c24b90..dfbd2af296 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -31,6 +31,7 @@ export { EntityPickerFieldExtension, EntityNamePickerFieldExtension, OwnerPickerFieldExtension, + OwnedEntityPickerFieldExtension, RepoUrlPickerFieldExtension, ScaffolderPage, scaffolderPlugin as plugin, @@ -42,6 +43,7 @@ export { OwnerPicker, RepoUrlPicker, TextValuePicker, + OwnedEntityPicker, } from './components/fields'; export { FavouriteTemplate } from './components/FavouriteTemplate'; export { TemplateList } from './components/TemplateList'; diff --git a/plugins/scaffolder/src/plugin.ts b/plugins/scaffolder/src/plugin.ts index b6ef0ebe17..95cad50eba 100644 --- a/plugins/scaffolder/src/plugin.ts +++ b/plugins/scaffolder/src/plugin.ts @@ -35,6 +35,7 @@ import { discoveryApiRef, identityApiRef, } from '@backstage/core-plugin-api'; +import { OwnedEntityPicker } from './components/fields/OwnedEntityPicker'; export const scaffolderPlugin = createPlugin({ id: 'scaffolder', @@ -95,3 +96,10 @@ export const ScaffolderPage = scaffolderPlugin.provide( mountPoint: rootRouteRef, }), ); + +export const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide( + createScaffolderFieldExtension({ + component: OwnedEntityPicker, + name: 'OwnedEntityPicker', + }), +); From 189ba4c340a910e127345e01b3221b6d1e7eaf77 Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Fri, 3 Dec 2021 15:50:09 -0500 Subject: [PATCH 043/189] Overwrite sqlite filepath per plugin Signed-off-by: Joe Porpeglia --- .../src/database/DatabaseManager.test.ts | 5 ++++- .../src/database/DatabaseManager.ts | 12 +++++++--- .../src/database/connectors/sqlite3.test.ts | 22 ------------------- .../src/database/connectors/sqlite3.ts | 13 ----------- 4 files changed, 13 insertions(+), 39 deletions(-) diff --git a/packages/backend-common/src/database/DatabaseManager.test.ts b/packages/backend-common/src/database/DatabaseManager.test.ts index bd2e7b9f71..d5271bc2b5 100644 --- a/packages/backend-common/src/database/DatabaseManager.test.ts +++ b/packages/backend-common/src/database/DatabaseManager.test.ts @@ -282,7 +282,10 @@ describe('DatabaseManager', () => { expect(baseConfig.get().client).toEqual('sqlite3'); // sqlite3 uses 'filename' instead of 'database' - expect(overrides).toHaveProperty('connection.filename'); + expect(overrides).toHaveProperty( + 'connection.filename', + `plugin_with_different_client/${pluginId}`, + ); }); it('provides database client specific base from plugin connection string when client set under plugin', async () => { diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts index 8e23a219ec..977516a18b 100644 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ b/packages/backend-common/src/database/DatabaseManager.ts @@ -114,10 +114,16 @@ export class DatabaseManager { const connection = this.getConnectionConfig(pluginId); if (this.getClientType(pluginId).client === 'sqlite3') { + const sqliteFilename = (connection as Knex.Sqlite3ConnectionConfig) + ?.filename; + + // if persisting to a file, create separate files per plugin to avoid db migration issues. + if (sqliteFilename !== ':memory:') { + return `${sqliteFilename}/${pluginId}`; + } + // sqlite database name should fallback to ':memory:' as a special case - return ( - (connection as Knex.Sqlite3ConnectionConfig)?.filename ?? ':memory:' - ); + return ':memory:'; } const databaseName = (connection as Knex.ConnectionConfig)?.database; diff --git a/packages/backend-common/src/database/connectors/sqlite3.test.ts b/packages/backend-common/src/database/connectors/sqlite3.test.ts index b9da19d247..cfc9f61527 100644 --- a/packages/backend-common/src/database/connectors/sqlite3.test.ts +++ b/packages/backend-common/src/database/connectors/sqlite3.test.ts @@ -73,28 +73,6 @@ describe('sqlite3', () => { }); }); - it('builds a persistent connection per database', () => { - expect( - buildSqliteDatabaseConfig( - createConfig({ - filename: path.join('path', 'to', 'foo'), - }), - { - connection: { - database: 'my-database', - }, - }, - ), - ).toEqual({ - client: 'sqlite3', - connection: { - filename: path.join('path', 'to', 'foo', 'my-database.sqlite'), - database: 'my-database', - }, - useNullAsDefault: true, - }); - }); - it('replaces the connection with an override', () => { expect( buildSqliteDatabaseConfig(createConfig(':memory:'), { diff --git a/packages/backend-common/src/database/connectors/sqlite3.ts b/packages/backend-common/src/database/connectors/sqlite3.ts index 3dfecd7e6b..41f80ed293 100644 --- a/packages/backend-common/src/database/connectors/sqlite3.ts +++ b/packages/backend-common/src/database/connectors/sqlite3.ts @@ -86,19 +86,6 @@ export function buildSqliteDatabaseConfig( overrides, ); - // If we don't create an in-memory database, interpret the connection string - // as a directory that contains multiple sqlite files based on the database - // name. - const database = (config.connection as Knex.ConnectionConfig).database; - const sqliteConnection = config.connection as Knex.Sqlite3ConnectionConfig; - - if (database && sqliteConnection.filename !== ':memory:') { - sqliteConnection.filename = path.join( - sqliteConnection.filename, - `${database}.sqlite`, - ); - } - return config; } From e51369952ed91364d217ca560e113fe4b559a993 Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Fri, 3 Dec 2021 16:07:30 -0500 Subject: [PATCH 044/189] Add suffix to plugin sqlite db file Signed-off-by: Joe Porpeglia --- packages/backend-common/src/database/DatabaseManager.test.ts | 2 +- packages/backend-common/src/database/DatabaseManager.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend-common/src/database/DatabaseManager.test.ts b/packages/backend-common/src/database/DatabaseManager.test.ts index d5271bc2b5..2587a70423 100644 --- a/packages/backend-common/src/database/DatabaseManager.test.ts +++ b/packages/backend-common/src/database/DatabaseManager.test.ts @@ -284,7 +284,7 @@ describe('DatabaseManager', () => { // sqlite3 uses 'filename' instead of 'database' expect(overrides).toHaveProperty( 'connection.filename', - `plugin_with_different_client/${pluginId}`, + `plugin_with_different_client/${pluginId}.sqlite`, ); }); diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts index 977516a18b..aee47aedc1 100644 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ b/packages/backend-common/src/database/DatabaseManager.ts @@ -119,7 +119,7 @@ export class DatabaseManager { // if persisting to a file, create separate files per plugin to avoid db migration issues. if (sqliteFilename !== ':memory:') { - return `${sqliteFilename}/${pluginId}`; + return `${sqliteFilename}/${pluginId}.sqlite`; } // sqlite database name should fallback to ':memory:' as a special case From fe24bc9a323afd69fb44ab410b910ea84a1be057 Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Fri, 3 Dec 2021 16:14:55 -0500 Subject: [PATCH 045/189] Add changeset Signed-off-by: Joe Porpeglia --- .changeset/pink-ladybugs-share.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/pink-ladybugs-share.md diff --git a/.changeset/pink-ladybugs-share.md b/.changeset/pink-ladybugs-share.md new file mode 100644 index 0000000000..c8f2e8f206 --- /dev/null +++ b/.changeset/pink-ladybugs-share.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': minor +--- + +Each plugin now saves to a separate sqlite database file when `connection.filename` is provided in the sqlite config. From ef8392dab249014fe7a51e152bde8d4dc2e42e43 Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Mon, 6 Dec 2021 11:24:09 -0500 Subject: [PATCH 046/189] Use path.join Signed-off-by: Joe Porpeglia --- packages/backend-common/src/database/DatabaseManager.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts index aee47aedc1..b026e83b4e 100644 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ b/packages/backend-common/src/database/DatabaseManager.ts @@ -28,6 +28,7 @@ import { normalizeConnection, } from './connection'; import { PluginDatabaseManager } from './types'; +import path from 'path'; /** * Provides a config lookup path for a plugin's config block. @@ -119,7 +120,7 @@ export class DatabaseManager { // if persisting to a file, create separate files per plugin to avoid db migration issues. if (sqliteFilename !== ':memory:') { - return `${sqliteFilename}/${pluginId}.sqlite`; + return path.join(sqliteFilename, `${pluginId}.sqlite`); } // sqlite database name should fallback to ':memory:' as a special case From c2a478d7f948c63db8b2e3dc23e64090048eca4b Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Mon, 6 Dec 2021 11:26:10 -0500 Subject: [PATCH 047/189] Update changeset Signed-off-by: Joe Porpeglia --- .changeset/pink-ladybugs-share.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.changeset/pink-ladybugs-share.md b/.changeset/pink-ladybugs-share.md index c8f2e8f206..7edeb12f6a 100644 --- a/.changeset/pink-ladybugs-share.md +++ b/.changeset/pink-ladybugs-share.md @@ -1,5 +1,6 @@ --- -'@backstage/backend-common': minor +'@backstage/backend-common': path --- Each plugin now saves to a separate sqlite database file when `connection.filename` is provided in the sqlite config. +Any existing sqlite database files will be ignored. From e081edc783bd9da4594ae3619d2f5ad50ee0c4da Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Mon, 6 Dec 2021 11:34:31 -0500 Subject: [PATCH 048/189] Fix changset typo Signed-off-by: Joe Porpeglia --- .changeset/pink-ladybugs-share.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/pink-ladybugs-share.md b/.changeset/pink-ladybugs-share.md index 7edeb12f6a..83f5b8b78a 100644 --- a/.changeset/pink-ladybugs-share.md +++ b/.changeset/pink-ladybugs-share.md @@ -1,5 +1,5 @@ --- -'@backstage/backend-common': path +'@backstage/backend-common': patch --- Each plugin now saves to a separate sqlite database file when `connection.filename` is provided in the sqlite config. From cf192e1a724368230f97d4fa1a6b98cac6266638 Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Mon, 6 Dec 2021 12:18:50 -0500 Subject: [PATCH 049/189] Check if sqlite filename was provided before making plugin-specific filename Signed-off-by: Joe Porpeglia --- packages/backend-common/src/database/DatabaseManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts index b026e83b4e..a00a4991cb 100644 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ b/packages/backend-common/src/database/DatabaseManager.ts @@ -119,7 +119,7 @@ export class DatabaseManager { ?.filename; // if persisting to a file, create separate files per plugin to avoid db migration issues. - if (sqliteFilename !== ':memory:') { + if (sqliteFilename && sqliteFilename !== ':memory:') { return path.join(sqliteFilename, `${pluginId}.sqlite`); } From d9a286bd56e3dd15b27f0b44daa148746ce3eea3 Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Wed, 8 Dec 2021 13:49:26 -0500 Subject: [PATCH 050/189] Use path.join for tests Signed-off-by: Joe Porpeglia --- packages/backend-common/src/database/DatabaseManager.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend-common/src/database/DatabaseManager.test.ts b/packages/backend-common/src/database/DatabaseManager.test.ts index 2587a70423..c72c740765 100644 --- a/packages/backend-common/src/database/DatabaseManager.test.ts +++ b/packages/backend-common/src/database/DatabaseManager.test.ts @@ -15,6 +15,7 @@ */ import { ConfigReader } from '@backstage/config'; import { omit } from 'lodash'; +import path from 'path'; import { createDatabaseClient, ensureDatabaseExists, @@ -284,7 +285,7 @@ describe('DatabaseManager', () => { // sqlite3 uses 'filename' instead of 'database' expect(overrides).toHaveProperty( 'connection.filename', - `plugin_with_different_client/${pluginId}.sqlite`, + path.join('plugin_with_different_client', `${pluginId}.sqlite`), ); }); From 63f5bc5f2cf699b0a479237331ad823dadd54ff5 Mon Sep 17 00:00:00 2001 From: Joe Porpeglia Date: Thu, 9 Dec 2021 17:59:56 -0500 Subject: [PATCH 051/189] Add connection.directory support for sqlite Signed-off-by: Joe Porpeglia --- .../src/database/DatabaseManager.test.ts | 128 ++++++++++++++---- .../src/database/DatabaseManager.ts | 27 +++- 2 files changed, 125 insertions(+), 30 deletions(-) diff --git a/packages/backend-common/src/database/DatabaseManager.test.ts b/packages/backend-common/src/database/DatabaseManager.test.ts index c72c740765..a48b1584aa 100644 --- a/packages/backend-common/src/database/DatabaseManager.test.ts +++ b/packages/backend-common/src/database/DatabaseManager.test.ts @@ -171,28 +171,6 @@ describe('DatabaseManager', () => { ); }); - it('uses top level sqlite database filename if plugin config is not present', async () => { - const testManager = DatabaseManager.fromConfig( - new ConfigReader({ - backend: { - database: { - client: 'sqlite3', - connection: 'some-file-path', - }, - }, - }), - ); - - await testManager.forPlugin('pluginwithoutconfig').getClient(); - const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); - const [_, overrides] = mockCalls[0]; - - expect(overrides).toHaveProperty( - 'connection.filename', - expect.stringContaining('some-file-path'), - ); - }); - it('provides an inmemory sqlite database if top level is also inmemory and plugin config is not present', async () => { const testManager = DatabaseManager.fromConfig( new ConfigReader({ @@ -215,6 +193,110 @@ describe('DatabaseManager', () => { ); }); + it('throws if top level sqlite filename is provided', async () => { + const testManager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'sqlite3', + connection: 'some-file-path', + }, + }, + }), + ); + + await expect( + testManager.forPlugin('pluginwithoutconfig').getClient(), + ).rejects.toBeInstanceOf(Error); + }); + + it('creates plugin-specific sqlite files when plugin config is not present', async () => { + const testManager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'sqlite3', + connection: { + directory: 'sqlite-files', + }, + }, + }, + }), + ); + + await testManager.forPlugin('pluginwithoutconfig').getClient(); + const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); + const [_, overrides] = mockCalls[0]; + + expect(overrides).toHaveProperty( + 'connection.filename', + path.join('sqlite-files', 'pluginwithoutconfig.sqlite'), + ); + }); + + it('uses sqlite directory from top level config and filename from plugin config', async () => { + const testManager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'sqlite3', + connection: { + directory: 'sqlite-files', + }, + plugin: { + test: { + connection: { + filename: 'other.sqlite', + }, + }, + }, + }, + }, + }), + ); + + await testManager.forPlugin('test').getClient(); + const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); + const [_, overrides] = mockCalls[0]; + + expect(overrides).toHaveProperty( + 'connection.filename', + path.join('sqlite-files', 'other.sqlite'), + ); + }); + + it('uses sqlite directory and filename from plugin config', async () => { + const testManager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'sqlite3', + connection: { + directory: 'sqlite-files', + }, + plugin: { + test: { + connection: { + directory: 'custom-sqlite-files', + filename: 'other.sqlite', + }, + }, + }, + }, + }, + }), + ); + + await testManager.forPlugin('test').getClient(); + const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); + const [_, overrides] = mockCalls[0]; + + expect(overrides).toHaveProperty( + 'connection.filename', + path.join('custom-sqlite-files', 'other.sqlite'), + ); + }); + it('connects to a plugin database using a specific database name', async () => { // testdbname.connection.database is set in config await manager.forPlugin('testdbname').getClient(); @@ -285,7 +367,7 @@ describe('DatabaseManager', () => { // sqlite3 uses 'filename' instead of 'database' expect(overrides).toHaveProperty( 'connection.filename', - path.join('plugin_with_different_client', `${pluginId}.sqlite`), + 'plugin_with_different_client', ); }); diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts index a00a4991cb..5959c60c83 100644 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ b/packages/backend-common/src/database/DatabaseManager.ts @@ -115,16 +115,18 @@ export class DatabaseManager { const connection = this.getConnectionConfig(pluginId); if (this.getClientType(pluginId).client === 'sqlite3') { - const sqliteFilename = (connection as Knex.Sqlite3ConnectionConfig) - ?.filename; + const sqliteFilename: string | undefined = ( + connection as Knex.Sqlite3ConnectionConfig + ).filename; - // if persisting to a file, create separate files per plugin to avoid db migration issues. - if (sqliteFilename && sqliteFilename !== ':memory:') { - return path.join(sqliteFilename, `${pluginId}.sqlite`); + if (sqliteFilename === ':memory:') { + return sqliteFilename; } - // sqlite database name should fallback to ':memory:' as a special case - return ':memory:'; + const sqliteDirectory = + (connection as { directory?: string }).directory ?? '.'; + + return path.join(sqliteDirectory, sqliteFilename ?? `${pluginId}.sqlite`); } const databaseName = (connection as Knex.ConnectionConfig)?.database; @@ -212,6 +214,17 @@ export class DatabaseManager { this.config.get('connection'), this.config.getString('client'), ); + + if ( + client === 'sqlite3' && + 'filename' in baseConnection && + baseConnection.filename !== ':memory:' + ) { + throw new Error( + '`connection.filename` is not supported for the base sqlite connection. Prefer `connection.directory` or provide a filename for the plugin connection instead.', + ); + } + // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The // `database` property from the base connection is omitted unless `pluginDivisionMode` // is set to `schema`. SQLite3's `filename` property is an exception as this is used as a From aa7a73e947ac88b561e6454ef263a07f58927e41 Mon Sep 17 00:00:00 2001 From: Emma Indal Date: Fri, 10 Dec 2021 10:12:13 +0100 Subject: [PATCH 052/189] [TechDocs] Add metadata to cli docs (#8445) Signed-off-by: Emma Indal --- docs/features/techdocs/cli.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/features/techdocs/cli.md b/docs/features/techdocs/cli.md index 5548adf7f0..30cb8314a0 100644 --- a/docs/features/techdocs/cli.md +++ b/docs/features/techdocs/cli.md @@ -1,4 +1,9 @@ -# TechDocs CLI +--- +id: cli +title: TechDocs CLI +# prettier-ignore +description: TechDocs CLI - a utility command line interface for managing TechDocs sites in Backstage. +--- Utility command line interface for managing TechDocs sites in [Backstage](https://github.com/backstage/backstage). From 4c0f0b2003587b9e30c98d0daa98bf88c0dea695 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 10 Dec 2021 10:47:37 +0100 Subject: [PATCH 053/189] catalog-react: removed core-app-api dependency Signed-off-by: Patrik Oldsberg --- .changeset/witty-singers-occur.md | 5 +++++ plugins/catalog-react/package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/witty-singers-occur.md diff --git a/.changeset/witty-singers-occur.md b/.changeset/witty-singers-occur.md new file mode 100644 index 0000000000..e039ee65a7 --- /dev/null +++ b/.changeset/witty-singers-occur.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Removed dependency on `@backstage/core-app-api`. diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index b5a6884fa5..866ba10add 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -31,7 +31,6 @@ "dependencies": { "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-app-api": "^0.2.0", "@backstage/core-components": "^0.8.0", "@backstage/core-plugin-api": "^0.3.0", "@backstage/errors": "^0.1.4", @@ -54,6 +53,7 @@ }, "devDependencies": { "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.0", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", From e3d163d48fbe14bca83160e4519244571f94c7d5 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 10 Dec 2021 10:52:26 +0100 Subject: [PATCH 054/189] catalog-react: release core-app-api dependency removal Signed-off-by: Patrik Oldsberg --- .changeset/witty-singers-occur.md | 5 ----- plugins/catalog-react/CHANGELOG.md | 6 ++++++ plugins/catalog-react/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/witty-singers-occur.md diff --git a/.changeset/witty-singers-occur.md b/.changeset/witty-singers-occur.md deleted file mode 100644 index e039ee65a7..0000000000 --- a/.changeset/witty-singers-occur.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Removed dependency on `@backstage/core-app-api`. diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index c628735ef1..5ebe626fad 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-catalog-react +## 0.6.6 + +### Patch Changes + +- 4c0f0b2003: Removed dependency on `@backstage/core-app-api`. + ## 0.6.5 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 866ba10add..da8300ae49 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "0.6.5", + "version": "0.6.6", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", From 3e92f22d2ec39aeca54f27b67e9de940d39e6ed8 Mon Sep 17 00:00:00 2001 From: Ben Lambert Date: Fri, 10 Dec 2021 11:01:15 +0100 Subject: [PATCH 055/189] Update .changeset/spicy-parents-fold.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ben Lambert Co-authored-by: Fredrik AdelΓΆw --- .changeset/spicy-parents-fold.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/spicy-parents-fold.md b/.changeset/spicy-parents-fold.md index 0fad18f31a..1ba056c7c8 100644 --- a/.changeset/spicy-parents-fold.md +++ b/.changeset/spicy-parents-fold.md @@ -4,7 +4,7 @@ Updated the root `package.json` to include files with `.cjs` and `.mjs` extensions in the `"lint-staged"` configuration. -The make this change to an existing app, apply the following changes to the `package.json` file: +To make this change to an existing app, apply the following changes to the `package.json` file: ```diff "lint-staged": { From 121787e87ebd37d6ed218bf129399cb6c7573366 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Fri, 10 Dec 2021 15:47:07 +0530 Subject: [PATCH 056/189] added api report Signed-off-by: mufaddal motiwala --- plugins/scaffolder/api-report.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 73fd8fae72..45419e82eb 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -96,6 +96,24 @@ export type FieldExtensionOptions = { validation?: CustomFieldValidator; }; +// Warning: (ae-missing-release-tag) "OwnedEntityPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const OwnedEntityPicker: ({ + onChange, + schema: { title, description }, + required, + uiSchema, + rawErrors, + formData, + idSchema, +}: FieldProps) => JSX.Element; + +// Warning: (ae-missing-release-tag) "OwnedEntityPickerFieldExtension" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const OwnedEntityPickerFieldExtension: () => null; + // Warning: (ae-missing-release-tag) "OwnerPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) From f2b4b348e44c676bc1e8174de93fa5e67c63f259 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Fri, 10 Dec 2021 10:20:59 +0000 Subject: [PATCH 057/189] Add tests for isLocationMatch function Signed-off-by: hiba-aldalaty --- packages/app/src/components/Root/Root.tsx | 18 +++- .../src/layout/Sidebar/utils.test.ts | 98 +++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 packages/core-components/src/layout/Sidebar/utils.test.ts diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 2d9b9b97f1..40834de76b 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -43,6 +43,8 @@ import { SidebarDivider, SidebarSpace, SidebarScrollWrapper, + SidebarSubmenu, + SidebarSubmenuItem, } from '@backstage/core-components'; import { AzurePullRequestsIcon } from '@backstage/plugin-azure-devops'; @@ -81,13 +83,27 @@ const SidebarLogo = () => { export const Root = ({ children }: PropsWithChildren<{}>) => ( - + {/* Global nav, not org-specific */} + + + + + + diff --git a/packages/core-components/src/layout/Sidebar/utils.test.ts b/packages/core-components/src/layout/Sidebar/utils.test.ts new file mode 100644 index 0000000000..b08dcda0fc --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/utils.test.ts @@ -0,0 +1,98 @@ +/* + * 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 { Location, Path } from 'history'; +import { isLocationMatch } from './utils'; + +describe('isLocationMatching', () => { + let currentLocation: Location; + let toLocation: Path; + + it('return false when pathname in target and current location differ', async () => { + currentLocation = { + pathname: '/catalog', + search: '?kind=component', + state: null, + hash: '', + key: '', + }; + toLocation = { + pathname: '/catalog-a', + search: '?kind=component', + hash: '', + }; + expect(isLocationMatch(currentLocation, toLocation)).toBe(false); + }); + + it('return true when exact match between current and target location parameters', async () => { + currentLocation = { + pathname: '/catalog', + search: '?kind=component', + state: null, + hash: '', + key: '', + }; + toLocation = { pathname: '/catalog', search: '?kind=component', hash: '' }; + expect(isLocationMatch(currentLocation, toLocation)).toBe(true); + }); + + it('return true when target query parameters are subset of current location query parameters', async () => { + currentLocation = { + pathname: '/catalog', + search: '?x=foo&y=bar', + state: null, + hash: '', + key: '', + }; + toLocation = { pathname: '/catalog', search: '?x=foo', hash: '' }; + expect(isLocationMatch(currentLocation, toLocation)).toBe(true); + }); + + it('return false when no matching query parameters between target and current location', async () => { + currentLocation = { + pathname: '/catalog', + search: '?y=bar', + state: null, + hash: '', + key: '', + }; + toLocation = { pathname: '/catalog', search: '?x=foo', hash: '' }; + expect(isLocationMatch(currentLocation, toLocation)).toBe(false); + }); + + it('return true when query parameters match in different order', async () => { + currentLocation = { + pathname: '/catalog', + search: '?y=bar&x=foo', + state: null, + hash: '', + key: '', + }; + toLocation = { pathname: '/catalog', search: '?x=foo&y=bar', hash: '' }; + expect(isLocationMatch(currentLocation, toLocation)).toBe(true); + }); + + it('return true when there is a matching query parameter alongside extra parameters', async () => { + currentLocation = { + pathname: '/catalog', + search: '?y=bar&x=foo', + state: null, + hash: '', + key: '', + }; + toLocation = { pathname: '/catalog', search: '', hash: '' }; + expect(isLocationMatch(currentLocation, toLocation)).toBe(true); + }); +}); From c13d0018ca20553e27afb90f2f59149bb4cc965d Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Fri, 10 Dec 2021 10:23:59 +0000 Subject: [PATCH 058/189] Undo changes to sidebar in Root.tsx used for testing Signed-off-by: hiba-aldalaty --- packages/app/src/components/Root/Root.tsx | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 40834de76b..657d64c3ed 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -83,27 +83,13 @@ const SidebarLogo = () => { export const Root = ({ children }: PropsWithChildren<{}>) => ( - + {/* Global nav, not org-specific */} - - - - - - From 501eb4ea9f25c77d8bd7f4337cd76076abb3d525 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Fri, 10 Dec 2021 10:24:59 +0000 Subject: [PATCH 059/189] Undo changes to sidebar in Root.tsx used for testing Signed-off-by: hiba-aldalaty --- packages/app/src/components/Root/Root.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 657d64c3ed..2d9b9b97f1 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -43,8 +43,6 @@ import { SidebarDivider, SidebarSpace, SidebarScrollWrapper, - SidebarSubmenu, - SidebarSubmenuItem, } from '@backstage/core-components'; import { AzurePullRequestsIcon } from '@backstage/plugin-azure-devops'; From 519198e2736fdb01bb07d80094bb4dc38ee28980 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Fri, 10 Dec 2021 11:09:04 +0000 Subject: [PATCH 060/189] Update type for parameter in isSidebarItemWithSubmenuActive function Signed-off-by: hiba-aldalaty --- packages/core-components/src/layout/Sidebar/Items.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 84f399ffa7..8b885134df 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -47,6 +47,7 @@ import { } from './config'; import { SidebarSubmenu } from './SidebarSubmenu'; import { isLocationMatch } from './utils'; +import { Location } from 'history'; export type SidebarItemClassKey = | 'root' @@ -173,7 +174,7 @@ const useStyles = makeStyles( function isSidebarItemWithSubmenuActive( submenu: ReactNode, - currentLocation: any, + currentLocation: Location, ) { // Item is active if any of submenu items have active paths const toPathnames: string[] = []; From e0f5b46fcc0343a9dd7bb48703373e91b1141d70 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 2 Dec 2021 16:37:30 +0100 Subject: [PATCH 061/189] snyk: ignore MPL and LGPL license warnings Signed-off-by: Patrik Oldsberg --- packages/cli/.snyk | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/cli/.snyk b/packages/cli/.snyk index 612b4b0525..3ad43bd3de 100644 --- a/packages/cli/.snyk +++ b/packages/cli/.snyk @@ -67,4 +67,16 @@ ignore: reason: Prototype pollution is not an effective attack against a CLI as it already executes arbitrary code expires: 2022-03-06T17:18:55.019Z created: 2021-09-06T17:18:55.027Z + + 'snyk:lic:npm:rollup-plugin-dts:LGPL-3.0': + - '*': + reason: Backstage itself does not redistribute this dependency in minified form + expires: 2031-09-06T17:18:55.027Z + created: 2021-09-06T17:18:55.027Z + + 'snyk:lic:npm:axe-core:MPL-2.0': + - '*': + reason: Backstage itself does not redistribute this dependency in minified form + expires: 2031-09-06T17:18:55.027Z + created: 2021-09-06T17:18:55.027Z patch: {} From d614e1cd9a35d3289dbf8e8164a4b4c1283d11b3 Mon Sep 17 00:00:00 2001 From: Praveen Ranjan Keshri Date: Fri, 10 Dec 2021 22:53:31 +0530 Subject: [PATCH 062/189] Updates post review by @Rugvip: 1. Updated reloadIntervalSeconds example to 10 minutes 2. Updated config load error message 3. Fixed vocab error Signed-off-by: Praveen Ranjan Keshri --- .changeset/brave-impalas-switch.md | 4 ++-- packages/config-loader/src/loader.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/brave-impalas-switch.md b/.changeset/brave-impalas-switch.md index de7e2ee528..729a4ec96a 100644 --- a/.changeset/brave-impalas-switch.md +++ b/.changeset/brave-impalas-switch.md @@ -4,7 +4,7 @@ Fixed bug in backend-common to allow passing of remote option in order to enable passing remote url in --config option. The remote option should be passed along with reloadIntervalSeconds from packages/backend/src/index.ts (Updated the file as well) -These changes are needed in `packages/backend/src/index.ts` if remote urls are desired to be passed in --config option and read and watch remote files for config. +These changes are needed in `packages/backend/src/index.ts` if remote URLs are desired to be passed in --config option and read and watch remote files for config. ```diff @@ -86,7 +86,11 @@ async function main() { @@ -12,7 +12,7 @@ These changes are needed in `packages/backend/src/index.ts` if remote urls are d argv: process.argv, logger, + remote: { -+ reloadIntervalSeconds: 60 * 60 * 12 // Check remote config changes every 12 hours. Change to your desired interval in seconds ++ reloadIntervalSeconds: 60 * 10 // Check remote config changes every 10 minutes. Change to your desired interval in seconds + } }); + diff --git a/packages/config-loader/src/loader.ts b/packages/config-loader/src/loader.ts index e7aa3d4c10..d19cd691be 100644 --- a/packages/config-loader/src/loader.ts +++ b/packages/config-loader/src/loader.ts @@ -129,7 +129,7 @@ export async function loadConfig( if (remote === undefined) { if (configUrls.length > 0) { throw new Error( - `Please make sure you are passing the remote option when loading the configuration. See https://backstage.io/docs/conf/writing#configuration-files for detailed info.`, + `Please make sure you are passing the remote option when loading remote configurations. See https://backstage.io/docs/conf/writing#configuration-files for detailed info.`, ); } } else if (remote.reloadIntervalSeconds <= 0) { From eec0750d8d85c2a1eaefc36c10763b5668d80561 Mon Sep 17 00:00:00 2001 From: Phil Gore Date: Fri, 10 Dec 2021 14:42:42 -0600 Subject: [PATCH 063/189] making cookiecutter an optional action based on passing in containerRunner Signed-off-by: Phil Gore --- .changeset/mighty-llamas-hope.md | 5 +++++ .../actions/builtin/createBuiltinActions.ts | 21 ++++++++++++------- .../scaffolder-backend/src/service/router.ts | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 .changeset/mighty-llamas-hope.md diff --git a/.changeset/mighty-llamas-hope.md b/.changeset/mighty-llamas-hope.md new file mode 100644 index 0000000000..7ea87e50d0 --- /dev/null +++ b/.changeset/mighty-llamas-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Makes cookiecutter a default, but optional action based on if a containerRunner argument is passed in to createRouter or createBuiltinActions diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index d38dfe3cdc..5ecdc1d595 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -46,22 +46,17 @@ export const createBuiltinActions = (options: { reader: UrlReader; integrations: ScmIntegrations; catalogClient: CatalogApi; - containerRunner: ContainerRunner; + containerRunner?: ContainerRunner; config: Config; }) => { const { reader, integrations, containerRunner, catalogClient, config } = options; - return [ + const actions = [ createFetchPlainAction({ reader, integrations, }), - createFetchCookiecutterAction({ - reader, - integrations, - containerRunner, - }), createFetchTemplateAction({ integrations, reader, @@ -97,4 +92,16 @@ export const createBuiltinActions = (options: { integrations, }), ]; + + if (containerRunner) { + actions.push( + createFetchCookiecutterAction({ + reader, + integrations, + containerRunner, + }), + ); + } + + return actions; }; diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index b8f2968287..9d26857ab9 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -55,7 +55,7 @@ export interface RouterOptions { catalogClient: CatalogApi; actions?: TemplateAction[]; taskWorkers?: number; - containerRunner: ContainerRunner; + containerRunner?: ContainerRunner; taskBroker?: TaskBroker; } From 2e4bc16c4a640f5ab9e321eb11fbb2e02c04d74b Mon Sep 17 00:00:00 2001 From: Phil Gore Date: Fri, 10 Dec 2021 14:55:02 -0600 Subject: [PATCH 064/189] adding scaffolder api report Signed-off-by: Phil Gore --- plugins/scaffolder-backend/api-report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 6ed4625f66..767b431352 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -68,7 +68,7 @@ export const createBuiltinActions: (options: { reader: UrlReader; integrations: ScmIntegrations; catalogClient: CatalogApi; - containerRunner: ContainerRunner; + containerRunner?: ContainerRunner; config: Config; }) => TemplateAction[]; @@ -289,7 +289,7 @@ export interface RouterOptions { // (undocumented) config: Config; // (undocumented) - containerRunner: ContainerRunner; + containerRunner?: ContainerRunner; // (undocumented) database: PluginDatabaseManager; // (undocumented) From 6156fb87303d4a3f5f03e474d8de3ce214dc2bc8 Mon Sep 17 00:00:00 2001 From: Tim Hansen Date: Fri, 10 Dec 2021 14:38:32 -0700 Subject: [PATCH 065/189] Skip updating selected types if they didn't change Signed-off-by: Tim Hansen --- .changeset/thirty-ways-attend.md | 5 +++++ plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .changeset/thirty-ways-attend.md diff --git a/.changeset/thirty-ways-attend.md b/.changeset/thirty-ways-attend.md new file mode 100644 index 0000000000..b294b4bfb0 --- /dev/null +++ b/.changeset/thirty-ways-attend.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +`useEntityTypeFilter`: Skip updating selected types if a kind filter change did not change them. diff --git a/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx b/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx index 5a8ed6775a..bf5777becc 100644 --- a/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx +++ b/plugins/catalog-react/src/hooks/useEntityTypeFilter.tsx @@ -16,6 +16,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { useAsync } from 'react-use'; +import isEqual from 'lodash/isEqual'; import { useApi } from '@backstage/core-plugin-api'; import { catalogApiRef } from '../api'; import { useEntityListProvider } from './useEntityListProvider'; @@ -107,7 +108,9 @@ export function useEntityTypeFilter(): EntityTypeReturn { const stillValidTypes = selectedTypes.filter(value => newTypes.includes(value), ); - setSelectedTypes(stillValidTypes); + if (!isEqual(selectedTypes, stillValidTypes)) { + setSelectedTypes(stillValidTypes); + } }, [loading, kind, selectedTypes, setSelectedTypes, entities]); useEffect(() => { From 90fbd943deb1560bb9acff3c99aa217eecc0ef3c Mon Sep 17 00:00:00 2001 From: lukzerom Date: Sat, 11 Dec 2021 00:35:19 +0100 Subject: [PATCH 066/189] Basic select api changes and adjustments ready Signed-off-by: lukzerom --- .../src/components/Select/Select.tsx | 55 +++++++---- .../src/components/Select/index.tsx | 7 +- .../fields/RepoUrlPicker/RepoUrlPicker.tsx | 93 ++++++++++--------- 3 files changed, 96 insertions(+), 59 deletions(-) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index a0e3aba94b..53a9a4800a 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -21,13 +21,13 @@ import FormControl from '@material-ui/core/FormControl'; import InputBase from '@material-ui/core/InputBase'; import MenuItem from '@material-ui/core/MenuItem'; import Select from '@material-ui/core/Select'; -import Typography from '@material-ui/core/Typography'; import { createStyles, makeStyles, Theme, withStyles, } from '@material-ui/core/styles'; +import Typography from '@material-ui/core/Typography'; import React, { useEffect, useState } from 'react'; import ClosedDropdown from './static/ClosedDropdown'; import OpenedDropdown from './static/OpenedDropdown'; @@ -92,7 +92,14 @@ const useStyles = makeStyles( chip: { margin: 2, }, + checkbox: {}, + select: { + '&:hover': { + cursor: 'not-allowed', + }, + }, + root: { display: 'flex', flexDirection: 'column', @@ -101,12 +108,12 @@ const useStyles = makeStyles( { name: 'BackstageSelect' }, ); -type Item = { +export type Item = { label: string; value: string | number; }; -type Selection = string | string[] | number | number[]; +export type Selection = string | string[] | number | number[]; export type SelectProps = { multiple?: boolean; @@ -116,6 +123,8 @@ export type SelectProps = { selected?: Selection; onChange: (arg: Selection) => void; triggerReset?: boolean; + native?: boolean; + disabled?: boolean; }; export function SelectComponent(props: SelectProps) { @@ -127,6 +136,8 @@ export function SelectComponent(props: SelectProps) { selected, onChange, triggerReset, + native = false, + disabled = false, } = props; const classes = useStyles(); const [value, setValue] = useState( @@ -150,6 +161,9 @@ export function SelectComponent(props: SelectProps) { }; const handleClick = (event: React.ChangeEvent) => { + // if (disabled) { + // return event.preventDefault(); + // } setOpen(previous => { if (multiple && !(event.target instanceof HTMLElement)) { return true; @@ -175,6 +189,8 @@ export function SelectComponent(props: SelectProps) { diff --git a/packages/core-components/src/components/Select/index.tsx b/packages/core-components/src/components/Select/index.tsx index 0f149f05b5..8c9ae28ac8 100644 --- a/packages/core-components/src/components/Select/index.tsx +++ b/packages/core-components/src/components/Select/index.tsx @@ -15,6 +15,11 @@ */ export { SelectComponent as Select } from './Select'; -export type { SelectClassKey, SelectInputBaseClassKey } from './Select'; +export type { + Item, + SelectClassKey, + SelectInputBaseClassKey, + Selection, +} from './Select'; export type { ClosedDropdownClassKey } from './static/ClosedDropdown'; export type { OpenedDropdownClassKey } from './static/OpenedDropdown'; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index c4b1e79262..42e24cc998 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -13,19 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useCallback, useEffect } from 'react'; -import { FieldProps } from '@rjsf/core'; -import { scaffolderApiRef } from '../../../api'; +import { Item, Progress, Select, Selection } from '@backstage/core-components'; +import { useApi } from '@backstage/core-plugin-api'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; -import { useAsync } from 'react-use'; -import Select from '@material-ui/core/Select'; -import InputLabel from '@material-ui/core/InputLabel'; -import Input from '@material-ui/core/Input'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; - -import { useApi } from '@backstage/core-plugin-api'; -import { Progress } from '@backstage/core-components'; +import Input from '@material-ui/core/Input'; +import InputLabel from '@material-ui/core/InputLabel'; +import { FieldProps } from '@rjsf/core'; +import React, { useCallback, useEffect } from 'react'; +import { useAsync } from 'react-use'; +import { scaffolderApiRef } from '../../../api'; function splitFormData(url: string | undefined, allowedOwners?: string[]) { let host = undefined; @@ -106,10 +104,10 @@ export const RepoUrlPicker = ({ allowedOwners, ); const updateHost = useCallback( - (evt: React.ChangeEvent<{ name?: string; value: unknown }>) => { + (value: Selection) => { onChange( serializeFormData({ - host: evt.target.value as string, + host: value as string, owner, repo, organization, @@ -121,6 +119,21 @@ export const RepoUrlPicker = ({ [onChange, owner, repo, organization, workspace, project], ); + const updateOwnerSelect = useCallback( + (value: Selection) => + onChange( + serializeFormData({ + host, + owner: value as string, + repo, + organization, + workspace, + project, + }), + ), + [onChange, host, repo, organization, workspace, project], + ); + const updateOwner = useCallback( (evt: React.ChangeEvent<{ name?: string; value: unknown }>) => onChange( @@ -224,6 +237,16 @@ export const RepoUrlPicker = ({ return ; } + const hostsOptions: Item[] = integrations + ? integrations + .filter(i => allowedHosts?.includes(i.host)) + .map(i => ({ label: i.title, value: i.host })) + : [{ label: 'Loading...', value: 'loading' }]; + + const ownersOptions: Item[] = allowedOwners + ? allowedOwners.map(i => ({ label: i, value: i })) + : [{ label: 'Loading...', value: 'loading' }]; + return ( <> 0 && !host} > - Host - + - {allowedOwners ? ( - allowedOwners.map(i => ( - - )) - ) : ( -

loading

- )} - ; - + label="Owner Available" + onChange={updateOwnerSelect} + disabled={ownersOptions.length === 1} + selected={owner} + items={ownersOptions} + /> + The organization, user or project that this repo will belong to From 919ffa9b539b7f295ccea4a1217027a2e9e9f1a8 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Sat, 11 Dec 2021 00:36:46 +0100 Subject: [PATCH 067/189] click handler adjustment Signed-off-by: lukzerom --- packages/core-components/src/components/Select/Select.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 53a9a4800a..02e45c8334 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -161,9 +161,10 @@ export function SelectComponent(props: SelectProps) { }; const handleClick = (event: React.ChangeEvent) => { - // if (disabled) { - // return event.preventDefault(); - // } + if (disabled) { + event.preventDefault(); + return; + } setOpen(previous => { if (multiple && !(event.target instanceof HTMLElement)) { return true; From 56a5466790e3b8d4cbe21e5ae861a23bcfa51d93 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Sat, 11 Dec 2021 00:51:26 +0100 Subject: [PATCH 068/189] eslint adjustments Signed-off-by: lukzerom --- .../fields/EntityPicker/EntityPicker.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx index a8ef524a13..d491af1da4 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx @@ -22,7 +22,7 @@ import { TextField } from '@material-ui/core'; import FormControl from '@material-ui/core/FormControl'; import Autocomplete from '@material-ui/lab/Autocomplete'; import { FieldProps } from '@rjsf/core'; -import React from 'react'; +import React, { useCallback, useEffect } from 'react'; import { useAsync } from 'react-use'; export const EntityPicker = ({ @@ -48,9 +48,18 @@ export const EntityPicker = ({ formatEntityRefTitle(e, { defaultKind }), ); - const onSelect = (_: any, value: string | null) => { - onChange(value || ''); - }; + const onSelect = useCallback( + (_: any, value: string | null) => { + onChange(value || ''); + }, + [onChange], + ); + + useEffect(() => { + if (entityRefs?.length === 1) { + onSelect('', entityRefs[0]); + } + }, [entityRefs, onSelect]); return ( 0 && !formData} > Date: Sat, 11 Dec 2021 01:07:35 +0100 Subject: [PATCH 069/189] Select changeset Signed-off-by: lukzerom --- .changeset/curvy-walls-itch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/curvy-walls-itch.md diff --git a/.changeset/curvy-walls-itch.md b/.changeset/curvy-walls-itch.md new file mode 100644 index 0000000000..18f35a6e24 --- /dev/null +++ b/.changeset/curvy-walls-itch.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': minor +--- + +Select component has extended API with few more props From 7b5d40c2410556378abddf20e1cae0f367174e82 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Sat, 11 Dec 2021 01:12:24 +0100 Subject: [PATCH 070/189] changeset scaffolder Signed-off-by: lukzerom --- .changeset/beige-balloons-grin.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/beige-balloons-grin.md diff --git a/.changeset/beige-balloons-grin.md b/.changeset/beige-balloons-grin.md new file mode 100644 index 0000000000..9ce1e0b6b5 --- /dev/null +++ b/.changeset/beige-balloons-grin.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +When user will have one option available in hostUrl or owner - autoselect and select component should be readonly From 625240c4baa57eea9e82f3b147139edad0a9712c Mon Sep 17 00:00:00 2001 From: lukzerom Date: Sat, 11 Dec 2021 01:14:13 +0100 Subject: [PATCH 071/189] clean Signed-off-by: lukzerom --- packages/core-components/src/components/Select/Select.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 02e45c8334..3b6582865c 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -92,13 +92,7 @@ const useStyles = makeStyles( chip: { margin: 2, }, - checkbox: {}, - select: { - '&:hover': { - cursor: 'not-allowed', - }, - }, root: { display: 'flex', From 133769ea846331f1ce10b4f59801ce1b3842cbf8 Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Sat, 11 Dec 2021 01:45:39 +0100 Subject: [PATCH 072/189] add links to docs for type BackstageSignInResult Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- plugins/auth-backend/api-report.md | 2 -- plugins/auth-backend/src/providers/oidc/provider.ts | 2 +- plugins/auth-backend/src/providers/types.ts | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index fd8d357a09..9ed523c678 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -549,8 +549,6 @@ export type OidcAuthResult = { userinfo: UserinfoResponse; }; -// Warning: (tsdoc-undefined-tag) The TSDoc tag "@BackstageSignInResult" is not defined in this configuration -// // @public export type OidcProviderOptions = { authHandler?: AuthHandler; diff --git a/plugins/auth-backend/src/providers/oidc/provider.ts b/plugins/auth-backend/src/providers/oidc/provider.ts index 98988ae6f7..fe4c042500 100644 --- a/plugins/auth-backend/src/providers/oidc/provider.ts +++ b/plugins/auth-backend/src/providers/oidc/provider.ts @@ -233,7 +233,7 @@ export const oAuth2DefaultSignInResolver: SignInResolver = * can be passed while creating a OIDC provider. * * authHandler : called after sign in was successful, a new object must be returned which includes a profile - * signInResolver: called after sign in was successful, expects to return a new @BackstageSignInResult + * signInResolver: called after sign in was successful, expects to return a new {@link BackstageSignInResult} * * Both options are optional. There is fallback for authHandler where the default handler expect an e-mail explicitly * otherwise it throws an error diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 6e61682f86..ecb466c768 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -258,7 +258,7 @@ export type SignInInfo = { /** * Sign in resolver type describes the function which handles the result of a successful authentication - * and must return a valid BackStageSignInResult + * and it must return a valid {@link BackstageSignInResult} * @public */ export type SignInResolver = ( From da156f2831888a0a474f99899b11d7792b54b05d Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 12:46:17 +0100 Subject: [PATCH 073/189] let's support also entities without spec.type Signed-off-by: Jan Vilimek --- .../src/components/Cards/OwnershipCard/OwnershipCard.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index fe23191779..091e8037ca 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -162,17 +162,15 @@ export const OwnershipCard = ({ const counts = ownedEntitiesList.reduce( (acc: EntityTypeProps[], ownedEntity) => { - if (typeof ownedEntity.spec?.type !== 'string') return acc; - const match = acc.find( - x => x.kind === ownedEntity.kind && x.type === ownedEntity.spec?.type, + x => x.kind === ownedEntity.kind && x.type === (ownedEntity.spec?.type ?? ownedEntity.kind), ); if (match) { match.count += 1; } else { acc.push({ kind: ownedEntity.kind, - type: ownedEntity.spec?.type, + type: ownedEntity.spec?.type?.toString() ?? ownedEntity.kind, count: 1, }); } From 26b04d2341739d65dc8145e8e0b3b08617757867 Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 12:48:14 +0100 Subject: [PATCH 074/189] New arg entityFilterKind for ownershipcard Signed-off-by: Jan Vilimek --- .../org/src/components/Cards/OwnershipCard/OwnershipCard.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 091e8037ca..56e87a26f6 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -128,10 +128,12 @@ const getQueryParams = ( export const OwnershipCard = ({ variant, + entityFilterKind }: { /** @deprecated The entity is now grabbed from context instead */ entity?: Entity; variant?: InfoCardVariants; + entityFilterKind?: string[]; }) => { const { entity } = useEntity(); const catalogApi = useApi(catalogApiRef); @@ -142,7 +144,7 @@ export const OwnershipCard = ({ error, value: componentsWithCounters, } = useAsync(async () => { - const kinds = ['Component', 'API']; + const kinds = entityFilterKind ?? ['Component', 'API']; const entitiesList = await catalogApi.getEntities({ filter: { kind: kinds, From 455da34c98ce6fc60e414ce4aec80ce1a3ac9cf6 Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 12:49:39 +0100 Subject: [PATCH 075/189] jest tests for ownershipCard improved Signed-off-by: Jan Vilimek --- .../OwnershipCard/OwnershipCard.test.tsx | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 8d6fc1a002..e5bf36ba8e 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -108,6 +108,22 @@ describe('OwnershipCard', () => { }, ], }, + { + kind: 'system', + metadata: { + name: 'my-systen', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, ] as any; it('displays entity counts', async () => { @@ -144,6 +160,7 @@ describe('OwnershipCard', () => { expect( queryByText(getByText('LIBRARY').parentElement!, '1'), ).toBeInTheDocument(); + expect(getByText('SYSTEM')).not.toBeInTheDocument(); }); it('links to the catalog with the group filter', async () => { @@ -222,3 +239,138 @@ describe('OwnershipCard', () => { ); }); }); + +describe('OwnershipCardWithCustomFilterDefinition', () => { + const groupEntity: GroupEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + name: 'my-team', + }, + spec: { + type: 'team', + children: [], + }, + relations: [ + { + type: 'memberOf', + target: { + kind: 'group', + name: 'ExampleGroup', + namespace: 'default', + }, + }, + ], + }; + + const items = [ + { + kind: 'API', + metadata: { + name: 'my-api', + }, + spec: { + type: 'openapi', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + { + kind: 'Component', + metadata: { + name: 'my-service', + }, + spec: { + type: 'service', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + { + kind: 'Component', + metadata: { + name: 'my-library', + namespace: 'other-namespace', + }, + spec: { + type: 'library', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + { + kind: 'system', + metadata: { + name: 'my-systen', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + ] as any; + + it('displays entity counts', async () => { + const catalogApi: jest.Mocked = { + getEntities: jest.fn(), + } as any; + + catalogApi.getEntities.mockResolvedValue({ + items, + }); + + const { getByText } = await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/create': catalogRouteRef, + }, + }, + ); + + expect(getByText('OPENAPI')).toBeInTheDocument(); + expect( + queryByText(getByText('OPENAPI').parentElement!, '1'), + ).toBeInTheDocument(); + expect(getByText('SERVICE')).not.toBeInTheDocument(); + expect(getByText('LIBRARY')).not.toBeInTheDocument(); + expect(getByText('SYSTEM')).toBeInTheDocument(); + expect( + queryByText(getByText('SYSTEM').parentElement!, '1'), + ).toBeInTheDocument(); + }); +}); From 5835456f6f52d784f778db4c919e40b6db1e645c Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 12:52:37 +0100 Subject: [PATCH 076/189] Example for entityFilterKind Signed-off-by: Jan Vilimek --- packages/app/src/components/catalog/EntityPage.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 9810f49386..e6cb43efdc 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -126,6 +126,8 @@ import { } from '@roadiehq/backstage-plugin-travis-ci'; import React, { ReactNode, useMemo, useState } from 'react'; +const customEntityFilterKind = ['Component', 'API', 'System']; + const EntityLayoutWrapper = (props: { children?: ReactNode }) => { const [badgesDialogOpen, setBadgesDialogOpen] = useState(false); @@ -523,7 +525,7 @@ const userPage = ( - + @@ -539,7 +541,7 @@ const groupPage = ( - + From fc2924b23e4a96c768f4234104b173261cfc0d3d Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 12:58:53 +0100 Subject: [PATCH 077/189] org plugin changelog Signed-off-by: Jan Vilimek --- plugins/org/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 0576d644da..e409087f1c 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/plugin-org +## 0.3.31 + +### Patch Changes + +- added `entityFilterKind` property for `EntityOwnershipCard` + ## 0.3.30 ### Patch Changes From 47755c2a60ffddcf94442fa3483f4c113b3eb176 Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 12:59:16 +0100 Subject: [PATCH 078/189] package.json 0.3.31 bump Signed-off-by: Jan Vilimek --- plugins/org/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/org/package.json b/plugins/org/package.json index 4e7f556547..3554b5657c 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.3.30", + "version": "0.3.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", From fe86adbcd24282dfae4d4fcd9b2aeb8c4db8c390 Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 13:05:36 +0100 Subject: [PATCH 079/189] root changelog Signed-off-by: Jan Vilimek --- .changeset/org-ownershipcard-filteradded.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/org-ownershipcard-filteradded.md diff --git a/.changeset/org-ownershipcard-filteradded.md b/.changeset/org-ownershipcard-filteradded.md new file mode 100644 index 0000000000..8f6c1bc37d --- /dev/null +++ b/.changeset/org-ownershipcard-filteradded.md @@ -0,0 +1,6 @@ +--- +"example-app": patch +"@backstage/plugin-org": patch +--- + +Added `entityFilterKind` property for `EntityOwnershipCard` From 75c47f4ee6724348260f03e74c279639e446348a Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 13:13:37 +0100 Subject: [PATCH 080/189] revert plugin changelog Signed-off-by: Jan Vilimek --- plugins/org/CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index e409087f1c..0576d644da 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,11 +1,5 @@ # @backstage/plugin-org -## 0.3.31 - -### Patch Changes - -- added `entityFilterKind` property for `EntityOwnershipCard` - ## 0.3.30 ### Patch Changes From 2fd0010a152fb1b0610e4d8c7bc0511c05a210cf Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Sat, 11 Dec 2021 13:13:58 +0100 Subject: [PATCH 081/189] revert package.json bump Signed-off-by: Jan Vilimek --- plugins/org/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/org/package.json b/plugins/org/package.json index 3554b5657c..4e7f556547 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.3.31", + "version": "0.3.30", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", From 846773cf453aaf3e4c947f7b9dd6d03792f6b807 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Sun, 12 Dec 2021 13:13:55 +0100 Subject: [PATCH 082/189] added docs Signed-off-by: lukzerom --- packages/core-components/api-report.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index d098403113..72d47b494c 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -528,6 +528,14 @@ export type InfoCardVariants = 'flex' | 'fullHeight' | 'gridItem'; // @public (undocumented) export function IntroCard(props: IntroCardProps): JSX.Element; +// Warning: (ae-missing-release-tag) "Item" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type Item = { + label: string; + value: string | number; +}; + // Warning: (tsdoc-malformed-html-name) Invalid HTML element: Expecting an HTML name // Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag // Warning: (ae-forgotten-export) The symbol "ItemCardProps" needs to be exported by the entry point index.d.ts @@ -835,6 +843,12 @@ export type SelectClassKey = // @public (undocumented) export type SelectInputBaseClassKey = 'root' | 'input'; +// Warning: (ae-missing-release-tag) "Selection" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +type Selection_2 = string | string[] | number | number[]; +export { Selection_2 as Selection }; + // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "Sidebar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // From 45ddfa099b1d5c18ce20860eceda09116d3b14e0 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Sun, 12 Dec 2021 13:16:13 +0100 Subject: [PATCH 083/189] added autoselect to vocab txt Signed-off-by: lukzerom --- .github/styles/vocab.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt index 4ec62923d8..a1bc30d73a 100644 --- a/.github/styles/vocab.txt +++ b/.github/styles/vocab.txt @@ -12,6 +12,7 @@ Atlassian automations autoscaling Autoscaling +autoselect Avro backrub Bigtable From 7474124e87fe0fda42364343b74c60d598c0394d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Dec 2021 04:14:45 +0000 Subject: [PATCH 084/189] build(deps-dev): bump @types/inquirer from 7.3.1 to 8.1.3 Bumps [@types/inquirer](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/inquirer) from 7.3.1 to 8.1.3. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/inquirer) --- updated-dependencies: - dependency-name: "@types/inquirer" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- packages/cli/package.json | 2 +- packages/create-app/package.json | 2 +- yarn.lock | 32 +++++++++----------------------- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 984c1c70d1..984fdc9129 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -128,7 +128,7 @@ "@types/express": "^4.17.6", "@types/fs-extra": "^9.0.1", "@types/http-proxy": "^1.17.4", - "@types/inquirer": "^7.3.1", + "@types/inquirer": "^8.1.3", "@types/mock-fs": "^4.13.0", "@types/node": "^14.14.32", "@types/recursive-readdir": "^2.2.0", diff --git a/packages/create-app/package.json b/packages/create-app/package.json index ec739820b9..e5108f540b 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -41,7 +41,7 @@ }, "devDependencies": { "@types/fs-extra": "^9.0.1", - "@types/inquirer": "^7.3.1", + "@types/inquirer": "^8.1.3", "@types/node": "^14.14.32", "@types/recursive-readdir": "^2.2.0", "mock-fs": "^5.1.1", diff --git a/yarn.lock b/yarn.lock index 7a599498d0..7cff1b6243 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7582,14 +7582,6 @@ resolved "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.25.1.tgz#b6140d5fc00ff3917b3f521784abef4bc0387ccc" integrity sha512-WZU/4bb+lvzyDmZzjJtp++9mfKy6B3lH6gGISgkcz6SU8hMILKRM0vi08TxIsb0dQB4Gzo68MWLmctu6xqUi9g== -"@types/inquirer@^7.3.1": - version "7.3.1" - resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.1.tgz#1f231224e7df11ccfaf4cf9acbcc3b935fea292d" - integrity sha512-osD38QVIfcdgsPCT0V3lD7eH0OFurX71Jft18bZrsVQWVRt6TuxRzlr0GJLrxoHZR2V5ph7/qP8se/dcnI7o0g== - dependencies: - "@types/through" "*" - rxjs "^6.4.0" - "@types/inquirer@^7.3.3": version "7.3.3" resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.3.tgz#92e6676efb67fa6925c69a2ee638f67a822952ac" @@ -7598,6 +7590,14 @@ "@types/through" "*" rxjs "^6.4.0" +"@types/inquirer@^8.1.3": + version "8.1.3" + resolved "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.1.3.tgz#dfda4c97cdbe304e4dceb378a80f79448ea5c8fe" + integrity sha512-AayK4ZL5ssPzR1OtnOLGAwpT0Dda3Xi/h1G0l1oJDNrowp7T1423q4Zb8/emr7tzRlCy4ssEri0LWVexAqHyKQ== + dependencies: + "@types/through" "*" + rxjs "^7.2.0" + "@types/is-function@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.0.tgz#1b0b819b1636c7baf0d6785d030d12edf70c3e83" @@ -25856,21 +25856,7 @@ run-script-webpack-plugin@^0.0.11: resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.0.11.tgz#04c510bed06b907fa2285e75feece71a25691171" integrity sha512-QmuBhiqBPmhQLpO5vMBHVTAGyoPBnrCM5gQ3IzgieiImBXiBbXcIv4kysCT1gilFNFxQk22oKQfiIhWbT/zXCw== -rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.6.0: - version "6.6.2" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2" - integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg== - dependencies: - tslib "^1.9.0" - -rxjs@^6.6.3: - version "6.6.6" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70" - integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg== - dependencies: - tslib "^1.9.0" - -rxjs@^6.6.7: +rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.6.0, rxjs@^6.6.3, rxjs@^6.6.7: version "6.6.7" resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== From 157d4bf78ee9104b1c9b6ae0fe5d71c9d4c35e3d Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Mon, 13 Dec 2021 10:19:41 +0530 Subject: [PATCH 085/189] add changeset Signed-off-by: Himanshu Mishra --- .changeset/old-glasses-tease.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/old-glasses-tease.md diff --git a/.changeset/old-glasses-tease.md b/.changeset/old-glasses-tease.md new file mode 100644 index 0000000000..e960de374b --- /dev/null +++ b/.changeset/old-glasses-tease.md @@ -0,0 +1,6 @@ +--- +'@backstage/cli': patch +'@backstage/create-app': patch +--- + +Bump @types/inquirer from 7.3.1 to 8.1.3 From 88bd7ef966ede89bffde162343a886499b759f85 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Mon, 13 Dec 2021 11:30:57 +0530 Subject: [PATCH 086/189] add a function for fetching user owned entities Signed-off-by: mufaddal motiwala --- .../OwnedEntityPicker/useOwnedEntities.ts | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts new file mode 100644 index 0000000000..ecdfc5c90f --- /dev/null +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts @@ -0,0 +1,60 @@ +/* + * 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 { + catalogApiRef, + loadCatalogOwnerRefs, + loadIdentityOwnerRefs, +} from '@backstage/plugin-catalog-react'; +import { identityApiRef, useApi } from '@backstage/core-plugin-api'; +import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; +import { CatalogListResponse } from '@backstage/catalog-client'; +import { useAsync } from 'react-use'; +import { useMemo } from 'react'; + +export function useOwnedEntities(allowedKinds?: string[]): { + loading: boolean; + ownedEntities: CatalogListResponse | undefined; +} { + const identityApi = useApi(identityApiRef); + const catalogApi = useApi(catalogApiRef); + + const { loading, value: refs } = useAsync(async () => { + const identityRefs = await loadIdentityOwnerRefs(identityApi); + const catalogRefs = await loadCatalogOwnerRefs(catalogApi, identityRefs); + const catalogs = await catalogApi.getEntities( + allowedKinds + ? { + filter: { + kind: allowedKinds, + [`relations.${RELATION_OWNED_BY}`]: + [...identityRefs, ...catalogRefs] || [], + }, + } + : { + filter: { + [`relations.${RELATION_OWNED_BY}`]: + [...identityRefs, ...catalogRefs] || [], + }, + }, + ); + return catalogs; + }, []); + const ownedEntities = useMemo(() => { + return refs; + }, [refs]); + + return useMemo(() => ({ loading, ownedEntities }), [loading, ownedEntities]); +} From c0154e444b1bd27ebe46e20d367101d5655aec57 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Mon, 13 Dec 2021 11:31:23 +0530 Subject: [PATCH 087/189] change API for fetching user owned entities Signed-off-by: mufaddal motiwala --- .../OwnedEntityPicker/OwnedEntityPicker.tsx | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx index b73158ac60..06b637a79c 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -13,18 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useApi } from '@backstage/core-plugin-api'; -import { - catalogApiRef, - formatEntityRefTitle, - useEntityOwnership, -} from '@backstage/plugin-catalog-react'; +import { formatEntityRefTitle } from '@backstage/plugin-catalog-react'; import { TextField } from '@material-ui/core'; import FormControl from '@material-ui/core/FormControl'; import Autocomplete from '@material-ui/lab/Autocomplete'; import { FieldProps } from '@rjsf/core'; import React from 'react'; -import { useAsync } from 'react-use'; +import { useOwnedEntities } from './useOwnedEntities'; export const OwnedEntityPicker = ({ onChange, @@ -37,24 +32,16 @@ export const OwnedEntityPicker = ({ }: FieldProps) => { const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[]; const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined; - const catalogApi = useApi(catalogApiRef); - const { isOwnedEntity } = useEntityOwnership(); + const { ownedEntities, loading } = useOwnedEntities(allowedKinds); - const { value: entities, loading } = useAsync(() => - catalogApi.getEntities( - allowedKinds ? { filter: { kind: allowedKinds } } : undefined, - ), - ); - - const entityRefs = entities?.items - .map(e => - isOwnedEntity(e) ? formatEntityRefTitle(e, { defaultKind }) : null, - ) + const entityRefs = ownedEntities?.items + .map(e => formatEntityRefTitle(e, { defaultKind })) .filter(n => n); const onSelect = (_: any, value: string | null) => { onChange(value || ''); }; + return ( Date: Mon, 13 Dec 2021 09:57:46 +0100 Subject: [PATCH 088/189] Delete old-glasses-tease.md Signed-off-by: Patrik Oldsberg --- .changeset/old-glasses-tease.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .changeset/old-glasses-tease.md diff --git a/.changeset/old-glasses-tease.md b/.changeset/old-glasses-tease.md deleted file mode 100644 index e960de374b..0000000000 --- a/.changeset/old-glasses-tease.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/cli': patch -'@backstage/create-app': patch ---- - -Bump @types/inquirer from 7.3.1 to 8.1.3 From 64dc7ed8c6568e29fb9e22c34febc2695b8172ca Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Mon, 13 Dec 2021 11:11:20 +0100 Subject: [PATCH 089/189] ownershipcard: prettier Signed-off-by: Jan Vilimek --- .../components/Cards/OwnershipCard/OwnershipCard.test.tsx | 2 +- .../src/components/Cards/OwnershipCard/OwnershipCard.tsx | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index e5bf36ba8e..e49720a9d4 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -352,7 +352,7 @@ describe('OwnershipCardWithCustomFilterDefinition', () => { const { getByText } = await renderInTestApp( - + , { diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 56e87a26f6..1e2d514359 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -128,7 +128,7 @@ const getQueryParams = ( export const OwnershipCard = ({ variant, - entityFilterKind + entityFilterKind, }: { /** @deprecated The entity is now grabbed from context instead */ entity?: Entity; @@ -165,7 +165,9 @@ export const OwnershipCard = ({ const counts = ownedEntitiesList.reduce( (acc: EntityTypeProps[], ownedEntity) => { const match = acc.find( - x => x.kind === ownedEntity.kind && x.type === (ownedEntity.spec?.type ?? ownedEntity.kind), + x => + x.kind === ownedEntity.kind && + x.type === (ownedEntity.spec?.type ?? ownedEntity.kind), ); if (match) { match.count += 1; From 9ed3dfb4d5ff25c676c23a016a6901d812c4ee97 Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Mon, 13 Dec 2021 11:11:42 +0100 Subject: [PATCH 090/189] changelog:prettier Signed-off-by: Jan Vilimek --- .changeset/org-ownershipcard-filteradded.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/org-ownershipcard-filteradded.md b/.changeset/org-ownershipcard-filteradded.md index 8f6c1bc37d..d95428ae02 100644 --- a/.changeset/org-ownershipcard-filteradded.md +++ b/.changeset/org-ownershipcard-filteradded.md @@ -1,6 +1,6 @@ --- -"example-app": patch -"@backstage/plugin-org": patch +'example-app': patch +'@backstage/plugin-org': patch --- Added `entityFilterKind` property for `EntityOwnershipCard` From 8390fff862d6206f6b38bb6ad34b55f3a471fb2b Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Mon, 13 Dec 2021 11:11:56 +0100 Subject: [PATCH 091/189] entitypage: prettier Signed-off-by: Jan Vilimek --- packages/app/src/components/catalog/EntityPage.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index e6cb43efdc..a7de64e89a 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -525,7 +525,10 @@ const userPage = ( - + @@ -541,7 +544,10 @@ const groupPage = ( - + From 8a7372cfd53e74a0e5c7a2961f5e787c0d831e25 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 13 Dec 2021 11:49:08 +0100 Subject: [PATCH 092/189] core-plugin-api: deprecated some auth api refs and marked the rest as experimental Co-authored-by: Johan Haals Signed-off-by: Patrik Oldsberg --- .changeset/nice-seahorses-look.md | 5 + docs/api/deprecations.md | 122 ++++++++++++++++++ packages/core-plugin-api/api-report.md | 24 ++-- .../src/apis/definitions/auth.ts | 32 ++--- 4 files changed, 156 insertions(+), 27 deletions(-) create mode 100644 .changeset/nice-seahorses-look.md diff --git a/.changeset/nice-seahorses-look.md b/.changeset/nice-seahorses-look.md new file mode 100644 index 0000000000..9652898c54 --- /dev/null +++ b/.changeset/nice-seahorses-look.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Deprecated `auth0AuthApiRef`, `oauth2ApiRef`, `oidcAuthApiRef`, `samlAuthApiRef`, and marked the rest of the auth `ApiRef`s as experimental. For more information on how to address the deprecations, see https://backstage.io/docs/api/deprecations#generic-auth-api-refs. diff --git a/docs/api/deprecations.md b/docs/api/deprecations.md index aca7e42d96..04c3da92bc 100644 --- a/docs/api/deprecations.md +++ b/docs/api/deprecations.md @@ -61,3 +61,125 @@ breaking change to make `theme` optional. This means that if you currently construct the themes that you pass on to `createApp` using `AppTheme` as an intermediate type, you will need to work around this in some way, for example by passing the themes to `createApp` more directly. + +### Generic Auth API Refs + +`Released 2021-12-16 in @backstage/core-plugin-api v0.3.1` + +There are four auth Utility API references in `@backstage/core-plugin-api` that +were too generic to be useful. The APIs in question are `auth0AuthApiRef`, +`oauth2ApiRef`, `oidcAuthApiRef`, and `samlAuthApiRef`. The issue with these +APIs was that they had no actual contract of what the backing auth provider was. +This made it more or less impossible to use these providers in open source +plugins in any meaningful way. We also did not want to keep these Utility API +references around just as helpers either, instead opting to remove them and let +integrators define their own APIs that are more specific to their auth provider. +This is also falls in line with a long-term goal to unify all auth providers to +not have separate frontend implementations. + +If you're currently using one of these API references for either Sign-In or +access delegation within an app, there are a couple of steps you need to take to +migrate to your own custom API. + +First, you'll need to define a new Utility API reference. If you're only using +the API for sign-in, you can put the definition in `packages/app/src/apis.ts`. +However, if you need to access your auth API inside plugins you you'll need to +export it from a common package. If you don't already have one we recommended +creating `@internal/apis` and from there export the API reference. + +```ts +// `ProfileInfoApi & BackstageIdentityApi & SessionApi` are required for sign-in +// Include `OAuthApi & OpenIdConnectApi` only if applicable +export const acmeAuthApiRef: ApiRef< + OAuthApi & + OpenIdConnectApi & + ProfileInfoApi & + BackstageIdentityApi & + SessionApi +> = createApiRef({ + id: 'internal.auth.acme', +}); +``` + +Next you'll want to wire up the API inside `packages/app/src/apis.ts`, which +varies depending on which API you're replacing. If you for example are replacing +the `oauth2ApiRef`, the factory might look like this: + +```ts +// oauth2 +createApiFactory({ + api: acmeAuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + configApi: configApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi, configApi }) => + OAuth2.create({ + discoveryApi, + oauthRequestApi, + environment: configApi.getOptionalString('auth.environment'), + }), +}); +``` + +Provider specific factory implementations, copy the code you need into the +factory method depending on which apiRef you previously used. + +```ts +// samlAuthApiRef +SamlAuth.create({ + discoveryApi, + environment: configApi.getOptionalString('auth.environment'), +}); + +// oidcAuthApiRef +OAuth2.create({ + discoveryApi, + oauthRequestApi, + provider: { + id: 'oidc', + title: 'Your Identity Provider', + icon: () => null, + }, + environment: configApi.getOptionalString('auth.environment'), +}); + +// auth0AuthApiRef +OAuth2.create({ + discoveryApi, + oauthRequestApi, + provider: { + id: 'auth0', + title: 'Auth0', + icon: () => null, + }, + defaultScopes: ['openid', 'email', 'profile'], + environment: configApi.getOptionalString('auth.environment'), +}); +``` + +Finally, for the provider to show up in your settings menu, you also need to +update the settings route in `packages/app/src/App.tsx` to pass the +`acmeAuthApiRef` to the `UserSettingsPage`. This replaces all existing provider +items, so you might want to add back any of the default ones that you are using +from the +[DefaultProviderSettings](https://github.com/backstage/backstage/blob/a3ec122170e0205fd3f9c307b98b1c5e4f55bf5f/plugins/user-settings/src/components/AuthProviders/DefaultProviderSettings.tsx#L35). + +```tsx + + } + /> + } +/> +``` diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index d0ac0b5352..ce9d226331 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -194,7 +194,7 @@ export type AppThemeApi = { // @public export const appThemeApiRef: ApiRef; -// @public +// @alpha export const atlassianAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi >; @@ -206,7 +206,7 @@ export function attachComponentData

( data: unknown, ): void; -// @public +// @public @deprecated export const auth0AuthApiRef: ApiRef< OpenIdConnectApi & ProfileInfoApi & BackstageIdentityApi & SessionApi >; @@ -272,7 +272,7 @@ export type BackstageUserIdentity = { ownershipEntityRefs: string[]; }; -// @public +// @alpha export const bitbucketAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi >; @@ -512,17 +512,17 @@ export function getComponentData( type: string, ): T | undefined; -// @public +// @alpha export const githubAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi >; -// @public +// @alpha export const gitlabAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi >; -// @public +// @alpha export const googleAuthApiRef: ApiRef< OAuthApi & OpenIdConnectApi & @@ -570,7 +570,7 @@ export type MergeParams< P2 extends AnyParams, > = (P1[keyof P1] extends never ? {} : P1) & (P2 extends undefined ? {} : P2); -// @public +// @alpha export const microsoftAuthApiRef: ApiRef< OAuthApi & OpenIdConnectApi & @@ -579,7 +579,7 @@ export const microsoftAuthApiRef: ApiRef< SessionApi >; -// @public +// @public @deprecated export const oauth2ApiRef: ApiRef< OAuthApi & OpenIdConnectApi & @@ -616,7 +616,7 @@ export type Observable = Observable_2; // @public @deprecated export type Observer = Observer_2; -// @public +// @public @deprecated export const oidcAuthApiRef: ApiRef< OAuthApi & OpenIdConnectApi & @@ -625,7 +625,7 @@ export const oidcAuthApiRef: ApiRef< SessionApi >; -// @public +// @alpha export const oktaAuthApiRef: ApiRef< OAuthApi & OpenIdConnectApi & @@ -637,7 +637,7 @@ export const oktaAuthApiRef: ApiRef< // @public export type OldIconComponent = ComponentType; -// @public +// @alpha export const oneloginAuthApiRef: ApiRef< OAuthApi & OpenIdConnectApi & @@ -738,7 +738,7 @@ export type RouteRef = { title?: string; }; -// @public +// @public @deprecated export const samlAuthApiRef: ApiRef< ProfileInfoApi & BackstageIdentityApi & SessionApi >; diff --git a/packages/core-plugin-api/src/apis/definitions/auth.ts b/packages/core-plugin-api/src/apis/definitions/auth.ts index 37308ec29b..8b799b2dd6 100644 --- a/packages/core-plugin-api/src/apis/definitions/auth.ts +++ b/packages/core-plugin-api/src/apis/definitions/auth.ts @@ -282,14 +282,14 @@ export type SessionApi = { /** * Provides authentication towards Google APIs and identities. * + * @alpha This API is **EXPERIMENTAL** and might change in the future. + * * @remarks * * See {@link https://developers.google.com/identity/protocols/googlescopes} for a full list of supported scopes. * * Note that the ID token payload is only guaranteed to contain the user's numerical Google ID, * email and expiration information. Do not rely on any other fields, as they might not be present. - * - * @public */ export const googleAuthApiRef: ApiRef< OAuthApi & @@ -304,12 +304,12 @@ export const googleAuthApiRef: ApiRef< /** * Provides authentication towards GitHub APIs. * + * @alpha This API is **EXPERIMENTAL** and might change in the future. + * * @remarks * * See {@link https://developer.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps/} * for a full list of supported scopes. - * - * @public */ export const githubAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi @@ -320,12 +320,12 @@ export const githubAuthApiRef: ApiRef< /** * Provides authentication towards Okta APIs. * + * @alpha This API is **EXPERIMENTAL** and might change in the future. + * * @remarks * * See {@link https://developer.okta.com/docs/guides/implement-oauth-for-okta/scopes/} * for a full list of supported scopes. - * - * @public */ export const oktaAuthApiRef: ApiRef< OAuthApi & @@ -340,12 +340,12 @@ export const oktaAuthApiRef: ApiRef< /** * Provides authentication towards GitLab APIs. * + * @alpha This API is **EXPERIMENTAL** and might change in the future. + * * @remarks * * See {@link https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#limiting-scopes-of-a-personal-access-token} * for a full list of supported scopes. - * - * @public */ export const gitlabAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi @@ -362,6 +362,7 @@ export const gitlabAuthApiRef: ApiRef< * for a full list of supported scopes. * * @public + * @deprecated See https://backstage.io/docs/api/deprecations#generic-auth-api-refs */ export const auth0AuthApiRef: ApiRef< OpenIdConnectApi & ProfileInfoApi & BackstageIdentityApi & SessionApi @@ -372,13 +373,13 @@ export const auth0AuthApiRef: ApiRef< /** * Provides authentication towards Microsoft APIs and identities. * + * @alpha This API is **EXPERIMENTAL** and might change in the future. + * * @remarks * * For more info and a full list of supported scopes, see: * - {@link https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent} * - {@link https://docs.microsoft.com/en-us/graph/permissions-reference} - * - * @public */ export const microsoftAuthApiRef: ApiRef< OAuthApi & @@ -394,6 +395,7 @@ export const microsoftAuthApiRef: ApiRef< * Provides authentication for custom identity providers. * * @public + * @deprecated See https://backstage.io/docs/api/deprecations#generic-auth-api-refs */ export const oauth2ApiRef: ApiRef< OAuthApi & @@ -409,6 +411,7 @@ export const oauth2ApiRef: ApiRef< * Provides authentication for custom OpenID Connect identity providers. * * @public + * @deprecated See https://backstage.io/docs/api/deprecations#generic-auth-api-refs */ export const oidcAuthApiRef: ApiRef< OAuthApi & @@ -424,6 +427,7 @@ export const oidcAuthApiRef: ApiRef< * Provides authentication for SAML-based identity providers. * * @public + * @deprecated See https://backstage.io/docs/api/deprecations#generic-auth-api-refs */ export const samlAuthApiRef: ApiRef< ProfileInfoApi & BackstageIdentityApi & SessionApi @@ -434,7 +438,7 @@ export const samlAuthApiRef: ApiRef< /** * Provides authentication towards OneLogin APIs. * - * @public + * @alpha This API is **EXPERIMENTAL** and might change in the future. */ export const oneloginAuthApiRef: ApiRef< OAuthApi & @@ -449,12 +453,11 @@ export const oneloginAuthApiRef: ApiRef< /** * Provides authentication towards Bitbucket APIs. * + * @alpha This API is **EXPERIMENTAL** and might change in the future. * @remarks * * See {@link https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/} * for a full list of supported scopes. - * - * @public */ export const bitbucketAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi @@ -465,12 +468,11 @@ export const bitbucketAuthApiRef: ApiRef< /** * Provides authentication towards Atlassian APIs. * + * @alpha This API is **EXPERIMENTAL** and might change in the future. * @remarks * * See {@link https://developer.atlassian.com/cloud/jira/platform/scopes-for-connect-and-oauth-2-3LO-apps/} * for a full list of supported scopes. - * - * @public */ export const atlassianAuthApiRef: ApiRef< OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi From c11ce4f55256c10cf12053501645775b7c28184b Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 13 Dec 2021 11:50:16 +0100 Subject: [PATCH 093/189] core-app-api: deprecated Auth0Auth Co-authored-by: Johan Haals Signed-off-by: Patrik Oldsberg --- .changeset/beige-news-cover.md | 5 +++++ packages/core-app-api/api-report.md | 2 +- .../implementations/auth/auth0/Auth0Auth.ts | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 .changeset/beige-news-cover.md diff --git a/.changeset/beige-news-cover.md b/.changeset/beige-news-cover.md new file mode 100644 index 0000000000..70cebcd76f --- /dev/null +++ b/.changeset/beige-news-cover.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': patch +--- + +Deprecated `Auth0Auth`, pointing to using `OAuth2` directly instead. diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index 51fd6bd06f..788dc4c6c3 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -254,7 +254,7 @@ export class AtlassianAuth { static create(options: OAuthApiCreateOptions): typeof atlassianAuthApiRef.T; } -// @public +// @public @deprecated export class Auth0Auth { // (undocumented) static create(options: OAuthApiCreateOptions): typeof auth0AuthApiRef.T; diff --git a/packages/core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts b/packages/core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts index d0a9dc5d99..d8f942b94b 100644 --- a/packages/core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/auth0/Auth0Auth.ts @@ -28,6 +28,23 @@ const DEFAULT_PROVIDER = { * Implements the OAuth flow to Auth0 products. * * @public + * @deprecated Use {@link OAuth2} instead + * + * @example + * + * ```ts + * OAuth2.create({ + * discoveryApi, + * oauthRequestApi, + * provider: { + * id: 'auth0', + * title: 'Auth0', + * icon: () => null, + * }, + * defaultScopes: ['openid', 'email', 'profile'], + * environment: configApi.getOptionalString('auth.environment'), + * }) + * ``` */ export default class Auth0Auth { static create(options: OAuthApiCreateOptions): typeof auth0AuthApiRef.T { From 9f5a08de13b0b8d925601b98e32bff49fd70b914 Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Mon, 13 Dec 2021 13:29:33 +0100 Subject: [PATCH 094/189] updated api-report Signed-off-by: Jan Vilimek --- plugins/org/api-report.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/org/api-report.md b/plugins/org/api-report.md index 88ce00fd52..60caa45134 100644 --- a/plugins/org/api-report.md +++ b/plugins/org/api-report.md @@ -33,9 +33,11 @@ export const EntityMembersListCard: (_props: { // @public (undocumented) export const EntityOwnershipCard: ({ variant, + entityFilterKind, }: { entity?: Entity | undefined; variant?: InfoCardVariants | undefined; + entityFilterKind?: string[] | undefined; }) => JSX.Element; // Warning: (ae-missing-release-tag) "EntityUserProfileCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -75,9 +77,11 @@ export { orgPlugin as plugin }; // @public (undocumented) export const OwnershipCard: ({ variant, + entityFilterKind, }: { entity?: Entity | undefined; variant?: InfoCardVariants | undefined; + entityFilterKind?: string[] | undefined; }) => JSX.Element; // Warning: (ae-missing-release-tag) "UserProfileCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) From 760791a642e6f3b57ac6ef4dd3d43891633f0fa2 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 13 Dec 2021 14:54:27 +0100 Subject: [PATCH 095/189] core-plugin-api: auth request type renames and deprecations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik AdelΓΆw Co-authored-by: Johan Haals Signed-off-by: Patrik Oldsberg --- .changeset/young-students-applaud.md | 11 +++ .../OAuthRequestApi/OAuthRequestManager.ts | 6 ++ packages/core-plugin-api/api-report.md | 49 ++++++++----- .../src/apis/definitions/OAuthRequestApi.ts | 68 ++++++++++--------- .../src/apis/definitions/auth.ts | 28 ++++++++ 5 files changed, 115 insertions(+), 47 deletions(-) create mode 100644 .changeset/young-students-applaud.md diff --git a/.changeset/young-students-applaud.md b/.changeset/young-students-applaud.md new file mode 100644 index 0000000000..bbd825cf00 --- /dev/null +++ b/.changeset/young-students-applaud.md @@ -0,0 +1,11 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Renamed `AuthProvider` to `AuthProviderInfo` and add a required 'id' property to match the majority of usage. The `AuthProvider` type without the `id` property still exists but is deprecated, and all usage of it without an `id` is deprecated as well. For example, calling `createAuthRequest` without a `provider.id` is deprecated and it will be required in the future. + +The following types have been renamed. The old names are still exported but deprecated, and are scheduled for removal in a future release. + +- Renamed `AuthRequesterOptions` to `OAuthRequesterOptions` +- Renamed `AuthRequester` to `OAuthRequester` +- Renamed `PendingAuthRequest` to `PendingOAuthRequest` diff --git a/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts b/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts index 7e7f3c2507..a6b33f85d5 100644 --- a/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts +++ b/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts @@ -39,6 +39,12 @@ export class OAuthRequestManager implements OAuthRequestApi { private handlerCount = 0; createAuthRequester(options: AuthRequesterOptions): AuthRequester { + if (!options.provider.id) { + // eslint-disable-next-line no-console + console.warn( + 'DEPRECATION WARNING: Not passing a provider id to createAuthRequester is deprecated, it will be required in the future', + ); + } const handler = new OAuthPendingRequests(); const index = this.handlerCount; diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index d0ac0b5352..65fbbb7ed1 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -211,22 +211,21 @@ export const auth0AuthApiRef: ApiRef< OpenIdConnectApi & ProfileInfoApi & BackstageIdentityApi & SessionApi >; +// @public @deprecated (undocumented) +export type AuthProvider = Omit; + // @public -export type AuthProvider = { +export type AuthProviderInfo = { + id: string; title: string; icon: IconComponent; }; -// @public -export type AuthRequester = ( - scopes: Set, -) => Promise; +// @public @deprecated (undocumented) +export type AuthRequester = OAuthRequester; -// @public -export type AuthRequesterOptions = { - provider: AuthProvider; - onAuthRequest(scopes: Set): Promise; -}; +// @public @deprecated (undocumented) +export type AuthRequesterOptions = OAuthRequesterOptions; // @public export type AuthRequestOptions = { @@ -598,15 +597,28 @@ export type OAuthApi = { // @public export type OAuthRequestApi = { - createAuthRequester( - options: AuthRequesterOptions, - ): AuthRequester; + createAuthRequester( + options: OAuthRequesterOptions, + ): OAuthRequester; authRequest$(): Observable_2; }; // @public export const oauthRequestApiRef: ApiRef; +// @public +export type OAuthRequester = ( + scopes: Set, +) => Promise; + +// @public +export type OAuthRequesterOptions = { + provider: Omit & { + id?: string; + }; + onAuthRequest(scopes: Set): Promise; +}; + // @public export type OAuthScope = string | string[]; @@ -679,10 +691,15 @@ export type PathParams = { [name in ParamNames]: string; }; +// @public @deprecated (undocumented) +export type PendingAuthRequest = PendingOAuthRequest; + // @public -export type PendingAuthRequest = { - provider: AuthProvider; - reject: () => void; +export type PendingOAuthRequest = { + provider: Omit & { + id?: string; + }; + reject(): void; trigger(): Promise; }; diff --git a/packages/core-plugin-api/src/apis/definitions/OAuthRequestApi.ts b/packages/core-plugin-api/src/apis/definitions/OAuthRequestApi.ts index 03e129ef6a..b78cc310c3 100644 --- a/packages/core-plugin-api/src/apis/definitions/OAuthRequestApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/OAuthRequestApi.ts @@ -14,31 +14,15 @@ * limitations under the License. */ -import { IconComponent } from '../../icons/types'; import { Observable } from '@backstage/types'; import { ApiRef, createApiRef } from '../system'; +import { AuthProviderInfo } from './auth'; /** - * Information about the auth provider that we're requesting a login towards. - * - * @remarks - * - * This should be shown to the user so that they can be informed about what login is being requested - * before a popup is shown. - * * @public + * @deprecated Use AuthProviderInfo instead */ -export type AuthProvider = { - /** - * Title for the auth provider, for example "GitHub" - */ - title: string; - - /** - * Icon for the auth provider. - */ - icon: IconComponent; -}; +export type AuthProvider = Omit; /** * Describes how to handle auth requests. Both how to show them to the user, and what to do when @@ -46,26 +30,34 @@ export type AuthProvider = { * * @public */ -export type AuthRequesterOptions = { +export type OAuthRequesterOptions = { /** * Information about the auth provider, which will be forwarded to auth requests. + * + * Not passing in an `id` is deprecated, and it will be required in the future. */ - provider: AuthProvider; + provider: Omit & { id?: string }; /** * Implementation of the auth flow, which will be called synchronously when * trigger() is called on an auth requests. */ - onAuthRequest(scopes: Set): Promise; + onAuthRequest(scopes: Set): Promise; }; +/** + * @public + * @deprecated Use OAuthRequesterOptions instead + */ +export type AuthRequesterOptions = OAuthRequesterOptions; + /** * Function used to trigger new auth requests for a set of scopes. * * @remarks * * The returned promise will resolve to the same value returned by the onAuthRequest in the - * {@link AuthRequesterOptions}. Or rejected, if the request is rejected. + * {@link OAuthRequesterOptions}. Or rejected, if the request is rejected. * * This function can be called multiple times before the promise resolves. All calls * will be merged into one request, and the scopes forwarded to the onAuthRequest will be the @@ -73,9 +65,15 @@ export type AuthRequesterOptions = { * * @public */ -export type AuthRequester = ( +export type OAuthRequester = ( scopes: Set, -) => Promise; +) => Promise; + +/** + * @public + * @deprecated Use OAuthRequester instead + */ +export type AuthRequester = OAuthRequester; /** * An pending auth request for a single auth provider. The request will remain in this pending @@ -88,16 +86,18 @@ export type AuthRequester = ( * * @public */ -export type PendingAuthRequest = { +export type PendingOAuthRequest = { /** * Information about the auth provider, as given in the AuthRequesterOptions + * + * Not passing in an `id` is deprecated, and it will be required in the future. */ - provider: AuthProvider; + provider: Omit & { id?: string }; /** * Rejects the request, causing all pending AuthRequester calls to fail with "RejectedError". */ - reject: () => void; + reject(): void; /** * Trigger the auth request to continue the auth flow, by for example showing a popup. @@ -107,6 +107,12 @@ export type PendingAuthRequest = { trigger(): Promise; }; +/** + * @public + * @deprecated Use PendingOAuthRequest instead + */ +export type PendingAuthRequest = PendingOAuthRequest; + /** * Provides helpers for implemented OAuth login flows within Backstage. * @@ -125,9 +131,9 @@ export type OAuthRequestApi = { * * See AuthRequesterOptions, AuthRequester, and handleAuthRequests for more info. */ - createAuthRequester( - options: AuthRequesterOptions, - ): AuthRequester; + createAuthRequester( + options: OAuthRequesterOptions, + ): OAuthRequester; /** * Observers pending auth requests. The returned observable will emit all diff --git a/packages/core-plugin-api/src/apis/definitions/auth.ts b/packages/core-plugin-api/src/apis/definitions/auth.ts index 37308ec29b..fad759dde8 100644 --- a/packages/core-plugin-api/src/apis/definitions/auth.ts +++ b/packages/core-plugin-api/src/apis/definitions/auth.ts @@ -15,6 +15,7 @@ */ import { ApiRef, createApiRef } from '../system'; +import { IconComponent } from '../../icons/types'; import { Observable } from '@backstage/types'; /** @@ -28,6 +29,33 @@ import { Observable } from '@backstage/types'; * const googleAuthApiRef = createApiRef({ ... }) */ +/** + * Information about the auth provider. + * + * @remarks + * + * This information is used both to connect the correct auth provider in the backend, as + * well as displaying the provider to the user. + * + * @public + */ +export type AuthProviderInfo = { + /** + * The ID of the auth provider. This should match with ID of the provider in the `@backstage/auth-backend`. + */ + id: string; + + /** + * Title for the auth provider, for example "GitHub" + */ + title: string; + + /** + * Icon for the auth provider. + */ + icon: IconComponent; +}; + /** * An array of scopes, or a scope string formatted according to the * auth provider, which is typically a space separated list. From 2771d9016ed983ee38c822f3932db3d596b34dd9 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Mon, 13 Dec 2021 09:28:56 -0500 Subject: [PATCH 096/189] Bump checkout action to newest major release Signed-off-by: Adam Harvey --- .github/workflows/changeset.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/changeset.yml b/.github/workflows/changeset.yml index 70afd15eee..a649904a01 100644 --- a/.github/workflows/changeset.yml +++ b/.github/workflows/changeset.yml @@ -10,7 +10,7 @@ jobs: name: Create Changeset PR runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Install Dependencies run: yarn --frozen-lockfile - name: Create Release Pull Request From 4f1a7d57df38af0ba8c07e023c511d5246d7bfd3 Mon Sep 17 00:00:00 2001 From: Adam Harvey Date: Mon, 13 Dec 2021 09:29:30 -0500 Subject: [PATCH 097/189] Remove specific pin versioning Signed-off-by: Adam Harvey --- .github/workflows/fossa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fossa.yml b/.github/workflows/fossa.yml index 9d054ff6df..3d0832f958 100644 --- a/.github/workflows/fossa.yml +++ b/.github/workflows/fossa.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v2 - name: Install Fossa run: "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | bash" From 9d6503e86c6e9cf07e79da82bf8f39bd141e7595 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 13 Dec 2021 15:21:09 +0100 Subject: [PATCH 098/189] core-*: update usage of deprecated auth types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik AdelΓΆw Co-authored-by: Johan Haals Signed-off-by: Patrik Oldsberg --- .changeset/shaggy-bears-remember.md | 6 ++++++ packages/core-app-api/api-report.md | 20 ++++++++----------- .../OAuthRequestApi/MockOAuthApi.ts | 4 ++-- .../OAuthRequestApi/OAuthRequestManager.ts | 18 ++++++++--------- .../auth/onelogin/OneLoginAuth.ts | 4 ++-- .../src/apis/implementations/auth/types.ts | 4 ++-- .../lib/AuthConnector/DefaultAuthConnector.ts | 10 +++++----- .../lib/AuthConnector/DirectAuthConnector.ts | 6 +++--- .../LoginRequestListItem.tsx | 4 ++-- packages/core-plugin-api/api-report.md | 2 +- .../src/apis/definitions/OAuthRequestApi.ts | 2 +- 11 files changed, 41 insertions(+), 39 deletions(-) create mode 100644 .changeset/shaggy-bears-remember.md diff --git a/.changeset/shaggy-bears-remember.md b/.changeset/shaggy-bears-remember.md new file mode 100644 index 0000000000..d041abb3d1 --- /dev/null +++ b/.changeset/shaggy-bears-remember.md @@ -0,0 +1,6 @@ +--- +'@backstage/core-app-api': patch +'@backstage/core-components': patch +--- + +Switched out usage of deprecated `OAuthRequestApi` types from `@backstage/core-plugin-api`. diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index 51fd6bd06f..a6c44f2b52 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -17,9 +17,7 @@ import { AppTheme } from '@backstage/core-plugin-api'; import { AppThemeApi } from '@backstage/core-plugin-api'; import { atlassianAuthApiRef } from '@backstage/core-plugin-api'; import { auth0AuthApiRef } from '@backstage/core-plugin-api'; -import { AuthProvider } from '@backstage/core-plugin-api'; -import { AuthRequester } from '@backstage/core-plugin-api'; -import { AuthRequesterOptions } from '@backstage/core-plugin-api'; +import { AuthProviderInfo } from '@backstage/core-plugin-api'; import { AuthRequestOptions } from '@backstage/core-plugin-api'; import { BackstageIdentity } from '@backstage/core-plugin-api'; import { BackstageIdentityApi } from '@backstage/core-plugin-api'; @@ -43,11 +41,13 @@ import { IdentityApi } from '@backstage/core-plugin-api'; import { microsoftAuthApiRef } from '@backstage/core-plugin-api'; import { OAuthApi } from '@backstage/core-plugin-api'; import { OAuthRequestApi } from '@backstage/core-plugin-api'; +import { OAuthRequester } from '@backstage/core-plugin-api'; +import { OAuthRequesterOptions } from '@backstage/core-plugin-api'; import { Observable } from '@backstage/types'; import { oktaAuthApiRef } from '@backstage/core-plugin-api'; import { oneloginAuthApiRef } from '@backstage/core-plugin-api'; import { OpenIdConnectApi } from '@backstage/core-plugin-api'; -import { PendingAuthRequest } from '@backstage/core-plugin-api'; +import { PendingOAuthRequest } from '@backstage/core-plugin-api'; import { PluginOutput } from '@backstage/core-plugin-api'; import { ProfileInfo } from '@backstage/core-plugin-api'; import { ProfileInfoApi } from '@backstage/core-plugin-api'; @@ -264,9 +264,7 @@ export class Auth0Auth { export type AuthApiCreateOptions = { discoveryApi: DiscoveryApi; environment?: string; - provider?: AuthProvider & { - id: string; - }; + provider?: AuthProviderInfo; }; // @public @@ -515,9 +513,9 @@ export type OAuthApiCreateOptions = AuthApiCreateOptions & { // @public export class OAuthRequestManager implements OAuthRequestApi { // (undocumented) - authRequest$(): Observable; + authRequest$(): Observable; // (undocumented) - createAuthRequester(options: AuthRequesterOptions): AuthRequester; + createAuthRequester(options: OAuthRequesterOptions): OAuthRequester; } // @public @@ -539,9 +537,7 @@ export type OneLoginAuthCreateOptions = { discoveryApi: DiscoveryApi; oauthRequestApi: OAuthRequestApi; environment?: string; - provider?: AuthProvider & { - id: string; - }; + provider?: AuthProviderInfo; }; // @public diff --git a/packages/core-app-api/src/apis/implementations/OAuthRequestApi/MockOAuthApi.ts b/packages/core-app-api/src/apis/implementations/OAuthRequestApi/MockOAuthApi.ts index 4a0a07ef34..193c474361 100644 --- a/packages/core-app-api/src/apis/implementations/OAuthRequestApi/MockOAuthApi.ts +++ b/packages/core-app-api/src/apis/implementations/OAuthRequestApi/MockOAuthApi.ts @@ -16,14 +16,14 @@ import { OAuthRequestApi, - AuthRequesterOptions, + OAuthRequesterOptions, } from '@backstage/core-plugin-api'; import { OAuthRequestManager } from './OAuthRequestManager'; export default class MockOAuthApi implements OAuthRequestApi { private readonly real = new OAuthRequestManager(); - createAuthRequester(options: AuthRequesterOptions) { + createAuthRequester(options: OAuthRequesterOptions) { return this.real.createAuthRequester(options); } diff --git a/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts b/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts index a6b33f85d5..f9d9270b2a 100644 --- a/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts +++ b/packages/core-app-api/src/apis/implementations/OAuthRequestApi/OAuthRequestManager.ts @@ -16,9 +16,9 @@ import { OAuthRequestApi, - PendingAuthRequest, - AuthRequester, - AuthRequesterOptions, + PendingOAuthRequest, + OAuthRequester, + OAuthRequesterOptions, } from '@backstage/core-plugin-api'; import { Observable } from '@backstage/types'; import { OAuthPendingRequests, PendingRequest } from './OAuthPendingRequests'; @@ -34,11 +34,11 @@ import { BehaviorSubject } from '../../../lib/subjects'; * @public */ export class OAuthRequestManager implements OAuthRequestApi { - private readonly subject = new BehaviorSubject([]); - private currentRequests: PendingAuthRequest[] = []; + private readonly subject = new BehaviorSubject([]); + private currentRequests: PendingOAuthRequest[] = []; private handlerCount = 0; - createAuthRequester(options: AuthRequesterOptions): AuthRequester { + createAuthRequester(options: OAuthRequesterOptions): OAuthRequester { if (!options.provider.id) { // eslint-disable-next-line no-console console.warn( @@ -73,8 +73,8 @@ export class OAuthRequestManager implements OAuthRequestApi { // Converts the pending request and popup options into a popup request that we can forward to subscribers. private makeAuthRequest( request: PendingRequest, - options: AuthRequesterOptions, - ): PendingAuthRequest | undefined { + options: OAuthRequesterOptions, + ): PendingOAuthRequest | undefined { const { scopes } = request; if (!scopes) { return undefined; @@ -94,7 +94,7 @@ export class OAuthRequestManager implements OAuthRequestApi { }; } - authRequest$(): Observable { + authRequest$(): Observable { return this.subject; } } diff --git a/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts b/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts index 9493d0809e..ea9e2cad28 100644 --- a/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts @@ -17,7 +17,7 @@ import { oneloginAuthApiRef, OAuthRequestApi, - AuthProvider, + AuthProviderInfo, DiscoveryApi, } from '@backstage/core-plugin-api'; import { OAuth2 } from '../oauth2'; @@ -30,7 +30,7 @@ export type OneLoginAuthCreateOptions = { discoveryApi: DiscoveryApi; oauthRequestApi: OAuthRequestApi; environment?: string; - provider?: AuthProvider & { id: string }; + provider?: AuthProviderInfo; }; const DEFAULT_PROVIDER = { diff --git a/packages/core-app-api/src/apis/implementations/auth/types.ts b/packages/core-app-api/src/apis/implementations/auth/types.ts index 825f433cec..55d6c19098 100644 --- a/packages/core-app-api/src/apis/implementations/auth/types.ts +++ b/packages/core-app-api/src/apis/implementations/auth/types.ts @@ -15,7 +15,7 @@ */ import { - AuthProvider, + AuthProviderInfo, DiscoveryApi, OAuthRequestApi, } from '@backstage/core-plugin-api'; @@ -36,5 +36,5 @@ export type OAuthApiCreateOptions = AuthApiCreateOptions & { export type AuthApiCreateOptions = { discoveryApi: DiscoveryApi; environment?: string; - provider?: AuthProvider & { id: string }; + provider?: AuthProviderInfo; }; diff --git a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts index 261a008d4b..a467957063 100644 --- a/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts +++ b/packages/core-app-api/src/lib/AuthConnector/DefaultAuthConnector.ts @@ -15,9 +15,9 @@ */ import { - AuthRequester, + OAuthRequester, OAuthRequestApi, - AuthProvider, + AuthProviderInfo, DiscoveryApi, } from '@backstage/core-plugin-api'; import { showLoginPopup } from '../loginPopup'; @@ -36,7 +36,7 @@ type Options = { * Information about the auth provider to be shown to the user. * The ID Must match the backend auth plugin configuration, for example 'google'. */ - provider: AuthProvider & { id: string }; + provider: AuthProviderInfo; /** * API used to instantiate an auth requester. */ @@ -65,9 +65,9 @@ export class DefaultAuthConnector { private readonly discoveryApi: DiscoveryApi; private readonly environment: string; - private readonly provider: AuthProvider & { id: string }; + private readonly provider: AuthProviderInfo; private readonly joinScopesFunc: (scopes: Set) => string; - private readonly authRequester: AuthRequester; + private readonly authRequester: OAuthRequester; private readonly sessionTransform: (response: any) => Promise; constructor(options: Options) { diff --git a/packages/core-app-api/src/lib/AuthConnector/DirectAuthConnector.ts b/packages/core-app-api/src/lib/AuthConnector/DirectAuthConnector.ts index 61fdd825a2..200ba755ac 100644 --- a/packages/core-app-api/src/lib/AuthConnector/DirectAuthConnector.ts +++ b/packages/core-app-api/src/lib/AuthConnector/DirectAuthConnector.ts @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { AuthProvider, DiscoveryApi } from '@backstage/core-plugin-api'; +import { AuthProviderInfo, DiscoveryApi } from '@backstage/core-plugin-api'; import { showLoginPopup } from '../loginPopup'; type Options = { discoveryApi: DiscoveryApi; environment?: string; - provider: AuthProvider & { id: string }; + provider: AuthProviderInfo; }; export class DirectAuthConnector { private readonly discoveryApi: DiscoveryApi; private readonly environment: string | undefined; - private readonly provider: AuthProvider & { id: string }; + private readonly provider: AuthProviderInfo; constructor(options: Options) { const { discoveryApi, environment, provider } = options; diff --git a/packages/core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx b/packages/core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx index ef0d2373e4..0c6bd62bcb 100644 --- a/packages/core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx +++ b/packages/core-components/src/components/OAuthRequestDialog/LoginRequestListItem.tsx @@ -22,7 +22,7 @@ import Typography from '@material-ui/core/Typography'; import Button from '@material-ui/core/Button'; import React, { useState } from 'react'; import { isError } from '@backstage/errors'; -import { PendingAuthRequest } from '@backstage/core-plugin-api'; +import { PendingOAuthRequest } from '@backstage/core-plugin-api'; export type LoginRequestListItemClassKey = 'root'; @@ -36,7 +36,7 @@ const useItemStyles = makeStyles( ); type RowProps = { - request: PendingAuthRequest; + request: PendingOAuthRequest; busy: boolean; setBusy: (busy: boolean) => void; }; diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 65fbbb7ed1..2f40a02253 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -600,7 +600,7 @@ export type OAuthRequestApi = { createAuthRequester( options: OAuthRequesterOptions, ): OAuthRequester; - authRequest$(): Observable_2; + authRequest$(): Observable_2; }; // @public diff --git a/packages/core-plugin-api/src/apis/definitions/OAuthRequestApi.ts b/packages/core-plugin-api/src/apis/definitions/OAuthRequestApi.ts index b78cc310c3..5b8dab29f7 100644 --- a/packages/core-plugin-api/src/apis/definitions/OAuthRequestApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/OAuthRequestApi.ts @@ -146,7 +146,7 @@ export type OAuthRequestApi = { * If a auth is triggered, and the auth handler resolves successfully, then all currently pending * AuthRequester calls will resolve to the value returned by the onAuthRequest call. */ - authRequest$(): Observable; + authRequest$(): Observable; }; /** From e7cce2b60385a09a57caaaae1f355cc967a7b01e Mon Sep 17 00:00:00 2001 From: Phil Kuang Date: Fri, 3 Dec 2021 15:49:52 -0500 Subject: [PATCH 099/189] fix(techdocsStorageClient): properly construct baseUrls Signed-off-by: Phil Kuang --- .changeset/techdocs-forty-pumas-compete.md | 5 +++++ plugins/techdocs/src/client.test.ts | 6 ++++++ plugins/techdocs/src/client.ts | 4 +++- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .changeset/techdocs-forty-pumas-compete.md diff --git a/.changeset/techdocs-forty-pumas-compete.md b/.changeset/techdocs-forty-pumas-compete.md new file mode 100644 index 0000000000..929ce3e2c9 --- /dev/null +++ b/.changeset/techdocs-forty-pumas-compete.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Fix issue where assets weren't being fetched from the correct URL path for doc URLs without trailing slashes diff --git a/plugins/techdocs/src/client.test.ts b/plugins/techdocs/src/client.test.ts index 7624f250d9..c05d0cc324 100644 --- a/plugins/techdocs/src/client.test.ts +++ b/plugins/techdocs/src/client.test.ts @@ -59,6 +59,12 @@ describe('TechDocsStorageClient', () => { ).resolves.toEqual( `${mockBaseUrl}/static/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test.js`, ); + + await expect( + storageApi.getBaseUrl('../test.js', mockEntity, 'some-docs-path'), + ).resolves.toEqual( + `${mockBaseUrl}/static/docs/${mockEntity.namespace}/${mockEntity.kind}/${mockEntity.name}/test.js`, + ); }); it('should return base url with correct entity structure', async () => { diff --git a/plugins/techdocs/src/client.ts b/plugins/techdocs/src/client.ts index 8a3ad59c03..f965cd7ced 100644 --- a/plugins/techdocs/src/client.ts +++ b/plugins/techdocs/src/client.ts @@ -263,9 +263,11 @@ export class TechDocsStorageClient implements TechDocsStorageApi { const { kind, namespace, name } = entityId; const apiOrigin = await this.getApiOrigin(); + const newBaseUrl = `${apiOrigin}/static/docs/${namespace}/${kind}/${name}/${path}`; + return new URL( oldBaseUrl, - `${apiOrigin}/static/docs/${namespace}/${kind}/${name}/${path}`, + newBaseUrl.endsWith('/') ? newBaseUrl : `${newBaseUrl}/`, ).toString(); } } From fd9c1abd2c76e5a54dcaf63c25aa2604dc0d67a9 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 13 Dec 2021 16:41:49 +0100 Subject: [PATCH 100/189] Delete cold-otters-prove.md Signed-off-by: Patrik Oldsberg --- .changeset/cold-otters-prove.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .changeset/cold-otters-prove.md diff --git a/.changeset/cold-otters-prove.md b/.changeset/cold-otters-prove.md deleted file mode 100644 index 37438b333e..0000000000 --- a/.changeset/cold-otters-prove.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': patch -'@backstage/cli': patch ---- - -chore(deps-dev): bump `@types/tar` from 4.0.5 to 6.1.1 From 8ab8c30f1b67b720c09525500476eb21eb2cc4cf Mon Sep 17 00:00:00 2001 From: Balasundaram Date: Mon, 13 Dec 2021 11:10:20 -0500 Subject: [PATCH 101/189] Adding fixes for changeset spelling Signed-off-by: Balasundaram --- .changeset/nervous-hounds-attend.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/nervous-hounds-attend.md b/.changeset/nervous-hounds-attend.md index 15ca4aa085..b54eb5a688 100644 --- a/.changeset/nervous-hounds-attend.md +++ b/.changeset/nervous-hounds-attend.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend': patch --- -Adding changes to create Gitlab Merge Request using custom action +Adding changes to create GitLab Merge Request using custom action From 2321b89ad1401bcb603e7e7ed6a05afb13397b61 Mon Sep 17 00:00:00 2001 From: Andrew Tran Date: Mon, 6 Dec 2021 10:08:42 -0600 Subject: [PATCH 102/189] make completed status green Signed-off-by: Andrew Tran --- plugins/kubernetes/src/utils/pod.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/kubernetes/src/utils/pod.tsx b/plugins/kubernetes/src/utils/pod.tsx index bfb40750cd..50cc983b9d 100644 --- a/plugins/kubernetes/src/utils/pod.tsx +++ b/plugins/kubernetes/src/utils/pod.tsx @@ -63,7 +63,13 @@ export const containerStatuses = (pod: V1Pod): ReactNode => { const renderCell = (reason: string | undefined) => ( Container: {next.name}} + value={ + reason === 'Completed' ? ( + Container: {next.name} + ) : ( + Container: {next.name} + ) + } subvalue={reason} />
From a9c008780700fcb6b26f495815007afe7ea04280 Mon Sep 17 00:00:00 2001 From: Andrew Tran Date: Mon, 13 Dec 2021 10:07:59 -0600 Subject: [PATCH 103/189] fix cronjobs accordion Signed-off-by: Andrew Tran --- plugins/kubernetes/src/components/Cluster/Cluster.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/kubernetes/src/components/Cluster/Cluster.tsx b/plugins/kubernetes/src/components/Cluster/Cluster.tsx index b7a819cdbf..eb12ba20f8 100644 --- a/plugins/kubernetes/src/components/Cluster/Cluster.tsx +++ b/plugins/kubernetes/src/components/Cluster/Cluster.tsx @@ -148,9 +148,9 @@ export const Cluster = ({ clusterObjects, podsWithErrors }: ClusterProps) => { - - - + + + From 6f0c850a8683d461f6e19e196c74703a8537f58d Mon Sep 17 00:00:00 2001 From: Andrew Tran Date: Mon, 13 Dec 2021 10:19:07 -0600 Subject: [PATCH 104/189] add changeset Signed-off-by: Andrew Tran --- .changeset/cold-dolls-beam.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cold-dolls-beam.md diff --git a/.changeset/cold-dolls-beam.md b/.changeset/cold-dolls-beam.md new file mode 100644 index 0000000000..5257cd5553 --- /dev/null +++ b/.changeset/cold-dolls-beam.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes': patch +--- + +Fixed styling bug for the CronJobsAccordions and updated Completed pods to display a green dot. From 0be6cb1111b401b8171fa3342c0c9a3a45140f6d Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Mon, 13 Dec 2021 16:17:52 +0100 Subject: [PATCH 105/189] no bump for example-app Signed-off-by: Jan Vilimek --- .changeset/org-ownershipcard-filteradded.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/org-ownershipcard-filteradded.md b/.changeset/org-ownershipcard-filteradded.md index d95428ae02..cbd1475bb1 100644 --- a/.changeset/org-ownershipcard-filteradded.md +++ b/.changeset/org-ownershipcard-filteradded.md @@ -1,5 +1,4 @@ --- -'example-app': patch '@backstage/plugin-org': patch --- From bc1e2f20bd6a0f3a95aa2a755da0946bd041c1d5 Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Mon, 13 Dec 2021 17:36:09 +0100 Subject: [PATCH 106/189] unit test fixed Signed-off-by: Jan Vilimek --- .../OwnershipCard/OwnershipCard.test.tsx | 225 ++++++------------ 1 file changed, 71 insertions(+), 154 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index e49720a9d4..912014092f 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import { Entity, GroupEntity, UserEntity } from '@backstage/catalog-model'; import { CatalogApi, catalogApiRef, @@ -51,6 +51,7 @@ describe('OwnershipCard', () => { const items = [ { + apiVersion: 'backstage.io/v1alpha1', kind: 'API', metadata: { name: 'my-api', @@ -108,23 +109,7 @@ describe('OwnershipCard', () => { }, ], }, - { - kind: 'system', - metadata: { - name: 'my-systen', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - ] as any; + ] as Entity[]; it('displays entity counts', async () => { const catalogApi: jest.Mocked = { @@ -148,6 +133,17 @@ describe('OwnershipCard', () => { }, ); + expect(catalogApi.getEntities).toHaveBeenCalledWith({ + filter: { kind: ['Component', 'API'] }, + fields: [ + 'kind', + 'metadata.name', + 'metadata.namespace', + 'spec.type', + 'relations', + ], + }); + expect(getByText('OPENAPI')).toBeInTheDocument(); expect( queryByText(getByText('OPENAPI').parentElement!, '1'), @@ -160,7 +156,63 @@ describe('OwnershipCard', () => { expect( queryByText(getByText('LIBRARY').parentElement!, '1'), ).toBeInTheDocument(); - expect(getByText('SYSTEM')).not.toBeInTheDocument(); + }); + + it('applies CustomFilterDefinition', async () => { + const catalogApi: jest.Mocked = { + getEntities: jest.fn(), + } as any; + + catalogApi.getEntities.mockResolvedValue({ + items: [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'system', + metadata: { + name: 'my-systen', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + ], + }); + + const { getByText } = await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/create': catalogRouteRef, + }, + }, + ); + + expect(catalogApi.getEntities).toHaveBeenCalledWith({ + filter: { kind: ['API', 'System'] }, + fields: [ + 'kind', + 'metadata.name', + 'metadata.namespace', + 'spec.type', + 'relations', + ], + }); + + expect(getByText('SYSTEM')).toBeInTheDocument(); + expect( + queryByText(getByText('SYSTEM').parentElement!, '1'), + ).toBeInTheDocument(); }); it('links to the catalog with the group filter', async () => { @@ -239,138 +291,3 @@ describe('OwnershipCard', () => { ); }); }); - -describe('OwnershipCardWithCustomFilterDefinition', () => { - const groupEntity: GroupEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Group', - metadata: { - name: 'my-team', - }, - spec: { - type: 'team', - children: [], - }, - relations: [ - { - type: 'memberOf', - target: { - kind: 'group', - name: 'ExampleGroup', - namespace: 'default', - }, - }, - ], - }; - - const items = [ - { - kind: 'API', - metadata: { - name: 'my-api', - }, - spec: { - type: 'openapi', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - { - kind: 'Component', - metadata: { - name: 'my-service', - }, - spec: { - type: 'service', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - { - kind: 'Component', - metadata: { - name: 'my-library', - namespace: 'other-namespace', - }, - spec: { - type: 'library', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - { - kind: 'system', - metadata: { - name: 'my-systen', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - ] as any; - - it('displays entity counts', async () => { - const catalogApi: jest.Mocked = { - getEntities: jest.fn(), - } as any; - - catalogApi.getEntities.mockResolvedValue({ - items, - }); - - const { getByText } = await renderInTestApp( - - - - - , - { - mountedRoutes: { - '/create': catalogRouteRef, - }, - }, - ); - - expect(getByText('OPENAPI')).toBeInTheDocument(); - expect( - queryByText(getByText('OPENAPI').parentElement!, '1'), - ).toBeInTheDocument(); - expect(getByText('SERVICE')).not.toBeInTheDocument(); - expect(getByText('LIBRARY')).not.toBeInTheDocument(); - expect(getByText('SYSTEM')).toBeInTheDocument(); - expect( - queryByText(getByText('SYSTEM').parentElement!, '1'), - ).toBeInTheDocument(); - }); -}); From 4594ea2dab62f033d288e7e8f7279438795adbdd Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 13 Dec 2021 18:24:46 +0100 Subject: [PATCH 107/189] catalog-react: weird api-report reordering Signed-off-by: Patrik Oldsberg --- plugins/catalog-react/api-report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index c4aa254226..c95a8dc508 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -271,14 +271,13 @@ export const EntityRefLink: React_2.ForwardRefExoticComponent< | 'children' | 'key' | 'id' - | 'className' | 'classes' - | 'innerRef' | 'defaultChecked' | 'defaultValue' | 'suppressContentEditableWarning' | 'suppressHydrationWarning' | 'accessKey' + | 'className' | 'contentEditable' | 'contextMenu' | 'draggable' @@ -519,6 +518,7 @@ export const EntityRefLink: React_2.ForwardRefExoticComponent< | 'onTransitionEndCapture' | 'component' | 'variant' + | 'innerRef' | 'download' | 'href' | 'hrefLang' From 201953b21ebc7adc2ae5f282bcacdc84a67e0084 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 13 Dec 2021 23:26:06 +0100 Subject: [PATCH 108/189] workflows/stale: bump PR close days to 5 Signed-off-by: Patrik Oldsberg --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 96a2a20109..5cbf4e32ef 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -24,7 +24,7 @@ jobs: recent activity from the author. It will be closed if no further activity occurs. If you are the author and the PR has been closed, feel free to re-open the PR and continue the contribution! days-before-pr-stale: 7 - days-before-pr-close: 3 + days-before-pr-close: 5 exempt-pr-labels: reviewer-approved,awaiting-review stale-pr-label: stale operations-per-run: 100 From 2c9001fef1866365e3ef040ee672280cc8bf52e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Dec 2021 04:20:37 +0000 Subject: [PATCH 109/189] build(deps): bump humanize-duration from 3.27.0 to 3.27.1 Bumps [humanize-duration](https://github.com/EvanHahn/HumanizeDuration.js) from 3.27.0 to 3.27.1. - [Release notes](https://github.com/EvanHahn/HumanizeDuration.js/releases) - [Changelog](https://github.com/EvanHahn/HumanizeDuration.js/blob/main/HISTORY.md) - [Commits](https://github.com/EvanHahn/HumanizeDuration.js/commits) --- updated-dependencies: - dependency-name: humanize-duration dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 19f6ad2b27..c10a3d9afb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16999,9 +16999,9 @@ human-signals@^2.1.0: integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== humanize-duration@^3.25.1, humanize-duration@^3.26.0, humanize-duration@^3.27.0: - version "3.27.0" - resolved "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.27.0.tgz#3f781b7cf8022ad587f76b9839b60bc2b29636b2" - integrity sha512-qLo/08cNc3Tb0uD7jK0jAcU5cnqCM0n568918E7R2XhMr/+7F37p4EY062W/stg7tmzvknNn9b/1+UhVRzsYrQ== + version "3.27.1" + resolved "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.27.1.tgz#2cd4ea4b03bd92184aee6d90d77a8f3d7628df69" + integrity sha512-jCVkMl+EaM80rrMrAPl96SGG4NRac53UyI1o/yAzebDntEY6K6/Fj2HOjdPg8omTqIe5Y0wPBai2q5xXrIbarA== humanize-ms@^1.2.1: version "1.2.1" From b5fb3dbc9e09ea85d4f01ca332cd6854d2177f68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Dec 2021 04:23:04 +0000 Subject: [PATCH 110/189] build(deps): bump @types/ldapjs from 2.2.0 to 2.2.2 Bumps [@types/ldapjs](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ldapjs) from 2.2.0 to 2.2.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/ldapjs) --- updated-dependencies: - dependency-name: "@types/ldapjs" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- yarn.lock | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/yarn.lock b/yarn.lock index 19f6ad2b27..4e77c271b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7756,9 +7756,9 @@ "@types/node" "*" "@types/ldapjs@^2.2.0": - version "2.2.0" - resolved "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-2.2.0.tgz#43ff78668c420b69a61b93e0acde71ddc0c7766d" - integrity sha512-L6ObSryRGOw0qYmN9B4w4s8UkoyRbxoWh7C1vc/Z6O/VXJQJqGBSyZPXRDmgKF+TZVGq/F7H37t0Cxrm+hLiRA== + version "2.2.2" + resolved "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-2.2.2.tgz#cf79510d8dc34e5579442c2743f8a228427eb99c" + integrity sha512-U5HdnwIZ5uZa+f3usxdqgyfNmOROxOxXvQdQtsu6sKo8fte5vej9br2csHxPvXreAbAO1bs8/rdEzvCLpi67nQ== dependencies: "@types/node" "*" @@ -7897,36 +7897,31 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^14.0.10", "@types/node@^14.14.31", "@types/node@^14.14.32": - version "14.17.8" - resolved "https://registry.npmjs.org/@types/node/-/node-14.17.8.tgz#813b73ab7d82ac06ddfd2458b13c88459a3b319f" - integrity sha512-0CHLt50GbUmH/6MrlBIKNdWCglvlyQKkorRf08/0DIi0ryuTPP+ijWLSI19SbDTHSKaagGDELiImY4BSikt61w== +"@types/node@*", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^16.9.2": + version "16.11.6" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" + integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== "@types/node@10.17.13", "@types/node@^10.1.0", "@types/node@^10.12.0": version "10.17.13" resolved "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c" integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg== -"@types/node@12.20.24": +"@types/node@12.20.24", "@types/node@^12.7.1": version "12.20.24" resolved "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz#c37ac69cb2948afb4cef95f424fa0037971a9a5c" integrity sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ== -"@types/node@^12.7.1": - version "12.12.58" - resolved "https://registry.npmjs.org/@types/node/-/node-12.12.58.tgz#46dae9b2b9ee5992818c8f7cee01ff4ce03ab44c" - integrity sha512-Be46CNIHWAagEfINOjmriSxuv7IVcqbGe+sDSg2SYCEz/0CRBy7LRASGfRbD8KZkqoePU73Wsx3UvOSFcq/9hA== +"@types/node@^14.0.10", "@types/node@^14.14.31", "@types/node@^14.14.32": + version "14.17.8" + resolved "https://registry.npmjs.org/@types/node/-/node-14.17.8.tgz#813b73ab7d82ac06ddfd2458b13c88459a3b319f" + integrity sha512-0CHLt50GbUmH/6MrlBIKNdWCglvlyQKkorRf08/0DIi0ryuTPP+ijWLSI19SbDTHSKaagGDELiImY4BSikt61w== "@types/node@^15.6.1": version "15.14.9" resolved "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== -"@types/node@^16.9.2": - version "16.11.6" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" - integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== - "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" From 39553c13576738a4c4de79ec92122b4db9ec6ee3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Dec 2021 04:23:56 +0000 Subject: [PATCH 111/189] build(deps): bump eslint-plugin-import from 2.22.1 to 2.25.3 Bumps [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) from 2.22.1 to 2.25.3. - [Release notes](https://github.com/import-js/eslint-plugin-import/releases) - [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md) - [Commits](https://github.com/import-js/eslint-plugin-import/compare/v2.22.1...v2.25.3) --- updated-dependencies: - dependency-name: eslint-plugin-import dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- yarn.lock | 144 ++++++++++++++++++++---------------------------------- 1 file changed, 53 insertions(+), 91 deletions(-) diff --git a/yarn.lock b/yarn.lock index 19f6ad2b27..f202ed7318 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9757,13 +9757,14 @@ array-unique@^0.3.2: resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -array.prototype.flat@^1.2.1, array.prototype.flat@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" - integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== +array.prototype.flat@^1.2.1, array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" + es-abstract "^1.19.0" array.prototype.flatmap@^1.2.1, array.prototype.flatmap@^1.2.4, array.prototype.flatmap@^1.2.5: version "1.2.5" @@ -11939,11 +11940,6 @@ constants-browserify@^1.0.0: resolved "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= - content-disposition@0.5.2: version "0.5.2" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -13042,10 +13038,10 @@ debug@4.3.1: dependencies: ms "2.1.2" -debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: - version "3.2.6" - resolved "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== +debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6, debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" @@ -13436,14 +13432,6 @@ dockerode@^3.3.1: docker-modem "^3.0.0" tar-fs "~2.0.1" -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - doctrine@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -14234,20 +14222,21 @@ eslint-formatter-friendly@^7.0.0: strip-ansi "5.2.0" text-table "0.2.0" -eslint-import-resolver-node@^0.3.4: - version "0.3.4" - resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" - integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA== +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== dependencies: - debug "^2.6.9" - resolve "^1.13.1" + debug "^3.2.7" + resolve "^1.20.0" -eslint-module-utils@^2.1.1, eslint-module-utils@^2.6.0: - version "2.6.0" - resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== +eslint-module-utils@^2.1.1, eslint-module-utils@^2.7.1: + version "2.7.1" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz#b435001c9f8dd4ab7f6d0efcae4b9696d4c24b7c" + integrity sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ== dependencies: - debug "^2.6.9" + debug "^3.2.7" + find-up "^2.1.0" pkg-dir "^2.0.0" eslint-plugin-cypress@^2.10.3: @@ -14268,23 +14257,23 @@ eslint-plugin-graphql@^4.0.0: lodash.without "^4.4.0" eslint-plugin-import@^2.20.2: - version "2.22.1" - resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" - integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw== + version "2.25.3" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz#a554b5f66e08fb4f6dc99221866e57cfff824766" + integrity sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg== dependencies: - array-includes "^3.1.1" - array.prototype.flat "^1.2.3" - contains-path "^0.1.0" + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" debug "^2.6.9" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.4" - eslint-module-utils "^2.6.0" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.1" has "^1.0.3" + is-core-module "^2.8.0" + is-glob "^4.0.3" minimatch "^3.0.4" - object.values "^1.1.1" - read-pkg-up "^2.0.0" - resolve "^1.17.0" - tsconfig-paths "^3.9.0" + object.values "^1.1.5" + resolve "^1.20.0" + tsconfig-paths "^3.11.0" eslint-plugin-jest@^24.1.0: version "24.3.6" @@ -17524,10 +17513,10 @@ is-ci@^3.0.0: dependencies: ci-info "^3.1.1" -is-core-module@^2.1.0, is-core-module@^2.2.0: - version "2.4.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" - integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== +is-core-module@^2.1.0, is-core-module@^2.2.0, is-core-module@^2.8.0: + version "2.8.0" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== dependencies: has "^1.0.3" @@ -17650,7 +17639,7 @@ is-generator-function@^1.0.7: resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz#dfb5c2b120e02b0a8d9d2c6806cd5621aa922f7b" integrity sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ== -is-glob@4.0.1, is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -17671,6 +17660,13 @@ is-glob@^3.0.0, is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-hexadecimal@^1.0.0: version "1.0.4" resolved "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" @@ -19668,16 +19664,6 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -22231,7 +22217,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -object.values@^1.1.0, object.values@^1.1.1, object.values@^1.1.5: +object.values@^1.1.0, object.values@^1.1.5: version "1.1.5" resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== @@ -23066,13 +23052,6 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -24930,14 +24909,6 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - read-pkg-up@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" @@ -24964,15 +24935,6 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -25612,7 +25574,7 @@ resolve-url@^0.2.1: resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.19.0, resolve@^1.3.2, resolve@^1.9.0: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.2, resolve@^1.9.0: version "1.20.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -28263,10 +28225,10 @@ ts-pnp@^1.1.6: resolved "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== -tsconfig-paths@^3.9.0: - version "3.9.0" - resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== +tsconfig-paths@^3.11.0: + version "3.12.0" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" + integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" From 1680a1c5ac061e58a0d1146310d4de10a00f33d1 Mon Sep 17 00:00:00 2001 From: Dede Hamzah Date: Tue, 14 Dec 2021 15:09:32 +0700 Subject: [PATCH 112/189] Add Missing Overridable Components Type for SidebarSpace, SidebarSpacer, and SidebarDivider Components Signed-off-by: Dede Hamzah --- .changeset/stupid-mice-dream.md | 5 +++++ packages/core-components/src/layout/Sidebar/Items.tsx | 6 ++++++ packages/core-components/src/layout/Sidebar/index.ts | 7 ++++++- packages/core-components/src/overridableComponents.ts | 6 ++++++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 .changeset/stupid-mice-dream.md diff --git a/.changeset/stupid-mice-dream.md b/.changeset/stupid-mice-dream.md new file mode 100644 index 0000000000..17d2609585 --- /dev/null +++ b/.changeset/stupid-mice-dream.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Add Missing Overridable Components Type for SidebarSpace, SidebarSpacer, and SidebarDivider Components. diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index c8c6db13a2..dac35bd3a7 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -548,6 +548,8 @@ export function SidebarSearchField(props: SidebarSearchFieldProps) { ); } +export type SidebarSpaceClassKey = 'root'; + export const SidebarSpace = styled('div')( { flex: 1, @@ -555,6 +557,8 @@ export const SidebarSpace = styled('div')( { name: 'BackstageSidebarSpace' }, ); +export type SidebarSpacerClassKey = 'root'; + export const SidebarSpacer = styled('div')( { height: 8, @@ -562,6 +566,8 @@ export const SidebarSpacer = styled('div')( { name: 'BackstageSidebarSpacer' }, ); +export type SidebarDividerClassKey = 'root'; + export const SidebarDivider = styled('hr')( { height: 1, diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index 79a86023ee..3d922f1322 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -33,7 +33,12 @@ export { SidebarSpacer, SidebarScrollWrapper, } from './Items'; -export type { SidebarItemClassKey } from './Items'; +export type { + SidebarItemClassKey, + SidebarSpaceClassKey, + SidebarSpacerClassKey, + SidebarDividerClassKey, +} from './Items'; export { IntroCard, SidebarIntro } from './Intro'; export type { SidebarIntroClassKey } from './Intro'; export { diff --git a/packages/core-components/src/overridableComponents.ts b/packages/core-components/src/overridableComponents.ts index 98b8f83abd..c53c47da1b 100644 --- a/packages/core-components/src/overridableComponents.ts +++ b/packages/core-components/src/overridableComponents.ts @@ -83,6 +83,9 @@ import { ItemCardHeaderClassKey, PageClassKey, SidebarClassKey, + SidebarSpaceClassKey, + SidebarSpacerClassKey, + SidebarDividerClassKey, SidebarIntroClassKey, SidebarItemClassKey, SidebarPageClassKey, @@ -157,6 +160,9 @@ type BackstageComponentsNameToClassKey = { BackstageItemCardHeader: ItemCardHeaderClassKey; BackstagePage: PageClassKey; BackstageSidebar: SidebarClassKey; + BackstageSidebarSpace: SidebarSpaceClassKey; + BackstageSidebarSpacer: SidebarSpacerClassKey; + BackstageSidebarDivider: SidebarDividerClassKey; BackstageSidebarIntro: SidebarIntroClassKey; BackstageSidebarItem: SidebarItemClassKey; BackstageSidebarPage: SidebarPageClassKey; From 9c0265a6aa9827f0640c97c1c3ad845f4199e6d4 Mon Sep 17 00:00:00 2001 From: Dede Hamzah Date: Tue, 14 Dec 2021 16:37:13 +0700 Subject: [PATCH 113/189] Update changeset to fix failed Vale Signed-off-by: Dede Hamzah --- .changeset/stupid-mice-dream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/stupid-mice-dream.md b/.changeset/stupid-mice-dream.md index 17d2609585..2cd2b4e067 100644 --- a/.changeset/stupid-mice-dream.md +++ b/.changeset/stupid-mice-dream.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- -Add Missing Overridable Components Type for SidebarSpace, SidebarSpacer, and SidebarDivider Components. +Add Missing Override Components Type for SidebarSpace, SidebarSpacer, and SidebarDivider Components. From 5b54d634778bc962a4e90c20d6b77aef3c9280cb Mon Sep 17 00:00:00 2001 From: Dede Hamzah Date: Tue, 14 Dec 2021 16:53:31 +0700 Subject: [PATCH 114/189] Add missing api report Signed-off-by: Dede Hamzah --- packages/core-components/api-report.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index d098403113..e12a6e04fe 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1152,6 +1152,11 @@ export const SidebarDivider: React_2.ComponentType< } >; +// Warning: (ae-missing-release-tag) "SidebarDividerClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type SidebarDividerClassKey = 'root'; + // @public export const SidebarExpandButton: () => JSX.Element | null; @@ -1760,6 +1765,11 @@ export const SidebarSpace: React_2.ComponentType< } >; +// Warning: (ae-missing-release-tag) "SidebarSpaceClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type SidebarSpaceClassKey = 'root'; + // Warning: (ae-missing-release-tag) "SidebarSpacer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -2029,6 +2039,11 @@ export const SidebarSpacer: React_2.ComponentType< } >; +// Warning: (ae-missing-release-tag) "SidebarSpacerClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type SidebarSpacerClassKey = 'root'; + // @public export const SidebarSubmenu: (props: SidebarSubmenuProps) => JSX.Element; From 5053de976c557b067c5bc30932817015ef696751 Mon Sep 17 00:00:00 2001 From: Brian Fletcher Date: Tue, 14 Dec 2021 11:43:03 +0000 Subject: [PATCH 115/189] add cronjobs to list of required permissions Signed-off-by: Brian Fletcher --- docs/features/kubernetes/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 07a12f54a0..2c5aefe7c3 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -263,6 +263,7 @@ following objects: - replicasets - horizontalpodautoscalers - ingresses +- cronjobs ## Surfacing your Kubernetes components as part of an entity From 68512f51786d6b032ba8b4494a2f7a3c30bfa8b7 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Thu, 18 Nov 2021 14:03:56 +0200 Subject: [PATCH 116/189] Add ability to re-use search cluster configuration from engine Signed-off-by: Charles Lowell --- ...w-client-method-to-elastic-search-egine.md | 6 + .../engines/ElasticSearchSearchEngine.test.ts | 13 +- .../src/engines/ElasticSearchSearchEngine.ts | 200 ++++++++++-------- 3 files changed, 128 insertions(+), 91 deletions(-) create mode 100644 .changeset/add-new-client-method-to-elastic-search-egine.md diff --git a/.changeset/add-new-client-method-to-elastic-search-egine.md b/.changeset/add-new-client-method-to-elastic-search-egine.md new file mode 100644 index 0000000000..b508d30bd2 --- /dev/null +++ b/.changeset/add-new-client-method-to-elastic-search-egine.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-search-backend-module-elasticsearch': minor +--- + +Add `newClient()` method to re-use the configuration of the elastic search +engine with custom clients diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts index 2877632013..0c80ef951d 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts @@ -15,7 +15,6 @@ */ import { getVoidLogger } from '@backstage/backend-common'; -import { SearchEngine } from '@backstage/search-common'; import { Client } from '@elastic/elasticsearch'; import Mock from '@elastic/elasticsearch-mock'; import { @@ -33,28 +32,30 @@ class ElasticSearchSearchEngineForTranslatorTests extends ElasticSearchSearchEng } const mock = new Mock(); -const client = new Client({ +const options = { node: 'http://localhost:9200', Connection: mock.getConnection(), -}); +}; describe('ElasticSearchSearchEngine', () => { - let testSearchEngine: SearchEngine; + let testSearchEngine: ElasticSearchSearchEngine; let inspectableSearchEngine: ElasticSearchSearchEngineForTranslatorTests; + let client: Client; beforeEach(() => { testSearchEngine = new ElasticSearchSearchEngine( - client, + options, 'search', '', getVoidLogger(), ); inspectableSearchEngine = new ElasticSearchSearchEngineForTranslatorTests( - client, + options, 'search', '', getVoidLogger(), ); + client = testSearchEngine.elasticSearchClient; }); describe('queryTranslator', () => { diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index 7912c691b3..1f2857fbd2 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -30,6 +30,12 @@ import esb from 'elastic-builder'; import { isEmpty, isNaN as nan, isNumber } from 'lodash'; import { Logger } from 'winston'; +export type ElasticSearchClientOptions = ConstructorParameters< + typeof Client +>[0] & { + provider?: 'aws' | 'elastic' | 'generic'; +}; + export type ConcreteElasticSearchQuery = { documentTypes?: string[]; elasticSearchQuery: Object; @@ -68,105 +74,56 @@ function isBlank(str: string) { * @public */ export class ElasticSearchSearchEngine implements SearchEngine { + private readonly elasticSearchClient: Client = this.newClient( + options => new Client(options), + ); constructor( - private readonly elasticSearchClient: Client, + private readonly elasticSearchClientOptions: ElasticSearchClientOptions, private readonly aliasPostfix: string, private readonly indexPrefix: string, private readonly logger: Logger, ) {} - static async fromConfig(options: ElasticSearchOptions) { - const { - logger, - config, - aliasPostfix = `search`, - indexPrefix = ``, - } = options; + static async fromConfig({ + logger, + config, + aliasPostfix = `search`, + indexPrefix = ``, + }: ElasticSearchOptions) { + const options = await createElasticSearchClientOptions( + config.getConfig('search.elasticsearch'), + ); + if (options.provider === 'elastic') { + logger.info('Initializing Elastic.co ElasticSearch search engine.'); + } else if (options.provider === 'aws') { + logger.info('Initializing AWS ElasticSearch search engine.'); + } else { + logger.info('Initializing ElasticSearch search engine.'); + } return new ElasticSearchSearchEngine( - await ElasticSearchSearchEngine.constructElasticSearchClient( - logger, - config.getConfig('search.elasticsearch'), - ), + options, aliasPostfix, indexPrefix, logger, ); } - private static async constructElasticSearchClient( - logger: Logger, - config?: Config, - ) { - if (!config) { - throw new Error('No elastic search config found'); - } - - const clientOptionsConfig = config.getOptionalConfig('clientOptions'); - const sslConfig = clientOptionsConfig?.getOptionalConfig('ssl'); - - if (config.getOptionalString('provider') === 'elastic') { - logger.info('Initializing Elastic.co ElasticSearch search engine.'); - const authConfig = config.getConfig('auth'); - return new Client({ - cloud: { - id: config.getString('cloudId'), - }, - auth: { - username: authConfig.getString('username'), - password: authConfig.getString('password'), - }, - ...(sslConfig - ? { - ssl: { - rejectUnauthorized: - sslConfig?.getOptionalBoolean('rejectUnauthorized'), - }, - } - : {}), - }); - } - if (config.getOptionalString('provider') === 'aws') { - logger.info('Initializing AWS ElasticSearch search engine.'); - const awsCredentials = await awsGetCredentials(); - const AWSConnection = createAWSConnection(awsCredentials); - return new Client({ - node: config.getString('node'), - ...AWSConnection, - ...(sslConfig - ? { - ssl: { - rejectUnauthorized: - sslConfig?.getOptionalBoolean('rejectUnauthorized'), - }, - } - : {}), - }); - } - logger.info('Initializing ElasticSearch search engine.'); - const authConfig = config.getOptionalConfig('auth'); - const auth = - authConfig && - (authConfig.has('apiKey') - ? { - apiKey: authConfig.getString('apiKey'), - } - : { - username: authConfig.getString('username'), - password: authConfig.getString('password'), - }); - return new Client({ - node: config.getString('node'), - auth, - ...(sslConfig - ? { - ssl: { - rejectUnauthorized: - sslConfig?.getOptionalBoolean('rejectUnauthorized'), - }, - } - : {}), - }); + /** + * Re-use the configuration of this search engine in order to construct other + * elastic search clients. This is useful if you want to create a client that + * talks to the same search cluster as your search engine, but you want to + * provide queries and receive results using a completely different format + * such as Relay pagination, or faceted search. + * + * ```javascript + * import { Client } from '@elastic/elastic-search'; + * + * let client = engine.newClient(options => new Client(options)); + * ``` + */ + newClient(create: (options: ElasticSearchClientOptions) => T): T { + return create(this.elasticSearchClientOptions); } protected translator(query: SearchQuery): ConcreteElasticSearchQuery { @@ -349,3 +306,76 @@ export function decodePageCursor(pageCursor?: string): { page: number } { export function encodePageCursor({ page }: { page: number }): string { return Buffer.from(`${page}`, 'utf-8').toString('base64'); } + +async function createElasticSearchClientOptions( + config?: Config, +): Promise { + if (!config) { + throw new Error('No elastic search config found'); + } + const clientOptionsConfig = config.getOptionalConfig('clientOptions'); + const sslConfig = clientOptionsConfig?.getOptionalConfig('ssl'); + + if (config.getOptionalString('provider') === 'elastic') { + const authConfig = config.getConfig('auth'); + return { + provider: 'elastic', + cloud: { + id: config.getString('cloudId'), + }, + auth: { + username: authConfig.getString('username'), + password: authConfig.getString('password'), + }, + ...(sslConfig + ? { + ssl: { + rejectUnauthorized: + sslConfig?.getOptionalBoolean('rejectUnauthorized'), + }, + } + : {}), + }; + } + if (config.getOptionalString('provider') === 'aws') { + const awsCredentials = await awsGetCredentials(); + const AWSConnection = createAWSConnection(awsCredentials); + return { + provider: 'aws', + node: config.getString('node'), + ...AWSConnection, + ...(sslConfig + ? { + ssl: { + rejectUnauthorized: + sslConfig?.getOptionalBoolean('rejectUnauthorized'), + }, + } + : {}), + }; + } + const authConfig = config.getOptionalConfig('auth'); + const auth = + authConfig && + (authConfig.has('apiKey') + ? { + apiKey: authConfig.getString('apiKey'), + } + : { + username: authConfig.getString('username'), + password: authConfig.getString('password'), + }); + return { + provider: 'generic', + node: config.getString('node'), + auth, + ...(sslConfig + ? { + ssl: { + rejectUnauthorized: + sslConfig?.getOptionalBoolean('rejectUnauthorized'), + }, + } + : {}), + }; +} From 29ca4a2b4c85effde27dcfd46bdd33b1c0c2d05c Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 22 Nov 2021 12:27:00 +0200 Subject: [PATCH 117/189] =?UTF-8?q?=F0=9F=91=8Ddowngrade=20changset=20to?= =?UTF-8?q?=20a=20patch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Charles Lowell --- .changeset/add-new-client-method-to-elastic-search-egine.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/add-new-client-method-to-elastic-search-egine.md b/.changeset/add-new-client-method-to-elastic-search-egine.md index b508d30bd2..9e5c363522 100644 --- a/.changeset/add-new-client-method-to-elastic-search-egine.md +++ b/.changeset/add-new-client-method-to-elastic-search-egine.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-search-backend-module-elasticsearch': minor +'@backstage/plugin-search-backend-module-elasticsearch': patch --- Add `newClient()` method to re-use the configuration of the elastic search From 445a48e7ebca69e14599859252aaa89ca5916108 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 22 Nov 2021 12:27:40 +0200 Subject: [PATCH 118/189] =?UTF-8?q?=F0=9F=91=8DUse=20a=20separately=20main?= =?UTF-8?q?tained=20set=20of=20ElasticSearchClientOptions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This completely decouples us from any particular point release of the ElasticSearch Client Signed-off-by: Charles Lowell --- .../src/engines/ElasticSearchClientOptions.ts | 125 ++++++++++++++++++ .../engines/ElasticSearchSearchEngine.test.ts | 3 +- .../src/engines/ElasticSearchSearchEngine.ts | 9 +- .../src/engines/index.ts | 5 +- 4 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientOptions.ts diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientOptions.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientOptions.ts new file mode 100644 index 0000000000..73cb149c0a --- /dev/null +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchClientOptions.ts @@ -0,0 +1,125 @@ +/* + * 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 type { ConnectionOptions as TLSConnectionOptions } from 'tls'; + +/** + * Options used to configure the `@elastic/elasticsearch` client and + * are what will be passed as an argument to the + * {@link ElasticSearchEngine.newClient} method + * + * They are drawn from the `ClientOptions` class of `@elastic/elasticsearch`, + * but are maintained separately so that this interface is not coupled to + */ +export interface ElasticSearchClientOptions { + provider?: 'aws' | 'elastic'; + node?: + | string + | string[] + | ElasticSearchNodeOptions + | ElasticSearchNodeOptions[]; + nodes?: + | string + | string[] + | ElasticSearchNodeOptions + | ElasticSearchNodeOptions[]; + Transport?: ElasticSearchTransportConstructor; + Connection?: ElasticSearchConnectionConstructor; + maxRetries?: number; + requestTimeout?: number; + pingTimeout?: number; + sniffInterval?: number | boolean; + sniffOnStart?: boolean; + sniffEndpoint?: string; + sniffOnConnectionFault?: boolean; + resurrectStrategy?: 'ping' | 'optimistic' | 'none'; + suggestCompression?: boolean; + compression?: 'gzip'; + ssl?: TLSConnectionOptions; + agent?: ElasticSearchAgentOptions | ((opts?: any) => unknown) | false; + nodeFilter?: (connection: any) => boolean; + nodeSelector?: ((connections: any[]) => any) | string; + headers?: Record; + opaqueIdPrefix?: string; + name?: string | symbol; + auth?: ElasticSearchAuth; + proxy?: string | URL; + enableMetaHeader?: boolean; + cloud?: { + id: string; + username?: string; + password?: string; + }; + disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor'; +} + +export type ElasticSearchAuth = + | { + username: string; + password: string; + } + | { + apiKey: + | string + | { + id: string; + api_key: string; + }; + }; + +export interface ElasticSearchNodeOptions { + url: URL; + id?: string; + agent?: ElasticSearchAgentOptions; + ssl?: TLSConnectionOptions; + headers?: Record; + roles?: { + master: boolean; + data: boolean; + ingest: boolean; + ml: boolean; + }; +} + +export interface ElasticSearchAgentOptions { + keepAlive?: boolean; + keepAliveMsecs?: number; + maxSockets?: number; + maxFreeSockets?: number; +} + +export interface ElasticSearchConnectionConstructor { + new (opts?: any): any; + statuses: { + ALIVE: string; + DEAD: string; + }; + roles: { + MASTER: string; + DATA: string; + INGEST: string; + ML: string; + }; +} + +export interface ElasticSearchTransportConstructor { + new (opts?: any): any; + sniffReasons: { + SNIFF_ON_START: string; + SNIFF_INTERVAL: string; + SNIFF_ON_CONNECTION_FAULT: string; + DEFAULT: string; + }; +} diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts index 0c80ef951d..1566a35b57 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts @@ -55,7 +55,8 @@ describe('ElasticSearchSearchEngine', () => { '', getVoidLogger(), ); - client = testSearchEngine.elasticSearchClient; + // eslint-disable-next-line dot-notation + client = testSearchEngine['elasticSearchClient']; }); describe('queryTranslator', () => { diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index 1f2857fbd2..d4814d37f3 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -30,11 +30,9 @@ import esb from 'elastic-builder'; import { isEmpty, isNaN as nan, isNumber } from 'lodash'; import { Logger } from 'winston'; -export type ElasticSearchClientOptions = ConstructorParameters< - typeof Client ->[0] & { - provider?: 'aws' | 'elastic' | 'generic'; -}; +import type { ElasticSearchClientOptions } from './ElasticSearchClientOptions'; + +export type { ElasticSearchClientOptions }; export type ConcreteElasticSearchQuery = { documentTypes?: string[]; @@ -366,7 +364,6 @@ async function createElasticSearchClientOptions( password: authConfig.getString('password'), }); return { - provider: 'generic', node: config.getString('node'), auth, ...(sslConfig diff --git a/plugins/search-backend-module-elasticsearch/src/engines/index.ts b/plugins/search-backend-module-elasticsearch/src/engines/index.ts index 2f3641c114..d5eee37803 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/index.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/index.ts @@ -15,4 +15,7 @@ */ export { ElasticSearchSearchEngine } from './ElasticSearchSearchEngine'; -export type { ConcreteElasticSearchQuery } from './ElasticSearchSearchEngine'; +export type { + ConcreteElasticSearchQuery, + ElasticSearchClientOptions, +} from './ElasticSearchSearchEngine'; From 35e3f6f52e36ca8411bd2052db8a13b964cfec36 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Mon, 22 Nov 2021 23:50:47 +0200 Subject: [PATCH 119/189] Add changes to API Report Signed-off-by: Charles Lowell --- .../api-report.md | 99 ++++++++++++++++++- .../src/index.ts | 1 + 2 files changed, 95 insertions(+), 5 deletions(-) diff --git a/plugins/search-backend-module-elasticsearch/api-report.md b/plugins/search-backend-module-elasticsearch/api-report.md index 1e798119c3..6dc0256586 100644 --- a/plugins/search-backend-module-elasticsearch/api-report.md +++ b/plugins/search-backend-module-elasticsearch/api-report.md @@ -3,18 +3,103 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts -import { Client } from '@elastic/elasticsearch'; +/// + import { Config } from '@backstage/config'; +import type { ConnectionOptions } from 'tls'; import { IndexableDocument } from '@backstage/search-common'; import { Logger as Logger_2 } from 'winston'; import { SearchEngine } from '@backstage/search-common'; import { SearchQuery } from '@backstage/search-common'; import { SearchResultSet } from '@backstage/search-common'; +// Warning: (ae-missing-release-tag) "ElasticSearchClientOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/plugin-search-backend-module-elasticsearch" does not have an export "ElasticSearchEngine" +// +// @public +export interface ElasticSearchClientOptions { + // Warning: (ae-forgotten-export) The symbol "ElasticSearchAgentOptions" needs to be exported by the entry point index.d.ts + // + // (undocumented) + agent?: ElasticSearchAgentOptions | ((opts?: any) => unknown) | false; + // Warning: (ae-forgotten-export) The symbol "ElasticSearchAuth" needs to be exported by the entry point index.d.ts + // + // (undocumented) + auth?: ElasticSearchAuth; + // (undocumented) + cloud?: { + id: string; + username?: string; + password?: string; + }; + // (undocumented) + compression?: 'gzip'; + // Warning: (ae-forgotten-export) The symbol "ElasticSearchConnectionConstructor" needs to be exported by the entry point index.d.ts + // + // (undocumented) + Connection?: ElasticSearchConnectionConstructor; + // (undocumented) + disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor'; + // (undocumented) + enableMetaHeader?: boolean; + // (undocumented) + headers?: Record; + // (undocumented) + maxRetries?: number; + // (undocumented) + name?: string | symbol; + // Warning: (ae-forgotten-export) The symbol "ElasticSearchNodeOptions" needs to be exported by the entry point index.d.ts + // + // (undocumented) + node?: + | string + | string[] + | ElasticSearchNodeOptions + | ElasticSearchNodeOptions[]; + // (undocumented) + nodeFilter?: (connection: any) => boolean; + // (undocumented) + nodes?: + | string + | string[] + | ElasticSearchNodeOptions + | ElasticSearchNodeOptions[]; + // (undocumented) + nodeSelector?: ((connections: any[]) => any) | string; + // (undocumented) + opaqueIdPrefix?: string; + // (undocumented) + pingTimeout?: number; + // (undocumented) + provider?: 'aws' | 'elastic'; + // (undocumented) + proxy?: string | URL; + // (undocumented) + requestTimeout?: number; + // (undocumented) + resurrectStrategy?: 'ping' | 'optimistic' | 'none'; + // (undocumented) + sniffEndpoint?: string; + // (undocumented) + sniffInterval?: number | boolean; + // (undocumented) + sniffOnConnectionFault?: boolean; + // (undocumented) + sniffOnStart?: boolean; + // (undocumented) + ssl?: ConnectionOptions; + // (undocumented) + suggestCompression?: boolean; + // Warning: (ae-forgotten-export) The symbol "ElasticSearchTransportConstructor" needs to be exported by the entry point index.d.ts + // + // (undocumented) + Transport?: ElasticSearchTransportConstructor; +} + // @public (undocumented) export class ElasticSearchSearchEngine implements SearchEngine { constructor( - elasticSearchClient: Client, + elasticSearchClientOptions: ElasticSearchClientOptions, aliasPostfix: string, indexPrefix: string, logger: Logger_2, @@ -22,11 +107,15 @@ export class ElasticSearchSearchEngine implements SearchEngine { // Warning: (ae-forgotten-export) The symbol "ElasticSearchOptions" needs to be exported by the entry point index.d.ts // // (undocumented) - static fromConfig( - options: ElasticSearchOptions, - ): Promise; + static fromConfig({ + logger, + config, + aliasPostfix, + indexPrefix, + }: ElasticSearchOptions): Promise; // (undocumented) index(type: string, documents: IndexableDocument[]): Promise; + newClient(create: (options: ElasticSearchClientOptions) => T): T; // (undocumented) query(query: SearchQuery): Promise; // Warning: (ae-forgotten-export) The symbol "ElasticSearchQueryTranslator" needs to be exported by the entry point index.d.ts diff --git a/plugins/search-backend-module-elasticsearch/src/index.ts b/plugins/search-backend-module-elasticsearch/src/index.ts index b4dab93b76..8cf96de858 100644 --- a/plugins/search-backend-module-elasticsearch/src/index.ts +++ b/plugins/search-backend-module-elasticsearch/src/index.ts @@ -21,3 +21,4 @@ */ export { ElasticSearchSearchEngine } from './engines'; +export type { ElasticSearchClientOptions } from './engines'; From a41fbfe73973dc8a53f647966228a691d331d8b6 Mon Sep 17 00:00:00 2001 From: Iain Billett Date: Tue, 14 Dec 2021 09:39:27 +0000 Subject: [PATCH 120/189] Search result location filtering Introduces filtering of unsafe search result locations. Signed-off-by: Iain Billett --- .changeset/sixty-pandas-switch.md | 8 ++ packages/backend/src/plugins/search.ts | 1 + .../search-backend/src/service/router.test.ts | 79 ++++++++++++++++++- plugins/search-backend/src/service/router.ts | 32 +++++++- 4 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 .changeset/sixty-pandas-switch.md diff --git a/.changeset/sixty-pandas-switch.md b/.changeset/sixty-pandas-switch.md new file mode 100644 index 0000000000..91e767e154 --- /dev/null +++ b/.changeset/sixty-pandas-switch.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-search-backend': minor +--- + +Search result location filtering + +This change introduces a filter for search results based on their location protocol. The intention is to filter out unsafe or +malicious values before they can be consumed by the frontend. By default locations must be http/https URLs (or paths). diff --git a/packages/backend/src/plugins/search.ts b/packages/backend/src/plugins/search.ts index 9a8db0f0f9..5659968e1d 100644 --- a/packages/backend/src/plugins/search.ts +++ b/packages/backend/src/plugins/search.ts @@ -96,5 +96,6 @@ export default async function createPlugin({ return await createRouter({ engine: indexBuilder.getSearchEngine(), logger, + discovery, }); } diff --git a/plugins/search-backend/src/service/router.test.ts b/plugins/search-backend/src/service/router.test.ts index 4b3cb30264..aeb5709379 100644 --- a/plugins/search-backend/src/service/router.test.ts +++ b/plugins/search-backend/src/service/router.test.ts @@ -14,10 +14,14 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; +import { + getVoidLogger, + PluginEndpointDiscovery, +} from '@backstage/backend-common'; import { IndexBuilder, LunrSearchEngine, + SearchEngine, } from '@backstage/plugin-search-backend-node'; import express from 'express'; import request from 'supertest'; @@ -26,14 +30,22 @@ import { createRouter } from './router'; describe('createRouter', () => { let app: express.Express; + let mockDiscoveryApi: jest.Mocked; + let mockSearchEngine: jest.Mocked; beforeAll(async () => { const logger = getVoidLogger(); const searchEngine = new LunrSearchEngine({ logger }); const indexBuilder = new IndexBuilder({ logger, searchEngine }); + mockDiscoveryApi = { + getBaseUrl: jest.fn(), + getExternalBaseUrl: jest.fn().mockResolvedValue('http://localhost:3000/'), + }; + const router = await createRouter({ engine: indexBuilder.getSearchEngine(), logger, + discovery: mockDiscoveryApi, }); app = express().use(router); }); @@ -49,5 +61,70 @@ describe('createRouter', () => { expect(response.status).toEqual(200); expect(response.body).toMatchObject({ results: [] }); }); + + describe('search result filtering', () => { + beforeAll(async () => { + const logger = getVoidLogger(); + mockDiscoveryApi = { + getBaseUrl: jest.fn(), + getExternalBaseUrl: jest + .fn() + .mockResolvedValue('http://localhost:3000/'), + }; + mockSearchEngine = { + index: jest.fn(), + setTranslator: jest.fn(), + query: jest.fn(), + }; + const indexBuilder = new IndexBuilder({ + logger, + searchEngine: mockSearchEngine, + }); + + const router = await createRouter({ + engine: indexBuilder.getSearchEngine(), + logger, + discovery: mockDiscoveryApi, + }); + app = express().use(router); + }); + + describe('where the search result set includes unsafe results', () => { + const safeResult = { + type: 'software-catalog', + document: { + text: 'safe', + title: 'safe-location', + // eslint-disable-next-line no-script-url + location: '/catalog/default/component/safe', + }, + }; + beforeEach(() => { + mockSearchEngine.query.mockResolvedValue({ + results: [ + { + type: 'software-catalog', + document: { + text: 'unsafe', + title: 'unsafe-location', + // eslint-disable-next-line no-script-url + location: 'javascript:alert("unsafe")', + }, + }, + safeResult, + ], + nextPageCursor: '', + previousPageCursor: '', + }); + }); + + it('removes the unsafe results', async () => { + const response = await request(app).get('/query'); + + expect(response.status).toEqual(200); + expect(response.body).toMatchObject({ results: [safeResult] }); + }); + }); + }); }); }); diff --git a/plugins/search-backend/src/service/router.ts b/plugins/search-backend/src/service/router.ts index 5bd99988a7..e13e0cc3bf 100644 --- a/plugins/search-backend/src/service/router.ts +++ b/plugins/search-backend/src/service/router.ts @@ -19,16 +19,42 @@ import Router from 'express-promise-router'; import { Logger } from 'winston'; import { SearchQuery, SearchResultSet } from '@backstage/search-common'; import { SearchEngine } from '@backstage/plugin-search-backend-node'; +import { PluginEndpointDiscovery } from '@backstage/backend-common'; export type RouterOptions = { engine: SearchEngine; logger: Logger; + discovery: PluginEndpointDiscovery; + allowedLocationProtocols?: string[]; }; +const defaultAllowedLocationProtocols = ['http:', 'https:']; + export async function createRouter( options: RouterOptions, ): Promise { - const { engine, logger } = options; + const { + engine, + logger, + discovery, + allowedLocationProtocols = defaultAllowedLocationProtocols, + } = options; + const baseUrl = await discovery.getExternalBaseUrl(''); + + const filterResultSet = ({ results, ...resultSet }: SearchResultSet) => ({ + ...resultSet, + results: results.filter(result => { + const protocol = new URL(result.document.location, baseUrl).protocol; + const isAllowed = allowedLocationProtocols.includes(protocol); + if (!isAllowed) { + logger.info( + `Rejected search result for "${result.document.title}" as location protocol "${protocol}" is unsafe`, + ); + } + return isAllowed; + }), + }); + const router = Router(); router.get( '/query', @@ -46,8 +72,8 @@ export async function createRouter( ); try { - const results = await engine?.query(req.query); - res.send(results); + const resultSet = await engine?.query(req.query); + res.send(filterResultSet(resultSet)); } catch (err) { throw new Error( `There was a problem performing the search query. ${err}`, From 71472b7bd8052f041f4ae78f8233757e730abe56 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Tue, 14 Dec 2021 16:52:59 +0200 Subject: [PATCH 121/189] Remove tsdoc since it is now in the guide Signed-off-by: Charles Lowell --- .../src/engines/ElasticSearchSearchEngine.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index d4814d37f3..8cb04a8ad7 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -107,19 +107,6 @@ export class ElasticSearchSearchEngine implements SearchEngine { ); } - /** - * Re-use the configuration of this search engine in order to construct other - * elastic search clients. This is useful if you want to create a client that - * talks to the same search cluster as your search engine, but you want to - * provide queries and receive results using a completely different format - * such as Relay pagination, or faceted search. - * - * ```javascript - * import { Client } from '@elastic/elastic-search'; - * - * let client = engine.newClient(options => new Client(options)); - * ``` - */ newClient(create: (options: ElasticSearchClientOptions) => T): T { return create(this.elasticSearchClientOptions); } From daf32e2c9bd184db43fd370918672ff66a1ad870 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Tue, 14 Dec 2021 15:04:09 +0000 Subject: [PATCH 122/189] chore: Generated changeset. Signed-off-by: Marley Powell --- .changeset/silly-dryers-smile.md | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .changeset/silly-dryers-smile.md diff --git a/.changeset/silly-dryers-smile.md b/.changeset/silly-dryers-smile.md new file mode 100644 index 0000000000..7337651532 --- /dev/null +++ b/.changeset/silly-dryers-smile.md @@ -0,0 +1,58 @@ +--- +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-azure-devops-backend': patch +'@backstage/plugin-azure-devops-common': patch +--- + +Created some initial filters that can be used to create pull request columns: + +- All +- AssignedToUser +- AssignedToCurrentUser +- AssignedToTeam +- AssignedToTeams +- AssignedToCurrentUsersTeams +- CreatedByUser +- CreatedByCurrentUser +- CreatedByTeam +- CreatedByTeams +- CreatedByCurrentUsersTeams + +Example custom column creation: + +```tsx +const COLUMN_CONFIGS: PullRequestColumnConfig[] = [ + { + title: 'Created by me', + filters: [{ type: FilterType.CreatedByCurrentUser }], + }, + { + title: 'Created by Backstage Core', + filters: [ + { + type: FilterType.CreatedByTeam, + teamName: 'Backstage Core', + }, + ], + }, + { + title: 'Assigned to my teams', + filters: [{ type: FilterType.AssignedToCurrentUsersTeams }], + }, + { + title: 'Other PRs', + filters: [{ type: FilterType.All }], + simplified: true, + }, +]; + + + } +/>; +``` From 98e01d0f2b0677a56af39b0864d9c1545b1cad99 Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Tue, 14 Dec 2021 15:04:52 +0000 Subject: [PATCH 123/189] feat: Updated type exports. Signed-off-by: Marley Powell --- .../src/components/PullRequestsPage/index.ts | 14 ++++++++++++++ .../PullRequestsPage/lib/filters/index.ts | 13 ++++++++++++- .../PullRequestsPage/lib/filters/types.ts | 10 ++++++++++ plugins/azure-devops/src/index.ts | 15 +++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/plugins/azure-devops/src/components/PullRequestsPage/index.ts b/plugins/azure-devops/src/components/PullRequestsPage/index.ts index e8b6cfa6bb..4061c72a8e 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/index.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/index.ts @@ -15,3 +15,17 @@ */ export { PullRequestsPage } from './PullRequestsPage'; +export type { PullRequestColumnConfig } from './lib/types'; +export { FilterType } from './lib/filters'; +export type { + BaseFilter, + Filter, + PullRequestFilter, + AssignedToUserFilter, + CreatedByUserFilter, + AssignedToTeamFilter, + CreatedByTeamFilter, + AssignedToTeamsFilter, + CreatedByTeamsFilter, + AllFilter, +} from './lib/filters'; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts index 5470b349cf..df165dc9ca 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/index.ts @@ -16,4 +16,15 @@ export { createFilter } from './createFilter'; export { FilterTypes, FilterType } from './types'; -export type { Filter, PullRequestFilter } from './types'; +export type { + BaseFilter, + Filter, + PullRequestFilter, + AssignedToUserFilter, + CreatedByUserFilter, + AssignedToTeamFilter, + CreatedByTeamFilter, + AssignedToTeamsFilter, + CreatedByTeamsFilter, + AllFilter, +} from './types'; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts index 085f38cb30..bc4643d51b 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/types.ts @@ -70,4 +70,14 @@ export type Filter = | CreatedByTeamsFilter | AllFilter; +export type { + AssignedToUserFilter, + CreatedByUserFilter, + AssignedToTeamFilter, + CreatedByTeamFilter, + AssignedToTeamsFilter, + CreatedByTeamsFilter, + AllFilter, +}; + export type PullRequestFilter = (pullRequest: DashboardPullRequest) => boolean; diff --git a/plugins/azure-devops/src/index.ts b/plugins/azure-devops/src/index.ts index c9b804bc8d..8289a93a5c 100644 --- a/plugins/azure-devops/src/index.ts +++ b/plugins/azure-devops/src/index.ts @@ -23,3 +23,18 @@ export { } from './plugin'; export { AzurePullRequestsIcon } from './components/AzurePullRequestsIcon'; + +export { FilterType } from './components/PullRequestsPage'; +export type { + PullRequestColumnConfig, + BaseFilter, + Filter, + PullRequestFilter, + AssignedToUserFilter, + CreatedByUserFilter, + AssignedToTeamFilter, + CreatedByTeamFilter, + AssignedToTeamsFilter, + CreatedByTeamsFilter, + AllFilter, +} from './components/PullRequestsPage'; From cc519974963a521ea82bc89bc7b9cdf873cd596a Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Tue, 14 Dec 2021 15:09:14 +0000 Subject: [PATCH 124/189] chore: Updated API reports. Signed-off-by: Marley Powell --- plugins/azure-devops-common/api-report.md | 6 + plugins/azure-devops/api-report.md | 163 ++++++++++++++++++++++ 2 files changed, 169 insertions(+) diff --git a/plugins/azure-devops-common/api-report.md b/plugins/azure-devops-common/api-report.md index bb458f169a..85a9e54847 100644 --- a/plugins/azure-devops-common/api-report.md +++ b/plugins/azure-devops-common/api-report.md @@ -61,6 +61,10 @@ export interface CreatedBy { // (undocumented) imageUrl?: string; // (undocumented) + teamIds?: string[]; + // (undocumented) + teamNames?: string[]; + // (undocumented) uniqueName?: string; } @@ -254,6 +258,8 @@ export interface Reviewer { // (undocumented) isRequired?: boolean; // (undocumented) + uniqueName?: string; + // (undocumented) voteStatus: PullRequestVoteStatus; } diff --git a/plugins/azure-devops/api-report.md b/plugins/azure-devops/api-report.md index 0f3e3310ef..11e238e6f5 100644 --- a/plugins/azure-devops/api-report.md +++ b/plugins/azure-devops/api-report.md @@ -6,9 +6,55 @@ /// import { BackstagePlugin } from '@backstage/core-plugin-api'; +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; import { Entity } from '@backstage/catalog-model'; import { SvgIconProps } from '@material-ui/core'; +// Warning: (ae-missing-release-tag) "AllFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AllFilter = BaseFilter & { + type: FilterType.All; +}; + +// Warning: (ae-missing-release-tag) "AssignedToTeamFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AssignedToTeamFilter = BaseFilter & { + type: FilterType.AssignedToTeam; + teamId: string; +}; + +// Warning: (ae-missing-release-tag) "AssignedToTeamsFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AssignedToTeamsFilter = BaseFilter & + ( + | { + type: FilterType.AssignedToTeams; + teamIds: string[]; + } + | { + type: FilterType.AssignedToCurrentUsersTeams; + teamIds?: string[]; + } + ); + +// Warning: (ae-missing-release-tag) "AssignedToUserFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AssignedToUserFilter = BaseFilter & + ( + | { + type: FilterType.AssignedToUser; + email: string; + } + | { + type: FilterType.AssignedToCurrentUser; + email?: string; + } + ); + // Warning: (ae-missing-release-tag) "azureDevOpsPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -25,11 +71,71 @@ export const AzurePullRequestsIcon: (props: SvgIconProps) => JSX.Element; export const AzurePullRequestsPage: ({ projectName, pollingInterval, + defaultColumnConfigs, }: { projectName?: string | undefined; pollingInterval?: number | undefined; + defaultColumnConfigs?: PullRequestColumnConfig[] | undefined; }) => JSX.Element; +// Warning: (ae-missing-release-tag) "BaseFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type BaseFilter = { + type: FilterType; +}; + +// Warning: (ae-missing-release-tag) "CreatedByTeamFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type CreatedByTeamFilter = BaseFilter & + ({ + type: FilterType.CreatedByTeam; + } & ( + | { + teamId: string; + } + | { + teamName: string; + } + )); + +// Warning: (ae-missing-release-tag) "CreatedByTeamsFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type CreatedByTeamsFilter = BaseFilter & + ( + | ({ + type: FilterType.CreatedByTeams; + } & ( + | { + teamIds: string[]; + } + | { + teamNames: string[]; + } + )) + | { + type: FilterType.CreatedByCurrentUsersTeams; + teamIds?: string[]; + } + ); + +// Warning: (ae-missing-release-tag) "CreatedByUserFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type CreatedByUserFilter = BaseFilter & + ( + | { + type: FilterType.CreatedByUser; + email: string; + } + | { + type: FilterType.CreatedByCurrentUser; + email?: string; + } + ); + // Warning: (ae-missing-release-tag) "EntityAzurePipelinesContent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -48,10 +154,67 @@ export const EntityAzurePullRequestsContent: ({ defaultLimit?: number | undefined; }) => JSX.Element; +// Warning: (ae-missing-release-tag) "Filter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type Filter = + | AssignedToUserFilter + | CreatedByUserFilter + | AssignedToTeamFilter + | CreatedByTeamFilter + | AssignedToTeamsFilter + | CreatedByTeamsFilter + | AllFilter; + +// Warning: (ae-missing-release-tag) "FilterType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum FilterType { + // (undocumented) + All = 'All', + // (undocumented) + AssignedToCurrentUser = 'AssignedToCurrentUser', + // (undocumented) + AssignedToCurrentUsersTeams = 'AssignedToCurrentUsersTeams', + // (undocumented) + AssignedToTeam = 'AssignedToTeam', + // (undocumented) + AssignedToTeams = 'AssignedToTeams', + // (undocumented) + AssignedToUser = 'AssignedToUser', + // (undocumented) + CreatedByCurrentUser = 'CreatedByCurrentUser', + // (undocumented) + CreatedByCurrentUsersTeams = 'CreatedByCurrentUsersTeams', + // (undocumented) + CreatedByTeam = 'CreatedByTeam', + // (undocumented) + CreatedByTeams = 'CreatedByTeams', + // (undocumented) + CreatedByUser = 'CreatedByUser', +} + // Warning: (ae-missing-release-tag) "isAzureDevOpsAvailable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export const isAzureDevOpsAvailable: (entity: Entity) => boolean; +// Warning: (ae-missing-release-tag) "PullRequestColumnConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface PullRequestColumnConfig { + // (undocumented) + filters: Filter[]; + // (undocumented) + simplified?: boolean; + // (undocumented) + title: string; +} + +// Warning: (ae-missing-release-tag) "PullRequestFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PullRequestFilter = (pullRequest: DashboardPullRequest) => boolean; + // (No @packageDocumentation comment for this package) ``` From bd658a58b7647f986a666ff85e9a193847d4de0d Mon Sep 17 00:00:00 2001 From: Marley Powell Date: Tue, 14 Dec 2021 15:40:51 +0000 Subject: [PATCH 125/189] test: Added some unit test for pull request filters. Signed-off-by: Marley Powell --- .../lib/filters/createFilter.test.ts | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.test.ts diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.test.ts b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.test.ts new file mode 100644 index 0000000000..b0ac4d402b --- /dev/null +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/filters/createFilter.test.ts @@ -0,0 +1,150 @@ +/* + * 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 { Filter, FilterType } from './types'; + +import { DashboardPullRequest } from '@backstage/plugin-azure-devops-common'; +import { createFilter } from './createFilter'; + +describe('createFilter', () => { + const pullRequest = { + createdBy: { + uniqueName: 'user1@backstage.com', + teamIds: ['team1Id', 'team2Id'], + }, + reviewers: [ + { uniqueName: 'user2@backstage.com' }, + { id: 'team2Id' }, + { id: 'team3Id' }, + ], + } as DashboardPullRequest; + + const testCases: Array<{ filter: Filter; result: boolean }> = [ + { + filter: { + type: FilterType.AssignedToUser, + email: 'user2@backstage.com', + }, + result: true, + }, + { + filter: { + type: FilterType.AssignedToUser, + email: 'random-user@backstage.com', + }, + result: false, + }, + { + filter: { + type: FilterType.CreatedByUser, + email: 'user1@backstage.com', + }, + result: true, + }, + { + filter: { + type: FilterType.CreatedByUser, + email: 'random-user@backstage.com', + }, + result: false, + }, + { + filter: { + type: FilterType.AssignedToTeam, + teamId: 'team2Id', + }, + result: true, + }, + { + filter: { + type: FilterType.AssignedToTeam, + teamId: 'randomTeamId', + }, + result: false, + }, + { + filter: { + type: FilterType.CreatedByTeam, + teamId: 'team1Id', + }, + result: true, + }, + { + filter: { + type: FilterType.CreatedByTeam, + teamId: 'randomTeamId', + }, + result: false, + }, + { + filter: { + type: FilterType.AssignedToTeams, + teamIds: ['team2Id', 'randomTeamId'], + }, + result: true, + }, + { + filter: { + type: FilterType.AssignedToTeams, + teamIds: ['team2Id', 'team3Id'], + }, + result: true, + }, + { + filter: { + type: FilterType.AssignedToTeams, + teamIds: ['randomTeam1Id', 'randomTeam2Id'], + }, + result: false, + }, + { + filter: { + type: FilterType.CreatedByTeams, + teamIds: ['team1Id', 'randomTeamId'], + }, + result: true, + }, + { + filter: { + type: FilterType.CreatedByTeams, + teamIds: ['team1Id', 'team2Id'], + }, + result: true, + }, + { + filter: { + type: FilterType.CreatedByTeams, + teamIds: ['randomTeam1Id', 'randomTeam2Id'], + }, + result: false, + }, + { + filter: { + type: FilterType.All, + }, + result: true, + }, + ]; + + testCases.forEach(({ filter, result }) => { + it(`should return ${String(result)} when pull request ${ + result ? 'is' : 'is not' + } ${filter.type}`, () => { + const pullRequestFilter = createFilter(filter); + expect(pullRequestFilter(pullRequest)).toBe(result); + }); + }); +}); From 92066353970f856d437ee8f9da51f8f5cf8d032a Mon Sep 17 00:00:00 2001 From: austinal Date: Mon, 13 Dec 2021 10:49:53 -0500 Subject: [PATCH 126/189] Fixed bug in OwnershipCard component where text wasn't correctly pluralized Signed-off-by: austinal --- plugins/org/package.json | 1 + .../org/src/components/Cards/OwnershipCard/OwnershipCard.tsx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/org/package.json b/plugins/org/package.json index 4e7f556547..845c2cb775 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -29,6 +29,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", + "pluralize": "^8.0.0", "qs": "^6.10.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index fe23191779..8e0090ed83 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -40,6 +40,7 @@ import { } from '@material-ui/core'; import qs from 'qs'; import React from 'react'; +import pluralize from 'pluralize'; import { useAsync } from 'react-use'; type EntityTypeProps = { @@ -96,7 +97,7 @@ const EntityCountTile = ({ {counter} - {name} + {pluralize(name, counter)} From 6f263c2cbc0135f074280116e964b3dd88420e50 Mon Sep 17 00:00:00 2001 From: austinal Date: Mon, 13 Dec 2021 13:21:11 -0500 Subject: [PATCH 127/189] Add changeset Signed-off-by: austinal --- .changeset/funny-chefs-guess.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/funny-chefs-guess.md diff --git a/.changeset/funny-chefs-guess.md b/.changeset/funny-chefs-guess.md new file mode 100644 index 0000000000..66824892f2 --- /dev/null +++ b/.changeset/funny-chefs-guess.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Fixed bug in OwnershipCard component where text wasn't correctly pluralized From 4ce74edaf6857a29126b10596862ecf6d98655ec Mon Sep 17 00:00:00 2001 From: Iain Billett Date: Tue, 14 Dec 2021 16:34:16 +0000 Subject: [PATCH 128/189] Fix standalone server Signed-off-by: Iain Billett --- plugins/search-backend/src/service/standaloneServer.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/search-backend/src/service/standaloneServer.ts b/plugins/search-backend/src/service/standaloneServer.ts index 9ba9dbd5f7..ce775c205a 100644 --- a/plugins/search-backend/src/service/standaloneServer.ts +++ b/plugins/search-backend/src/service/standaloneServer.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { createServiceBuilder } from '@backstage/backend-common'; +import { + createServiceBuilder, + loadBackendConfig, + SingleHostDiscovery, +} from '@backstage/backend-common'; import { Server } from 'http'; import { Logger } from 'winston'; import { createRouter } from './router'; @@ -33,6 +37,8 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'search-backend' }); + const config = await loadBackendConfig({ logger, argv: process.argv }); + const discovery = SingleHostDiscovery.fromConfig(config); const searchEngine = new LunrSearchEngine({ logger }); const indexBuilder = new IndexBuilder({ logger, searchEngine }); logger.debug('Starting application server...'); @@ -42,6 +48,7 @@ export async function startStandaloneServer( const router = await createRouter({ engine: indexBuilder.getSearchEngine(), logger, + discovery, }); let service = createServiceBuilder(module) From faaa7f009cb0645a793452710972441e3811faf1 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Tue, 14 Dec 2021 17:49:16 +0100 Subject: [PATCH 129/189] changed type name to select item Signed-off-by: lukzerom --- .../core-components/src/components/Select/Select.tsx | 4 ++-- .../core-components/src/components/Select/index.tsx | 2 +- .../components/fields/RepoUrlPicker/RepoUrlPicker.tsx | 11 ++++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 3b6582865c..b5a641acd4 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -102,7 +102,7 @@ const useStyles = makeStyles( { name: 'BackstageSelect' }, ); -export type Item = { +export type SelectItem = { label: string; value: string | number; }; @@ -111,7 +111,7 @@ export type Selection = string | string[] | number | number[]; export type SelectProps = { multiple?: boolean; - items: Item[]; + items: SelectItem[]; label: string; placeholder?: string; selected?: Selection; diff --git a/packages/core-components/src/components/Select/index.tsx b/packages/core-components/src/components/Select/index.tsx index 8c9ae28ac8..293d626ee6 100644 --- a/packages/core-components/src/components/Select/index.tsx +++ b/packages/core-components/src/components/Select/index.tsx @@ -16,10 +16,10 @@ export { SelectComponent as Select } from './Select'; export type { - Item, SelectClassKey, SelectInputBaseClassKey, Selection, + SelectItem, } from './Select'; export type { ClosedDropdownClassKey } from './static/ClosedDropdown'; export type { OpenedDropdownClassKey } from './static/OpenedDropdown'; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index 42e24cc998..e4d6f280f4 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -13,7 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Item, Progress, Select, Selection } from '@backstage/core-components'; +import { + Progress, + Select, + Selection, + SelectItem, +} from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; import FormControl from '@material-ui/core/FormControl'; @@ -237,13 +242,13 @@ export const RepoUrlPicker = ({ return ; } - const hostsOptions: Item[] = integrations + const hostsOptions: SelectItem[] = integrations ? integrations .filter(i => allowedHosts?.includes(i.host)) .map(i => ({ label: i.title, value: i.host })) : [{ label: 'Loading...', value: 'loading' }]; - const ownersOptions: Item[] = allowedOwners + const ownersOptions: SelectItem[] = allowedOwners ? allowedOwners.map(i => ({ label: i, value: i })) : [{ label: 'Loading...', value: 'loading' }]; From 31c0106a4e991f367637fba883897ce11168e902 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Tue, 14 Dec 2021 17:51:02 +0100 Subject: [PATCH 130/189] on change instead of on select in entitypicker Signed-off-by: lukzerom --- .../src/components/fields/EntityPicker/EntityPicker.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx index d491af1da4..452a5d97b1 100644 --- a/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/EntityPicker/EntityPicker.tsx @@ -57,9 +57,9 @@ export const EntityPicker = ({ useEffect(() => { if (entityRefs?.length === 1) { - onSelect('', entityRefs[0]); + onChange(entityRefs[0]); } - }, [entityRefs, onSelect]); + }, [entityRefs, onChange]); return ( Date: Tue, 14 Dec 2021 18:09:02 +0100 Subject: [PATCH 131/189] Delete old changeset Signed-off-by: lukzerom --- .changeset/beige-balloons-grin.md | 5 ----- .changeset/curvy-walls-itch.md | 5 ----- 2 files changed, 10 deletions(-) delete mode 100644 .changeset/beige-balloons-grin.md delete mode 100644 .changeset/curvy-walls-itch.md diff --git a/.changeset/beige-balloons-grin.md b/.changeset/beige-balloons-grin.md deleted file mode 100644 index 9ce1e0b6b5..0000000000 --- a/.changeset/beige-balloons-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': minor ---- - -When user will have one option available in hostUrl or owner - autoselect and select component should be readonly diff --git a/.changeset/curvy-walls-itch.md b/.changeset/curvy-walls-itch.md deleted file mode 100644 index 18f35a6e24..0000000000 --- a/.changeset/curvy-walls-itch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': minor ---- - -Select component has extended API with few more props From 14d0bc908104c7a9396859257102dbe585731643 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Tue, 14 Dec 2021 18:14:11 +0100 Subject: [PATCH 132/189] updated docs Signed-off-by: lukzerom --- packages/core-components/api-report.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 72d47b494c..3a19dcba0d 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -528,14 +528,6 @@ export type InfoCardVariants = 'flex' | 'fullHeight' | 'gridItem'; // @public (undocumented) export function IntroCard(props: IntroCardProps): JSX.Element; -// Warning: (ae-missing-release-tag) "Item" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export type Item = { - label: string; - value: string | number; -}; - // Warning: (tsdoc-malformed-html-name) Invalid HTML element: Expecting an HTML name // Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag // Warning: (ae-forgotten-export) The symbol "ItemCardProps" needs to be exported by the entry point index.d.ts @@ -849,6 +841,14 @@ export type SelectInputBaseClassKey = 'root' | 'input'; type Selection_2 = string | string[] | number | number[]; export { Selection_2 as Selection }; +// Warning: (ae-missing-release-tag) "SelectItem" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type SelectItem = { + label: string; + value: string | number; +}; + // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "Sidebar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // From b646a73fe048e81e21aa73c9d73ea96efa8b9032 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Tue, 14 Dec 2021 18:22:52 +0100 Subject: [PATCH 133/189] changeset fix Signed-off-by: lukzerom --- .changeset/ten-candles-call.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/ten-candles-call.md diff --git a/.changeset/ten-candles-call.md b/.changeset/ten-candles-call.md new file mode 100644 index 0000000000..d14020b9c8 --- /dev/null +++ b/.changeset/ten-candles-call.md @@ -0,0 +1,9 @@ +--- +'@backstage/core-components': minor +'@backstage/plugin-scaffolder': minor +--- + +In @backstage/plugin-scaffolder - When user will have one option available in hostUrl or owner - autoselect and select component should be readonly. + +in @backstage/core-components - Select component has extended API with few more props: native : boolean, disabled: boolean. native - if set to true - Select component will use native browser select picker (not rendered by Material UI lib ). +disabled - if set to true - action on component will not be possible. From 801323b9230903d5de701483861e503f8f6996fe Mon Sep 17 00:00:00 2001 From: Iain Billett Date: Tue, 14 Dec 2021 17:47:48 +0000 Subject: [PATCH 134/189] Api Report Signed-off-by: Iain Billett --- plugins/search-backend/api-report.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/search-backend/api-report.md b/plugins/search-backend/api-report.md index cac97bd725..c4558f1b59 100644 --- a/plugins/search-backend/api-report.md +++ b/plugins/search-backend/api-report.md @@ -5,6 +5,7 @@ ```ts import express from 'express'; import { Logger as Logger_2 } from 'winston'; +import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { SearchEngine } from '@backstage/plugin-search-backend-node'; // Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -18,5 +19,7 @@ export function createRouter(options: RouterOptions): Promise; export type RouterOptions = { engine: SearchEngine; logger: Logger_2; + discovery: PluginEndpointDiscovery; + allowedLocationProtocols?: string[]; }; ``` From 60abfd536aaf070d4249f1c383a3719abb8f45ea Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Tue, 14 Dec 2021 19:04:51 +0100 Subject: [PATCH 135/189] Improved unit tests Signed-off-by: Jan Vilimek --- plugins/org/package.json | 1 + .../OwnershipCard/OwnershipCard.test.tsx | 208 +++++++++--------- 2 files changed, 106 insertions(+), 103 deletions(-) diff --git a/plugins/org/package.json b/plugins/org/package.json index 4e7f556547..8df865f386 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -40,6 +40,7 @@ "devDependencies": { "@backstage/cli": "^0.10.1", "@backstage/core-app-api": "^0.2.0", + "@backstage/catalog-client": "^0.5.2", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 912014092f..c4710c14ab 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -14,6 +14,10 @@ * limitations under the License. */ +import { + CatalogEntitiesRequest, + CatalogListResponse, +} from '@backstage/catalog-client'; import { Entity, GroupEntity, UserEntity } from '@backstage/catalog-model'; import { CatalogApi, @@ -26,6 +30,97 @@ import { queryByText } from '@testing-library/react'; import React from 'react'; import { OwnershipCard } from './OwnershipCard'; +const items = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'API', + metadata: { + name: 'my-api', + }, + spec: { + type: 'openapi', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + { + kind: 'Component', + metadata: { + name: 'my-service', + }, + spec: { + type: 'service', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + { + kind: 'Component', + metadata: { + name: 'my-library', + namespace: 'other-namespace', + }, + spec: { + type: 'library', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'System', + metadata: { + name: 'my-system', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, +] as Entity[]; + +const getEntitiesMock = ( + request?: CatalogEntitiesRequest, +): Promise> => { + const filterKinds = + !Array.isArray(request?.filter) && Array.isArray(request?.filter?.kind) + ? request?.filter?.kind ?? [] + : []; // we expect the request to be like { filter: { kind: ['API','System'], .... } + return Promise.resolve({ + items: items.filter(item => filterKinds.find(k => k === item.kind)), + } as CatalogListResponse); +}; + describe('OwnershipCard', () => { const groupEntity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', @@ -49,76 +144,12 @@ describe('OwnershipCard', () => { ], }; - const items = [ - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'API', - metadata: { - name: 'my-api', - }, - spec: { - type: 'openapi', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - { - kind: 'Component', - metadata: { - name: 'my-service', - }, - spec: { - type: 'service', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - { - kind: 'Component', - metadata: { - name: 'my-library', - namespace: 'other-namespace', - }, - spec: { - type: 'library', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - ] as Entity[]; - it('displays entity counts', async () => { const catalogApi: jest.Mocked = { getEntities: jest.fn(), } as any; - catalogApi.getEntities.mockResolvedValue({ - items, - }); + catalogApi.getEntities.mockImplementation(getEntitiesMock); const { getByText } = await renderInTestApp( @@ -156,6 +187,7 @@ describe('OwnershipCard', () => { expect( queryByText(getByText('LIBRARY').parentElement!, '1'), ).toBeInTheDocument(); + expect(() => getByText('SYSTEM')).toThrowError(); }); it('applies CustomFilterDefinition', async () => { @@ -163,27 +195,7 @@ describe('OwnershipCard', () => { getEntities: jest.fn(), } as any; - catalogApi.getEntities.mockResolvedValue({ - items: [ - { - apiVersion: 'backstage.io/v1alpha1', - kind: 'system', - metadata: { - name: 'my-systen', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - ], - }); + catalogApi.getEntities.mockImplementation(getEntitiesMock); const { getByText } = await renderInTestApp( @@ -198,21 +210,15 @@ describe('OwnershipCard', () => { }, ); - expect(catalogApi.getEntities).toHaveBeenCalledWith({ - filter: { kind: ['API', 'System'] }, - fields: [ - 'kind', - 'metadata.name', - 'metadata.namespace', - 'spec.type', - 'relations', - ], - }); - expect(getByText('SYSTEM')).toBeInTheDocument(); expect( queryByText(getByText('SYSTEM').parentElement!, '1'), ).toBeInTheDocument(); + expect(getByText('OPENAPI')).toBeInTheDocument(); + expect( + queryByText(getByText('OPENAPI').parentElement!, '1'), + ).toBeInTheDocument(); + expect(() => getByText('LIBRARY')).toThrowError(); }); it('links to the catalog with the group filter', async () => { @@ -220,9 +226,7 @@ describe('OwnershipCard', () => { getEntities: jest.fn(), } as any; - catalogApi.getEntities.mockResolvedValue({ - items, - }); + catalogApi.getEntities.mockImplementation(getEntitiesMock); const { getByText } = await renderInTestApp( @@ -268,9 +272,7 @@ describe('OwnershipCard', () => { getEntities: jest.fn(), } as any; - catalogApi.getEntities.mockResolvedValue({ - items, - }); + catalogApi.getEntities.mockImplementation(getEntitiesMock); const { getByText } = await renderInTestApp( From 3491a36ab9bf2248e60cf10ed2436bd003ae2c5a Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Tue, 14 Dec 2021 23:45:33 +0530 Subject: [PATCH 136/189] add useOwnedEntites to catalog-react Signed-off-by: mufaddal motiwala --- .changeset/eleven-baboons-sparkle.md | 5 +++++ plugins/catalog-react/api-report.md | 7 +++++++ plugins/catalog-react/src/hooks/index.ts | 1 + .../src/hooks}/useOwnedEntities.ts | 15 +++++++++++++-- .../OwnedEntityPicker/OwnedEntityPicker.tsx | 6 ++++-- 5 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 .changeset/eleven-baboons-sparkle.md rename plugins/{scaffolder/src/components/fields/OwnedEntityPicker => catalog-react/src/hooks}/useOwnedEntities.ts (82%) diff --git a/.changeset/eleven-baboons-sparkle.md b/.changeset/eleven-baboons-sparkle.md new file mode 100644 index 0000000000..7dba4792bc --- /dev/null +++ b/.changeset/eleven-baboons-sparkle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': minor +--- + +added useOwnedEntities hook to get the list of entities of the logged-in user diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index c4aa254226..ef469e3b02 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -9,6 +9,7 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { AsyncState } from 'react-use/lib/useAsync'; import { CATALOG_FILTER_EXISTS } from '@backstage/catalog-client'; import { CatalogApi } from '@backstage/catalog-client'; +import { CatalogListResponse } from '@backstage/catalog-client'; import { ComponentEntity } from '@backstage/catalog-model'; import { ComponentProps } from 'react'; import { Context } from 'react'; @@ -847,6 +848,12 @@ export function useEntityOwnership(): { // @public export function useEntityTypeFilter(): EntityTypeReturn; +// @public +export function useOwnedEntities(allowedKinds?: string[]): { + loading: boolean; + ownedEntities: CatalogListResponse | undefined; +}; + // Warning: (ae-missing-release-tag) "useOwnUser" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public diff --git a/plugins/catalog-react/src/hooks/index.ts b/plugins/catalog-react/src/hooks/index.ts index bbbca3a501..a6684732ce 100644 --- a/plugins/catalog-react/src/hooks/index.ts +++ b/plugins/catalog-react/src/hooks/index.ts @@ -42,3 +42,4 @@ export { useEntityOwnership, loadIdentityOwnerRefs, } from './useEntityOwnership'; +export { useOwnedEntities } from './useOwnedEntities'; diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts b/plugins/catalog-react/src/hooks/useOwnedEntities.ts similarity index 82% rename from plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts rename to plugins/catalog-react/src/hooks/useOwnedEntities.ts index ecdfc5c90f..f9191364cb 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/useOwnedEntities.ts +++ b/plugins/catalog-react/src/hooks/useOwnedEntities.ts @@ -13,17 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { catalogApiRef } from './../api'; import { - catalogApiRef, loadCatalogOwnerRefs, loadIdentityOwnerRefs, -} from '@backstage/plugin-catalog-react'; +} from './useEntityOwnership'; import { identityApiRef, useApi } from '@backstage/core-plugin-api'; import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; import { CatalogListResponse } from '@backstage/catalog-client'; import { useAsync } from 'react-use'; import { useMemo } from 'react'; +/** + * Takes the relevant parts of the Backstage identity, and translates them into + * a list of entities which are owned by the user. Takes an optional parameter + * to filter the entities based on allowedKinds + * + * @public + * + * @param allowedKinds - Array of allowed kinds to filter the entities + * @returns CatalogListResponse + */ export function useOwnedEntities(allowedKinds?: string[]): { loading: boolean; ownedEntities: CatalogListResponse | undefined; @@ -52,6 +62,7 @@ export function useOwnedEntities(allowedKinds?: string[]): { ); return catalogs; }, []); + const ownedEntities = useMemo(() => { return refs; }, [refs]); diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx index 06b637a79c..3c2fc2b495 100644 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx +++ b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { formatEntityRefTitle } from '@backstage/plugin-catalog-react'; +import { + formatEntityRefTitle, + useOwnedEntities, +} from '@backstage/plugin-catalog-react'; import { TextField } from '@material-ui/core'; import FormControl from '@material-ui/core/FormControl'; import Autocomplete from '@material-ui/lab/Autocomplete'; import { FieldProps } from '@rjsf/core'; import React from 'react'; -import { useOwnedEntities } from './useOwnedEntities'; export const OwnedEntityPicker = ({ onChange, From a91c4dd05a4bd47cc72ddeab21c65b22a0a933ad Mon Sep 17 00:00:00 2001 From: Iain Billett Date: Tue, 14 Dec 2021 18:18:05 +0000 Subject: [PATCH 137/189] Update create-app template Signed-off-by: Iain Billett --- .../templates/default-app/packages/backend/src/plugins/search.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/search.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/search.ts index f23b0c7bcf..74ea8f032c 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/plugins/search.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/plugins/search.ts @@ -50,5 +50,6 @@ export default async function createPlugin({ return await createRouter({ engine: indexBuilder.getSearchEngine(), logger, + discovery, }); } From 5515862338a5af8249d52e0e62ee2e230668d847 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Tue, 14 Dec 2021 20:36:03 +0200 Subject: [PATCH 138/189] Run api report and add minimal tsdoc. Signed-off-by: Charles Lowell --- .../src/engines/ElasticSearchSearchEngine.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index 8cb04a8ad7..ca54d46310 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -107,6 +107,11 @@ export class ElasticSearchSearchEngine implements SearchEngine { ); } + /** + * Create a custom search client from the derived elastic search + * configuration. This need not be the same client that the engine uses + * internally. + */ newClient(create: (options: ElasticSearchClientOptions) => T): T { return create(this.elasticSearchClientOptions); } From baf39f45b52a7ece304d70c68233640aafe40077 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Tue, 14 Dec 2021 20:49:27 +0200 Subject: [PATCH 139/189] Add explainer for `newClient` to the search howto Signed-off-by: Charles Lowell --- docs/features/search/search-engines.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/features/search/search-engines.md b/docs/features/search/search-engines.md index 1331c73b72..8342c74096 100644 --- a/docs/features/search/search-engines.md +++ b/docs/features/search/search-engines.md @@ -90,6 +90,18 @@ within your instance. The configuration options are documented in the The underlying functionality is using official ElasticSearch client version 7.x, meaning that ElasticSearch version 7 is the only one confirmed to be supported. +Should you need to create your own bespoke search experiences that require more +than just a query translator (such as faceted search or Relay pagination), you +can access the configuration of the search engine in order to create new elastic +search clients. The version of the client need not be the same as one used +internally by the elastic search engine plugin. For example: + +```typescript +import { Client } from '@elastic/elastic-search'; + +const client = searchEngine.newClient(options => new Client(options)); +``` + ## Example configurations ### AWS From 8ecfac35fda4aa9bec329230cf06bd056cf05ede Mon Sep 17 00:00:00 2001 From: lukzerom Date: Tue, 14 Dec 2021 23:37:16 +0100 Subject: [PATCH 140/189] patch instead of minor Signed-off-by: lukzerom --- .changeset/ten-candles-call.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/ten-candles-call.md b/.changeset/ten-candles-call.md index d14020b9c8..8907da06bd 100644 --- a/.changeset/ten-candles-call.md +++ b/.changeset/ten-candles-call.md @@ -1,6 +1,6 @@ --- -'@backstage/core-components': minor -'@backstage/plugin-scaffolder': minor +'@backstage/core-components': patch +'@backstage/plugin-scaffolder': patch --- In @backstage/plugin-scaffolder - When user will have one option available in hostUrl or owner - autoselect and select component should be readonly. From aec8c678c8b111955af200d5d4ba584101b7fbab Mon Sep 17 00:00:00 2001 From: lukzerom Date: Tue, 14 Dec 2021 23:40:30 +0100 Subject: [PATCH 141/189] selected items instead of selection Signed-off-by: lukzerom --- .../core-components/src/components/Select/Select.tsx | 12 ++++++------ .../core-components/src/components/Select/index.tsx | 2 +- .../fields/RepoUrlPicker/RepoUrlPicker.tsx | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index b5a641acd4..82be078cd0 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -107,15 +107,15 @@ export type SelectItem = { value: string | number; }; -export type Selection = string | string[] | number | number[]; +export type SelectedItems = string | string[] | number | number[]; export type SelectProps = { multiple?: boolean; items: SelectItem[]; label: string; placeholder?: string; - selected?: Selection; - onChange: (arg: Selection) => void; + selected?: SelectedItems; + onChange: (arg: SelectedItems) => void; triggerReset?: boolean; native?: boolean; disabled?: boolean; @@ -134,7 +134,7 @@ export function SelectComponent(props: SelectProps) { disabled = false, } = props; const classes = useStyles(); - const [value, setValue] = useState( + const [value, setValue] = useState( selected || (multiple ? [] : ''), ); const [isOpen, setOpen] = useState(false); @@ -150,8 +150,8 @@ export function SelectComponent(props: SelectProps) { }, [selected]); const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => { - setValue(event.target.value as Selection); - onChange(event.target.value as Selection); + setValue(event.target.value as SelectedItems); + onChange(event.target.value as SelectedItems); }; const handleClick = (event: React.ChangeEvent) => { diff --git a/packages/core-components/src/components/Select/index.tsx b/packages/core-components/src/components/Select/index.tsx index 293d626ee6..870c2a0899 100644 --- a/packages/core-components/src/components/Select/index.tsx +++ b/packages/core-components/src/components/Select/index.tsx @@ -17,8 +17,8 @@ export { SelectComponent as Select } from './Select'; export type { SelectClassKey, + SelectedItems, SelectInputBaseClassKey, - Selection, SelectItem, } from './Select'; export type { ClosedDropdownClassKey } from './static/ClosedDropdown'; diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index e4d6f280f4..92261b6cac 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -16,7 +16,7 @@ import { Progress, Select, - Selection, + SelectedItems, SelectItem, } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; @@ -109,7 +109,7 @@ export const RepoUrlPicker = ({ allowedOwners, ); const updateHost = useCallback( - (value: Selection) => { + (value: SelectedItems) => { onChange( serializeFormData({ host: value as string, @@ -125,7 +125,7 @@ export const RepoUrlPicker = ({ ); const updateOwnerSelect = useCallback( - (value: Selection) => + (value: SelectedItems) => onChange( serializeFormData({ host, From 2d244da5c49903c50b91a5e49bb168daf21c4fc9 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Tue, 14 Dec 2021 23:59:22 +0100 Subject: [PATCH 142/189] public adnotation Signed-off-by: lukzerom --- packages/core-components/src/components/Select/Select.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/core-components/src/components/Select/Select.tsx b/packages/core-components/src/components/Select/Select.tsx index 82be078cd0..022df0a7ad 100644 --- a/packages/core-components/src/components/Select/Select.tsx +++ b/packages/core-components/src/components/Select/Select.tsx @@ -32,6 +32,7 @@ import React, { useEffect, useState } from 'react'; import ClosedDropdown from './static/ClosedDropdown'; import OpenedDropdown from './static/OpenedDropdown'; +/** @public */ export type SelectInputBaseClassKey = 'root' | 'input'; const BootstrapInput = withStyles( @@ -60,6 +61,7 @@ const BootstrapInput = withStyles( { name: 'BackstageSelectInputBase' }, )(InputBase); +/** @public */ export type SelectClassKey = | 'formControl' | 'label' @@ -102,11 +104,13 @@ const useStyles = makeStyles( { name: 'BackstageSelect' }, ); +/** @public */ export type SelectItem = { label: string; value: string | number; }; +/** @public */ export type SelectedItems = string | string[] | number | number[]; export type SelectProps = { @@ -121,6 +125,7 @@ export type SelectProps = { disabled?: boolean; }; +/** @public */ export function SelectComponent(props: SelectProps) { const { multiple, From b040d62e8e2b5bb8efe2634fe1c1bb42a4f928e0 Mon Sep 17 00:00:00 2001 From: lukzerom Date: Wed, 15 Dec 2021 00:03:42 +0100 Subject: [PATCH 143/189] docs update Signed-off-by: lukzerom --- packages/core-components/api-report.md | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 3a19dcba0d..086a0bc632 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -814,13 +814,10 @@ export type ResponseErrorPanelClassKey = 'text' | 'divider'; export function RoutedTabs(props: { routes: SubRoute_2[] }): JSX.Element; // Warning: (ae-forgotten-export) The symbol "SelectProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "SelectComponent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export function Select(props: SelectProps): JSX.Element; -// Warning: (ae-missing-release-tag) "SelectClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export type SelectClassKey = | 'formControl' @@ -830,19 +827,12 @@ export type SelectClassKey = | 'checkbox' | 'root'; -// Warning: (ae-missing-release-tag) "SelectInputBaseClassKey" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// +// @public (undocumented) +export type SelectedItems = string | string[] | number | number[]; + // @public (undocumented) export type SelectInputBaseClassKey = 'root' | 'input'; -// Warning: (ae-missing-release-tag) "Selection" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -type Selection_2 = string | string[] | number | number[]; -export { Selection_2 as Selection }; - -// Warning: (ae-missing-release-tag) "SelectItem" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export type SelectItem = { label: string; From 813db5928bf1bff5a4ee15fa63608c86c99292cc Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 15 Dec 2021 01:17:58 +0100 Subject: [PATCH 144/189] core-plugin-api: document ErrorApiErrorContext.hidden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik AdelΓΆw Co-authored-by: Johan Haals Signed-off-by: Patrik Oldsberg --- .../core-plugin-api/src/apis/definitions/ErrorApi.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/core-plugin-api/src/apis/definitions/ErrorApi.ts b/packages/core-plugin-api/src/apis/definitions/ErrorApi.ts index 45ee0901c8..364a7bd29a 100644 --- a/packages/core-plugin-api/src/apis/definitions/ErrorApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/ErrorApi.ts @@ -41,7 +41,15 @@ export type Error = ErrorApiError; * @public */ export type ErrorApiErrorContext = { - // If set to true, this error should not be displayed to the user. Defaults to false. + /** + * If set to true, this error should not be displayed to the user. + * + * Hidden errors are typically not displayed in the UI, but the ErrorApi + * implementation may still report them to error tracking services + * or other utilities that care about all errors. + * + * @defaultValue false + */ hidden?: boolean; }; From 12f674f60825aa2079bd756e895fc632e4742156 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 15 Dec 2021 01:39:47 +0100 Subject: [PATCH 145/189] package.json: fix duplicate api-extractor installs Signed-off-by: Patrik Oldsberg --- package.json | 7 +-- yarn.lock | 143 ++++++++++++++++++++------------------------------- 2 files changed, 61 insertions(+), 89 deletions(-) diff --git a/package.json b/package.json index 3a20ce7f8e..57cf603090 100644 --- a/package.json +++ b/package.json @@ -55,9 +55,9 @@ }, "version": "1.0.0", "dependencies": { - "@microsoft/api-documenter": "^7.13.68", - "@microsoft/api-extractor": "^7.18.7", - "@microsoft/api-extractor-model": "^7.13.5", + "@microsoft/api-documenter": "^7.13.77", + "@microsoft/api-extractor": "^7.19.2", + "@microsoft/api-extractor-model": "^7.15.1", "@microsoft/tsdoc": "^0.13.2" }, "devDependencies": { @@ -78,6 +78,7 @@ "prettier": "^2.2.1", "shx": "^0.3.2", "ts-node": "^10.4.0", + "typescript": "~4.3.5", "yarn-lock-check": "^1.0.5" }, "prettier": "@spotify/prettier-config", diff --git a/yarn.lock b/yarn.lock index 0a47ca410c..61ab32bf3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4846,54 +4846,45 @@ resolved "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== -"@microsoft/api-documenter@^7.13.68": - version "7.13.68" - resolved "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.13.68.tgz#c1e144764cac0684adefe78fd848d78c3f374681" - integrity sha512-cRjwK1TDyGxFGgCsRG8G0Yi3Z4akvfWgw1pWAxKFbm7ajlQQGZcHPnb+n4lKlSeQ5g/cxc7hcdw54Mvisne9Bg== +"@microsoft/api-documenter@^7.13.77": + version "7.13.77" + resolved "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.13.77.tgz#9760b42553679695620b578436ce14c357454e88" + integrity sha512-kot4VJlQUd7i0mFSM7IjyOhF0WWyVrmN9x3sXmd72imgCg9w795QHSkphJ7Qc6ZjhHcolaJvBByEPTKG4exZmA== dependencies: - "@microsoft/api-extractor-model" "7.13.16" + "@microsoft/api-extractor-model" "7.15.1" "@microsoft/tsdoc" "0.13.2" - "@rushstack/node-core-library" "3.43.2" - "@rushstack/ts-command-line" "4.10.4" + "@rushstack/node-core-library" "3.44.2" + "@rushstack/ts-command-line" "4.10.5" colors "~1.2.1" js-yaml "~3.13.1" resolve "~1.17.0" -"@microsoft/api-extractor-model@7.13.16": - version "7.13.16" - resolved "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.13.16.tgz#1d67541ebbcea32672c5fdd9392dc1579b2fc23a" - integrity sha512-ttdxVXsTWL5dd26W1YNLe3LgDsE0EE273aZlcLe58W0opymBybCYU1Mn+OHQM8BuErrdvdN8LdpWAAbkiOEN/Q== +"@microsoft/api-extractor-model@7.15.1", "@microsoft/api-extractor-model@^7.15.1": + version "7.15.1" + resolved "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.15.1.tgz#e52d68676e846d8b86e3b18e2654af39fba6e4a1" + integrity sha512-DWfS1o3oMY0mzdO3OuQbD/9vzn80jwM6tFd7XbiYnkpxwhD83LMGXz7NZWwSh+IaA+9w3LF4w62fT31Qq+dAMw== dependencies: "@microsoft/tsdoc" "0.13.2" "@microsoft/tsdoc-config" "~0.15.2" - "@rushstack/node-core-library" "3.43.2" + "@rushstack/node-core-library" "3.44.2" -"@microsoft/api-extractor-model@7.13.5", "@microsoft/api-extractor-model@^7.13.5": - version "7.13.5" - resolved "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.13.5.tgz#7836a81ba47b9a654062ed0361e4eee69afae51e" - integrity sha512-il6AebNltYo5hEtqXZw4DMvrwBPn6+F58TxwqmsLY+U+sSJNxaYn2jYksArrjErXVPR3gUgRMqD6zsdIkg+WEQ== +"@microsoft/api-extractor@^7.19.2": + version "7.19.2" + resolved "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.19.2.tgz#8c546003523163c1432f6e19506065f790d6182c" + integrity sha512-LxSa9lwp7eYtM4i5y/1n79QpotPKlmpCrVQbkb0LAHE1sCRHpZDTb6p3cMJthDhYPMjAYKOLfq639GwtZrg23Q== dependencies: + "@microsoft/api-extractor-model" "7.15.1" "@microsoft/tsdoc" "0.13.2" "@microsoft/tsdoc-config" "~0.15.2" - "@rushstack/node-core-library" "3.40.0" - -"@microsoft/api-extractor@^7.18.7": - version "7.18.7" - resolved "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.18.7.tgz#851d2413a3c5d696f7cc914eb59de7a7882b2e8b" - integrity sha512-JhtV8LoyLuIecbgCPyZQg08G1kngIRWpai2UzwNil9mGVGYiDZVeeKx8c2phmlPcogmMDm4oQROxyuiYt5sJiw== - dependencies: - "@microsoft/api-extractor-model" "7.13.5" - "@microsoft/tsdoc" "0.13.2" - "@microsoft/tsdoc-config" "~0.15.2" - "@rushstack/node-core-library" "3.40.0" - "@rushstack/rig-package" "0.3.0" - "@rushstack/ts-command-line" "4.9.0" + "@rushstack/node-core-library" "3.44.2" + "@rushstack/rig-package" "0.3.6" + "@rushstack/ts-command-line" "4.10.5" colors "~1.2.1" lodash "~4.17.15" resolve "~1.17.0" semver "~7.3.0" source-map "~0.6.1" - typescript "~4.3.5" + typescript "~4.5.2" "@microsoft/fetch-event-source@2.0.1": version "2.0.1" @@ -5649,25 +5640,10 @@ estree-walker "^2.0.1" picomatch "^2.2.2" -"@rushstack/node-core-library@3.40.0": - version "3.40.0" - resolved "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.40.0.tgz#2551915ea34e34ec2abb7172b9d7f4546144d9d4" - integrity sha512-P6uMPI7cqTdawLSPAG5BQrBu1MHlGRPqecp7ruIRgyukIEzkmh0QAnje4jAL/l1r3hw0qe4e+Dz5ZSnukT/Egg== - dependencies: - "@types/node" "10.17.13" - colors "~1.2.1" - fs-extra "~7.0.1" - import-lazy "~4.0.0" - jju "~1.4.0" - resolve "~1.17.0" - semver "~7.3.0" - timsort "~0.3.0" - z-schema "~3.18.3" - -"@rushstack/node-core-library@3.43.2": - version "3.43.2" - resolved "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.43.2.tgz#f067371a94fd92ed8f9d9aa8201c5e9e17a19f0f" - integrity sha512-b7AEhSf6CvZgvuDcWMFDeKx2mQSn9AVnMQVyxNxFeHCtLz3gJicqCOlw2GOXM8HKh6PInLdil/NVCDcstwSrIw== +"@rushstack/node-core-library@3.44.2": + version "3.44.2" + resolved "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.44.2.tgz#4fcd8f76887ae5968f2796f633a7e48f5ebd2271" + integrity sha512-lQ8Ct267UKkNSJSDxpBWn7SyyITWQ9l3Xqww0V+YY0rMt02r9eiGvwwPaU1ugJW7IMVo6r/HXvgbmpOSPyzGyg== dependencies: "@types/node" "12.20.24" colors "~1.2.1" @@ -5677,30 +5653,20 @@ resolve "~1.17.0" semver "~7.3.0" timsort "~0.3.0" - z-schema "~3.18.3" + z-schema "~5.0.2" -"@rushstack/rig-package@0.3.0": - version "0.3.0" - resolved "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.0.tgz#334ad2846797861361b3445d4cc9ae9164b1885c" - integrity sha512-Lj6noF7Q4BBm1hKiBDw94e6uZvq1xlBwM/d2cBFaPqXeGdV+G6r3qaCWfRiSXK0pcHpGGpV5Tb2MdfhVcO6G/g== +"@rushstack/rig-package@0.3.6": + version "0.3.6" + resolved "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.6.tgz#a57b53db59106fb93bcda36cad4f8602f508ebc6" + integrity sha512-H/uFsAT6cD4JCYrlQXYMZg+wPVECByFoJLGqfGRiTwSS5ngQw9QxnFV2mPG2LrxFUsMjLQ2lsrYr523700XzfA== dependencies: resolve "~1.17.0" strip-json-comments "~3.1.1" -"@rushstack/ts-command-line@4.10.4": - version "4.10.4" - resolved "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.4.tgz#05142b74e5cb207d3dd9b935c82f80d7fcb68042" - integrity sha512-4T5ao4UgDb6LmiRj4GumvG3VT/p6RSMgl7TN7S58ifaAGN2GeTNBajFCDdJs9QQP0d/4tA5p0SFzT7Ps5Byirg== - dependencies: - "@types/argparse" "1.0.38" - argparse "~1.0.9" - colors "~1.2.1" - string-argv "~0.3.1" - -"@rushstack/ts-command-line@4.9.0": - version "4.9.0" - resolved "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.9.0.tgz#781ba42cff73cae097b6d5241b6441e7cc2fe6e0" - integrity sha512-kmT8t+JfnvphISF1C5WwY56RefjwgajhSjs9J4ckvAFXZDXR6F5cvF5/RTh7fGCzIomg8esy2PHO/b52zFoZvA== +"@rushstack/ts-command-line@4.10.5": + version "4.10.5" + resolved "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.5.tgz#a31a44ddd24fe3a594e4ad91c22f3ea7668b43a9" + integrity sha512-5fVlTDbKsJ5WyT6L7NrnOlLG3uoITKxoqTPP2j0QZEi95kPbVT4+VPZaXXDJtkrao9qrIyig8pLK9WABY1bb3w== dependencies: "@types/argparse" "1.0.38" argparse "~1.0.9" @@ -7902,16 +7868,16 @@ resolved "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -"@types/node@10.17.13", "@types/node@^10.1.0", "@types/node@^10.12.0": - version "10.17.13" - resolved "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c" - integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg== - "@types/node@12.20.24", "@types/node@^12.7.1": version "12.20.24" resolved "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz#c37ac69cb2948afb4cef95f424fa0037971a9a5c" integrity sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ== +"@types/node@^10.1.0", "@types/node@^10.12.0": + version "10.17.13" + resolved "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c" + integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg== + "@types/node@^14.0.10", "@types/node@^14.14.31", "@types/node@^14.14.32": version "14.17.8" resolved "https://registry.npmjs.org/@types/node/-/node-14.17.8.tgz#813b73ab7d82ac06ddfd2458b13c88459a3b319f" @@ -19797,7 +19763,7 @@ lodash.flattendeep@^4.0.0: resolved "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= -lodash.get@^4, lodash.get@^4.0.0, lodash.get@^4.4.2: +lodash.get@^4, lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= @@ -19832,7 +19798,7 @@ lodash.isempty@^4.4.0: resolved "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" integrity sha1-b4bL7di+TsmHvpqvM8loTbGzHn4= -lodash.isequal@^4.0.0: +lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= @@ -28427,6 +28393,11 @@ typescript@~4.3.5: resolved "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== +typescript@~4.5.2: + version "4.5.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" + integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== + ua-parser-js@^0.7.18: version "0.7.28" resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" @@ -29114,10 +29085,10 @@ validate.io-number@^1.0.3: resolved "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz#f63ffeda248bf28a67a8d48e0e3b461a1665baf8" integrity sha1-9j/+2iSL8opnqNSODjtGGhZluvg= -validator@^8.0.0: - version "8.2.0" - resolved "https://registry.npmjs.org/validator/-/validator-8.2.0.tgz#3c1237290e37092355344fef78c231249dab77b9" - integrity sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA== +validator@^13.7.0: + version "13.7.0" + resolved "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" + integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== value-or-promise@1.0.11: version "1.0.11" @@ -30156,14 +30127,14 @@ yup@^0.32.9: property-expr "^2.0.4" toposort "^2.0.2" -z-schema@~3.18.3: - version "3.18.4" - resolved "https://registry.npmjs.org/z-schema/-/z-schema-3.18.4.tgz#ea8132b279533ee60be2485a02f7e3e42541a9a2" - integrity sha512-DUOKC/IhbkdLKKiV89gw9DUauTV8U/8yJl1sjf6MtDmzevLKOF2duNJ495S3MFVjqZarr+qNGCPbkg4mu4PpLw== +z-schema@~5.0.2: + version "5.0.2" + resolved "https://registry.npmjs.org/z-schema/-/z-schema-5.0.2.tgz#f410394b2c9fcb9edaf6a7511491c0bb4e89a504" + integrity sha512-40TH47ukMHq5HrzkeVE40Ad7eIDKaRV2b+Qpi2prLc9X9eFJFzV7tMe5aH12e6avaSS/u5l653EQOv+J9PirPw== dependencies: - lodash.get "^4.0.0" - lodash.isequal "^4.0.0" - validator "^8.0.0" + lodash.get "^4.4.2" + lodash.isequal "^4.5.0" + validator "^13.7.0" optionalDependencies: commander "^2.7.1" From 7b6b992e7ac40be54cd299921120b07e287deff0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 15 Dec 2021 01:40:04 +0100 Subject: [PATCH 146/189] scripts/api-extractor: remove workaround for duplicate install Signed-off-by: Patrik Oldsberg --- scripts/api-extractor.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/scripts/api-extractor.ts b/scripts/api-extractor.ts index 8ca7743cf2..22eae267ee 100644 --- a/scripts/api-extractor.ts +++ b/scripts/api-extractor.ts @@ -35,7 +35,6 @@ import { import { Program } from 'typescript'; import { DocNode, - DocSection, IDocNodeContainerParameters, TSDocTagSyntaxKind, } from '@microsoft/tsdoc'; @@ -51,7 +50,6 @@ import { DocHeading } from '@microsoft/api-documenter/lib/nodes/DocHeading'; import { CustomMarkdownEmitter } from '@microsoft/api-documenter/lib/markdown/CustomMarkdownEmitter'; import { IMarkdownEmitterContext } from '@microsoft/api-documenter/lib/markdown/MarkdownEmitter'; import { AstDeclaration } from '@microsoft/api-extractor/lib/analyzer/AstDeclaration'; -import { DocTableCell } from '@microsoft/api-documenter/lib/nodes/DocTableCell'; const tmpDir = resolvePath(__dirname, '../node_modules/.cache/api-extractor'); @@ -605,18 +603,9 @@ async function buildDocs({ }); for (const apiMember of apiModel.members) { - // This is a workaround for this check failing: https://github.com/microsoft/rushstack/blob/915aca8d8847b65981892f44f0544ccb00752792/apps/api-documenter/src/documenters/MarkdownDocumenter.ts#L991 - const description = new DocSection({ configuration }); - if (apiMember.tsdocComment !== undefined) { - this._appendAndMergeSection( - description, - apiMember.tsdocComment.summarySection, - ); - } - const row = new DocTableRow({ configuration }, [ this._createTitleCell(apiMember), - new DocTableCell({ configuration }, description.nodes), + this._createDescriptionCell(apiMember), ]); if (apiMember.kind === 'Package') { From 0c09c969c7c4ca8b577620fc22dddd734de29441 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Dec 2021 04:12:30 +0000 Subject: [PATCH 147/189] build(deps-dev): bump @types/dagre from 0.7.44 to 0.7.46 Bumps [@types/dagre](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/dagre) from 0.7.44 to 0.7.46. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/dagre) --- updated-dependencies: - dependency-name: "@types/dagre" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0a47ca410c..d8c198afc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7327,9 +7327,9 @@ "@types/d3-selection" "*" "@types/dagre@^0.7.44": - version "0.7.44" - resolved "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.44.tgz#8f4b796b118ca29c132da7068fbc0d0351ee5851" - integrity sha512-N6HD+79w77ZVAaVO7JJDW5yJ9LAxM62FpgNGO9xEde+KVYjDRyhIMzfiErXpr1g0JPon9kwlBzoBK6s4fOww9Q== + version "0.7.46" + resolved "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.46.tgz#c51ffcc62ca8a9affa07f5e06842acd840d3d442" + integrity sha512-ku3y+F8sPqmiB5Ugl22NpukI2dLAViJiWwdtueXLeuF4fxZozl+bytPSFVlLu/gDgaKiwobu3LBXXRWktIMiIA== "@types/debug@^4.0.0": version "4.1.7" From 95284ba57210aed75cf223bf96fc1bacc8b35e04 Mon Sep 17 00:00:00 2001 From: Jan Vilimek Date: Wed, 15 Dec 2021 09:45:15 +0100 Subject: [PATCH 148/189] improved tests / comment Signed-off-by: Jan Vilimek --- .../src/components/Cards/OwnershipCard/OwnershipCard.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index c4710c14ab..439365e583 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -115,7 +115,7 @@ const getEntitiesMock = ( const filterKinds = !Array.isArray(request?.filter) && Array.isArray(request?.filter?.kind) ? request?.filter?.kind ?? [] - : []; // we expect the request to be like { filter: { kind: ['API','System'], .... } + : []; // we expect the request to be like { filter: { kind: ['API','System'], .... }. If changed in OwnerShipCard, let's change in also here return Promise.resolve({ items: items.filter(item => filterKinds.find(k => k === item.kind)), } as CatalogListResponse); From a6c72b0d2ce6b5a9964712d468ae40313db03670 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 15 Dec 2021 10:40:26 +0100 Subject: [PATCH 149/189] Label PRs Signed-off-by: Johan Haals --- .github/labeler.yml | 9 +++++++++ .github/workflows/label.yml | 12 ++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/label.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..c16064c841 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,9 @@ +catalog: + - plugins/catalog/**/* + - plugins/catalog-*/**/* +scaffolder: + - plugins/scaffolder/**/* + - plugins/scaffolder-*/**/* +search: + - plugins/search/**/* + - plugins/search-*/**/* diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml new file mode 100644 index 0000000000..0e112f97ac --- /dev/null +++ b/.github/workflows/label.yml @@ -0,0 +1,12 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v3 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + sync-labels: true From cb65389b4804e0b6402876c93308f350e0c30f84 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 15 Dec 2021 10:54:38 +0100 Subject: [PATCH 150/189] format Signed-off-by: Johan Haals --- .github/workflows/label.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 0e112f97ac..dc7127ab0d 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -1,12 +1,12 @@ -name: "Pull Request Labeler" +name: 'Pull Request Labeler' on: -- pull_request_target + - pull_request_target jobs: triage: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v3 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - sync-labels: true + - uses: actions/labeler@v3 + with: + repo-token: '${{ secrets.GITHUB_TOKEN }}' + sync-labels: true From cafdecfc2fb54889e105254884572af40eaf2ca0 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 15 Dec 2021 10:58:15 +0100 Subject: [PATCH 151/189] add packages/catalog Signed-off-by: Johan Haals --- .github/labeler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index c16064c841..112f77e078 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,6 +1,7 @@ catalog: - plugins/catalog/**/* - plugins/catalog-*/**/* + - packages/catalog-*/**/* scaffolder: - plugins/scaffolder/**/* - plugins/scaffolder-*/**/* From 5ad82708fd1dd7b38ae8bc4b18a7792bc3d524df Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Wed, 15 Dec 2021 16:28:26 +0530 Subject: [PATCH 152/189] changed minor to patch Signed-off-by: mufaddal motiwala --- .changeset/eleven-baboons-sparkle.md | 2 +- .changeset/perfect-buses-collect.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/eleven-baboons-sparkle.md b/.changeset/eleven-baboons-sparkle.md index 7dba4792bc..e8c28af482 100644 --- a/.changeset/eleven-baboons-sparkle.md +++ b/.changeset/eleven-baboons-sparkle.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-catalog-react': minor +'@backstage/plugin-catalog-react': patch --- added useOwnedEntities hook to get the list of entities of the logged-in user diff --git a/.changeset/perfect-buses-collect.md b/.changeset/perfect-buses-collect.md index cd7b8164cf..e0df504087 100644 --- a/.changeset/perfect-buses-collect.md +++ b/.changeset/perfect-buses-collect.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder': minor +'@backstage/plugin-scaffolder': patch --- Added OwnedEntityPicker field which displays Owned Entities in options From 651d1e7696f13ccba3178b2a6fb811acfdc6c116 Mon Sep 17 00:00:00 2001 From: Iain Billett Date: Wed, 15 Dec 2021 11:50:44 +0000 Subject: [PATCH 153/189] Don't use discovery API Signed-off-by: Iain Billett --- packages/backend/src/plugins/search.ts | 1 - .../packages/backend/src/plugins/search.ts | 1 - plugins/search-backend/api-report.md | 3 --- .../search-backend/src/service/router.test.ts | 18 +----------------- plugins/search-backend/src/service/router.ts | 16 ++++------------ .../src/service/standaloneServer.ts | 9 +-------- 6 files changed, 6 insertions(+), 42 deletions(-) diff --git a/packages/backend/src/plugins/search.ts b/packages/backend/src/plugins/search.ts index 5659968e1d..9a8db0f0f9 100644 --- a/packages/backend/src/plugins/search.ts +++ b/packages/backend/src/plugins/search.ts @@ -96,6 +96,5 @@ export default async function createPlugin({ return await createRouter({ engine: indexBuilder.getSearchEngine(), logger, - discovery, }); } diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/search.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/search.ts index 74ea8f032c..f23b0c7bcf 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/plugins/search.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/plugins/search.ts @@ -50,6 +50,5 @@ export default async function createPlugin({ return await createRouter({ engine: indexBuilder.getSearchEngine(), logger, - discovery, }); } diff --git a/plugins/search-backend/api-report.md b/plugins/search-backend/api-report.md index c4558f1b59..cac97bd725 100644 --- a/plugins/search-backend/api-report.md +++ b/plugins/search-backend/api-report.md @@ -5,7 +5,6 @@ ```ts import express from 'express'; import { Logger as Logger_2 } from 'winston'; -import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { SearchEngine } from '@backstage/plugin-search-backend-node'; // Warning: (ae-missing-release-tag) "createRouter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -19,7 +18,5 @@ export function createRouter(options: RouterOptions): Promise; export type RouterOptions = { engine: SearchEngine; logger: Logger_2; - discovery: PluginEndpointDiscovery; - allowedLocationProtocols?: string[]; }; ``` diff --git a/plugins/search-backend/src/service/router.test.ts b/plugins/search-backend/src/service/router.test.ts index aeb5709379..77a1be1eb4 100644 --- a/plugins/search-backend/src/service/router.test.ts +++ b/plugins/search-backend/src/service/router.test.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - getVoidLogger, - PluginEndpointDiscovery, -} from '@backstage/backend-common'; +import { getVoidLogger } from '@backstage/backend-common'; import { IndexBuilder, LunrSearchEngine, @@ -30,22 +27,16 @@ import { createRouter } from './router'; describe('createRouter', () => { let app: express.Express; - let mockDiscoveryApi: jest.Mocked; let mockSearchEngine: jest.Mocked; beforeAll(async () => { const logger = getVoidLogger(); const searchEngine = new LunrSearchEngine({ logger }); const indexBuilder = new IndexBuilder({ logger, searchEngine }); - mockDiscoveryApi = { - getBaseUrl: jest.fn(), - getExternalBaseUrl: jest.fn().mockResolvedValue('http://localhost:3000/'), - }; const router = await createRouter({ engine: indexBuilder.getSearchEngine(), logger, - discovery: mockDiscoveryApi, }); app = express().use(router); }); @@ -65,12 +56,6 @@ describe('createRouter', () => { describe('search result filtering', () => { beforeAll(async () => { const logger = getVoidLogger(); - mockDiscoveryApi = { - getBaseUrl: jest.fn(), - getExternalBaseUrl: jest - .fn() - .mockResolvedValue('http://localhost:3000/'), - }; mockSearchEngine = { index: jest.fn(), setTranslator: jest.fn(), @@ -84,7 +69,6 @@ describe('createRouter', () => { const router = await createRouter({ engine: indexBuilder.getSearchEngine(), logger, - discovery: mockDiscoveryApi, }); app = express().use(router); }); diff --git a/plugins/search-backend/src/service/router.ts b/plugins/search-backend/src/service/router.ts index e13e0cc3bf..aae1914fc1 100644 --- a/plugins/search-backend/src/service/router.ts +++ b/plugins/search-backend/src/service/router.ts @@ -19,32 +19,24 @@ import Router from 'express-promise-router'; import { Logger } from 'winston'; import { SearchQuery, SearchResultSet } from '@backstage/search-common'; import { SearchEngine } from '@backstage/plugin-search-backend-node'; -import { PluginEndpointDiscovery } from '@backstage/backend-common'; export type RouterOptions = { engine: SearchEngine; logger: Logger; - discovery: PluginEndpointDiscovery; - allowedLocationProtocols?: string[]; }; -const defaultAllowedLocationProtocols = ['http:', 'https:']; +const allowedLocationProtocols = ['http:', 'https:']; export async function createRouter( options: RouterOptions, ): Promise { - const { - engine, - logger, - discovery, - allowedLocationProtocols = defaultAllowedLocationProtocols, - } = options; - const baseUrl = await discovery.getExternalBaseUrl(''); + const { engine, logger } = options; const filterResultSet = ({ results, ...resultSet }: SearchResultSet) => ({ ...resultSet, results: results.filter(result => { - const protocol = new URL(result.document.location, baseUrl).protocol; + const protocol = new URL(result.document.location, 'https://example.com') + .protocol; const isAllowed = allowedLocationProtocols.includes(protocol); if (!isAllowed) { logger.info( diff --git a/plugins/search-backend/src/service/standaloneServer.ts b/plugins/search-backend/src/service/standaloneServer.ts index ce775c205a..9ba9dbd5f7 100644 --- a/plugins/search-backend/src/service/standaloneServer.ts +++ b/plugins/search-backend/src/service/standaloneServer.ts @@ -14,11 +14,7 @@ * limitations under the License. */ -import { - createServiceBuilder, - loadBackendConfig, - SingleHostDiscovery, -} from '@backstage/backend-common'; +import { createServiceBuilder } from '@backstage/backend-common'; import { Server } from 'http'; import { Logger } from 'winston'; import { createRouter } from './router'; @@ -37,8 +33,6 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'search-backend' }); - const config = await loadBackendConfig({ logger, argv: process.argv }); - const discovery = SingleHostDiscovery.fromConfig(config); const searchEngine = new LunrSearchEngine({ logger }); const indexBuilder = new IndexBuilder({ logger, searchEngine }); logger.debug('Starting application server...'); @@ -48,7 +42,6 @@ export async function startStandaloneServer( const router = await createRouter({ engine: indexBuilder.getSearchEngine(), logger, - discovery, }); let service = createServiceBuilder(module) From 8b3f624aa50ba01f61aa61ffa8a0bb4a2746ebab Mon Sep 17 00:00:00 2001 From: Brian Fletcher Date: Tue, 14 Dec 2021 11:59:02 +0000 Subject: [PATCH 154/189] adds cronjobs to vocab list Signed-off-by: Brian Fletcher --- .github/styles/vocab.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt index 4ec62923d8..f4393b591b 100644 --- a/.github/styles/vocab.txt +++ b/.github/styles/vocab.txt @@ -53,6 +53,7 @@ configs const cookiecutter cron +cronjobs css Datadog dataflow From 62915c368856695a46cb2166ee3a79c7191be861 Mon Sep 17 00:00:00 2001 From: Brian Fletcher Date: Wed, 15 Dec 2021 13:25:12 +0000 Subject: [PATCH 155/189] add batch api group explanation Signed-off-by: Brian Fletcher --- docs/features/kubernetes/configuration.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 2c5aefe7c3..32ab830322 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -263,6 +263,11 @@ following objects: - replicasets - horizontalpodautoscalers - ingresses + +The following RBAC permissions are required on the batch API group for the +following objects: + +- jobs - cronjobs ## Surfacing your Kubernetes components as part of an entity From c47959856a033d1a36903199fbd9e60ef88ca4f4 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Wed, 15 Dec 2021 15:29:14 +0200 Subject: [PATCH 156/189] Don't use initializer syntax for instantiating client For some reason, the property initializer syntax stopped working. An update to TypeScript? An update to Jest? Unknown, but sticking to the less fancy constructor body to do property init seems to work. Signed-off-by: Charles Lowell --- .../src/engines/ElasticSearchSearchEngine.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index ca54d46310..48caf0d4f1 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -72,15 +72,16 @@ function isBlank(str: string) { * @public */ export class ElasticSearchSearchEngine implements SearchEngine { - private readonly elasticSearchClient: Client = this.newClient( - options => new Client(options), - ); + private readonly elasticSearchClient: Client; + constructor( private readonly elasticSearchClientOptions: ElasticSearchClientOptions, private readonly aliasPostfix: string, private readonly indexPrefix: string, private readonly logger: Logger, - ) {} + ) { + this.elasticSearchClient = this.newClient(options => new Client(options)); + } static async fromConfig({ logger, From 8d9ab4d7c1da0a8ea123fbdc92fe8fc74340cc57 Mon Sep 17 00:00:00 2001 From: mufaddal motiwala Date: Wed, 15 Dec 2021 20:44:53 +0530 Subject: [PATCH 157/189] removed test case Signed-off-by: mufaddal motiwala --- .../OwnedEntityPicker.test.tsx | 137 ------------------ 1 file changed, 137 deletions(-) delete mode 100644 plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx diff --git a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx b/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx deleted file mode 100644 index ef6fc1b648..0000000000 --- a/plugins/scaffolder/src/components/fields/OwnedEntityPicker/OwnedEntityPicker.test.tsx +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { Entity } from '@backstage/catalog-model'; -import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react'; -import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; -import { FieldProps } from '@rjsf/core'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; -import { OwnedEntityPicker } from './OwnedEntityPicker'; - -const makeEntity = (kind: string, namespace: string, name: string): Entity => ({ - apiVersion: 'backstage.io/v1beta1', - kind, - metadata: { namespace, name }, -}); - -describe('', () => { - let entities: Entity[]; - const onChange = jest.fn(); - const schema = {}; - const required = false; - let uiSchema: { - 'ui:options': { allowedKinds?: string[]; defaultKind?: string }; - }; - const rawErrors: string[] = []; - const formData = undefined; - - let props: FieldProps; - - const catalogApi: jest.Mocked = { - getLocationById: jest.fn(), - getEntityByName: jest.fn(), - getEntities: jest.fn(async () => ({ items: entities })), - addLocation: jest.fn(), - getLocationByEntity: jest.fn(), - removeEntityByUid: jest.fn(), - } as any; - let Wrapper: React.ComponentType; - - beforeEach(() => { - entities = [ - makeEntity('Group', 'default', 'team-a'), - makeEntity('Group', 'default', 'squad-b'), - ]; - - Wrapper = ({ children }: { children?: React.ReactNode }) => ( - - {children} - - ); - }); - - afterEach(() => jest.resetAllMocks()); - - describe('without allowedKinds', () => { - beforeEach(() => { - uiSchema = { 'ui:options': {} }; - props = { - onChange, - schema, - required, - uiSchema, - rawErrors, - formData, - } as unknown as FieldProps; - - catalogApi.getEntities.mockResolvedValue({ items: entities }); - }); - - it('searches for all entities', async () => { - await renderInTestApp( - - - , - ); - - expect(catalogApi.getEntities).toHaveBeenCalledWith(undefined); - }); - - it('updates even if there is not an exact match', async () => { - const { getByLabelText } = await renderInTestApp( - - - , - ); - const input = getByLabelText('Entity'); - - userEvent.type(input, 'squ'); - input.blur(); - - expect(onChange).toHaveBeenCalledWith('squ'); - }); - }); - - describe('with allowedKinds', () => { - beforeEach(() => { - uiSchema = { 'ui:options': { allowedKinds: ['User'] } }; - props = { - onChange, - schema, - required, - uiSchema, - rawErrors, - formData, - } as unknown as FieldProps; - - catalogApi.getEntities.mockResolvedValue({ items: entities }); - }); - - it('searches for users and groups', async () => { - await renderInTestApp( - - - , - ); - - expect(catalogApi.getEntities).toHaveBeenCalledWith({ - filter: { - kind: ['User'], - }, - }); - }); - }); -}); From 18d4f500afdf49c39afb62bfc0e3b038894c5253 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 15 Dec 2021 14:25:44 +0100 Subject: [PATCH 158/189] core-plugin-api: mark AnalyticsApi as experimental MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik AdelΓΆw Signed-off-by: Patrik Oldsberg --- .changeset/cool-cows-report.md | 5 ++++ packages/core-plugin-api/api-report.md | 25 ++++++++++--------- .../src/analytics/AnalyticsContext.tsx | 2 +- .../core-plugin-api/src/analytics/types.ts | 10 +++++--- .../src/analytics/useAnalytics.tsx | 2 +- .../src/apis/definitions/AnalyticsApi.ts | 14 +++++++---- 6 files changed, 35 insertions(+), 23 deletions(-) create mode 100644 .changeset/cool-cows-report.md diff --git a/.changeset/cool-cows-report.md b/.changeset/cool-cows-report.md new file mode 100644 index 0000000000..2b183e39c2 --- /dev/null +++ b/.changeset/cool-cows-report.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Deprecated the `AnyAnalyticsContext` type and mark the `AnalyticsApi` experimental. diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 9fd4f57ae9..8403a06b6f 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -35,25 +35,26 @@ export type AlertMessage = { severity?: 'success' | 'info' | 'warning' | 'error'; }; -// @public +// @alpha export type AnalyticsApi = { captureEvent(event: AnalyticsEvent): void; }; -// @public +// @alpha export const analyticsApiRef: ApiRef; -// @public +// @alpha export const AnalyticsContext: (options: { attributes: Partial; children: ReactNode; }) => JSX.Element; -// @public -export type AnalyticsContextValue = CommonAnalyticsContext & - AnyAnalyticsContext; +// @alpha +export type AnalyticsContextValue = CommonAnalyticsContext & { + [param in string]: string | boolean | number | undefined; +}; -// @public +// @alpha export type AnalyticsEvent = { action: string; subject: string; @@ -62,12 +63,12 @@ export type AnalyticsEvent = { context: AnalyticsContextValue; }; -// @public +// @alpha export type AnalyticsEventAttributes = { [attribute in string]: string | boolean | number; }; -// @public +// @alpha export type AnalyticsTracker = { captureEvent: ( action: string, @@ -79,7 +80,7 @@ export type AnalyticsTracker = { ) => void; }; -// @public +// @public @deprecated export type AnyAnalyticsContext = { [param in string]: string | boolean | number | undefined; }; @@ -282,7 +283,7 @@ export type BootErrorPageProps = { error: Error; }; -// @public +// @alpha export type CommonAnalyticsContext = { pluginId: string; routeRef: string; @@ -820,7 +821,7 @@ export type TypesToApiRefs = { [key in keyof T]: ApiRef; }; -// @public +// @alpha export function useAnalytics(): AnalyticsTracker; // @public diff --git a/packages/core-plugin-api/src/analytics/AnalyticsContext.tsx b/packages/core-plugin-api/src/analytics/AnalyticsContext.tsx index 075cdff3ff..af362cd921 100644 --- a/packages/core-plugin-api/src/analytics/AnalyticsContext.tsx +++ b/packages/core-plugin-api/src/analytics/AnalyticsContext.tsx @@ -60,7 +60,7 @@ export const useAnalyticsContext = (): AnalyticsContextValue => { * Analytics contexts are additive, meaning the context ultimately emitted with * an event is the combination of all contexts in the parent tree. * - * @public + * @alpha */ export const AnalyticsContext = (options: { attributes: Partial; diff --git a/packages/core-plugin-api/src/analytics/types.ts b/packages/core-plugin-api/src/analytics/types.ts index d001c38d3e..431e453a61 100644 --- a/packages/core-plugin-api/src/analytics/types.ts +++ b/packages/core-plugin-api/src/analytics/types.ts @@ -17,7 +17,7 @@ /** * Common analytics context attributes. * - * @public + * @alpha */ export type CommonAnalyticsContext = { /** @@ -40,6 +40,7 @@ export type CommonAnalyticsContext = { * Allows arbitrary scalar values as context attributes too. * * @public + * @deprecated Will be removed, use `AnalyticsContextValue` instead */ export type AnyAnalyticsContext = { [param in string]: string | boolean | number | undefined; @@ -48,7 +49,8 @@ export type AnyAnalyticsContext = { /** * Analytics context envelope. * - * @public + * @alpha */ -export type AnalyticsContextValue = CommonAnalyticsContext & - AnyAnalyticsContext; +export type AnalyticsContextValue = CommonAnalyticsContext & { + [param in string]: string | boolean | number | undefined; +}; diff --git a/packages/core-plugin-api/src/analytics/useAnalytics.tsx b/packages/core-plugin-api/src/analytics/useAnalytics.tsx index 5a047e5a63..f1297c5e4e 100644 --- a/packages/core-plugin-api/src/analytics/useAnalytics.tsx +++ b/packages/core-plugin-api/src/analytics/useAnalytics.tsx @@ -35,7 +35,7 @@ function useAnalyticsApi(): AnalyticsApi { /** * Gets a pre-configured analytics tracker. * - * @public + * @alpha */ export function useAnalytics(): AnalyticsTracker { const trackerRef = useRef(null); diff --git a/packages/core-plugin-api/src/apis/definitions/AnalyticsApi.ts b/packages/core-plugin-api/src/apis/definitions/AnalyticsApi.ts index ef190d6c21..dc38d7a250 100644 --- a/packages/core-plugin-api/src/apis/definitions/AnalyticsApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/AnalyticsApi.ts @@ -21,7 +21,7 @@ import { AnalyticsContextValue } from '../../analytics/types'; * Represents an event worth tracking in an analytics system that could inform * how users of a Backstage instance are using its features. * - * @public + * @alpha */ export type AnalyticsEvent = { /** @@ -79,7 +79,7 @@ export type AnalyticsEvent = { * A structure allowing other arbitrary metadata to be provided by analytics * event emitters. * - * @public + * @alpha */ export type AnalyticsEventAttributes = { [attribute in string]: string | boolean | number; @@ -89,7 +89,7 @@ export type AnalyticsEventAttributes = { * Represents a tracker with methods that can be called to track events in a * configured analytics service. * - * @public + * @alpha */ export type AnalyticsTracker = { captureEvent: ( @@ -103,6 +103,8 @@ export type AnalyticsTracker = { }; /** + * **EXPERIMENTAL** + * * The Analytics API is used to track user behavior in a Backstage instance. * * @remarks @@ -111,7 +113,7 @@ export type AnalyticsTracker = { * useAnalytics() hook. This will return a pre-configured AnalyticsTracker * with relevant methods for instrumentation. * - * @public + * @alpha */ export type AnalyticsApi = { /** @@ -122,9 +124,11 @@ export type AnalyticsApi = { }; /** + * **EXPERIMENTAL** + * * The {@link ApiRef} of {@link AnalyticsApi}. * - * @public + * @alpha */ export const analyticsApiRef: ApiRef = createApiRef({ id: 'core.analytics', From fc8fc025103310d1c0e4ab3ee0a7e9ae826d685b Mon Sep 17 00:00:00 2001 From: Rogerio Angeliski Date: Wed, 15 Dec 2021 13:05:39 -0300 Subject: [PATCH 159/189] add more options to rails new Signed-off-by: Rogerio Angeliski --- .changeset/gentle-humans-hope.md | 5 +++++ .../src/actions/fetch/rails/index.ts | 10 ++++++++++ .../actions/fetch/rails/railsArgumentResolver.test.ts | 2 ++ .../src/actions/fetch/rails/railsArgumentResolver.ts | 10 ++++++++++ 4 files changed, 27 insertions(+) create mode 100644 .changeset/gentle-humans-hope.md diff --git a/.changeset/gentle-humans-hope.md b/.changeset/gentle-humans-hope.md new file mode 100644 index 0000000000..b8c337cec9 --- /dev/null +++ b/.changeset/gentle-humans-hope.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-rails': patch +--- + +Add new options to rails new (force and skipTests) diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts index 00a5690c0a..56c45fa015 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts @@ -96,6 +96,16 @@ export function createFetchRailsAction(options: { description: "Don't run Webpack install", type: 'boolean', }, + skipTest: { + title: 'skipTest', + description: 'Skip test files', + type: 'boolean', + }, + force: { + title: 'force', + description: 'Overwrite files that already exist', + type: 'boolean', + }, api: { title: 'api', description: 'Preconfigure smaller stack for API only apps', diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts index 99a113f4f7..cced9f7ac2 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts @@ -27,6 +27,8 @@ describe('railsArgumentResolver', () => { [{ api: true }, ['--api']], [{ skipBundle: true }, ['--skip-bundle']], [{ skipWebpackInstall: true }, ['--skip-webpack-install']], + [{ skipTest: true }, ['--skip-test']], + [{ force: true }, ['--force']], [{ webpacker: 'vue' }, ['--webpack', 'vue']], [{ database: 'postgresql' }, ['--database', 'postgresql']], [{ railsVersion: 'dev' }, ['--dev']], diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts index 60251a702d..4006ead630 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts @@ -51,6 +51,8 @@ export type RailsRunOptions = { railsVersion?: RailsVersion; skipBundle?: boolean; skipWebpackInstall?: boolean; + skipTest?: boolean; + force?: boolean; }; export const railsArgumentResolver = ( @@ -76,6 +78,14 @@ export const railsArgumentResolver = ( argumentsToRun.push('--skip-webpack-install'); } + if (options?.skipTest) { + argumentsToRun.push('--skip-test'); + } + + if (options?.force) { + argumentsToRun.push('--force'); + } + if ( options?.webpacker && Object.values(Webpacker).includes(options?.webpacker as Webpacker) From 68b2a31a0531f11c43e4db8a2de28bebd4ae399d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlio=20Zynger?= Date: Wed, 15 Dec 2021 17:12:26 +0100 Subject: [PATCH 160/189] Update Airflow plugin README Airflow v1 exposed an experimental API [that got dropped](https://airflow.apache.org/docs/apache-airflow/stable/deprecated-rest-api-ref.html) later on. Let's add a note to the README making explicit users of Airflow v1 won't be able to integrate with this plugin unless they update. Signed-off-by: Julio Zynger --- plugins/apache-airflow/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/apache-airflow/README.md b/plugins/apache-airflow/README.md index c57ab9da43..bdbb1b981f 100644 --- a/plugins/apache-airflow/README.md +++ b/plugins/apache-airflow/README.md @@ -2,6 +2,9 @@ Welcome to the apache-airflow plugin! +This plugin serves as frontend to the REST API exposed by Apache Airflow. +Note only [Airflow v2 (and later)](https://airflow.apache.org/docs/apache-airflow/stable/deprecated-rest-api-ref.html) integrate with the plugin. + ## Feature Requests & Ideas - [ ] Add support for running multiple instances of Airflow for monitoring From eb3fd85d3e558ec77999a3ee8012407617a672cd Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Wed, 15 Dec 2021 17:33:49 +0100 Subject: [PATCH 161/189] feature: add crumbIssuer option to jenkins (optional) configuration, improve the UI to show a notification after executing the action: re-build Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- .changeset/twenty-tigers-smash.md | 5 ++ .changeset/twenty-tigers-ymash.md | 5 ++ plugins/jenkins-backend/api-report.md | 4 ++ .../src/service/jenkinsApi.test.ts | 13 ++++ .../jenkins-backend/src/service/jenkinsApi.ts | 1 + .../src/service/jenkinsInfoProvider.test.ts | 1 + .../src/service/jenkinsInfoProvider.ts | 8 ++- plugins/jenkins/api-report.md | 8 +-- plugins/jenkins/src/api/JenkinsApi.ts | 25 ++++---- .../BuildsPage/lib/CITable/CITable.tsx | 60 +++++++++++++++---- 10 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 .changeset/twenty-tigers-smash.md create mode 100644 .changeset/twenty-tigers-ymash.md diff --git a/.changeset/twenty-tigers-smash.md b/.changeset/twenty-tigers-smash.md new file mode 100644 index 0000000000..b7b06074dd --- /dev/null +++ b/.changeset/twenty-tigers-smash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-jenkins-backend': patch +--- + +feature: add crumbIssuer option to jenkins (optional) configuration, improve the UI to show a notification after executing the action re-build diff --git a/.changeset/twenty-tigers-ymash.md b/.changeset/twenty-tigers-ymash.md new file mode 100644 index 0000000000..609b30e0f5 --- /dev/null +++ b/.changeset/twenty-tigers-ymash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-jenkins': patch +--- + +feature: add crumbIssuer option to jenkins (optional) configuration, improve the UI to show a notification after executing the action re-build diff --git a/plugins/jenkins-backend/api-report.md b/plugins/jenkins-backend/api-report.md index c909c54806..b8d171f9c1 100644 --- a/plugins/jenkins-backend/api-report.md +++ b/plugins/jenkins-backend/api-report.md @@ -52,6 +52,8 @@ export interface JenkinsInfo { // (undocumented) baseUrl: string; // (undocumented) + crumbIssuer?: boolean; + // (undocumented) headers?: Record; // (undocumented) jobFullName: string; @@ -77,6 +79,8 @@ export interface JenkinsInstanceConfig { // (undocumented) baseUrl: string; // (undocumented) + crumbIssuer?: boolean; + // (undocumented) name: string; // (undocumented) username: string; diff --git a/plugins/jenkins-backend/src/service/jenkinsApi.test.ts b/plugins/jenkins-backend/src/service/jenkinsApi.test.ts index 5f74259eef..a410d8ad92 100644 --- a/plugins/jenkins-backend/src/service/jenkinsApi.test.ts +++ b/plugins/jenkins-backend/src/service/jenkinsApi.test.ts @@ -411,4 +411,17 @@ describe('JenkinsApi', () => { }); expect(mockedJenkinsClient.job.build).toBeCalledWith(jobFullName); }); + + it('buildProject with crumbIssuer option', async () => { + const info: JenkinsInfo = { ...jenkinsInfo, crumbIssuer: true }; + await jenkinsApi.buildProject(info, jobFullName); + + expect(mockedJenkins).toHaveBeenCalledWith({ + baseUrl: jenkinsInfo.baseUrl, + headers: jenkinsInfo.headers, + promisify: true, + crumbIssuer: true, + }); + expect(mockedJenkinsClient.job.build).toBeCalledWith(jobFullName); + }); }); diff --git a/plugins/jenkins-backend/src/service/jenkinsApi.ts b/plugins/jenkins-backend/src/service/jenkinsApi.ts index 13705ce049..f156259f04 100644 --- a/plugins/jenkins-backend/src/service/jenkinsApi.ts +++ b/plugins/jenkins-backend/src/service/jenkinsApi.ts @@ -146,6 +146,7 @@ export class JenkinsApiImpl { baseUrl: jenkinsInfo.baseUrl, headers: jenkinsInfo.headers, promisify: true, + crumbIssuer: jenkinsInfo.crumbIssuer, }) as any; } diff --git a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts index 08439297a7..21a2022bb3 100644 --- a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts +++ b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts @@ -210,6 +210,7 @@ describe('DefaultJenkinsInfoProvider', () => { expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); expect(info).toStrictEqual({ baseUrl: 'https://jenkins.example.com', + crumbIssuer: undefined, headers: { Authorization: 'Basic YmFja3N0YWdlIC0gYm90OjEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNlZGYwMTI=', diff --git a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts index 1a992e73f1..f5cb52b696 100644 --- a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts +++ b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts @@ -38,6 +38,7 @@ export interface JenkinsInfo { baseUrl: string; headers?: Record; jobFullName: string; // TODO: make this an array + crumbIssuer?: boolean; } export interface JenkinsInstanceConfig { @@ -45,6 +46,7 @@ export interface JenkinsInstanceConfig { baseUrl: string; username: string; apiKey: string; + crumbIssuer?: boolean; } /** @@ -70,6 +72,7 @@ export class JenkinsConfig { baseUrl: c.getString('baseUrl'), username: c.getString('username'), apiKey: c.getString('apiKey'), + crumbIssuer: c.getOptionalBoolean('crumbIssuer'), })) || []; // load unnamed default config @@ -81,6 +84,7 @@ export class JenkinsConfig { const baseUrl = jenkinsConfig.getOptionalString('baseUrl'); const username = jenkinsConfig.getOptionalString('username'); const apiKey = jenkinsConfig.getOptionalString('apiKey'); + const crumbIssuer = jenkinsConfig.getOptionalBoolean('crumbIssuer'); if (hasNamedDefault && (baseUrl || username || apiKey)) { throw new Error( @@ -98,12 +102,13 @@ export class JenkinsConfig { if (unnamedAllPresent) { const unnamedInstanceConfig = [ - { name: DEFAULT_JENKINS_NAME, baseUrl, username, apiKey }, + { name: DEFAULT_JENKINS_NAME, baseUrl, username, apiKey, crumbIssuer }, ] as { name: string; baseUrl: string; username: string; apiKey: string; + crumbIssuer: boolean; }[]; return new JenkinsConfig([ @@ -227,6 +232,7 @@ export class DefaultJenkinsInfoProvider implements JenkinsInfoProvider { Authorization: `Basic ${creds}`, }, jobFullName, + crumbIssuer: instanceConfig.crumbIssuer, }; } diff --git a/plugins/jenkins/api-report.md b/plugins/jenkins/api-report.md index f33e565d89..829256e22d 100644 --- a/plugins/jenkins/api-report.md +++ b/plugins/jenkins/api-report.md @@ -9,8 +9,8 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; -import { EntityName } from '@backstage/catalog-model'; -import { EntityRef } from '@backstage/catalog-model'; +import type { EntityName } from '@backstage/catalog-model'; +import type { EntityRef } from '@backstage/catalog-model'; import { IdentityApi } from '@backstage/core-plugin-api'; import { InfoCardVariants } from '@backstage/core-components'; import { RouteRef } from '@backstage/core-plugin-api'; @@ -72,7 +72,7 @@ export interface JenkinsApi { entity: EntityName; jobFullName: string; buildNumber: string; - }): Promise; + }): Promise; } // Warning: (ae-missing-release-tag) "jenkinsApiRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -117,7 +117,7 @@ export class JenkinsClient implements JenkinsApi { entity: EntityName; jobFullName: string; buildNumber: string; - }): Promise; + }): Promise; } // Warning: (ae-missing-release-tag) "jenkinsPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/jenkins/src/api/JenkinsApi.ts b/plugins/jenkins/src/api/JenkinsApi.ts index 4b23fb4292..48e506953f 100644 --- a/plugins/jenkins/src/api/JenkinsApi.ts +++ b/plugins/jenkins/src/api/JenkinsApi.ts @@ -19,7 +19,7 @@ import { DiscoveryApi, IdentityApi, } from '@backstage/core-plugin-api'; -import { EntityName, EntityRef } from '@backstage/catalog-model'; +import type { EntityName, EntityRef } from '@backstage/catalog-model'; export const jenkinsApiRef = createApiRef({ id: 'plugin.jenkins.service2', @@ -66,7 +66,7 @@ export interface Project { inQueue: string; // added by us status: string; // == inQueue ? 'queued' : lastBuild.building ? 'running' : lastBuild.result, - onRestartClick: () => Promise; // TODO rename to handle.* ? also, should this be on lastBuild? + onRestartClick: () => Promise; // TODO rename to handle.* ? also, should this be on lastBuild? } export interface JenkinsApi { @@ -106,7 +106,7 @@ export interface JenkinsApi { entity: EntityName; jobFullName: string; buildNumber: string; - }): Promise; + }): Promise; } export class JenkinsClient implements JenkinsApi { @@ -140,7 +140,7 @@ export class JenkinsClient implements JenkinsApi { url.searchParams.append('branch', filter.branch); } - const idToken = await this.identityApi.getIdToken(); + const idToken = await this.getToken(); const response = await fetch(url.href, { method: 'GET', headers: { @@ -151,8 +151,8 @@ export class JenkinsClient implements JenkinsApi { return ( (await response.json()).projects?.map((p: Project) => ({ ...p, - onRestartClick: async () => { - await this.retry({ + onRestartClick: () => { + return this.retry({ entity, jobFullName: p.fullName, buildNumber: String(p.lastBuild.number), @@ -179,7 +179,7 @@ export class JenkinsClient implements JenkinsApi { jobFullName, )}/${encodeURIComponent(buildNumber)}`; - const idToken = await this.identityApi.getIdToken(); + const idToken = await this.getToken(); const response = await fetch(url, { method: 'GET', headers: { @@ -198,7 +198,7 @@ export class JenkinsClient implements JenkinsApi { entity: EntityName; jobFullName: string; buildNumber: string; - }): Promise { + }): Promise { const url = `${await this.discoveryApi.getBaseUrl( 'jenkins', )}/v1/entity/${encodeURIComponent(entity.namespace)}/${encodeURIComponent( @@ -207,12 +207,17 @@ export class JenkinsClient implements JenkinsApi { jobFullName, )}/${encodeURIComponent(buildNumber)}:rebuild`; - const idToken = await this.identityApi.getIdToken(); - await fetch(url, { + const idToken = await this.getToken(); + return fetch(url, { method: 'POST', headers: { ...(idToken && { Authorization: `Bearer ${idToken}` }), }, }); } + + private async getToken() { + const { token } = await this.identityApi.getCredentials(); + return token; + } } diff --git a/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx index b1eaf2c24c..e14b24912b 100644 --- a/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx +++ b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; -import { Box, IconButton, Link, Typography, Tooltip } from '@material-ui/core'; +import React, { useState } from 'react'; +import { Box, IconButton, Link, Tooltip, Typography } from '@material-ui/core'; import RetryIcon from '@material-ui/icons/Replay'; import JenkinsLogo from '../../../../assets/JenkinsLogo.svg'; import { Link as RouterLink } from 'react-router-dom'; import { JenkinsRunStatus } from '../Status'; import { useBuilds } from '../../../useBuilds'; import { buildRouteRef } from '../../../../plugin'; -import { Table, TableColumn } from '@backstage/core-components'; +import { Progress, Table, TableColumn } from '@backstage/core-components'; import { Project } from '../../../../api/JenkinsApi'; -import { useRouteRef } from '@backstage/core-plugin-api'; +import { alertApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; const FailCount = ({ count }: { count: number }): JSX.Element | null => { if (count !== 0) { @@ -173,13 +173,51 @@ const generatedColumns: TableColumn[] = [ { title: 'Actions', sorting: false, - render: (row: Partial) => ( - - - - - - ), + render: (row: Partial) => { + const ActionWrapper = () => { + const [isLoadingRebuild, setIsLoadingRebuild] = useState(false); + const alertApi = useApi(alertApiRef); + + const onRebuild = async () => { + if (row.onRestartClick) { + setIsLoadingRebuild(true); + try { + const response = await row.onRestartClick(); + const body = (await response.json()) as { + error?: { message: string }; + }; + if (response.status !== 200) { + alertApi.post({ + message: `Jenkins re-build has been failed. Reason: ${body.error?.message}`, + severity: 'error', + }); + } else { + alertApi.post({ + message: 'Jenkins re-build has been successfully executed', + severity: 'success', + }); + } + } finally { + setIsLoadingRebuild(false); + } + } + }; + + return ( + + <> + {isLoadingRebuild && } + {!isLoadingRebuild && ( + + + + )} + + + ); + }; + return ; + }, width: '10%', }, ]; From 7927005152203ac15b48645a9ca84536fe20ad58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 7 Jul 2021 17:10:36 +0200 Subject: [PATCH 162/189] Add `fetchApiRef` which implements fetch, plus Backstage token header when available. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This intends to be the basis for other plugins' data fetching needs, so that they can transparently interact with the catalog and other parts of the Backstage ecosystem without explicitly having to deal with authenticating themselves. Signed-off-by: Fredrik AdelΓΆw --- .changeset/blue-queens-sniff.md | 7 ++ .changeset/lovely-drinks-kiss.md | 5 ++ packages/app-defaults/src/defaults/apis.ts | 23 +++++ packages/catalog-client/api-report.md | 8 +- packages/catalog-client/src/CatalogClient.ts | 17 ++-- .../catalog-client/src/types/discovery.ts | 2 +- packages/catalog-client/src/types/fetch.ts | 26 ++++++ packages/catalog-client/src/types/index.ts | 1 + packages/core-app-api/api-report.md | 35 ++++++++ packages/core-app-api/package.json | 1 + ...ageProtocolResolverFetchMiddleware.test.ts | 86 +++++++++++++++++++ ...ackstageProtocolResolverFetchMiddleware.ts | 64 ++++++++++++++ .../FetchApi/FetchApiBuilder.ts | 55 ++++++++++++ .../IdentityAwareFetchMiddleware.test.ts | 43 ++++++++++ .../FetchApi/IdentityAwareFetchMiddleware.ts | 59 +++++++++++++ .../apis/implementations/FetchApi/index.ts | 20 +++++ .../apis/implementations/FetchApi/types.ts | 39 +++++++++ .../src/apis/implementations/index.ts | 1 + packages/core-plugin-api/api-report.md | 9 ++ packages/core-plugin-api/package.json | 2 +- .../src/apis/definitions/FetchApi.ts | 38 ++++++++ .../src/apis/definitions/index.ts | 1 + 22 files changed, 532 insertions(+), 10 deletions(-) create mode 100644 .changeset/blue-queens-sniff.md create mode 100644 .changeset/lovely-drinks-kiss.md create mode 100644 packages/catalog-client/src/types/fetch.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.test.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/FetchApiBuilder.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.test.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/index.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/types.ts create mode 100644 packages/core-plugin-api/src/apis/definitions/FetchApi.ts diff --git a/.changeset/blue-queens-sniff.md b/.changeset/blue-queens-sniff.md new file mode 100644 index 0000000000..9a26507f92 --- /dev/null +++ b/.changeset/blue-queens-sniff.md @@ -0,0 +1,7 @@ +--- +'@backstage/app-defaults': patch +'@backstage/core-app-api': patch +'@backstage/core-plugin-api': patch +--- + +Add `FetchApi` and related `fetchApiRef` which implement fetch, with an added Backstage token header when available. diff --git a/.changeset/lovely-drinks-kiss.md b/.changeset/lovely-drinks-kiss.md new file mode 100644 index 0000000000..f343888920 --- /dev/null +++ b/.changeset/lovely-drinks-kiss.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': patch +--- + +Add the ability to supply a custom `fetchApi`. In the default frontend app setup, this will use the `fetchApiRef` implementation. diff --git a/packages/app-defaults/src/defaults/apis.ts b/packages/app-defaults/src/defaults/apis.ts index d3c76d52bd..06562caaef 100644 --- a/packages/app-defaults/src/defaults/apis.ts +++ b/packages/app-defaults/src/defaults/apis.ts @@ -34,6 +34,9 @@ import { OneLoginAuth, UnhandledErrorForwarder, AtlassianAuth, + FetchApiBuilder, + IdentityAwareFetchMiddleware, + BackstageProtocolResolverFetchMiddleware, } from '@backstage/core-app-api'; import { @@ -42,6 +45,8 @@ import { analyticsApiRef, errorApiRef, discoveryApiRef, + fetchApiRef, + identityApiRef, oauthRequestApiRef, googleAuthApiRef, githubAuthApiRef, @@ -92,6 +97,24 @@ export const apis = [ deps: { errorApi: errorApiRef }, factory: ({ errorApi }) => WebStorage.create({ errorApi }), }), + createApiFactory({ + api: fetchApiRef, + deps: { identityApi: identityApiRef, discoveryApi: discoveryApiRef }, + factory: ({ identityApi, discoveryApi }) => { + return FetchApiBuilder.create() + .with( + new IdentityAwareFetchMiddleware(() => { + return identityApi.getCredentials().then(r => r.token); + }), + ) + .with( + new BackstageProtocolResolverFetchMiddleware(plugin => { + return discoveryApi.getBaseUrl(plugin); + }), + ) + .build(); + }, + }), createApiFactory({ api: oauthRequestApiRef, deps: {}, diff --git a/packages/catalog-client/api-report.md b/packages/catalog-client/api-report.md index e16ca740f6..41aea63716 100644 --- a/packages/catalog-client/api-report.md +++ b/packages/catalog-client/api-report.md @@ -5,6 +5,7 @@ ```ts import { Entity } from '@backstage/catalog-model'; import { EntityName } from '@backstage/catalog-model'; +import { default as fetch_2 } from 'cross-fetch'; import { Location as Location_2 } from '@backstage/catalog-model'; // @public @@ -71,7 +72,7 @@ export interface CatalogApi { // @public export class CatalogClient implements CatalogApi { - constructor(options: { discoveryApi: DiscoveryApi }); + constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }); addLocation( { type, target, dryRun, presence }: AddLocationRequest, options?: CatalogRequestOptions, @@ -155,4 +156,9 @@ export type DiscoveryApi = { // @public export const ENTITY_STATUS_CATALOG_PROCESSING_TYPE = 'backstage.io/catalog-processing'; + +// @public +export type FetchApi = { + fetch: typeof fetch_2; +}; ``` diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index 29d01fbe5c..047a8c7cce 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -25,7 +25,7 @@ import { stringifyLocationReference, } from '@backstage/catalog-model'; import { ResponseError } from '@backstage/errors'; -import fetch from 'cross-fetch'; +import crossFetch from 'cross-fetch'; import { CATALOG_FILTER_EXISTS, AddLocationRequest, @@ -38,6 +38,7 @@ import { CatalogEntityAncestorsResponse, } from './types/api'; import { DiscoveryApi } from './types/discovery'; +import { FetchApi } from './types/fetch'; /** * A frontend and backend compatible client for communicating with the Backstage Catalog. @@ -46,9 +47,11 @@ import { DiscoveryApi } from './types/discovery'; * */ export class CatalogClient implements CatalogApi { private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; - constructor(options: { discoveryApi: DiscoveryApi }) { + constructor(options: { discoveryApi: DiscoveryApi; fetchApi?: FetchApi }) { this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi || { fetch: crossFetch }; } /** @@ -206,7 +209,7 @@ export class CatalogClient implements CatalogApi { * @public */ async refreshEntity(entityRef: string, options?: CatalogRequestOptions) { - const response = await fetch( + const response = await this.fetchApi.fetch( `${await this.discoveryApi.getBaseUrl('catalog')}/refresh`, { headers: { @@ -237,7 +240,7 @@ export class CatalogClient implements CatalogApi { { type = 'url', target, dryRun, presence }: AddLocationRequest, options?: CatalogRequestOptions, ): Promise { - const response = await fetch( + const response = await this.fetchApi.fetch( `${await this.discoveryApi.getBaseUrl('catalog')}/locations${ dryRun ? '?dryRun=true' : '' }`, @@ -376,7 +379,7 @@ export class CatalogClient implements CatalogApi { const headers: Record = options?.token ? { Authorization: `Bearer ${options.token}` } : {}; - const response = await fetch(url, { method, headers }); + const response = await this.fetchApi.fetch(url, { method, headers }); if (!response.ok) { throw await ResponseError.fromResponse(response); @@ -392,7 +395,7 @@ export class CatalogClient implements CatalogApi { const headers: Record = options?.token ? { Authorization: `Bearer ${options.token}` } : {}; - const response = await fetch(url, { method, headers }); + const response = await this.fetchApi.fetch(url, { method, headers }); if (!response.ok) { throw await ResponseError.fromResponse(response); @@ -410,7 +413,7 @@ export class CatalogClient implements CatalogApi { const headers: Record = options?.token ? { Authorization: `Bearer ${options.token}` } : {}; - const response = await fetch(url, { method, headers }); + const response = await this.fetchApi.fetch(url, { method, headers }); if (!response.ok) { if (response.status === 404) { diff --git a/packages/catalog-client/src/types/discovery.ts b/packages/catalog-client/src/types/discovery.ts index 19ee5ed19c..5fa14372e3 100644 --- a/packages/catalog-client/src/types/discovery.ts +++ b/packages/catalog-client/src/types/discovery.ts @@ -15,7 +15,7 @@ */ /** - * This is a copy of the core DiscoveryApi, to avoid importing core. + * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. * * @public */ diff --git a/packages/catalog-client/src/types/fetch.ts b/packages/catalog-client/src/types/fetch.ts new file mode 100644 index 0000000000..cdddd31810 --- /dev/null +++ b/packages/catalog-client/src/types/fetch.ts @@ -0,0 +1,26 @@ +/* + * 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 fetch from 'cross-fetch'; + +/** + * This is a copy of FetchApi, to avoid importing core-plugin-api. + * + * @public + */ +export type FetchApi = { + fetch: typeof fetch; +}; diff --git a/packages/catalog-client/src/types/index.ts b/packages/catalog-client/src/types/index.ts index 3552a72e3c..f3c6fab4e9 100644 --- a/packages/catalog-client/src/types/index.ts +++ b/packages/catalog-client/src/types/index.ts @@ -25,5 +25,6 @@ export type { CatalogEntityAncestorsResponse, } from './api'; export type { DiscoveryApi } from './discovery'; +export type { FetchApi } from './fetch'; export { CATALOG_FILTER_EXISTS } from './api'; export { ENTITY_STATUS_CATALOG_PROCESSING_TYPE } from './status'; diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index 8a3f0edf14..3277be7841 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -26,6 +26,7 @@ import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import { ConfigReader } from '@backstage/config'; import { createApp as createApp_2 } from '@backstage/app-defaults'; +import crossFetch from 'cross-fetch'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { ErrorApi } from '@backstage/core-plugin-api'; import { ErrorApiError } from '@backstage/core-plugin-api'; @@ -34,6 +35,7 @@ import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { FeatureFlag } from '@backstage/core-plugin-api'; import { FeatureFlagsApi } from '@backstage/core-plugin-api'; import { FeatureFlagsSaveOptions } from '@backstage/core-plugin-api'; +import { FetchApi } from '@backstage/core-plugin-api'; import { gitlabAuthApiRef } from '@backstage/core-plugin-api'; import { googleAuthApiRef } from '@backstage/core-plugin-api'; import { IconComponent } from '@backstage/core-plugin-api'; @@ -288,6 +290,14 @@ export type BackstagePluginWithAnyOutput = Omit< )[]; }; +// @public +export class BackstageProtocolResolverFetchMiddleware + implements FetchMiddleware +{ + constructor(discovery: (pluginId: string) => Promise); + apply(next: FetchFunction): FetchFunction; +} + // @public export class BitbucketAuth { // (undocumented) @@ -369,6 +379,24 @@ export type FeatureFlaggedProps = { } ); +// @public +export class FetchApiBuilder { + // (undocumented) + build(): FetchApi; + // (undocumented) + static create(): FetchApiBuilder; + // (undocumented) + with(middleware: FetchMiddleware): FetchApiBuilder; +} + +// @public +export type FetchFunction = typeof crossFetch; + +// @public +export interface FetchMiddleware { + apply(next: FetchFunction): FetchFunction; +} + // @public export const FlatRoutes: (props: FlatRoutesProps) => JSX.Element | null; @@ -426,6 +454,13 @@ export class GoogleAuth { static create(options: OAuthApiCreateOptions): typeof googleAuthApiRef.T; } +// @public +export class IdentityAwareFetchMiddleware implements FetchMiddleware { + constructor(tokenFunction: () => Promise); + apply(next: FetchFunction): FetchFunction; + setHeaderName(name: string): IdentityAwareFetchMiddleware; +} + // @public export class LocalStorageFeatureFlags implements FeatureFlagsApi { // (undocumented) diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 23079d7ba0..d138417143 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -39,6 +39,7 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@types/prop-types": "^15.7.3", + "cross-fetch": "^3.0.6", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.test.ts b/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.test.ts new file mode 100644 index 0000000000..7dcb90573b --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.test.ts @@ -0,0 +1,86 @@ +/* + * 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 { BackstageProtocolResolverFetchMiddleware } from './BackstageProtocolResolverFetchMiddleware'; + +describe('BackstageProtocolResolverFetchMiddleware', () => { + it.each([['https://passthrough.com/a']])( + 'passes through regular URLs, %p', + async (url: string) => { + const resolve = jest.fn(); + const middleware = new BackstageProtocolResolverFetchMiddleware(resolve); + const inner = jest.fn(); + const outer = middleware.apply(inner); + + await outer(url); + expect(inner.mock.calls[0][0]).toBe(url); + expect(resolve).not.toBeCalled(); + }, + ); + + it.each([ + [ + 'backstage://my-plugin/sub/path', + 'my-plugin', + 'https://real.com/base', + 'https://real.com/base/sub/path', + ], + [ + 'backstage://my-plugin/sub/path/', + 'my-plugin', + 'https://real.com/base/', + 'https://real.com/base/sub/path/', + ], + ['backstage://x', 'x', 'http://real.com:8080', 'http://real.com:8080'], + [ + 'backstage://x/a/b?c=d&e=f#g', + 'x', + 'https://real.com/base', + 'https://real.com/base/a/b?c=d&e=f#g', + ], + [ + 'backstage://x?c=d&e=f#g', + 'x', + 'https://real.com:8080/base', + 'https://real.com:8080/base?c=d&e=f#g', + ], + [ + 'backstage://username:password@x?c=d&e=f#g', + 'x', + 'https://real.com:8080/base', + 'https://username:password@real.com:8080/base?c=d&e=f#g', + ], + [ + 'backstage://x?c=d&e=f#g', + 'x', + 'https://username:password@real.com:8080/base', + 'https://username:password@real.com:8080/base?c=d&e=f#g', + ], + ])( + 'resolves backstage URLs, %p', + async (original, host, resolved, result) => { + const resolve = jest.fn(); + const middleware = new BackstageProtocolResolverFetchMiddleware(resolve); + const inner = jest.fn(); + const outer = middleware.apply(inner); + + resolve.mockResolvedValueOnce(resolved); + await outer(original); + expect(inner.mock.calls[0][0]).toBe(result); + expect(resolve).toHaveBeenLastCalledWith(host); + }, + ); +}); diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts b/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts new file mode 100644 index 0000000000..03d08c3096 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts @@ -0,0 +1,64 @@ +/* + * 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 { FetchFunction, FetchMiddleware } from './types'; + +function join(left: string, right: string): string { + if (!right || right === '/') { + return left; + } + + return `${left.replace(/\/$/, '')}/${right.replace(/^\//, '')}`; +} + +/** + * Handles translation from backstage://some-plugin-id/ to concrete + * http(s) URLs. + * + * @public + */ +export class BackstageProtocolResolverFetchMiddleware + implements FetchMiddleware +{ + constructor( + private readonly discovery: (pluginId: string) => Promise, + ) {} + + /** + * {@inheritdoc FetchMiddleware.apply} + */ + apply(next: FetchFunction): FetchFunction { + return async (input, init) => { + const request = new Request(input, init); + const { protocol, hostname, pathname, search, hash, username, password } = + new URL(request.url); + + if (protocol !== 'backstage:') { + return next(input, init); + } + + let base = await this.discovery(hostname); + if (username || password) { + const baseUrl = new URL(base); + const authority = `${username}${password ? `:${password}` : ''}@`; + base = `${baseUrl.protocol}//${authority}${baseUrl.host}${baseUrl.pathname}`; + } + + const target = `${join(base, pathname)}${search}${hash}`; + return next(target, request); + }; + } +} diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/FetchApiBuilder.ts b/packages/core-app-api/src/apis/implementations/FetchApi/FetchApiBuilder.ts new file mode 100644 index 0000000000..1c96eb1ad6 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/FetchApiBuilder.ts @@ -0,0 +1,55 @@ +/* + * 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 { FetchApi } from '@backstage/core-plugin-api'; +import crossFetch from 'cross-fetch'; +import { FetchFunction, FetchMiddleware } from './types'; + +/** + * Builds a fetch API, based on the builtin fetch wrapped by a set of optional + * middleware implementations that add behaviors. + * + * @public + */ +export class FetchApiBuilder { + static create(): FetchApiBuilder { + return new FetchApiBuilder(crossFetch, []); + } + + private constructor( + private readonly implementation: FetchFunction, + private readonly middleware: FetchMiddleware[], + ) {} + + with(middleware: FetchMiddleware): FetchApiBuilder { + return new FetchApiBuilder(this.implementation, [ + ...this.middleware, + middleware, + ]); + } + + build(): FetchApi { + let result = this.implementation; + + for (const m of this.middleware) { + result = m.apply(result); + } + + return { + fetch: result, + }; + } +} diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.test.ts b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.test.ts new file mode 100644 index 0000000000..381ebd62a9 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.test.ts @@ -0,0 +1,43 @@ +/* + * 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 { IdentityAwareFetchMiddleware } from './IdentityAwareFetchMiddleware'; + +describe('IdentityAwareFetchMiddleware', () => { + it('injects the header only when a token is available', async () => { + const tokenFunction = jest.fn(); + const middleware = new IdentityAwareFetchMiddleware(tokenFunction); + const inner = jest.fn(); + const outer = middleware.apply(inner); + + // No token available + tokenFunction.mockResolvedValueOnce(undefined); + await outer(new Request('https://example.com')); + expect([...inner.mock.calls[0][0].headers.entries()]).toEqual([]); + + // Supply a token, header gets added + tokenFunction.mockResolvedValueOnce('token'); + await outer(new Request('https://example.com')); + expect([...inner.mock.calls[1][0].headers.entries()]).toEqual([ + ['backstage-token', 'token'], + ]); + + // Token no longer available + tokenFunction.mockResolvedValueOnce(undefined); + await outer(new Request('https://example.com')); + expect([...inner.mock.calls[2][0].headers.entries()]).toEqual([]); + }); +}); diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.ts b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.ts new file mode 100644 index 0000000000..474ca83894 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.ts @@ -0,0 +1,59 @@ +/* + * 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 { FetchFunction, FetchMiddleware } from './types'; + +const DEFAULT_HEADER_NAME = 'backstage-token'; + +/** + * A fetch middleware, which injects a Backstage token header when the user is + * signed in. + * + * @public + */ +export class IdentityAwareFetchMiddleware implements FetchMiddleware { + private headerName: string; + private tokenFunction: () => Promise; + + constructor(tokenFunction: () => Promise) { + this.headerName = DEFAULT_HEADER_NAME; + this.tokenFunction = tokenFunction; + } + + /** + * {@inheritdoc FetchMiddleware.apply} + */ + apply(next: FetchFunction): FetchFunction { + return async (input, init) => { + const token = await this.tokenFunction(); + if (typeof token !== 'string') { + return next(input, init); + } + + const request = new Request(input, init); + request.headers.set(this.headerName, token); + return next(request); + }; + } + + /** + * Changes the header name from the default value to a custom one. + */ + setHeaderName(name: string): IdentityAwareFetchMiddleware { + this.headerName = name; + return this; + } +} diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/index.ts b/packages/core-app-api/src/apis/implementations/FetchApi/index.ts new file mode 100644 index 0000000000..7544bd8bf2 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { BackstageProtocolResolverFetchMiddleware } from './BackstageProtocolResolverFetchMiddleware'; +export { FetchApiBuilder } from './FetchApiBuilder'; +export { IdentityAwareFetchMiddleware } from './IdentityAwareFetchMiddleware'; +export type { FetchFunction, FetchMiddleware } from './types'; diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/types.ts b/packages/core-app-api/src/apis/implementations/FetchApi/types.ts new file mode 100644 index 0000000000..4cf0bf47f4 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/types.ts @@ -0,0 +1,39 @@ +/* + * 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 crossFetch from 'cross-fetch'; + +/** + * The type of a fetch call. + * + * @public + */ +export type FetchFunction = typeof crossFetch; + +/** + * A middleware that modifies the behavior of an ongoing fetch. + * + * @public + */ +export interface FetchMiddleware { + /** + * Applies this middleware to an inner implementation. + * + * @param next - The next, inner, implementation, that this middleware shall + * call out to as part of the request cycle. + */ + apply(next: FetchFunction): FetchFunction; +} diff --git a/packages/core-app-api/src/apis/implementations/index.ts b/packages/core-app-api/src/apis/implementations/index.ts index c494f966f2..1c79d3d164 100644 --- a/packages/core-app-api/src/apis/implementations/index.ts +++ b/packages/core-app-api/src/apis/implementations/index.ts @@ -27,5 +27,6 @@ export * from './ConfigApi'; export * from './DiscoveryApi'; export * from './ErrorApi'; export * from './FeatureFlagsApi'; +export * from './FetchApi'; export * from './OAuthRequestApi'; export * from './StorageApi'; diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 9fd4f57ae9..148115fd69 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -9,6 +9,7 @@ import { BackstagePlugin as BackstagePlugin_2 } from '@backstage/core-plugin-api import { BackstageTheme } from '@backstage/theme'; import { ComponentType } from 'react'; import { Config } from '@backstage/config'; +import { default as fetch_2 } from 'cross-fetch'; import { IconComponent as IconComponent_2 } from '@backstage/core-plugin-api'; import { IdentityApi as IdentityApi_2 } from '@backstage/core-plugin-api'; import { Observable as Observable_2 } from '@backstage/types'; @@ -505,6 +506,14 @@ export enum FeatureFlagState { None = 0, } +// @public +export type FetchApi = { + fetch: typeof fetch_2; +}; + +// @public +export const fetchApiRef: ApiRef; + // @public export function getComponentData( node: ReactNode, diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 72827bde73..365cec3134 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -34,6 +34,7 @@ "@backstage/types": "^0.1.1", "@backstage/version-bridge": "^0.1.1", "@material-ui/core": "^4.12.2", + "cross-fetch": "^3.0.6", "history": "^5.0.0", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", @@ -56,7 +57,6 @@ "@types/node": "^14.14.32", "@types/prop-types": "^15.7.3", "@types/zen-observable": "^0.8.0", - "cross-fetch": "^3.0.6", "msw": "^0.35.0" }, "files": [ diff --git a/packages/core-plugin-api/src/apis/definitions/FetchApi.ts b/packages/core-plugin-api/src/apis/definitions/FetchApi.ts new file mode 100644 index 0000000000..30eb950634 --- /dev/null +++ b/packages/core-plugin-api/src/apis/definitions/FetchApi.ts @@ -0,0 +1,38 @@ +/* + * 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 fetch from 'cross-fetch'; +import { ApiRef, createApiRef } from '../system'; + +/** + * A wrapper for the fetch API, that has additional behaviors such as the + * ability to automatically inject auth information where necessary. + * + * @public + */ +export type FetchApi = { + fetch: typeof fetch; +}; + +/** + * A wrapper for the fetch API, that has additional behaviors such as the + * ability to automatically inject auth information where necessary. + * + * @public + */ +export const fetchApiRef: ApiRef = createApiRef({ + id: 'core.fetch', +}); diff --git a/packages/core-plugin-api/src/apis/definitions/index.ts b/packages/core-plugin-api/src/apis/definitions/index.ts index b7666bcb54..67d442587d 100644 --- a/packages/core-plugin-api/src/apis/definitions/index.ts +++ b/packages/core-plugin-api/src/apis/definitions/index.ts @@ -29,6 +29,7 @@ export * from './ConfigApi'; export * from './DiscoveryApi'; export * from './ErrorApi'; export * from './FeatureFlagsApi'; +export * from './FetchApi'; export * from './IdentityApi'; export * from './OAuthRequestApi'; export * from './StorageApi'; From afb7f31840d506c270035d1b53e5f4ede553e1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 9 Dec 2021 15:10:20 +0100 Subject: [PATCH 163/189] fixed the browser behavior for BackstageProtocolResolverFetchMiddleware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik AdelΓΆw --- .../BackstageProtocolResolverFetchMiddleware.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts b/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts index 03d08c3096..2144d0058d 100644 --- a/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts +++ b/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts @@ -43,13 +43,18 @@ export class BackstageProtocolResolverFetchMiddleware apply(next: FetchFunction): FetchFunction { return async (input, init) => { const request = new Request(input, init); - const { protocol, hostname, pathname, search, hash, username, password } = - new URL(request.url); + const prefix = 'backstage://'; - if (protocol !== 'backstage:') { + if (!request.url.startsWith(prefix)) { return next(input, init); } + // Switch to a known protocol, since browser URL parsing misbehaves wildly + // on foreign protocols + const { hostname, pathname, search, hash, username, password } = new URL( + `http://${request.url.substring(prefix.length)}`, + ); + let base = await this.discovery(hostname); if (username || password) { const baseUrl = new URL(base); From 3fa31ec84a4b564397d410228df25a9c75dac2d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 14 Dec 2021 14:11:30 +0100 Subject: [PATCH 164/189] address comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik AdelΓΆw --- .changeset/itchy-grapes-think.md | 25 +++ packages/app-defaults/src/defaults/apis.ts | 32 ++-- packages/catalog-client/api-report.md | 3 +- packages/catalog-client/src/types/fetch.ts | 2 - packages/core-app-api/api-report.md | 50 +++--- packages/core-app-api/package.json | 1 - .../FetchApi/FetchMiddlewares.ts | 76 +++++++++ ...dentityAuthInjectorFetchMiddleware.test.ts | 153 ++++++++++++++++++ .../IdentityAuthInjectorFetchMiddleware.ts | 82 ++++++++++ .../IdentityAwareFetchMiddleware.test.ts | 43 ----- .../FetchApi/IdentityAwareFetchMiddleware.ts | 59 ------- ...inProtocolResolverFetchMiddleware.test.ts} | 31 ++-- ... PluginProtocolResolverFetchMiddleware.ts} | 26 ++- .../{FetchApiBuilder.ts => createFetchApi.ts} | 47 +++--- .../apis/implementations/FetchApi/index.ts | 7 +- .../apis/implementations/FetchApi/types.ts | 11 +- packages/core-plugin-api/api-report.md | 3 +- packages/core-plugin-api/package.json | 2 +- .../src/apis/definitions/FetchApi.ts | 1 - plugins/catalog/api-report.md | 2 +- plugins/catalog/src/CatalogClientWrapper.ts | 7 + plugins/catalog/src/plugin.ts | 16 +- 22 files changed, 444 insertions(+), 235 deletions(-) create mode 100644 .changeset/itchy-grapes-think.md create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/FetchMiddlewares.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.test.ts create mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.ts delete mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.test.ts delete mode 100644 packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.ts rename packages/core-app-api/src/apis/implementations/FetchApi/{BackstageProtocolResolverFetchMiddleware.test.ts => PluginProtocolResolverFetchMiddleware.test.ts} (69%) rename packages/core-app-api/src/apis/implementations/FetchApi/{BackstageProtocolResolverFetchMiddleware.ts => PluginProtocolResolverFetchMiddleware.ts} (75%) rename packages/core-app-api/src/apis/implementations/FetchApi/{FetchApiBuilder.ts => createFetchApi.ts} (54%) diff --git a/.changeset/itchy-grapes-think.md b/.changeset/itchy-grapes-think.md new file mode 100644 index 0000000000..c453b24922 --- /dev/null +++ b/.changeset/itchy-grapes-think.md @@ -0,0 +1,25 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Deprecated the `CatalogClientWrapper` class. + +The default implementation of `catalogApiRef` that this plugin exposes, is now powered by the new `fetchApiRef`. The default implementation of _that_ API, in turn, has the ability to inject the user's Backstage token in requests in a similar manner to what the deprecated `CatalogClientWrapper` used to do. The latter has therefore been taken out of the default catalog API implementation. + +If you use a custom `fetchApiRef` implementation that does NOT issue tokens, or use a custom `catalogApiRef` implementation which does NOT use the default `fetchApiRef`, you can still for some time wrap your catalog API in this class to get back the old behavior: + +```ts +// Add this to your packages/app/src/plugins.ts if you want to get back the old +// catalog client behavior: +createApiFactory({ + api: catalogApiRef, + deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef }, + factory: ({ discoveryApi, identityApi }) => + new CatalogClientWrapper({ + client: new CatalogClient({ discoveryApi }), + identityApi, + }), +}), +``` + +But do consider migrating to making use of the `fetchApiRef` as soon as convenient, since the wrapper class will be removed in a future release. diff --git a/packages/app-defaults/src/defaults/apis.ts b/packages/app-defaults/src/defaults/apis.ts index 06562caaef..29aa62bdab 100644 --- a/packages/app-defaults/src/defaults/apis.ts +++ b/packages/app-defaults/src/defaults/apis.ts @@ -34,9 +34,8 @@ import { OneLoginAuth, UnhandledErrorForwarder, AtlassianAuth, - FetchApiBuilder, - IdentityAwareFetchMiddleware, - BackstageProtocolResolverFetchMiddleware, + createFetchApi, + FetchMiddlewares, } from '@backstage/core-app-api'; import { @@ -99,20 +98,23 @@ export const apis = [ }), createApiFactory({ api: fetchApiRef, - deps: { identityApi: identityApiRef, discoveryApi: discoveryApiRef }, - factory: ({ identityApi, discoveryApi }) => { - return FetchApiBuilder.create() - .with( - new IdentityAwareFetchMiddleware(() => { - return identityApi.getCredentials().then(r => r.token); + deps: { + configApi: configApiRef, + identityApi: identityApiRef, + discoveryApi: discoveryApiRef, + }, + factory: ({ configApi, identityApi, discoveryApi }) => { + return createFetchApi({ + middleware: [ + FetchMiddlewares.resolvePluginProtocol({ + discoveryApi, }), - ) - .with( - new BackstageProtocolResolverFetchMiddleware(plugin => { - return discoveryApi.getBaseUrl(plugin); + FetchMiddlewares.injectIdentityAuth({ + identityApi, + config: configApi, }), - ) - .build(); + ], + }); }, }), createApiFactory({ diff --git a/packages/catalog-client/api-report.md b/packages/catalog-client/api-report.md index 41aea63716..495c98a104 100644 --- a/packages/catalog-client/api-report.md +++ b/packages/catalog-client/api-report.md @@ -5,7 +5,6 @@ ```ts import { Entity } from '@backstage/catalog-model'; import { EntityName } from '@backstage/catalog-model'; -import { default as fetch_2 } from 'cross-fetch'; import { Location as Location_2 } from '@backstage/catalog-model'; // @public @@ -159,6 +158,6 @@ export const ENTITY_STATUS_CATALOG_PROCESSING_TYPE = // @public export type FetchApi = { - fetch: typeof fetch_2; + fetch: typeof fetch; }; ``` diff --git a/packages/catalog-client/src/types/fetch.ts b/packages/catalog-client/src/types/fetch.ts index cdddd31810..59de6a68f1 100644 --- a/packages/catalog-client/src/types/fetch.ts +++ b/packages/catalog-client/src/types/fetch.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import fetch from 'cross-fetch'; - /** * This is a copy of FetchApi, to avoid importing core-plugin-api. * diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index 3277be7841..78bfd83251 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -24,9 +24,9 @@ import { BackstageIdentityApi } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; +import { Config } from '@backstage/config'; import { ConfigReader } from '@backstage/config'; import { createApp as createApp_2 } from '@backstage/app-defaults'; -import crossFetch from 'cross-fetch'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { ErrorApi } from '@backstage/core-plugin-api'; import { ErrorApiError } from '@backstage/core-plugin-api'; @@ -290,14 +290,6 @@ export type BackstagePluginWithAnyOutput = Omit< )[]; }; -// @public -export class BackstageProtocolResolverFetchMiddleware - implements FetchMiddleware -{ - constructor(discovery: (pluginId: string) => Promise); - apply(next: FetchFunction): FetchFunction; -} - // @public export class BitbucketAuth { // (undocumented) @@ -328,6 +320,12 @@ export function createApp( options?: Parameters[0], ): BackstageApp & AppContext; +// @public +export function createFetchApi(options: { + baseImplementation?: typeof fetch | undefined; + middleware?: FetchMiddleware | FetchMiddleware[] | undefined; +}): FetchApi; + // @public export function createSpecializedApp(options: AppOptions): BackstageApp; @@ -380,21 +378,24 @@ export type FeatureFlaggedProps = { ); // @public -export class FetchApiBuilder { - // (undocumented) - build(): FetchApi; - // (undocumented) - static create(): FetchApiBuilder; - // (undocumented) - with(middleware: FetchMiddleware): FetchApiBuilder; +export interface FetchMiddleware { + apply(next: typeof fetch): typeof fetch; } // @public -export type FetchFunction = typeof crossFetch; - -// @public -export interface FetchMiddleware { - apply(next: FetchFunction): FetchFunction; +export class FetchMiddlewares { + static injectIdentityAuth(options: { + identityApi: IdentityApi; + config?: Config; + urlPrefixAllowlist?: string[]; + header?: { + name: string; + value: (backstageToken: string) => string; + }; + }): FetchMiddleware; + static resolvePluginProtocol(options: { + discoveryApi: DiscoveryApi; + }): FetchMiddleware; } // @public @@ -454,13 +455,6 @@ export class GoogleAuth { static create(options: OAuthApiCreateOptions): typeof googleAuthApiRef.T; } -// @public -export class IdentityAwareFetchMiddleware implements FetchMiddleware { - constructor(tokenFunction: () => Promise); - apply(next: FetchFunction): FetchFunction; - setHeaderName(name: string): IdentityAwareFetchMiddleware; -} - // @public export class LocalStorageFeatureFlags implements FeatureFlagsApi { // (undocumented) diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index d138417143..23079d7ba0 100644 --- a/packages/core-app-api/package.json +++ b/packages/core-app-api/package.json @@ -39,7 +39,6 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@types/prop-types": "^15.7.3", - "cross-fetch": "^3.0.6", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", "react-use": "^17.2.4", diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/FetchMiddlewares.ts b/packages/core-app-api/src/apis/implementations/FetchApi/FetchMiddlewares.ts new file mode 100644 index 0000000000..1cf09ff20d --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/FetchMiddlewares.ts @@ -0,0 +1,76 @@ +/* + * 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 { Config } from '@backstage/config'; +import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api'; +import { IdentityAuthInjectorFetchMiddleware } from './IdentityAuthInjectorFetchMiddleware'; +import { PluginProtocolResolverFetchMiddleware } from './PluginProtocolResolverFetchMiddleware'; +import { FetchMiddleware } from './types'; + +/** + * A collection of common middlewares for the FetchApi. + * + * @public + */ +export class FetchMiddlewares { + /** + * Handles translation from `plugin://` URLs to concrete http(s) URLs based on + * the discovery API. + * + * @remarks + * + * If the request is for `plugin://catalog/entities?filter=x=y`, the discovery + * API will be queried for `'catalog'`. If it returned + * `https://backstage.example.net/api/catalog`, the resulting query would be + * `https://backstage.example.net/api/catalog/entities?filter=x=y`. + * + * If the incoming URL protocol was not `plugin`, the request is just passed + * through verbatim to the underlying implementation. + */ + static resolvePluginProtocol(options: { + discoveryApi: DiscoveryApi; + }): FetchMiddleware { + return new PluginProtocolResolverFetchMiddleware(options.discoveryApi); + } + + /** + * Injects a Backstage token header when the user is signed in. + * + * @remarks + * + * Per default, an `Authorization: Bearer ` is generated. This can be + * customized using the `header` option. + * + * The header injection only happens on allowlisted URLs. Per default, if the + * `config` option is passed in, the `backend.baseUrl` is allowlisted, unless + * the `urlPrefixAllowlist` option is passed in, in which case it takes + * precedence. If you pass in neither config nor an allowlist, the middleware + * will have no effect. + */ + static injectIdentityAuth(options: { + identityApi: IdentityApi; + config?: Config; + urlPrefixAllowlist?: string[]; + header?: { + name: string; + value: (backstageToken: string) => string; + }; + }): FetchMiddleware { + return IdentityAuthInjectorFetchMiddleware.create(options); + } + + private constructor() {} +} diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.test.ts b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.test.ts new file mode 100644 index 0000000000..b69a4b9f7a --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.test.ts @@ -0,0 +1,153 @@ +/* + * 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 { ConfigReader } from '@backstage/config'; +import { IdentityApi } from '@backstage/core-plugin-api'; +import { IdentityAuthInjectorFetchMiddleware } from './IdentityAuthInjectorFetchMiddleware'; + +describe('IdentityAuthInjectorFetchMiddleware', () => { + it('creates using defaults', async () => { + const middleware = IdentityAuthInjectorFetchMiddleware.create({ + identityApi: undefined as any, + }); + expect(middleware.urlPrefixAllowlist).toEqual([]); + expect(middleware.headerName).toEqual('authorization'); + expect(middleware.headerValue('t')).toEqual('Bearer t'); + }); + + it('creates using config', async () => { + const middleware = IdentityAuthInjectorFetchMiddleware.create({ + identityApi: undefined as any, + config: new ConfigReader({ + backend: { baseUrl: 'https://example.com/api' }, + }), + header: { name: 'auth', value: t => `${t}!` }, + }); + expect(middleware.urlPrefixAllowlist).toEqual(['https://example.com/api']); + expect(middleware.headerName).toEqual('auth'); + expect(middleware.headerValue('t')).toEqual('t!'); + }); + + it('creates using explicit allowlist', async () => { + const middleware = IdentityAuthInjectorFetchMiddleware.create({ + identityApi: undefined as any, + config: new ConfigReader({ + backend: { baseUrl: 'https://example.com/api' }, + }), + urlPrefixAllowlist: ['https://a.com', 'http://b.com:8080/'], + }); + expect(middleware.urlPrefixAllowlist).toEqual([ + 'https://a.com', + 'http://b.com:8080', + ]); + }); + + it('injects the header only when a token is available', async () => { + const tokenFunction = jest.fn(); + const identityApi = { + getCredentials: tokenFunction, + } as unknown as IdentityApi; + + const middleware = new IdentityAuthInjectorFetchMiddleware( + identityApi, + ['https://example.com'], + 'Authorization', + token => `Bearer ${token}`, + ); + const inner = jest.fn(); + const outer = middleware.apply(inner); + + // No token available + tokenFunction.mockResolvedValueOnce({ token: undefined }); + await outer(new Request('https://example.com')); + expect([...inner.mock.calls[0][0].headers.entries()]).toEqual([]); + + // Supply a token, header gets added + tokenFunction.mockResolvedValueOnce({ token: 'token' }); + await outer(new Request('https://example.com')); + expect([...inner.mock.calls[1][0].headers.entries()]).toEqual([ + ['authorization', 'Bearer token'], + ]); + + // Token no longer available + tokenFunction.mockResolvedValueOnce({ token: undefined }); + await outer(new Request('https://example.com')); + expect([...inner.mock.calls[2][0].headers.entries()]).toEqual([]); + }); + + it('does not overwrite an existing header with the same name', async () => { + const identityApi = { + getCredentials: () => ({ token: 'token' }), + } as unknown as IdentityApi; + + const middleware = new IdentityAuthInjectorFetchMiddleware( + identityApi, + ['https://example.com'], + 'Authorization', + token => `Bearer ${token}`, + ); + const inner = jest.fn(); + const outer = middleware.apply(inner); + + // No token available + await outer(new Request('https://example.com')); + expect([...inner.mock.calls[0][0].headers.entries()]).toEqual([ + ['authorization', 'Bearer token'], + ]); + + // Supply a token, header gets added + await outer( + new Request('https://example.com', { + headers: { authorization: 'do-not-clobber' }, + }), + ); + expect([...inner.mock.calls[1][0].headers.entries()]).toEqual([ + ['authorization', 'do-not-clobber'], + ]); + }); + + it('does not affect requests outside the allowlist', async () => { + const identityApi = { + getCredentials: () => ({ token: 'token' }), + } as unknown as IdentityApi; + + const middleware = new IdentityAuthInjectorFetchMiddleware( + identityApi, + ['https://example.com:8080/root'], + 'Authorization', + token => `Bearer ${token}`, + ); + + const inner = jest.fn(); + const outer = middleware.apply(inner); + + await outer(new Request('https://example.com:8080/root')); + await outer(new Request('https://example.com:8080/root/sub')); + await outer(new Request('https://example.com:8080/root2')); + await outer(new Request('https://example.com/root')); + await outer(new Request('http://example.com:8080/root')); + await outer(new Request('https://example.com/root')); + + const no: string[][] = []; + const yes: string[][] = [['authorization', 'Bearer token']]; + expect([...inner.mock.calls[0][0].headers.entries()]).toEqual(yes); + expect([...inner.mock.calls[1][0].headers.entries()]).toEqual(yes); + expect([...inner.mock.calls[2][0].headers.entries()]).toEqual(no); + expect([...inner.mock.calls[3][0].headers.entries()]).toEqual(no); + expect([...inner.mock.calls[4][0].headers.entries()]).toEqual(no); + expect([...inner.mock.calls[5][0].headers.entries()]).toEqual(no); + }); +}); diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.ts b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.ts new file mode 100644 index 0000000000..46ada0a505 --- /dev/null +++ b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAuthInjectorFetchMiddleware.ts @@ -0,0 +1,82 @@ +/* + * 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 { Config } from '@backstage/config'; +import { IdentityApi } from '@backstage/core-plugin-api'; +import { FetchMiddleware } from './types'; + +/** + * A fetch middleware, which injects a Backstage token header when the user is + * signed in. + */ +export class IdentityAuthInjectorFetchMiddleware implements FetchMiddleware { + static create(options: { + identityApi: IdentityApi; + config?: Config; + urlPrefixAllowlist?: string[]; + header?: { + name: string; + value: (backstageToken: string) => string; + }; + }): IdentityAuthInjectorFetchMiddleware { + const allowlist: string[] = []; + if (options.urlPrefixAllowlist) { + allowlist.push(...options.urlPrefixAllowlist); + } else if (options.config) { + allowlist.push(options.config.getString('backend.baseUrl')); + } + + const headerName = options.header?.name || 'authorization'; + const headerValue = options.header?.value || (token => `Bearer ${token}`); + + return new IdentityAuthInjectorFetchMiddleware( + options.identityApi, + allowlist.map(prefix => prefix.replace(/\/$/, '')), + headerName, + headerValue, + ); + } + + constructor( + public readonly identityApi: IdentityApi, + public readonly urlPrefixAllowlist: string[], + public readonly headerName: string, + public readonly headerValue: (pluginId: string) => string, + ) {} + + apply(next: typeof fetch): typeof fetch { + return async (input, init) => { + // Skip this middleware if the header already exists, or if the URL + // doesn't match any of the allowlist items, or if there was no token + const request = new Request(input, init); + const { token } = await this.identityApi.getCredentials(); + if ( + request.headers.get(this.headerName) || + !this.urlPrefixAllowlist.some( + prefix => + request.url === prefix || request.url.startsWith(`${prefix}/`), + ) || + typeof token !== 'string' || + !token + ) { + return next(input, init); + } + + request.headers.set(this.headerName, this.headerValue(token)); + return next(request); + }; + } +} diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.test.ts b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.test.ts deleted file mode 100644 index 381ebd62a9..0000000000 --- a/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 { IdentityAwareFetchMiddleware } from './IdentityAwareFetchMiddleware'; - -describe('IdentityAwareFetchMiddleware', () => { - it('injects the header only when a token is available', async () => { - const tokenFunction = jest.fn(); - const middleware = new IdentityAwareFetchMiddleware(tokenFunction); - const inner = jest.fn(); - const outer = middleware.apply(inner); - - // No token available - tokenFunction.mockResolvedValueOnce(undefined); - await outer(new Request('https://example.com')); - expect([...inner.mock.calls[0][0].headers.entries()]).toEqual([]); - - // Supply a token, header gets added - tokenFunction.mockResolvedValueOnce('token'); - await outer(new Request('https://example.com')); - expect([...inner.mock.calls[1][0].headers.entries()]).toEqual([ - ['backstage-token', 'token'], - ]); - - // Token no longer available - tokenFunction.mockResolvedValueOnce(undefined); - await outer(new Request('https://example.com')); - expect([...inner.mock.calls[2][0].headers.entries()]).toEqual([]); - }); -}); diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.ts b/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.ts deleted file mode 100644 index 474ca83894..0000000000 --- a/packages/core-app-api/src/apis/implementations/FetchApi/IdentityAwareFetchMiddleware.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 { FetchFunction, FetchMiddleware } from './types'; - -const DEFAULT_HEADER_NAME = 'backstage-token'; - -/** - * A fetch middleware, which injects a Backstage token header when the user is - * signed in. - * - * @public - */ -export class IdentityAwareFetchMiddleware implements FetchMiddleware { - private headerName: string; - private tokenFunction: () => Promise; - - constructor(tokenFunction: () => Promise) { - this.headerName = DEFAULT_HEADER_NAME; - this.tokenFunction = tokenFunction; - } - - /** - * {@inheritdoc FetchMiddleware.apply} - */ - apply(next: FetchFunction): FetchFunction { - return async (input, init) => { - const token = await this.tokenFunction(); - if (typeof token !== 'string') { - return next(input, init); - } - - const request = new Request(input, init); - request.headers.set(this.headerName, token); - return next(request); - }; - } - - /** - * Changes the header name from the default value to a custom one. - */ - setHeaderName(name: string): IdentityAwareFetchMiddleware { - this.headerName = name; - return this; - } -} diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.test.ts b/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.test.ts similarity index 69% rename from packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.test.ts rename to packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.test.ts index 7dcb90573b..2f4ec6b536 100644 --- a/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.test.ts +++ b/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.test.ts @@ -14,14 +14,18 @@ * limitations under the License. */ -import { BackstageProtocolResolverFetchMiddleware } from './BackstageProtocolResolverFetchMiddleware'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { PluginProtocolResolverFetchMiddleware } from './PluginProtocolResolverFetchMiddleware'; -describe('BackstageProtocolResolverFetchMiddleware', () => { +describe('PluginProtocolResolverFetchMiddleware', () => { it.each([['https://passthrough.com/a']])( 'passes through regular URLs, %p', - async (url: string) => { + async url => { const resolve = jest.fn(); - const middleware = new BackstageProtocolResolverFetchMiddleware(resolve); + const discoveryApi = { getBaseUrl: resolve } as unknown as DiscoveryApi; + const middleware = new PluginProtocolResolverFetchMiddleware( + discoveryApi, + ); const inner = jest.fn(); const outer = middleware.apply(inner); @@ -33,38 +37,38 @@ describe('BackstageProtocolResolverFetchMiddleware', () => { it.each([ [ - 'backstage://my-plugin/sub/path', + 'plugin://my-plugin/sub/path', 'my-plugin', 'https://real.com/base', 'https://real.com/base/sub/path', ], [ - 'backstage://my-plugin/sub/path/', + 'plugin://my-plugin/sub/path/', 'my-plugin', 'https://real.com/base/', 'https://real.com/base/sub/path/', ], - ['backstage://x', 'x', 'http://real.com:8080', 'http://real.com:8080'], + ['plugin://x', 'x', 'http://real.com:8080', 'http://real.com:8080'], [ - 'backstage://x/a/b?c=d&e=f#g', + 'plugin://x/a/b?c=d&e=f#g', 'x', 'https://real.com/base', 'https://real.com/base/a/b?c=d&e=f#g', ], [ - 'backstage://x?c=d&e=f#g', + 'plugin://x?c=d&e=f#g', 'x', 'https://real.com:8080/base', 'https://real.com:8080/base?c=d&e=f#g', ], [ - 'backstage://username:password@x?c=d&e=f#g', + 'plugin://username:password@x?c=d&e=f#g', 'x', 'https://real.com:8080/base', 'https://username:password@real.com:8080/base?c=d&e=f#g', ], [ - 'backstage://x?c=d&e=f#g', + 'plugin://x?c=d&e=f#g', 'x', 'https://username:password@real.com:8080/base', 'https://username:password@real.com:8080/base?c=d&e=f#g', @@ -73,7 +77,10 @@ describe('BackstageProtocolResolverFetchMiddleware', () => { 'resolves backstage URLs, %p', async (original, host, resolved, result) => { const resolve = jest.fn(); - const middleware = new BackstageProtocolResolverFetchMiddleware(resolve); + const discoveryApi = { getBaseUrl: resolve } as unknown as DiscoveryApi; + const middleware = new PluginProtocolResolverFetchMiddleware( + discoveryApi, + ); const inner = jest.fn(); const outer = middleware.apply(inner); diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts b/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.ts similarity index 75% rename from packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts rename to packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.ts index 2144d0058d..72834731fe 100644 --- a/packages/core-app-api/src/apis/implementations/FetchApi/BackstageProtocolResolverFetchMiddleware.ts +++ b/packages/core-app-api/src/apis/implementations/FetchApi/PluginProtocolResolverFetchMiddleware.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { FetchFunction, FetchMiddleware } from './types'; +import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { FetchMiddleware } from './types'; function join(left: string, right: string): string { if (!right || right === '/') { @@ -25,25 +26,16 @@ function join(left: string, right: string): string { } /** - * Handles translation from backstage://some-plugin-id/ to concrete - * http(s) URLs. - * - * @public + * Handles translation from plugin://some-plugin-id/ to concrete http(s) + * URLs. */ -export class BackstageProtocolResolverFetchMiddleware - implements FetchMiddleware -{ - constructor( - private readonly discovery: (pluginId: string) => Promise, - ) {} +export class PluginProtocolResolverFetchMiddleware implements FetchMiddleware { + constructor(private readonly discoveryApi: DiscoveryApi) {} - /** - * {@inheritdoc FetchMiddleware.apply} - */ - apply(next: FetchFunction): FetchFunction { + apply(next: typeof fetch): typeof fetch { return async (input, init) => { const request = new Request(input, init); - const prefix = 'backstage://'; + const prefix = 'plugin://'; if (!request.url.startsWith(prefix)) { return next(input, init); @@ -55,7 +47,7 @@ export class BackstageProtocolResolverFetchMiddleware `http://${request.url.substring(prefix.length)}`, ); - let base = await this.discovery(hostname); + let base = await this.discoveryApi.getBaseUrl(hostname); if (username || password) { const baseUrl = new URL(base); const authority = `${username}${password ? `:${password}` : ''}@`; diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/FetchApiBuilder.ts b/packages/core-app-api/src/apis/implementations/FetchApi/createFetchApi.ts similarity index 54% rename from packages/core-app-api/src/apis/implementations/FetchApi/FetchApiBuilder.ts rename to packages/core-app-api/src/apis/implementations/FetchApi/createFetchApi.ts index 1c96eb1ad6..1b85695daa 100644 --- a/packages/core-app-api/src/apis/implementations/FetchApi/FetchApiBuilder.ts +++ b/packages/core-app-api/src/apis/implementations/FetchApi/createFetchApi.ts @@ -15,41 +15,32 @@ */ import { FetchApi } from '@backstage/core-plugin-api'; -import crossFetch from 'cross-fetch'; -import { FetchFunction, FetchMiddleware } from './types'; +import { FetchMiddleware } from './types'; /** * Builds a fetch API, based on the builtin fetch wrapped by a set of optional * middleware implementations that add behaviors. * + * @remarks + * + * The middleware are applied in reverse order, i.e. the last one will be + * "closest" to the base implementation. Passing in `[M1, M2, M3]` effectively + * leads to `M1(M2(M3(baseImplementation)))`. + * * @public */ -export class FetchApiBuilder { - static create(): FetchApiBuilder { - return new FetchApiBuilder(crossFetch, []); +export function createFetchApi(options: { + baseImplementation?: typeof fetch | undefined; + middleware?: FetchMiddleware | FetchMiddleware[] | undefined; +}): FetchApi { + let result = options.baseImplementation || global.fetch; + + const middleware = [options.middleware ?? []].flat().reverse(); + for (const m of middleware) { + result = m.apply(result); } - private constructor( - private readonly implementation: FetchFunction, - private readonly middleware: FetchMiddleware[], - ) {} - - with(middleware: FetchMiddleware): FetchApiBuilder { - return new FetchApiBuilder(this.implementation, [ - ...this.middleware, - middleware, - ]); - } - - build(): FetchApi { - let result = this.implementation; - - for (const m of this.middleware) { - result = m.apply(result); - } - - return { - fetch: result, - }; - } + return { + fetch: result, + }; } diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/index.ts b/packages/core-app-api/src/apis/implementations/FetchApi/index.ts index 7544bd8bf2..0f82a9020b 100644 --- a/packages/core-app-api/src/apis/implementations/FetchApi/index.ts +++ b/packages/core-app-api/src/apis/implementations/FetchApi/index.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -export { BackstageProtocolResolverFetchMiddleware } from './BackstageProtocolResolverFetchMiddleware'; -export { FetchApiBuilder } from './FetchApiBuilder'; -export { IdentityAwareFetchMiddleware } from './IdentityAwareFetchMiddleware'; -export type { FetchFunction, FetchMiddleware } from './types'; +export { createFetchApi } from './createFetchApi'; +export { FetchMiddlewares } from './FetchMiddlewares'; +export type { FetchMiddleware } from './types'; diff --git a/packages/core-app-api/src/apis/implementations/FetchApi/types.ts b/packages/core-app-api/src/apis/implementations/FetchApi/types.ts index 4cf0bf47f4..5bf029cbf0 100644 --- a/packages/core-app-api/src/apis/implementations/FetchApi/types.ts +++ b/packages/core-app-api/src/apis/implementations/FetchApi/types.ts @@ -14,15 +14,6 @@ * limitations under the License. */ -import crossFetch from 'cross-fetch'; - -/** - * The type of a fetch call. - * - * @public - */ -export type FetchFunction = typeof crossFetch; - /** * A middleware that modifies the behavior of an ongoing fetch. * @@ -35,5 +26,5 @@ export interface FetchMiddleware { * @param next - The next, inner, implementation, that this middleware shall * call out to as part of the request cycle. */ - apply(next: FetchFunction): FetchFunction; + apply(next: typeof fetch): typeof fetch; } diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 148115fd69..67c10837ac 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -9,7 +9,6 @@ import { BackstagePlugin as BackstagePlugin_2 } from '@backstage/core-plugin-api import { BackstageTheme } from '@backstage/theme'; import { ComponentType } from 'react'; import { Config } from '@backstage/config'; -import { default as fetch_2 } from 'cross-fetch'; import { IconComponent as IconComponent_2 } from '@backstage/core-plugin-api'; import { IdentityApi as IdentityApi_2 } from '@backstage/core-plugin-api'; import { Observable as Observable_2 } from '@backstage/types'; @@ -508,7 +507,7 @@ export enum FeatureFlagState { // @public export type FetchApi = { - fetch: typeof fetch_2; + fetch: typeof fetch; }; // @public diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 365cec3134..72827bde73 100644 --- a/packages/core-plugin-api/package.json +++ b/packages/core-plugin-api/package.json @@ -34,7 +34,6 @@ "@backstage/types": "^0.1.1", "@backstage/version-bridge": "^0.1.1", "@material-ui/core": "^4.12.2", - "cross-fetch": "^3.0.6", "history": "^5.0.0", "prop-types": "^15.7.2", "react-router-dom": "6.0.0-beta.0", @@ -57,6 +56,7 @@ "@types/node": "^14.14.32", "@types/prop-types": "^15.7.3", "@types/zen-observable": "^0.8.0", + "cross-fetch": "^3.0.6", "msw": "^0.35.0" }, "files": [ diff --git a/packages/core-plugin-api/src/apis/definitions/FetchApi.ts b/packages/core-plugin-api/src/apis/definitions/FetchApi.ts index 30eb950634..ba304157ea 100644 --- a/packages/core-plugin-api/src/apis/definitions/FetchApi.ts +++ b/packages/core-plugin-api/src/apis/definitions/FetchApi.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import fetch from 'cross-fetch'; import { ApiRef, createApiRef } from '../system'; /** diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index 2be7fc8575..80271c89af 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -66,7 +66,7 @@ export type BackstageOverrides = Overrides & { // Warning: (ae-missing-release-tag) "CatalogClientWrapper" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public +// @public @deprecated export class CatalogClientWrapper implements CatalogApi { constructor(options: { client: CatalogClient; identityApi: IdentityApi }); // (undocumented) diff --git a/plugins/catalog/src/CatalogClientWrapper.ts b/plugins/catalog/src/CatalogClientWrapper.ts index 0463cbf30e..c5f072e96c 100644 --- a/plugins/catalog/src/CatalogClientWrapper.ts +++ b/plugins/catalog/src/CatalogClientWrapper.ts @@ -30,6 +30,13 @@ import { IdentityApi } from '@backstage/core-plugin-api'; /** * CatalogClient wrapper that injects identity token for all requests + * + * @deprecated The default catalog client now uses the `fetchApiRef` + * implementation, which in turn by default issues tokens just the same as this + * class used to assist in doing. If you use a custom `fetchApiRef` + * implementation that does NOT issue tokens, or use a custom `catalogApiRef` + * implementation which does not use the default `fetchApiRef`, you can wrap + * your catalog API in this class to get back the old behavior. */ export class CatalogClientWrapper implements CatalogApi { private readonly identityApi: IdentityApi; diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 20f937b2e7..66fdf4638f 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -22,7 +22,6 @@ import { entityRouteRef, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; -import { CatalogClientWrapper } from './CatalogClientWrapper'; import { createComponentRouteRef, viewTechDocRouteRef } from './routes'; import { createApiFactory, @@ -30,7 +29,7 @@ import { createPlugin, createRoutableExtension, discoveryApiRef, - identityApiRef, + fetchApiRef, storageApiRef, } from '@backstage/core-plugin-api'; @@ -39,14 +38,13 @@ export const catalogPlugin = createPlugin({ apis: [ createApiFactory({ api: catalogApiRef, - deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef }, - factory: ({ discoveryApi, identityApi }) => - new CatalogClientWrapper({ - client: new CatalogClient({ discoveryApi }), - identityApi, - }), + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ discoveryApi, fetchApi }) => + new CatalogClient({ discoveryApi, fetchApi }), }), - createApiFactory({ api: starredEntitiesApiRef, deps: { storageApi: storageApiRef }, From 6e5f6621876f4c20c040f73aeba702ea16cdcaa9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Dec 2021 04:20:04 +0000 Subject: [PATCH 165/189] build(deps): bump mock-fs from 5.1.0 to 5.1.2 Bumps [mock-fs](https://github.com/tschaub/mock-fs) from 5.1.0 to 5.1.2. - [Release notes](https://github.com/tschaub/mock-fs/releases) - [Changelog](https://github.com/tschaub/mock-fs/blob/main/changelog.md) - [Commits](https://github.com/tschaub/mock-fs/compare/v5.1.0...v5.1.2) --- updated-dependencies: - dependency-name: mock-fs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- yarn.lock | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index d6b47335ef..cca08863df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21282,12 +21282,7 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mock-fs@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/mock-fs/-/mock-fs-5.1.0.tgz#a9aebd4e6d74a626f84b86eae8a372bd061754e8" - integrity sha512-wXdQ2nIk81TYIGLphUnbXl8akQpjb9ItfZefMcTxZcoe+djMkd5POU8fQdSEErxVAeT4CgDHWveYquys4H6Cmw== - -mock-fs@^5.1.1: +mock-fs@^5.1.0, mock-fs@^5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/mock-fs/-/mock-fs-5.1.2.tgz#6fa486e06d00f8793a8d2228de980eff93ce6db7" integrity sha512-YkjQkdLulFrz0vD4BfNQdQRVmgycXTV7ykuHMlyv+C8WCHazpkiQRDthwa02kSyo8wKnY9wRptHfQLgmf0eR+A== From ef6a039e074f656f9671dbd50100f644f6dcae2e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 Dec 2021 08:56:38 +0000 Subject: [PATCH 166/189] Version Packages --- ...w-client-method-to-elastic-search-egine.md | 6 -- .changeset/beige-mangos-knock.md | 5 -- .changeset/beige-news-cover.md | 5 -- .changeset/cold-dolls-beam.md | 5 -- .changeset/cool-cows-report.md | 5 -- .changeset/eight-insects-kiss.md | 5 -- .changeset/five-cats-hunt.md | 5 -- .changeset/mighty-llamas-hope.md | 5 -- .changeset/nervous-hounds-attend.md | 5 -- .changeset/nice-seahorses-look.md | 5 -- .changeset/org-ownershipcard-filteradded.md | 5 -- .changeset/pink-ladybugs-share.md | 6 -- .changeset/shaggy-bears-remember.md | 6 -- .changeset/silly-dryers-smile.md | 58 ----------------- .changeset/spicy-parents-fold.md | 13 ---- .changeset/strong-doors-destroy.md | 5 -- .changeset/strong-paws-laugh.md | 5 -- .changeset/stupid-mice-dream.md | 5 -- .changeset/sweet-camels-learn.md | 5 -- .changeset/techdocs-forty-pumas-compete.md | 5 -- .changeset/thirty-ways-attend.md | 5 -- .changeset/weak-berries-heal.md | 14 ---- .changeset/young-students-applaud.md | 11 ---- packages/app/CHANGELOG.md | 18 ++++++ packages/app/package.json | 26 ++++---- packages/backend-common/CHANGELOG.md | 7 ++ packages/backend-common/package.json | 4 +- packages/backend/CHANGELOG.md | 14 ++++ packages/backend/package.json | 20 +++--- packages/catalog-model/CHANGELOG.md | 6 ++ packages/catalog-model/package.json | 4 +- packages/cli/CHANGELOG.md | 6 ++ packages/cli/package.json | 10 +-- packages/codemods/CHANGELOG.md | 9 +++ packages/codemods/package.json | 2 +- packages/core-app-api/CHANGELOG.md | 10 +++ packages/core-app-api/package.json | 8 +-- packages/core-components/CHANGELOG.md | 10 +++ packages/core-components/package.json | 8 +-- packages/core-plugin-api/CHANGELOG.md | 14 ++++ packages/core-plugin-api/package.json | 6 +- packages/create-app/CHANGELOG.md | 14 ++++ packages/create-app/package.json | 2 +- plugins/allure/package.json | 8 +-- plugins/analytics-module-ga/package.json | 8 +-- plugins/apache-airflow/CHANGELOG.md | 22 +++++++ plugins/apache-airflow/package.json | 10 +-- plugins/api-docs/package.json | 8 +-- plugins/auth-backend/CHANGELOG.md | 9 +++ plugins/auth-backend/package.json | 8 +-- plugins/azure-devops-backend/CHANGELOG.md | 61 ++++++++++++++++++ plugins/azure-devops-backend/package.json | 8 +-- plugins/azure-devops-common/CHANGELOG.md | 57 +++++++++++++++++ plugins/azure-devops-common/package.json | 4 +- plugins/azure-devops/CHANGELOG.md | 64 +++++++++++++++++++ plugins/azure-devops/package.json | 16 ++--- plugins/badges/package.json | 8 +-- plugins/bazaar/package.json | 6 +- plugins/bitrise/package.json | 8 +-- plugins/catalog-backend/CHANGELOG.md | 9 +++ plugins/catalog-backend/package.json | 8 +-- plugins/catalog-graph/package.json | 8 +-- plugins/catalog-import/package.json | 8 +-- plugins/catalog-react/CHANGELOG.md | 10 +++ plugins/catalog-react/package.json | 12 ++-- plugins/catalog/package.json | 8 +-- plugins/circleci/package.json | 8 +-- plugins/cloudbuild/package.json | 8 +-- plugins/code-coverage/package.json | 8 +-- plugins/config-schema/package.json | 8 +-- plugins/cost-insights/package.json | 8 +-- plugins/explore/package.json | 8 +-- plugins/firehydrant/package.json | 8 +-- plugins/fossa/package.json | 8 +-- plugins/gcp-projects/package.json | 8 +-- plugins/git-release-manager/package.json | 8 +-- plugins/github-actions/CHANGELOG.md | 11 ++++ plugins/github-actions/package.json | 14 ++-- plugins/github-deployments/package.json | 8 +-- plugins/gitops-profiles/package.json | 8 +-- plugins/graphiql/package.json | 8 +-- plugins/home/package.json | 8 +-- plugins/ilert/package.json | 8 +-- plugins/jenkins/package.json | 8 +-- plugins/kafka/package.json | 8 +-- plugins/kubernetes/CHANGELOG.md | 11 ++++ plugins/kubernetes/package.json | 14 ++-- plugins/lighthouse/package.json | 8 +-- plugins/newrelic/package.json | 8 +-- plugins/org/CHANGELOG.md | 11 ++++ plugins/org/package.json | 14 ++-- plugins/pagerduty/package.json | 8 +-- plugins/rollbar/package.json | 8 +-- plugins/scaffolder-backend/CHANGELOG.md | 11 ++++ plugins/scaffolder-backend/package.json | 10 +-- plugins/scaffolder/package.json | 10 +-- .../CHANGELOG.md | 7 ++ .../package.json | 6 +- plugins/search/package.json | 8 +-- plugins/sentry/package.json | 8 +-- plugins/shortcuts/package.json | 8 +-- plugins/sonarqube/package.json | 8 +-- plugins/splunk-on-call/package.json | 8 +-- plugins/tech-insights/package.json | 24 +++---- plugins/tech-radar/package.json | 8 +-- plugins/techdocs/CHANGELOG.md | 11 ++++ plugins/techdocs/package.json | 14 ++-- plugins/todo/package.json | 8 +-- plugins/user-settings/package.json | 8 +-- plugins/xcmetrics/package.json | 8 +-- 110 files changed, 688 insertions(+), 480 deletions(-) delete mode 100644 .changeset/add-new-client-method-to-elastic-search-egine.md delete mode 100644 .changeset/beige-mangos-knock.md delete mode 100644 .changeset/beige-news-cover.md delete mode 100644 .changeset/cold-dolls-beam.md delete mode 100644 .changeset/cool-cows-report.md delete mode 100644 .changeset/eight-insects-kiss.md delete mode 100644 .changeset/five-cats-hunt.md delete mode 100644 .changeset/mighty-llamas-hope.md delete mode 100644 .changeset/nervous-hounds-attend.md delete mode 100644 .changeset/nice-seahorses-look.md delete mode 100644 .changeset/org-ownershipcard-filteradded.md delete mode 100644 .changeset/pink-ladybugs-share.md delete mode 100644 .changeset/shaggy-bears-remember.md delete mode 100644 .changeset/silly-dryers-smile.md delete mode 100644 .changeset/spicy-parents-fold.md delete mode 100644 .changeset/strong-doors-destroy.md delete mode 100644 .changeset/strong-paws-laugh.md delete mode 100644 .changeset/stupid-mice-dream.md delete mode 100644 .changeset/sweet-camels-learn.md delete mode 100644 .changeset/techdocs-forty-pumas-compete.md delete mode 100644 .changeset/thirty-ways-attend.md delete mode 100644 .changeset/weak-berries-heal.md delete mode 100644 .changeset/young-students-applaud.md create mode 100644 plugins/apache-airflow/CHANGELOG.md diff --git a/.changeset/add-new-client-method-to-elastic-search-egine.md b/.changeset/add-new-client-method-to-elastic-search-egine.md deleted file mode 100644 index 9e5c363522..0000000000 --- a/.changeset/add-new-client-method-to-elastic-search-egine.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-elasticsearch': patch ---- - -Add `newClient()` method to re-use the configuration of the elastic search -engine with custom clients diff --git a/.changeset/beige-mangos-knock.md b/.changeset/beige-mangos-knock.md deleted file mode 100644 index d8723c3f87..0000000000 --- a/.changeset/beige-mangos-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-github-actions': patch ---- - -Show empty state only when workflow API call has completed diff --git a/.changeset/beige-news-cover.md b/.changeset/beige-news-cover.md deleted file mode 100644 index 70cebcd76f..0000000000 --- a/.changeset/beige-news-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-app-api': patch ---- - -Deprecated `Auth0Auth`, pointing to using `OAuth2` directly instead. diff --git a/.changeset/cold-dolls-beam.md b/.changeset/cold-dolls-beam.md deleted file mode 100644 index 5257cd5553..0000000000 --- a/.changeset/cold-dolls-beam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes': patch ---- - -Fixed styling bug for the CronJobsAccordions and updated Completed pods to display a green dot. diff --git a/.changeset/cool-cows-report.md b/.changeset/cool-cows-report.md deleted file mode 100644 index 2b183e39c2..0000000000 --- a/.changeset/cool-cows-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': patch ---- - -Deprecated the `AnyAnalyticsContext` type and mark the `AnalyticsApi` experimental. diff --git a/.changeset/eight-insects-kiss.md b/.changeset/eight-insects-kiss.md deleted file mode 100644 index 4b09829bf3..0000000000 --- a/.changeset/eight-insects-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Items in `` are now only active when their full path is active (including search parameters). diff --git a/.changeset/five-cats-hunt.md b/.changeset/five-cats-hunt.md deleted file mode 100644 index cf3364a23a..0000000000 --- a/.changeset/five-cats-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Fixed the handling of optional locations so that the catalog no longer logs `NotFoundError`s for missing optional locations. diff --git a/.changeset/mighty-llamas-hope.md b/.changeset/mighty-llamas-hope.md deleted file mode 100644 index 7ea87e50d0..0000000000 --- a/.changeset/mighty-llamas-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Makes cookiecutter a default, but optional action based on if a containerRunner argument is passed in to createRouter or createBuiltinActions diff --git a/.changeset/nervous-hounds-attend.md b/.changeset/nervous-hounds-attend.md deleted file mode 100644 index b54eb5a688..0000000000 --- a/.changeset/nervous-hounds-attend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Adding changes to create GitLab Merge Request using custom action diff --git a/.changeset/nice-seahorses-look.md b/.changeset/nice-seahorses-look.md deleted file mode 100644 index 9652898c54..0000000000 --- a/.changeset/nice-seahorses-look.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-plugin-api': patch ---- - -Deprecated `auth0AuthApiRef`, `oauth2ApiRef`, `oidcAuthApiRef`, `samlAuthApiRef`, and marked the rest of the auth `ApiRef`s as experimental. For more information on how to address the deprecations, see https://backstage.io/docs/api/deprecations#generic-auth-api-refs. diff --git a/.changeset/org-ownershipcard-filteradded.md b/.changeset/org-ownershipcard-filteradded.md deleted file mode 100644 index cbd1475bb1..0000000000 --- a/.changeset/org-ownershipcard-filteradded.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-org': patch ---- - -Added `entityFilterKind` property for `EntityOwnershipCard` diff --git a/.changeset/pink-ladybugs-share.md b/.changeset/pink-ladybugs-share.md deleted file mode 100644 index 83f5b8b78a..0000000000 --- a/.changeset/pink-ladybugs-share.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-common': patch ---- - -Each plugin now saves to a separate sqlite database file when `connection.filename` is provided in the sqlite config. -Any existing sqlite database files will be ignored. diff --git a/.changeset/shaggy-bears-remember.md b/.changeset/shaggy-bears-remember.md deleted file mode 100644 index d041abb3d1..0000000000 --- a/.changeset/shaggy-bears-remember.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/core-app-api': patch -'@backstage/core-components': patch ---- - -Switched out usage of deprecated `OAuthRequestApi` types from `@backstage/core-plugin-api`. diff --git a/.changeset/silly-dryers-smile.md b/.changeset/silly-dryers-smile.md deleted file mode 100644 index 7337651532..0000000000 --- a/.changeset/silly-dryers-smile.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -'@backstage/plugin-azure-devops': patch -'@backstage/plugin-azure-devops-backend': patch -'@backstage/plugin-azure-devops-common': patch ---- - -Created some initial filters that can be used to create pull request columns: - -- All -- AssignedToUser -- AssignedToCurrentUser -- AssignedToTeam -- AssignedToTeams -- AssignedToCurrentUsersTeams -- CreatedByUser -- CreatedByCurrentUser -- CreatedByTeam -- CreatedByTeams -- CreatedByCurrentUsersTeams - -Example custom column creation: - -```tsx -const COLUMN_CONFIGS: PullRequestColumnConfig[] = [ - { - title: 'Created by me', - filters: [{ type: FilterType.CreatedByCurrentUser }], - }, - { - title: 'Created by Backstage Core', - filters: [ - { - type: FilterType.CreatedByTeam, - teamName: 'Backstage Core', - }, - ], - }, - { - title: 'Assigned to my teams', - filters: [{ type: FilterType.AssignedToCurrentUsersTeams }], - }, - { - title: 'Other PRs', - filters: [{ type: FilterType.All }], - simplified: true, - }, -]; - - - } -/>; -``` diff --git a/.changeset/spicy-parents-fold.md b/.changeset/spicy-parents-fold.md deleted file mode 100644 index 1ba056c7c8..0000000000 --- a/.changeset/spicy-parents-fold.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Updated the root `package.json` to include files with `.cjs` and `.mjs` extensions in the `"lint-staged"` configuration. - -To make this change to an existing app, apply the following changes to the `package.json` file: - -```diff - "lint-staged": { -- "*.{js,jsx,ts,tsx}": [ -+ "*.{js,jsx,ts,tsx,mjs,cjs}": [ -``` diff --git a/.changeset/strong-doors-destroy.md b/.changeset/strong-doors-destroy.md deleted file mode 100644 index d568ed4e07..0000000000 --- a/.changeset/strong-doors-destroy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Add support for `.cjs` and `.mjs` extensions in local and dependency modules. diff --git a/.changeset/strong-paws-laugh.md b/.changeset/strong-paws-laugh.md deleted file mode 100644 index de39440e34..0000000000 --- a/.changeset/strong-paws-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend': patch ---- - -export minimal typescript types for OIDC provider diff --git a/.changeset/stupid-mice-dream.md b/.changeset/stupid-mice-dream.md deleted file mode 100644 index 2cd2b4e067..0000000000 --- a/.changeset/stupid-mice-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Add Missing Override Components Type for SidebarSpace, SidebarSpacer, and SidebarDivider Components. diff --git a/.changeset/sweet-camels-learn.md b/.changeset/sweet-camels-learn.md deleted file mode 100644 index 60481b9363..0000000000 --- a/.changeset/sweet-camels-learn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-model': patch ---- - -Added an optional `presence` field to Location spec, which describes whether the target of a location is required to exist or not. It defaults to `'required'`, which is the current behaviour of the catalog. diff --git a/.changeset/techdocs-forty-pumas-compete.md b/.changeset/techdocs-forty-pumas-compete.md deleted file mode 100644 index 929ce3e2c9..0000000000 --- a/.changeset/techdocs-forty-pumas-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fix issue where assets weren't being fetched from the correct URL path for doc URLs without trailing slashes diff --git a/.changeset/thirty-ways-attend.md b/.changeset/thirty-ways-attend.md deleted file mode 100644 index b294b4bfb0..0000000000 --- a/.changeset/thirty-ways-attend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -`useEntityTypeFilter`: Skip updating selected types if a kind filter change did not change them. diff --git a/.changeset/weak-berries-heal.md b/.changeset/weak-berries-heal.md deleted file mode 100644 index 4160d078fc..0000000000 --- a/.changeset/weak-berries-heal.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/plugin-apache-airflow': minor ---- - -Introduces a new plugin for the Apache Airflow workflow management platform. -This implementation has been tested with the Apache Airflow v2 API, -authenticating with basic authentication through the Backstage proxy plugin. - -Supported functionality includes: - -- Information card of version information of the Airflow instance -- Information card of instance health for the meta-database and scheduler -- Table of DAGs with meta information and status, along with a link to view - details in the Airflow UI diff --git a/.changeset/young-students-applaud.md b/.changeset/young-students-applaud.md deleted file mode 100644 index bbd825cf00..0000000000 --- a/.changeset/young-students-applaud.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@backstage/core-plugin-api': patch ---- - -Renamed `AuthProvider` to `AuthProviderInfo` and add a required 'id' property to match the majority of usage. The `AuthProvider` type without the `id` property still exists but is deprecated, and all usage of it without an `id` is deprecated as well. For example, calling `createAuthRequest` without a `provider.id` is deprecated and it will be required in the future. - -The following types have been renamed. The old names are still exported but deprecated, and are scheduled for removal in a future release. - -- Renamed `AuthRequesterOptions` to `OAuthRequesterOptions` -- Renamed `AuthRequester` to `OAuthRequester` -- Renamed `PendingAuthRequest` to `PendingOAuthRequest` diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 3f3ac75853..d1055a54bf 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,23 @@ # example-app +## 0.2.57 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-github-actions@0.4.27 + - @backstage/core-app-api@0.2.1 + - @backstage/plugin-kubernetes@0.5.1 + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + - @backstage/plugin-org@0.3.31 + - @backstage/plugin-azure-devops@0.1.7 + - @backstage/cli@0.10.2 + - @backstage/catalog-model@0.9.8 + - @backstage/plugin-techdocs@0.12.10 + - @backstage/plugin-catalog-react@0.6.7 + - @backstage/plugin-apache-airflow@0.1.0 + ## 0.2.56 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 99b90952e3..a9e8e8ddc8 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,39 +1,39 @@ { "name": "example-app", - "version": "0.2.56", + "version": "0.2.57", "private": true, "bundled": true, "dependencies": { "@backstage/app-defaults": "^0.1.2", - "@backstage/catalog-model": "^0.9.7", - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/catalog-model": "^0.9.8", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/integration-react": "^0.1.15", "@backstage/plugin-api-docs": "^0.6.18", - "@backstage/plugin-azure-devops": "^0.1.6", - "@backstage/plugin-apache-airflow": "^0.0.0", + "@backstage/plugin-azure-devops": "^0.1.7", + "@backstage/plugin-apache-airflow": "^0.1.0", "@backstage/plugin-badges": "^0.2.16", "@backstage/plugin-catalog": "^0.7.4", "@backstage/plugin-catalog-graph": "^0.2.3", "@backstage/plugin-catalog-import": "^0.7.5", - "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-catalog-react": "^0.6.7", "@backstage/plugin-circleci": "^0.2.31", "@backstage/plugin-cloudbuild": "^0.2.29", "@backstage/plugin-code-coverage": "^0.1.19", "@backstage/plugin-cost-insights": "^0.11.13", "@backstage/plugin-explore": "^0.3.22", "@backstage/plugin-gcp-projects": "^0.3.10", - "@backstage/plugin-github-actions": "^0.4.26", + "@backstage/plugin-github-actions": "^0.4.27", "@backstage/plugin-graphiql": "^0.2.24", "@backstage/plugin-home": "^0.4.7", "@backstage/plugin-jenkins": "^0.5.14", "@backstage/plugin-kafka": "^0.2.22", - "@backstage/plugin-kubernetes": "^0.5.0", + "@backstage/plugin-kubernetes": "^0.5.1", "@backstage/plugin-lighthouse": "^0.2.31", "@backstage/plugin-newrelic": "^0.3.10", - "@backstage/plugin-org": "^0.3.30", + "@backstage/plugin-org": "^0.3.31", "@backstage/plugin-pagerduty": "0.3.19", "@backstage/plugin-rollbar": "^0.3.20", "@backstage/plugin-scaffolder": "^0.11.14", @@ -41,7 +41,7 @@ "@backstage/plugin-sentry": "^0.3.30", "@backstage/plugin-shortcuts": "^0.1.15", "@backstage/plugin-tech-radar": "^0.4.13", - "@backstage/plugin-techdocs": "^0.12.9", + "@backstage/plugin-techdocs": "^0.12.10", "@backstage/plugin-todo": "^0.1.16", "@backstage/plugin-user-settings": "^0.3.13", "@backstage/search-common": "^0.2.0", diff --git a/packages/backend-common/CHANGELOG.md b/packages/backend-common/CHANGELOG.md index ad3fb33365..4bd21df721 100644 --- a/packages/backend-common/CHANGELOG.md +++ b/packages/backend-common/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/backend-common +## 0.9.14 + +### Patch Changes + +- fe24bc9a32: Each plugin now saves to a separate sqlite database file when `connection.filename` is provided in the sqlite config. + Any existing sqlite database files will be ignored. + ## 0.9.13 ### Patch Changes diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 824b676c82..91b8f46255 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.9.13", + "version": "0.9.14", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -81,7 +81,7 @@ } }, "devDependencies": { - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.10.2", "@backstage/test-utils": "^0.1.24", "@types/archiver": "^5.1.0", "@types/compression": "^1.7.0", diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index fa8632e2ef..9c7b00b61f 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,19 @@ # example-backend +## 0.2.57 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@0.0.7 + - @backstage/plugin-catalog-backend@0.19.2 + - @backstage/plugin-scaffolder-backend@0.15.17 + - @backstage/backend-common@0.9.14 + - @backstage/plugin-azure-devops-backend@0.2.5 + - @backstage/plugin-auth-backend@0.5.1 + - @backstage/catalog-model@0.9.8 + - example-app@0.2.57 + ## 0.2.56 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index ae61bc7a45..80ae3b0998 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.2.56", + "version": "0.2.57", "main": "dist/index.cjs.js", "types": "src/index.ts", "license": "Apache-2.0", @@ -24,16 +24,16 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.9.13", + "@backstage/backend-common": "^0.9.14", "@backstage/catalog-client": "^0.5.2", - "@backstage/catalog-model": "^0.9.7", + "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.10", "@backstage/integration": "^0.6.10", "@backstage/plugin-app-backend": "^0.3.19", - "@backstage/plugin-auth-backend": "^0.5.0", - "@backstage/plugin-azure-devops-backend": "^0.2.4", + "@backstage/plugin-auth-backend": "^0.5.1", + "@backstage/plugin-azure-devops-backend": "^0.2.5", "@backstage/plugin-badges-backend": "^0.1.13", - "@backstage/plugin-catalog-backend": "^0.19.1", + "@backstage/plugin-catalog-backend": "^0.19.2", "@backstage/plugin-code-coverage-backend": "^0.1.16", "@backstage/plugin-graphql-backend": "^0.1.9", "@backstage/plugin-jenkins-backend": "^0.1.9", @@ -41,11 +41,11 @@ "@backstage/plugin-kafka-backend": "^0.2.12", "@backstage/plugin-proxy-backend": "^0.2.14", "@backstage/plugin-rollbar-backend": "^0.1.16", - "@backstage/plugin-scaffolder-backend": "^0.15.16", + "@backstage/plugin-scaffolder-backend": "^0.15.17", "@backstage/plugin-scaffolder-backend-module-rails": "^0.2.0", "@backstage/plugin-search-backend": "^0.2.8", "@backstage/plugin-search-backend-node": "^0.4.2", - "@backstage/plugin-search-backend-module-elasticsearch": "^0.0.6", + "@backstage/plugin-search-backend-module-elasticsearch": "^0.0.7", "@backstage/plugin-search-backend-module-pg": "^0.2.2", "@backstage/plugin-techdocs-backend": "^0.12.0", "@backstage/plugin-tech-insights-backend": "^0.1.3", @@ -56,7 +56,7 @@ "@octokit/rest": "^18.5.3", "azure-devops-node-api": "^11.0.1", "dockerode": "^3.3.1", - "example-app": "^0.2.56", + "example-app": "^0.2.57", "express": "^4.17.1", "express-promise-router": "^4.1.0", "express-prom-bundle": "^6.3.6", @@ -68,7 +68,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.10.2", "@types/dockerode": "^3.3.0", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5" diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index efd6513cdd..8c0a65c20a 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/catalog-model +## 0.9.8 + +### Patch Changes + +- ad7338bb48: Added an optional `presence` field to Location spec, which describes whether the target of a location is required to exist or not. It defaults to `'required'`, which is the current behaviour of the catalog. + ## 0.9.7 ### Patch Changes diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 60331d9dc8..6fdc89bdfb 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/catalog-model", "description": "Types and validators that help describe the model of a Backstage Catalog", - "version": "0.9.7", + "version": "0.9.8", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -42,7 +42,7 @@ "yup": "^0.32.9" }, "devDependencies": { - "@backstage/cli": "^0.10.0", + "@backstage/cli": "^0.10.2", "@types/jest": "^26.0.7", "@types/lodash": "^4.14.151", "yaml": "^1.9.2" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 0c30e8b251..5d51ea890b 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/cli +## 0.10.2 + +### Patch Changes + +- 25dfc2d483: Add support for `.cjs` and `.mjs` extensions in local and dependency modules. + ## 0.10.1 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 4208662f76..4b59d46827 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli", "description": "CLI for developing Backstage plugins and apps", - "version": "0.10.1", + "version": "0.10.2", "private": false, "publishConfig": { "access": "public" @@ -116,11 +116,11 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/backend-common": "^0.9.13", + "@backstage/backend-common": "^0.9.14", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", - "@backstage/core-app-api": "^0.2.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@backstage/theme": "^0.2.14", diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index d7e402270a..803579a963 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/codemods +## 0.1.26 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@0.2.1 + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + ## 0.1.25 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 32bf6be518..8261e30547 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/codemods", "description": "A collection of codemods for Backstage projects", - "version": "0.1.25", + "version": "0.1.26", "private": false, "publishConfig": { "access": "public", diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index ff15f45898..66e0c7d6ed 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/core-app-api +## 0.2.1 + +### Patch Changes + +- c11ce4f552: Deprecated `Auth0Auth`, pointing to using `OAuth2` directly instead. +- 9d6503e86c: Switched out usage of deprecated `OAuthRequestApi` types from `@backstage/core-plugin-api`. +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + ## 0.2.0 ### Minor Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 23079d7ba0..166f39a484 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": "0.2.0", + "version": "0.2.1", "private": false, "publishConfig": { "access": "public", @@ -30,9 +30,9 @@ }, "dependencies": { "@backstage/app-defaults": "^0.1.2", - "@backstage/core-components": "^0.8.0", + "@backstage/core-components": "^0.8.1", "@backstage/config": "^0.1.11", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@backstage/version-bridge": "^0.1.1", @@ -49,7 +49,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.10.2", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index 4eab9cea54..2171a72ccb 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/core-components +## 0.8.1 + +### Patch Changes + +- 2c17e5b073: Items in `` are now only active when their full path is active (including search parameters). +- 9d6503e86c: Switched out usage of deprecated `OAuthRequestApi` types from `@backstage/core-plugin-api`. +- 1680a1c5ac: Add Missing Override Components Type for SidebarSpace, SidebarSpacer, and SidebarDivider Components. +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + ## 0.8.0 ### Minor Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index f47335fce8..b47a221227 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.8.0", + "version": "0.8.1", "private": false, "publishConfig": { "access": "public", @@ -30,7 +30,7 @@ }, "dependencies": { "@backstage/config": "^0.1.11", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.5", "@backstage/theme": "^0.2.14", "@material-table/core": "^3.1.0", @@ -72,8 +72,8 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/core-app-api": "^0.2.0", - "@backstage/cli": "^0.10.1", + "@backstage/core-app-api": "^0.2.1", + "@backstage/cli": "^0.10.2", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index fdf64779fb..06d36ef486 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/core-plugin-api +## 0.3.1 + +### Patch Changes + +- 18d4f500af: Deprecated the `AnyAnalyticsContext` type and mark the `AnalyticsApi` experimental. +- 8a7372cfd5: Deprecated `auth0AuthApiRef`, `oauth2ApiRef`, `oidcAuthApiRef`, `samlAuthApiRef`, and marked the rest of the auth `ApiRef`s as experimental. For more information on how to address the deprecations, see https://backstage.io/docs/api/deprecations#generic-auth-api-refs. +- 760791a642: Renamed `AuthProvider` to `AuthProviderInfo` and add a required 'id' property to match the majority of usage. The `AuthProvider` type without the `id` property still exists but is deprecated, and all usage of it without an `id` is deprecated as well. For example, calling `createAuthRequest` without a `provider.id` is deprecated and it will be required in the future. + + The following types have been renamed. The old names are still exported but deprecated, and are scheduled for removal in a future release. + + - Renamed `AuthRequesterOptions` to `OAuthRequesterOptions` + - Renamed `AuthRequester` to `OAuthRequester` + - Renamed `PendingAuthRequest` to `PendingOAuthRequest` + ## 0.3.0 ### Minor Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 72827bde73..20479acfeb 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": "0.3.0", + "version": "0.3.1", "private": false, "publishConfig": { "access": "public", @@ -45,8 +45,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index cdcf7f4952..60d8a55635 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/create-app +## 0.4.8 + +### Patch Changes + +- 25dfc2d483: Updated the root `package.json` to include files with `.cjs` and `.mjs` extensions in the `"lint-staged"` configuration. + + To make this change to an existing app, apply the following changes to the `package.json` file: + + ```diff + "lint-staged": { + - "*.{js,jsx,ts,tsx}": [ + + "*.{js,jsx,ts,tsx,mjs,cjs}": [ + ``` + ## 0.4.7 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index e5108f540b..7a6c7ad551 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "A CLI that helps you create your own Backstage app", - "version": "0.4.7", + "version": "0.4.8", "private": false, "publishConfig": { "access": "public" diff --git a/plugins/allure/package.json b/plugins/allure/package.json index 8b3ee3b882..261c5e1879 100644 --- a/plugins/allure/package.json +++ b/plugins/allure/package.json @@ -23,8 +23,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -37,8 +37,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/analytics-module-ga/package.json b/plugins/analytics-module-ga/package.json index 15055b2a4f..5f48d4404e 100644 --- a/plugins/analytics-module-ga/package.json +++ b/plugins/analytics-module-ga/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "@backstage/config": "^0.1.5", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -35,8 +35,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/apache-airflow/CHANGELOG.md b/plugins/apache-airflow/CHANGELOG.md new file mode 100644 index 0000000000..64abdb929a --- /dev/null +++ b/plugins/apache-airflow/CHANGELOG.md @@ -0,0 +1,22 @@ +# @backstage/plugin-apache-airflow + +## 0.1.0 + +### Minor Changes + +- 9aea335911: Introduces a new plugin for the Apache Airflow workflow management platform. + This implementation has been tested with the Apache Airflow v2 API, + authenticating with basic authentication through the Backstage proxy plugin. + + Supported functionality includes: + + - Information card of version information of the Airflow instance + - Information card of instance health for the meta-database and scheduler + - Table of DAGs with meta information and status, along with a link to view + details in the Airflow UI + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 diff --git a/plugins/apache-airflow/package.json b/plugins/apache-airflow/package.json index a361961d12..58c5dceb77 100644 --- a/plugins/apache-airflow/package.json +++ b/plugins/apache-airflow/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-apache-airflow", - "version": "0.0.0", + "version": "0.1.0", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", @@ -33,8 +33,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 93df7e68aa..fd057cf358 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -32,8 +32,8 @@ "dependencies": { "@asyncapi/react-component": "^1.0.0-next.25", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog": "^0.7.4", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", @@ -54,8 +54,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/auth-backend/CHANGELOG.md b/plugins/auth-backend/CHANGELOG.md index dc45804449..cfdae9f4ef 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-auth-backend +## 0.5.1 + +### Patch Changes + +- 699c2e9ddc: export minimal typescript types for OIDC provider +- Updated dependencies + - @backstage/backend-common@0.9.14 + - @backstage/catalog-model@0.9.8 + ## 0.5.0 ### Minor Changes diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index b2822c4f33..c7d208eef2 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-auth-backend", "description": "A Backstage backend plugin that handles authentication", - "version": "0.5.0", + "version": "0.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,9 +30,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.13", + "@backstage/backend-common": "^0.9.14", "@backstage/catalog-client": "^0.5.2", - "@backstage/catalog-model": "^0.9.7", + "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", "@backstage/test-utils": "^0.1.24", @@ -73,7 +73,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.10.2", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/express-session": "^1.17.2", diff --git a/plugins/azure-devops-backend/CHANGELOG.md b/plugins/azure-devops-backend/CHANGELOG.md index e0e74a9bc6..ff802a30e1 100644 --- a/plugins/azure-devops-backend/CHANGELOG.md +++ b/plugins/azure-devops-backend/CHANGELOG.md @@ -1,5 +1,66 @@ # @backstage/plugin-azure-devops-backend +## 0.2.5 + +### Patch Changes + +- daf32e2c9b: Created some initial filters that can be used to create pull request columns: + + - All + - AssignedToUser + - AssignedToCurrentUser + - AssignedToTeam + - AssignedToTeams + - AssignedToCurrentUsersTeams + - CreatedByUser + - CreatedByCurrentUser + - CreatedByTeam + - CreatedByTeams + - CreatedByCurrentUsersTeams + + Example custom column creation: + + ```tsx + const COLUMN_CONFIGS: PullRequestColumnConfig[] = [ + { + title: 'Created by me', + filters: [{ type: FilterType.CreatedByCurrentUser }], + }, + { + title: 'Created by Backstage Core', + filters: [ + { + type: FilterType.CreatedByTeam, + teamName: 'Backstage Core', + }, + ], + }, + { + title: 'Assigned to my teams', + filters: [{ type: FilterType.AssignedToCurrentUsersTeams }], + }, + { + title: 'Other PRs', + filters: [{ type: FilterType.All }], + simplified: true, + }, + ]; + + + } + />; + ``` + +- Updated dependencies + - @backstage/backend-common@0.9.14 + - @backstage/plugin-azure-devops-common@0.1.3 + ## 0.2.4 ### Patch Changes diff --git a/plugins/azure-devops-backend/package.json b/plugins/azure-devops-backend/package.json index 9741380fb1..a7aec3f2d6 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.2.4", + "version": "0.2.5", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,9 +20,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.13", + "@backstage/backend-common": "^0.9.14", "@backstage/config": "^0.1.11", - "@backstage/plugin-azure-devops-common": "^0.1.2", + "@backstage/plugin-azure-devops-common": "^0.1.3", "@types/express": "^4.17.6", "azure-devops-node-api": "^11.0.1", "express": "^4.17.1", @@ -31,7 +31,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.10.2", "@types/supertest": "^2.0.8", "supertest": "^4.0.2", "msw": "^0.35.0" diff --git a/plugins/azure-devops-common/CHANGELOG.md b/plugins/azure-devops-common/CHANGELOG.md index b2c8645e94..84c2cae9a5 100644 --- a/plugins/azure-devops-common/CHANGELOG.md +++ b/plugins/azure-devops-common/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/plugin-azure-devops-common +## 0.1.3 + +### Patch Changes + +- daf32e2c9b: Created some initial filters that can be used to create pull request columns: + + - All + - AssignedToUser + - AssignedToCurrentUser + - AssignedToTeam + - AssignedToTeams + - AssignedToCurrentUsersTeams + - CreatedByUser + - CreatedByCurrentUser + - CreatedByTeam + - CreatedByTeams + - CreatedByCurrentUsersTeams + + Example custom column creation: + + ```tsx + const COLUMN_CONFIGS: PullRequestColumnConfig[] = [ + { + title: 'Created by me', + filters: [{ type: FilterType.CreatedByCurrentUser }], + }, + { + title: 'Created by Backstage Core', + filters: [ + { + type: FilterType.CreatedByTeam, + teamName: 'Backstage Core', + }, + ], + }, + { + title: 'Assigned to my teams', + filters: [{ type: FilterType.AssignedToCurrentUsersTeams }], + }, + { + title: 'Other PRs', + filters: [{ type: FilterType.All }], + simplified: true, + }, + ]; + + + } + />; + ``` + ## 0.1.2 ### Patch Changes diff --git a/plugins/azure-devops-common/package.json b/plugins/azure-devops-common/package.json index 7b82296c40..f8a9622bff 100644 --- a/plugins/azure-devops-common/package.json +++ b/plugins/azure-devops-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops-common", - "version": "0.1.2", + "version": "0.1.3", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "clean": "backstage-cli clean" }, "devDependencies": { - "@backstage/cli": "^0.10.1" + "@backstage/cli": "^0.10.2" }, "files": [ "dist" diff --git a/plugins/azure-devops/CHANGELOG.md b/plugins/azure-devops/CHANGELOG.md index 57f80f508b..c79c3abdbc 100644 --- a/plugins/azure-devops/CHANGELOG.md +++ b/plugins/azure-devops/CHANGELOG.md @@ -1,5 +1,69 @@ # @backstage/plugin-azure-devops +## 0.1.7 + +### Patch Changes + +- daf32e2c9b: Created some initial filters that can be used to create pull request columns: + + - All + - AssignedToUser + - AssignedToCurrentUser + - AssignedToTeam + - AssignedToTeams + - AssignedToCurrentUsersTeams + - CreatedByUser + - CreatedByCurrentUser + - CreatedByTeam + - CreatedByTeams + - CreatedByCurrentUsersTeams + + Example custom column creation: + + ```tsx + const COLUMN_CONFIGS: PullRequestColumnConfig[] = [ + { + title: 'Created by me', + filters: [{ type: FilterType.CreatedByCurrentUser }], + }, + { + title: 'Created by Backstage Core', + filters: [ + { + type: FilterType.CreatedByTeam, + teamName: 'Backstage Core', + }, + ], + }, + { + title: 'Assigned to my teams', + filters: [{ type: FilterType.AssignedToCurrentUsersTeams }], + }, + { + title: 'Other PRs', + filters: [{ type: FilterType.All }], + simplified: true, + }, + ]; + + + } + />; + ``` + +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + - @backstage/plugin-azure-devops-common@0.1.3 + - @backstage/catalog-model@0.9.8 + - @backstage/plugin-catalog-react@0.6.7 + ## 0.1.6 ### Patch Changes diff --git a/plugins/azure-devops/package.json b/plugins/azure-devops/package.json index a37259739f..5d048c6471 100644 --- a/plugins/azure-devops/package.json +++ b/plugins/azure-devops/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-azure-devops", - "version": "0.1.6", + "version": "0.1.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -27,12 +27,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/catalog-model": "^0.9.8", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.4", - "@backstage/plugin-azure-devops-common": "^0.1.2", - "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-azure-devops-common": "^0.1.3", + "@backstage/plugin-catalog-react": "^0.6.7", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -46,8 +46,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/badges/package.json b/plugins/badges/package.json index 441f72c550..9d35a3b9e2 100644 --- a/plugins/badges/package.json +++ b/plugins/badges/package.json @@ -28,8 +28,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.5", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", @@ -43,8 +43,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/bazaar/package.json b/plugins/bazaar/package.json index 3db79b9cdf..88da003778 100644 --- a/plugins/bazaar/package.json +++ b/plugins/bazaar/package.json @@ -23,8 +23,8 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/cli": "^0.10.1", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog": "^0.7.4", "@backstage/plugin-catalog-react": "^0.6.5", "@date-io/luxon": "1.x", @@ -42,7 +42,7 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.10.2", "@backstage/dev-utils": "^0.2.14", "@testing-library/jest-dom": "^5.10.1", "cross-fetch": "^3.0.6" diff --git a/plugins/bitrise/package.json b/plugins/bitrise/package.json index 35a0a9e079..c4a02c7403 100644 --- a/plugins/bitrise/package.json +++ b/plugins/bitrise/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -40,8 +40,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/catalog-backend/CHANGELOG.md b/plugins/catalog-backend/CHANGELOG.md index dc7fc50f76..ce502f8f46 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,14 @@ # @backstage/plugin-catalog-backend +## 0.19.2 + +### Patch Changes + +- 3368f27aef: Fixed the handling of optional locations so that the catalog no longer logs `NotFoundError`s for missing optional locations. +- Updated dependencies + - @backstage/backend-common@0.9.14 + - @backstage/catalog-model@0.9.8 + ## 0.19.1 ### Patch Changes diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 6cfb73a3d1..d49723b7d2 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-backend", "description": "The Backstage backend plugin that provides the Backstage catalog", - "version": "0.19.1", + "version": "0.19.2", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,9 +30,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.9.13", + "@backstage/backend-common": "^0.9.14", "@backstage/catalog-client": "^0.5.2", - "@backstage/catalog-model": "^0.9.7", + "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", "@backstage/integration": "^0.6.10", @@ -63,7 +63,7 @@ }, "devDependencies": { "@backstage/backend-test-utils": "^0.1.10", - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.10.2", "@backstage/test-utils": "^0.1.24", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index b421a15265..59afadc62e 100644 --- a/plugins/catalog-graph/package.json +++ b/plugins/catalog-graph/package.json @@ -23,8 +23,8 @@ "dependencies": { "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -42,8 +42,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index d417a337df..e017c45d09 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -33,8 +33,8 @@ "dependencies": { "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.3", "@backstage/integration": "^0.6.10", "@backstage/integration-react": "^0.1.15", @@ -56,8 +56,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index 5ebe626fad..0f7e08ead2 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,15 @@ # @backstage/plugin-catalog-react +## 0.6.7 + +### Patch Changes + +- 6156fb8730: `useEntityTypeFilter`: Skip updating selected types if a kind filter change did not change them. +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + - @backstage/catalog-model@0.9.8 + ## 0.6.6 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index da8300ae49..0bdffc0724 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-catalog-react", "description": "A frontend library that helps other Backstage plugins interact with the catalog", - "version": "0.6.6", + "version": "0.6.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,9 +30,9 @@ }, "dependencies": { "@backstage/catalog-client": "^0.5.2", - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/catalog-model": "^0.9.8", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.4", "@backstage/integration": "^0.6.10", "@backstage/types": "^0.1.1", @@ -52,8 +52,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 57e14b5475..00504d7777 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -33,8 +33,8 @@ "dependencies": { "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.3", "@backstage/integration-react": "^0.1.15", "@backstage/plugin-catalog-react": "^0.6.5", @@ -53,8 +53,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index e2aa415043..f449e5556c 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -33,8 +33,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -52,8 +52,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index 6e91b22fcb..44dafc8245 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -32,8 +32,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -49,8 +49,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/code-coverage/package.json b/plugins/code-coverage/package.json index 951a93110a..c5cb3e3acb 100644 --- a/plugins/code-coverage/package.json +++ b/plugins/code-coverage/package.json @@ -23,8 +23,8 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.4", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", @@ -43,8 +43,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index 59d34cc00d..accf5e2d01 100644 --- a/plugins/config-schema/package.json +++ b/plugins/config-schema/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.5", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", @@ -38,8 +38,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index 45975163e4..94ec2bb5fe 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -32,8 +32,8 @@ }, "dependencies": { "@backstage/config": "^0.1.10", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -56,8 +56,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 9975992ea5..4db5aa31e2 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -32,8 +32,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/plugin-explore-react": "^0.0.8", "@backstage/theme": "^0.2.14", @@ -50,8 +50,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/firehydrant/package.json b/plugins/firehydrant/package.json index 68ee004605..784346e07c 100644 --- a/plugins/firehydrant/package.json +++ b/plugins/firehydrant/package.json @@ -22,8 +22,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -36,8 +36,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/fossa/package.json b/plugins/fossa/package.json index b28c8bd89f..6542721b61 100644 --- a/plugins/fossa/package.json +++ b/plugins/fossa/package.json @@ -33,8 +33,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.3", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", @@ -50,8 +50,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index e73dc7736a..5580595dc8 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,8 +44,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/git-release-manager/package.json b/plugins/git-release-manager/package.json index ab11255e08..720f624fdd 100644 --- a/plugins/git-release-manager/package.json +++ b/plugins/git-release-manager/package.json @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/integration": "^0.6.10", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -40,8 +40,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/github-actions/CHANGELOG.md b/plugins/github-actions/CHANGELOG.md index 4c4a339415..15c8f61978 100644 --- a/plugins/github-actions/CHANGELOG.md +++ b/plugins/github-actions/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-github-actions +## 0.4.27 + +### Patch Changes + +- 89bd772b00: Show empty state only when workflow API call has completed +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + - @backstage/catalog-model@0.9.8 + - @backstage/plugin-catalog-react@0.6.7 + ## 0.4.26 ### Patch Changes diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 434a0b6224..22cd220e9c 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-github-actions", "description": "A Backstage plugin that integrates towards GitHub Actions", - "version": "0.4.26", + "version": "0.4.27", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -33,11 +33,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/catalog-model": "^0.9.8", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/integration": "^0.6.10", - "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-catalog-react": "^0.6.7", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -52,8 +52,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/github-deployments/package.json b/plugins/github-deployments/package.json index 1965f98ef1..d593ae7ac0 100644 --- a/plugins/github-deployments/package.json +++ b/plugins/github-deployments/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.3", "@backstage/integration": "^0.6.10", "@backstage/integration-react": "^0.1.15", @@ -40,8 +40,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 834fd2f7cf..b6d3f2f569 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -32,8 +32,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -45,8 +45,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index ec5a37bf36..7f165cbef5 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -45,8 +45,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/home/package.json b/plugins/home/package.json index b04e4a787d..4d14388d09 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -36,8 +36,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 5c07bc9d21..a476abebd8 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.3", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", @@ -40,8 +40,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index 2211bf54de..5822a262b5 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -33,8 +33,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -49,8 +49,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/kafka/package.json b/plugins/kafka/package.json index 309e239a68..d3353a1f0d 100644 --- a/plugins/kafka/package.json +++ b/plugins/kafka/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -36,8 +36,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 0329a9bc5b..94826738b3 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-kubernetes +## 0.5.1 + +### Patch Changes + +- 6f0c850a86: Fixed styling bug for the CronJobsAccordions and updated Completed pods to display a green dot. +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + - @backstage/catalog-model@0.9.8 + - @backstage/plugin-catalog-react@0.6.7 + ## 0.5.0 ### Minor Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 3a2ea6a9a9..02b8e85855 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.5.0", + "version": "0.5.1", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,11 +31,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", + "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", - "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", + "@backstage/plugin-catalog-react": "^0.6.7", "@backstage/plugin-kubernetes-common": "^0.2.0", "@kubernetes/client-node": "^0.16.0", "@backstage/theme": "^0.2.14", @@ -53,8 +53,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 43aabc3e3f..3820e85fdd 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -34,8 +34,8 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.10", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -48,8 +48,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index b7be235b9e..9a32e23e18 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -32,8 +32,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,8 +44,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 0576d644da..eb2599237c 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-org +## 0.3.31 + +### Patch Changes + +- fe86adbcd2: Added `entityFilterKind` property for `EntityOwnershipCard` +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + - @backstage/catalog-model@0.9.8 + - @backstage/plugin-catalog-react@0.6.7 + ## 0.3.30 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 8df865f386..8733c1c322 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.3.30", + "version": "0.3.31", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", - "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/catalog-model": "^0.9.8", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", + "@backstage/plugin-catalog-react": "^0.6.7", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -38,8 +38,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/catalog-client": "^0.5.2", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", diff --git a/plugins/pagerduty/package.json b/plugins/pagerduty/package.json index 59e76878b5..1b6c38465f 100644 --- a/plugins/pagerduty/package.json +++ b/plugins/pagerduty/package.json @@ -32,8 +32,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -49,8 +49,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index d6a14a5b2a..012cb24490 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -33,8 +33,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -50,8 +50,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 3986961f16..50d10b564c 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-scaffolder-backend +## 0.15.17 + +### Patch Changes + +- eec0750d8d: Makes cookiecutter a default, but optional action based on if a containerRunner argument is passed in to createRouter or createBuiltinActions +- ed52f74ab3: Adding changes to create GitLab Merge Request using custom action +- Updated dependencies + - @backstage/plugin-catalog-backend@0.19.2 + - @backstage/backend-common@0.9.14 + - @backstage/catalog-model@0.9.8 + ## 0.15.16 ### Patch Changes diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 2dae658d74..3686c33c40 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-scaffolder-backend", "description": "The Backstage backend plugin that helps you create new things", - "version": "0.15.16", + "version": "0.15.17", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -31,13 +31,13 @@ "build:assets": "node scripts/build-nunjucks.js" }, "dependencies": { - "@backstage/backend-common": "^0.9.13", + "@backstage/backend-common": "^0.9.14", "@backstage/catalog-client": "^0.5.2", - "@backstage/catalog-model": "^0.9.7", + "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.11", "@backstage/errors": "^0.1.5", "@backstage/integration": "^0.6.10", - "@backstage/plugin-catalog-backend": "^0.19.1", + "@backstage/plugin-catalog-backend": "^0.19.2", "@backstage/plugin-scaffolder-common": "^0.1.1", "@backstage/plugin-scaffolder-backend-module-cookiecutter": "^0.1.5", "@backstage/types": "^0.1.1", @@ -73,7 +73,7 @@ "vm2": "^3.9.5" }, "devDependencies": { - "@backstage/cli": "^0.10.1", + "@backstage/cli": "^0.10.2", "@backstage/test-utils": "^0.1.24", "@types/command-exists": "^1.2.0", "@types/fs-extra": "^9.0.1", diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index e3aaa722b0..3d42126624 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -34,8 +34,8 @@ "@backstage/catalog-client": "^0.5.2", "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.5", "@backstage/integration": "^0.6.10", "@backstage/integration-react": "^0.1.15", @@ -66,10 +66,10 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/plugin-catalog": "^0.7.4", - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", + "@backstage/plugin-catalog": "^0.7.4", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^11.2.5", diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index f36078c503..52ca5efaff 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,12 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 0.0.7 + +### Patch Changes + +- 68512f5178: Add `newClient()` method to re-use the configuration of the elastic search + engine with custom clients + ## 0.0.6 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 633af83ca6..0873fb24ac 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": "0.0.6", + "version": "0.0.7", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -30,8 +30,8 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/backend-common": "^0.9.13", - "@backstage/cli": "^0.10.1", + "@backstage/backend-common": "^0.9.14", + "@backstage/cli": "^0.10.2", "@elastic/elasticsearch-mock": "^0.3.0" }, "files": [ diff --git a/plugins/search/package.json b/plugins/search/package.json index dbef8e5608..85996d65c3 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -32,8 +32,8 @@ "dependencies": { "@backstage/catalog-model": "^0.9.7", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.4", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/search-common": "^0.2.1", @@ -52,8 +52,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 41dc522e77..0f41bfaf16 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -33,8 +33,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -49,8 +49,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/shortcuts/package.json b/plugins/shortcuts/package.json index a706d43e0e..a03dde616b 100644 --- a/plugins/shortcuts/package.json +++ b/plugins/shortcuts/package.json @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", @@ -39,8 +39,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/sonarqube/package.json b/plugins/sonarqube/package.json index 451ec86659..d1daf47b67 100644 --- a/plugins/sonarqube/package.json +++ b/plugins/sonarqube/package.json @@ -34,8 +34,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -50,8 +50,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/splunk-on-call/package.json b/plugins/splunk-on-call/package.json index e5b55836a4..faa49a962e 100644 --- a/plugins/splunk-on-call/package.json +++ b/plugins/splunk-on-call/package.json @@ -32,8 +32,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -48,8 +48,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/tech-insights/package.json b/plugins/tech-insights/package.json index 16e1ec6784..9466433b8e 100644 --- a/plugins/tech-insights/package.json +++ b/plugins/tech-insights/package.json @@ -20,26 +20,26 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/catalog-model": "^0.9.7", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", + "@backstage/errors": "^0.1.4", + "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-tech-insights-common": "^0.2.0", "@backstage/theme": "^0.2.14", + "@backstage/types": "^0.1.1", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", - "react-use": "^17.2.4", "react-router-dom": "6.0.0-beta.0", - "@backstage/plugin-catalog-react": "^0.6.5", - "@backstage/plugin-tech-insights-common": "^0.2.0", - "@backstage/catalog-model": "^0.9.7", - "@backstage/errors": "^0.1.4", - "@backstage/types": "^0.1.1" + "react-use": "^17.2.4" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", @@ -47,8 +47,8 @@ "@testing-library/user-event": "^13.1.8", "@types/jest": "^26.0.7", "@types/node": "^14.14.32", - "msw": "^0.35.0", - "cross-fetch": "^3.0.6" + "cross-fetch": "^3.0.6", + "msw": "^0.35.0" }, "files": [ "dist" diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 7d6fdb4afe..b68a05c546 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -31,8 +31,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -46,8 +46,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/techdocs/CHANGELOG.md b/plugins/techdocs/CHANGELOG.md index 5cab32a73f..d12e2df366 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,16 @@ # @backstage/plugin-techdocs +## 0.12.10 + +### Patch Changes + +- e7cce2b603: Fix issue where assets weren't being fetched from the correct URL path for doc URLs without trailing slashes +- Updated dependencies + - @backstage/core-plugin-api@0.3.1 + - @backstage/core-components@0.8.1 + - @backstage/catalog-model@0.9.8 + - @backstage/plugin-catalog-react@0.6.7 + ## 0.12.9 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 4ac62a2b56..f9e3db913b 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-techdocs", "description": "The Backstage plugin that renders technical documentation for your components", - "version": "0.12.9", + "version": "0.12.10", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -32,15 +32,15 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.9.7", + "@backstage/catalog-model": "^0.9.8", "@backstage/config": "^0.1.11", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.5", "@backstage/integration": "^0.6.10", "@backstage/integration-react": "^0.1.15", "@backstage/plugin-catalog": "^0.7.4", - "@backstage/plugin-catalog-react": "^0.6.5", + "@backstage/plugin-catalog-react": "^0.6.7", "@backstage/plugin-search": "^0.5.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -62,8 +62,8 @@ "react-dom": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/todo/package.json b/plugins/todo/package.json index 10f2b311ca..deef4ac7f2 100644 --- a/plugins/todo/package.json +++ b/plugins/todo/package.json @@ -28,8 +28,8 @@ }, "dependencies": { "@backstage/catalog-model": "^0.9.7", - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.3", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", @@ -42,8 +42,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index aaef5eb0a3..6d9f4bac21 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", @@ -44,8 +44,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", diff --git a/plugins/xcmetrics/package.json b/plugins/xcmetrics/package.json index 55488aa8f4..26fcc28f9f 100644 --- a/plugins/xcmetrics/package.json +++ b/plugins/xcmetrics/package.json @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core-components": "^0.8.0", - "@backstage/core-plugin-api": "^0.3.0", + "@backstage/core-components": "^0.8.1", + "@backstage/core-plugin-api": "^0.3.1", "@backstage/errors": "^0.1.3", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", @@ -37,8 +37,8 @@ "react": "^16.13.1 || ^17.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@backstage/core-app-api": "^0.2.0", + "@backstage/cli": "^0.10.2", + "@backstage/core-app-api": "^0.2.1", "@backstage/dev-utils": "^0.2.14", "@backstage/test-utils": "^0.1.24", "@testing-library/jest-dom": "^5.10.1", From b80e25bf1d3b31bdb6ebe56cd627bd2c6d20b8c6 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Thu, 16 Dec 2021 10:03:27 +0100 Subject: [PATCH 167/189] add search packages to matching Signed-off-by: Johan Haals --- .github/labeler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index 112f77e078..5f513b3db8 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -8,3 +8,4 @@ scaffolder: search: - plugins/search/**/* - plugins/search-*/**/* + - packages/search-*/**/* From 5463c03b35cc815cb619ae92a79203ce6030290e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 15 Dec 2021 22:47:52 +0100 Subject: [PATCH 168/189] Add support for passing paging parameters to the getEntities call of the catalog client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik AdelΓΆw --- .changeset/silver-books-clean.md | 5 ++ packages/catalog-client/api-report.md | 3 + .../catalog-client/src/CatalogClient.test.ts | 18 +++++ packages/catalog-client/src/CatalogClient.ts | 12 +++- packages/catalog-client/src/types/api.ts | 70 +++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 .changeset/silver-books-clean.md diff --git a/.changeset/silver-books-clean.md b/.changeset/silver-books-clean.md new file mode 100644 index 0000000000..9685cc2119 --- /dev/null +++ b/.changeset/silver-books-clean.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': patch +--- + +Add support for passing paging parameters to the getEntities call of the catalog client diff --git a/packages/catalog-client/api-report.md b/packages/catalog-client/api-report.md index e16ca740f6..88c5ad6c27 100644 --- a/packages/catalog-client/api-report.md +++ b/packages/catalog-client/api-report.md @@ -121,6 +121,9 @@ export type CatalogEntitiesRequest = { | Record | undefined; fields?: string[] | undefined; + offset?: number; + limit?: number; + after?: string; }; // @public diff --git a/packages/catalog-client/src/CatalogClient.test.ts b/packages/catalog-client/src/CatalogClient.test.ts index d2db98bb25..1331f8e874 100644 --- a/packages/catalog-client/src/CatalogClient.test.ts +++ b/packages/catalog-client/src/CatalogClient.test.ts @@ -175,6 +175,24 @@ describe('CatalogClient', () => { { apiVersion: '2' }, ]); }); + + it('builds paging parameters properly', async () => { + expect.assertions(2); + + server.use( + rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { + expect(req.url.search).toBe('?offset=1&limit=2&after=%3D'); + return res(ctx.json([])); + }), + ); + + const response = await client.getEntities( + { offset: 1, limit: 2, after: '=' }, + { token }, + ); + + expect(response.items).toEqual([]); + }); }); describe('getLocationById', () => { diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index 29d01fbe5c..0e5e2600bb 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -110,7 +110,7 @@ export class CatalogClient implements CatalogApi { request?: CatalogEntitiesRequest, options?: CatalogRequestOptions, ): Promise> { - const { filter = [], fields = [] } = request ?? {}; + const { filter = [], fields = [], offset, limit, after } = request ?? {}; const filterItems = [filter].flat(); const params: string[] = []; @@ -141,6 +141,16 @@ export class CatalogClient implements CatalogApi { params.push(`fields=${fields.map(encodeURIComponent).join(',')}`); } + if (offset !== undefined) { + params.push(`offset=${offset}`); + } + if (limit !== undefined) { + params.push(`limit=${limit}`); + } + if (after !== undefined) { + params.push(`after=${encodeURIComponent(after)}`); + } + const query = params.length ? `?${params.join('&')}` : ''; const entities: Entity[] = await this.requestRequired( 'GET', diff --git a/packages/catalog-client/src/types/api.ts b/packages/catalog-client/src/types/api.ts index 6344caff7c..3a09e14d71 100644 --- a/packages/catalog-client/src/types/api.ts +++ b/packages/catalog-client/src/types/api.ts @@ -29,11 +29,81 @@ export const CATALOG_FILTER_EXISTS = Symbol('CATALOG_FILTER_EXISTS'); * @public */ export type CatalogEntitiesRequest = { + /** + * If given, return only entities that match the given patterns. + * + * @remarks + * + * If multiple filter sets are given as an array, then there is effectively an + * OR between each filter set. + * + * Within one filter set, there is effectively an AND between the various + * keys. + * + * Within one key, if there are more than one value, then there is effectively + * an OR between them. + * + * Example: For an input of + * + * ``` + * [ + * { kind: ['API', 'Component'] }, + * { 'metadata.name': 'a', 'metadata.namespace': 'b' } + * ] + * ``` + * + * This effectively means + * + * ``` + * (kind = EITHER 'API' OR 'Component') + * OR + * (metadata.name = 'a' AND metadata.namespace = 'b' ) + * ``` + * + * Each key is a dot separated path in each object. + * + * As a value you can also pass in the symbol `CATALOG_FILTER_EXISTS` + * (exported from this package), which means that you assert on the existence + * of that key, no matter what its value is. + */ filter?: | Record[] | Record | undefined; + /** + * If given, return only the parts of each entity that match those dot + * separated paths in each object. + * + * @remarks + * + * Example: For an input of `['kind', 'metadata.annotations']`, then response + * objects will be shaped like + * + * ``` + * { + * "kind": "Component", + * "metadata": { + * "annotations": { + * "foo": "bar" + * } + * } + * } + * ``` + */ fields?: string[] | undefined; + /** + * If given, skips over the first N items in the result set. + */ + offset?: number; + /** + * If given, returns at most N items from the result set. + */ + limit?: number; + /** + * If given, skips over all items before that cursor as returned by a previous + * request. + */ + after?: string; }; /** From 6b7b4b3fa2fe42c0eceb411e61b04df98b9e9dbe Mon Sep 17 00:00:00 2001 From: Arve Systad <290195+ArveSystad@users.noreply.github.com> Date: Thu, 16 Dec 2021 10:33:10 +0100 Subject: [PATCH 169/189] Correct keyword for microsoftAuthApiRef Makes for a little less guesswork in the middle of things. --- docs/auth/microsoft/provider.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/auth/microsoft/provider.md b/docs/auth/microsoft/provider.md index 1e24235f1a..ef79127223 100644 --- a/docs/auth/microsoft/provider.md +++ b/docs/auth/microsoft/provider.md @@ -48,6 +48,6 @@ The Microsoft provider is a structure with three configuration keys: ## Adding the provider to the Backstage frontend -To add the provider to the frontend, add the `microsoftAuthApi` reference and +To add the provider to the frontend, add the `microsoftAuthApiRef` reference and `SignInPage` component as shown in [Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page). From 51ee84204d27eefc7d2d44fd1a7b92cc964a00bb Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Thu, 16 Dec 2021 14:05:51 +0100 Subject: [PATCH 170/189] fix typo. on changesets Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- .changeset/twenty-tigers-smash.md | 2 +- .changeset/twenty-tigers-ymash.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/twenty-tigers-smash.md b/.changeset/twenty-tigers-smash.md index b7b06074dd..3ad694fbba 100644 --- a/.changeset/twenty-tigers-smash.md +++ b/.changeset/twenty-tigers-smash.md @@ -2,4 +2,4 @@ '@backstage/plugin-jenkins-backend': patch --- -feature: add crumbIssuer option to jenkins (optional) configuration, improve the UI to show a notification after executing the action re-build +feature: add crumbIssuer option to Jenkins (optional) configuration, improve the UI to show a notification after executing the action re-build diff --git a/.changeset/twenty-tigers-ymash.md b/.changeset/twenty-tigers-ymash.md index 609b30e0f5..c3e03ba75d 100644 --- a/.changeset/twenty-tigers-ymash.md +++ b/.changeset/twenty-tigers-ymash.md @@ -2,4 +2,4 @@ '@backstage/plugin-jenkins': patch --- -feature: add crumbIssuer option to jenkins (optional) configuration, improve the UI to show a notification after executing the action re-build +feature: add crumbIssuer option to Jenkins (optional) configuration, improve the UI to show a notification after executing the action re-build From 7e9f1118dc8aef168247bacdfc8921f03023750b Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Wed, 15 Dec 2021 17:05:13 -0500 Subject: [PATCH 171/189] remove deprecations packages/core-plugin-api/src/routing/RouteRef.ts:27 Signed-off-by: Colton Padden --- packages/core-plugin-api/src/routing/RouteRef.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/core-plugin-api/src/routing/RouteRef.ts b/packages/core-plugin-api/src/routing/RouteRef.ts index 8bd3d604f6..37d79f3b83 100644 --- a/packages/core-plugin-api/src/routing/RouteRef.ts +++ b/packages/core-plugin-api/src/routing/RouteRef.ts @@ -23,17 +23,6 @@ import { } from './types'; import { OldIconComponent } from '../icons/types'; -/** - * @deprecated - * @internal - */ -export type RouteRefConfig = { - params?: ParamKeys; - path?: string; - icon?: OldIconComponent; - title: string; -}; - /** * @internal */ From 26cbea8e691e51277b8a3d2e9127288e4d02aae0 Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Wed, 15 Dec 2021 17:05:29 -0500 Subject: [PATCH 172/189] remove deprecations packages/core-plugin-api/src/routing/types.ts:147,152,157 Signed-off-by: Colton Padden --- packages/core-plugin-api/src/routing/types.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/packages/core-plugin-api/src/routing/types.ts b/packages/core-plugin-api/src/routing/types.ts index bd419abb76..6232810e56 100644 --- a/packages/core-plugin-api/src/routing/types.ts +++ b/packages/core-plugin-api/src/routing/types.ts @@ -142,23 +142,6 @@ export type AnyRouteRef = | SubRouteRef | ExternalRouteRef; -// TODO(Rugvip): None of these should be found in the wild anymore, remove in next minor release -/** - * @deprecated - * @internal - */ -export type ConcreteRoute = {}; -/** - * @deprecated - * @internal - */ -export type AbsoluteRouteRef = RouteRef<{}>; -/** - * @deprecated - * @internal - */ -export type MutableRouteRef = RouteRef<{}>; - /** * A duplicate of the react-router RouteObject, but with routeRef added * @internal From 771b9c07fe6c3fd62fa07d983fb64f418b45ce5b Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Wed, 15 Dec 2021 17:18:46 -0500 Subject: [PATCH 173/189] remove deprecations packages/test-utils/src/testUtils/Keyboard.js:28 Signed-off-by: Colton Padden --- .changeset/neat-stingrays-decide.md | 5 + packages/test-utils/api-report.md | 46 ---- packages/test-utils/src/testUtils/Keyboard.js | 225 ------------------ packages/test-utils/src/testUtils/index.tsx | 1 - 4 files changed, 5 insertions(+), 272 deletions(-) create mode 100644 .changeset/neat-stingrays-decide.md delete mode 100644 packages/test-utils/src/testUtils/Keyboard.js diff --git a/.changeset/neat-stingrays-decide.md b/.changeset/neat-stingrays-decide.md new file mode 100644 index 0000000000..cf56a81331 --- /dev/null +++ b/.changeset/neat-stingrays-decide.md @@ -0,0 +1,5 @@ +--- +'@backstage/test-utils': patch +--- + +Remove deprecated `Keyboard` class which has been superseded by `@testing-library/user-event#userEvent` diff --git a/packages/test-utils/api-report.md b/packages/test-utils/api-report.md index a01f306fab..295cf3a8c3 100644 --- a/packages/test-utils/api-report.md +++ b/packages/test-utils/api-report.md @@ -34,52 +34,6 @@ export type ErrorWithContext = { context?: ErrorApiErrorContext; }; -// @public @deprecated (undocumented) -export class Keyboard { - constructor( - target: any, - { - debug, - }?: { - debug?: boolean | undefined; - }, - ); - // (undocumented) - click(): Promise; - // (undocumented) - debug: boolean; - // (undocumented) - document: any; - // (undocumented) - enter(value: any): Promise; - // (undocumented) - escape(): Promise; - // (undocumented) - get focused(): any; - // (undocumented) - static fromReadableInput(input: any): any; - // (undocumented) - _log(message: any, ...args: any[]): void; - // (undocumented) - _pretty(element: any): string; - // (undocumented) - send(chars: any): Promise; - // (undocumented) - _sendKey(key: any, charCode: any, action: any): Promise; - // (undocumented) - tab(): Promise; - // (undocumented) - static toReadableInput(chars: any): any; - // (undocumented) - toString(): string; - // (undocumented) - static type(target: any, input: any): Promise; - // (undocumented) - type(input: any): Promise; - // (undocumented) - static typeDebug(target: any, input: any): Promise; -} - // @public export type LogCollector = AsyncLogCollector | SyncLogCollector; diff --git a/packages/test-utils/src/testUtils/Keyboard.js b/packages/test-utils/src/testUtils/Keyboard.js deleted file mode 100644 index 2a7928f8cd..0000000000 --- a/packages/test-utils/src/testUtils/Keyboard.js +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { act, fireEvent } from '@testing-library/react'; - -const codes = { - Tab: 9, - Enter: 10, - Click: 17 /* This keyboard can click, deal with it */, - Esc: 27, -}; - -/** - * @public - * @deprecated superseded by {@link @testing-library/user-event#userEvent} - */ -export class Keyboard { - static async type(target, input) { - await new Keyboard(target).type(input); - } - - static async typeDebug(target, input) { - await new Keyboard(target, { debug: true }).type(input); - } - - static toReadableInput(chars) { - return chars.split('').map(char => { - switch (char.charCodeAt(0)) { - case codes.Tab: - return ''; - case codes.Enter: - return ''; - case codes.Click: - return ''; - case codes.Esc: - return ''; - default: - return char; - } - }); - } - - static fromReadableInput(input) { - return input.trim().replace(/\s*<([a-zA-Z]+)>\s*/g, (match, name) => { - if (name in codes) { - return String.fromCharCode(codes[name]); - } - throw new Error(`Unknown char name: '${name}'`); - }); - } - - constructor(target, { debug = false } = {}) { - this.debug = debug; - - if (target.ownerDocument) { - this.document = target.ownerDocument; - } else if (target.baseElement) { - this.document = target.baseElement.ownerDocument; - } else { - throw new TypeError( - 'Keyboard(target): target must be DOM node or react-testing-library render() output', - ); - } - } - - toString() { - return `Keyboard{document=${this.document}, debug=${this.debug}}`; - } - - _log(message, ...args) { - if (this.debug) { - // eslint-disable-next-line no-console - console.log(`[Keyboard] ${message}`, ...args); - } - } - - _pretty(element) { - const attrs = [...element.attributes] - .map(attr => `${attr.name}="${attr.value}"`) - .join(' '); - return `<${element.nodeName.toLocaleLowerCase('en-US')} ${attrs}>`; - } - - get focused() { - return this.document.activeElement; - } - - async type(input) { - this._log( - `sending sequence '${input}' with initial focus ${this._pretty( - this.focused, - )}`, - ); - await this.send(Keyboard.fromReadableInput(input)); - } - - async send(chars) { - for (const key of chars.split('')) { - const charCode = key.charCodeAt(0); - - if (charCode === codes.Tab) { - await this.tab(); - continue; - } - - const focused = this.focused; - if (!focused || focused === this.document.body) { - throw Error( - `No element focused in document while trying to type '${Keyboard.toReadableInput( - chars, - )}'`, - ); - } - const nextValue = (focused.value || '') + key; - - if (charCode >= 32) { - await this._sendKey(key, charCode, () => { - this._log( - `sending +${key} = '${nextValue}' to ${this._pretty(focused)}`, - ); - fireEvent.change(focused, { - target: { value: nextValue }, - bubbles: true, - cancelable: true, - }); - }); - } else if (charCode === codes.Enter) { - await this.enter(focused.value || ''); - } else if (charCode === codes.Esc) { - await this.escape(); - } else if (charCode === codes.Click) { - await this.click(); - } else { - throw new Error(`Unsupported char code, ${charCode}`); - } - } - } - - async click() { - this._log(`clicking ${this._pretty(this.focused)}`); - await act(async () => fireEvent.click(this.focused)); - } - - async tab() { - await this._sendKey('Tab', codes.Tab, () => { - const focusable = this.document.querySelectorAll( - [ - 'a[href]', - 'area[href]', - 'input:not([disabled])', - 'select:not([disabled])', - 'textarea:not([disabled])', - 'button:not([disabled])', - 'iframe', - 'object', - 'embed', - '*[tabindex]', - '*[contenteditable]', - ].join(','), - ); - - const tabbable = [...focusable].filter(el => { - return el.tabIndex >= 0; - }); - - const focused = this.document.activeElement; - const focusedIndex = tabbable.indexOf(focused); - const nextFocus = tabbable[focusedIndex + (1 % tabbable.length)]; - - this._log( - `tabbing to ${this._pretty(nextFocus)} ${this.focused.textContent}`, - ); - nextFocus.focus(); - }); - } - - async enter(value) { - this._log(`submitting '${value}' via ${this._pretty(this.focused)}`); - await act(() => - this._sendKey('Enter', codes.Enter, () => { - if (this.focused.type === 'button') { - fireEvent.click(this.focused, { target: { value } }); - } else { - fireEvent.submit(this.focused, { - target: { value }, - bubbles: true, - cancelable: true, - }); - } - }), - ); - } - - async escape() { - this._log(`escape from ${this._pretty(this.focused)}`); - await act(async () => this._sendKey('Escape', codes.Esc)); - } - - async _sendKey(key, charCode, action) { - const event = { key, charCode, keyCode: charCode, which: charCode }; - const focused = this.focused; - - if (fireEvent.keyDown(focused, event)) { - if (fireEvent.keyPress(focused, event)) { - if (action) { - action(); - } - } - } - fireEvent.keyUp(focused, event); - } -} diff --git a/packages/test-utils/src/testUtils/index.tsx b/packages/test-utils/src/testUtils/index.tsx index c778c5c837..a7850fc158 100644 --- a/packages/test-utils/src/testUtils/index.tsx +++ b/packages/test-utils/src/testUtils/index.tsx @@ -19,7 +19,6 @@ export { default as mockBreakpoint } from './mockBreakpoint'; export { wrapInTestApp, renderInTestApp } from './appWrappers'; export type { TestAppOptions } from './appWrappers'; export * from './msw'; -export * from './Keyboard'; export * from './logCollector'; export * from './testingLibrary'; export { TestApiProvider, TestApiRegistry } from './TestApiProvider'; From 6b69b448624fc4355576a0aeeaf2a040858a1ce8 Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Wed, 15 Dec 2021 17:31:32 -0500 Subject: [PATCH 174/189] remove deprecations packages/core-plugin-api/src/apis/system/types.ts:38,55 Signed-off-by: Colton Padden --- .changeset/young-dodos-bake.md | 5 +++++ packages/core-plugin-api/api-report.md | 12 ----------- .../core-plugin-api/src/apis/system/types.ts | 20 ------------------- 3 files changed, 5 insertions(+), 32 deletions(-) create mode 100644 .changeset/young-dodos-bake.md diff --git a/.changeset/young-dodos-bake.md b/.changeset/young-dodos-bake.md new file mode 100644 index 0000000000..93689ad2c8 --- /dev/null +++ b/.changeset/young-dodos-bake.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Remove deprecated types `ApiRefType` and `ApiRefsToTypes` diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index e142c1ab96..0cf97a4c13 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -144,18 +144,6 @@ export type ApiRefConfig = { description?: string; }; -// @public @deprecated -export type ApiRefsToTypes< - T extends { - [key in string]: ApiRef; - }, -> = { - [key in keyof T]: ApiRefType; -}; - -// @public @deprecated -export type ApiRefType = T extends ApiRef ? U : never; - // @public export type AppComponents = { NotFoundErrorPage: ComponentType<{}>; diff --git a/packages/core-plugin-api/src/apis/system/types.ts b/packages/core-plugin-api/src/apis/system/types.ts index a449e83450..96614c320c 100644 --- a/packages/core-plugin-api/src/apis/system/types.ts +++ b/packages/core-plugin-api/src/apis/system/types.ts @@ -31,33 +31,13 @@ export type ApiRef = { */ export type AnyApiRef = ApiRef; -/** - * Transforms ApiRef type into its inner API type. - * - * @public - * @deprecated unused type. - */ -export type ApiRefType = T extends ApiRef ? U : never; - /** * Wraps a type with API properties into a type holding their respective {@link ApiRef}s. - * Reverse type transform of {@link ApiRefsToTypes}. * * @public */ export type TypesToApiRefs = { [key in keyof T]: ApiRef }; -/** - * Unwraps type with {@link ApiRef} properties into a type holding their respective API types. - * Reverse type transform of {@link TypesToApiRefs}. - * - * @public - * @deprecated unused type. - */ -export type ApiRefsToTypes }> = { - [key in keyof T]: ApiRefType; -}; - /** * Provides lookup of APIs through their {@link ApiRef}s. * From 67d6cb3c7ea4cb5381ceb61770487949d60260ff Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Wed, 15 Dec 2021 18:48:46 -0500 Subject: [PATCH 175/189] remove deprecations packages/config-loader/src/loader.ts:63 Signed-off-by: Colton Padden --- .changeset/perfect-apricots-raise.md | 5 +++++ packages/backend-common/src/config.ts | 1 - packages/cli/src/lib/config.ts | 1 - packages/config-loader/api-report.md | 5 ----- packages/config-loader/src/loader.test.ts | 14 ++++---------- packages/config-loader/src/loader.ts | 12 ------------ 6 files changed, 9 insertions(+), 29 deletions(-) create mode 100644 .changeset/perfect-apricots-raise.md diff --git a/.changeset/perfect-apricots-raise.md b/.changeset/perfect-apricots-raise.md new file mode 100644 index 0000000000..9d6c617476 --- /dev/null +++ b/.changeset/perfect-apricots-raise.md @@ -0,0 +1,5 @@ +--- +'@backstage/config-loader': patch +--- + +Removed deprecated option `configPaths` as it has been superseded by `configTargets` diff --git a/packages/backend-common/src/config.ts b/packages/backend-common/src/config.ts index 941ad26e65..b536b53958 100644 --- a/packages/backend-common/src/config.ts +++ b/packages/backend-common/src/config.ts @@ -202,7 +202,6 @@ export async function loadBackendConfig(options: { const config = new ObservableConfigProxy(options.logger); const { appConfigs } = await loadConfig({ configRoot: paths.targetRoot, - configPaths: [], configTargets: configTargets, watch: { onChange(newConfigs) { diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/lib/config.ts index d343a554f8..f85db276b2 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/lib/config.ts @@ -59,7 +59,6 @@ export async function loadCliConfig(options: Options) { ? async name => process.env[name] || 'x' : undefined, configRoot: paths.targetRoot, - configPaths: [], configTargets: configTargets, }); diff --git a/packages/config-loader/api-report.md b/packages/config-loader/api-report.md index e0fab50e5b..76c6468556 100644 --- a/packages/config-loader/api-report.md +++ b/packages/config-loader/api-report.md @@ -45,7 +45,6 @@ export function loadConfig( // @public export type LoadConfigOptions = { configRoot: string; - configPaths: string[]; configTargets: ConfigTarget[]; env?: string; experimentalEnvFunc?: (name: string) => Promise; @@ -103,8 +102,4 @@ export type TransformFunc = ( visibility: ConfigVisibility; }, ) => T | undefined; - -// Warnings were encountered during analysis: -// -// src/loader.d.ts:33:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/config-loader" does not have an export "configTargets" ``` diff --git a/packages/config-loader/src/loader.test.ts b/packages/config-loader/src/loader.test.ts index b5c986eeb9..97c3037244 100644 --- a/packages/config-loader/src/loader.test.ts +++ b/packages/config-loader/src/loader.test.ts @@ -118,7 +118,6 @@ describe('loadConfig', () => { await expect( loadConfig({ configRoot: '/root', - configPaths: [], configTargets: [], env: 'production', }), @@ -146,7 +145,6 @@ describe('loadConfig', () => { await expect( loadConfig({ configRoot: '/root', - configPaths: [], configTargets: [{ url: configUrl }], env: 'production', remote: { @@ -173,8 +171,10 @@ describe('loadConfig', () => { await expect( loadConfig({ configRoot: '/root', - configPaths: ['/root/app-config2.yaml'], - configTargets: [{ path: '/root/app-config.yaml' }], + configTargets: [ + { path: '/root/app-config.yaml' }, + { path: '/root/app-config2.yaml' }, + ], env: 'production', }), ).resolves.toEqual({ @@ -207,7 +207,6 @@ describe('loadConfig', () => { await expect( loadConfig({ configRoot: '/root', - configPaths: ['/root/app-config.yaml'], configTargets: [{ path: '/root/app-config.yaml' }], env: 'production', }), @@ -231,7 +230,6 @@ describe('loadConfig', () => { await expect( loadConfig({ configRoot: '/root', - configPaths: [], configTargets: [ { path: '/root/app-config.yaml' }, { path: '/root/app-config.development.yaml' }, @@ -274,7 +272,6 @@ describe('loadConfig', () => { await expect( loadConfig({ configRoot: '/root', - configPaths: [], configTargets: [{ path: '/root/app-config.substitute.yaml' }], env: 'development', }), @@ -302,7 +299,6 @@ describe('loadConfig', () => { await expect( loadConfig({ configRoot: '/root', - configPaths: [], configTargets: [], watch: { onChange: onChange.resolve, @@ -353,7 +349,6 @@ describe('loadConfig', () => { await expect( loadConfig({ configRoot: '/root', - configPaths: [], configTargets: [{ url: configUrl }], watch: { onChange: onChange.resolve, @@ -401,7 +396,6 @@ describe('loadConfig', () => { await loadConfig({ configRoot: '/root', - configPaths: [], configTargets: [], watch: { onChange: () => { diff --git a/packages/config-loader/src/loader.ts b/packages/config-loader/src/loader.ts index 6a92ed519d..7f4bf8ab0a 100644 --- a/packages/config-loader/src/loader.ts +++ b/packages/config-loader/src/loader.ts @@ -59,11 +59,6 @@ export type LoadConfigOptions = { // The root directory of the config loading context. Used to find default configs. configRoot: string; - /** Absolute paths to load config files from. Configs from earlier paths have lower priority. - * @deprecated Use {@link configTargets} instead. - */ - configPaths: string[]; - // Paths to load config files from. Configs from earlier paths have lower priority. configTargets: ConfigTarget[]; @@ -114,13 +109,6 @@ export async function loadConfig( .filter((e): e is { path: string } => e.hasOwnProperty('path')) .map(configTarget => configTarget.path); - // Append deprecated configPaths to the absolute config paths received via configTargets. - options.configPaths.forEach(cp => { - if (!configPaths.includes(cp)) { - configPaths.push(cp); - } - }); - const configUrls: string[] = options.configTargets .slice() .filter((e): e is { url: string } => e.hasOwnProperty('url')) From 62d77827e1520bf7fe33ab21cbd8863845bfb12d Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Wed, 15 Dec 2021 20:10:35 -0500 Subject: [PATCH 176/189] remove associated tests for deprecated Keyboard.js Signed-off-by: Colton Padden --- .../test-utils/src/testUtils/Keyboard.test.js | 108 ------------------ 1 file changed, 108 deletions(-) delete mode 100644 packages/test-utils/src/testUtils/Keyboard.test.js diff --git a/packages/test-utils/src/testUtils/Keyboard.test.js b/packages/test-utils/src/testUtils/Keyboard.test.js deleted file mode 100644 index 41ee3a12d6..0000000000 --- a/packages/test-utils/src/testUtils/Keyboard.test.js +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { Keyboard } from './Keyboard'; -import { render } from '@testing-library/react'; - -describe('testUtils.Keyboard', () => { - it('types into some inputs with focus and submits a form', async () => { - const typed1 = []; - const typed2 = []; - const typed3 = []; - - let submitted = false; - const handleSubmit = event => { - event.preventDefault(); - submitted = true; - }; - - const rendered = render( -

- typed1.push(value)} /> - typed2.push(value)} - /* eslint-disable-next-line jsx-a11y/no-autofocus */ - autoFocus - /> - typed3.push(value)} /> - , - ); - - const keyboard = new Keyboard(rendered); - await keyboard.send('xy'); - await keyboard.tab(); - await keyboard.send('abc'); - await keyboard.enter(); - - expect(typed1).toEqual([]); - expect(typed2).toEqual(['x', 'xy']); - expect(typed3).toEqual(['a', 'ab', 'abc']); - expect(submitted).toBe(true); - }); - - it('can use Keyboard.type to send readable input', async () => { - const typed1 = []; - const typed2 = []; - const typed3 = []; - - let submitted = false; - const handleSubmit = event => { - event.preventDefault(); - submitted = true; - }; - - const rendered = render( -
- typed1.push(value)} - /> - typed2.push(value)} - /> - typed3.push(value)} - /> -
, - ); - - await Keyboard.type(rendered, ' a b c '); - - expect(typed1).toEqual(['1a']); - expect(typed2).toEqual(['2b']); - expect(typed3).toEqual(['3c']); - expect(submitted).toBe(true); - }); - - it('should be able to navigate a radio input with click', async () => { - const selections = []; - - const rendered = render( -
selections.push(value)}> - - - -
, - ); - - await Keyboard.type(rendered, ' '); - - expect(selections).toEqual(['a', 'c']); - }); -}); From 7e0b8b0cde98c9c3059bb03a3dcb93842fe32407 Mon Sep 17 00:00:00 2001 From: Colton Padden Date: Thu, 16 Dec 2021 08:31:44 -0500 Subject: [PATCH 177/189] bumped changesets for deprecations from patch to minor Signed-off-by: Colton Padden --- .changeset/neat-stingrays-decide.md | 4 ++-- .changeset/perfect-apricots-raise.md | 2 +- .changeset/young-dodos-bake.md | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.changeset/neat-stingrays-decide.md b/.changeset/neat-stingrays-decide.md index cf56a81331..f339d7ded6 100644 --- a/.changeset/neat-stingrays-decide.md +++ b/.changeset/neat-stingrays-decide.md @@ -1,5 +1,5 @@ --- -'@backstage/test-utils': patch +'@backstage/test-utils': minor --- -Remove deprecated `Keyboard` class which has been superseded by `@testing-library/user-event#userEvent` +Removed deprecated `Keyboard` class which has been superseded by `@testing-library/user-event#userEvent` diff --git a/.changeset/perfect-apricots-raise.md b/.changeset/perfect-apricots-raise.md index 9d6c617476..d7a40e6343 100644 --- a/.changeset/perfect-apricots-raise.md +++ b/.changeset/perfect-apricots-raise.md @@ -1,5 +1,5 @@ --- -'@backstage/config-loader': patch +'@backstage/config-loader': minor --- Removed deprecated option `configPaths` as it has been superseded by `configTargets` diff --git a/.changeset/young-dodos-bake.md b/.changeset/young-dodos-bake.md index 93689ad2c8..f620c6a1a4 100644 --- a/.changeset/young-dodos-bake.md +++ b/.changeset/young-dodos-bake.md @@ -1,5 +1,5 @@ --- -'@backstage/core-plugin-api': patch +'@backstage/core-plugin-api': minor --- -Remove deprecated types `ApiRefType` and `ApiRefsToTypes` +Removed deprecated types `ApiRefType` and `ApiRefsToTypes` From 393f107893ec4ab4903d9022b8c3d0b6d0c4970d Mon Sep 17 00:00:00 2001 From: Joon Park Date: Thu, 16 Dec 2021 14:35:46 +0000 Subject: [PATCH 178/189] Create catalog permissions. (#8403) These permissions will be used to integrate catalog with the permissions framework. Signed-off-by: Joon Park --- .changeset/gold-seas-wave.md | 5 + plugins/catalog-common/.eslintrc.js | 3 + plugins/catalog-common/README.md | 9 ++ plugins/catalog-common/api-report.md | 31 ++++++ plugins/catalog-common/package.json | 41 ++++++++ plugins/catalog-common/src/index.ts | 33 +++++++ plugins/catalog-common/src/permissions.ts | 113 ++++++++++++++++++++++ plugins/catalog-common/src/setupTests.ts | 16 +++ 8 files changed, 251 insertions(+) create mode 100644 .changeset/gold-seas-wave.md create mode 100644 plugins/catalog-common/.eslintrc.js create mode 100644 plugins/catalog-common/README.md create mode 100644 plugins/catalog-common/api-report.md create mode 100644 plugins/catalog-common/package.json create mode 100644 plugins/catalog-common/src/index.ts create mode 100644 plugins/catalog-common/src/permissions.ts create mode 100644 plugins/catalog-common/src/setupTests.ts diff --git a/.changeset/gold-seas-wave.md b/.changeset/gold-seas-wave.md new file mode 100644 index 0000000000..ec0c6451b7 --- /dev/null +++ b/.changeset/gold-seas-wave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-common': minor +--- + +Create catalog-common and add catalog permissions. diff --git a/plugins/catalog-common/.eslintrc.js b/plugins/catalog-common/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/plugins/catalog-common/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; diff --git a/plugins/catalog-common/README.md b/plugins/catalog-common/README.md new file mode 100644 index 0000000000..2566a737d8 --- /dev/null +++ b/plugins/catalog-common/README.md @@ -0,0 +1,9 @@ +# Catalog Common + +Shared isomorphic code for the catalog plugin. + +## Links + +- [Frontend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/catalog) +- [Backend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/catalog-backend) +- [The Backstage homepage](https://backstage.io) diff --git a/plugins/catalog-common/api-report.md b/plugins/catalog-common/api-report.md new file mode 100644 index 0000000000..8e03fc16b5 --- /dev/null +++ b/plugins/catalog-common/api-report.md @@ -0,0 +1,31 @@ +## API Report File for "@backstage/plugin-catalog-common" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { Permission } from '@backstage/plugin-permission-common'; + +// @public +export const catalogEntityDeletePermission: Permission; + +// @public +export const catalogEntityReadPermission: Permission; + +// @public +export const catalogEntityRefreshPermission: Permission; + +// @public +export const catalogLocationCreatePermission: Permission; + +// @public +export const catalogLocationDeletePermission: Permission; + +// @public +export const catalogLocationReadPermission: Permission; + +// @public (undocumented) +export const RESOURCE_TYPE_CATALOG_ENTITY = 'catalog-entity'; + +// @public (undocumented) +export const RESOURCE_TYPE_CATALOG_LOCATION = 'catalog-location'; +``` diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json new file mode 100644 index 0000000000..439a76fe58 --- /dev/null +++ b/plugins/catalog-common/package.json @@ -0,0 +1,41 @@ +{ + "name": "@backstage/plugin-catalog-common", + "description": "Common functionalities for the catalog plugin", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": false, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "module": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/catalog-common" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "build": "backstage-cli build", + "lint": "backstage-cli lint", + "test": "backstage-cli test --passWithNoTests", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", + "clean": "backstage-cli clean" + }, + "dependencies": { + "@backstage/plugin-permission-common": "^0.2.0" + }, + "devDependencies": { + "@backstage/cli": "^0.10.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/catalog-common/src/index.ts b/plugins/catalog-common/src/index.ts new file mode 100644 index 0000000000..a38a5ed93b --- /dev/null +++ b/plugins/catalog-common/src/index.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * Provides shared objects useful for interacting with the catalog and its + * entities, such as catalog permissions. + * + * @packageDocumentation + */ + +export { + RESOURCE_TYPE_CATALOG_ENTITY, + RESOURCE_TYPE_CATALOG_LOCATION, + catalogEntityReadPermission, + catalogEntityDeletePermission, + catalogEntityRefreshPermission, + catalogLocationReadPermission, + catalogLocationCreatePermission, + catalogLocationDeletePermission, +} from './permissions'; diff --git a/plugins/catalog-common/src/permissions.ts b/plugins/catalog-common/src/permissions.ts new file mode 100644 index 0000000000..eb7b01c31e --- /dev/null +++ b/plugins/catalog-common/src/permissions.ts @@ -0,0 +1,113 @@ +/* + * 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 { Permission } from '@backstage/plugin-permission-common'; + +/** + * {@link https://backstage.io/docs/features/software-catalog/software-catalog-overview} + * @public + */ +export const RESOURCE_TYPE_CATALOG_ENTITY = 'catalog-entity'; + +/** + * {@link https://backstage.io/docs/features/software-catalog/descriptor-format#kind-location} + * @public + */ +export const RESOURCE_TYPE_CATALOG_LOCATION = 'catalog-location'; + +/** + * This permission is used to authorize actions that involve reading one or more + * entities from the catalog. + * + * If this permission is not authorized, it will appear that the entity does not + * exist in the catalog β€” both in the frontend and in API responses. + * @public + */ +export const catalogEntityReadPermission: Permission = { + name: 'catalog.entity.read', + attributes: { + action: 'read', + }, + resourceType: RESOURCE_TYPE_CATALOG_ENTITY, +}; + +/** + * This permission is used to designate actions that involve removing one or + * more entities from the catalog. + * @public + */ +export const catalogEntityDeletePermission: Permission = { + name: 'catalog.entity.delete', + attributes: { + action: 'delete', + }, + resourceType: RESOURCE_TYPE_CATALOG_ENTITY, +}; + +/** + * This permission is used to designate refreshing one or more entities from the + * catalog. + * @public + */ +export const catalogEntityRefreshPermission: Permission = { + name: 'catalog.entity.refresh', + attributes: { + action: 'update', + }, + resourceType: RESOURCE_TYPE_CATALOG_ENTITY, +}; + +/** + * This permission is used to designate actions that involve reading one or more + * locations from the catalog. + * + * If this permission is not authorized, it will appear that the location does + * not exist in the catalog β€” both in the frontend and in API responses. + * @public + */ +export const catalogLocationReadPermission: Permission = { + name: 'catalog.location.read', + attributes: { + action: 'read', + }, + resourceType: RESOURCE_TYPE_CATALOG_LOCATION, +}; + +/** + * This permission is used to designate actions that involve creating catalog + * locations. + * @public + */ +export const catalogLocationCreatePermission: Permission = { + name: 'catalog.location.create', + attributes: { + action: 'create', + }, + resourceType: RESOURCE_TYPE_CATALOG_LOCATION, +}; + +/** + * This permission is used to designate actions that involve deleting locations + * from the catalog. + * @public + */ +export const catalogLocationDeletePermission: Permission = { + name: 'catalog.location.delete', + attributes: { + action: 'delete', + }, + resourceType: RESOURCE_TYPE_CATALOG_LOCATION, +}; diff --git a/plugins/catalog-common/src/setupTests.ts b/plugins/catalog-common/src/setupTests.ts new file mode 100644 index 0000000000..fb7d1a181a --- /dev/null +++ b/plugins/catalog-common/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export {}; From 2a374057f59bc94240d9a2ddc3434478e2f3dfac Mon Sep 17 00:00:00 2001 From: Reinoud Kruithof <2184455+reinoudk@users.noreply.github.com> Date: Thu, 16 Dec 2021 16:49:59 +0100 Subject: [PATCH 179/189] fix(user-settings): use non-deprecated IdentityApi methods This fixes the undefined identity error that is being thrown on the user-settings page. Signed-off-by: Reinoud Kruithof <2184455+reinoudk@users.noreply.github.com> --- .changeset/cuddly-suns-sit.md | 5 +++ .../src/components/useUserProfileInfo.ts | 31 ++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 .changeset/cuddly-suns-sit.md diff --git a/.changeset/cuddly-suns-sit.md b/.changeset/cuddly-suns-sit.md new file mode 100644 index 0000000000..f1fe16add6 --- /dev/null +++ b/.changeset/cuddly-suns-sit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-user-settings': patch +--- + +Fix undefined identity bug in UserSettingsProfileCard caused by using deprecated methods of the IdentityApi diff --git a/plugins/user-settings/src/components/useUserProfileInfo.ts b/plugins/user-settings/src/components/useUserProfileInfo.ts index 336ea34ee4..075dead332 100644 --- a/plugins/user-settings/src/components/useUserProfileInfo.ts +++ b/plugins/user-settings/src/components/useUserProfileInfo.ts @@ -14,13 +14,36 @@ * limitations under the License. */ -import { useApi, identityApiRef } from '@backstage/core-plugin-api'; +import { + useApi, + identityApiRef, + BackstageUserIdentity, + ProfileInfo, +} from '@backstage/core-plugin-api'; +import { useEffect, useState } from 'react'; export const useUserProfile = () => { const identityApi = useApi(identityApiRef); - const userId = identityApi.getUserId(); - const profile = identityApi.getProfile(); - const displayName = profile.displayName ?? userId; + + const [displayName, setDisplayName] = useState< + string | BackstageUserIdentity + >(''); + const [profile, setProfile] = useState({}); + + const getUserProfile = async () => { + const backstageIdentity = await identityApi.getBackstageIdentity(); + const profileInfo = await identityApi.getProfileInfo(); + const name = profileInfo.displayName ?? backstageIdentity; + + setDisplayName(name); + setProfile(profileInfo); + }; + + useEffect(() => { + if (!displayName) { + getUserProfile(); + } + }); return { profile, displayName }; }; From 85b844585c83e8d29b45d1f0f6272b7b471d7bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 16 Dec 2021 21:27:21 +0100 Subject: [PATCH 180/189] fixup api report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik AdelΓΆw --- packages/backend-common/api-report.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/backend-common/api-report.md b/packages/backend-common/api-report.md index e623f656ab..fae460c856 100644 --- a/packages/backend-common/api-report.md +++ b/packages/backend-common/api-report.md @@ -21,6 +21,7 @@ import { GitLabIntegration } from '@backstage/integration'; import { isChildPath } from '@backstage/cli-common'; import { JsonValue } from '@backstage/types'; import { Knex } from 'knex'; +import { LoadConfigOptionsRemote } from '@backstage/config-loader'; import { Logger as Logger_2 } from 'winston'; import { MergeResult } from 'isomorphic-git'; import { PushResult } from 'isomorphic-git'; @@ -389,6 +390,7 @@ export function isDatabaseConflictError(e: unknown): boolean; // @public export function loadBackendConfig(options: { logger: Logger_2; + remote?: LoadConfigOptionsRemote; argv: string[]; }): Promise; From 24a67e3e2e327792a1c6733eeff9c7fd721af090 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 17 Dec 2021 00:48:03 +0100 Subject: [PATCH 181/189] auth-backend: fix identity fallback to populate userEntityRef correctly Signed-off-by: Patrik Oldsberg --- .changeset/rare-ladybugs-invite.md | 5 ++ .../src/lib/oauth/OAuthAdapter.test.ts | 90 ++++++++++++++++++- .../src/lib/oauth/OAuthAdapter.ts | 13 ++- 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 .changeset/rare-ladybugs-invite.md diff --git a/.changeset/rare-ladybugs-invite.md b/.changeset/rare-ladybugs-invite.md new file mode 100644 index 0000000000..4153363b9c --- /dev/null +++ b/.changeset/rare-ladybugs-invite.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Fixed the fallback identity population to correctly generate an entity reference for `userEntityRef` if no token is provided. diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts index 92c76b04b7..a3fc77bc02 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts @@ -17,7 +17,7 @@ import express from 'express'; import { THOUSAND_DAYS_MS, TEN_MINUTES_MS, OAuthAdapter } from './OAuthAdapter'; import { encodeState } from './helpers'; -import { OAuthHandlers } from './types'; +import { OAuthHandlers, OAuthResponse } from './types'; const mockResponseData = { providerInfo: { @@ -36,6 +36,12 @@ const mockResponseData = { }, }; +function mkTokenBody(payload: unknown): string { + return Buffer.from(JSON.stringify(payload), 'utf8') + .toString('base64') + .replace(/=/g, ''); +} + describe('OAuthAdapter', () => { class MyAuthProvider implements OAuthHandlers { async start() { @@ -249,4 +255,86 @@ describe('OAuthAdapter', () => { 'Refresh token is not supported for provider test-provider', ); }); + + it('correctly populates incomplete identities', async () => { + const mockRefresh = jest.fn, [express.Request]>(); + + const oauthProvider = new OAuthAdapter( + { + refresh: mockRefresh, + start: jest.fn(), + handler: jest.fn(), + } as OAuthHandlers, + { + ...oAuthProviderOptions, + tokenIssuer: { + issueToken: async ({ claims }) => `a.${mkTokenBody(claims)}.a`, + listPublicKeys: async () => ({ keys: [] }), + }, + disableRefresh: false, + isOriginAllowed: () => false, + }, + ); + + const mockRequest = { + header: () => 'XMLHttpRequest', + cookies: { + 'test-provider-refresh-token': 'token', + }, + query: {}, + } as unknown as express.Request; + + const mockResponse = { + json: jest.fn().mockReturnThis(), + status: jest.fn().mockReturnThis(), + } as unknown as express.Response; + + // Without a token + mockRefresh.mockResolvedValueOnce({ + ...mockResponseData, + backstageIdentity: { + id: 'foo', + token: '', + }, + }); + await oauthProvider.refresh(mockRequest, mockResponse); + expect(mockResponse.json).toHaveBeenCalledTimes(1); + expect(mockResponse.json).toHaveBeenLastCalledWith({ + ...mockResponseData, + backstageIdentity: { + id: 'foo', + token: `a.${mkTokenBody({ sub: 'user:default/foo' })}.a`, + idToken: `a.${mkTokenBody({ sub: 'user:default/foo' })}.a`, + identity: { + type: 'user', + userEntityRef: 'user:default/foo', + ownershipEntityRefs: [], + }, + }, + }); + + // With a token + mockRefresh.mockResolvedValueOnce({ + ...mockResponseData, + backstageIdentity: { + id: 'foo', + token: `z.${mkTokenBody({ sub: 'user:my-ns/foo' })}.z`, + }, + }); + await oauthProvider.refresh(mockRequest, mockResponse); + expect(mockResponse.json).toHaveBeenCalledTimes(2); + expect(mockResponse.json).toHaveBeenLastCalledWith({ + ...mockResponseData, + backstageIdentity: { + id: 'foo', + token: `z.${mkTokenBody({ sub: 'user:my-ns/foo' })}.z`, + idToken: `z.${mkTokenBody({ sub: 'user:my-ns/foo' })}.z`, + identity: { + type: 'user', + userEntityRef: 'user:my-ns/foo', + ownershipEntityRefs: [], + }, + }, + }); + }); }); diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index eb3f7efa42..4d5d507aa1 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -17,6 +17,11 @@ import express from 'express'; import crypto from 'crypto'; import { URL } from 'url'; +import { + ENTITY_DEFAULT_NAMESPACE, + parseEntityRef, + stringifyEntityRef, +} from '@backstage/catalog-model'; import { AuthProviderRouteHandlers, AuthProviderConfig, @@ -243,8 +248,14 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { return prepareBackstageIdentityResponse(identity); } + const userEntityRef = stringifyEntityRef( + parseEntityRef(identity.id, { + defaultKind: 'user', + defaultNamespace: ENTITY_DEFAULT_NAMESPACE, + }), + ); const token = await this.options.tokenIssuer.issueToken({ - claims: { sub: identity.id }, + claims: { sub: userEntityRef }, }); return prepareBackstageIdentityResponse({ ...identity, token }); From bc3695fe7ab6e3fbb88caf4f66ec15407e5fcee0 Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Fri, 17 Dec 2021 02:39:54 +0100 Subject: [PATCH 182/189] remobe base response model and throw an error if jenkins:rebuild fails Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- plugins/jenkins/src/api/JenkinsApi.ts | 14 +++++++++---- .../BuildsPage/lib/CITable/CITable.tsx | 21 +++++++++---------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/plugins/jenkins/src/api/JenkinsApi.ts b/plugins/jenkins/src/api/JenkinsApi.ts index 48e506953f..ce63f84f13 100644 --- a/plugins/jenkins/src/api/JenkinsApi.ts +++ b/plugins/jenkins/src/api/JenkinsApi.ts @@ -20,6 +20,8 @@ import { IdentityApi, } from '@backstage/core-plugin-api'; import type { EntityName, EntityRef } from '@backstage/catalog-model'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { ResponseError } from '@backstage/errors'; export const jenkinsApiRef = createApiRef({ id: 'plugin.jenkins.service2', @@ -66,7 +68,7 @@ export interface Project { inQueue: string; // added by us status: string; // == inQueue ? 'queued' : lastBuild.building ? 'running' : lastBuild.result, - onRestartClick: () => Promise; // TODO rename to handle.* ? also, should this be on lastBuild? + onRestartClick: () => Promise; // TODO rename to handle.* ? also, should this be on lastBuild? } export interface JenkinsApi { @@ -106,7 +108,7 @@ export interface JenkinsApi { entity: EntityName; jobFullName: string; buildNumber: string; - }): Promise; + }): Promise; } export class JenkinsClient implements JenkinsApi { @@ -198,7 +200,7 @@ export class JenkinsClient implements JenkinsApi { entity: EntityName; jobFullName: string; buildNumber: string; - }): Promise { + }): Promise { const url = `${await this.discoveryApi.getBaseUrl( 'jenkins', )}/v1/entity/${encodeURIComponent(entity.namespace)}/${encodeURIComponent( @@ -208,12 +210,16 @@ export class JenkinsClient implements JenkinsApi { )}/${encodeURIComponent(buildNumber)}:rebuild`; const idToken = await this.getToken(); - return fetch(url, { + const response = await fetch(url, { method: 'POST', headers: { ...(idToken && { Authorization: `Bearer ${idToken}` }), }, }); + + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } } private async getToken() { diff --git a/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx index e14b24912b..cbc46248cf 100644 --- a/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx +++ b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx @@ -24,6 +24,8 @@ import { buildRouteRef } from '../../../../plugin'; import { Progress, Table, TableColumn } from '@backstage/core-components'; import { Project } from '../../../../api/JenkinsApi'; import { alertApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { ResponseError } from '@backstage/errors'; const FailCount = ({ count }: { count: number }): JSX.Element | null => { if (count !== 0) { @@ -182,20 +184,17 @@ const generatedColumns: TableColumn[] = [ if (row.onRestartClick) { setIsLoadingRebuild(true); try { - const response = await row.onRestartClick(); - const body = (await response.json()) as { - error?: { message: string }; - }; - if (response.status !== 200) { + await row.onRestartClick(); + alertApi.post({ + message: 'Jenkins re-build has been successfully executed', + severity: 'success', + }); + } catch (e) { + if (e instanceof ResponseError) { alertApi.post({ - message: `Jenkins re-build has been failed. Reason: ${body.error?.message}`, + message: `Jenkins re-build has been failed. Error: ${e.message}`, severity: 'error', }); - } else { - alertApi.post({ - message: 'Jenkins re-build has been successfully executed', - severity: 'success', - }); } } finally { setIsLoadingRebuild(false); From 76676422a6b50f3d6f76fff00ed7f2b8dd302323 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Dec 2021 04:08:23 +0000 Subject: [PATCH 183/189] build(deps): bump sucrase from 3.20.2 to 3.20.3 Bumps [sucrase](https://github.com/alangpierce/sucrase) from 3.20.2 to 3.20.3. - [Release notes](https://github.com/alangpierce/sucrase/releases) - [Changelog](https://github.com/alangpierce/sucrase/blob/main/CHANGELOG.md) - [Commits](https://github.com/alangpierce/sucrase/commits) --- updated-dependencies: - dependency-name: sucrase dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- yarn.lock | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/yarn.lock b/yarn.lock index cca08863df..e300785cd4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15877,19 +15877,7 @@ glob@^6.0.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: - version "7.1.7" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.2.0: +glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7, glob@^7.2.0: version "7.2.0" resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -27229,9 +27217,9 @@ subscriptions-transport-ws@^0.9.18, subscriptions-transport-ws@^0.9.19: ws "^5.2.0 || ^6.0.0 || ^7.0.0" sucrase@^3.18.0, sucrase@^3.20.2: - version "3.20.2" - resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.20.2.tgz#28a28dc58a55be0d6916d5c9b2440d203e9ffe62" - integrity sha512-EdJ5M6VEvToIZwIWiZ71cxe4CklDRG8PdSjUSst+BZCUGlaEhnrdQo/LOXsuq3MjWRbfepg1XTffClK0Tmo0HQ== + version "3.20.3" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.20.3.tgz#424f1e75b77f955724b06060f1ae708f5f0935cf" + integrity sha512-azqwq0/Bs6RzLAdb4dXxsCgMtAaD2hzmUr4UhSfsxO46JFPAwMnnb441B/qsudZiS6Ylea3JXZe3Q497lsgXzQ== dependencies: commander "^4.0.0" glob "7.1.6" From 047d92db5e185480ee7edcc9f5815f3cc8adb98e Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Fri, 17 Dec 2021 11:38:19 +0100 Subject: [PATCH 184/189] improve success and fail messages, re-generated api reports Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- plugins/jenkins/api-report.md | 4 ++-- .../jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/jenkins/api-report.md b/plugins/jenkins/api-report.md index 829256e22d..a6926c1639 100644 --- a/plugins/jenkins/api-report.md +++ b/plugins/jenkins/api-report.md @@ -72,7 +72,7 @@ export interface JenkinsApi { entity: EntityName; jobFullName: string; buildNumber: string; - }): Promise; + }): Promise; } // Warning: (ae-missing-release-tag) "jenkinsApiRef" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -117,7 +117,7 @@ export class JenkinsClient implements JenkinsApi { entity: EntityName; jobFullName: string; buildNumber: string; - }): Promise; + }): Promise; } // Warning: (ae-missing-release-tag) "jenkinsPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx index cbc46248cf..34afbc7198 100644 --- a/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx +++ b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx @@ -186,13 +186,13 @@ const generatedColumns: TableColumn[] = [ try { await row.onRestartClick(); alertApi.post({ - message: 'Jenkins re-build has been successfully executed', + message: 'Jenkins re-build has successfully executed', severity: 'success', }); } catch (e) { if (e instanceof ResponseError) { alertApi.post({ - message: `Jenkins re-build has been failed. Error: ${e.message}`, + message: `Jenkins re-build has failed. Error: ${e.message}`, severity: 'error', }); } From 375ed38b167156c529fe5e8db441ec3a62b79ef7 Mon Sep 17 00:00:00 2001 From: Reinoud Kruithof <2184455+reinoudk@users.noreply.github.com> Date: Fri, 17 Dec 2021 11:31:51 +0100 Subject: [PATCH 185/189] feat(user-settings): use useAsync and return loading status Signed-off-by: Reinoud Kruithof <2184455+reinoudk@users.noreply.github.com> --- plugins/user-settings/api-report.md | 1 + .../src/components/useUserProfileInfo.ts | 45 ++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/plugins/user-settings/api-report.md b/plugins/user-settings/api-report.md index a801f2e807..0d8f132f37 100644 --- a/plugins/user-settings/api-report.md +++ b/plugins/user-settings/api-report.md @@ -119,5 +119,6 @@ export const UserSettingsThemeToggle: () => JSX.Element; export const useUserProfile: () => { profile: ProfileInfo; displayName: string; + loading: boolean; }; ``` diff --git a/plugins/user-settings/src/components/useUserProfileInfo.ts b/plugins/user-settings/src/components/useUserProfileInfo.ts index 075dead332..fbc7b92dcb 100644 --- a/plugins/user-settings/src/components/useUserProfileInfo.ts +++ b/plugins/user-settings/src/components/useUserProfileInfo.ts @@ -15,35 +15,38 @@ */ import { - useApi, + alertApiRef, identityApiRef, - BackstageUserIdentity, - ProfileInfo, + useApi, } from '@backstage/core-plugin-api'; -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; +import { useAsync } from 'react-use'; export const useUserProfile = () => { const identityApi = useApi(identityApiRef); + const alertApi = useApi(alertApiRef); - const [displayName, setDisplayName] = useState< - string | BackstageUserIdentity - >(''); - const [profile, setProfile] = useState({}); - - const getUserProfile = async () => { - const backstageIdentity = await identityApi.getBackstageIdentity(); - const profileInfo = await identityApi.getProfileInfo(); - const name = profileInfo.displayName ?? backstageIdentity; - - setDisplayName(name); - setProfile(profileInfo); - }; + const { value, loading, error } = useAsync(async () => { + return { + profile: await identityApi.getProfileInfo(), + identity: await identityApi.getBackstageIdentity(), + }; + }, []); useEffect(() => { - if (!displayName) { - getUserProfile(); + if (error) { + alertApi.post({ + message: `Failed to load user identity: ${error}`, + severity: "error", + }); } - }); + }, [error, alertApi]); - return { profile, displayName }; + return { + profile: loading ? {} : value!.profile, + displayName: loading + ? '' + : value!.profile.displayName ?? value!.identity.userEntityRef, + loading, + }; }; From 7e889bfb30c100a592623cea69d2f5a6869cd3d4 Mon Sep 17 00:00:00 2001 From: Reinoud Kruithof <2184455+reinoudk@users.noreply.github.com> Date: Fri, 17 Dec 2021 15:12:30 +0100 Subject: [PATCH 186/189] fix(user-settings): prevent using undefined value Signed-off-by: Reinoud Kruithof <2184455+reinoudk@users.noreply.github.com> --- .../src/components/useUserProfileInfo.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/plugins/user-settings/src/components/useUserProfileInfo.ts b/plugins/user-settings/src/components/useUserProfileInfo.ts index fbc7b92dcb..6f9b5c154e 100644 --- a/plugins/user-settings/src/components/useUserProfileInfo.ts +++ b/plugins/user-settings/src/components/useUserProfileInfo.ts @@ -17,6 +17,7 @@ import { alertApiRef, identityApiRef, + ProfileInfo, useApi, } from '@backstage/core-plugin-api'; import { useEffect } from 'react'; @@ -37,16 +38,22 @@ export const useUserProfile = () => { if (error) { alertApi.post({ message: `Failed to load user identity: ${error}`, - severity: "error", + severity: 'error', }); } }, [error, alertApi]); + if (loading || error) { + return { + profile: {} as ProfileInfo, + displayName: '', + loading, + }; + } + return { - profile: loading ? {} : value!.profile, - displayName: loading - ? '' - : value!.profile.displayName ?? value!.identity.userEntityRef, + profile: value!.profile, + displayName: value!.profile.displayName ?? value!.identity.userEntityRef, loading, }; }; From ff9ace4d2a903469c205e4b3061683c078b74f8b Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 17 Dec 2021 15:39:07 +0100 Subject: [PATCH 187/189] chore: added some readme notes Signed-off-by: blam --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 1078631926..3e91cfe7c3 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ # [Backstage](https://backstage.io) +> πŸŽ„ The maintainers will be taking a break over the holidays from week beginning 20th Dec. The Repository and Discord may be quieter than usual. We will be back next year, rested and restored, on Jan. 3. πŸŽ„ + +> πŸŽ… Happy holidays and a Happy New Year to all, and especially those that have made this year special for Backstage! πŸŽ… + [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![CNCF Status](https://img.shields.io/badge/cncf%20status-sandbox-blue.svg)](https://www.cncf.io/projects) [![Main CI Build](https://github.com/backstage/backstage/workflows/Main%20Master%20Build/badge.svg)](https://github.com/backstage/backstage/actions?query=workflow%3A%22Main+Master+Build%22) From 01e1f746f1e70621f48e87bfd33553efc6481519 Mon Sep 17 00:00:00 2001 From: goenning Date: Fri, 17 Dec 2021 15:10:48 +0000 Subject: [PATCH 188/189] update docs Signed-off-by: goenning --- .../writing-custom-field-extensions.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/features/software-templates/writing-custom-field-extensions.md b/docs/features/software-templates/writing-custom-field-extensions.md index ebb7af4398..fab2e1e2cb 100644 --- a/docs/features/software-templates/writing-custom-field-extensions.md +++ b/docs/features/software-templates/writing-custom-field-extensions.md @@ -26,7 +26,7 @@ You can create your own Field Extension by using the `API` like below: ```tsx -//packages/app/scaffolder/MyCustomExtension/MyCustomExtension.tsx +//packages/app/src/scaffolder/MyCustomExtension/MyCustomExtension.tsx import React from 'react'; import { FieldProps, FieldValidation } from '@rjsf/core'; import FormControl from '@material-ui/core/FormControl'; @@ -68,7 +68,7 @@ export const myCustomValidation = ( ``` ```tsx -// packages/app/scaffolder/MyCustomExtension/extensions.ts +// packages/app/src/scaffolder/MyCustomExtension/extensions.ts /* This is where the magic happens and creates the custom field extension. @@ -94,7 +94,7 @@ export const MyCustomFieldExtension = plugin.provide( ``` ```tsx -// packages/app/scaffolder/MyCustomExtension/index.ts +// packages/app/src/scaffolder/MyCustomExtension/index.ts export { MyCustomFieldExtension } from './extension'; ``` @@ -102,7 +102,7 @@ export { MyCustomFieldExtension } from './extension'; Once all these files are in place, you then need to provide your custom extension to the `scaffolder` plugin. -You do this in `packages/app/App.tsx`. You need to provide the +You do this in `packages/app/src/App.tsx`. You need to provide the `customFieldExtensions` as children to the `ScaffolderPage`. ```tsx @@ -118,7 +118,7 @@ const routes = ( Should look something like this instead: ```tsx -import { MyCustomFieldExtension } from './scafffolder/MyCustomExtension'; +import { MyCustomFieldExtension } from './scaffolder/MyCustomExtension'; const routes = ( ... From d03ee9e28f0c32e6ad36ddca4eb7adbe592f74ae Mon Sep 17 00:00:00 2001 From: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> Date: Sat, 18 Dec 2021 19:10:15 +0100 Subject: [PATCH 189/189] feature: remove instanceof check from CITable, add @backstage/errors to jenkins plugin to resolve eslint related issues Signed-off-by: Hasan Ozdemir <21654050+nodify-at@users.noreply.github.com> --- plugins/jenkins/package.json | 1 + plugins/jenkins/src/api/JenkinsApi.ts | 1 - .../components/BuildsPage/lib/CITable/CITable.tsx | 12 ++++-------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index 5822a262b5..862c2cdfb3 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -35,6 +35,7 @@ "@backstage/catalog-model": "^0.9.7", "@backstage/core-components": "^0.8.1", "@backstage/core-plugin-api": "^0.3.1", + "@backstage/errors": "^0.1.5", "@backstage/plugin-catalog-react": "^0.6.5", "@backstage/theme": "^0.2.14", "@material-ui/core": "^4.12.2", diff --git a/plugins/jenkins/src/api/JenkinsApi.ts b/plugins/jenkins/src/api/JenkinsApi.ts index ce63f84f13..33edf0ade3 100644 --- a/plugins/jenkins/src/api/JenkinsApi.ts +++ b/plugins/jenkins/src/api/JenkinsApi.ts @@ -20,7 +20,6 @@ import { IdentityApi, } from '@backstage/core-plugin-api'; import type { EntityName, EntityRef } from '@backstage/catalog-model'; -// eslint-disable-next-line import/no-extraneous-dependencies import { ResponseError } from '@backstage/errors'; export const jenkinsApiRef = createApiRef({ diff --git a/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx index 34afbc7198..a959ba39c9 100644 --- a/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx +++ b/plugins/jenkins/src/components/BuildsPage/lib/CITable/CITable.tsx @@ -24,8 +24,6 @@ import { buildRouteRef } from '../../../../plugin'; import { Progress, Table, TableColumn } from '@backstage/core-components'; import { Project } from '../../../../api/JenkinsApi'; import { alertApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { ResponseError } from '@backstage/errors'; const FailCount = ({ count }: { count: number }): JSX.Element | null => { if (count !== 0) { @@ -190,12 +188,10 @@ const generatedColumns: TableColumn[] = [ severity: 'success', }); } catch (e) { - if (e instanceof ResponseError) { - alertApi.post({ - message: `Jenkins re-build has failed. Error: ${e.message}`, - severity: 'error', - }); - } + alertApi.post({ + message: `Jenkins re-build has failed. Error: ${e.message}`, + severity: 'error', + }); } finally { setIsLoadingRebuild(false); }