From 722c8a9e8af503e1a0952cbc3c393265628d834a Mon Sep 17 00:00:00 2001 From: Marek Calus Date: Sun, 25 Oct 2020 20:50:43 +0100 Subject: [PATCH 01/33] Cleanup after refactoring of plugins --- packages/app/src/apis.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/packages/app/src/apis.ts b/packages/app/src/apis.ts index c129bebfa2..567ac13c78 100644 --- a/packages/app/src/apis.ts +++ b/packages/app/src/apis.ts @@ -25,16 +25,6 @@ import { GraphQLEndpoints, } from '@backstage/plugin-graphiql'; -import { - TravisCIApi, - travisCIApiRef, -} from '@roadiehq/backstage-plugin-travis-ci'; - -import { - GithubPullRequestsClient, - githubPullRequestsApiRef, -} from '@roadiehq/backstage-plugin-github-pull-requests'; - import { costInsightsApiRef } from '@backstage/plugin-cost-insights'; import { ExampleCostInsightsClient } from './plugins/cost-insights'; @@ -59,8 +49,4 @@ export const apis = [ }), createApiFactory(costInsightsApiRef, new ExampleCostInsightsClient()), - - // TODO: move to plugins - createApiFactory(travisCIApiRef, new TravisCIApi()), - createApiFactory(githubPullRequestsApiRef, new GithubPullRequestsClient()), ]; From e7f5471fde971b8381a9963e7a8d86fe6107262b Mon Sep 17 00:00:00 2001 From: Marek Calus Date: Sun, 25 Oct 2020 20:55:43 +0100 Subject: [PATCH 02/33] Add changeset --- .changeset/sweet-bikes-battle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sweet-bikes-battle.md diff --git a/.changeset/sweet-bikes-battle.md b/.changeset/sweet-bikes-battle.md new file mode 100644 index 0000000000..68ed8caeeb --- /dev/null +++ b/.changeset/sweet-bikes-battle.md @@ -0,0 +1,5 @@ +--- +'example-app': patch +--- + +cleaning up because external plugins have already implemented new api for creating From fd910e9560e40f98e7791cd5e2bc12b563d354bb Mon Sep 17 00:00:00 2001 From: Marek Calus Date: Sun, 25 Oct 2020 23:50:37 +0100 Subject: [PATCH 03/33] Bump travis-ci package version --- packages/app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/package.json b/packages/app/package.json index dc452e0803..e047e0e4a9 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -36,7 +36,7 @@ "@octokit/rest": "^18.0.0", "@roadiehq/backstage-plugin-github-insights": "^0.2.7", "@roadiehq/backstage-plugin-github-pull-requests": "^0.5.2", - "@roadiehq/backstage-plugin-travis-ci": "^0.2.3", + "@roadiehq/backstage-plugin-travis-ci": "^0.2.5", "dayjs": "^1.9.1", "history": "^5.0.0", "prop-types": "^15.7.2", From f09e6eb4ce308431cb2668e96412b292630aaba1 Mon Sep 17 00:00:00 2001 From: Fabian Chong Date: Mon, 26 Oct 2020 13:35:25 +0800 Subject: [PATCH 04/33] Add tsconfig to non monorepo plugin. --- packages/cli/src/commands/plugin/diff.ts | 6 +----- packages/cli/src/lib/tasks.ts | 6 ++++++ packages/cli/templates/default-plugin/tsconfig.json | 13 +++++++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 packages/cli/templates/default-plugin/tsconfig.json diff --git a/packages/cli/src/commands/plugin/diff.ts b/packages/cli/src/commands/plugin/diff.ts index f5dfa670b7..012c061f74 100644 --- a/packages/cli/src/commands/plugin/diff.ts +++ b/packages/cli/src/commands/plugin/diff.ts @@ -40,17 +40,13 @@ const fileHandlers = [ patterns: ['package.json'], handler: handlers.packageJson, }, - { - patterns: ['tsconfig.json'], - handler: handlers.exactMatch, - }, { // make sure files in 1st level of src/ and dev/ exist patterns: ['.eslintrc.js', /^(src|dev)\/[^/]+$/], handler: handlers.exists, }, { - patterns: ['README.md', /^src\//], + patterns: ['README.md', 'tsconfig.json', /^src\//], handler: handlers.skip, }, ]; diff --git a/packages/cli/src/lib/tasks.ts b/packages/cli/src/lib/tasks.ts index 0753301b78..80dc1a5ed7 100644 --- a/packages/cli/src/lib/tasks.ts +++ b/packages/cli/src/lib/tasks.ts @@ -20,6 +20,7 @@ import handlebars from 'handlebars'; import ora from 'ora'; import { basename, dirname } from 'path'; import recursive from 'recursive-readdir'; +import { paths } from './paths'; const TASK_NAME_MAX_LENGTH = 14; @@ -72,6 +73,7 @@ export async function templatingTask( const files = await recursive(templateDir).catch(error => { throw new Error(`Failed to read template directory: ${error.message}`); }); + const isMonoRepo = await fs.pathExists(paths.resolveTargetRoot('lerna.json')); for (const file of files) { const destinationFile = file.replace(templateDir, destinationDir); @@ -92,6 +94,10 @@ export async function templatingTask( }); }); } else { + if (isMonoRepo && file.match('tsconfig.json')) { + continue; + } + await Task.forItem('copying', basename(file), async () => { await fs.copyFile(file, destinationFile).catch(error => { const destination = destinationFile; diff --git a/packages/cli/templates/default-plugin/tsconfig.json b/packages/cli/templates/default-plugin/tsconfig.json new file mode 100644 index 0000000000..d77f0fe3b4 --- /dev/null +++ b/packages/cli/templates/default-plugin/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@backstage/cli/config/tsconfig.json", + "include": [ + "src", + "dev", + "migrations" + ], + "exclude": ["node_modules"], + "compilerOptions": { + "outDir": "dist-types", + "rootDir": "." + } +} From 36a71d2780b2d355936542409eec1bc3a4a2a558 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 26 Oct 2020 15:46:22 +0100 Subject: [PATCH 05/33] catalog-backend: removed deprecated location processors --- .changeset/polite-laws-think.md | 5 + .../templates/default-app/app-config.yaml.hbs | 22 +- .../processors/AzureApiReaderProcessor.ts | 146 ---------- .../processors/BitbucketApiReaderProcessor.ts | 138 --------- .../processors/GithubReaderProcessor.ts | 274 ------------------ .../processors/GitlabApiReaderProcessor.ts | 141 --------- .../processors/GitlabReaderProcessor.ts | 94 ------ .../src/ingestion/processors/index.ts | 5 - .../src/service/CatalogBuilder.ts | 38 +-- 9 files changed, 26 insertions(+), 837 deletions(-) create mode 100644 .changeset/polite-laws-think.md delete mode 100644 plugins/catalog-backend/src/ingestion/processors/AzureApiReaderProcessor.ts delete mode 100644 plugins/catalog-backend/src/ingestion/processors/BitbucketApiReaderProcessor.ts delete mode 100644 plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts delete mode 100644 plugins/catalog-backend/src/ingestion/processors/GitlabApiReaderProcessor.ts delete mode 100644 plugins/catalog-backend/src/ingestion/processors/GitlabReaderProcessor.ts diff --git a/.changeset/polite-laws-think.md b/.changeset/polite-laws-think.md new file mode 100644 index 0000000000..a5eb7f9883 --- /dev/null +++ b/.changeset/polite-laws-think.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Removed support for deprecated `catalog.providers` config that have been moved to `integrations` diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index a0b9f156ed..1f265d7e7d 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -39,6 +39,17 @@ backend: # $file: /ca/server.crt {{/if}} +integrations: + github: + - host: github.com + token: + $env: GITHUB_TOKEN + ### Example for how to add your GitHub Enterprise instance using the API: + # - host: ghe.example.net + # apiBaseUrl: https://ghe.example.net/api/v3 + # token: + # $env: GHE_TOKEN + proxy: '/test': target: 'https://example.com' @@ -66,17 +77,6 @@ scaffolder: catalog: rules: - allow: [Component, API, Group, User, Template, Location] - processors: - github: - providers: - - target: https://github.com - token: - $env: GITHUB_TOKEN - # Example for how to add your GitHub Enterprise instance: - # - target: https://ghe.example.net - # apiBaseUrl: https://ghe.example.net/api/v3 - # token: - # $env: GHE_TOKEN locations: # Backstage example components - type: url diff --git a/plugins/catalog-backend/src/ingestion/processors/AzureApiReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/AzureApiReaderProcessor.ts deleted file mode 100644 index 9b9ba586ef..0000000000 --- a/plugins/catalog-backend/src/ingestion/processors/AzureApiReaderProcessor.ts +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LocationSpec } from '@backstage/catalog-model'; - -import { Config } from '@backstage/config'; -import fetch from 'cross-fetch'; -import * as result from './results'; -import { CatalogProcessor, CatalogProcessorEmit } from './types'; - -// *********************************************************************** -// * NOTE: This has been replaced by packages/backend-common/src/reading * -// * Don't implement new functionality here as this file will be removed * -// *********************************************************************** - -export class AzureApiReaderProcessor implements CatalogProcessor { - private privateToken: string; - - constructor(config: Config) { - this.privateToken = - config.getOptionalString('catalog.processors.azureApi.privateToken') ?? - ''; - } - - getRequestOptions(): RequestInit { - const headers: HeadersInit = {}; - - if (this.privateToken !== '') { - headers.Authorization = `Basic ${Buffer.from( - `:${this.privateToken}`, - 'utf8', - ).toString('base64')}`; - } - - return { - headers, - }; - } - - async readLocation( - location: LocationSpec, - optional: boolean, - emit: CatalogProcessorEmit, - ): Promise { - if (location.type !== 'azure/api') { - return false; - } - - try { - const url = this.buildRawUrl(location.target); - - const response = await fetch(url.toString(), this.getRequestOptions()); - - // for private repos when PAT is not valid, Azure API returns a http status code 203 with sign in page html - if (response.ok && response.status !== 203) { - const data = Buffer.from(await response.text()); - emit(result.data(location, data)); - } else { - const message = `${location.target} could not be read as ${url}, ${response.status} ${response.statusText}`; - if (response.status === 404) { - if (!optional) { - emit(result.notFoundError(location, message)); - } - } else { - emit(result.generalError(location, message)); - } - } - } catch (e) { - const message = `Unable to read ${location.type} ${location.target}, ${e}`; - emit(result.generalError(location, message)); - } - return true; - } - - // Converts - // from: https://dev.azure.com/{organization}/{project}/_git/reponame?path={path}&version=GB{commitOrBranch}&_a=contents - // to: https://dev.azure.com/{organization}/{project}/_apis/git/repositories/reponame/items?path={path}&version={commitOrBranch} - buildRawUrl(target: string): URL { - try { - const url = new URL(target); - - const [ - empty, - userOrOrg, - project, - srcKeyword, - repoName, - ] = url.pathname.split('/'); - - const path = url.searchParams.get('path') || ''; - const ref = url.searchParams.get('version')?.substr(2); - - if ( - url.hostname !== 'dev.azure.com' || - empty !== '' || - userOrOrg === '' || - project === '' || - srcKeyword !== '_git' || - repoName === '' || - path === '' || - ref === '' - ) { - throw new Error('Wrong Azure Devops URL or Invalid file path'); - } - - // transform to api - url.pathname = [ - empty, - userOrOrg, - project, - '_apis', - 'git', - 'repositories', - repoName, - 'items', - ].join('/'); - - const queryParams = [`path=${path}`]; - - if (ref) { - queryParams.push(`version=${ref}`); - } - - url.search = queryParams.join('&'); - - url.protocol = 'https'; - - return url; - } catch (e) { - throw new Error(`Incorrect url: ${target}, ${e}`); - } - } -} diff --git a/plugins/catalog-backend/src/ingestion/processors/BitbucketApiReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/BitbucketApiReaderProcessor.ts deleted file mode 100644 index 337053965f..0000000000 --- a/plugins/catalog-backend/src/ingestion/processors/BitbucketApiReaderProcessor.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LocationSpec } from '@backstage/catalog-model'; -import fetch from 'cross-fetch'; -import * as result from './results'; -import { Config } from '@backstage/config'; -import { CatalogProcessor, CatalogProcessorEmit } from './types'; - -// *********************************************************************** -// * NOTE: This has been replaced by packages/backend-common/src/reading * -// * Don't implement new functionality here as this file will be removed * -// *********************************************************************** - -export class BitbucketApiReaderProcessor implements CatalogProcessor { - private username: string; - private password: string; - - constructor(config: Config) { - this.username = - config.getOptionalString('catalog.processors.bitbucketApi.username') ?? - ''; - this.password = - config.getOptionalString('catalog.processors.bitbucketApi.appPassword') ?? - ''; - } - - getRequestOptions(): RequestInit { - const headers: HeadersInit = {}; - - if (this.username !== '' && this.password !== '') { - headers.Authorization = `Basic ${Buffer.from( - `${this.username}:${this.password}`, - 'utf8', - ).toString('base64')}`; - } - - const requestOptions: RequestInit = { - headers, - }; - - return requestOptions; - } - - async readLocation( - location: LocationSpec, - optional: boolean, - emit: CatalogProcessorEmit, - ): Promise { - if (location.type !== 'bitbucket/api') { - return false; - } - - try { - const url = this.buildRawUrl(location.target); - - const response = await fetch(url.toString(), this.getRequestOptions()); - - if (response.ok) { - const data = await response.text(); - emit(result.data(location, Buffer.from(data))); - } else { - const message = `${location.target} could not be read as ${url}, ${response.status} ${response.statusText}`; - if (response.status === 404) { - if (!optional) { - emit(result.notFoundError(location, message)); - } - } else { - emit(result.generalError(location, message)); - } - } - } catch (e) { - const message = `Unable to read ${location.type} ${location.target}, ${e}`; - emit(result.generalError(location, message)); - } - return true; - } - - // Converts - // from: https://bitbucket.org/orgname/reponame/src/master/file.yaml - // to: https://api.bitbucket.org/2.0/repositories/orgname/reponame/src/master/file.yaml - - buildRawUrl(target: string): URL { - try { - const url = new URL(target); - - const [ - empty, - userOrOrg, - repoName, - srcKeyword, - ref, - ...restOfPath - ] = url.pathname.split('/'); - - if ( - url.hostname !== 'bitbucket.org' || - empty !== '' || - userOrOrg === '' || - repoName === '' || - srcKeyword !== 'src' - ) { - throw new Error('Wrong Bitbucket URL or Invalid file path'); - } - - // transform to api - url.pathname = [ - empty, - '2.0', - 'repositories', - userOrOrg, - repoName, - 'src', - ref, - ...restOfPath, - ].join('/'); - url.hostname = 'api.bitbucket.org'; - url.protocol = 'https'; - - return url; - } catch (e) { - throw new Error(`Incorrect url: ${target}, ${e}`); - } - } -} diff --git a/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts deleted file mode 100644 index fed7f2a5c2..0000000000 --- a/plugins/catalog-backend/src/ingestion/processors/GithubReaderProcessor.ts +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LocationSpec } from '@backstage/catalog-model'; -import { Config } from '@backstage/config'; -import parseGitUri from 'git-url-parse'; -import fetch from 'cross-fetch'; -import { Logger } from 'winston'; -import * as result from './results'; -import { CatalogProcessor, CatalogProcessorEmit } from './types'; - -// *********************************************************************** -// * NOTE: This has been replaced by packages/backend-common/src/reading * -// * Don't implement new functionality here as this file will be removed * -// *********************************************************************** - -/** - * The configuration parameters for a single GitHub API provider. - */ -export type ProviderConfig = { - /** - * The prefix of the target that this matches on, e.g. "https://github.com", - * with no trailing slash. - */ - target: string; - - /** - * The base URL of the API of this provider, e.g. "https://api.github.com", - * with no trailing slash. - * - * May be omitted specifically for GitHub; then it will be deduced. - * - * The API will always be preferred if both its base URL and a token are - * present. - */ - apiBaseUrl?: string; - - /** - * The base URL of the raw fetch endpoint of this provider, e.g. - * "https://raw.githubusercontent.com", with no trailing slash. - * - * May be omitted specifically for GitHub; then it will be deduced. - * - * The API will always be preferred if both its base URL and a token are - * present. - */ - rawBaseUrl?: string; - - /** - * The authorization token to use for requests to this provider. - * - * If no token is specified, anonymous access is used. - */ - token?: string; -}; - -export function getApiRequestOptions(provider: ProviderConfig): RequestInit { - const headers: HeadersInit = { - Accept: 'application/vnd.github.v3.raw', - }; - - if (provider.token) { - headers.Authorization = `token ${provider.token}`; - } - - return { - headers, - }; -} - -export function getRawRequestOptions(provider: ProviderConfig): RequestInit { - const headers: HeadersInit = {}; - - if (provider.token) { - headers.Authorization = `token ${provider.token}`; - } - - return { - headers, - }; -} - -// Converts for example -// from: https://github.com/a/b/blob/branchname/path/to/c.yaml -// to: https://api.github.com/repos/a/b/contents/path/to/c.yaml?ref=branchname -export function getApiUrl(target: string, provider: ProviderConfig): URL { - try { - const { owner, name, ref, filepathtype, filepath } = parseGitUri(target); - - if ( - !owner || - !name || - !ref || - (filepathtype !== 'blob' && filepathtype !== 'raw') - ) { - throw new Error('Wrong URL or invalid file path'); - } - - const pathWithoutSlash = filepath.replace(/^\//, ''); - return new URL( - `${provider.apiBaseUrl}/repos/${owner}/${name}/contents/${pathWithoutSlash}?ref=${ref}`, - ); - } catch (e) { - throw new Error(`Incorrect URL: ${target}, ${e}`); - } -} - -// Converts for example -// from: https://github.com/a/b/blob/branchname/c.yaml -// to: https://raw.githubusercontent.com/a/b/branchname/c.yaml -export function getRawUrl(target: string, provider: ProviderConfig): URL { - try { - const { owner, name, ref, filepathtype, filepath } = parseGitUri(target); - - if ( - !owner || - !name || - !ref || - (filepathtype !== 'blob' && filepathtype !== 'raw') - ) { - throw new Error('Wrong URL or invalid file path'); - } - - const pathWithoutSlash = filepath.replace(/^\//, ''); - return new URL( - `${provider.rawBaseUrl}/${owner}/${name}/${ref}/${pathWithoutSlash}`, - ); - } catch (e) { - throw new Error(`Incorrect URL: ${target}, ${e}`); - } -} - -export function readConfig(config: Config, logger: Logger): ProviderConfig[] { - const providers: ProviderConfig[] = []; - - // TODO(freben): Deprecate the old config root entirely in a later release - if (config.has('catalog.processors.githubApi')) { - logger.warn( - 'The catalog.processors.githubApi configuration key has been deprecated, please use catalog.processors.github instead', - ); - } - - // In a previous version of the configuration, we only supported github, - // and the "privateToken" key held the token to use for it. The new - // configuration method is to use the "providers" key instead. - const providerConfigs = - config.getOptionalConfigArray('catalog.processors.github.providers') ?? - config.getOptionalConfigArray('catalog.processors.githubApi.providers') ?? - []; - const legacyToken = - config.getOptionalString('catalog.processors.github.privateToken') ?? - config.getOptionalString('catalog.processors.githubApi.privateToken'); - - // First read all the explicit providers - for (const providerConfig of providerConfigs) { - const target = providerConfig.getString('target').replace(/\/+$/, ''); - let apiBaseUrl = providerConfig.getOptionalString('apiBaseUrl'); - let rawBaseUrl = providerConfig.getOptionalString('rawBaseUrl'); - const token = providerConfig.getOptionalString('token'); - - if (apiBaseUrl) { - apiBaseUrl = apiBaseUrl.replace(/\/+$/, ''); - } else if (target === 'https://github.com') { - apiBaseUrl = 'https://api.github.com'; - } - - if (rawBaseUrl) { - rawBaseUrl = rawBaseUrl.replace(/\/+$/, ''); - } else if (target === 'https://github.com') { - rawBaseUrl = 'https://raw.githubusercontent.com'; - } - - if (!apiBaseUrl && !rawBaseUrl) { - throw new Error( - `Provider at ${target} must configure an explicit apiBaseUrl or rawBaseUrl`, - ); - } - - providers.push({ target, apiBaseUrl, rawBaseUrl, token }); - } - - // If no explicit github.com provider was added, put one in the list as - // a convenience - if (!providers.some(p => p.target === 'https://github.com')) { - providers.push({ - target: 'https://github.com', - apiBaseUrl: 'https://api.github.com', - rawBaseUrl: 'https://raw.githubusercontent.com', - token: legacyToken, - }); - } - - return providers; -} - -/** - * A processor that adds the ability to read files from GitHub v3 APIs, such as - * the one exposed by GitHub itself. - */ -export class GithubReaderProcessor implements CatalogProcessor { - private providers: ProviderConfig[]; - - static fromConfig(config: Config, logger: Logger) { - return new GithubReaderProcessor(readConfig(config, logger)); - } - - constructor(providers: ProviderConfig[]) { - this.providers = providers; - } - - async readLocation( - location: LocationSpec, - optional: boolean, - emit: CatalogProcessorEmit, - ): Promise { - // The github/api type is for backward compatibility - if (location.type !== 'github' && location.type !== 'github/api') { - return false; - } - - const provider = this.providers.find(p => - location.target.startsWith(`${p.target}/`), - ); - if (!provider) { - throw new Error( - `There is no GitHub provider that matches ${location.target}. Please add a configuration entry for it under catalog.processors.github.providers.`, - ); - } - - try { - const useApi = - provider.apiBaseUrl && (provider.token || !provider.rawBaseUrl); - const url = useApi - ? getApiUrl(location.target, provider) - : getRawUrl(location.target, provider); - const options = useApi - ? getApiRequestOptions(provider) - : getRawRequestOptions(provider); - const response = await fetch(url.toString(), options); - - if (response.ok) { - const data = await response.text(); - emit(result.data(location, Buffer.from(data))); - } else { - const message = `${location.target} could not be read as ${url}, ${response.status} ${response.statusText}`; - if (response.status === 404) { - if (!optional) { - emit(result.notFoundError(location, message)); - } - } else { - emit(result.generalError(location, message)); - } - } - } catch (e) { - const message = `Unable to read ${location.type} ${location.target}, ${e}`; - emit(result.generalError(location, message)); - } - - return true; - } -} diff --git a/plugins/catalog-backend/src/ingestion/processors/GitlabApiReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GitlabApiReaderProcessor.ts deleted file mode 100644 index 51a286c7ea..0000000000 --- a/plugins/catalog-backend/src/ingestion/processors/GitlabApiReaderProcessor.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LocationSpec } from '@backstage/catalog-model'; -import fetch from 'cross-fetch'; -import { Config } from '@backstage/config'; -import * as result from './results'; -import { CatalogProcessor, CatalogProcessorEmit } from './types'; - -// *********************************************************************** -// * NOTE: This has been replaced by packages/backend-common/src/reading * -// * Don't implement new functionality here as this file will be removed * -// *********************************************************************** - -export class GitlabApiReaderProcessor implements CatalogProcessor { - private privateToken: string; - - constructor(config: Config) { - this.privateToken = - config.getOptionalString('catalog.processors.gitlabApi.privateToken') ?? - ''; - } - - getRequestOptions(): RequestInit { - const headers: HeadersInit = { 'PRIVATE-TOKEN': '' }; - if (this.privateToken !== '') { - headers['PRIVATE-TOKEN'] = this.privateToken; - } - - const requestOptions: RequestInit = { - headers, - }; - - return requestOptions; - } - - async readLocation( - location: LocationSpec, - optional: boolean, - emit: CatalogProcessorEmit, - ): Promise { - if (location.type !== 'gitlab/api') { - return false; - } - - try { - const projectID = await this.getProjectID(location.target); - const url = this.buildRawUrl(location.target, projectID); - const response = await fetch(url.toString(), this.getRequestOptions()); - if (response.ok) { - const data = await response.text(); - emit(result.data(location, Buffer.from(data))); - } else { - const message = `${location.target} could not be read as ${url}, ${response.status} ${response.statusText}`; - if (response.status === 404) { - if (!optional) { - emit(result.notFoundError(location, message)); - } - } else { - emit(result.generalError(location, message)); - } - } - } catch (e) { - const message = `Unable to read ${location.type} ${location.target}, ${e}`; - emit(result.generalError(location, message)); - } - return true; - } - - // convert https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath - // to https://gitlab.com/api/v4/projects//repository/files/filepath?ref=branch - buildRawUrl(target: string, projectID: Number): URL { - try { - const url = new URL(target); - - const branchAndfilePath = url.pathname.split('/-/blob/')[1]; - - const [branch, ...filePath] = branchAndfilePath.split('/'); - - url.pathname = [ - '/api/v4/projects', - projectID, - 'repository/files', - encodeURIComponent(filePath.join('/')), - 'raw', - ].join('/'); - url.search = `?ref=${branch}`; - - return url; - } catch (e) { - throw new Error(`Incorrect url: ${target}, ${e}`); - } - } - - async getProjectID(target: string): Promise { - const url = new URL(target); - - if ( - // absPaths to gitlab files should contain /-/blob - // ex: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath - !url.pathname.match(/\/\-\/blob\//) - ) { - throw new Error('Please provide full path to yaml file from Gitlab'); - } - try { - const repo = url.pathname.split('/-/blob/')[0]; - - // Find ProjectID from url - // convert 'https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath' - // to 'https://gitlab.com/api/v4/projects/groupA%2Fteams%2FsubgroupA%2FteamA%2Frepo' - const repoIDLookup = new URL( - `${url.protocol + url.hostname}/api/v4/projects/${encodeURIComponent( - repo.replace(/^\//, ''), - )}`, - ); - const response = await fetch( - repoIDLookup.toString(), - this.getRequestOptions(), - ); - const projectIDJson = await response.json(); - const projectID: Number = projectIDJson.id; - - return projectID; - } catch (e) { - throw new Error(`Could not get GitLab ProjectID for: ${target}, ${e}`); - } - } -} diff --git a/plugins/catalog-backend/src/ingestion/processors/GitlabReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/GitlabReaderProcessor.ts deleted file mode 100644 index 38498b44fa..0000000000 --- a/plugins/catalog-backend/src/ingestion/processors/GitlabReaderProcessor.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { LocationSpec } from '@backstage/catalog-model'; -import fetch from 'cross-fetch'; -import * as result from './results'; -import { CatalogProcessor, CatalogProcessorEmit } from './types'; - -// *********************************************************************** -// * NOTE: This has been replaced by packages/backend-common/src/reading * -// * Don't implement new functionality here as this file will be removed * -// *********************************************************************** - -export class GitlabReaderProcessor implements CatalogProcessor { - async readLocation( - location: LocationSpec, - optional: boolean, - emit: CatalogProcessorEmit, - ): Promise { - if (location.type !== 'gitlab') { - return false; - } - - try { - const url = this.buildRawUrl(location.target); - - const response = await fetch(url.toString()); - - if (response.ok) { - const data = await response.text(); - emit(result.data(location, Buffer.from(data))); - } else { - const message = `${location.target} could not be read as ${url}, ${response.status} ${response.statusText}`; - if (response.status === 404) { - if (!optional) { - throw result.notFoundError(location, message); - } - } else { - throw result.generalError(location, message); - } - } - } catch (e) { - const message = `Unable to read ${location.type} ${location.target}, ${e}`; - emit(result.generalError(location, message)); - } - - return true; - } - - // Converts - // from: https://gitlab.example.com/a/b/blob/master/c.yaml - // to: https://gitlab.example.com/a/b/raw/master/c.yaml - private buildRawUrl(target: string): URL { - try { - const url = new URL(target); - - const [empty, userOrOrg, repoName, , ...restOfPath] = url.pathname - .split('/') - // for the common case https://gitlab.example.com/a/b/-/blob/master/c.yaml - .filter(path => path !== '-'); - - if ( - empty !== '' || - userOrOrg === '' || - repoName === '' || - !restOfPath.join('/').match(/\.yaml$/) - ) { - throw new Error('Wrong GitLab URL'); - } - - // Replace 'blob' with 'raw' - url.pathname = [empty, userOrOrg, repoName, 'raw', ...restOfPath].join( - '/', - ); - - return url; - } catch (e) { - throw new Error(`Incorrect url: ${target}, ${e}`); - } - } -} diff --git a/plugins/catalog-backend/src/ingestion/processors/index.ts b/plugins/catalog-backend/src/ingestion/processors/index.ts index 92303f04a3..8344678e5f 100644 --- a/plugins/catalog-backend/src/ingestion/processors/index.ts +++ b/plugins/catalog-backend/src/ingestion/processors/index.ts @@ -20,14 +20,9 @@ export { results }; export * from './types'; export { AnnotateLocationEntityProcessor } from './AnnotateLocationEntityProcessor'; -export { AzureApiReaderProcessor } from './AzureApiReaderProcessor'; -export { BitbucketApiReaderProcessor } from './BitbucketApiReaderProcessor'; export { CodeOwnersProcessor } from './CodeOwnersProcessor'; export { FileReaderProcessor } from './FileReaderProcessor'; export { GithubOrgReaderProcessor } from './GithubOrgReaderProcessor'; -export { GithubReaderProcessor } from './GithubReaderProcessor'; -export { GitlabApiReaderProcessor } from './GitlabApiReaderProcessor'; -export { GitlabReaderProcessor } from './GitlabReaderProcessor'; export { OwnerRelationProcessor } from './OwnerRelationProcessor'; export { LocationRefProcessor } from './LocationEntityProcessor'; export { PlaceholderProcessor } from './PlaceholderProcessor'; diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 4ec2a0834d..e795310915 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -43,15 +43,10 @@ import { import { DatabaseManager } from '../database'; import { AnnotateLocationEntityProcessor, - AzureApiReaderProcessor, - BitbucketApiReaderProcessor, CatalogProcessor, CodeOwnersProcessor, FileReaderProcessor, GithubOrgReaderProcessor, - GithubReaderProcessor, - GitlabApiReaderProcessor, - GitlabReaderProcessor, OwnerRelationProcessor, HigherOrderOperation, HigherOrderOperations, @@ -318,6 +313,8 @@ export class CatalogBuilder { private buildProcessors(): CatalogProcessor[] { const { config, logger, reader } = this.env; + this.checkDeprecatedReaderProcessors(); + const placeholderResolvers: Record = { json: jsonPlaceholderResolver, yaml: yamlPlaceholderResolver, @@ -342,48 +339,33 @@ export class CatalogBuilder { return [ StaticLocationProcessor.fromConfig(config), new PlaceholderProcessor({ resolvers: placeholderResolvers, reader }), - ...this.buildDeprecatedReaderProcessors(), ...processors, ]; } - // TODO(Rugvip): These are added for backwards compatibility if config exists - // The idea is to have everyone migrate from using the old processors to - // the new integration config driven UrlReaders. In an upcoming release we - // can then completely remove support for the old processors, but still - // keep handling the deprecated location types for a while, but with a - // warning. - private buildDeprecatedReaderProcessors(): CatalogProcessor[] { - const { config, logger } = this.env; - - const result = []; - const pc = config.getOptionalConfig('catalog.processors'); + // TODO(Rugvip): These old processors are removed, for a while we'll be throwing + // errors here to make sure people know where to move the config + private checkDeprecatedReaderProcessors() { + const pc = this.env.config.getOptionalConfig('catalog.processors'); if (pc?.has('github')) { - logger.warn( + throw new Error( `Using deprecated configuration for catalog.processors.github, move to using integrations.github instead`, ); - result.push(GithubReaderProcessor.fromConfig(config, logger)); } if (pc?.has('gitlabApi')) { - logger.warn( + throw new Error( `Using deprecated configuration for catalog.processors.gitlabApi, move to using integrations.gitlab instead`, ); - result.push(new GitlabApiReaderProcessor(config)); - result.push(new GitlabReaderProcessor()); } if (pc?.has('bitbucketApi')) { - logger.warn( + throw new Error( `Using deprecated configuration for catalog.processors.bitbucketApi, move to using integrations.bitbucket instead`, ); - result.push(new BitbucketApiReaderProcessor(config)); } if (pc?.has('azureApi')) { - logger.warn( + throw new Error( `Using deprecated configuration for catalog.processors.azureApi, move to using integrations.azure instead`, ); - result.push(new AzureApiReaderProcessor(config)); } - - return result; } } From 12c1fbfeb9e5422a144486cc4d1245ce569602d5 Mon Sep 17 00:00:00 2001 From: Eric Nilsson Date: Mon, 26 Oct 2020 22:38:48 +0100 Subject: [PATCH 06/33] added validation for CRA and stage-failure fix --- .../sample-templates/create-react-app/template.yaml | 1 + .../src/scaffolder/jobs/processor.ts | 2 +- .../MultistepJsonForm/MultistepJsonForm.tsx | 12 +++++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml b/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml index 2c8b3b3d6d..10109dee3d 100644 --- a/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml @@ -22,6 +22,7 @@ spec: component_id: title: Name type: string + pattern: ^[a-z0-9]+(-[a-z0-9]+)*$ description: Unique name of the component. Lowercase, URL-safe characters only. description: title: Description diff --git a/plugins/scaffolder-backend/src/scaffolder/jobs/processor.ts b/plugins/scaffolder-backend/src/scaffolder/jobs/processor.ts index c39677232d..f1dbb24dd7 100644 --- a/plugins/scaffolder-backend/src/scaffolder/jobs/processor.ts +++ b/plugins/scaffolder-backend/src/scaffolder/jobs/processor.ts @@ -118,8 +118,8 @@ export class JobProcessor implements Processor { stage.status = 'COMPLETED'; } catch (error) { // Log to the current stage the error that occured and fail the stage. - logger.error(`Stage failed with error: ${error.message}`); stage.status = 'FAILED'; + logger.error(`Stage failed with error: ${error.message}`); // Throw the error so the job can be failed too. throw error; diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx index f0ba720b39..9e7a405731 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx @@ -25,7 +25,7 @@ import { Stepper, Typography, } from '@material-ui/core'; -import { FormProps, IChangeEvent, withTheme } from '@rjsf/core'; +import { AjvError, FormProps, IChangeEvent, withTheme } from '@rjsf/core'; import { Theme as MuiTheme } from '@rjsf/material-ui'; import React, { useState } from 'react'; @@ -63,6 +63,15 @@ export const MultistepJsonForm = ({ setActiveStep(Math.min(activeStep + 1, steps.length)); const handleBack = () => setActiveStep(Math.max(activeStep - 1, 0)); + const transformErrors = (errors: AjvError[]) => + errors.map(error => { + if (error.name === 'pattern') { + error.message = 'does not match the required pattern'; + error.stack = `${error.property} ${error.message}, see its description`; + } + return error; + }); + return ( <> @@ -75,6 +84,7 @@ export const MultistepJsonForm = ({ formData={formData} onChange={onChange} schema={schema as FormProps['schema']} + transformErrors={transformErrors} onSubmit={e => { if (e.errors.length === 0) handleNext(); }} From 75763dadd97f74860c0b5d823ea4f4b940e0f540 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 26 Oct 2020 19:31:42 +0100 Subject: [PATCH 07/33] scaffolder-backend: add Preparers.fromConfig + integration type detection --- packages/backend/src/plugins/scaffolder.ts | 18 +----- .../src/scaffolder/stages/helpers.test.ts | 31 ++++++++- .../src/scaffolder/stages/helpers.ts | 37 +++++++++++ .../src/scaffolder/stages/prepare/azure.ts | 4 +- .../src/scaffolder/stages/prepare/github.ts | 4 +- .../src/scaffolder/stages/prepare/gitlab.ts | 4 +- .../scaffolder/stages/prepare/preparers.ts | 63 ++++++++++++++++++- 7 files changed, 135 insertions(+), 26 deletions(-) diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index 24bd4e942f..ef00198430 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -17,10 +17,6 @@ import { CookieCutter, createRouter, - FilePreparer, - GithubPreparer, - GitlabPreparer, - AzurePreparer, Preparers, Publishers, GithubPublisher, @@ -46,16 +42,7 @@ export default async function createPlugin({ templaters.register('cookiecutter', cookiecutterTemplater); templaters.register('cra', craTemplater); - const filePreparer = new FilePreparer(); - - const gitlabPreparer = new GitlabPreparer(config); - const azurePreparer = new AzurePreparer(config); - const preparers = new Preparers(); - - preparers.register('file', filePreparer); - preparers.register('gitlab', gitlabPreparer); - preparers.register('gitlab/api', gitlabPreparer); - preparers.register('azure/api', azurePreparer); + const preparers = await Preparers.fromConfig(config, { logger }); const publishers = new Publishers(); @@ -80,9 +67,6 @@ export default async function createPlugin({ repoVisibility, }); - const githubPreparer = new GithubPreparer({ token: githubToken }); - - preparers.register('github', githubPreparer); publishers.register('file', githubPublisher); publishers.register('github', githubPublisher); } catch (e) { diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/helpers.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/helpers.test.ts index 8b174a1edf..09bd6b7885 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/helpers.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/helpers.test.ts @@ -13,11 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { parseLocationAnnotation } from './helpers'; +import { + makeDeprecatedLocationTypeDetector, + parseLocationAnnotation, +} from './helpers'; import { TemplateEntityV1alpha1, LOCATION_ANNOTATION, } from '@backstage/catalog-model'; +import { ConfigReader } from '@backstage/config'; describe('Helpers', () => { describe('parseLocationAnnotation', () => { @@ -253,4 +257,29 @@ describe('Helpers', () => { }); }); }); + + describe('makeDeprecatedLocationTypeDetector', () => { + it('detects deprecated location types', () => { + const detector = makeDeprecatedLocationTypeDetector( + new ConfigReader({ + integrations: { + github: [{ host: 'derp.com' }, { host: 'foo.com' }], + gitlab: [{ host: 'derp.org' }, { host: 'foo.org' }], + azure: [{ host: 'derp.net' }, { host: 'foo.net' }], + }, + }), + ); + + expect(detector('http://lol:wut@derp.com/wat')).toBe('github'); + expect(detector('https://foo.com/wat')).toBe('github'); + expect(detector('http://derp.org:80/wat')).toBe('gitlab'); + expect(detector('https://foo.org/wat')).toBe('gitlab'); + expect(detector('http://not.derp.net')).toBe(undefined); + expect(detector('http://derp.net')).toBe('azure/api'); + expect(detector('http://derp.net:8080/wat')).toBe('azure/api'); + expect(detector('http://github.com')).toBe('github'); + expect(detector('http://gitlab.com')).toBe('gitlab'); + expect(detector('http://dev.azure.com')).toBe('azure/api'); + }); + }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/helpers.ts index 3f31f19d59..e54e796b3b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/helpers.ts @@ -17,6 +17,7 @@ import { TemplateEntityV1alpha1, LOCATION_ANNOTATION, } from '@backstage/catalog-model'; +import { Config } from '@backstage/config'; import { InputError } from '@backstage/backend-common'; import { RemoteProtocol } from './types'; @@ -54,3 +55,39 @@ export const parseLocationAnnotation = ( location, }; }; + +export type DeprecatedLocationTypeDetector = ( + url: string, +) => string | undefined; + +// The reason for the existence of this is to help in migration to using mostly locations +// of type 'url'. This allows us to detect the deprecated location type based on the host, +// which we in turn can use to select out preparer or publisher. +// +// TODO(Rugvip): This should be removed in the future once we fully migrate to using +// integrations configuration for the scaffolder. +export function makeDeprecatedLocationTypeDetector( + config: Config, +): DeprecatedLocationTypeDetector { + const hostMap = new Map(); + + // These are installed by default by the integrations + hostMap.set('github.com', 'github'); + hostMap.set('gitlab.com', 'gitlab'); + hostMap.set('dev.azure.com', 'azure/api'); + + config.getOptionalConfigArray('integrations.github')?.forEach(sub => { + hostMap.set(sub.getString('host'), 'github'); + }); + config.getOptionalConfigArray('integrations.gitlab')?.forEach(sub => { + hostMap.set(sub.getString('host'), 'gitlab'); + }); + config.getOptionalConfigArray('integrations.azure')?.forEach(sub => { + hostMap.set(sub.getString('host'), 'azure/api'); + }); + + return (url: string): string | undefined => { + const parsed = new URL(url); + return hostMap.get(parsed.hostname); + }; +} diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts index c2cb97e505..dc74ec0f75 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts @@ -35,9 +35,9 @@ export class AzurePreparer implements PreparerBase { async prepare(template: TemplateEntityV1alpha1): Promise { const { protocol, location } = parseLocationAnnotation(template); - if (protocol !== 'azure/api') { + if (!['azure/api', 'url'].includes(protocol)) { throw new InputError( - `Wrong location protocol: ${protocol}, should be 'azure/api'`, + `Wrong location protocol: ${protocol}, should be 'url'`, ); } const templateId = template.metadata.name; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts index 6eee00f9cb..0f064d22fa 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts @@ -34,9 +34,9 @@ export class GithubPreparer implements PreparerBase { const { protocol, location } = parseLocationAnnotation(template); const { token } = this; - if (protocol !== 'github') { + if (!['github', 'url'].includes(protocol)) { throw new InputError( - `Wrong location protocol: ${protocol}, should be 'github'`, + `Wrong location protocol: ${protocol}, should be 'url'`, ); } const templateId = template.metadata.name; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts index 8efc158a96..8ccde0b626 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts @@ -36,9 +36,9 @@ export class GitlabPreparer implements PreparerBase { async prepare(template: TemplateEntityV1alpha1): Promise { const { protocol, location } = parseLocationAnnotation(template); - if (['gitlab', 'gitlab/api'].indexOf(protocol) < 0) { + if (!['gitlab', 'gitlab/api', 'url'].includes(protocol)) { throw new InputError( - `Wrong location protocol: ${protocol}, should be 'gitlab' or 'gitlab/api'`, + `Wrong location protocol: ${protocol}, should be 'url'`, ); } const templateId = template.metadata.name; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts index 5efb3ad60d..59537e73f4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts @@ -14,26 +14,85 @@ * limitations under the License. */ +import { Config } from '@backstage/config'; +import { Logger } from 'winston'; import { PreparerBase, PreparerBuilder } from './types'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; -import { parseLocationAnnotation } from '../helpers'; +import { + DeprecatedLocationTypeDetector, + makeDeprecatedLocationTypeDetector, + parseLocationAnnotation, +} from '../helpers'; import { RemoteProtocol } from '../types'; +import { FilePreparer } from './file'; +import { GitlabPreparer } from './gitlab'; +import { AzurePreparer } from './azure'; +import { GithubPreparer } from './github'; export class Preparers implements PreparerBuilder { private preparerMap = new Map(); + constructor(private readonly typeDetector?: DeprecatedLocationTypeDetector) {} + register(protocol: RemoteProtocol, preparer: PreparerBase) { this.preparerMap.set(protocol, preparer); } get(template: TemplateEntityV1alpha1): PreparerBase { - const { protocol } = parseLocationAnnotation(template); + const { protocol, location } = parseLocationAnnotation(template); + const preparer = this.preparerMap.get(protocol); if (!preparer) { + if ((protocol as string) === 'url') { + const type = this.typeDetector?.(location); + const preparer2 = type && this.preparerMap.get(type as RemoteProtocol); + if (preparer2) { + return preparer2; + } + throw new Error(`No preparer integration found for url "${location}"`); + } throw new Error(`No preparer registered for type: "${protocol}"`); } return preparer; } + + static async fromConfig( + config: Config, + { logger }: { logger: Logger }, + ): Promise { + const typeDetector = makeDeprecatedLocationTypeDetector(config); + + const preparers = new Preparers(typeDetector); + + const filePreparer = new FilePreparer(); + const gitlabPreparer = new GitlabPreparer(config); + const azurePreparer = new AzurePreparer(config); + + preparers.register('file', filePreparer); + preparers.register('gitlab', gitlabPreparer); + preparers.register('gitlab/api', gitlabPreparer); + preparers.register('azure/api', azurePreparer); + + const githubConfig = config.getOptionalConfig('scaffolder.github'); + if (githubConfig) { + try { + const githubToken = githubConfig.getString('token'); + const githubPreparer = new GithubPreparer({ token: githubToken }); + + preparers.register('github', githubPreparer); + } catch (e) { + if (process.env.NODE_ENV !== 'development') { + throw new Error( + `Failed to initialize github scaffolding provider, ${e.message}`, + ); + } + + logger.warn(`Skipping github scaffolding provider, ${e.message}`); + } + } + + return preparers; + } } From f8064794ccb4b8dae7ec91895576de001aa17d03 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 26 Oct 2020 23:28:09 +0100 Subject: [PATCH 08/33] scaffolder-backend: add Publishers.fromConfig --- packages/backend/src/plugins/scaffolder.ts | 99 +------------- .../scaffolder/stages/publish/publishers.ts | 124 +++++++++++++++++- 2 files changed, 124 insertions(+), 99 deletions(-) diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index ef00198430..c84928ea68 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -19,16 +19,9 @@ import { createRouter, Preparers, Publishers, - GithubPublisher, - GitlabPublisher, - AzurePublisher, CreateReactAppTemplater, Templaters, - RepoVisibilityOptions, } from '@backstage/plugin-scaffolder-backend'; -import { Octokit } from '@octokit/rest'; -import { Gitlab } from '@gitbeaker/node'; -import { getPersonalAccessTokenHandler, WebApi } from 'azure-devops-node-api'; import type { PluginEnvironment } from '../types'; import Docker from 'dockerode'; @@ -43,98 +36,10 @@ export default async function createPlugin({ templaters.register('cra', craTemplater); const preparers = await Preparers.fromConfig(config, { logger }); - - const publishers = new Publishers(); - - const githubConfig = config.getOptionalConfig('scaffolder.github'); - - if (githubConfig) { - try { - const repoVisibility = githubConfig.getString( - 'visibility', - ) as RepoVisibilityOptions; - - const githubToken = githubConfig.getString('token'); - const githubHost = - githubConfig.getOptionalString('host') ?? 'https://github.com'; - const githubClient = new Octokit({ - auth: githubToken, - baseUrl: githubHost, - }); - const githubPublisher = new GithubPublisher({ - client: githubClient, - token: githubToken, - repoVisibility, - }); - - publishers.register('file', githubPublisher); - publishers.register('github', githubPublisher); - } catch (e) { - const providerName = 'github'; - if (process.env.NODE_ENV !== 'development') { - throw new Error( - `Failed to initialize ${providerName} scaffolding provider, ${e.message}`, - ); - } - - logger.warn( - `Skipping ${providerName} scaffolding provider, ${e.message}`, - ); - } - } - - const gitLabConfig = config.getOptionalConfig('scaffolder.gitlab.api'); - if (gitLabConfig) { - try { - const gitLabToken = gitLabConfig.getString('token'); - const gitLabClient = new Gitlab({ - host: gitLabConfig.getOptionalString('baseUrl'), - token: gitLabToken, - }); - const gitLabPublisher = new GitlabPublisher(gitLabClient, gitLabToken); - publishers.register('gitlab', gitLabPublisher); - publishers.register('gitlab/api', gitLabPublisher); - } catch (e) { - const providerName = 'gitlab'; - if (process.env.NODE_ENV !== 'development') { - throw new Error( - `Failed to initialize ${providerName} scaffolding provider, ${e.message}`, - ); - } - - logger.warn( - `Skipping ${providerName} scaffolding provider, ${e.message}`, - ); - } - } - - const azureConfig = config.getOptionalConfig('scaffolder.azure'); - if (azureConfig) { - try { - const baseUrl = azureConfig.getString('baseUrl'); - const azureToken = azureConfig.getConfig('api').getString('token'); - - const authHandler = getPersonalAccessTokenHandler(azureToken); - const webApi = new WebApi(baseUrl, authHandler); - const azureClient = await webApi.getGitApi(); - - const azurePublisher = new AzurePublisher(azureClient, azureToken); - publishers.register('azure/api', azurePublisher); - } catch (e) { - const providerName = 'azure'; - if (process.env.NODE_ENV !== 'development') { - throw new Error( - `Failed to initialize ${providerName} scaffolding provider, ${e.message}`, - ); - } - - logger.warn( - `Skipping ${providerName} scaffolding provider, ${e.message}`, - ); - } - } + const publishers = await Publishers.fromConfig(config, { logger }); const dockerClient = new Docker(); + return await createRouter({ preparers, templaters, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts index a88acc518d..80203e3b54 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts @@ -14,26 +14,146 @@ * limitations under the License. */ +import { Logger } from 'winston'; +import { Octokit } from '@octokit/rest'; +import { Gitlab } from '@gitbeaker/node'; +import { getPersonalAccessTokenHandler, WebApi } from 'azure-devops-node-api'; +import { Config } from '@backstage/config'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; -import { parseLocationAnnotation } from '../helpers'; +import { + DeprecatedLocationTypeDetector, + makeDeprecatedLocationTypeDetector, + parseLocationAnnotation, +} from '../helpers'; import { PublisherBase, PublisherBuilder } from './types'; import { RemoteProtocol } from '../types'; +import { GithubPublisher, RepoVisibilityOptions } from './github'; +import { GitlabPublisher } from './gitlab'; +import { AzurePublisher } from './azure'; export class Publishers implements PublisherBuilder { private publisherMap = new Map(); + constructor(private readonly typeDetector?: DeprecatedLocationTypeDetector) {} + register(protocol: RemoteProtocol, publisher: PublisherBase) { this.publisherMap.set(protocol, publisher); } get(template: TemplateEntityV1alpha1): PublisherBase { - const { protocol } = parseLocationAnnotation(template); + const { protocol, location } = parseLocationAnnotation(template); const publisher = this.publisherMap.get(protocol); if (!publisher) { + if ((protocol as string) === 'url') { + const type = this.typeDetector?.(location); + const publisher2 = + type && this.publisherMap.get(type as RemoteProtocol); + if (publisher2) { + return publisher2; + } + throw new Error(`No preparer integration found for url "${location}"`); + } throw new Error(`No publisher registered for type: "${protocol}"`); } return publisher; } + + static async fromConfig( + config: Config, + { logger }: { logger: Logger }, + ): Promise { + const typeDetector = makeDeprecatedLocationTypeDetector(config); + const publishers = new Publishers(typeDetector); + + const githubConfig = config.getOptionalConfig('scaffolder.github'); + if (githubConfig) { + try { + const repoVisibility = githubConfig.getString( + 'visibility', + ) as RepoVisibilityOptions; + + const githubToken = githubConfig.getString('token'); + const githubHost = + githubConfig.getOptionalString('host') ?? 'https://github.com'; + const githubClient = new Octokit({ + auth: githubToken, + baseUrl: githubHost, + }); + const githubPublisher = new GithubPublisher({ + client: githubClient, + token: githubToken, + repoVisibility, + }); + + publishers.register('file', githubPublisher); + publishers.register('github', githubPublisher); + } catch (e) { + const providerName = 'github'; + if (process.env.NODE_ENV !== 'development') { + throw new Error( + `Failed to initialize ${providerName} scaffolding provider, ${e.message}`, + ); + } + + logger.warn( + `Skipping ${providerName} scaffolding provider, ${e.message}`, + ); + } + } + + const gitLabConfig = config.getOptionalConfig('scaffolder.gitlab.api'); + if (gitLabConfig) { + try { + const gitLabToken = gitLabConfig.getString('token'); + const gitLabClient = new Gitlab({ + host: gitLabConfig.getOptionalString('baseUrl'), + token: gitLabToken, + }); + const gitLabPublisher = new GitlabPublisher(gitLabClient, gitLabToken); + publishers.register('gitlab', gitLabPublisher); + publishers.register('gitlab/api', gitLabPublisher); + } catch (e) { + const providerName = 'gitlab'; + if (process.env.NODE_ENV !== 'development') { + throw new Error( + `Failed to initialize ${providerName} scaffolding provider, ${e.message}`, + ); + } + + logger.warn( + `Skipping ${providerName} scaffolding provider, ${e.message}`, + ); + } + } + + const azureConfig = config.getOptionalConfig('scaffolder.azure'); + if (azureConfig) { + try { + const baseUrl = azureConfig.getString('baseUrl'); + const azureToken = azureConfig.getConfig('api').getString('token'); + + const authHandler = getPersonalAccessTokenHandler(azureToken); + const webApi = new WebApi(baseUrl, authHandler); + const azureClient = await webApi.getGitApi(); + + const azurePublisher = new AzurePublisher(azureClient, azureToken); + publishers.register('azure/api', azurePublisher); + } catch (e) { + const providerName = 'azure'; + if (process.env.NODE_ENV !== 'development') { + throw new Error( + `Failed to initialize ${providerName} scaffolding provider, ${e.message}`, + ); + } + + logger.warn( + `Skipping ${providerName} scaffolding provider, ${e.message}`, + ); + } + } + + return publishers; + } } From c633158fdad87e8d0608e7967b672c4cc7c38db3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 26 Oct 2020 23:28:29 +0100 Subject: [PATCH 09/33] scaffolder-backend: default github api url to api.github.com --- app-config.yaml | 1 - .../src/scaffolder/stages/publish/publishers.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index 05bf39b5b3..6e3a68a229 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -156,7 +156,6 @@ catalog: scaffolder: github: - host: https://github.com token: $env: GITHUB_TOKEN visibility: public # or 'internal' or 'private' diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts index 80203e3b54..23f15745ba 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts @@ -76,7 +76,7 @@ export class Publishers implements PublisherBuilder { const githubToken = githubConfig.getString('token'); const githubHost = - githubConfig.getOptionalString('host') ?? 'https://github.com'; + githubConfig.getOptionalString('host') ?? 'https://api.github.com'; const githubClient = new Octokit({ auth: githubToken, baseUrl: githubHost, From 991a950e047e7523e3aeb1ecd62a98a01cc7515e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 26 Oct 2020 23:33:03 +0100 Subject: [PATCH 10/33] changesets: added changeset for scaffolder-backend updates --- .changeset/chilly-emus-fetch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chilly-emus-fetch.md diff --git a/.changeset/chilly-emus-fetch.md b/.changeset/chilly-emus-fetch.md new file mode 100644 index 0000000000..ad77c90f4e --- /dev/null +++ b/.changeset/chilly-emus-fetch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Added .fromConfig static factories for Preparers and Publishers + read integrations config to support url location types From 7c28026ae02d90fb7398aa726a22f72fcf871a78 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 26 Oct 2020 23:34:25 +0100 Subject: [PATCH 11/33] docs: update scaffolder-backend installation docs --- .../software-templates/installation.md | 40 +------------------ 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/docs/features/software-templates/installation.md b/docs/features/software-templates/installation.md index 842c59e289..bac5f60789 100644 --- a/docs/features/software-templates/installation.md +++ b/docs/features/software-templates/installation.md @@ -111,44 +111,8 @@ export default async function createPlugin({ templaters.register('cookiecutter', cookiecutterTemplater); templaters.register('cra', craTemplater); - const filePreparer = new FilePreparer(); - const githubPreparer = new GithubPreparer(); - const gitlabPreparer = new GitlabPreparer(config); - const preparers = new Preparers(); - - preparers.register('file', filePreparer); - preparers.register('github', githubPreparer); - preparers.register('gitlab', gitlabPreparer); - preparers.register('gitlab/api', gitlabPreparer); - - const publishers = new Publishers(); - - const githubToken = config.getString('scaffolder.github.token'); - const repoVisibility = config.getString( - 'scaffolder.github.visibility', - ) as RepoVisibilityOptions; - - const githubClient = new Octokit({ auth: githubToken }); - const githubPublisher = new GithubPublisher({ - client: githubClient, - token: githubToken, - repoVisibility, - }); - publishers.register('file', githubPublisher); - publishers.register('github', githubPublisher); - - const gitLabConfig = config.getOptionalConfig('scaffolder.gitlab.api'); - - if (gitLabConfig) { - const gitLabToken = gitLabConfig.getString('token'); - const gitLabClient = new Gitlab({ - host: gitLabConfig.getOptionalString('baseUrl'), - token: gitLabToken, - }); - const gitLabPublisher = new GitlabPublisher(gitLabClient, gitLabToken); - publishers.register('gitlab', gitLabPublisher); - publishers.register('gitlab/api', gitLabPublisher); - } + const preparers = await Preparers.fromConfig(config, { logger }); + const publishers = await Publishers.fromConfig(config, { logger }); const dockerClient = new Docker(); return await createRouter({ From 99133b930121a800affd8aa4b50e0391013adae8 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 27 Oct 2020 01:17:33 +0100 Subject: [PATCH 12/33] chore(proxy): added some contrib doxs for corporate proxy config --- .../help-im-behind-a-corporate-proxy.md | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md diff --git a/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md b/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md new file mode 100644 index 0000000000..75b1b6ff7f --- /dev/null +++ b/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md @@ -0,0 +1,51 @@ +# Running the backend behind a Corporate Proxy + +Let's admit it, we've all been there. Sometimes you've gotta run stuff with no way out to the public internet, only the smallest of corporate proxy tunnels. + +Whilst this isn't supported natively by Backstage, this might help you get your installation up and running making calls through the said proxy tunnel. + +Unfortunately, `nodejs` does not respect `HTTP(S)_PROXY` environment variables by default, and the library that we use to provide `fetch` functionality `node-fetch` (provided by `cross-fetch`) does not also respect these environment variables. + +There are however some ways to get this to work without too much effort. It's most likely that you're going to run into these issues from the `backend` part of `backstage` as that's the part that isn't helped by your browser or OS's settings for the corporate proxy. + +**Note:** You're gonna want to be in your backend working directory for these solutions as that's where the requests come from that don't go through this proxy. + +### Using `global-agent` + +1. Install `global-agent` using `yarn install global-agent` +2. Go to the entry file for the backend (`src/index.ts`) +3. At the top of the file paste the following: + +```ts +import 'global-agent/bootstrap'; +``` + +4. Start the backend with the `global-agent` variables + +```sh +export GLOBAL_AGENT_HTTP_PROXY=$HTTP_PROXY +yarn start +``` + +More information and more options for configuring `global-agent` including just using the default environment variables can be found here: https://github.com/gajus/global-agent + +### Using `proxy-agent` + +`proxy-agent` is a library that you can use to override the `globalAgents` of `node` land with a tunnel to use for each request. + +1. Install `global-agent` using `yarn install proxy-agent` +2. Go to the entry file for the backend (`src/index.ts`) +3. At the top of the file paste the following: + +```ts +import ProxyAgent from 'proxy-agent'; +import http from 'http'; +import https from 'https'; + +if (process.env.HTTP_PROXY) { + http.globalAgent = new ProxyAgent(process.env.HTTP_PROXY); + https.globalAgent = new ProxyAgent(process.env.HTTP_PROXY); +} +``` + +4. Start the backend with `yarn start` From 4727dc98f9d11e3a7fd6901af1007cec89b9aa74 Mon Sep 17 00:00:00 2001 From: Fabian Chong Date: Tue, 27 Oct 2020 12:05:08 +0800 Subject: [PATCH 13/33] adding tsconfig.json to default-backend-plugin --- .../templates/default-backend-plugin/tsconfig.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 packages/cli/templates/default-backend-plugin/tsconfig.json diff --git a/packages/cli/templates/default-backend-plugin/tsconfig.json b/packages/cli/templates/default-backend-plugin/tsconfig.json new file mode 100644 index 0000000000..d77f0fe3b4 --- /dev/null +++ b/packages/cli/templates/default-backend-plugin/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@backstage/cli/config/tsconfig.json", + "include": [ + "src", + "dev", + "migrations" + ], + "exclude": ["node_modules"], + "compilerOptions": { + "outDir": "dist-types", + "rootDir": "." + } +} From 51394c24bd0727f1eea00ed70ae83f508c2a2a6c Mon Sep 17 00:00:00 2001 From: Fabian Chong Date: Tue, 27 Oct 2020 12:06:30 +0800 Subject: [PATCH 14/33] removing migration from frontend plugin --- packages/cli/templates/default-plugin/tsconfig.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/cli/templates/default-plugin/tsconfig.json b/packages/cli/templates/default-plugin/tsconfig.json index d77f0fe3b4..b61e496175 100644 --- a/packages/cli/templates/default-plugin/tsconfig.json +++ b/packages/cli/templates/default-plugin/tsconfig.json @@ -2,8 +2,7 @@ "extends": "@backstage/cli/config/tsconfig.json", "include": [ "src", - "dev", - "migrations" + "dev" ], "exclude": ["node_modules"], "compilerOptions": { From 2a662cda68ad62142d214e1d303459f1a84779c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Oct 2020 04:25:17 +0000 Subject: [PATCH 15/33] chore(deps-dev): bump @spotify/prettier-config in /microsite Bumps [@spotify/prettier-config](https://github.com/spotify/web-scripts) from 8.0.0 to 9.0.0. - [Release notes](https://github.com/spotify/web-scripts/releases) - [Changelog](https://github.com/spotify/web-scripts/blob/master/CHANGELOG.md) - [Commits](https://github.com/spotify/web-scripts/compare/v8.0.0...v9.0.0) Signed-off-by: dependabot[bot] --- microsite/package.json | 2 +- microsite/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/microsite/package.json b/microsite/package.json index ecf7752b05..a84364c214 100644 --- a/microsite/package.json +++ b/microsite/package.json @@ -14,7 +14,7 @@ "rename-version": "docusaurus-rename-version" }, "devDependencies": { - "@spotify/prettier-config": "^8.0.0", + "@spotify/prettier-config": "^9.0.0", "docusaurus": "^2.0.0-alpha.66", "js-yaml": "^3.14.0", "prettier": "^2.0.5" diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 6707532f9c..b120cb2d47 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -959,10 +959,10 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@spotify/prettier-config@^8.0.0": - version "8.0.0" - resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-8.0.0.tgz#8b6c2bd579ddc54887155a0721fe04e96c89f7f2" - integrity sha512-so8w32ZV42CHWxOEXcBtbNO/hLXFrQNXVmhfzhUI6dVB9cq2xjRaiqu8GjFj8LvKbWpPj+S+KwTIS4aDVWqrFQ== +"@spotify/prettier-config@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@spotify/prettier-config/-/prettier-config-9.0.0.tgz#7b562d56573c6fc0094446fbc92b22bc318945dc" + integrity sha512-In1q0tIiqTYKAGe3KOHDcFDdZRFISyQeSeipeTHGfki23ebHRZcjxvqj5SSdBkw65D4VpSREMi0s9i5iJiMcTw== "@types/cheerio@^0.22.8": version "0.22.21" From b863687d7f763c88350832dd6bb25aa1f5ff775a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Oct 2020 04:39:49 +0000 Subject: [PATCH 16/33] chore(deps): bump @rollup/plugin-commonjs from 13.0.0 to 16.0.0 Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins) from 13.0.0 to 16.0.0. - [Release notes](https://github.com/rollup/plugins/releases) - [Commits](https://github.com/rollup/plugins/compare/commonjs-v13.0.0...commonjs-v16.0.0) Signed-off-by: dependabot[bot] --- packages/cli/package.json | 2 +- yarn.lock | 39 ++++++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index d6e73b41fa..3024c2eeaf 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -34,7 +34,7 @@ "@hot-loader/react-dom": "^16.13.0", "@lerna/package-graph": "^3.18.5", "@lerna/project": "^3.18.0", - "@rollup/plugin-commonjs": "^13.0.0", + "@rollup/plugin-commonjs": "^16.0.0", "@rollup/plugin-json": "^4.0.2", "@rollup/plugin-node-resolve": "^9.0.0", "@rollup/plugin-yaml": "^2.1.1", diff --git a/yarn.lock b/yarn.lock index 3d3300493a..1c655081ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3715,18 +3715,18 @@ react-router-dom "6.0.0-beta.0" react-use "^15.3.3" -"@rollup/plugin-commonjs@^13.0.0": - version "13.0.0" - resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-13.0.0.tgz#8a1d684ba6848afe8b9e3d85649d4b2f6f7217ec" - integrity sha512-Anxc3qgkAi7peAyesTqGYidG5GRim9jtg8xhmykNaZkImtvjA7Wsqep08D2mYsqw1IF7rA3lYfciLgzUSgRoqw== +"@rollup/plugin-commonjs@^16.0.0": + version "16.0.0" + resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz#169004d56cd0f0a1d0f35915d31a036b0efe281f" + integrity sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw== dependencies: - "@rollup/pluginutils" "^3.0.8" + "@rollup/pluginutils" "^3.1.0" commondir "^1.0.1" - estree-walker "^1.0.1" - glob "^7.1.2" - is-reference "^1.1.2" - magic-string "^0.25.2" - resolve "^1.11.0" + estree-walker "^2.0.1" + glob "^7.1.6" + is-reference "^1.2.1" + magic-string "^0.25.7" + resolve "^1.17.0" "@rollup/plugin-json@^4.0.2": version "4.1.0" @@ -11085,6 +11085,11 @@ estree-walker@^1.0.1: resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== +estree-walker@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz#f8e030fb21cefa183b44b7ad516b747434e7a3e0" + integrity sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -13968,12 +13973,12 @@ is-promise@^2.1, is-promise@^2.1.0: resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== -is-reference@^1.1.2: - version "1.1.4" - resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz#3f95849886ddb70256a3e6d062b1a68c13c51427" - integrity sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw== +is-reference@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" + integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== dependencies: - "@types/estree" "0.0.39" + "@types/estree" "*" is-regex@^1.0.4, is-regex@^1.0.5, is-regex@^1.1.1: version "1.1.1" @@ -15845,7 +15850,7 @@ macos-release@^2.2.0: resolved "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f" integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA== -magic-string@^0.25.2: +magic-string@^0.25.7: version "0.25.7" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== @@ -20442,7 +20447,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.17.0, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.15.1, resolve@^1.16.1, resolve@^1.17.0, resolve@^1.3.2: +resolve@1.17.0, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.15.1, resolve@^1.16.1, resolve@^1.17.0, resolve@^1.3.2: version "1.17.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== From 7c7cc0b1dd57d46f1c3f11e55a888280d5480224 Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 27 Oct 2020 09:45:24 +0100 Subject: [PATCH 17/33] docs: fix copy and paste error --- contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md b/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md index 75b1b6ff7f..d02fa4b510 100644 --- a/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md +++ b/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md @@ -33,7 +33,7 @@ More information and more options for configuring `global-agent` including just `proxy-agent` is a library that you can use to override the `globalAgents` of `node` land with a tunnel to use for each request. -1. Install `global-agent` using `yarn install proxy-agent` +1. Install `proxy-agent` using `yarn install proxy-agent` 2. Go to the entry file for the backend (`src/index.ts`) 3. At the top of the file paste the following: From c46cdf34e326c1ac9191591bd2cb35875a7b94e3 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 27 Oct 2020 10:00:40 +0100 Subject: [PATCH 18/33] scaffolder-backend: fix review nit --- .../src/scaffolder/stages/prepare/preparers.ts | 6 +++--- .../src/scaffolder/stages/publish/publishers.ts | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts index 59537e73f4..226f7e3836 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/preparers.ts @@ -46,9 +46,9 @@ export class Preparers implements PreparerBuilder { if (!preparer) { if ((protocol as string) === 'url') { const type = this.typeDetector?.(location); - const preparer2 = type && this.preparerMap.get(type as RemoteProtocol); - if (preparer2) { - return preparer2; + const detected = type && this.preparerMap.get(type as RemoteProtocol); + if (detected) { + return detected; } throw new Error(`No preparer integration found for url "${location}"`); } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts index 23f15745ba..db383aaf7f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/publishers.ts @@ -47,10 +47,9 @@ export class Publishers implements PublisherBuilder { if (!publisher) { if ((protocol as string) === 'url') { const type = this.typeDetector?.(location); - const publisher2 = - type && this.publisherMap.get(type as RemoteProtocol); - if (publisher2) { - return publisher2; + const detected = type && this.publisherMap.get(type as RemoteProtocol); + if (detected) { + return detected; } throw new Error(`No preparer integration found for url "${location}"`); } From 2f62e180419573f786b331d7246680f2c1622615 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 26 Oct 2020 17:05:07 +0100 Subject: [PATCH 19/33] catalog-backend: remove data parsing processing step --- .changeset/mighty-starfishes-taste.md | 5 + .../src/ingestion/LocationReaders.ts | 37 ---- .../processors/FileReaderProcessor.ts | 6 +- .../processors/UrlReaderProcessor.test.ts | 10 +- .../processors/UrlReaderProcessor.ts | 6 +- .../processors/YamlProcessor.test.ts | 151 --------------- .../src/ingestion/processors/YamlProcessor.ts | 63 ------ .../src/ingestion/processors/index.ts | 1 - .../src/ingestion/processors/results.ts | 7 - .../src/ingestion/processors/types.ts | 21 -- .../ingestion/processors/util/parse.test.ts | 180 ++++++++++++++++++ .../src/ingestion/processors/util/parse.ts | 49 +++++ .../src/service/CatalogBuilder.test.ts | 11 +- .../src/service/CatalogBuilder.ts | 2 - 14 files changed, 250 insertions(+), 299 deletions(-) create mode 100644 .changeset/mighty-starfishes-taste.md delete mode 100644 plugins/catalog-backend/src/ingestion/processors/YamlProcessor.test.ts delete mode 100644 plugins/catalog-backend/src/ingestion/processors/YamlProcessor.ts create mode 100644 plugins/catalog-backend/src/ingestion/processors/util/parse.test.ts create mode 100644 plugins/catalog-backend/src/ingestion/processors/util/parse.ts diff --git a/.changeset/mighty-starfishes-taste.md b/.changeset/mighty-starfishes-taste.md new file mode 100644 index 0000000000..eb43ce69b8 --- /dev/null +++ b/.changeset/mighty-starfishes-taste.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Removed the parseData step from catalog processors. Locations readers should emit full entities instead. diff --git a/plugins/catalog-backend/src/ingestion/LocationReaders.ts b/plugins/catalog-backend/src/ingestion/LocationReaders.ts index 11ae45cae9..45bf2e8ae0 100644 --- a/plugins/catalog-backend/src/ingestion/LocationReaders.ts +++ b/plugins/catalog-backend/src/ingestion/LocationReaders.ts @@ -28,7 +28,6 @@ import { CatalogRulesEnforcer } from './CatalogRules'; import * as result from './processors/results'; import { CatalogProcessor, - CatalogProcessorDataResult, CatalogProcessorEmit, CatalogProcessorEntityResult, CatalogProcessorErrorResult, @@ -75,8 +74,6 @@ export class LocationReaders implements LocationReader { for (const item of items) { if (item.type === 'location') { await this.handleLocation(item, emit); - } else if (item.type === 'data') { - await this.handleData(item, emit); } else if (item.type === 'entity') { if (rulesEnforcer.isAllowed(item.entity, item.location)) { const relations = Array(); @@ -165,40 +162,6 @@ export class LocationReaders implements LocationReader { logger.warn(message); } - private async handleData( - item: CatalogProcessorDataResult, - emit: CatalogProcessorEmit, - ) { - const { processors, logger } = this.options; - - const validatedEmit: CatalogProcessorEmit = emitResult => { - if (emitResult.type === 'relation') { - throw new Error('parseData may not emit entity relations'); - } - - emit(emitResult); - }; - - for (const processor of processors) { - if (processor.parseData) { - try { - if ( - await processor.parseData(item.data, item.location, validatedEmit) - ) { - return; - } - } catch (e) { - const message = `Processor ${processor.constructor.name} threw an error while parsing ${item.location.type} ${item.location.target}, ${e}`; - emit(result.generalError(item.location, message)); - logger.warn(message); - } - } - } - - const message = `No processor was able to parse location ${item.location.type} ${item.location.target}`; - emit(result.inputError(item.location, message)); - } - private async handleEntity( item: CatalogProcessorEntityResult, emit: CatalogProcessorEmit, diff --git a/plugins/catalog-backend/src/ingestion/processors/FileReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/FileReaderProcessor.ts index 83fc01185b..2328ec3c7a 100644 --- a/plugins/catalog-backend/src/ingestion/processors/FileReaderProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/FileReaderProcessor.ts @@ -18,6 +18,7 @@ import { LocationSpec } from '@backstage/catalog-model'; import fs from 'fs-extra'; import * as result from './results'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; +import { parseEntityYaml } from './util/parse'; export class FileReaderProcessor implements CatalogProcessor { async readLocation( @@ -33,7 +34,10 @@ export class FileReaderProcessor implements CatalogProcessor { const exists = await fs.pathExists(location.target); if (exists) { const data = await fs.readFile(location.target); - emit(result.data(location, data)); + + for (const parseResult of parseEntityYaml(data, location)) { + emit(parseResult); + } } else if (!optional) { const message = `${location.type} ${location.target} does not exist`; emit(result.notFoundError(location, message)); diff --git a/plugins/catalog-backend/src/ingestion/processors/UrlReaderProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/UrlReaderProcessor.test.ts index 73046f0ed1..9bf72d620b 100644 --- a/plugins/catalog-backend/src/ingestion/processors/UrlReaderProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/UrlReaderProcessor.test.ts @@ -21,7 +21,7 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { msw } from '@backstage/test-utils'; import { - CatalogProcessorDataResult, + CatalogProcessorEntityResult, CatalogProcessorErrorResult, CatalogProcessorResult, } from './types'; @@ -42,17 +42,17 @@ describe('UrlReaderProcessor', () => { server.use( rest.get(`${mockApiOrigin}/component.yaml`, (_, res, ctx) => - res(ctx.body('Hello')), + res(ctx.json({ mock: 'entity' })), ), ); const generated = (await new Promise(emit => processor.readLocation(spec, false, emit), - )) as CatalogProcessorDataResult; + )) as CatalogProcessorEntityResult; - expect(generated.type).toBe('data'); + expect(generated.type).toBe('entity'); expect(generated.location).toBe(spec); - expect(generated.data.toString('utf8')).toBe('Hello'); + expect(generated.entity).toEqual({ mock: 'entity' }); }); it('should fail load from url with error', async () => { diff --git a/plugins/catalog-backend/src/ingestion/processors/UrlReaderProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/UrlReaderProcessor.ts index 0169abbbe3..d31f053c80 100644 --- a/plugins/catalog-backend/src/ingestion/processors/UrlReaderProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/UrlReaderProcessor.ts @@ -19,6 +19,7 @@ import { LocationSpec } from '@backstage/catalog-model'; import { Logger } from 'winston'; import * as result from './results'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; +import { parseEntityYaml } from './util/parse'; // TODO(Rugvip): Added for backwards compatibility when moving to UrlReader, this // can be removed in a bit @@ -55,7 +56,10 @@ export class UrlReaderProcessor implements CatalogProcessor { try { const data = await this.options.reader.read(location.target); - emit(result.data(location, data)); + + for (const parseResult of parseEntityYaml(data, location)) { + emit(parseResult); + } } catch (error) { const message = `Unable to read ${location.type}, ${error}`; diff --git a/plugins/catalog-backend/src/ingestion/processors/YamlProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/YamlProcessor.test.ts deleted file mode 100644 index f5d2dfea38..0000000000 --- a/plugins/catalog-backend/src/ingestion/processors/YamlProcessor.test.ts +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Entity } from '@backstage/catalog-model'; -import { TextEncoder } from 'util'; -import yaml from 'yaml'; -import { - CatalogProcessorEntityResult, - CatalogProcessorErrorResult, -} from './types'; -import { YamlProcessor } from './YamlProcessor'; - -describe('YamlProcessor', () => { - const processor = new YamlProcessor(); - const locationSpec = { - type: 'url', - target: 'http://example.com/component.yaml', - }; - - function encodeEntity(entity: string): Buffer { - const data = new TextEncoder().encode(entity); - return Buffer.from(data); - } - - it('should only process files with yaml', async () => { - const wrongLocationSpec = { - type: 'url', - target: 'http://example.com/component.json', - }; - - const buffer = Buffer.from([]); - const never = jest.fn(); - - expect(await processor.parseData(buffer, wrongLocationSpec, never)).toBe( - false, - ); - - expect(never).not.toBeCalled(); - }); - - it('should process url that contains yaml', async () => { - const containsYamlLocationSpec = { - type: 'url', - target: 'http://example.com/component?path=test.yaml&c=1&d=2', - }; - - const buffer = Buffer.from([]); - const emit = jest.fn(); - - expect( - await processor.parseData(buffer, containsYamlLocationSpec, emit), - ).toBe(true); - - expect(emit).toBeCalled(); - }); - - it('should process entity with yaml', async () => { - const entity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Component', - metadata: { - name: 'my-component', - }, - spec: {}, - } as Entity; - - const buffer = encodeEntity(yaml.stringify(entity)); - const emit = jest.fn(); - - expect(await processor.parseData(buffer, locationSpec, emit)).toBe(true); - - const e = emit.mock.calls[0][0] as CatalogProcessorEntityResult; - expect(e.type).toBe('entity'); - expect(e.location).toBe(locationSpec); - expect(e.entity).toEqual(entity); - }); - - it('should process multiple entities with yaml', async () => { - const entityComponent = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Component', - metadata: { - name: 'my-component', - }, - spec: {}, - } as Entity; - - const entityApi = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'API', - metadata: { - name: 'my-api', - }, - spec: {}, - } as Entity; - - const buffer = encodeEntity( - `${yaml.stringify(entityComponent)}---\n${yaml.stringify(entityApi)}`, - ); - const emit = jest.fn(); - - expect(await processor.parseData(buffer, locationSpec, emit)).toBe(true); - - const eComponent = emit.mock.calls[0][0] as CatalogProcessorEntityResult; - expect(eComponent.type).toBe('entity'); - expect(eComponent.location).toBe(locationSpec); - expect(eComponent.entity).toEqual(entityComponent); - - const eApi = emit.mock.calls[1][0] as CatalogProcessorEntityResult; - expect(eApi.type).toBe('entity'); - expect(eApi.location).toBe(locationSpec); - expect(eApi.entity).toEqual(entityApi); - }); - - it('should fail process entity on invalid yaml', async () => { - const buffer = encodeEntity('{'); - const emit = jest.fn(); - - expect(await processor.parseData(buffer, locationSpec, emit)).toBe(true); - - const e = emit.mock.calls[0][0] as CatalogProcessorErrorResult; - expect(e.error.message).toMatch(/^YAML error, /); - expect(e.type).toBe('error'); - expect(e.location).toBe(locationSpec); - }); - - it('should fail process entity if not object at root', async () => { - const buffer = encodeEntity('[]'); - const emit = jest.fn(); - - expect(await processor.parseData(buffer, locationSpec, emit)).toBe(true); - - const e = emit.mock.calls[0][0] as CatalogProcessorErrorResult; - expect(e.error.message).toMatch(/^Expected object at root, got /); - expect(e.type).toBe('error'); - expect(e.location).toBe(locationSpec); - }); -}); diff --git a/plugins/catalog-backend/src/ingestion/processors/YamlProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/YamlProcessor.ts deleted file mode 100644 index 46df4e6a2b..0000000000 --- a/plugins/catalog-backend/src/ingestion/processors/YamlProcessor.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Entity, LocationSpec } from '@backstage/catalog-model'; -import lodash from 'lodash'; -import yaml from 'yaml'; -import * as result from './results'; -import { CatalogProcessor, CatalogProcessorEmit } from './types'; - -/** - * Handles incoming raw data buffers, and if they have a yaml extension, - * attempts to parse them into structured data and emitting them as un- - * validated entities. - */ -export class YamlProcessor implements CatalogProcessor { - async parseData( - data: Buffer, - location: LocationSpec, - emit: CatalogProcessorEmit, - ): Promise { - if (!location.target.match(/\.ya?ml/)) { - return false; - } - - let documents: yaml.Document.Parsed[]; - try { - documents = yaml.parseAllDocuments(data.toString('utf8')).filter(d => d); - } catch (e) { - emit(result.generalError(location, `Failed to parse YAML, ${e}`)); - return true; - } - - for (const document of documents) { - if (document.errors?.length) { - const message = `YAML error, ${document.errors[0]}`; - emit(result.generalError(location, message)); - } else { - const json = document.toJSON(); - if (lodash.isPlainObject(json)) { - emit(result.entity(location, json as Entity)); - } else { - const message = `Expected object at root, got ${typeof json}`; - emit(result.generalError(location, message)); - } - } - } - - return true; - } -} diff --git a/plugins/catalog-backend/src/ingestion/processors/index.ts b/plugins/catalog-backend/src/ingestion/processors/index.ts index 8344678e5f..d654f37dc7 100644 --- a/plugins/catalog-backend/src/ingestion/processors/index.ts +++ b/plugins/catalog-backend/src/ingestion/processors/index.ts @@ -29,4 +29,3 @@ export { PlaceholderProcessor } from './PlaceholderProcessor'; export type { PlaceholderResolver } from './PlaceholderProcessor'; export { StaticLocationProcessor } from './StaticLocationProcessor'; export { UrlReaderProcessor } from './UrlReaderProcessor'; -export { YamlProcessor } from './YamlProcessor'; diff --git a/plugins/catalog-backend/src/ingestion/processors/results.ts b/plugins/catalog-backend/src/ingestion/processors/results.ts index 158bc3d950..5f92087cec 100644 --- a/plugins/catalog-backend/src/ingestion/processors/results.ts +++ b/plugins/catalog-backend/src/ingestion/processors/results.ts @@ -51,13 +51,6 @@ export function generalError( return { type: 'error', location: atLocation, error: new Error(message) }; } -export function data( - atLocation: LocationSpec, - newData: Buffer, -): CatalogProcessorResult { - return { type: 'data', location: atLocation, data: newData }; -} - export function location( newLocation: LocationSpec, optional: boolean, diff --git a/plugins/catalog-backend/src/ingestion/processors/types.ts b/plugins/catalog-backend/src/ingestion/processors/types.ts index 7821a61437..5d353d5af0 100644 --- a/plugins/catalog-backend/src/ingestion/processors/types.ts +++ b/plugins/catalog-backend/src/ingestion/processors/types.ts @@ -35,20 +35,6 @@ export type CatalogProcessor = { emit: CatalogProcessorEmit, ): Promise; - /** - * Parses a raw data buffer that was read from a location. - * - * @param data The data to parse - * @param location The location that the data came from - * @param emit A sink for items resulting from the parsing - * @returns True if handled by this processor, false otherwise - */ - parseData?( - data: Buffer, - location: LocationSpec, - emit: CatalogProcessorEmit, - ): Promise; - /** * Pre-processes an emitted entity, after it has been emitted but before it * has been validated. @@ -105,12 +91,6 @@ export type CatalogProcessorLocationResult = { optional: boolean; }; -export type CatalogProcessorDataResult = { - type: 'data'; - data: Buffer; - location: LocationSpec; -}; - export type CatalogProcessorEntityResult = { type: 'entity'; entity: Entity; @@ -131,7 +111,6 @@ export type CatalogProcessorErrorResult = { export type CatalogProcessorResult = | CatalogProcessorLocationResult - | CatalogProcessorDataResult | CatalogProcessorEntityResult | CatalogProcessorRelationResult | CatalogProcessorErrorResult; diff --git a/plugins/catalog-backend/src/ingestion/processors/util/parse.test.ts b/plugins/catalog-backend/src/ingestion/processors/util/parse.test.ts new file mode 100644 index 0000000000..1400a066cd --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/processors/util/parse.test.ts @@ -0,0 +1,180 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { parseEntityYaml } from './parse'; +import * as result from '../results'; + +const testLoc = { + target: 'my-loc-target', + type: 'my-loc-type', +}; + +describe('parseEntityYaml', () => { + it('should parse a yaml', () => { + const results = Array.from( + parseEntityYaml( + Buffer.from( + ` + apiVersion: backstage.io/v1alpha1 + kind: Component + metadata: + name: backstage + description: backstage.io + annotations: + github.com/project-slug: 'spotify/backstage' + spec: + type: website + lifecycle: production + owner: guest + `, + 'utf8', + ), + testLoc, + ), + ); + + expect(results).toEqual([ + result.entity(testLoc, { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'backstage', + description: 'backstage.io', + annotations: { + 'github.com/project-slug': 'spotify/backstage', + }, + }, + spec: { + type: 'website', + lifecycle: 'production', + owner: 'guest', + }, + }), + ]); + }); + + it('should parse multiple docs', () => { + const results = Array.from( + parseEntityYaml( + Buffer.from( + ` + apiVersion: backstage.io/v1alpha1 + kind: Component + metadata: + name: web + spec: + type: website +--- + apiVersion: backstage.io/v1alpha1 + kind: Component + metadata: + name: srv + spec: + type: service + `, + 'utf8', + ), + testLoc, + ), + ); + + expect(results).toEqual([ + result.entity(testLoc, { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'web', + }, + spec: { + type: 'website', + }, + }), + result.entity(testLoc, { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'srv', + }, + spec: { + type: 'service', + }, + }), + ]); + }); + + it('should emit parsing errors', () => { + const results = Array.from( + parseEntityYaml(Buffer.from('`', 'utf8'), testLoc), + ); + + // Parse errors are always per document + expect(results).toEqual([ + result.generalError( + testLoc, + 'YAML error, YAMLSemanticError: Plain value cannot start with reserved character `', + ), + ]); + }); + + it('should emit parsing errors for individual documents', () => { + const results = Array.from( + parseEntityYaml( + Buffer.from( + ` + apiVersion: backstage.io/v1alpha1 + kind: Component + metadata: + name: web + spec: + type: website +--- + apiVersion: backstage.io/v1alpha1 + this: - is - not [valid] yaml + `, + 'utf8', + ), + testLoc, + ), + ); + + expect(results).toEqual([ + result.entity(testLoc, { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'web', + }, + spec: { + type: 'website', + }, + }), + result.generalError( + testLoc, + 'YAML error, YAMLSemanticError: Nested mappings are not allowed in compact mappings', + ), + ]); + }); + + it('must be an object at root', () => { + const results = Array.from( + parseEntityYaml(Buffer.from('imma-string', 'utf8'), testLoc), + ); + + expect(results).toEqual([ + result.generalError(testLoc, 'Expected object at root, got string'), + ]); + }); +}); diff --git a/plugins/catalog-backend/src/ingestion/processors/util/parse.ts b/plugins/catalog-backend/src/ingestion/processors/util/parse.ts new file mode 100644 index 0000000000..3f07a815b0 --- /dev/null +++ b/plugins/catalog-backend/src/ingestion/processors/util/parse.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Entity, LocationSpec } from '@backstage/catalog-model'; +import lodash from 'lodash'; +import yaml from 'yaml'; +import * as result from '../results'; +import { CatalogProcessorResult } from '../types'; + +export function* parseEntityYaml( + data: Buffer, + location: LocationSpec, +): Iterable { + let documents: yaml.Document.Parsed[]; + try { + documents = yaml.parseAllDocuments(data.toString('utf8')).filter(d => d); + } catch (e) { + yield result.generalError(location, `Failed to parse YAML, ${e}`); + return; + } + + for (const document of documents) { + if (document.errors?.length) { + const message = `YAML error, ${document.errors[0]}`; + yield result.generalError(location, message); + } else { + const json = document.toJSON(); + if (lodash.isPlainObject(json)) { + yield result.entity(location, json as Entity); + } else { + const message = `Expected object at root, got ${typeof json}`; + yield result.generalError(location, message); + } + } + } +} diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.test.ts b/plugins/catalog-backend/src/service/CatalogBuilder.test.ts index bc71934488..4e474c287a 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.test.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.test.ts @@ -83,15 +83,6 @@ describe('CatalogBuilder', () => { emit: CatalogProcessorEmit, ) { expect(location.type).toBe('test'); - emit(result.data(location, await reader.read('ignored'))); - return true; - }, - async parseData( - data: Buffer, - location: LocationSpec, - emit: CatalogProcessorEmit, - ) { - expect(data.toString()).toEqual('junk'); emit( result.entity(location, { apiVersion: 'av', @@ -123,7 +114,7 @@ describe('CatalogBuilder', () => { type: 'test', target: '', }); - expect.assertions(8); + expect.assertions(7); expect(added.entities).toEqual([ { apiVersion: 'av', diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index e795310915..485e66acbb 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -56,7 +56,6 @@ import { PlaceholderResolver, StaticLocationProcessor, UrlReaderProcessor, - YamlProcessor, } from '../ingestion'; import { CatalogRulesEnforcer } from '../ingestion/CatalogRules'; import { LdapOrgReaderProcessor } from '../ingestion/processors/LdapOrgReaderProcessor'; @@ -329,7 +328,6 @@ export class CatalogBuilder { GithubOrgReaderProcessor.fromConfig(config, { logger }), LdapOrgReaderProcessor.fromConfig(config, { logger }), new UrlReaderProcessor({ reader, logger }), - new YamlProcessor(), new CodeOwnersProcessor({ reader }), new LocationRefProcessor(), new OwnerRelationProcessor(), From 24e5730200befee2965f788696f9234edd554652 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 27 Oct 2020 10:07:25 +0100 Subject: [PATCH 20/33] techdocs-backend: remove duplicate log tagging --- .../techdocs-backend/src/service/helpers.ts | 18 +++++------------- plugins/techdocs-backend/src/service/router.ts | 6 ++---- .../src/techdocs/stages/generate/techdocs.ts | 8 ++++---- .../src/techdocs/stages/prepare/dir.ts | 2 +- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/plugins/techdocs-backend/src/service/helpers.ts b/plugins/techdocs-backend/src/service/helpers.ts index 1b8e130ec0..b308dc28af 100644 --- a/plugins/techdocs-backend/src/service/helpers.ts +++ b/plugins/techdocs-backend/src/service/helpers.ts @@ -66,22 +66,16 @@ export class DocsBuilder { } public async build() { - this.logger.info( - `[TechDocs] Running preparer on entity ${getEntityId(this.entity)}`, - ); + this.logger.info(`Running preparer on entity ${getEntityId(this.entity)}`); const preparedDir = await this.preparer.prepare(this.entity); - this.logger.info( - `[TechDocs] Running generator on entity ${getEntityId(this.entity)}`, - ); + this.logger.info(`Running generator on entity ${getEntityId(this.entity)}`); const { resultDir } = await this.generator.run({ directory: preparedDir, dockerClient: this.dockerClient, }); - this.logger.info( - `[TechDocs] Running publisher on entity ${getEntityId(this.entity)}`, - ); + this.logger.info(`Running publisher on entity ${getEntityId(this.entity)}`); await this.publisher.publish({ entity: this.entity, directory: resultDir, @@ -117,16 +111,14 @@ export class DocsBuilder { // Check if documentation source is newer than what we have if (storageTimeStamp && storageTimeStamp >= lastCommit) { this.logger.debug( - `[TechDocs] Docs for entity ${getEntityId( - this.entity, - )} is up to date.`, + `Docs for entity ${getEntityId(this.entity)} is up to date.`, ); return true; } } this.logger.debug( - `[TechDocs] Docs for entity ${getEntityId(this.entity)} was outdated.`, + `Docs for entity ${getEntityId(this.entity)} was outdated.`, ); return false; } diff --git a/plugins/techdocs-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index b6f8865a57..2254e721bd 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -71,9 +71,7 @@ export async function createRouter({ const mkDocsMetadata = await (await fetch(metadataURL)).json(); res.send(mkDocsMetadata); } catch (err) { - logger.info( - `[TechDocs] Unable to get metadata for ${path} with error ${err}`, - ); + logger.info(`Unable to get metadata for ${path} with error ${err}`); throw new Error(`Unable to get metadata for ${path} with error ${err}`); } }); @@ -93,7 +91,7 @@ export async function createRouter({ res.send({ ...entity, locationMetadata }); } catch (err) { logger.info( - `[TechDocs] Unable to get metadata for ${kind}/${namespace}/${name} with error ${err}`, + `Unable to get metadata for ${kind}/${namespace}/${name} with error ${err}`, ); throw new Error( `Unable to get metadata for ${kind}/${namespace}/${name} with error ${err}`, diff --git a/plugins/techdocs-backend/src/techdocs/stages/generate/techdocs.ts b/plugins/techdocs-backend/src/techdocs/stages/generate/techdocs.ts index ac73963f9a..1160ff1ade 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/generate/techdocs.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/generate/techdocs.ts @@ -83,7 +83,7 @@ export class TechdocsGenerator implements GeneratorBase { logStream, }); this.logger.info( - `[TechDocs]: Successfully generated docs from ${directory} into ${resultDir} using local mkdocs`, + `Successfully generated docs from ${directory} into ${resultDir} using local mkdocs`, ); break; case 'docker': @@ -96,7 +96,7 @@ export class TechdocsGenerator implements GeneratorBase { dockerClient, }); this.logger.info( - `[TechDocs]: Successfully generated docs from ${directory} into ${resultDir} using techdocs-container`, + `Successfully generated docs from ${directory} into ${resultDir} using techdocs-container`, ); break; default: @@ -106,9 +106,9 @@ export class TechdocsGenerator implements GeneratorBase { } } catch (error) { this.logger.debug( - `[TechDocs]: Failed to generate docs from ${directory} into ${resultDir}`, + `Failed to generate docs from ${directory} into ${resultDir}`, ); - this.logger.debug(`[TechDocs]: Build failed with error: ${log}`); + this.logger.debug(`Build failed with error: ${log}`); throw new Error( `Failed to generate docs from ${directory} into ${resultDir} with error ${error.message}`, ); diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.ts index d76aee25bd..1effcf61b5 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.ts @@ -38,7 +38,7 @@ export class DirectoryPreparer implements PreparerBase { ); this.logger.debug( - `[TechDocs] Building docs for entity with type 'dir' and managed-by-location '${type}'`, + `Building docs for entity with type 'dir' and managed-by-location '${type}'`, ); switch (type) { case 'github': From 796b844cb3492cf6ed0615ea99d02fcc18789eab Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 27 Oct 2020 11:05:42 +0100 Subject: [PATCH 21/33] chore(docs): more docs around proxy setup --- .../docs/tutorials/help-im-behind-a-corporate-proxy.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md b/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md index d02fa4b510..4f8351ac15 100644 --- a/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md +++ b/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md @@ -42,9 +42,16 @@ import ProxyAgent from 'proxy-agent'; import http from 'http'; import https from 'https'; +/* + Something to note here, this might need different configuration depending on your own setup. + If you only have an http_proxy then you'll need to set that as both the http and https globalAgent instead. +*/ if (process.env.HTTP_PROXY) { http.globalAgent = new ProxyAgent(process.env.HTTP_PROXY); - https.globalAgent = new ProxyAgent(process.env.HTTP_PROXY); +} + +if (process.env.HTTPS_PROXY) { + https.globalAgent = new ProxyAgent(process.env.HTTPS_PROXY); } ``` From 754109ee6153d209766898e72dc2841c81749d06 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 27 Oct 2020 12:00:01 +0100 Subject: [PATCH 22/33] v0.1.1-alpha.26 --- lerna.json | 2 +- packages/app/package.json | 56 ++++++++++++------------- packages/backend-common/package.json | 12 +++--- packages/backend/package.json | 32 +++++++------- packages/catalog-model/package.json | 6 +-- packages/cli-common/package.json | 2 +- packages/cli/package.json | 8 ++-- packages/config-loader/package.json | 4 +- packages/config/package.json | 2 +- packages/core-api/package.json | 12 +++--- packages/core/package.json | 12 +++--- packages/create-app/package.json | 4 +- packages/dev-utils/package.json | 10 ++--- packages/docgen/package.json | 2 +- packages/e2e-test/package.json | 6 +-- packages/storybook/package.json | 4 +- packages/techdocs-cli/package.json | 4 +- packages/test-utils-core/package.json | 2 +- packages/test-utils/package.json | 10 ++--- packages/theme/package.json | 4 +- plugins/api-docs/package.json | 20 ++++----- plugins/app-backend/package.json | 8 ++-- plugins/auth-backend/package.json | 12 +++--- plugins/catalog-backend/package.json | 12 +++--- plugins/catalog-graphql/package.json | 16 +++---- plugins/catalog/package.json | 22 +++++----- plugins/circleci/package.json | 18 ++++---- plugins/cloudbuild/package.json | 18 ++++---- plugins/cost-insights/package.json | 20 ++++----- plugins/explore/package.json | 16 +++---- plugins/gcp-projects/package.json | 14 +++---- plugins/github-actions/package.json | 20 ++++----- plugins/gitops-profiles/package.json | 14 +++---- plugins/graphiql/package.json | 16 +++---- plugins/graphql/package.json | 10 ++--- plugins/jenkins/package.json | 18 ++++---- plugins/kubernetes-backend/package.json | 8 ++-- plugins/kubernetes/package.json | 22 +++++----- plugins/lighthouse/package.json | 24 +++++------ plugins/newrelic/package.json | 14 +++---- plugins/proxy-backend/package.json | 8 ++-- plugins/register-component/package.json | 18 ++++---- plugins/rollbar-backend/package.json | 8 ++-- plugins/rollbar/package.json | 20 ++++----- plugins/scaffolder-backend/package.json | 10 ++--- plugins/scaffolder/package.json | 20 ++++----- plugins/sentry-backend/package.json | 6 +-- plugins/sentry/package.json | 14 +++---- plugins/tech-radar/package.json | 16 +++---- plugins/techdocs-backend/package.json | 12 +++--- plugins/techdocs/package.json | 22 +++++----- plugins/user-settings/package.json | 16 +++---- plugins/welcome/package.json | 16 +++---- 53 files changed, 351 insertions(+), 351 deletions(-) diff --git a/lerna.json b/lerna.json index f804c800de..5871423f78 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "packages": ["packages/*", "plugins/*"], "npmClient": "yarn", "useWorkspaces": true, - "version": "0.1.1-alpha.25" + "version": "0.1.1-alpha.26" } diff --git a/packages/app/package.json b/packages/app/package.json index dc452e0803..bb446a3458 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,36 +1,36 @@ { "name": "example-app", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": true, "bundled": true, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-api-docs": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/plugin-circleci": "^0.1.1-alpha.25", - "@backstage/plugin-cloudbuild": "^0.1.1-alpha.25", - "@backstage/plugin-cost-insights": "^0.1.1-alpha.25", - "@backstage/plugin-explore": "^0.1.1-alpha.25", - "@backstage/plugin-gcp-projects": "^0.1.1-alpha.25", - "@backstage/plugin-github-actions": "^0.1.1-alpha.25", - "@backstage/plugin-gitops-profiles": "^0.1.1-alpha.25", - "@backstage/plugin-graphiql": "^0.1.1-alpha.25", - "@backstage/plugin-jenkins": "^0.1.1-alpha.25", - "@backstage/plugin-kubernetes": "^0.1.1-alpha.25", - "@backstage/plugin-lighthouse": "^0.1.1-alpha.25", - "@backstage/plugin-newrelic": "^0.1.1-alpha.25", - "@backstage/plugin-register-component": "^0.1.1-alpha.25", - "@backstage/plugin-rollbar": "^0.1.1-alpha.25", - "@backstage/plugin-scaffolder": "^0.1.1-alpha.25", - "@backstage/plugin-sentry": "^0.1.1-alpha.25", - "@backstage/plugin-tech-radar": "^0.1.1-alpha.25", - "@backstage/plugin-techdocs": "^0.1.1-alpha.25", - "@backstage/plugin-user-settings": "^0.1.1-alpha.25", - "@backstage/plugin-welcome": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-api-docs": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/plugin-circleci": "^0.1.1-alpha.26", + "@backstage/plugin-cloudbuild": "^0.1.1-alpha.26", + "@backstage/plugin-cost-insights": "^0.1.1-alpha.26", + "@backstage/plugin-explore": "^0.1.1-alpha.26", + "@backstage/plugin-gcp-projects": "^0.1.1-alpha.26", + "@backstage/plugin-github-actions": "^0.1.1-alpha.26", + "@backstage/plugin-gitops-profiles": "^0.1.1-alpha.26", + "@backstage/plugin-graphiql": "^0.1.1-alpha.26", + "@backstage/plugin-jenkins": "^0.1.1-alpha.26", + "@backstage/plugin-kubernetes": "^0.1.1-alpha.26", + "@backstage/plugin-lighthouse": "^0.1.1-alpha.26", + "@backstage/plugin-newrelic": "^0.1.1-alpha.26", + "@backstage/plugin-register-component": "^0.1.1-alpha.26", + "@backstage/plugin-rollbar": "^0.1.1-alpha.26", + "@backstage/plugin-scaffolder": "^0.1.1-alpha.26", + "@backstage/plugin-sentry": "^0.1.1-alpha.26", + "@backstage/plugin-tech-radar": "^0.1.1-alpha.26", + "@backstage/plugin-techdocs": "^0.1.1-alpha.26", + "@backstage/plugin-user-settings": "^0.1.1-alpha.26", + "@backstage/plugin-welcome": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@octokit/rest": "^18.0.0", diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 875163dd96..dea2f16bae 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.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/cli-common": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/config-loader": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli-common": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/config-loader": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@types/cors": "^2.8.6", "@types/express": "^4.17.6", "compression": "^1.7.4", @@ -62,7 +62,7 @@ } }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@types/compression": "^1.7.0", "@types/http-errors": "^1.6.3", "@types/minimist": "^1.2.0", diff --git a/packages/backend/package.json b/packages/backend/package.json index ef55b007a7..9f8e66bc61 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "dist/index.cjs.js", "types": "src/index.ts", "private": true, @@ -18,24 +18,24 @@ "migrate:create": "knex migrate:make -x ts" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/plugin-app-backend": "^0.1.1-alpha.25", - "@backstage/plugin-auth-backend": "^0.1.1-alpha.25", - "@backstage/plugin-catalog-backend": "^0.1.1-alpha.25", - "@backstage/plugin-graphql-backend": "^0.1.1-alpha.25", - "@backstage/plugin-kubernetes-backend": "^0.1.1-alpha.25", - "@backstage/plugin-proxy-backend": "^0.1.1-alpha.25", - "@backstage/plugin-rollbar-backend": "^0.1.1-alpha.25", - "@backstage/plugin-scaffolder-backend": "^0.1.1-alpha.25", - "@backstage/plugin-sentry-backend": "^0.1.1-alpha.25", - "@backstage/plugin-techdocs-backend": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/plugin-app-backend": "^0.1.1-alpha.26", + "@backstage/plugin-auth-backend": "^0.1.1-alpha.26", + "@backstage/plugin-catalog-backend": "^0.1.1-alpha.26", + "@backstage/plugin-graphql-backend": "^0.1.1-alpha.26", + "@backstage/plugin-kubernetes-backend": "^0.1.1-alpha.26", + "@backstage/plugin-proxy-backend": "^0.1.1-alpha.26", + "@backstage/plugin-rollbar-backend": "^0.1.1-alpha.26", + "@backstage/plugin-scaffolder-backend": "^0.1.1-alpha.26", + "@backstage/plugin-sentry-backend": "^0.1.1-alpha.26", + "@backstage/plugin-techdocs-backend": "^0.1.1-alpha.26", "@gitbeaker/node": "^23.5.0", "@octokit/rest": "^18.0.0", "azure-devops-node-api": "^10.1.1", "dockerode": "^3.2.0", - "example-app": "^0.1.1-alpha.25", + "example-app": "^0.1.1-alpha.26", "express": "^4.17.1", "express-promise-router": "^3.0.3", "knex": "^0.21.1", @@ -45,7 +45,7 @@ "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@types/dockerode": "^2.5.32", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 5ba2b6efdf..c97aea9572 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-model", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/config": "^0.1.1-alpha.26", "@types/json-schema": "^7.0.5", "@types/yup": "^0.29.8", "json-schema": "^0.2.5", @@ -29,7 +29,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@types/express": "^4.17.6", "@types/jest": "^26.0.7", "@types/lodash": "^4.14.151", diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index d9492ef127..56fb0d3417 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/cli-common", "description": "Common functionality used by cli, backend, and create-app", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/cli/package.json b/packages/cli/package.json index 3024c2eeaf..8a330d861b 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.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public" @@ -28,9 +28,9 @@ "backstage-cli": "bin/backstage-cli" }, "dependencies": { - "@backstage/cli-common": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/config-loader": "^0.1.1-alpha.25", + "@backstage/cli-common": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/config-loader": "^0.1.1-alpha.26", "@hot-loader/react-dom": "^16.13.0", "@lerna/package-graph": "^3.18.5", "@lerna/project": "^3.18.0", diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index eead016c8f..2eef7db027 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config-loader", "description": "Config loading functionality used by Backstage backend, and CLI", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", @@ -30,7 +30,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/config": "^0.1.1-alpha.26", "fs-extra": "^9.0.0", "yaml": "^1.9.2", "yup": "^0.29.3" diff --git a/packages/config/package.json b/packages/config/package.json index 589c87c15c..d8ee50e97c 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/config", "description": "Config API used by Backstage core, backend, and CLI", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", diff --git a/packages/core-api/package.json b/packages/core-api/package.json index 5b1456d1ba..34949e4315 100644 --- a/packages/core-api/package.json +++ b/packages/core-api/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core-api", "description": "Internal Core API used by Backstage plugins and apps", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@types/react": "^16.9", @@ -42,8 +42,8 @@ "zen-observable": "^0.8.15" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/test-utils-core": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/test-utils-core": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/packages/core/package.json b/packages/core/package.json index 2b0fa58266..ec4411b390 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/core", "description": "Core API used by Backstage plugins and apps", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", @@ -29,9 +29,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/core-api": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/core-api": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -55,8 +55,8 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 44745a7a81..ff9e1fa636 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/create-app", "description": "Create app package for Backstage", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public" @@ -27,7 +27,7 @@ "start": "nodemon --" }, "dependencies": { - "@backstage/cli-common": "^0.1.1-alpha.25", + "@backstage/cli-common": "^0.1.1-alpha.26", "chalk": "^4.0.0", "commander": "^6.1.0", "fs-extra": "^9.0.0", diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 21793bda81..d61336465f 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/dev-utils", "description": "Utilities for developing Backstage plugins.", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@testing-library/jest-dom": "^5.10.1", diff --git a/packages/docgen/package.json b/packages/docgen/package.json index 7c0bf846bd..18f26d6941 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,7 +1,7 @@ { "name": "docgen", "description": "Tool for generating API Documentation for itself", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": true, "homepage": "https://backstage.io", "repository": { diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 764e3c415a..9098b3cd07 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,7 +1,7 @@ { "name": "e2e-test", "description": "E2E test for verifying Backstage packages", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": true, "homepage": "https://backstage.io", "repository": { @@ -24,14 +24,14 @@ "e2e-test": "bin/e2e-test" }, "devDependencies": { - "@backstage/cli-common": "^0.1.1-alpha.25", + "@backstage/cli-common": "^0.1.1-alpha.26", "@types/fs-extra": "^9.0.1", "@types/node": "^13.7.2", "chalk": "^4.0.0", "commander": "^6.1.0", + "cross-fetch": "^3.0.6", "fs-extra": "^9.0.0", "handlebars": "^4.7.3", - "cross-fetch": "^3.0.6", "pgtools": "^0.3.0", "tree-kill": "^1.2.2", "ts-node": "^8.6.2", diff --git a/packages/storybook/package.json b/packages/storybook/package.json index b1e45a26b6..9eefd85128 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "description": "Storybook build for core package", "private": true, "scripts": { @@ -14,7 +14,7 @@ ] }, "dependencies": { - "@backstage/theme": "^0.1.1-alpha.25" + "@backstage/theme": "^0.1.1-alpha.26" }, "devDependencies": { "@storybook/addon-actions": "^6.0.21", diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 30ca6e4538..c111a2973a 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,7 +1,7 @@ { "name": "@techdocs/cli", "description": "CLI for running TechDocs locally.", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public" @@ -40,7 +40,7 @@ "ext": "ts" }, "dependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "commander": "^6.1.0", "fs-extra": "^9.0.1", "http-proxy": "^1.18.1", diff --git a/packages/test-utils-core/package.json b/packages/test-utils-core/package.json index 96d153d397..1db8f6f023 100644 --- a/packages/test-utils-core/package.json +++ b/packages/test-utils-core/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils-core", "description": "Utilities to test Backstage core", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 2a290802d3..74e0c8dcf7 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/test-utils", "description": "Utilities to test Backstage plugins and apps.", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", @@ -29,10 +29,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/core-api": "^0.1.1-alpha.25", - "@backstage/test-utils-core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/core-api": "^0.1.1-alpha.26", + "@backstage/test-utils-core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/packages/theme/package.json b/packages/theme/package.json index 95d0ee150b..ddec0e7981 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/theme", "description": "material-ui theme for use with Backstage.", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", @@ -31,7 +31,7 @@ "@material-ui/core": "^4.11.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25" + "@backstage/cli": "^0.1.1-alpha.26" }, "files": [ "dist" diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 6820027c6e..baf574d5b5 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,10 +20,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@kyma-project/asyncapi-react": "^0.13.1", "@material-icons/font": "^1.0.2", "@material-ui/core": "^4.11.0", @@ -39,9 +39,9 @@ "swagger-ui-react": "^3.31.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", @@ -49,8 +49,8 @@ "@types/node": "^12.0.0", "@types/react": "^16.9", "@types/swagger-ui-react": "^3.23.3", - "msw": "^0.21.2", - "cross-fetch": "^3.0.6" + "cross-fetch": "^3.0.6", + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index b402d9fa5b..8297b466af 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/config-loader": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/config-loader": "^0.1.1-alpha.26", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^3.0.3", @@ -30,7 +30,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@types/supertest": "^2.0.8", "msw": "^0.20.5", "supertest": "^4.0.2" diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 25129f33f7..6489c8547d 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,13 +20,14 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", "@types/express": "^4.17.6", "compression": "^1.7.4", "cookie-parser": "^1.4.5", "cors": "^2.8.5", + "cross-fetch": "^3.0.6", "express": "^4.17.1", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.0", @@ -47,11 +48,10 @@ "passport-saml": "^1.3.3", "uuid": "^8.0.0", "winston": "^3.2.1", - "cross-fetch": "^3.0.6", "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@types/body-parser": "^1.19.0", "@types/cookie-parser": "^1.4.2", "@types/jwt-decode": "2.2.1", diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 7d41da2888..cd8e363901 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "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.1.1-alpha.25", - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", "@octokit/graphql": "^4.5.6", "@types/express": "^4.17.6", "codeowners-utils": "^1.0.2", @@ -45,8 +45,8 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@types/core-js": "^2.5.4", "@types/git-url-parse": "^9.0.0", "@types/ldapjs": "^1.0.9", diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index 3c8c45d246..f74aaf7b57 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-graphql", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,28 +20,28 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", "@graphql-modules/core": "^0.7.17", "apollo-server": "^2.16.1", + "cross-fetch": "^3.0.6", "graphql": "^15.3.0", "graphql-tag": "^2.11.0", "graphql-type-json": "^0.3.2", - "cross-fetch": "^3.0.6", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@graphql-codegen/cli": "^1.17.7", "@graphql-codegen/typescript": "^1.17.7", "@graphql-codegen/typescript-resolvers": "^1.17.7", "@types/express": "^4.17.7", "@types/supertest": "^2.0.8", "eslint-plugin-graphql": "^4.0.0", - "supertest": "^4.0.2", "msw": "^0.21.2", + "supertest": "^4.0.2", "ts-node": "^8.10.2" }, "files": [ diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 3d0c932cdd..663ac7554b 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-scaffolder": "^0.1.1-alpha.25", - "@backstage/plugin-techdocs": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-scaffolder": "^0.1.1-alpha.26", + "@backstage/plugin-techdocs": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -41,18 +41,18 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/react-hooks": "^3.3.0", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", + "cross-fetch": "^3.0.6", "msw": "^0.21.2", - "react-test-renderer": "^16.13.1", - "cross-fetch": "^3.0.6" + "react-test-renderer": "^16.13.1" }, "files": [ "dist" diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index 464bb41441..7733d713ab 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-circleci", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "postpack": "backstage-cli postpack" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -38,17 +38,17 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", "@types/react-lazylog": "^4.5.0", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/cloudbuild/package.json b/plugins/cloudbuild/package.json index f8bf338dd1..29bfd1b261 100644 --- a/plugins/cloudbuild/package.json +++ b/plugins/cloudbuild/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cloudbuild", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,10 +20,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -39,16 +39,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index e79c4ab962..eae19fecb1 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-cost-insights", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,10 +21,10 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -44,18 +44,18 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.25", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "@types/yup": "^0.29.8", "@types/recharts": "^1.8.14", - "msw": "^0.21.2", + "@types/yup": "^0.29.8", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/explore/package.json b/plugins/explore/package.json index c3e08dc9fe..4db68909b9 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-explore", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -33,16 +33,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", - "cross-fetch": "^3.0.6" + "cross-fetch": "^3.0.6", + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json index 783504a2cf..4c6375ebf6 100644 --- a/plugins/gcp-projects/package.json +++ b/plugins/gcp-projects/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gcp-projects", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -31,16 +31,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index 63390fdcc0..75fed63465 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-github-actions", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,11 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/core-api": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/core-api": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -40,16 +40,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index 2daa8b103e..18486bc2b7 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-gitops-profiles", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -32,16 +32,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index bda33bb43e..9e1ffd5ef1 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -1,7 +1,7 @@ { "name": "@backstage/plugin-graphiql", "description": "Backstage plugin for browsing GraphQL APIs", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "private": false, "publishConfig": { "access": "public", @@ -31,8 +31,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -43,18 +43,18 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/codemirror": "^0.0.97", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", + "cross-fetch": "^3.0.6", "msw": "^0.21.2", - "react-router-dom": "6.0.0-beta.0", - "cross-fetch": "^3.0.6" + "react-router-dom": "6.0.0-beta.0" }, "files": [ "dist" diff --git a/plugins/graphql/package.json b/plugins/graphql/package.json index 63fb2c88db..58b6c763c6 100644 --- a/plugins/graphql/package.json +++ b/plugins/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-graphql-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -19,9 +19,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/plugin-catalog-graphql": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/plugin-catalog-graphql": "^0.1.1-alpha.26", "@graphql-modules/core": "^0.7.17", "@types/express": "^4.17.6", "apollo-server": "^2.16.1", @@ -35,7 +35,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@types/supertest": "^2.0.8", "eslint-plugin-graphql": "^4.0.0", "msw": "^0.20.5", diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index b3f19b2b16..194ae71429 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-jenkins", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "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.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -36,17 +36,17 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", "@types/testing-library__jest-dom": "^5.9.1", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index fc068621ee..26cc842db9 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", "@kubernetes/client-node": "^0.12.1", "@types/express": "^4.17.6", "compression": "^1.7.4", @@ -37,7 +37,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "supertest": "^4.0.2" }, "files": [ diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 1ab4e4a2fb..6544d751e1 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,11 +20,11 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-kubernetes-backend": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-kubernetes-backend": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@kubernetes/client-node": "^0.12.1", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", @@ -35,16 +35,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", - "cross-fetch": "^3.0.6" + "cross-fetch": "^3.0.6", + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index eb2fdde5bc..8285d29635 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-lighthouse", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,12 +21,12 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/core-api": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/core-api": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -39,16 +39,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", - "cross-fetch": "^3.0.6" + "cross-fetch": "^3.0.6", + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/newrelic/package.json b/plugins/newrelic/package.json index 3372562ca2..b9a12cc648 100644 --- a/plugins/newrelic/package.json +++ b/plugins/newrelic/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-newrelic", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -31,16 +31,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index 0d7cf00509..fcb68dcd78 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -19,8 +19,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^3.0.3", @@ -33,7 +33,7 @@ "yup": "^0.29.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@types/http-proxy-middleware": "^0.19.3", "@types/supertest": "^2.0.8", "@types/uuid": "^8.0.0", diff --git a/plugins/register-component/package.json b/plugins/register-component/package.json index 9729a78d80..5c3f985b4d 100644 --- a/plugins/register-component/package.json +++ b/plugins/register-component/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-register-component", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "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.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -36,16 +36,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/rollbar-backend/package.json b/plugins/rollbar-backend/package.json index e00f046901..cb553d859b 100644 --- a/plugins/rollbar-backend/package.json +++ b/plugins/rollbar-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-rollbar-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,8 +20,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", "@types/express": "^4.17.6", "axios": "^0.20.0", "camelcase-keys": "^6.2.2", @@ -37,7 +37,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@types/supertest": "^2.0.8", "supertest": "^4.0.2" }, diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 4b44d17c62..27421cfd4d 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-rollbar", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "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.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -37,9 +37,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/react-hooks": "^3.3.0", @@ -47,8 +47,8 @@ "@types/jest": "^26.0.7", "@types/node": "^12.0.0", "@types/react": "^16.9", - "msw": "^0.21.2", - "cross-fetch": "^3.0.6" + "cross-fetch": "^3.0.6", + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index ec197dbc55..1c85adc23a 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "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.1.1-alpha.25", - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", "@gitbeaker/core": "^23.5.0", "@gitbeaker/node": "^23.5.0", "@octokit/rest": "^18.0.0", @@ -47,7 +47,7 @@ "yaml": "^1.10.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "@octokit/types": "^5.4.1", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index bda3ff52aa..751f4075b2 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "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.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -41,16 +41,16 @@ "swr": "^0.3.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", - "cross-fetch": "^3.0.6" + "cross-fetch": "^3.0.6", + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/sentry-backend/package.json b/plugins/sentry-backend/package.json index 4702242b2c..b51eb1509a 100644 --- a/plugins/sentry-backend/package.json +++ b/plugins/sentry-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sentry-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,7 +20,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", "@types/express": "^4.17.6", "axios": "^0.20.0", "compression": "^1.7.4", @@ -34,7 +34,7 @@ "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25" + "@backstage/cli": "^0.1.1-alpha.26" }, "files": [ "dist" diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index 0060777491..4d9cd59bc3 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-sentry", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -36,9 +36,9 @@ "timeago.js": "^4.0.2" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 19ac41fa8d..3e05fa85d2 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-tech-radar", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,9 +21,9 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -35,8 +35,9 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.25", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", @@ -45,9 +46,8 @@ "@types/jest": "^26.0.7", "@types/node": "^12.0.0", "@types/react": "^16.9", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index e3878e95b5..5bdc7ba282 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-backend", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -20,12 +20,13 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/backend-common": "^0.1.1-alpha.25", - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/config": "^0.1.1-alpha.25", + "@backstage/backend-common": "^0.1.1-alpha.26", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/config": "^0.1.1-alpha.26", "@types/dockerode": "^2.5.34", "@types/express": "^4.17.6", "command-exists-promise": "^2.0.2", + "cross-fetch": "^3.0.6", "dockerode": "^3.2.1", "express": "^4.17.1", "express-promise-router": "^3.0.3", @@ -33,11 +34,10 @@ "git-url-parse": "^11.4.0", "knex": "^0.21.1", "nodegit": "^0.27.0", - "cross-fetch": "^3.0.6", "winston": "^3.2.1" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", "supertest": "^4.0.2" }, "files": [ diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index eb6bb597d9..9f5a099ad6 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -22,12 +22,12 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/catalog-model": "^0.1.1-alpha.25", - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/core-api": "^0.1.1-alpha.25", - "@backstage/plugin-catalog": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/catalog-model": "^0.1.1-alpha.26", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/core-api": "^0.1.1-alpha.26", + "@backstage/plugin-catalog": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -40,17 +40,17 @@ "sanitize-html": "^1.27.0" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.25", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", "canvas": "^2.6.1", - "msw": "^0.21.2", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25" + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 9748bb1a9e..6f96d7b2fd 100644 --- a/plugins/user-settings/package.json +++ b/plugins/user-settings/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-user-settings", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", @@ -21,8 +21,8 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -32,16 +32,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", "@types/node": "^12.0.0", - "msw": "^0.21.2", - "cross-fetch": "^3.0.6" + "cross-fetch": "^3.0.6", + "msw": "^0.21.2" }, "files": [ "dist" diff --git a/plugins/welcome/package.json b/plugins/welcome/package.json index 653678f1f3..380a4b0a46 100644 --- a/plugins/welcome/package.json +++ b/plugins/welcome/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-welcome", - "version": "0.1.1-alpha.25", + "version": "0.1.1-alpha.26", "main": "src/index.ts", "types": "src/index.ts", "private": false, @@ -21,8 +21,8 @@ "start": "backstage-cli plugin:serve" }, "dependencies": { - "@backstage/core": "^0.1.1-alpha.25", - "@backstage/theme": "^0.1.1-alpha.25", + "@backstage/core": "^0.1.1-alpha.26", + "@backstage/theme": "^0.1.1-alpha.26", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", @@ -32,16 +32,16 @@ "react-use": "^15.3.3" }, "devDependencies": { - "@backstage/cli": "^0.1.1-alpha.25", - "@backstage/dev-utils": "^0.1.1-alpha.25", + "@backstage/cli": "^0.1.1-alpha.26", + "@backstage/dev-utils": "^0.1.1-alpha.26", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", "@types/jest": "^26.0.7", - "msw": "^0.21.2", + "@types/node": "^12.0.0", "cross-fetch": "^3.0.6", - "@backstage/test-utils": "^0.1.1-alpha.25", - "@types/node": "^12.0.0" + "msw": "^0.21.2" }, "files": [ "dist" From ab44512727601b7aeeae33a253d3f14f3855525d Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 27 Oct 2020 12:02:49 +0100 Subject: [PATCH 23/33] fix unbumped packages and bump changelog --- CHANGELOG.md | 6 ++++-- plugins/cost-insights/package.json | 2 +- plugins/tech-radar/package.json | 2 +- plugins/techdocs/package.json | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f445c189f4..0ab3459628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re ## Next Release +> Collect changes for the next release below + +## v0.1.1-alpha.26 + ### @backstage/cli - Configuration files are no longer selected through `APP_ENV` or `NODE_ENV`. The default configuration files are `app-config.yaml` and, fix it exists, `app-config.local.yaml` in the repo root. To load a different set of files, use `--config ` arguments. @@ -16,8 +20,6 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re ## v0.1.1-alpha.25 -> Collect changes for the next release below - ### @backstage/cli - The recommended way to set the configuration environment is now to use `APP_ENV` instead of `NODE_ENV`. diff --git a/plugins/cost-insights/package.json b/plugins/cost-insights/package.json index eae19fecb1..7e3aec3412 100644 --- a/plugins/cost-insights/package.json +++ b/plugins/cost-insights/package.json @@ -46,7 +46,7 @@ "devDependencies": { "@backstage/cli": "^0.1.1-alpha.26", "@backstage/dev-utils": "^0.1.1-alpha.26", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 3e05fa85d2..f27f4c1784 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -37,7 +37,7 @@ "devDependencies": { "@backstage/cli": "^0.1.1-alpha.26", "@backstage/dev-utils": "^0.1.1-alpha.26", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 9f5a099ad6..9d14f0a919 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -42,7 +42,7 @@ "devDependencies": { "@backstage/cli": "^0.1.1-alpha.26", "@backstage/dev-utils": "^0.1.1-alpha.26", - "@backstage/test-utils": "^0.1.1-alpha.25", + "@backstage/test-utils": "^0.1.1-alpha.26", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", From 4e9453d6ed0c5099b28fcc3a81f192de8b123628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Frinnstr=C3=B6m?= Date: Fri, 23 Oct 2020 14:42:59 +0200 Subject: [PATCH 24/33] Add workdir config support to scaffolder --- app-config.yaml | 1 + packages/backend/src/plugins/scaffolder.ts | 1 + .../templates/default-app/app-config.yaml.hbs | 1 + .../scaffolder/stages/prepare/azure.test.ts | 19 +++++++++----- .../src/scaffolder/stages/prepare/azure.ts | 15 ++++++----- .../scaffolder/stages/prepare/file.test.ts | 5 +++- .../src/scaffolder/stages/prepare/file.ts | 9 ++++--- .../scaffolder/stages/prepare/github.test.ts | 20 ++++++++++----- .../src/scaffolder/stages/prepare/github.ts | 9 ++++--- .../scaffolder/stages/prepare/gitlab.test.ts | 19 +++++++++----- .../src/scaffolder/stages/prepare/gitlab.ts | 10 +++++--- .../src/scaffolder/stages/prepare/types.ts | 2 +- .../src/service/router.test.ts | 2 ++ .../scaffolder-backend/src/service/router.ts | 25 ++++++++++++++++++- 14 files changed, 99 insertions(+), 39 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index 6e3a68a229..009876a64b 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -155,6 +155,7 @@ catalog: target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml scaffolder: + # workingDirectory: /tmp # Use this to configure a working direcotry for the scaffolder, defaults to the OS temp-dir github: token: $env: GITHUB_TOKEN diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index c84928ea68..6eacd143c1 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -45,6 +45,7 @@ export default async function createPlugin({ templaters, publishers, logger, + config, dockerClient, }); } diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index 1f265d7e7d..9f66e7db0a 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -69,6 +69,7 @@ auth: providers: {} scaffolder: + # workingDirectory: /tmp # Use this to configure a working direcotry for the scaffolder, defaults to the OS temp-dir github: token: $env: GITHUB_TOKEN diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts index 7a7973e981..065ebaefa5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts @@ -19,6 +19,11 @@ const mocks = { CheckoutOptions: jest.fn(() => {}), }; jest.doMock('nodegit', () => mocks); +jest.doMock('fs-extra', () => ({ + promises: { + mkdtemp: jest.fn(dir => `${dir}-static`), + }, +})); import { AzurePreparer } from './azure'; import { @@ -73,7 +78,7 @@ describe('AzurePreparer', () => { it('calls the clone command with the correct arguments for a repository', async () => { const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', @@ -99,7 +104,7 @@ describe('AzurePreparer', () => { }, ]), ); - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', @@ -117,7 +122,7 @@ describe('AzurePreparer', () => { it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); delete mockEntity.spec.path; - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', @@ -129,10 +134,12 @@ describe('AzurePreparer', () => { it('return the temp directory with the path to the folder if it is specified', async () => { const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity); + const response = await preparer.prepare(mockEntity, { + workingDirectory: '/workDir', + }); - expect(response.split('\\').join('/')).toMatch( - /\/template\/test\/1\/2\/3$/, + expect(response).toBe( + `/workDir/graphql-starter-static/template/test/1/2/3`, ); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts index dc74ec0f75..aaf8508c8e 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts @@ -15,7 +15,6 @@ */ import fs from 'fs-extra'; import path from 'path'; -import os from 'os'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { parseLocationAnnotation } from '../helpers'; import { InputError } from '@backstage/backend-common'; @@ -32,8 +31,12 @@ export class AzurePreparer implements PreparerBase { config.getOptionalString('scaffolder.azure.api.token') ?? ''; } - async prepare(template: TemplateEntityV1alpha1): Promise { + async prepare( + template: TemplateEntityV1alpha1, + opts: { workingDirectory: string }, + ): Promise { const { protocol, location } = parseLocationAnnotation(template); + const { workingDirectory } = opts; if (!['azure/api', 'url'].includes(protocol)) { throw new InputError( @@ -42,18 +45,14 @@ export class AzurePreparer implements PreparerBase { } const templateId = template.metadata.name; - const url = new URL(location); // Need to extract filepath from search parameter const parsedGitLocation = GitUriParser(location); const repositoryCheckoutUrl = parsedGitLocation.toString('https'); - const tempDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), templateId), + path.join(workingDirectory, templateId), ); const templateDirectory = path.join( - `${path - .dirname(url.searchParams.get('path') || '') - .replace(/^\/+/g, '')}`, // Strip leading slash + `${path.dirname(parsedGitLocation.filepath)}`, template.spec.path ?? '.', ); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.test.ts index b9472fbc8d..d226736efe 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.test.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import os from 'os'; import fs from 'fs-extra'; import YAML from 'yaml'; import { FilePreparer } from './file'; @@ -42,7 +43,9 @@ const setupTest = async (fixturePath: string) => { }; const filePreparer = new FilePreparer(); - const resultDir = await filePreparer.prepare(template); + const resultDir = await filePreparer.prepare(template, { + workingDirectory: os.tmpdir(), + }); return { filePreparer, template, resultDir }; }; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts index b5ac846cf2..828238ae08 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts @@ -15,15 +15,18 @@ */ import fs from 'fs-extra'; import path from 'path'; -import os from 'os'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { parseLocationAnnotation } from '../helpers'; import { InputError } from '@backstage/backend-common'; import { PreparerBase } from './types'; export class FilePreparer implements PreparerBase { - async prepare(template: TemplateEntityV1alpha1): Promise { + async prepare( + template: TemplateEntityV1alpha1, + opts: { workingDirectory: string }, + ): Promise { const { protocol, location } = parseLocationAnnotation(template); + const { workingDirectory } = opts; if (protocol !== 'file') { throw new InputError( @@ -33,7 +36,7 @@ export class FilePreparer implements PreparerBase { const templateId = template.metadata.name; const tempDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), templateId), + path.join(workingDirectory, templateId), ); const parentDirectory = path.resolve( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts index de57043a50..29655f7ee9 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts @@ -19,6 +19,11 @@ const mocks = { CheckoutOptions: jest.fn(() => {}), }; jest.doMock('nodegit', () => mocks); +jest.doMock('fs-extra', () => ({ + promises: { + mkdtemp: jest.fn(dir => `${dir}-static`), + }, +})); import { GithubPreparer } from './github'; import { @@ -71,7 +76,7 @@ describe('GitHubPreparer', () => { }); it('calls the clone command with the correct arguments for a repository', async () => { const preparer = new GithubPreparer(); - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://github.com/benjdlambert/backstage-graphql-template', @@ -84,7 +89,7 @@ describe('GitHubPreparer', () => { it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { const preparer = new GithubPreparer(); delete mockEntity.spec.path; - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://github.com/benjdlambert/backstage-graphql-template', @@ -97,15 +102,18 @@ describe('GitHubPreparer', () => { it('return the temp directory with the path to the folder if it is specified', async () => { const preparer = new GithubPreparer(); mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity); + const response = await preparer.prepare(mockEntity, { + workingDirectory: '/workDir', + }); - expect(response.split('\\').join('/')).toMatch( - /\/template\/test\/1\/2\/3$/, + expect(response).toBe( + `/workDir/graphql-starter-static/template/test/1/2/3`, ); }); + it('calls the clone command with the token when provided', async () => { const preparer = new GithubPreparer({ token: 'abc' }); - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://github.com/benjdlambert/backstage-graphql-template', diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts index 0f064d22fa..863b760d03 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts @@ -15,7 +15,6 @@ */ import fs from 'fs-extra'; import path from 'path'; -import os from 'os'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { parseLocationAnnotation } from '../helpers'; import { InputError } from '@backstage/backend-common'; @@ -30,8 +29,12 @@ export class GithubPreparer implements PreparerBase { this.token = params.token; } - async prepare(template: TemplateEntityV1alpha1): Promise { + async prepare( + template: TemplateEntityV1alpha1, + opts: { workingDirectory: string }, + ): Promise { const { protocol, location } = parseLocationAnnotation(template); + const { workingDirectory } = opts; const { token } = this; if (!['github', 'url'].includes(protocol)) { @@ -44,7 +47,7 @@ export class GithubPreparer implements PreparerBase { const parsedGitLocation = GitUriParser(location); const repositoryCheckoutUrl = parsedGitLocation.toString('https'); const tempDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), templateId), + path.join(workingDirectory, templateId), ); const templateDirectory = path.join( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts index b25886b027..8df853ac06 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts @@ -18,6 +18,11 @@ const mocks = { CheckoutOptions: jest.fn(() => {}), }; jest.doMock('nodegit', () => mocks); +jest.doMock('fs-extra', () => ({ + promises: { + mkdtemp: jest.fn(dir => `${dir}-static`), + }, +})); import { GitlabPreparer } from './gitlab'; import { @@ -74,7 +79,7 @@ describe('GitLabPreparer', () => { it(`calls the clone command with the correct arguments for a repository using the ${protocol} protocol`, async () => { const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); mockEntity = mockEntityWithProtocol(protocol); - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://gitlab.com/benjdlambert/backstage-graphql-template', @@ -101,7 +106,7 @@ describe('GitLabPreparer', () => { ]), ); mockEntity = mockEntityWithProtocol(protocol); - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://gitlab.com/benjdlambert/backstage-graphql-template', @@ -120,7 +125,7 @@ describe('GitLabPreparer', () => { const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); mockEntity = mockEntityWithProtocol(protocol); delete mockEntity.spec.path; - await preparer.prepare(mockEntity); + await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://gitlab.com/benjdlambert/backstage-graphql-template', @@ -133,10 +138,12 @@ describe('GitLabPreparer', () => { const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); mockEntity = mockEntityWithProtocol(protocol); mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity); + const response = await preparer.prepare(mockEntity, { + workingDirectory: '/workDir', + }); - expect(response.split('\\').join('/')).toMatch( - /\/template\/test\/1\/2\/3$/, + expect(response).toBe( + `/workDir/graphql-starter-static/template/test/1/2/3`, ); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts index 8ccde0b626..5be72f85b5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts @@ -15,7 +15,6 @@ */ import fs from 'fs-extra'; import path from 'path'; -import os from 'os'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { parseLocationAnnotation } from '../helpers'; import { InputError } from '@backstage/backend-common'; @@ -33,8 +32,12 @@ export class GitlabPreparer implements PreparerBase { ''; } - async prepare(template: TemplateEntityV1alpha1): Promise { + async prepare( + template: TemplateEntityV1alpha1, + opts: { workingDirectory: string }, + ): Promise { const { protocol, location } = parseLocationAnnotation(template); + const { workingDirectory } = opts; if (!['gitlab', 'gitlab/api', 'url'].includes(protocol)) { throw new InputError( @@ -45,9 +48,8 @@ export class GitlabPreparer implements PreparerBase { const parsedGitLocation = GitUriParser(location); const repositoryCheckoutUrl = parsedGitLocation.toString('https'); - const tempDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), templateId), + path.join(workingDirectory, templateId), ); const templateDirectory = path.join( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts index c9dd14c0a3..940d2b4178 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts @@ -25,7 +25,7 @@ export type PreparerBase = { */ prepare( template: TemplateEntityV1alpha1, - opts: { logger: Logger }, + opts: { logger: Logger; workingDirectory: string }, ): Promise; }; diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 35d6b50ece..9e44fb8cbe 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -15,6 +15,7 @@ */ import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; import express from 'express'; import request from 'supertest'; import { createRouter } from './router'; @@ -32,6 +33,7 @@ describe('createRouter', () => { preparers: new Preparers(), templaters: new Templaters(), publishers: new Publishers(), + config: ConfigReader.fromConfigs([]), dockerClient: new Docker(), }); app = express().use(router); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index f61d2566b9..60c17a3e80 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -15,7 +15,9 @@ */ import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; -import { JsonValue } from '@backstage/config'; +import { Config, JsonValue } from '@backstage/config'; +import os from 'os'; +import fs from 'fs-extra'; import Docker from 'dockerode'; import express from 'express'; import Router from 'express-promise-router'; @@ -36,6 +38,7 @@ export interface RouterOptions { publishers: PublisherBuilder; logger: Logger; + config: Config; dockerClient: Docker; } @@ -50,12 +53,31 @@ export async function createRouter( templaters, publishers, logger: parentLogger, + config, dockerClient, } = options; const logger = parentLogger.child({ plugin: 'scaffolder' }); const jobProcessor = new JobProcessor(); + const workingDirectory = + config.getOptionalString('scaffolder.workingDirectory') ?? os.tmpdir(); + try { + // Check if working directory exists and is writable + await fs.promises.access( + workingDirectory, + fs.constants.F_OK | fs.constants.W_OK, + ); + logger.info(`using working directory: ${workingDirectory}`); + } catch (err) { + logger.error( + `working directory ${workingDirectory} ${ + err.code === 'ENOENT' ? 'does not exist' : 'is not writable' + }`, + ); + throw err; + } + router .get('/v1/job/:jobId', ({ params }, res) => { const job = jobProcessor.get(params.jobId); @@ -104,6 +126,7 @@ export async function createRouter( const preparer = preparers.get(ctx.entity); const skeletonDir = await preparer.prepare(ctx.entity, { logger: ctx.logger, + workingDirectory, }); return { skeletonDir }; }, From 3f9f500fe343fd5f5c1927930663cb217f3a55a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Frinnstr=C3=B6m?= Date: Mon, 26 Oct 2020 14:32:08 +0100 Subject: [PATCH 25/33] Add testing for working directory config --- .../src/service/router.test.ts | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 9e44fb8cbe..32f9604caf 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -14,6 +14,18 @@ * limitations under the License. */ +const mockAccess = jest.fn(); +jest.doMock('fs-extra', () => ({ + promises: { + access: mockAccess, + }, + constants: { + F_OK: 0, + W_OK: 1, + }, +})); + +import os from 'os'; import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import express from 'express'; @@ -24,6 +36,107 @@ import Docker from 'dockerode'; jest.mock('dockerode'); +describe('createRouter - working directory', () => { + const mockPrepare = jest.fn(); + const mockPreparers = new Preparers(); + + beforeAll(() => { + const mockPreparer = { + prepare: mockPrepare, + }; + mockPreparers.register('azure/api', mockPreparer); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + const workDirConfig = (path: string) => ({ + context: '', + data: { + scaffolder: { + workingDirectory: path, + }, + }, + }); + + const template = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'azure/api:dev.azure.com', + }, + }, + spec: { + owner: 'template@backstage.io', + path: '.', + schema: {}, + }, + }; + + it('should throw an error when working directory does not exist or is not writable', async () => { + mockAccess.mockImplementation(() => { + throw new Error('access error'); + }); + + await expect( + createRouter({ + logger: getVoidLogger(), + preparers: new Preparers(), + templaters: new Templaters(), + publishers: new Publishers(), + config: ConfigReader.fromConfigs([workDirConfig('/path')]), + dockerClient: new Docker(), + }), + ).rejects.toThrow('access error'); + }); + + it('should use the working directory when configured', async () => { + const router = await createRouter({ + logger: getVoidLogger(), + preparers: mockPreparers, + templaters: new Templaters(), + publishers: new Publishers(), + config: ConfigReader.fromConfigs([workDirConfig('/path')]), + dockerClient: new Docker(), + }); + + const app = express().use(router); + await request(app).post('/v1/jobs').send({ + template, + values: {}, + }); + + expect(mockPrepare).toBeCalledWith(expect.anything(), { + logger: expect.anything(), + workingDirectory: '/path', + }); + }); + + it('should default to OS temp-dir when no working directory is configured', async () => { + const router = await createRouter({ + logger: getVoidLogger(), + preparers: mockPreparers, + templaters: new Templaters(), + publishers: new Publishers(), + config: ConfigReader.fromConfigs([]), + dockerClient: new Docker(), + }); + + const app = express().use(router); + await request(app).post('/v1/jobs').send({ + template, + values: {}, + }); + + expect(mockPrepare).toBeCalledWith(expect.anything(), { + logger: expect.anything(), + workingDirectory: os.tmpdir(), + }); + }); +}); + describe('createRouter', () => { let app: express.Express; From 3b44008556e92d274199e7477f74fd2402a10f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Frinnstr=C3=B6m?= Date: Mon, 26 Oct 2020 14:45:47 +0100 Subject: [PATCH 26/33] Add missing config to create-app --- .../default-app/packages/backend/src/plugins/scaffolder.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts b/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts index 240309fbd1..8de15920e9 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/plugins/scaffolder.ts @@ -102,6 +102,7 @@ export default async function createPlugin({ templaters, publishers, logger, + config, dockerClient, }); } From 7f417559bb2728adcbb34eec6355468f2c8b91bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Frinnstr=C3=B6m?= Date: Mon, 26 Oct 2020 16:04:45 +0100 Subject: [PATCH 27/33] Move working directory config to backend --- app-config.yaml | 2 +- packages/create-app/templates/default-app/app-config.yaml.hbs | 2 +- plugins/scaffolder-backend/src/service/router.test.ts | 2 +- plugins/scaffolder-backend/src/service/router.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app-config.yaml b/app-config.yaml index 009876a64b..4746e822da 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -16,6 +16,7 @@ backend: credentials: true csp: connect-src: ["'self'", 'http:', 'https:'] + # workingDirectory: /tmp # Use this to configure a working direcotry for the scaffolder, defaults to the OS temp-dir # See README.md in the proxy-backend plugin for information on the configuration format proxy: @@ -155,7 +156,6 @@ catalog: target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml scaffolder: - # workingDirectory: /tmp # Use this to configure a working direcotry for the scaffolder, defaults to the OS temp-dir github: token: $env: GITHUB_TOKEN diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index 9f66e7db0a..d643c72e0c 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -38,6 +38,7 @@ backend: #ca: # if you have a CA file and want to verify it you can uncomment this section # $file: /ca/server.crt {{/if}} + # workingDirectory: /tmp # Use this to configure a working direcotry for the scaffolder, defaults to the OS temp-dir integrations: github: @@ -69,7 +70,6 @@ auth: providers: {} scaffolder: - # workingDirectory: /tmp # Use this to configure a working direcotry for the scaffolder, defaults to the OS temp-dir github: token: $env: GITHUB_TOKEN diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 32f9604caf..bca17aa029 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -54,7 +54,7 @@ describe('createRouter - working directory', () => { const workDirConfig = (path: string) => ({ context: '', data: { - scaffolder: { + backend: { workingDirectory: path, }, }, diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 60c17a3e80..e66728ac91 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -61,7 +61,7 @@ export async function createRouter( const jobProcessor = new JobProcessor(); const workingDirectory = - config.getOptionalString('scaffolder.workingDirectory') ?? os.tmpdir(); + config.getOptionalString('backend.workingDirectory') ?? os.tmpdir(); try { // Check if working directory exists and is writable await fs.promises.access( From fe9ec8f98888b1d755352851b51bc2447009d44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Frinnstr=C3=B6m?= Date: Mon, 26 Oct 2020 17:10:27 +0100 Subject: [PATCH 28/33] Updated types and moved defaulting logic --- .../scaffolder/stages/prepare/azure.test.ts | 12 ++++++- .../src/scaffolder/stages/prepare/azure.ts | 5 +-- .../src/scaffolder/stages/prepare/file.ts | 5 +-- .../scaffolder/stages/prepare/github.test.ts | 13 ++++++- .../src/scaffolder/stages/prepare/github.ts | 5 +-- .../scaffolder/stages/prepare/gitlab.test.ts | 12 ++++++- .../src/scaffolder/stages/prepare/gitlab.ts | 5 +-- .../src/scaffolder/stages/prepare/types.ts | 2 +- .../src/service/router.test.ts | 4 +-- .../scaffolder-backend/src/service/router.ts | 34 ++++++++++--------- 10 files changed, 66 insertions(+), 31 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts index 065ebaefa5..ca5c29e9ce 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts @@ -132,6 +132,16 @@ describe('AzurePreparer', () => { }); it('return the temp directory with the path to the folder if it is specified', async () => { + const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); + mockEntity.spec.path = './template/test/1/2/3'; + const response = await preparer.prepare(mockEntity, {}); + + expect(response.split('\\').join('/')).toMatch( + /\/template\/test\/1\/2\/3$/, + ); + }); + + it('return the working directory with the path to the folder if it is specified', async () => { const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); mockEntity.spec.path = './template/test/1/2/3'; const response = await preparer.prepare(mockEntity, { @@ -139,7 +149,7 @@ describe('AzurePreparer', () => { }); expect(response).toBe( - `/workDir/graphql-starter-static/template/test/1/2/3`, + '/workDir/graphql-starter-static/template/test/1/2/3', ); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts index aaf8508c8e..bd5458b329 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import os from 'os'; import fs from 'fs-extra'; import path from 'path'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; @@ -33,10 +34,10 @@ export class AzurePreparer implements PreparerBase { async prepare( template: TemplateEntityV1alpha1, - opts: { workingDirectory: string }, + opts: { workingDirectory?: string }, ): Promise { const { protocol, location } = parseLocationAnnotation(template); - const { workingDirectory } = opts; + const workingDirectory = opts.workingDirectory ?? os.tmpdir(); if (!['azure/api', 'url'].includes(protocol)) { throw new InputError( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts index 828238ae08..b97e4ae08b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import os from 'os'; import fs from 'fs-extra'; import path from 'path'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; @@ -23,10 +24,10 @@ import { PreparerBase } from './types'; export class FilePreparer implements PreparerBase { async prepare( template: TemplateEntityV1alpha1, - opts: { workingDirectory: string }, + opts: { workingDirectory?: string }, ): Promise { const { protocol, location } = parseLocationAnnotation(template); - const { workingDirectory } = opts; + const workingDirectory = opts.workingDirectory ?? os.tmpdir(); if (protocol !== 'file') { throw new InputError( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts index 29655f7ee9..d652d8aa35 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts @@ -99,7 +99,18 @@ describe('GitHubPreparer', () => { }, ); }); + it('return the temp directory with the path to the folder if it is specified', async () => { + const preparer = new GithubPreparer(); + mockEntity.spec.path = './template/test/1/2/3'; + const response = await preparer.prepare(mockEntity, {}); + + expect(response.split('\\').join('/')).toMatch( + /\/template\/test\/1\/2\/3$/, + ); + }); + + it('return the working directory with the path to the folder if it is specified', async () => { const preparer = new GithubPreparer(); mockEntity.spec.path = './template/test/1/2/3'; const response = await preparer.prepare(mockEntity, { @@ -107,7 +118,7 @@ describe('GitHubPreparer', () => { }); expect(response).toBe( - `/workDir/graphql-starter-static/template/test/1/2/3`, + '/workDir/graphql-starter-static/template/test/1/2/3', ); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts index 863b760d03..1987c416b3 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import os from 'os'; import fs from 'fs-extra'; import path from 'path'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; @@ -31,10 +32,10 @@ export class GithubPreparer implements PreparerBase { async prepare( template: TemplateEntityV1alpha1, - opts: { workingDirectory: string }, + opts: { workingDirectory?: string }, ): Promise { const { protocol, location } = parseLocationAnnotation(template); - const { workingDirectory } = opts; + const workingDirectory = opts.workingDirectory ?? os.tmpdir(); const { token } = this; if (!['github', 'url'].includes(protocol)) { diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts index 8df853ac06..3ee9dd103d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts @@ -138,12 +138,22 @@ describe('GitLabPreparer', () => { const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); mockEntity = mockEntityWithProtocol(protocol); mockEntity.spec.path = './template/test/1/2/3'; + const response = await preparer.prepare(mockEntity, {}); + + expect(response.split('\\').join('/')).toMatch( + /\/template\/test\/1\/2\/3$/, + ); + }); + + it('return the working directory with the path to the folder if it is specified', async () => { + const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); + mockEntity.spec.path = './template/test/1/2/3'; const response = await preparer.prepare(mockEntity, { workingDirectory: '/workDir', }); expect(response).toBe( - `/workDir/graphql-starter-static/template/test/1/2/3`, + '/workDir/graphql-starter-static/template/test/1/2/3', ); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts index 5be72f85b5..55fc846bb5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import os from 'os'; import fs from 'fs-extra'; import path from 'path'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; @@ -34,10 +35,10 @@ export class GitlabPreparer implements PreparerBase { async prepare( template: TemplateEntityV1alpha1, - opts: { workingDirectory: string }, + opts: { workingDirectory?: string }, ): Promise { const { protocol, location } = parseLocationAnnotation(template); - const { workingDirectory } = opts; + const workingDirectory = opts.workingDirectory ?? os.tmpdir(); if (!['gitlab', 'gitlab/api', 'url'].includes(protocol)) { throw new InputError( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts index 940d2b4178..1a28b316c6 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts @@ -25,7 +25,7 @@ export type PreparerBase = { */ prepare( template: TemplateEntityV1alpha1, - opts: { logger: Logger; workingDirectory: string }, + opts: { logger: Logger; workingDirectory?: string }, ): Promise; }; diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index bca17aa029..fae7ee8beb 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -25,7 +25,6 @@ jest.doMock('fs-extra', () => ({ }, })); -import os from 'os'; import { getVoidLogger } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import express from 'express'; @@ -114,7 +113,7 @@ describe('createRouter - working directory', () => { }); }); - it('should default to OS temp-dir when no working directory is configured', async () => { + it('should not pass along anything when no working directory is configured', async () => { const router = await createRouter({ logger: getVoidLogger(), preparers: mockPreparers, @@ -132,7 +131,6 @@ describe('createRouter - working directory', () => { expect(mockPrepare).toBeCalledWith(expect.anything(), { logger: expect.anything(), - workingDirectory: os.tmpdir(), }); }); }); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index e66728ac91..bcb0896c6e 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -60,22 +60,24 @@ export async function createRouter( const logger = parentLogger.child({ plugin: 'scaffolder' }); const jobProcessor = new JobProcessor(); - const workingDirectory = - config.getOptionalString('backend.workingDirectory') ?? os.tmpdir(); - try { - // Check if working directory exists and is writable - await fs.promises.access( - workingDirectory, - fs.constants.F_OK | fs.constants.W_OK, - ); - logger.info(`using working directory: ${workingDirectory}`); - } catch (err) { - logger.error( - `working directory ${workingDirectory} ${ - err.code === 'ENOENT' ? 'does not exist' : 'is not writable' - }`, - ); - throw err; + let workingDirectory: string; + if (config.has('backend.workingDirectory')) { + workingDirectory = config.getString('backend.workingDirectory'); + try { + // Check if working directory exists and is writable + await fs.promises.access( + workingDirectory, + fs.constants.F_OK | fs.constants.W_OK, + ); + logger.info(`using working directory: ${workingDirectory}`); + } catch (err) { + logger.error( + `working directory ${workingDirectory} ${ + err.code === 'ENOENT' ? 'does not exist' : 'is not writable' + }`, + ); + throw err; + } } router From 2e9d34fd87970bec402c8b23de452a3c20038847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Frinnstr=C3=B6m?= Date: Mon, 26 Oct 2020 17:18:32 +0100 Subject: [PATCH 29/33] Loosen up the type some more --- .../src/scaffolder/stages/prepare/azure.test.ts | 8 ++++---- .../src/scaffolder/stages/prepare/azure.ts | 4 ++-- .../src/scaffolder/stages/prepare/file.ts | 4 ++-- .../src/scaffolder/stages/prepare/github.test.ts | 8 ++++---- .../src/scaffolder/stages/prepare/github.ts | 4 ++-- .../src/scaffolder/stages/prepare/gitlab.test.ts | 8 ++++---- .../src/scaffolder/stages/prepare/gitlab.ts | 4 ++-- .../src/scaffolder/stages/prepare/types.ts | 2 +- plugins/scaffolder-backend/src/service/router.ts | 1 - 9 files changed, 21 insertions(+), 22 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts index ca5c29e9ce..97f01e6b7d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.test.ts @@ -78,7 +78,7 @@ describe('AzurePreparer', () => { it('calls the clone command with the correct arguments for a repository', async () => { const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', @@ -104,7 +104,7 @@ describe('AzurePreparer', () => { }, ]), ); - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', @@ -122,7 +122,7 @@ describe('AzurePreparer', () => { it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); delete mockEntity.spec.path; - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://dev.azure.com/backstage-org/backstage-project/_git/template-repo', @@ -134,7 +134,7 @@ describe('AzurePreparer', () => { it('return the temp directory with the path to the folder if it is specified', async () => { const preparer = new AzurePreparer(ConfigReader.fromConfigs([])); mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, {}); + const response = await preparer.prepare(mockEntity); expect(response.split('\\').join('/')).toMatch( /\/template\/test\/1\/2\/3$/, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts index bd5458b329..bdcc7e07de 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/azure.ts @@ -34,10 +34,10 @@ export class AzurePreparer implements PreparerBase { async prepare( template: TemplateEntityV1alpha1, - opts: { workingDirectory?: string }, + opts?: { workingDirectory?: string }, ): Promise { const { protocol, location } = parseLocationAnnotation(template); - const workingDirectory = opts.workingDirectory ?? os.tmpdir(); + const workingDirectory = opts?.workingDirectory ?? os.tmpdir(); if (!['azure/api', 'url'].includes(protocol)) { throw new InputError( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts index b97e4ae08b..683d0c8cfb 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts @@ -24,10 +24,10 @@ import { PreparerBase } from './types'; export class FilePreparer implements PreparerBase { async prepare( template: TemplateEntityV1alpha1, - opts: { workingDirectory?: string }, + opts?: { workingDirectory?: string }, ): Promise { const { protocol, location } = parseLocationAnnotation(template); - const workingDirectory = opts.workingDirectory ?? os.tmpdir(); + const workingDirectory = opts?.workingDirectory ?? os.tmpdir(); if (protocol !== 'file') { throw new InputError( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts index d652d8aa35..f251a39d28 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts @@ -76,7 +76,7 @@ describe('GitHubPreparer', () => { }); it('calls the clone command with the correct arguments for a repository', async () => { const preparer = new GithubPreparer(); - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://github.com/benjdlambert/backstage-graphql-template', @@ -89,7 +89,7 @@ describe('GitHubPreparer', () => { it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { const preparer = new GithubPreparer(); delete mockEntity.spec.path; - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://github.com/benjdlambert/backstage-graphql-template', @@ -103,7 +103,7 @@ describe('GitHubPreparer', () => { it('return the temp directory with the path to the folder if it is specified', async () => { const preparer = new GithubPreparer(); mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, {}); + const response = await preparer.prepare(mockEntity); expect(response.split('\\').join('/')).toMatch( /\/template\/test\/1\/2\/3$/, @@ -124,7 +124,7 @@ describe('GitHubPreparer', () => { it('calls the clone command with the token when provided', async () => { const preparer = new GithubPreparer({ token: 'abc' }); - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://github.com/benjdlambert/backstage-graphql-template', diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts index 1987c416b3..04b0bbcce1 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts @@ -32,10 +32,10 @@ export class GithubPreparer implements PreparerBase { async prepare( template: TemplateEntityV1alpha1, - opts: { workingDirectory?: string }, + opts?: { workingDirectory?: string }, ): Promise { const { protocol, location } = parseLocationAnnotation(template); - const workingDirectory = opts.workingDirectory ?? os.tmpdir(); + const workingDirectory = opts?.workingDirectory ?? os.tmpdir(); const { token } = this; if (!['github', 'url'].includes(protocol)) { diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts index 3ee9dd103d..a229c4f394 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts @@ -79,7 +79,7 @@ describe('GitLabPreparer', () => { it(`calls the clone command with the correct arguments for a repository using the ${protocol} protocol`, async () => { const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); mockEntity = mockEntityWithProtocol(protocol); - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://gitlab.com/benjdlambert/backstage-graphql-template', @@ -106,7 +106,7 @@ describe('GitLabPreparer', () => { ]), ); mockEntity = mockEntityWithProtocol(protocol); - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://gitlab.com/benjdlambert/backstage-graphql-template', @@ -125,7 +125,7 @@ describe('GitLabPreparer', () => { const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); mockEntity = mockEntityWithProtocol(protocol); delete mockEntity.spec.path; - await preparer.prepare(mockEntity, { workingDirectory: '/workDir' }); + await preparer.prepare(mockEntity); expect(mocks.Clone.clone).toHaveBeenNthCalledWith( 1, 'https://gitlab.com/benjdlambert/backstage-graphql-template', @@ -138,7 +138,7 @@ describe('GitLabPreparer', () => { const preparer = new GitlabPreparer(ConfigReader.fromConfigs([])); mockEntity = mockEntityWithProtocol(protocol); mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, {}); + const response = await preparer.prepare(mockEntity); expect(response.split('\\').join('/')).toMatch( /\/template\/test\/1\/2\/3$/, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts index 55fc846bb5..4553137c26 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.ts @@ -35,10 +35,10 @@ export class GitlabPreparer implements PreparerBase { async prepare( template: TemplateEntityV1alpha1, - opts: { workingDirectory?: string }, + opts?: { workingDirectory?: string }, ): Promise { const { protocol, location } = parseLocationAnnotation(template); - const workingDirectory = opts.workingDirectory ?? os.tmpdir(); + const workingDirectory = opts?.workingDirectory ?? os.tmpdir(); if (!['gitlab', 'gitlab/api', 'url'].includes(protocol)) { throw new InputError( diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts index 1a28b316c6..c17edc24a4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/types.ts @@ -25,7 +25,7 @@ export type PreparerBase = { */ prepare( template: TemplateEntityV1alpha1, - opts: { logger: Logger; workingDirectory?: string }, + opts?: { logger: Logger; workingDirectory?: string }, ): Promise; }; diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index bcb0896c6e..fb40489622 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -16,7 +16,6 @@ import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; import { Config, JsonValue } from '@backstage/config'; -import os from 'os'; import fs from 'fs-extra'; import Docker from 'dockerode'; import express from 'express'; From 5e4551e3a103b8975c0598bde747a9c32ddb7706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Frinnstr=C3=B6m?= Date: Tue, 27 Oct 2020 11:58:22 +0100 Subject: [PATCH 30/33] Add changeset --- .changeset/spicy-rockets-ring.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .changeset/spicy-rockets-ring.md diff --git a/.changeset/spicy-rockets-ring.md b/.changeset/spicy-rockets-ring.md new file mode 100644 index 0000000000..b39b433c1b --- /dev/null +++ b/.changeset/spicy-rockets-ring.md @@ -0,0 +1,10 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Added support for configuring the working directory of the Scaffolder: + +```yaml +backend: + workingDirectory: /some-dir # Use this to configure a working directory for the scaffolder, defaults to the OS temp-dir +``` From 97c2cb19b31c153d0bdb891a535fc5b2bcf20590 Mon Sep 17 00:00:00 2001 From: Abhishek Jakhar Date: Tue, 27 Oct 2020 18:10:51 +0530 Subject: [PATCH 31/33] feat: make entity not found page responsive (#3125) * feat: make EntityNotFound component responsive * feat: convert Illo from jsx file type to tsx file type * fix: give value to alt tag of Illo * feat: add test case for EntityNotFound component * chore: add changeset --- .changeset/slimy-garlics-eat.md | 5 ++++ .../EntityNotFound/EntityNotFound.test.tsx | 29 +++++++++++++++++++ .../EntityNotFound/EntityNotFound.tsx | 11 ++++++- .../{Illo.jsx => Illo/Illo.tsx} | 19 ++++++++++-- .../EntityNotFound/{ => Illo}/illo.svg | 0 .../components/EntityNotFound/Illo/index.ts | 16 ++++++++++ 6 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 .changeset/slimy-garlics-eat.md create mode 100644 plugins/catalog/src/components/EntityNotFound/EntityNotFound.test.tsx rename plugins/catalog/src/components/EntityNotFound/{Illo.jsx => Illo/Illo.tsx} (69%) rename plugins/catalog/src/components/EntityNotFound/{ => Illo}/illo.svg (100%) create mode 100644 plugins/catalog/src/components/EntityNotFound/Illo/index.ts diff --git a/.changeset/slimy-garlics-eat.md b/.changeset/slimy-garlics-eat.md new file mode 100644 index 0000000000..3ecc0ce495 --- /dev/null +++ b/.changeset/slimy-garlics-eat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +update the EntityNotFound component diff --git a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.test.tsx b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.test.tsx new file mode 100644 index 0000000000..ddb27d584a --- /dev/null +++ b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.test.tsx @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { renderInTestApp } from '@backstage/test-utils'; + +import { EntityNotFound } from './EntityNotFound'; + +describe('', () => { + it('renders without exploding', async () => { + const { getByText } = await renderInTestApp(); + expect(getByText(/entity was not found/i)).toBeInTheDocument(); + expect(getByText(/getting started documentation/i)).toBeInTheDocument(); + expect(getByText(/docs/i)).toBeInTheDocument(); + }); +}); diff --git a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx index c7560c6894..21ca09dae1 100644 --- a/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx +++ b/plugins/catalog/src/components/EntityNotFound/EntityNotFound.tsx @@ -25,12 +25,21 @@ const useStyles = makeStyles(theme => ({ container: { paddingTop: theme.spacing(24), paddingLeft: theme.spacing(8), + [theme.breakpoints.down('xs')]: { + padding: theme.spacing(2), + }, }, title: { paddingBottom: theme.spacing(2), + [theme.breakpoints.down('xs')]: { + fontSize: 32, + }, }, body: { paddingBottom: theme.spacing(6), + [theme.breakpoints.down('xs')]: { + paddingBottom: theme.spacing(5), + }, }, })); @@ -38,7 +47,7 @@ export const EntityNotFound = () => { const classes = useStyles(); return ( - + diff --git a/plugins/catalog/src/components/EntityNotFound/Illo.jsx b/plugins/catalog/src/components/EntityNotFound/Illo/Illo.tsx similarity index 69% rename from plugins/catalog/src/components/EntityNotFound/Illo.jsx rename to plugins/catalog/src/components/EntityNotFound/Illo/Illo.tsx index 36b8d84f5d..6c7bb9d788 100644 --- a/plugins/catalog/src/components/EntityNotFound/Illo.jsx +++ b/plugins/catalog/src/components/EntityNotFound/Illo/Illo.tsx @@ -18,16 +18,29 @@ import React from 'react'; import { makeStyles } from '@material-ui/core'; import IlloSvgUrl from './illo.svg'; -const useStyles = makeStyles({ +const useStyles = makeStyles(theme => ({ illo: { maxWidth: '60%', top: 100, right: 20, position: 'absolute', + [theme.breakpoints.down('xs')]: { + maxWidth: '96%', + position: 'relative', + top: 'unset', + right: 'unset', + margin: `${theme.spacing(10)}px auto ${theme.spacing(4)}px`, + }, }, -}); +})); export const Illo = () => { const classes = useStyles(); - return ; + return ( + Illustration on entity not found page + ); }; diff --git a/plugins/catalog/src/components/EntityNotFound/illo.svg b/plugins/catalog/src/components/EntityNotFound/Illo/illo.svg similarity index 100% rename from plugins/catalog/src/components/EntityNotFound/illo.svg rename to plugins/catalog/src/components/EntityNotFound/Illo/illo.svg diff --git a/plugins/catalog/src/components/EntityNotFound/Illo/index.ts b/plugins/catalog/src/components/EntityNotFound/Illo/index.ts new file mode 100644 index 0000000000..264a75a5b1 --- /dev/null +++ b/plugins/catalog/src/components/EntityNotFound/Illo/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { Illo } from './Illo'; From 99ab175f5970a1befcc922c8101403efd61669e3 Mon Sep 17 00:00:00 2001 From: Eric Nilsson Date: Tue, 27 Oct 2020 15:40:13 +0100 Subject: [PATCH 32/33] removed transformErrors function --- .../MultistepJsonForm/MultistepJsonForm.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx index 9e7a405731..f0ba720b39 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx @@ -25,7 +25,7 @@ import { Stepper, Typography, } from '@material-ui/core'; -import { AjvError, FormProps, IChangeEvent, withTheme } from '@rjsf/core'; +import { FormProps, IChangeEvent, withTheme } from '@rjsf/core'; import { Theme as MuiTheme } from '@rjsf/material-ui'; import React, { useState } from 'react'; @@ -63,15 +63,6 @@ export const MultistepJsonForm = ({ setActiveStep(Math.min(activeStep + 1, steps.length)); const handleBack = () => setActiveStep(Math.max(activeStep - 1, 0)); - const transformErrors = (errors: AjvError[]) => - errors.map(error => { - if (error.name === 'pattern') { - error.message = 'does not match the required pattern'; - error.stack = `${error.property} ${error.message}, see its description`; - } - return error; - }); - return ( <> @@ -84,7 +75,6 @@ export const MultistepJsonForm = ({ formData={formData} onChange={onChange} schema={schema as FormProps['schema']} - transformErrors={transformErrors} onSubmit={e => { if (e.errors.length === 0) handleNext(); }} From 3422f40b81626b1703029d02ea549b7681b3af1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 27 Oct 2020 17:03:15 +0100 Subject: [PATCH 33/33] fix(deps): yarn.lock changes missed (#3128) --- yarn.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1c655081ab..81caf8d0d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3692,16 +3692,16 @@ react-router "6.0.0-beta.0" react-use "^15.3.3" -"@roadiehq/backstage-plugin-travis-ci@^0.2.3": - version "0.2.3" - resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-travis-ci/-/backstage-plugin-travis-ci-0.2.3.tgz#2d1c5a7ed3eab4fdcf95243b73dee44c0cff5a57" - integrity sha512-Xi8vZFbcm+D4ykyU3I9hImAd22F1v6M1F/H9CJanRHqj5esJxnuCS2+Kf+w09bwb9DuM8/c68PuMlf3PMIsOwg== +"@roadiehq/backstage-plugin-travis-ci@^0.2.5": + version "0.2.5" + resolved "https://registry.npmjs.org/@roadiehq/backstage-plugin-travis-ci/-/backstage-plugin-travis-ci-0.2.5.tgz#588cd8b4a4dd4bd426c0012f8d35eae4504b55f4" + integrity sha512-4aJizmvIeunpl8D/YDvzagNzikPU51DSZFz1tN0XCwRR+buTPknV141qsKP+yxUbs6nx3Xuh+T/vNkb9lk6FlA== dependencies: - "@backstage/catalog-model" "^0.1.1-alpha.22" - "@backstage/core" "^0.1.1-alpha.22" - "@backstage/core-api" "^0.1.1-alpha.22" - "@backstage/plugin-catalog" "^0.1.1-alpha.22" - "@backstage/theme" "^0.1.1-alpha.22" + "@backstage/catalog-model" "^0.1.1-alpha.24" + "@backstage/core" "^0.1.1-alpha.24" + "@backstage/core-api" "^0.1.1-alpha.24" + "@backstage/plugin-catalog" "^0.1.1-alpha.24" + "@backstage/theme" "^0.1.1-alpha.24" "@material-ui/core" "^4.9.1" "@material-ui/icons" "^4.9.1" "@material-ui/lab" "4.0.0-alpha.45"