From 42addd8c8df87a0a93e9ae824acdf11f43e55030 Mon Sep 17 00:00:00 2001 From: Alex Rybchenko Date: Fri, 18 Nov 2022 14:16:58 +0100 Subject: [PATCH 01/87] added formData to validation function Signed-off-by: Alex Rybchenko --- plugins/scaffolder/api-report.md | 9 +++++---- plugins/scaffolder/src/extensions/types.ts | 3 ++- .../TemplateWizardPage/Stepper/createAsyncValidators.ts | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 33a5f8c2fe..f94cb26d21 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -110,9 +110,9 @@ export type EntityPickerUiOptions = export const EntityTagsPickerFieldExtension: FieldExtensionComponent< string[], { - showCounts?: boolean | undefined; - kinds?: string[] | undefined; helperText?: string | undefined; + kinds?: string[] | undefined; + showCounts?: boolean | undefined; } >; @@ -120,9 +120,9 @@ export const EntityTagsPickerFieldExtension: FieldExtensionComponent< export const EntityTagsPickerFieldSchema: FieldSchema< string[], { - showCounts?: boolean | undefined; - kinds?: string[] | undefined; helperText?: string | undefined; + kinds?: string[] | undefined; + showCounts?: boolean | undefined; } >; @@ -224,6 +224,7 @@ export type NextCustomFieldValidator = ( field: FieldValidation_2, context: { apiHolder: ApiHolder; + formData: JsonObject; }, ) => void | Promise; diff --git a/plugins/scaffolder/src/extensions/types.ts b/plugins/scaffolder/src/extensions/types.ts index 3834b39c0a..5e133c676b 100644 --- a/plugins/scaffolder/src/extensions/types.ts +++ b/plugins/scaffolder/src/extensions/types.ts @@ -23,6 +23,7 @@ import { } from '@rjsf/utils'; import { PropsWithChildren } from 'react'; import { JSONSchema7 } from 'json-schema'; +import { JsonObject } from '@backstage/types'; /** * Field validation type for Custom Field Extensions. @@ -100,7 +101,7 @@ export interface NextFieldExtensionComponentProps< export type NextCustomFieldValidator = ( data: TFieldReturnValue, field: FieldValidationV5, - context: { apiHolder: ApiHolder }, + context: { apiHolder: ApiHolder; formData: JsonObject }, ) => void | Promise; /** diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/createAsyncValidators.ts b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/createAsyncValidators.ts index 1355387eda..6483ce2393 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/createAsyncValidators.ts +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/createAsyncValidators.ts @@ -42,7 +42,7 @@ export const createAsyncValidators = ( if (validator) { const fieldValidation = createFieldValidation(); try { - await validator(value, fieldValidation, context); + await validator(value, fieldValidation, { ...context, formData }); } catch (ex) { fieldValidation.addError(ex.message); } From 596b7cf1a00729b06b80e967e6d2e0e834e213e9 Mon Sep 17 00:00:00 2001 From: Alex Rybchenko Date: Fri, 18 Nov 2022 14:47:10 +0100 Subject: [PATCH 02/87] initial support of ui options in scaffolder forms Signed-off-by: Alex Rybchenko --- .../sample-templates/bitbucket-demo/template.yaml | 2 ++ plugins/scaffolder-backend/src/service/router.ts | 1 + plugins/scaffolder/api-report.md | 3 +++ .../scaffolder/src/components/TemplatePage/TemplatePage.tsx | 1 + plugins/scaffolder/src/types.ts | 3 +++ 5 files changed, 10 insertions(+) diff --git a/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml b/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml index 52714f6d73..269c3be1a6 100644 --- a/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml @@ -4,6 +4,8 @@ metadata: name: bitbucket-demo title: Test Bitbucket RepoUrlPicker template description: scaffolder v1beta3 template demo publishing to bitbucket + ui:options: + finishButtonLabel: Publish spec: owner: backstage/techdocs-core type: service diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index eff7e95c50..be3c89601c 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -259,6 +259,7 @@ export async function createRouter( res.json({ title: template.metadata.title ?? template.metadata.name, description: template.metadata.description, + 'ui:options': template.metadata['ui:options'], steps: parameters.map(schema => ({ title: schema.title ?? 'Please enter the following information', description: schema.description, diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 33a5f8c2fe..e9cbc5bb0e 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -640,6 +640,9 @@ export type TemplateGroupFilter = { export type TemplateParameterSchema = { title: string; description?: string; + ['ui:options']?: { + finishButtonLabel?: string; + }; steps: Array<{ title: string; description?: string; diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index 87678d2a83..4b2de4b56e 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -152,6 +152,7 @@ export const TemplatePage = ({ onReset={handleFormReset} onFinish={handleCreate} layouts={layouts} + finishButtonLabel={schema['ui:options']?.finishButtonLabel} steps={schema.steps.map(step => { return { ...step, diff --git a/plugins/scaffolder/src/types.ts b/plugins/scaffolder/src/types.ts index acb0f0e114..8645fc8697 100644 --- a/plugins/scaffolder/src/types.ts +++ b/plugins/scaffolder/src/types.ts @@ -80,6 +80,9 @@ export type ScaffolderTaskOutput = { export type TemplateParameterSchema = { title: string; description?: string; + ['ui:options']?: { + finishButtonLabel?: string; + }; steps: Array<{ title: string; description?: string; From 777d6c7bdce0f1f741e32e6928a3caf0fe873873 Mon Sep 17 00:00:00 2001 From: Alex Rybchenko Date: Wed, 23 Nov 2022 15:53:36 +0100 Subject: [PATCH 03/87] leave only backend changes Signed-off-by: Alex Rybchenko --- .../sample-templates/bitbucket-demo/template.yaml | 2 -- plugins/scaffolder/api-report.md | 3 --- .../scaffolder/src/components/TemplatePage/TemplatePage.tsx | 1 - plugins/scaffolder/src/types.ts | 3 --- 4 files changed, 9 deletions(-) diff --git a/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml b/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml index 269c3be1a6..52714f6d73 100644 --- a/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/bitbucket-demo/template.yaml @@ -4,8 +4,6 @@ metadata: name: bitbucket-demo title: Test Bitbucket RepoUrlPicker template description: scaffolder v1beta3 template demo publishing to bitbucket - ui:options: - finishButtonLabel: Publish spec: owner: backstage/techdocs-core type: service diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index e9cbc5bb0e..33a5f8c2fe 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -640,9 +640,6 @@ export type TemplateGroupFilter = { export type TemplateParameterSchema = { title: string; description?: string; - ['ui:options']?: { - finishButtonLabel?: string; - }; steps: Array<{ title: string; description?: string; diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index 4b2de4b56e..87678d2a83 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -152,7 +152,6 @@ export const TemplatePage = ({ onReset={handleFormReset} onFinish={handleCreate} layouts={layouts} - finishButtonLabel={schema['ui:options']?.finishButtonLabel} steps={schema.steps.map(step => { return { ...step, diff --git a/plugins/scaffolder/src/types.ts b/plugins/scaffolder/src/types.ts index 8645fc8697..acb0f0e114 100644 --- a/plugins/scaffolder/src/types.ts +++ b/plugins/scaffolder/src/types.ts @@ -80,9 +80,6 @@ export type ScaffolderTaskOutput = { export type TemplateParameterSchema = { title: string; description?: string; - ['ui:options']?: { - finishButtonLabel?: string; - }; steps: Array<{ title: string; description?: string; From b07ccffad01f34abefa9cb3e5b313a9ab5a23e47 Mon Sep 17 00:00:00 2001 From: Alex Rybchenko Date: Wed, 23 Nov 2022 16:01:22 +0100 Subject: [PATCH 04/87] added changeset Signed-off-by: Alex Rybchenko --- .changeset/nasty-lizards-train.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nasty-lizards-train.md diff --git a/.changeset/nasty-lizards-train.md b/.changeset/nasty-lizards-train.md new file mode 100644 index 0000000000..82d49cf682 --- /dev/null +++ b/.changeset/nasty-lizards-train.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Backend now returns 'ui:options' value from template metadata, it can be used by all your custom scaffolder components. From bef58bf44210fef30b3a4f2b4cea79ce1176c203 Mon Sep 17 00:00:00 2001 From: Alex Rybchenko Date: Fri, 18 Nov 2022 14:55:29 +0100 Subject: [PATCH 05/87] api report Signed-off-by: Alex Rybchenko --- plugins/scaffolder/api-report.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index f94cb26d21..46b2ea3c8a 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -110,9 +110,9 @@ export type EntityPickerUiOptions = export const EntityTagsPickerFieldExtension: FieldExtensionComponent< string[], { - helperText?: string | undefined; - kinds?: string[] | undefined; showCounts?: boolean | undefined; + kinds?: string[] | undefined; + helperText?: string | undefined; } >; @@ -120,9 +120,9 @@ export const EntityTagsPickerFieldExtension: FieldExtensionComponent< export const EntityTagsPickerFieldSchema: FieldSchema< string[], { - helperText?: string | undefined; - kinds?: string[] | undefined; showCounts?: boolean | undefined; + kinds?: string[] | undefined; + helperText?: string | undefined; } >; From 9000952e872d9ea5b27a5b09afe47722657d87ae Mon Sep 17 00:00:00 2001 From: Alex Rybchenko Date: Tue, 29 Nov 2022 17:55:10 +0100 Subject: [PATCH 06/87] added changeset Signed-off-by: Alex Rybchenko --- .changeset/nasty-dragons-melt.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nasty-dragons-melt.md diff --git a/.changeset/nasty-dragons-melt.md b/.changeset/nasty-dragons-melt.md new file mode 100644 index 0000000000..b083ebce62 --- /dev/null +++ b/.changeset/nasty-dragons-melt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +All form data is now passed to validator functions in 'next' scaffolder, so it's now possible to perform validation for fields that depend on other field values From b5e3da44c4155fd2b074696a05dc8c2a492f668b Mon Sep 17 00:00:00 2001 From: TheMonolithX64 Date: Fri, 2 Dec 2022 17:42:20 +0000 Subject: [PATCH 07/87] Update broken links to cli docs Signed-off-by: TheMonolithX64 --- docs/getting-started/keeping-backstage-updated.md | 4 ++-- packages/backend/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/getting-started/keeping-backstage-updated.md b/docs/getting-started/keeping-backstage-updated.md index 64f78c0997..8e130e7094 100644 --- a/docs/getting-started/keeping-backstage-updated.md +++ b/docs/getting-started/keeping-backstage-updated.md @@ -13,7 +13,7 @@ starting point that's meant to be evolved. The Backstage CLI has a command to bump all `@backstage` packages and dependencies you're using to the latest versions: -[versions:bump](https://backstage.io/docs/cli/commands#versionsbump). +[versions:bump](https://backstage.io/docs/local-dev/cli-commands#versionsbump). ```bash yarn backstage-cli versions:bump @@ -70,7 +70,7 @@ example, depends on global referential equality. This can cause problems in Backstage with API lookup, or config loading. To help resolve these situations, the Backstage CLI has -[versions:check](https://backstage.io/docs/cli/commands#versionscheck). This +[versions:check](https://backstage.io/docs/local-dev/cli-commands#versionscheck). This will validate versions of `@backstage` packages in your app to check for duplicate definitions: diff --git a/packages/backend/README.md b/packages/backend/README.md index f4c115db65..e4fd81749d 100644 --- a/packages/backend/README.md +++ b/packages/backend/README.md @@ -31,7 +31,7 @@ The backend starts up on port 7007 per default. ### Debugging -The backend is a node process that can be inspected to allow breakpoints and live debugging. To enable this, pass the `--inspect` flag to [backend:dev](https://backstage.io/docs/cli/commands#backenddev). +The backend is a node process that can be inspected to allow breakpoints and live debugging. To enable this, pass the `--inspect` flag to [backend:dev](https://backstage.io/docs/local-dev/cli-build-system#backend-development). To debug the backend in [Visual Studio Code](https://code.visualstudio.com/): From 833872e55b758ea57d0212f66738b5009ba90973 Mon Sep 17 00:00:00 2001 From: djamaile Date: Fri, 9 Dec 2022 11:19:02 +0100 Subject: [PATCH 08/87] chore: use changeset feedback action Signed-off-by: djamaile --- .../workflows/automate_changeset_feedback.yml | 73 +------------------ 1 file changed, 4 insertions(+), 69 deletions(-) diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index 700eae7d0c..b6b5ea3d7e 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -21,75 +21,10 @@ jobs: if: github.repository == 'backstage/backstage' && github.event.pull_request.user.login != 'backstage-service' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: backstage/actions/changeset-feedback@v0.5.9 with: # Fetch the commit that's merged into the base rather than the target ref # This will let us diff only the contents of the PR, without fetching more history - ref: 'refs/pull/${{ github.event.pull_request.number }}/merge' - - - name: fetch base - run: git fetch --depth 1 origin ${{ github.base_ref }} - - # We avoid using the in-source script since this workflow has elevated permissions that we don't want to expose - - name: Generate Feedback - id: generate-feedback - run: | - rm -f generate.js - wget -O generate.js https://raw.githubusercontent.com/backstage/backstage/master/scripts/generate-changeset-feedback.js 1>&2 - node generate.js FETCH_HEAD > feedback.txt - - - name: Post Feedback - uses: actions/github-script@v6 - env: - ISSUE_NUMBER: ${{ github.event.pull_request.number }} - with: - script: | - const owner = "backstage"; - const repo = "backstage"; - const marker = ""; - const feedback = require('fs').readFileSync('feedback.txt', 'utf8'); - const issue_number = Number(process.env.ISSUE_NUMBER); - const body = feedback.trim() ? feedback + marker : undefined - - const existingComments = await github.paginate(github.rest.issues.listComments, { - owner, - repo, - issue_number, - }); - - const existingComment = existingComments.find((c) => - c.user.login === "github-actions[bot]" && - c.body.includes(marker) - ); - - if (existingComment) { - if (body) { - if (existingComment.body !== body) { - console.log(`updating existing comment in #${issue_number}`); - await github.rest.issues.updateComment({ - owner, - repo, - comment_id: existingComment.id, - body, - }); - } else { - console.log(`skipped update of identical comment in #${issue_number}`); - } - } else { - console.log(`removing comment from #${issue_number}`); - await github.rest.issues.deleteComment({ - owner, - repo, - comment_id: existingComment.id, - body, - }); - } - } else if (body) { - console.log(`creating comment for #${issue_number}`); - await github.rest.issues.createComment({ - owner, - repo, - issue_number, - body, - }); - } + diffRef: 'refs/pull/${{ github.event.pull_request.number }}/merge' + github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} + issue-number: ${{ steps.pr-number.outputs.pr-number }} From a162f33a5f9ca17071b9418b14ed3e36dbfadbcb Mon Sep 17 00:00:00 2001 From: Djam Date: Fri, 9 Dec 2022 15:32:02 +0100 Subject: [PATCH 09/87] Update automate_changeset_feedback.yml Signed-off-by: Djam --- .github/workflows/automate_changeset_feedback.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index b6b5ea3d7e..3637ed11e7 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -21,10 +21,13 @@ jobs: if: github.repository == 'backstage/backstage' && github.event.pull_request.user.login != 'backstage-service' runs-on: ubuntu-latest steps: - - uses: backstage/actions/changeset-feedback@v0.5.9 + - uses: backstage/actions/changeset-feedback@vchangeset-patches with: # Fetch the commit that's merged into the base rather than the target ref # This will let us diff only the contents of the PR, without fetching more history diffRef: 'refs/pull/${{ github.event.pull_request.number }}/merge' github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} issue-number: ${{ steps.pr-number.outputs.pr-number }} + app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} + private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} + installation-id: ${{ secrets.BACKSTAGE_GOALIE_INSTALLATION_ID }} From 24ff18621cdf08f1a0d806f0f08198c6e0fe3cb1 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 9 Dec 2022 17:27:56 +0100 Subject: [PATCH 10/87] catalog-backend: reference cleanup fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Signed-off-by: Patrik Oldsberg --- .../database/DefaultProcessingDatabase.test.ts | 17 +++++++++++------ .../src/database/DefaultProcessingDatabase.ts | 3 --- .../src/database/DefaultProviderDatabase.ts | 5 +++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts index 4fbb38b4fc..540c93ef13 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts @@ -462,12 +462,17 @@ describe('DefaultProcessingDatabase', () => { knexTx( 'refresh_state_references', ).select(), - ).resolves.toEqual([ - expect.objectContaining({ - source_entity_ref: 'location:default/fakelocation', - target_entity_ref: 'component:default/1', - }), - ]); + ).resolves.toEqual( + step.expectConflict + ? [] + : [ + // eslint-disable-next-line jest/no-conditional-expect + expect.objectContaining({ + source_entity_ref: 'location:default/fakelocation', + target_entity_ref: 'component:default/1', + }), + ], + ); expect(mockLogger.error).not.toHaveBeenCalled(); } diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts index 1127deed7e..761f5bfd72 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.ts @@ -314,7 +314,6 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { // Keeps track of the entities that we end up inserting to update refresh_state_references afterwards const stateReferences = new Array(); - const conflictingStateReferences = new Array(); // Upsert all of the unprocessed entities into the refresh_state table, by // their entity ref. @@ -357,13 +356,11 @@ export class DefaultProcessingDatabase implements ProcessingDatabase { this.options.logger.warn( `Detected conflicting entityRef ${entityRef} already referenced by ${conflictingKey} and now also ${locationKey}`, ); - conflictingStateReferences.push(entityRef); } } // Replace all references for the originating entity or source and then create new ones await tx('refresh_state_references') - .whereNotIn('target_entity_ref', conflictingStateReferences) .andWhere({ source_entity_ref: options.sourceEntityRef }) .delete(); await tx.batchInsert( diff --git a/plugins/catalog-backend/src/database/DefaultProviderDatabase.ts b/plugins/catalog-backend/src/database/DefaultProviderDatabase.ts index f1073fd984..a0d376327b 100644 --- a/plugins/catalog-backend/src/database/DefaultProviderDatabase.ts +++ b/plugins/catalog-backend/src/database/DefaultProviderDatabase.ts @@ -161,6 +161,11 @@ export class DefaultProviderDatabase implements ProviderDatabase { }); } + await tx('refresh_state_references') + .where('target_entity_ref', entityRef) + .andWhere({ source_key: options.sourceKey }) + .delete(); + if (ok) { await tx( 'refresh_state_references', From 22e51086eb761e9b4354d452ba6084d1c8b49a17 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 9 Dec 2022 17:31:18 +0100 Subject: [PATCH 11/87] catalog-backend: add failing test from #15111 Signed-off-by: Patrik Oldsberg --- .../database/DefaultProviderDatabase.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts index 43f2209b60..140925b6fd 100644 --- a/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts @@ -610,6 +610,23 @@ describe('DefaultProviderDatabase', () => { }), ]), ); + let references = await knex( + 'refresh_state_references', + ).select(); + expect(references).toEqual([ + { + id: 1, + source_key: 'lols', + source_entity_ref: null, + target_entity_ref: 'component:default/a', + }, + { + id: 2, + source_key: 'lols', + source_entity_ref: null, + target_entity_ref: 'component:default/b', + }, + ]); await db.transaction(async tx => { await db.replaceUnprocessedEntities(tx, { @@ -653,6 +670,23 @@ describe('DefaultProviderDatabase', () => { }), ]), ); + references = await knex( + 'refresh_state_references', + ).select(); + expect(references).toEqual([ + { + id: 2, + source_key: 'lols', + source_entity_ref: null, + target_entity_ref: 'component:default/b', + }, + { + id: 3, + source_key: 'lols', + source_entity_ref: null, + target_entity_ref: 'component:default/a', + }, + ]); }, 60_000, ); From d136793ff0abe67b4d43d16ccfa1b14cfaf72f69 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 9 Dec 2022 17:32:25 +0100 Subject: [PATCH 12/87] changesets: added changeset for catalog reference fix Signed-off-by: Patrik Oldsberg --- .changeset/tasty-impalas-mix.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tasty-impalas-mix.md diff --git a/.changeset/tasty-impalas-mix.md b/.changeset/tasty-impalas-mix.md new file mode 100644 index 0000000000..c830c45c56 --- /dev/null +++ b/.changeset/tasty-impalas-mix.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Fixed an issue where internal references in the catalog would stick around for longer than expected, causing entities to not be deleted or orphaned as expected. From 9cfb9842c89fc95095c6f6ab547c303f401dd30e Mon Sep 17 00:00:00 2001 From: Djam Date: Mon, 12 Dec 2022 13:47:58 +0100 Subject: [PATCH 13/87] Update automate_changeset_feedback.yml Signed-off-by: Djam --- .github/workflows/automate_changeset_feedback.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index 3637ed11e7..dc1b22fc8c 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -26,7 +26,6 @@ jobs: # Fetch the commit that's merged into the base rather than the target ref # This will let us diff only the contents of the PR, without fetching more history diffRef: 'refs/pull/${{ github.event.pull_request.number }}/merge' - github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} issue-number: ${{ steps.pr-number.outputs.pr-number }} app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} From 6b261d9b29da56c64b059a5c2321ea1f7a37ade2 Mon Sep 17 00:00:00 2001 From: Alex Rybchenko Date: Tue, 13 Dec 2022 18:05:44 +0100 Subject: [PATCH 14/87] updated changeset Signed-off-by: Alex Rybchenko --- .changeset/nasty-dragons-melt.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.changeset/nasty-dragons-melt.md b/.changeset/nasty-dragons-melt.md index b083ebce62..2f6610ff31 100644 --- a/.changeset/nasty-dragons-melt.md +++ b/.changeset/nasty-dragons-melt.md @@ -1,5 +1,15 @@ --- -'@backstage/plugin-scaffolder': minor +'@backstage/plugin-scaffolder': patch --- -All form data is now passed to validator functions in 'next' scaffolder, so it's now possible to perform validation for fields that depend on other field values +Form data is now passed to validator functions in 'next' scaffolder, so it's now possible to perform validation for fields that depend on other field values. This is something that we discourage due to the coupling that it creates, but is sometimes still the most sensible solution. + +```typescript jsx +export const myCustomValidation = ( + value: string, + validation: FieldValidation, + { apiHolder, formData }: { apiHolder: ApiHolder; formData: JsonObject }, +) => { + // validate +}; +``` From 380f549b75cade7b22b18c306093d3a773c6cb24 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Thu, 15 Dec 2022 19:19:17 +0000 Subject: [PATCH 15/87] bump @rjsf/*-v5 dependencies Signed-off-by: Paul Cowan --- .changeset/slimy-cameras-hang.md | 5 +++++ plugins/scaffolder/package.json | 8 ++++---- yarn.lock | 28 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 18 deletions(-) create mode 100644 .changeset/slimy-cameras-hang.md diff --git a/.changeset/slimy-cameras-hang.md b/.changeset/slimy-cameras-hang.md new file mode 100644 index 0000000000..1a4d32532a --- /dev/null +++ b/.changeset/slimy-cameras-hang.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +bump `@rjsf/*-v5` dependencies diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index bc9ae4069e..90c76fe9c9 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -55,11 +55,11 @@ "@material-ui/lab": "4.0.0-alpha.57", "@react-hookz/web": "^20.0.0", "@rjsf/core": "^3.2.1", - "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.12", + "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.14", "@rjsf/material-ui": "^3.2.1", - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.12", - "@rjsf/utils": "^5.0.0-beta.12", - "@rjsf/validator-ajv8": "^5.0.0-beta.12", + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.14", + "@rjsf/utils": "^5.0.0-beta.14", + "@rjsf/validator-ajv8": "^5.0.0-beta.14", "@types/json-schema": "^7.0.9", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", diff --git a/yarn.lock b/yarn.lock index e10597a7d8..87fddcdb9a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7485,11 +7485,11 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.57 "@react-hookz/web": ^20.0.0 "@rjsf/core": ^3.2.1 - "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.12" + "@rjsf/core-v5": "npm:@rjsf/core@^5.0.0-beta.14" "@rjsf/material-ui": ^3.2.1 - "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.12" - "@rjsf/utils": ^5.0.0-beta.12 - "@rjsf/validator-ajv8": ^5.0.0-beta.12 + "@rjsf/material-ui-v5": "npm:@rjsf/material-ui@^5.0.0-beta.14" + "@rjsf/utils": ^5.0.0-beta.14 + "@rjsf/validator-ajv8": ^5.0.0-beta.14 "@testing-library/jest-dom": ^5.10.1 "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 @@ -12667,9 +12667,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/core-v5@npm:@rjsf/core@^5.0.0-beta.12": - version: 5.0.0-beta.12 - resolution: "@rjsf/core@npm:5.0.0-beta.12" +"@rjsf/core-v5@npm:@rjsf/core@^5.0.0-beta.14": + version: 5.0.0-beta.14 + resolution: "@rjsf/core@npm:5.0.0-beta.14" dependencies: lodash: ^4.17.15 lodash-es: ^4.17.15 @@ -12678,7 +12678,7 @@ __metadata: peerDependencies: "@rjsf/utils": ^5.0.0-beta.1 react: ^16.14.0 || >=17 - checksum: 6c3fe058a29716cb8d31d436e284aa7ab51ec3c272dc34d49275ea0033c3350a2486249767d454bca20a4ccd00ed910f7ed518d2ebe30693b0218db1b3c990ac + checksum: 2e1a1ba4b4385401868628a127da72439a617abc72952c64e07dd1134f2252dcc13a4ec57876cb3bc44ab519e1d3c05eccfd3764eb76178526ebea051179a6ba languageName: node linkType: hard @@ -12701,16 +12701,16 @@ __metadata: languageName: node linkType: hard -"@rjsf/material-ui-v5@npm:@rjsf/material-ui@^5.0.0-beta.12": - version: 5.0.0-beta.12 - resolution: "@rjsf/material-ui@npm:5.0.0-beta.12" +"@rjsf/material-ui-v5@npm:@rjsf/material-ui@^5.0.0-beta.14": + version: 5.0.0-beta.14 + resolution: "@rjsf/material-ui@npm:5.0.0-beta.14" peerDependencies: "@material-ui/core": ^4.12.3 "@material-ui/icons": ^4.11.2 "@rjsf/core": ^5.0.0-beta.1 "@rjsf/utils": ^5.0.0-beta.1 react: ^16.14.0 || >=17 - checksum: 9b67c64956e74af6230d722fe9510fc50e6133c6913642f5bcbcb8da38b7ff5d912bc90a6b6692eb3df315ba9b330136556fb41854fb351e432433d584c1a969 + checksum: 5abc14a274b97a29288abd489f80f9b3fca53e4429ff96f6c03368dfe625d34b3f66ec2e446a84a8a1874d9dc81cb62ef5a706fc1b200bbe1632c612960a9dc6 languageName: node linkType: hard @@ -12726,7 +12726,7 @@ __metadata: languageName: node linkType: hard -"@rjsf/utils@npm:^5.0.0-beta.12": +"@rjsf/utils@npm:^5.0.0-beta.14": version: 5.0.0-beta.14 resolution: "@rjsf/utils@npm:5.0.0-beta.14" dependencies: @@ -12741,7 +12741,7 @@ __metadata: languageName: node linkType: hard -"@rjsf/validator-ajv8@npm:^5.0.0-beta.12": +"@rjsf/validator-ajv8@npm:^5.0.0-beta.14": version: 5.0.0-beta.14 resolution: "@rjsf/validator-ajv8@npm:5.0.0-beta.14" dependencies: From 27b23a86ad5a4c761d6411fc627290f9c3c6a828 Mon Sep 17 00:00:00 2001 From: Christina Chan <6462356+cchawn@users.noreply.github.com> Date: Thu, 15 Dec 2022 15:52:00 -0500 Subject: [PATCH 16/87] feat(scaffolder-backend-module-rails): handle more rails new arguments Signed-off-by: Christina Chan <6462356+cchawn@users.noreply.github.com> --- .changeset/strange-colts-sniff.md | 5 +++ .../src/actions/fetch/rails/index.ts | 25 ++++++++++++ .../fetch/rails/railsArgumentResolver.test.ts | 5 +++ .../fetch/rails/railsArgumentResolver.ts | 39 +++++++++++++++---- 4 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 .changeset/strange-colts-sniff.md diff --git a/.changeset/strange-colts-sniff.md b/.changeset/strange-colts-sniff.md new file mode 100644 index 0000000000..8d3e90ca7e --- /dev/null +++ b/.changeset/strange-colts-sniff.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-rails': minor +--- + +Added more (optional) arguments to the `createFetchRailsAction` to be passed to `rails new` diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts index d1a9ed7650..49b7ac100b 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts @@ -103,6 +103,31 @@ export function createFetchRailsAction(options: { description: 'Skip test files', type: 'boolean', }, + skipActionCable: { + title: 'skipActionCable', + description: 'Skip Action Cable files', + type: 'boolean', + }, + skipActionMailer: { + title: 'skipActionMailer', + description: 'Skip Action Mailer files', + type: 'boolean', + }, + skipActionMailbox: { + title: 'skipActionMailbox', + description: 'Skip Action Mailbox gem', + type: 'boolean', + }, + skipActiveStorage: { + title: 'skipActiveStorage', + description: 'Skip Active Storage files', + type: 'boolean', + }, + skipActionText: { + title: 'skipActionText', + description: 'Skip Action Text gem', + type: 'boolean', + }, force: { title: 'force', description: 'Overwrite files that already exist', diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts index 1f926eedb0..401ebb295f 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts @@ -28,6 +28,11 @@ describe('railsArgumentResolver', () => { [{ skipBundle: true }, ['--skip-bundle']], [{ skipWebpackInstall: true }, ['--skip-webpack-install']], [{ skipTest: true }, ['--skip-test']], + [{ skipActionCable: true }, ['--skip-action-cable']], + [{ skipActionMailer: true }, ['--skip-action-mailer']], + [{ skipActionMailbox: true }, ['--skip-action-mailbox']], + [{ skipActiveStorage: true }, ['--skip-active-storage']], + [{ skipActionText: true }, ['--skip-action-text']], [{ force: true }, ['--force']], [{ webpacker: 'vue' }, ['--webpack', 'vue']], [{ database: 'postgresql' }, ['--database', 'postgresql']], diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts index 53e1d1f8f6..666eac7958 100644 --- a/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts @@ -44,16 +44,21 @@ enum RailsVersion { } export type RailsRunOptions = { - minimal?: boolean; api?: boolean; + database?: Database; + force?: boolean; + minimal?: boolean; + railsVersion?: RailsVersion; + skipActionCable?: boolean; + skipActionMailbox?: boolean; + skipActionMailer?: boolean; + skipActionText?: boolean; + skipActiveStorage?: boolean; + skipBundle?: boolean; + skipTest?: boolean; + skipWebpackInstall?: boolean; template?: string; webpacker?: Webpacker; - database?: Database; - railsVersion?: RailsVersion; - skipBundle?: boolean; - skipWebpackInstall?: boolean; - skipTest?: boolean; - force?: boolean; }; export const railsArgumentResolver = ( @@ -83,6 +88,26 @@ export const railsArgumentResolver = ( argumentsToRun.push('--skip-test'); } + if (options?.skipActionCable) { + argumentsToRun.push('--skip-action-cable'); + } + + if (options?.skipActionMailer) { + argumentsToRun.push('--skip-action-mailer'); + } + + if (options?.skipActionMailbox) { + argumentsToRun.push('--skip-action-mailbox'); + } + + if (options?.skipActiveStorage) { + argumentsToRun.push('--skip-active-storage'); + } + + if (options?.skipActionText) { + argumentsToRun.push('--skip-action-text'); + } + if (options?.force) { argumentsToRun.push('--force'); } From 8e0358e18dab34a742d1314bec64bfcb39fda9b2 Mon Sep 17 00:00:00 2001 From: Brett Wright Date: Fri, 16 Dec 2022 08:34:09 +1100 Subject: [PATCH 17/87] Added --skip-install parameter to backstage-cli versions:bump Signed-off-by: Brett Wright --- .changeset/witty-pears-explode.md | 5 +++++ packages/cli/cli-report.md | 1 + packages/cli/src/commands/index.ts | 1 + packages/cli/src/commands/versions/bump.ts | 8 +++++++- 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .changeset/witty-pears-explode.md diff --git a/.changeset/witty-pears-explode.md b/.changeset/witty-pears-explode.md new file mode 100644 index 0000000000..7197536f47 --- /dev/null +++ b/.changeset/witty-pears-explode.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added --skip-install parameter to backstage-cli versions:bump diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index d82f8da60e..fa9a2aca8d 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -569,6 +569,7 @@ Usage: backstage-cli versions:bump [options] Options: --pattern --release + --skip-install -h, --help ``` diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 82cb60e62f..628e46df85 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -365,6 +365,7 @@ export function registerCommands(program: Command) { 'Bump to a specific Backstage release line or version', 'main', ) + .option('--skip-install', 'Skips yarn install step') .description('Bump Backstage packages to the latest versions') .action(lazy(() => import('./versions/bump').then(m => m.default))); diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index 81f98b8421..cf47b17643 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -255,7 +255,13 @@ export default async (opts: OptionValues) => { ); } - await runYarnInstall(); + if (opts.skipInstall === undefined) { + await runYarnInstall(); + } else { + console.log(); + + console.log(chalk.yellow(`Skipping yarn install`)); + } if (breakingUpdates.size > 0) { console.log(); From 214792a4bed18e98f087cb8dcdc68ab01887767d Mon Sep 17 00:00:00 2001 From: Brett Wright Date: Fri, 16 Dec 2022 20:12:49 +1100 Subject: [PATCH 18/87] Update .changeset/witty-pears-explode.md Co-authored-by: Philipp Hugenroth Signed-off-by: Brett Wright --- .changeset/witty-pears-explode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/witty-pears-explode.md b/.changeset/witty-pears-explode.md index 7197536f47..1ffbc05487 100644 --- a/.changeset/witty-pears-explode.md +++ b/.changeset/witty-pears-explode.md @@ -2,4 +2,4 @@ '@backstage/cli': patch --- -Added --skip-install parameter to backstage-cli versions:bump +Added `--skip-install` parameter to `backstage-cli versions:bump` From c868d04e167c3f5f737c25d07bdf3a351e93f4ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 12:26:47 +0000 Subject: [PATCH 19/87] Update dependency json5 to v2.2.2 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 643d4b5446..952f261f60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27094,11 +27094,11 @@ __metadata: linkType: hard "json5@npm:^2.1.2, json5@npm:^2.1.3, json5@npm:^2.2.0, json5@npm:^2.2.1": - version: 2.2.1 - resolution: "json5@npm:2.2.1" + version: 2.2.2 + resolution: "json5@npm:2.2.2" bin: json5: lib/cli.js - checksum: 74b8a23b102a6f2bf2d224797ae553a75488b5adbaee9c9b6e5ab8b510a2fc6e38f876d4c77dea672d4014a44b2399e15f2051ac2b37b87f74c0c7602003543b + checksum: 9a878d66b72157b073cf0017f3e5d93ec209fa5943abcb38d37a54b208917c166bd473c26a24695e67a016ce65759aeb89946592991f8f9174fb96c8e2492683 languageName: node linkType: hard From 9ce7866ecdbe18f68d6285cea10821db3ee0187d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 13:21:41 +0000 Subject: [PATCH 20/87] Update dependency @kubernetes/client-node to v0.18.0 Signed-off-by: Renovate Bot --- .changeset/renovate-6993874.md | 8 +++ packages/backend-common/package.json | 2 +- plugins/kubernetes-backend/package.json | 2 +- plugins/kubernetes-common/package.json | 2 +- plugins/kubernetes/package.json | 2 +- yarn.lock | 81 +++++++------------------ 6 files changed, 35 insertions(+), 62 deletions(-) create mode 100644 .changeset/renovate-6993874.md diff --git a/.changeset/renovate-6993874.md b/.changeset/renovate-6993874.md new file mode 100644 index 0000000000..67aacd5459 --- /dev/null +++ b/.changeset/renovate-6993874.md @@ -0,0 +1,8 @@ +--- +'@backstage/backend-common': patch +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-common': patch +'@backstage/plugin-kubernetes': patch +--- + +Updated dependency `@kubernetes/client-node` to `0.18.0`. diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index ee768618a4..da7c46dce1 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -43,7 +43,7 @@ "@google-cloud/storage": "^6.0.0", "@keyv/memcache": "^1.3.5", "@keyv/redis": "^2.5.3", - "@kubernetes/client-node": "0.17.0", + "@kubernetes/client-node": "0.18.0", "@manypkg/get-packages": "^1.1.3", "@octokit/rest": "^19.0.3", "@types/cors": "^2.8.6", diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index b895fdaeb5..21e8613456 100644 --- a/plugins/kubernetes-backend/package.json +++ b/plugins/kubernetes-backend/package.json @@ -45,7 +45,7 @@ "@backstage/plugin-kubernetes-common": "workspace:^", "@google-cloud/container": "^4.0.0", "@jest-mock/express": "^2.0.1", - "@kubernetes/client-node": "0.17.0", + "@kubernetes/client-node": "0.18.0", "@types/express": "^4.17.6", "@types/luxon": "^3.0.0", "aws-sdk": "^2.840.0", diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 46a58c0cbc..3dc122fd6a 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -39,7 +39,7 @@ }, "dependencies": { "@backstage/catalog-model": "workspace:^", - "@kubernetes/client-node": "0.17.0" + "@kubernetes/client-node": "0.18.0" }, "devDependencies": { "@backstage/cli": "workspace:^" diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 8e9dfee09d..7de34f1fb1 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -40,7 +40,7 @@ "@backstage/plugin-catalog-react": "workspace:^", "@backstage/plugin-kubernetes-common": "workspace:^", "@backstage/theme": "workspace:^", - "@kubernetes/client-node": "0.17.0", + "@kubernetes/client-node": "0.18.0", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", diff --git a/yarn.lock b/yarn.lock index 2cda2a9e27..a529da2fe4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3402,7 +3402,7 @@ __metadata: "@google-cloud/storage": ^6.0.0 "@keyv/memcache": ^1.3.5 "@keyv/redis": ^2.5.3 - "@kubernetes/client-node": 0.17.0 + "@kubernetes/client-node": 0.18.0 "@manypkg/get-packages": ^1.1.3 "@octokit/rest": ^19.0.3 "@types/archiver": ^5.1.0 @@ -6734,7 +6734,7 @@ __metadata: "@backstage/plugin-kubernetes-common": "workspace:^" "@google-cloud/container": ^4.0.0 "@jest-mock/express": ^2.0.1 - "@kubernetes/client-node": 0.17.0 + "@kubernetes/client-node": 0.18.0 "@types/aws4": ^1.5.1 "@types/express": ^4.17.6 "@types/http-proxy-middleware": ^0.19.3 @@ -6768,7 +6768,7 @@ __metadata: dependencies: "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^" - "@kubernetes/client-node": 0.17.0 + "@kubernetes/client-node": 0.18.0 languageName: unknown linkType: soft @@ -6787,7 +6787,7 @@ __metadata: "@backstage/plugin-kubernetes-common": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" - "@kubernetes/client-node": 0.17.0 + "@kubernetes/client-node": 0.18.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.57 @@ -11151,33 +11151,33 @@ __metadata: languageName: node linkType: hard -"@kubernetes/client-node@npm:0.17.0": - version: 0.17.0 - resolution: "@kubernetes/client-node@npm:0.17.0" +"@kubernetes/client-node@npm:0.18.0": + version: 0.18.0 + resolution: "@kubernetes/client-node@npm:0.18.0" dependencies: "@types/js-yaml": ^4.0.1 "@types/node": ^10.12.0 "@types/request": ^2.47.1 - "@types/stream-buffers": ^3.0.3 - "@types/tar": ^4.0.3 - "@types/underscore": ^1.8.9 "@types/ws": ^6.0.1 byline: ^5.0.0 execa: 5.0.0 isomorphic-ws: ^4.0.1 js-yaml: ^4.1.0 jsonpath-plus: ^0.19.0 - openid-client: ^5.1.6 + openid-client: ^5.3.0 request: ^2.88.0 rfc4648: ^1.3.0 shelljs: ^0.8.5 stream-buffers: ^3.0.2 tar: ^6.1.11 tmp-promise: ^3.0.2 - tslib: ^1.9.3 - underscore: ^1.9.1 + tslib: ^2.4.1 + underscore: ^1.13.6 ws: ^7.3.1 - checksum: 5a6edce96946966d8b61359ab043b42e69d1b31178133bc3bf4b5a5c9191766986e08f85d6ae814b56546ed20389817a79dca5101342543d79d750f30cba21f7 + dependenciesMeta: + openid-client: + optional: true + checksum: ea973ddf793b7351da5e1beaac461b8f2ae581cb6d65b62669f248f8cb345f0d54d4b888820fb49f471bc60bace37e706120f46d10d3726a63ccaed8b6cb401b languageName: node linkType: hard @@ -14768,15 +14768,6 @@ __metadata: languageName: node linkType: hard -"@types/minipass@npm:*": - version: 3.1.2 - resolution: "@types/minipass@npm:3.1.2" - dependencies: - "@types/node": "*" - checksum: 0d01e11b5b959625385a482ad29ea16352be42506b459555b0f77fd82235e9c540946cc9c05a73fed1ae30b132914baaa4ccf257ed2cad20bc9773f0a06f4bac - languageName: node - linkType: hard - "@types/mock-fs@npm:^4.10.0, @types/mock-fs@npm:^4.13.0": version: 4.13.1 resolution: "@types/mock-fs@npm:4.13.1" @@ -15367,15 +15358,6 @@ __metadata: languageName: node linkType: hard -"@types/stream-buffers@npm:^3.0.3": - version: 3.0.4 - resolution: "@types/stream-buffers@npm:3.0.4" - dependencies: - "@types/node": "*" - checksum: 5b432b2bf963d612747b79ac317562888236d6a9ea14414fb055c24e7be9643b5e3c7b7470841fa82802aa1c1c0d752a4ba935bbc0cfb12de6b89f7e1dadee92 - languageName: node - linkType: hard - "@types/styled-jsx@npm:^2.2.8": version: 2.2.8 resolution: "@types/styled-jsx@npm:2.2.8" @@ -15422,16 +15404,6 @@ __metadata: languageName: node linkType: hard -"@types/tar@npm:^4.0.3": - version: 4.0.5 - resolution: "@types/tar@npm:4.0.5" - dependencies: - "@types/minipass": "*" - "@types/node": "*" - checksum: 476d8af8f4cffcd973de026e043271be76171f9cb07bb869ba38a193ce89ee361b59ff8484e28b57216266063d91502c5208d2ab6b976e7370d9bdf4c4dadadc - languageName: node - linkType: hard - "@types/tar@npm:^6.1.1": version: 6.1.3 resolution: "@types/tar@npm:6.1.3" @@ -15501,13 +15473,6 @@ __metadata: languageName: node linkType: hard -"@types/underscore@npm:^1.8.9": - version: 1.11.4 - resolution: "@types/underscore@npm:1.11.4" - checksum: db9f8486bc851b732259e51f42d62aad1ae2158be5724612dc125ece5f5d61c51447f9dea28284c2a0f79cb95e788d01cb5ce97709880019213e69fab0dd1696 - languageName: node - linkType: hard - "@types/unist@npm:*, @types/unist@npm:^2.0.0": version: 2.0.6 resolution: "@types/unist@npm:2.0.6" @@ -30553,7 +30518,7 @@ __metadata: languageName: node linkType: hard -"openid-client@npm:^5.1.6, openid-client@npm:^5.2.1": +"openid-client@npm:^5.2.1, openid-client@npm:^5.3.0": version: 5.3.1 resolution: "openid-client@npm:5.3.1" dependencies: @@ -37109,10 +37074,10 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:~2.4.0": - version: 2.4.0 - resolution: "tslib@npm:2.4.0" - checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 +"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.4.1, tslib@npm:~2.4.0": + version: 2.4.1 + resolution: "tslib@npm:2.4.1" + checksum: 19480d6e0313292bd6505d4efe096a6b31c70e21cf08b5febf4da62e95c265c8f571f7b36fcc3d1a17e068032f59c269fab3459d6cd3ed6949eafecf64315fca languageName: node linkType: hard @@ -37436,10 +37401,10 @@ __metadata: languageName: node linkType: hard -"underscore@npm:^1.12.1, underscore@npm:^1.9.1, underscore@npm:~1.13.2": - version: 1.13.4 - resolution: "underscore@npm:1.13.4" - checksum: 6b04f66cd454e8793a552dc49c71e24e5208a29b9d9c0af988a96948af79103399c36fb15db43f3629bfed152f8b1fe94f44e1249e9d196069c0fc7edfadb636 +"underscore@npm:^1.12.1, underscore@npm:^1.13.6, underscore@npm:~1.13.2": + version: 1.13.6 + resolution: "underscore@npm:1.13.6" + checksum: d5cedd14a9d0d91dd38c1ce6169e4455bb931f0aaf354108e47bd46d3f2da7464d49b2171a5cf786d61963204a42d01ea1332a903b7342ad428deaafaf70ec36 languageName: node linkType: hard From 4f3ab4562a86995e54f3241fb941c59dda6391b5 Mon Sep 17 00:00:00 2001 From: Christina Chan <6462356+cchawn@users.noreply.github.com> Date: Fri, 16 Dec 2022 10:55:11 -0500 Subject: [PATCH 21/87] fix: mark change as patch not minor update Signed-off-by: Christina Chan <6462356+cchawn@users.noreply.github.com> --- .changeset/strange-colts-sniff.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/strange-colts-sniff.md b/.changeset/strange-colts-sniff.md index 8d3e90ca7e..831c180a09 100644 --- a/.changeset/strange-colts-sniff.md +++ b/.changeset/strange-colts-sniff.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder-backend-module-rails': minor +'@backstage/plugin-scaffolder-backend-module-rails': patch --- Added more (optional) arguments to the `createFetchRailsAction` to be passed to `rails new` From c7f50e840bfd681c5b8cca556c7aa39e615abe3c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 17:15:03 +0000 Subject: [PATCH 22/87] Update helm/kind-action action to v1.5.0 Signed-off-by: Renovate Bot --- .github/workflows/verify_kubernetes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify_kubernetes.yml b/.github/workflows/verify_kubernetes.yml index 6fc392805c..d4eb7df7b2 100644 --- a/.github/workflows/verify_kubernetes.yml +++ b/.github/workflows/verify_kubernetes.yml @@ -33,7 +33,7 @@ jobs: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: bootstrap kind - uses: helm/kind-action@v1.4.0 + uses: helm/kind-action@v1.5.0 - name: kubernetes test working-directory: packages/backend-common From fc51bd8aa0124ba3cbb5e9055ba85a9d5e9fa9da Mon Sep 17 00:00:00 2001 From: Kyle Leonhard Date: Fri, 16 Dec 2022 11:20:37 -0800 Subject: [PATCH 23/87] Add support for enabling Gitub wiki, issues and projects Signed-off-by: Kyle Leonhard --- .changeset/sharp-poets-count.md | 5 + plugins/scaffolder-backend/api-report.md | 6 + .../builtin/github/githubRepoCreate.test.ts | 104 ++++++++++++++++++ .../builtin/github/githubRepoCreate.ts | 12 ++ .../actions/builtin/github/helpers.ts | 9 ++ .../actions/builtin/github/inputProperties.ts | 18 +++ .../actions/builtin/publish/github.test.ts | 104 ++++++++++++++++++ .../actions/builtin/publish/github.ts | 12 ++ 8 files changed, 270 insertions(+) create mode 100644 .changeset/sharp-poets-count.md diff --git a/.changeset/sharp-poets-count.md b/.changeset/sharp-poets-count.md new file mode 100644 index 0000000000..33ec80b718 --- /dev/null +++ b/.changeset/sharp-poets-count.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Add support for disabling Github repository wiki, issues and projects diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 40a0ec11a0..69ef893dc3 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -225,6 +225,9 @@ export function createGithubRepoCreateAction(options: { } )[] | undefined; + hasProjects?: boolean | undefined; + hasWiki?: boolean | undefined; + hasIssues?: boolean | undefined; token?: string | undefined; topics?: string[] | undefined; }>; @@ -412,6 +415,9 @@ export function createPublishGithubAction(options: { } )[] | undefined; + hasProjects?: boolean | undefined; + hasWiki?: boolean | undefined; + hasIssues?: boolean | undefined; token?: string | undefined; topics?: string[] | undefined; }>; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts index 5692682882..0b0f98e2e7 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts @@ -152,6 +152,60 @@ describe('github:repo:create', () => { allow_auto_merge: false, visibility: 'private', }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + hasWiki: true, + hasProjects: true, + hasIssues: true, + }, + }); + expect( + mockOctokit.rest.repos.createInOrg, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + org: 'owner', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + allow_auto_merge: false, + visibility: 'private', + has_wiki: true, + has_projects: true, + has_issues: true, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + hasWiki: false, + hasProjects: false, + hasIssues: false, + }, + }); + expect( + mockOctokit.rest.repos.createInOrg, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + org: 'owner', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + allow_auto_merge: false, + visibility: 'private', + has_wiki: false, + has_projects: false, + has_issues: false, + }); }); it('should call the githubApis with the correct values for createForAuthenticatedUser', async () => { @@ -217,6 +271,56 @@ describe('github:repo:create', () => { allow_rebase_merge: true, allow_auto_merge: false, }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + hasWiki: true, + hasProjects: true, + hasIssues: true, + }, + }); + expect( + mockOctokit.rest.repos.createForAuthenticatedUser, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + allow_auto_merge: false, + has_wiki: true, + has_projects: true, + has_issues: true, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + hasWiki: false, + hasProjects: false, + hasIssues: false, + }, + }); + expect( + mockOctokit.rest.repos.createForAuthenticatedUser, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + allow_auto_merge: false, + has_wiki: false, + has_projects: false, + has_issues: false, + }); }); it('should add access for the team when it starts with the owner', async () => { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts index 4f2cf4a71e..598e3314fb 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.ts @@ -76,6 +76,9 @@ export function createGithubRepoCreateAction(options: { access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; } >; + hasProjects?: boolean; + hasWiki?: boolean; + hasIssues?: boolean; token?: string; topics?: string[]; }>({ @@ -103,6 +106,9 @@ export function createGithubRepoCreateAction(options: { allowRebaseMerge: inputProps.allowRebaseMerge, allowAutoMerge: inputProps.allowAutoMerge, collaborators: inputProps.collaborators, + hasProjects: inputProps.hasProjects, + hasWiki: inputProps.hasWiki, + hasIssues: inputProps.hasIssues, token: inputProps.token, topics: inputProps.topics, }, @@ -128,6 +134,9 @@ export function createGithubRepoCreateAction(options: { allowRebaseMerge = true, allowAutoMerge = false, collaborators, + hasProjects = undefined, + hasWiki = undefined, + hasIssues = undefined, topics, token: providedToken, } = ctx.input; @@ -160,6 +169,9 @@ export function createGithubRepoCreateAction(options: { allowAutoMerge, access, collaborators, + hasProjects, + hasWiki, + hasIssues, topics, ctx.logger, ); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts index 216a94ac57..499826ee6b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/helpers.ts @@ -122,6 +122,9 @@ export async function createGithubRepoWithCollaboratorsAndTopics( } )[] | undefined, + hasProjects: boolean | undefined, + hasWiki: boolean | undefined, + hasIssues: boolean | undefined, topics: string[] | undefined, logger: Logger, ) { @@ -144,6 +147,9 @@ export async function createGithubRepoWithCollaboratorsAndTopics( allow_rebase_merge: allowRebaseMerge, allow_auto_merge: allowAutoMerge, homepage: homepage, + has_projects: hasProjects, + has_wiki: hasWiki, + has_issues: hasIssues, }) : client.rest.repos.createForAuthenticatedUser({ name: repo, @@ -155,6 +161,9 @@ export async function createGithubRepoWithCollaboratorsAndTopics( allow_rebase_merge: allowRebaseMerge, allow_auto_merge: allowAutoMerge, homepage: homepage, + has_projects: hasProjects, + has_wiki: hasWiki, + has_issues: hasIssues, }); let newRepo; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts index a99a3030ac..07dd0f8163 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/inputProperties.ts @@ -132,6 +132,21 @@ const collaborators = { oneOf: [{ required: ['user'] }, { required: ['team'] }], }, }; +const hasProjects = { + title: 'Enable projects', + type: 'boolean', + description: `Enable projects for the repository. The default value is 'true' unless the organization has disabled repository projects`, +}; +const hasWiki = { + title: 'Enable the wiki', + type: 'boolean', + description: `Enable the wiki for the repository. The default value is 'true'`, +}; +const hasIssues = { + title: 'Enable issues', + type: 'boolean', + description: `Enable issues for the repository. The default value is 'true'`, +}; const token = { title: 'Authentication Token', type: 'string', @@ -223,6 +238,9 @@ export { dismissStaleReviews }; export { requiredStatusCheckContexts }; export { requireBranchesToBeUpToDate }; export { requiredConversationResolution }; +export { hasProjects }; +export { hasIssues }; +export { hasWiki }; export { sourcePath }; export { token }; export { topics }; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts index fa3b3c9b45..68e328e9fc 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts @@ -157,6 +157,60 @@ describe('publish:github', () => { allow_auto_merge: false, visibility: 'private', }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + hasWiki: true, + hasProjects: true, + hasIssues: true, + }, + }); + expect( + mockOctokit.rest.repos.createInOrg, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + org: 'owner', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + allow_auto_merge: false, + visibility: 'private', + has_wiki: true, + has_projects: true, + has_issues: true, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + hasWiki: false, + hasProjects: false, + hasIssues: false, + }, + }); + expect( + mockOctokit.rest.repos.createInOrg, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + org: 'owner', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + allow_auto_merge: false, + visibility: 'private', + has_wiki: false, + has_projects: false, + has_issues: false, + }); }); it('should call the githubApis with the correct values for createForAuthenticatedUser', async () => { @@ -222,6 +276,56 @@ describe('publish:github', () => { allow_rebase_merge: true, allow_auto_merge: false, }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + hasWiki: true, + hasProjects: true, + hasIssues: true, + }, + }); + expect( + mockOctokit.rest.repos.createForAuthenticatedUser, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + allow_auto_merge: false, + has_wiki: true, + has_projects: true, + has_issues: true, + }); + + await action.handler({ + ...mockContext, + input: { + ...mockContext.input, + hasWiki: false, + hasProjects: false, + hasIssues: false, + }, + }); + expect( + mockOctokit.rest.repos.createForAuthenticatedUser, + ).toHaveBeenCalledWith({ + description: 'description', + name: 'repo', + private: true, + delete_branch_on_merge: false, + allow_squash_merge: true, + allow_merge_commit: true, + allow_rebase_merge: true, + allow_auto_merge: false, + has_wiki: false, + has_projects: false, + has_issues: false, + }); }); it('should call initRepoAndPush with the correct values', async () => { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts index e246234d2c..edb1c699d7 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts @@ -88,6 +88,9 @@ export function createPublishGithubAction(options: { access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage'; } >; + hasProjects?: boolean | undefined; + hasWiki?: boolean | undefined; + hasIssues?: boolean | undefined; token?: string; topics?: string[]; }>({ @@ -124,6 +127,9 @@ export function createPublishGithubAction(options: { allowAutoMerge: inputProps.allowAutoMerge, sourcePath: inputProps.sourcePath, collaborators: inputProps.collaborators, + hasProjects: inputProps.hasProjects, + hasWiki: inputProps.hasWiki, + hasIssues: inputProps.hasIssues, token: inputProps.token, topics: inputProps.topics, }, @@ -161,6 +167,9 @@ export function createPublishGithubAction(options: { allowRebaseMerge = true, allowAutoMerge = false, collaborators, + hasProjects = undefined, + hasWiki = undefined, + hasIssues = undefined, topics, token: providedToken, } = ctx.input; @@ -193,6 +202,9 @@ export function createPublishGithubAction(options: { allowAutoMerge, access, collaborators, + hasProjects, + hasWiki, + hasIssues, topics, ctx.logger, ); From 62870e2385039317dc211a4009fb4235c817a606 Mon Sep 17 00:00:00 2001 From: Kyle Leonhard Date: Fri, 16 Dec 2022 11:33:28 -0800 Subject: [PATCH 24/87] Format Signed-off-by: Kyle Leonhard --- .../actions/builtin/github/githubRepoCreate.test.ts | 8 ++------ .../src/scaffolder/actions/builtin/publish/github.test.ts | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts index 0b0f98e2e7..3c37f28ccd 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/github/githubRepoCreate.test.ts @@ -162,9 +162,7 @@ describe('github:repo:create', () => { hasIssues: true, }, }); - expect( - mockOctokit.rest.repos.createInOrg, - ).toHaveBeenCalledWith({ + expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({ description: 'description', name: 'repo', org: 'owner', @@ -189,9 +187,7 @@ describe('github:repo:create', () => { hasIssues: false, }, }); - expect( - mockOctokit.rest.repos.createInOrg, - ).toHaveBeenCalledWith({ + expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({ description: 'description', name: 'repo', org: 'owner', diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts index 68e328e9fc..68e6521187 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.test.ts @@ -167,9 +167,7 @@ describe('publish:github', () => { hasIssues: true, }, }); - expect( - mockOctokit.rest.repos.createInOrg, - ).toHaveBeenCalledWith({ + expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({ description: 'description', name: 'repo', org: 'owner', @@ -194,9 +192,7 @@ describe('publish:github', () => { hasIssues: false, }, }); - expect( - mockOctokit.rest.repos.createInOrg, - ).toHaveBeenCalledWith({ + expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({ description: 'description', name: 'repo', org: 'owner', From dd375b47c0db5562be20868dad7f3bb4ab138752 Mon Sep 17 00:00:00 2001 From: Brett Wright Date: Sat, 17 Dec 2022 10:38:17 +1100 Subject: [PATCH 25/87] Update packages/cli/src/commands/versions/bump.ts Co-authored-by: Johan Haals Signed-off-by: Brett Wright --- packages/cli/src/commands/versions/bump.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index cf47b17643..1905aded20 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -255,7 +255,7 @@ export default async (opts: OptionValues) => { ); } - if (opts.skipInstall === undefined) { + if (!opts.skipInstall) { await runYarnInstall(); } else { console.log(); From 385b0530e208728b67bf466f062fcdddb848660b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 18 Dec 2022 17:18:44 +0000 Subject: [PATCH 26/87] Update dependency @react-hookz/web to v20.0.2 Signed-off-by: Renovate Bot --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index c9d87f09b8..866dc84dfd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12657,8 +12657,8 @@ __metadata: linkType: hard "@react-hookz/web@npm:^20.0.0": - version: 20.0.1 - resolution: "@react-hookz/web@npm:20.0.1" + version: 20.0.2 + resolution: "@react-hookz/web@npm:20.0.2" dependencies: "@react-hookz/deep-equal": ^1.0.3 peerDependencies: @@ -12668,7 +12668,7 @@ __metadata: peerDependenciesMeta: js-cookie: optional: true - checksum: 433dcb140953a877d4c81e1c176cd4302c184293ccddc5ee8de3ae3e592441b528c0c88bc07ed29fea2c993bacb146dfe0c7541832cb56785f07d8717626a1a2 + checksum: 38e9f660d247cd434d1de428f9ae49baf243f65187af3ebe2d4cd8ac1ecd660e37c64cec916dc9e9d4b7d609071b4c31d486ace3193e506fda64b11db96c5321 languageName: node linkType: hard From 51ce9b787f03d60acede079085d3f1da1f8944fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 18 Dec 2022 18:00:24 +0000 Subject: [PATCH 27/87] Update dependency @rollup/plugin-commonjs to v23.0.7 Signed-off-by: Renovate Bot --- yarn.lock | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 866dc84dfd..cdac83456b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11090,7 +11090,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13": version: 1.4.14 resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 @@ -12875,21 +12875,21 @@ __metadata: linkType: hard "@rollup/plugin-commonjs@npm:^23.0.0": - version: 23.0.5 - resolution: "@rollup/plugin-commonjs@npm:23.0.5" + version: 23.0.7 + resolution: "@rollup/plugin-commonjs@npm:23.0.7" dependencies: "@rollup/pluginutils": ^5.0.1 commondir: ^1.0.1 estree-walker: ^2.0.2 glob: ^8.0.3 is-reference: 1.2.1 - magic-string: ^0.26.4 + magic-string: ^0.27.0 peerDependencies: rollup: ^2.68.0||^3.0.0 peerDependenciesMeta: rollup: optional: true - checksum: 10094de3052d51a0e608dc2875c1f2fb345e4724ce6461e22c0c6030fc10b0c70fe939cc164f42807b0f4f95f2ed79bee78fe86a56380eda96b21b833b095dcb + checksum: 01d90947bd4aa664c568cec172399825921f29afc035a6d8aec153868ab151ce7901ad56a101c76655e31b21567ddc70313c4bca476685b872218f041757a8c9 languageName: node linkType: hard @@ -28273,7 +28273,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.26.4, magic-string@npm:^0.26.6": +"magic-string@npm:^0.26.6": version: 0.26.7 resolution: "magic-string@npm:0.26.7" dependencies: @@ -28282,6 +28282,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.27.0": + version: 0.27.0 + resolution: "magic-string@npm:0.27.0" + dependencies: + "@jridgewell/sourcemap-codec": ^1.4.13 + checksum: 273faaa50baadb7a2df6e442eac34ad611304fc08fe16e24fe2e472fd944bfcb73ffb50d2dc972dc04e92784222002af46868cb9698b1be181c81830fd95a13e + languageName: node + linkType: hard + "make-dir@npm:^2.0.0, make-dir@npm:^2.1.0": version: 2.1.0 resolution: "make-dir@npm:2.1.0" From 385339ee2a24bd538f47241ad645ae999a0caf0a Mon Sep 17 00:00:00 2001 From: Steve Cprek Date: Mon, 12 Dec 2022 15:59:11 -0600 Subject: [PATCH 28/87] Add links in README to reference Sonarqube FE/BE Signed-off-by: Steve Cprek --- plugins/sonarqube-backend/README.md | 4 ++++ plugins/sonarqube/README.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/plugins/sonarqube-backend/README.md b/plugins/sonarqube-backend/README.md index ac3973a5c0..4d16dce025 100644 --- a/plugins/sonarqube-backend/README.md +++ b/plugins/sonarqube-backend/README.md @@ -137,3 +137,7 @@ sonarqube: baseUrl: https://special-project-sonarqube.example.com apiKey: abcdef0123456789abcedf0123456789ab ``` + +## Links + +- [Sonarqube Frontend](../sonarqube/README.md) diff --git a/plugins/sonarqube/README.md b/plugins/sonarqube/README.md index d8ed6dfb8d..ab85d128aa 100644 --- a/plugins/sonarqube/README.md +++ b/plugins/sonarqube/README.md @@ -58,3 +58,7 @@ spec: ``` `YOUR_INSTANCE_NAME/` is optional and will query the default instance if not provided. + +## Links + +- [Sonarqube Backend](../sonarqube-backend/README.md) From 2440060f175fa5def9da7748ada777b497c822ed Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 19 Dec 2022 13:09:46 +0100 Subject: [PATCH 29/87] changeset: exit prerelease Signed-off-by: Patrik Oldsberg --- .changeset/pre.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index 4efcd59f16..38e7ac8419 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "next", "initialVersions": { "example-app": "0.2.77", From f75bf763309b7a710b02cf8a5d88aeb17a7ebee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Mon, 19 Dec 2022 13:44:30 +0100 Subject: [PATCH 30/87] implement ordering in the catalog backend and client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/fifty-zoos-nail.md | 5 + .changeset/silver-chicken-travel.md | 5 + packages/catalog-client/api-report.md | 12 ++ .../catalog-client/src/CatalogClient.test.ts | 23 ++++ packages/catalog-client/src/CatalogClient.ts | 23 +++- packages/catalog-client/src/types/api.ts | 46 +++++++ packages/catalog-client/src/types/index.ts | 1 + plugins/catalog-backend/src/catalog/types.ts | 9 ++ .../service/DefaultEntitiesCatalog.test.ts | 124 ++++++++++++++++-- .../src/service/DefaultEntitiesCatalog.ts | 46 ++++++- .../src/service/createRouter.ts | 2 + .../request/parseEntityOrderParams.test.ts | 43 ++++++ .../service/request/parseEntityOrderParams.ts | 48 +++++++ 13 files changed, 370 insertions(+), 17 deletions(-) create mode 100644 .changeset/fifty-zoos-nail.md create mode 100644 .changeset/silver-chicken-travel.md create mode 100644 plugins/catalog-backend/src/service/request/parseEntityOrderParams.test.ts create mode 100644 plugins/catalog-backend/src/service/request/parseEntityOrderParams.ts diff --git a/.changeset/fifty-zoos-nail.md b/.changeset/fifty-zoos-nail.md new file mode 100644 index 0000000000..7260a0b542 --- /dev/null +++ b/.changeset/fifty-zoos-nail.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': minor +--- + +Implemented support for the `order` directive on `getEntities` diff --git a/.changeset/silver-chicken-travel.md b/.changeset/silver-chicken-travel.md new file mode 100644 index 0000000000..e5dea6381d --- /dev/null +++ b/.changeset/silver-chicken-travel.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Implemented server side ordering in the entities endpoint diff --git a/packages/catalog-client/api-report.md b/packages/catalog-client/api-report.md index 2f76be79e2..a81314308b 100644 --- a/packages/catalog-client/api-report.md +++ b/packages/catalog-client/api-report.md @@ -161,6 +161,17 @@ export type EntityFilterQuery = | Record[] | Record; +// @public +export type EntityOrderQuery = + | { + field: string; + order: 'asc' | 'desc'; + } + | Array<{ + field: string; + order: 'asc' | 'desc'; + }>; + // @public export interface GetEntitiesByRefsRequest { entityRefs: string[]; @@ -179,6 +190,7 @@ export interface GetEntitiesRequest { filter?: EntityFilterQuery; limit?: number; offset?: number; + order?: EntityOrderQuery; } // @public diff --git a/packages/catalog-client/src/CatalogClient.test.ts b/packages/catalog-client/src/CatalogClient.test.ts index 1206d557c1..f87b12353d 100644 --- a/packages/catalog-client/src/CatalogClient.test.ts +++ b/packages/catalog-client/src/CatalogClient.test.ts @@ -193,6 +193,29 @@ describe('CatalogClient', () => { expect(response.items).toEqual([]); }); + + it('handles ordering properly', async () => { + expect.assertions(2); + + server.use( + rest.get(`${mockBaseUrl}/entities`, (req, res, ctx) => { + expect(req.url.search).toBe('?order=kind&order=-metadata.name'); + return res(ctx.json([])); + }), + ); + + const response = await client.getEntities( + { + order: [ + { field: 'kind', order: 'asc' }, + { field: 'metadata.name', order: 'desc' }, + ], + }, + { token }, + ); + + expect(response.items).toEqual([]); + }); }); describe('getEntitiesByRefs', () => { diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index d15f382ddd..0a5954d4bd 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -99,7 +99,14 @@ export class CatalogClient implements CatalogApi { request?: GetEntitiesRequest, options?: CatalogRequestOptions, ): Promise { - const { filter = [], fields = [], offset, limit, after } = request ?? {}; + const { + filter = [], + fields = [], + order, + offset, + limit, + after, + } = request ?? {}; const params: string[] = []; // filter param can occur multiple times, for example @@ -129,6 +136,20 @@ export class CatalogClient implements CatalogApi { params.push(`fields=${fields.map(encodeURIComponent).join(',')}`); } + if (order) { + for (const directive of [order].flat()) { + if (directive) { + // We could choose to always put in the + prefix, but it's not + // required (ascending sort is the default) and it always gets URL + // encoded to %2B which looks a bit less pretty - so we don't + const str = `${directive.order === 'desc' ? '-' : ''}${ + directive.field + }`; + params.push(`order=${encodeURIComponent(str)}`); + } + } + } + if (offset !== undefined) { params.push(`offset=${offset}`); } diff --git a/packages/catalog-client/src/types/api.ts b/packages/catalog-client/src/types/api.ts index 771adaaeee..d662a9d106 100644 --- a/packages/catalog-client/src/types/api.ts +++ b/packages/catalog-client/src/types/api.ts @@ -98,6 +98,48 @@ export type EntityFilterQuery = */ export type EntityFieldsQuery = string[]; +/** + * Dot-separated field based ordering directives, controlling the sort order of + * the output entities. + * + * @remarks + * + * Each field is a dot-separated path into an entity's keys. The order is either + * ascending (`asc`, lexicographical order) or descending (`desc`, reverse + * lexicographical order). The ordering is case insensitive. + * + * If more than one order directive is given, later directives have lower + * precedence (they are applied only when directives of higher precedence have + * equal values). + * + * Example: + * + * ``` + * [ + * { field: 'kind', order: 'asc' }, + * { field: 'metadata.name', order: 'desc' }, + * ] + * ``` + * + * This will order the output first by kind ascending, and then within each kind + * (if there's more than one of a given kind) by their name descending. + * + * When given a field that does NOT exist on all entities in the result set, + * those entities that do not have the field will always be sorted last in that + * particular order step, no matter what the desired order was. + * + * @public + */ +export type EntityOrderQuery = + | { + field: string; + order: 'asc' | 'desc'; + } + | Array<{ + field: string; + order: 'asc' | 'desc'; + }>; + /** * The request type for {@link CatalogClient.getEntities}. * @@ -113,6 +155,10 @@ export interface GetEntitiesRequest { * declarations. */ fields?: EntityFieldsQuery; + /** + *If given, order the result set by those directives. + */ + order?: EntityOrderQuery; /** * If given, skips over the first N items in the result set. */ diff --git a/packages/catalog-client/src/types/index.ts b/packages/catalog-client/src/types/index.ts index 5ac058e349..81b985eb42 100644 --- a/packages/catalog-client/src/types/index.ts +++ b/packages/catalog-client/src/types/index.ts @@ -22,6 +22,7 @@ export type { CatalogRequestOptions, EntityFieldsQuery, EntityFilterQuery, + EntityOrderQuery, GetEntitiesByRefsRequest, GetEntitiesByRefsResponse, GetEntitiesRequest, diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index 84673a3900..faf7451acd 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -38,6 +38,14 @@ export type EntityPagination = { after?: string; }; +/** + * A sorting rule for entities. + */ +export type EntityOrder = { + field: string; + order: 'asc' | 'desc'; +}; + /** * Matches rows in the search table. * @public @@ -71,6 +79,7 @@ export type PageInfo = export type EntitiesRequest = { filter?: EntityFilter; fields?: (entity: Entity) => Entity; + order?: EntityOrder[]; pagination?: EntityPagination; authorizationToken?: string; }; diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index b84596c78c..6735709662 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -28,6 +28,7 @@ import { import { Stitcher } from '../stitching/Stitcher'; import { buildEntitySearch } from '../stitching/buildEntitySearch'; import { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog'; +import { EntitiesRequest } from '../catalog/types'; describe('DefaultEntitiesCatalog', () => { const databases = TestDatabases.create({ @@ -254,7 +255,7 @@ describe('DefaultEntitiesCatalog', () => { describe('entities', () => { it.each(databases.eachSupportedId())( - 'should return correct entity for simple filter', + 'should return correct entity for simple filter, %p', async databaseId => { const { knex } = await createDatabase(databaseId); const entity1: Entity = { @@ -284,10 +285,11 @@ describe('DefaultEntitiesCatalog', () => { expect(entities.length).toBe(1); expect(entities[0]).toEqual(entity2); }, + 60_000, ); it.each(databases.eachSupportedId())( - 'should return correct entity for negation filter', + 'should return correct entity for negation filter, %p', async databaseId => { const { knex } = await createDatabase(databaseId); const entity1: Entity = { @@ -319,10 +321,11 @@ describe('DefaultEntitiesCatalog', () => { expect(entities.length).toBe(1); expect(entities[0]).toEqual(entity1); }, + 60_000, ); it.each(databases.eachSupportedId())( - 'should return correct entities for nested filter', + 'should return correct entities for nested filter, %p', async databaseId => { const { knex } = await createDatabase(databaseId); const entity1: Entity = { @@ -388,10 +391,11 @@ describe('DefaultEntitiesCatalog', () => { expect(entities).toContainEqual(entity2); expect(entities).toContainEqual(entity4); }, + 60_000, ); it.each(databases.eachSupportedId())( - 'should return correct entities for complex negation filter', + 'should return correct entities for complex negation filter, %p', async databaseId => { const { knex } = await createDatabase(databaseId); const entity1: Entity = { @@ -429,10 +433,11 @@ describe('DefaultEntitiesCatalog', () => { expect(entities.length).toBe(1); expect(entities).toContainEqual(entity1); }, + 60_000, ); it.each(databases.eachSupportedId())( - 'should return no matches for an empty values array', + 'should return no matches for an empty values array, %p', // NOTE: An empty values array is not a sensible input in a realistic scenario. async databaseId => { const { knex } = await createDatabase(databaseId); @@ -461,6 +466,7 @@ describe('DefaultEntitiesCatalog', () => { expect(entities.length).toBe(0); }, + 60_000, ); it.each(databases.eachSupportedId())( @@ -517,12 +523,105 @@ describe('DefaultEntitiesCatalog', () => { }, ]); }, + 60_000, + ); + + it.each(databases.eachSupportedId())( + 'can order and combine with filtering, %p', + async databaseId => { + const { knex } = await createDatabase(databaseId); + + const entity1: Entity = { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'n1' }, + spec: { a: 'foo' }, + }; + const entity2: Entity = { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'n2' }, + spec: { a: 'bar' }, + }; + const entity3: Entity = { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'n3' }, + spec: { a: 'bar', b: 'lonely' }, + }; + const entity4: Entity = { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'n4' }, + spec: { a: 'baz', b: 'only' }, + }; + await addEntityToSearch(knex, entity1); + await addEntityToSearch(knex, entity2); + await addEntityToSearch(knex, entity3); + await addEntityToSearch(knex, entity4); + + const catalog = new DefaultEntitiesCatalog(knex, stitcher); + + function f(request: EntitiesRequest): Promise { + return catalog + .entities(request) + .then(response => response.entities.map(e => e.metadata.name)); + } + + await expect( + f({ order: [{ field: 'metadata.name', order: 'asc' }] }), + ).resolves.toEqual(['n1', 'n2', 'n3', 'n4']); + + await expect( + f({ order: [{ field: 'metadata.name', order: 'desc' }] }), + ).resolves.toEqual(['n4', 'n3', 'n2', 'n1']); + + await expect( + f({ + order: [ + { field: 'spec.a', order: 'asc' }, + { field: 'metadata.name', order: 'desc' }, + ], + }), + ).resolves.toEqual(['n3', 'n2', 'n4', 'n1']); + + await expect( + f({ + filter: { not: { key: 'spec.b', values: ['lonely'] } }, + order: [ + { field: 'spec.a', order: 'asc' }, + { field: 'metadata.name', order: 'desc' }, + ], + }), + ).resolves.toEqual(['n2', 'n4', 'n1']); + + // only n3 and n4 has spec.b, nulls (no match) always goes last no matter the order + await expect( + f({ + order: [ + { field: 'spec.b', order: 'asc' }, + { field: 'metadata.name', order: 'asc' }, + ], + }), + ).resolves.toEqual(['n3', 'n4', 'n1', 'n2']); + + // only n3 and n4 has spec.b, nulls (no match) always goes last no matter the order + await expect( + f({ + order: [ + { field: 'spec.b', order: 'desc' }, + { field: 'metadata.name', order: 'asc' }, + ], + }), + ).resolves.toEqual(['n4', 'n3', 'n1', 'n2']); + }, + 60_000, ); }); describe('entitiesBatch', () => { it.each(databases.eachSupportedId())( - 'queries for entities by ref, including duplicates, and gracefully returns null for missing entities', + 'queries for entities by ref, including duplicates, and gracefully returns null for missing entities, %p', async databaseId => { const { knex } = await createDatabase(databaseId); @@ -571,12 +670,13 @@ describe('DefaultEntitiesCatalog', () => { 'k:default/two', ]); }, + 60_000, ); }); describe('removeEntityByUid', () => { it.each(databases.eachSupportedId())( - 'also clears parent hashes', + 'also clears parent hashes, %p', async databaseId => { const { knex } = await createDatabase(databaseId); @@ -659,12 +759,13 @@ describe('DefaultEntitiesCatalog', () => { new Set(['k:default/unrelated1', 'k:default/unrelated2']), ); }, + 60_000, ); }); describe('facets', () => { it.each(databases.eachSupportedId())( - 'can filter and collect properly', + 'can filter and collect properly, %p', async databaseId => { const { knex } = await createDatabase(databaseId); @@ -697,10 +798,11 @@ describe('DefaultEntitiesCatalog', () => { }, }); }, + 60_000, ); it.each(databases.eachSupportedId())( - 'can match on annotations and labels with dots in them', + 'can match on annotations and labels with dots in them, %p', async databaseId => { const { knex } = await createDatabase(databaseId); @@ -743,10 +845,11 @@ describe('DefaultEntitiesCatalog', () => { }, }); }, + 60_000, ); it.each(databases.eachSupportedId())( - 'can match on strings in arrays', + 'can match on strings in arrays, %p', async databaseId => { const { knex } = await createDatabase(databaseId); @@ -784,6 +887,7 @@ describe('DefaultEntitiesCatalog', () => { }, }); }, + 60_000, ); }); }); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index 14f22f862b..d598881371 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -97,7 +97,7 @@ function addCondition( // make a lot of sense. However, it had abysmal performance on sqlite // when datasets grew large, so we're using IN instead. const matchQuery = db('search') - .select(entityIdField) + .select('search.entity_id') .where({ key: filter.key.toLowerCase() }) .andWhere(function keyFilter() { if (filter.values) { @@ -178,14 +178,48 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { let entitiesQuery = db('final_entities').select('final_entities.*'); + + request?.order?.forEach(({ field }, index) => { + const alias = `order_${index}`; + entitiesQuery = entitiesQuery.leftOuterJoin( + { [alias]: 'search' }, + function search(inner) { + inner + .on(`${alias}.entity_id`, 'final_entities.entity_id') + .andOn(`${alias}.key`, db.raw('?', [field])); + }, + ); + }); + + entitiesQuery = entitiesQuery.whereNotNull('final_entities.final_entity'); + if (request?.filter) { - entitiesQuery = parseFilter(request.filter, entitiesQuery, db); + entitiesQuery = parseFilter( + request.filter, + entitiesQuery, + db, + false, + 'final_entities.entity_id', + ); } - // TODO: move final_entities to use entity_ref - entitiesQuery = entitiesQuery - .whereNotNull('final_entities.final_entity') - .orderBy('entity_id', 'asc'); + request?.order?.forEach(({ order }, index) => { + if (db.client.config.client === 'pg') { + // pg correctly orders by the column value and handling nulls in one go + entitiesQuery = entitiesQuery.orderBy([ + { column: `order_${index}.value`, order, nulls: 'last' }, + ]); + } else { + // sqlite and mysql translate the above statement ONLY into "order by (value is null) asc" + // no matter what the order is, for some reason, so we have to manually add back the statement + // that translates to "order by value " while avoiding to give an order + entitiesQuery = entitiesQuery.orderBy([ + { column: `order_${index}.value`, order: undefined, nulls: 'last' }, + { column: `order_${index}.value`, order }, + ]); + } + }); + entitiesQuery = entitiesQuery.orderBy('final_entities.entity_id', 'asc'); // stable sort const { limit, offset } = parsePagination(request?.pagination); if (limit !== undefined) { diff --git a/plugins/catalog-backend/src/service/createRouter.ts b/plugins/catalog-backend/src/service/createRouter.ts index 4680dbb899..6a31fcd0b6 100644 --- a/plugins/catalog-backend/src/service/createRouter.ts +++ b/plugins/catalog-backend/src/service/createRouter.ts @@ -41,6 +41,7 @@ import { parseEntityTransformParams, } from './request'; import { parseEntityFacetParams } from './request/parseEntityFacetParams'; +import { parseEntityOrderParams } from './request/parseEntityOrderParams'; import { LocationService, RefreshOptions, RefreshService } from './types'; import { disallowReadonlyMode, @@ -113,6 +114,7 @@ export async function createRouter( const { entities, pageInfo } = await entitiesCatalog.entities({ filter: parseEntityFilterParams(req.query), fields: parseEntityTransformParams(req.query), + order: parseEntityOrderParams(req.query), pagination: parseEntityPaginationParams(req.query), authorizationToken: getBearerToken(req.header('authorization')), }); diff --git a/plugins/catalog-backend/src/service/request/parseEntityOrderParams.test.ts b/plugins/catalog-backend/src/service/request/parseEntityOrderParams.test.ts new file mode 100644 index 0000000000..77cf73f57b --- /dev/null +++ b/plugins/catalog-backend/src/service/request/parseEntityOrderParams.test.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { parseEntityOrderParams } from './parseEntityOrderParams'; + +describe('parseEntityOrderParams', () => { + it('handles missing parameter', () => { + expect(parseEntityOrderParams({})).toBeUndefined(); + }); + + it('handles parameters with various orders', () => { + expect(parseEntityOrderParams({ order: ['a', '+b', '-c'] })).toEqual([ + { field: 'a', order: 'asc' }, + { field: 'b', order: 'asc' }, + { field: 'c', order: 'desc' }, + ]); + }); + + it('rejects missing order or key', () => { + expect(() => parseEntityOrderParams({ order: [''] })).toThrow( + 'Invalid order parameter "", no field given', + ); + expect(() => parseEntityOrderParams({ order: ['+'] })).toThrow( + 'Invalid order parameter "+", no field given', + ); + expect(() => parseEntityOrderParams({ order: ['-'] })).toThrow( + 'Invalid order parameter "-", no field given', + ); + }); +}); diff --git a/plugins/catalog-backend/src/service/request/parseEntityOrderParams.ts b/plugins/catalog-backend/src/service/request/parseEntityOrderParams.ts new file mode 100644 index 0000000000..d10119fd47 --- /dev/null +++ b/plugins/catalog-backend/src/service/request/parseEntityOrderParams.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { InputError } from '@backstage/errors'; +import { EntityOrder } from '../../catalog/types'; +import { parseStringsParam } from './common'; + +export function parseEntityOrderParams( + params: Record, +): EntityOrder[] | undefined { + return parseStringsParam(params.order, 'order')?.map(item => { + let order: 'asc' | 'desc'; + let field: string; + switch (item[0]) { + case '+': + order = 'asc'; + field = item.slice(1).trim(); + break; + case '-': + order = 'desc'; + field = item.slice(1).trim(); + break; + default: + order = 'asc'; + field = item.trim(); + break; + } + + if (!field) { + throw new InputError(`Invalid order parameter "${item}", no field given`); + } + + return { field, order }; + }); +} From 3dee2f5ad0323d1b2f952111165772b04625ebee Mon Sep 17 00:00:00 2001 From: Steve Cprek Date: Mon, 19 Dec 2022 09:07:46 -0600 Subject: [PATCH 31/87] Add changeset Signed-off-by: Steve Cprek --- .changeset/witty-phones-chew.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/witty-phones-chew.md diff --git a/.changeset/witty-phones-chew.md b/.changeset/witty-phones-chew.md new file mode 100644 index 0000000000..b2002307e9 --- /dev/null +++ b/.changeset/witty-phones-chew.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-sonarqube': patch +'@backstage/plugin-sonarqube-backend': patch +--- + +Sonarqube doc change to link FE/BE changes needed From 2ea043388e943f9ecd2454a49709fd606c212a78 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Mon, 19 Dec 2022 16:37:04 +0100 Subject: [PATCH 32/87] Update .changeset/witty-phones-chew.md Signed-off-by: Patrik Oldsberg --- .changeset/witty-phones-chew.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/witty-phones-chew.md b/.changeset/witty-phones-chew.md index b2002307e9..93c5659c4e 100644 --- a/.changeset/witty-phones-chew.md +++ b/.changeset/witty-phones-chew.md @@ -3,4 +3,4 @@ '@backstage/plugin-sonarqube-backend': patch --- -Sonarqube doc change to link FE/BE changes needed +Added links to the frontend and backend plugins in the readme. From 79afad089a5ede2779fe8a2478728a7dd6f54537 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 19 Dec 2022 16:39:53 +0100 Subject: [PATCH 33/87] chore: support initial form data from queryString Signed-off-by: blam --- .../Stepper/Stepper.test.tsx | 32 +++++++++++++++++++ .../TemplateWizardPage/Stepper/Stepper.tsx | 4 ++- .../TemplateWizardPage/Stepper/useFormData.ts | 32 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 plugins/scaffolder/src/next/TemplateWizardPage/Stepper/useFormData.ts diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx index 6c02492cd8..c8dbb0cb19 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx @@ -189,6 +189,38 @@ describe('Stepper', () => { expect(getByText('invalid postcode')).toBeInTheDocument(); }); + it('should grab the initial formData from the query', async () => { + const manifest: TemplateParameterSchema = { + steps: [ + { + title: 'Step 1', + schema: { + properties: { + firstName: { + type: 'string', + }, + }, + }, + }, + ], + title: 'initialize formData', + }; + + const mockFormData = { firstName: 'John' }; + + Object.defineProperty(window, 'location', { + value: { + search: `?formData=${JSON.stringify(mockFormData)}`, + }, + }); + + const { getByRole } = await renderInTestApp( + , + ); + + expect(getByRole('textbox', { name: 'firstName' })).toHaveValue('John'); + }); + it('should initialize formState with undefined form values', async () => { const manifest: TemplateParameterSchema = { steps: [ diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx index 7051b197f1..fffacae2f2 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx @@ -38,6 +38,7 @@ import validator from '@rjsf/validator-ajv8'; import { selectedTemplateRouteRef } from '../../../routes'; import type { ErrorTransformer } from '@rjsf/utils'; import { getDefaultFormState } from '@rjsf/utils'; +import { useFormData } from './useFormData'; const useStyles = makeStyles(theme => ({ backButton: { @@ -72,7 +73,8 @@ export const Stepper = (props: StepperProps) => { const { steps } = useTemplateSchema(props.manifest); const apiHolder = useApiHolder(); const [activeStep, setActiveStep] = useState(0); - const [formState, setFormState] = useState>({}); + const [formState, setFormState] = useFormData(); + const [errors, setErrors] = useState< undefined | Record >(); diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/useFormData.ts b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/useFormData.ts new file mode 100644 index 0000000000..1500216688 --- /dev/null +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/useFormData.ts @@ -0,0 +1,32 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import qs from 'qs'; +import { useState } from 'react'; + +export const useFormData = () => { + return useState>(() => { + const query = qs.parse(window.location.search, { + ignoreQueryPrefix: true, + }); + + try { + return JSON.parse(query.formData as string); + } catch (e) { + return {}; + } + }); +}; From 5b10b2485a975d43db0367916f1317ebeecbddb2 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 19 Dec 2022 16:41:54 +0100 Subject: [PATCH 34/87] chore: add changeset Signed-off-by: blam --- .changeset/old-zoos-grow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/old-zoos-grow.md diff --git a/.changeset/old-zoos-grow.md b/.changeset/old-zoos-grow.md new file mode 100644 index 0000000000..2049cadfac --- /dev/null +++ b/.changeset/old-zoos-grow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Parse `formData` from `window.location.query` for `scaffolder/next` From 8503f20db0d53e7f905bc08e37eb5eb3ce75e90b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Dec 2022 16:20:02 +0000 Subject: [PATCH 35/87] chore(deps): update backstage/actions action to v0.5.12 Signed-off-by: Renovate Bot --- .github/workflows/ci.yml | 6 +++--- .github/workflows/cron.yml | 2 +- .github/workflows/deploy_docker-image.yml | 2 +- .github/workflows/deploy_nightly.yml | 2 +- .github/workflows/deploy_packages.yml | 4 ++-- .github/workflows/issue.yaml | 2 +- .github/workflows/pr-review-comment.yaml | 2 +- .github/workflows/pr.yaml | 2 +- .github/workflows/sync_code-formatting.yml | 2 +- .github/workflows/sync_snyk-github-issues.yml | 2 +- .github/workflows/verify_e2e-linux.yml | 2 +- .github/workflows/verify_kubernetes.yml | 2 +- .github/workflows/verify_storybook.yml | 2 +- 13 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e84557fc2..a37ae745c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -63,7 +63,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -181,7 +181,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index becab0e952..7ceff46303 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -8,7 +8,7 @@ jobs: cron: runs-on: ubuntu-latest steps: - - uses: backstage/actions/cron@v0.5.11 + - uses: backstage/actions/cron@v0.5.12 with: app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml index 2fae365b18..b2bc62161c 100644 --- a/.github/workflows/deploy_docker-image.yml +++ b/.github/workflows/deploy_docker-image.yml @@ -26,7 +26,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/deploy_nightly.yml b/.github/workflows/deploy_nightly.yml index 57be0b4c1c..80f923e149 100644 --- a/.github/workflows/deploy_nightly.yml +++ b/.github/workflows/deploy_nightly.yml @@ -26,7 +26,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index d3fd8a40ff..837d3eed9c 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -68,7 +68,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -145,7 +145,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml index 94f154d70c..0a24956cfd 100644 --- a/.github/workflows/issue.yaml +++ b/.github/workflows/issue.yaml @@ -10,4 +10,4 @@ jobs: if: github.repository == 'backstage/backstage' steps: - name: Issue sync - uses: backstage/actions/issue-sync@v0.5.11 + uses: backstage/actions/issue-sync@v0.5.12 diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml index f77f23cea0..c7093cbf07 100644 --- a/.github/workflows/pr-review-comment.yaml +++ b/.github/workflows/pr-review-comment.yaml @@ -35,7 +35,7 @@ jobs: const prNumber = artifact.name.slice('pr_number-'.length) core.setOutput('pr-number', prNumber); - - uses: backstage/actions/re-review@v0.5.11 + - uses: backstage/actions/re-review@v0.5.12 with: app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 2ce763e78b..2a12a0d1af 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -18,7 +18,7 @@ jobs: if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request ) steps: - name: PR sync - uses: backstage/actions/pr-sync@v0.5.11 + uses: backstage/actions/pr-sync@v0.5.12 with: github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index cfc08ccb75..601066d16a 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -20,7 +20,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index 5e370873de..4a18ba9e67 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -23,7 +23,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index bb6765cece..a7913e69da 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -52,7 +52,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/verify_kubernetes.yml b/.github/workflows/verify_kubernetes.yml index d4eb7df7b2..c8f9182038 100644 --- a/.github/workflows/verify_kubernetes.yml +++ b/.github/workflows/verify_kubernetes.yml @@ -28,7 +28,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index 20a1ef0e7b..aa06fcd081 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -35,7 +35,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@v0.5.11 + uses: backstage/actions/yarn-install@v0.5.12 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: storybook yarn install From 6aa2b965ebce0fa000b891d8dea67fb72a0a7e80 Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 19 Dec 2022 12:27:41 +0100 Subject: [PATCH 36/87] when looking for the page within the outlet, reject addons wrapper as well as addons, because different versions of react router use different numbers of wrappers. Should be compatible with all 6.* versions now Signed-off-by: Morgan --- plugins/techdocs-react/src/addons.tsx | 4 ++ plugins/techdocs-react/src/index.ts | 1 + plugins/techdocs/package.json | 1 + .../TechDocsReaderPage.test.tsx | 47 +++++++++++++++++++ .../TechDocsReaderPage/TechDocsReaderPage.tsx | 8 +++- 5 files changed, 59 insertions(+), 2 deletions(-) diff --git a/plugins/techdocs-react/src/addons.tsx b/plugins/techdocs-react/src/addons.tsx index a562007260..d77f53a426 100644 --- a/plugins/techdocs-react/src/addons.tsx +++ b/plugins/techdocs-react/src/addons.tsx @@ -27,6 +27,10 @@ import { import { TechDocsAddonLocations, TechDocsAddonOptions } from './types'; +/** + * Key for each addon. + * @public + */ export const TECHDOCS_ADDONS_KEY = 'techdocs.addons.addon.v1'; /** diff --git a/plugins/techdocs-react/src/index.ts b/plugins/techdocs-react/src/index.ts index 00ba620651..5cbab1a326 100644 --- a/plugins/techdocs-react/src/index.ts +++ b/plugins/techdocs-react/src/index.ts @@ -25,6 +25,7 @@ export { createTechDocsAddonExtension, TechDocsAddons, TECHDOCS_ADDONS_WRAPPER_KEY, + TECHDOCS_ADDONS_KEY, } from './addons'; export { techdocsApiRef, techdocsStorageApiRef } from './api'; export type { SyncResult, TechDocsApi, TechDocsStorageApi } from './api'; diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index c3e8fdca9b..0add511f41 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -67,6 +67,7 @@ "@backstage/cli": "workspace:^", "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", + "@backstage/plugin-techdocs-module-addons-contrib": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx index 4b23075908..3d75b7defe 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx @@ -27,6 +27,11 @@ import { techdocsApiRef, techdocsStorageApiRef } from '../../../api'; import { rootRouteRef, rootDocsRouteRef } from '../../../routes'; import { TechDocsReaderPage } from './TechDocsReaderPage'; +import { Route, useParams } from 'react-router-dom'; +import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; +import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; +import { Page } from '@backstage/core-components'; +import { FlatRoutes } from '@backstage/core-app-api'; const mockEntityMetadata = { locationMetadata: { @@ -66,6 +71,16 @@ const techdocsStorageApiMock: jest.Mocked = { syncEntityDocs: jest.fn(), }; +const PageMock = () => { + const { namespace, kind, name } = useParams(); + return <>{`LayoutMock: ${namespace}#${kind}#${name}`}; +}; + +jest.mock('@backstage/core-components', () => ({ + ...jest.requireActual('@backstage/core-components'), + Page: jest.fn(), +})); + const Wrapper = ({ children }: { children: React.ReactNode }) => { return ( @@ -146,4 +161,36 @@ describe('', () => { expect(rendered.getByText('techdocs reader page')).toBeInTheDocument(); }); }); + + it('should render techdocs reader page with addons', async () => { + (Page as jest.Mock).mockImplementation(PageMock); + const name = 'test-name'; + const namespace = 'test-namespace'; + const kind = 'test'; + + await act(async () => { + const rendered = await renderInTestApp( + + + } + > + + + + + + , + { + mountedRoutes, + routeEntries: ['/docs/test-namespace/test/test-name'], + }, + ); + + expect( + rendered.getByText(`LayoutMock: ${namespace}#${kind}#${name}`), + ).toBeInTheDocument(); + }); + }); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx index 0e9b244d74..ffe95e0b7e 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx @@ -21,6 +21,7 @@ import { Page } from '@backstage/core-components'; import { CompoundEntityRef } from '@backstage/catalog-model'; import { TECHDOCS_ADDONS_WRAPPER_KEY, + TECHDOCS_ADDONS_KEY, TechDocsReaderPageProvider, } from '@backstage/plugin-techdocs-react'; @@ -165,11 +166,14 @@ export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => { if (!children) { const childrenList = outlet ? Children.toArray(outlet.props.children) : []; - const grandChildren = childrenList.flatMap( + const grandChildren = childrenList.flatMap( child => (child as ReactElement)?.props?.children ?? [], ); + const page: React.ReactNode = grandChildren.find( - grandChild => !getComponentData(grandChild, TECHDOCS_ADDONS_WRAPPER_KEY), + grandChild => + !getComponentData(grandChild, TECHDOCS_ADDONS_WRAPPER_KEY) && + !getComponentData(grandChild, TECHDOCS_ADDONS_KEY), ); // As explained above, "page" is configuration 4 and is 1 From 786f1b14199fff01690929b4974136fe8192e472 Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 19 Dec 2022 17:43:16 +0100 Subject: [PATCH 37/87] add changeset and update api-report Signed-off-by: Morgan --- .changeset/tidy-hats-begin.md | 6 ++++++ plugins/techdocs-react/api-report.md | 3 +++ 2 files changed, 9 insertions(+) create mode 100644 .changeset/tidy-hats-begin.md diff --git a/.changeset/tidy-hats-begin.md b/.changeset/tidy-hats-begin.md new file mode 100644 index 0000000000..ee500408e1 --- /dev/null +++ b/.changeset/tidy-hats-begin.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-react': minor +'@backstage/plugin-techdocs': patch +--- + +Support older versions of react-router diff --git a/plugins/techdocs-react/api-report.md b/plugins/techdocs-react/api-report.md index 09da4e012c..f1d6d3f177 100644 --- a/plugins/techdocs-react/api-report.md +++ b/plugins/techdocs-react/api-report.md @@ -32,6 +32,9 @@ export const SHADOW_DOM_STYLE_LOAD_EVENT = 'TECH_DOCS_SHADOW_DOM_STYLE_LOAD'; // @public export type SyncResult = 'cached' | 'updated'; +// @public +export const TECHDOCS_ADDONS_KEY = 'techdocs.addons.addon.v1'; + // @public export const TECHDOCS_ADDONS_WRAPPER_KEY = 'techdocs.addons.wrapper.v1'; From 028f88ecb4431928aadf25dfaf794b3cebff81d5 Mon Sep 17 00:00:00 2001 From: Morgan Bentell Date: Mon, 19 Dec 2022 18:06:41 +0100 Subject: [PATCH 38/87] Update test string Signed-off-by: Morgan Bentell --- .../components/TechDocsReaderPage/TechDocsReaderPage.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx index 3d75b7defe..1303901375 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx @@ -73,7 +73,7 @@ const techdocsStorageApiMock: jest.Mocked = { const PageMock = () => { const { namespace, kind, name } = useParams(); - return <>{`LayoutMock: ${namespace}#${kind}#${name}`}; + return <>{`PageMock: ${namespace}#${kind}#${name}`}; }; jest.mock('@backstage/core-components', () => ({ @@ -189,7 +189,7 @@ describe('', () => { ); expect( - rendered.getByText(`LayoutMock: ${namespace}#${kind}#${name}`), + rendered.getByText(`PageMock: ${namespace}#${kind}#${name}`), ).toBeInTheDocument(); }); }); From 63a0b341223846ec28908c65a15ba835a416629f Mon Sep 17 00:00:00 2001 From: Kyle Leonhard Date: Mon, 19 Dec 2022 09:16:33 -0800 Subject: [PATCH 39/87] Update .changeset/sharp-poets-count.md Co-authored-by: Johan Haals Signed-off-by: Kyle Leonhard --- .changeset/sharp-poets-count.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/sharp-poets-count.md b/.changeset/sharp-poets-count.md index 33ec80b718..48920c132d 100644 --- a/.changeset/sharp-poets-count.md +++ b/.changeset/sharp-poets-count.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder-backend': minor --- Add support for disabling Github repository wiki, issues and projects From e0dada2000fb3609ec7e37806d1e18cbb5f7b48f Mon Sep 17 00:00:00 2001 From: Morgan Date: Mon, 19 Dec 2022 18:17:46 +0100 Subject: [PATCH 40/87] yarn lock Signed-off-by: Morgan --- yarn.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn.lock b/yarn.lock index aa82c2bf97..b70833a34e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8263,6 +8263,7 @@ __metadata: "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/plugin-search-react": "workspace:^" + "@backstage/plugin-techdocs-module-addons-contrib": "workspace:^" "@backstage/plugin-techdocs-react": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^" From 177245cdadb10352167d851623dc7ea56bb8bf82 Mon Sep 17 00:00:00 2001 From: Djam Date: Mon, 19 Dec 2022 21:09:13 +0100 Subject: [PATCH 41/87] Update automate_changeset_feedback.yml Signed-off-by: Djam --- .github/workflows/automate_changeset_feedback.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index dc1b22fc8c..d27f0b84e0 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -21,12 +21,20 @@ jobs: if: github.repository == 'backstage/backstage' && github.event.pull_request.user.login != 'backstage-service' runs-on: ubuntu-latest steps: - - uses: backstage/actions/changeset-feedback@vchangeset-patches + - uses: actions/checkout@v3 with: # Fetch the commit that's merged into the base rather than the target ref # This will let us diff only the contents of the PR, without fetching more history - diffRef: 'refs/pull/${{ github.event.pull_request.number }}/merge' - issue-number: ${{ steps.pr-number.outputs.pr-number }} + ref: 'refs/pull/${{ github.event.pull_request.number }}/merge' + - name: fetch base + run: git fetch --depth 1 origin ${{ github.base_ref }} + - uses: backstage/actions/changeset-feedback@v0.5.12 + name: Generate feedback + with: + diffRef: 'origin/master' + marker: + issue-number: ${{ github.event.pull_request.number }} + botUsername: github-actions[bot] app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} installation-id: ${{ secrets.BACKSTAGE_GOALIE_INSTALLATION_ID }} From 10320fd82e8ac87782711baea9db83914d5576fa Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 14 Dec 2022 14:55:12 +0100 Subject: [PATCH 42/87] repo-tools: remove lint rule overrides Signed-off-by: Patrik Oldsberg --- packages/repo-tools/src/commands/api-reports/api-extractor.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/repo-tools/src/commands/api-reports/api-extractor.ts b/packages/repo-tools/src/commands/api-reports/api-extractor.ts index 5ec0804ee8..e4546a0f2e 100644 --- a/packages/repo-tools/src/commands/api-reports/api-extractor.ts +++ b/packages/repo-tools/src/commands/api-reports/api-extractor.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -/* eslint-disable import/no-extraneous-dependencies */ -/* eslint-disable no-restricted-imports */ import { resolve as resolvePath, relative as relativePath, From 9b1193f2772f221e3403b4339bbf277cc697dc7a Mon Sep 17 00:00:00 2001 From: Juan Pablo Garcia Ripa Date: Mon, 19 Dec 2022 23:31:08 +0100 Subject: [PATCH 43/87] add missing dependencies to repo-tools Signed-off-by: Juan Pablo Garcia Ripa --- .changeset/clean-peas-try.md | 5 +++++ packages/repo-tools/package.json | 11 +++++++++++ .../src/commands/api-reports/api-extractor.ts | 19 ++++++++++++++----- yarn.lock | 10 +++++++++- 4 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 .changeset/clean-peas-try.md diff --git a/.changeset/clean-peas-try.md b/.changeset/clean-peas-try.md new file mode 100644 index 0000000000..b18a5931e8 --- /dev/null +++ b/.changeset/clean-peas-try.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +declare dependencies diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 595cbf1196..a5ef3006bb 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -37,6 +37,7 @@ "@microsoft/api-extractor": "^7.23.0", "@microsoft/api-extractor-model": "^7.17.2", "@microsoft/tsdoc": "0.14.1", + "@microsoft/tsdoc-config": "0.16.1", "chalk": "^4.0.0", "commander": "^9.1.0", "fs-extra": "10.1.0", @@ -51,6 +52,16 @@ "@types/mock-fs": "^4.13.0", "mock-fs": "^5.1.0" }, + "peerDependencies": { + "@rushstack/node-core-library": "*", + "prettier": "^2.8.1", + "typescript": "> 3.0.0" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + }, "files": [ "bin", "dist/**/*.js" diff --git a/packages/repo-tools/src/commands/api-reports/api-extractor.ts b/packages/repo-tools/src/commands/api-reports/api-extractor.ts index e4546a0f2e..9e844d97c8 100644 --- a/packages/repo-tools/src/commands/api-reports/api-extractor.ts +++ b/packages/repo-tools/src/commands/api-reports/api-extractor.ts @@ -22,7 +22,7 @@ import { join, } from 'path'; import { execFile } from 'child_process'; -import prettier from 'prettier'; +import type prettierType from 'prettier'; import fs from 'fs-extra'; import { Extractor, @@ -211,10 +211,19 @@ ApiReportGenerator.generateReviewFileContent = collector, ...moreArgs, ); - return prettier.format(content, { - ...require('@spotify/prettier-config'), - parser: 'markdown', - }); + + try { + const prettier = require('prettier') as typeof prettierType; + + const config = prettier.resolveConfig.sync(cliPaths.targetRoot) ?? {}; + return prettier.format(content, { + ...config, + parser: 'markdown', + }); + } catch (e) { + // console.warn('Failed to format API report with prettier', e); + return content; + } }; export async function createTemporaryTsConfig(includedPackageDirs: string[]) { diff --git a/yarn.lock b/yarn.lock index aa82c2bf97..5cc879e997 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8512,6 +8512,7 @@ __metadata: "@microsoft/api-extractor": ^7.23.0 "@microsoft/api-extractor-model": ^7.17.2 "@microsoft/tsdoc": 0.14.1 + "@microsoft/tsdoc-config": 0.16.1 "@types/is-glob": ^4.0.2 "@types/mock-fs": ^4.13.0 chalk: ^4.0.0 @@ -8522,6 +8523,13 @@ __metadata: minimatch: ^5.1.1 mock-fs: ^5.1.0 ts-node: ^10.0.0 + peerDependencies: + "@rushstack/node-core-library": "*" + prettier: ^2.8.1 + typescript: "> 3.0.0" + peerDependenciesMeta: + prettier: + optional: true bin: backstage-repo-tools: bin/backstage-repo-tools languageName: unknown @@ -11562,7 +11570,7 @@ __metadata: languageName: node linkType: hard -"@microsoft/tsdoc-config@npm:~0.16.1": +"@microsoft/tsdoc-config@npm:0.16.1, @microsoft/tsdoc-config@npm:~0.16.1": version: 0.16.1 resolution: "@microsoft/tsdoc-config@npm:0.16.1" dependencies: From 339c24bbfc554538b85ef5062c66c8634d1ab4ee Mon Sep 17 00:00:00 2001 From: Brett Wright Date: Tue, 20 Dec 2022 11:20:39 +1100 Subject: [PATCH 44/87] Added test for skipInstall option Signed-off-by: Brett Wright --- .../cli/src/commands/versions/bump.test.ts | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index 25682a4cd4..e1b06877de 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -222,6 +222,102 @@ describe('bump', () => { }); }); + it('should bump backstage dependencies but not them installed', async () => { + mockFs({ + '/yarn.lock': lockfileMock, + '/package.json': JSON.stringify({ + workspaces: { + packages: ['packages/*'], + }, + }), + '/packages/a/package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), + '/packages/b/package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), + }); + + jest + .spyOn(paths, 'resolveTargetRoot') + .mockImplementation((...path) => resolvePath('/', ...path)); + jest.spyOn(runObj, 'run').mockResolvedValue(undefined); + worker.use( + rest.get( + 'https://versions.backstage.io/v1/tags/main/manifest.json', + (_, res, ctx) => + res( + ctx.status(200), + ctx.json({ + packages: [], + }), + ), + ), + ); + const { log: logs } = await withLogCollector(['log'], async () => { + await bump({ + pattern: null, + release: 'main', + skipInstall: true, + } as unknown as Command); + }); + expect(logs.filter(Boolean)).toEqual([ + 'Using default pattern glob @backstage/*', + 'Checking for updates of @backstage/core', + 'Checking for updates of @backstage/theme', + 'Checking for updates of @backstage/core-api', + 'Some packages are outdated, updating', + 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', + 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', + 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', + 'bumping @backstage/core in a to ^1.0.6', + 'bumping @backstage/core in b to ^1.0.6', + 'bumping @backstage/theme in b to ^2.0.0', + 'Skipping yarn install', + '⚠️ The following packages may have breaking changes:', + ' @backstage/theme : 1.0.0 ~> 2.0.0', + ' https://github.com/backstage/backstage/blob/master/packages/theme/CHANGELOG.md', + 'Version bump complete!', + ]); + + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(3); + expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); + expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core-api'); + expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/theme'); + + expect(runObj.run).not.toHaveBeenCalledWith( + 'yarn', + ['install'], + expect.any(Object), + ); + + const lockfileContents = await fs.readFile('/yarn.lock', 'utf8'); + expect(lockfileContents).toBe(lockfileMockResult); + + const packageA = await fs.readJson('/packages/a/package.json'); + expect(packageA).toEqual({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.6', + }, + }); + const packageB = await fs.readJson('/packages/b/package.json'); + expect(packageB).toEqual({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.6', + '@backstage/theme': '^2.0.0', + }, + }); + }); + it('should prefer dependency versions from release manifest', async () => { mockFs({ '/yarn.lock': lockfileMock, From 665c681f3ce1e6438e1448a4c8b4fc98ddbc7442 Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 20 Dec 2022 09:55:50 +0100 Subject: [PATCH 45/87] fix tests that broke Signed-off-by: Morgan --- .../TechDocsReaderPage/TechDocsReaderPage.test.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx index 1303901375..b8077c604f 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx @@ -30,9 +30,10 @@ import { TechDocsReaderPage } from './TechDocsReaderPage'; import { Route, useParams } from 'react-router-dom'; import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; -import { Page } from '@backstage/core-components'; import { FlatRoutes } from '@backstage/core-app-api'; +import { Page } from '@backstage/core-components'; + const mockEntityMetadata = { locationMetadata: { type: 'github', @@ -112,6 +113,12 @@ describe('', () => { afterEach(() => { jest.resetAllMocks(); }); + + beforeEach(() => { + const realPage = jest.requireActual('@backstage/core-components').Page; + (Page as jest.Mock).mockImplementation(realPage); + }); + it('should render a techdocs reader page without children', async () => { const rendered = await renderInTestApp( From e567de03a1c0762ce2f3f56591bff7108cb20f80 Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 20 Dec 2022 10:03:48 +0100 Subject: [PATCH 46/87] add another test Signed-off-by: Morgan --- .../TechDocsReaderPage.test.tsx | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx index b8077c604f..808cb84ccf 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx @@ -200,4 +200,31 @@ describe('', () => { ).toBeInTheDocument(); }); }); + + it('should render techdocs reader page with addons and page', async () => { + (Page as jest.Mock).mockImplementation(PageMock); + await act(async () => { + const rendered = await renderInTestApp( + + + } + > +

the page

+ + + +
+
+
, + { + mountedRoutes, + routeEntries: ['/docs/test-namespace/test/test-name'], + }, + ); + + expect(rendered.getByText('the page')).toBeInTheDocument(); + }); + }); }); From 57ad6553d04bca7963100f972ed625a32dfe0a90 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 16 Dec 2022 18:40:10 +0000 Subject: [PATCH 47/87] pass through transformErrors to TemplateWizardPage Signed-off-by: Paul Cowan --- .changeset/perfect-garlics-care.md | 5 +++++ plugins/scaffolder/src/next/Router/Router.test.tsx | 14 ++++++++++++++ plugins/scaffolder/src/next/Router/Router.tsx | 5 ++++- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 .changeset/perfect-garlics-care.md diff --git a/.changeset/perfect-garlics-care.md b/.changeset/perfect-garlics-care.md new file mode 100644 index 0000000000..e6f56e6d69 --- /dev/null +++ b/.changeset/perfect-garlics-care.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Pass through transformErrors to TemplateWizardPage diff --git a/plugins/scaffolder/src/next/Router/Router.test.tsx b/plugins/scaffolder/src/next/Router/Router.test.tsx index 1aaca1a94b..78e21f57fd 100644 --- a/plugins/scaffolder/src/next/Router/Router.test.tsx +++ b/plugins/scaffolder/src/next/Router/Router.test.tsx @@ -54,6 +54,20 @@ describe('Router', () => { expect(TemplateWizardPage).toHaveBeenCalled(); }); + it('should pass through the transformErrors property', async () => { + const transformErrorsMock = jest.fn(); + + await renderInTestApp(, { + routeEntries: ['/templates/default/foo'], + }); + + const mock = TemplateWizardPage as jest.Mock; + + const [{ transformErrors }] = mock.mock.calls[0]; + + expect(transformErrors).toEqual(transformErrors); + }); + it('should extract the fieldExtensions and pass them through', async () => { const mockComponent = () => null; const CustomFieldExtension = scaffolderPlugin.provide( diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/next/Router/Router.tsx index 9ca1e39681..ecf89c8742 100644 --- a/plugins/scaffolder/src/next/Router/Router.tsx +++ b/plugins/scaffolder/src/next/Router/Router.tsx @@ -93,7 +93,10 @@ export const Router = (props: PropsWithChildren) => { path={nextSelectedTemplateRouteRef.path} element={ - + } /> From b23bf0c84d941794aeae22b38f0df2c1630901b9 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 16 Dec 2022 18:54:10 +0000 Subject: [PATCH 48/87] run api-report Signed-off-by: Paul Cowan --- plugins/scaffolder/api-report.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index 68bc893b6f..db928f0c62 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -110,9 +110,9 @@ export type EntityPickerUiOptions = export const EntityTagsPickerFieldExtension: FieldExtensionComponent< string[], { - showCounts?: boolean | undefined; - kinds?: string[] | undefined; helperText?: string | undefined; + kinds?: string[] | undefined; + showCounts?: boolean | undefined; } >; @@ -120,9 +120,9 @@ export const EntityTagsPickerFieldExtension: FieldExtensionComponent< export const EntityTagsPickerFieldSchema: FieldSchema< string[], { - showCounts?: boolean | undefined; - kinds?: string[] | undefined; helperText?: string | undefined; + kinds?: string[] | undefined; + showCounts?: boolean | undefined; } >; From 0fb3edbda2a5846f780fc74bd103401446bad397 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Fri, 16 Dec 2022 19:06:11 +0000 Subject: [PATCH 49/87] fix changeset message Signed-off-by: Paul Cowan --- .changeset/perfect-garlics-care.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/perfect-garlics-care.md b/.changeset/perfect-garlics-care.md index e6f56e6d69..121ffd5c0f 100644 --- a/.changeset/perfect-garlics-care.md +++ b/.changeset/perfect-garlics-care.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder': patch --- -Pass through transformErrors to TemplateWizardPage +Pass through `transformErrors` to `TemplateWizardPage` From 1469f0b2de0b829c585aa32db895ebb1725c1840 Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Mon, 19 Dec 2022 16:46:32 +0000 Subject: [PATCH 50/87] create a FormProps intersection type to augment next/Router props Signed-off-by: Paul Cowan --- plugins/scaffolder/api-report.md | 12 ++++++---- plugins/scaffolder/src/index.ts | 1 + plugins/scaffolder/src/next/Router/Router.tsx | 5 ++-- .../TemplateWizardPage/Stepper/Stepper.tsx | 7 +++--- .../TemplateWizardPage/TemplateWizardPage.tsx | 7 +++--- plugins/scaffolder/src/next/index.ts | 2 ++ plugins/scaffolder/src/next/types.ts | 23 +++++++++++++++++++ 7 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 plugins/scaffolder/src/next/types.ts diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index db928f0c62..808decc89e 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -11,7 +11,6 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; -import type { ErrorTransformer } from '@rjsf/utils'; import { Extension } from '@backstage/core-plugin-api'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { FetchApi } from '@backstage/core-plugin-api'; @@ -19,7 +18,8 @@ import { FieldProps } from '@rjsf/core'; import { FieldProps as FieldProps_2 } from '@rjsf/utils'; import { FieldValidation } from '@rjsf/core'; import { FieldValidation as FieldValidation_2 } from '@rjsf/utils'; -import type { FormProps } from '@rjsf/core'; +import type { FormProps as FormProps_2 } from '@rjsf/core'; +import type { FormProps as FormProps_3 } from '@rjsf/core-v5'; import { IdentityApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; import { JSONSchema7 } from 'json-schema'; @@ -167,6 +167,9 @@ export interface FieldSchema { readonly uiOptionsType: TUiOptions; } +// @alpha +export type FormProps = Pick; + // @public export type LayoutComponent<_TInputProps> = () => null; @@ -179,7 +182,7 @@ export interface LayoutOptions

{ } // @public -export type LayoutTemplate = FormProps['ObjectFieldTemplate']; +export type LayoutTemplate = FormProps_2['ObjectFieldTemplate']; // @public export type ListActionsResponse = Array<{ @@ -264,8 +267,7 @@ export type NextRouterProps = { TaskPageComponent?: React_2.ComponentType<{}>; }; groups?: TemplateGroupFilter[]; - transformErrors?: ErrorTransformer; -}; +} & FormProps; // @alpha export const NextScaffolderPage: ( diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index 0e5e2630ac..1ed1346176 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -74,6 +74,7 @@ export type { TaskPageProps } from './components/TaskPage'; export { NextScaffolderPage } from './plugin'; export type { NextRouterProps } from './next'; export type { TemplateGroupFilter } from './next'; +export type { FormProps } from './next'; export { createNextScaffolderFieldExtension, type NextCustomFieldValidator, diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/next/Router/Router.tsx index ecf89c8742..9ce1ad9588 100644 --- a/plugins/scaffolder/src/next/Router/Router.tsx +++ b/plugins/scaffolder/src/next/Router/Router.tsx @@ -30,7 +30,7 @@ import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '../TemplateListPage/TemplateGroups'; import { nextSelectedTemplateRouteRef } from '../../routes'; import { SecretsContextProvider } from '../../components/secrets/SecretsContext'; -import type { ErrorTransformer } from '@rjsf/utils'; +import type { FormProps } from '../types'; /** * The Props for the Scaffolder Router @@ -45,8 +45,7 @@ export type NextRouterProps = { TaskPageComponent?: React.ComponentType<{}>; }; groups?: TemplateGroupFilter[]; - transformErrors?: ErrorTransformer; -}; +} & FormProps; /** * The Scaffolder Router diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx index fffacae2f2..c11fd450ee 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx @@ -36,9 +36,9 @@ import { useTemplateSchema } from './useTemplateSchema'; import { ReviewState } from './ReviewState'; import validator from '@rjsf/validator-ajv8'; import { selectedTemplateRouteRef } from '../../../routes'; -import type { ErrorTransformer } from '@rjsf/utils'; import { getDefaultFormState } from '@rjsf/utils'; import { useFormData } from './useFormData'; +import { FormProps } from '../../types'; const useStyles = makeStyles(theme => ({ backButton: { @@ -55,12 +55,11 @@ const useStyles = makeStyles(theme => ({ }, })); -export interface StepperProps { +export type StepperProps = { manifest: TemplateParameterSchema; extensions: NextFieldExtensionOptions[]; onComplete: (values: Record) => Promise; - transformErrors?: ErrorTransformer; -} +} & FormProps; // TODO(blam): We require here, as the types in this package depend on @rjsf/core explicitly // which is what we're using here as the default types, it needs to depend on @rjsf/core-v5 because diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx index 31a5808233..0990bb40ce 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/TemplateWizardPage.tsx @@ -44,12 +44,11 @@ import { } from '../../routes'; import { SecretsContext } from '../../components/secrets/SecretsContext'; import { JsonValue } from '@backstage/types'; -import type { ErrorTransformer } from '@rjsf/utils'; +import type { FormProps } from '../types'; -export interface TemplateWizardPageProps { +export type TemplateWizardPageProps = { customFieldExtensions: NextFieldExtensionOptions[]; - transformErrors?: ErrorTransformer; -} +} & FormProps; const useStyles = makeStyles(() => ({ markdown: { diff --git a/plugins/scaffolder/src/next/index.ts b/plugins/scaffolder/src/next/index.ts index 089c268b0b..3a874e3b41 100644 --- a/plugins/scaffolder/src/next/index.ts +++ b/plugins/scaffolder/src/next/index.ts @@ -16,3 +16,5 @@ export * from './Router'; export * from './TemplateListPage'; export * from './TemplateWizardPage'; + +export type { FormProps } from './types'; diff --git a/plugins/scaffolder/src/next/types.ts b/plugins/scaffolder/src/next/types.ts new file mode 100644 index 0000000000..d0d3ed1011 --- /dev/null +++ b/plugins/scaffolder/src/next/types.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { FormProps as SchemaFormProps } from '@rjsf/core-v5'; + +/** + * Any `@rjsf/core` form properties that are publicly exposed to the `NextScaffolderpage` + * + * @alpha + */ +export type FormProps = Pick; From ed00e37d58a55b3ae136231ba795e366afbd583a Mon Sep 17 00:00:00 2001 From: Paul Cowan Date: Tue, 20 Dec 2022 09:30:49 +0000 Subject: [PATCH 51/87] make FormProps a prop on next/Router Signed-off-by: Paul Cowan --- .../scaffolder/src/next/Router/Router.test.tsx | 15 +++++++++++---- plugins/scaffolder/src/next/Router/Router.tsx | 5 +++-- .../TemplateWizardPage/Stepper/Stepper.test.tsx | 2 +- .../next/TemplateWizardPage/Stepper/Stepper.tsx | 5 +++-- .../TemplateWizardPage/TemplateWizardPage.tsx | 5 +++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/plugins/scaffolder/src/next/Router/Router.test.tsx b/plugins/scaffolder/src/next/Router/Router.test.tsx index 78e21f57fd..0e890005ac 100644 --- a/plugins/scaffolder/src/next/Router/Router.test.tsx +++ b/plugins/scaffolder/src/next/Router/Router.test.tsx @@ -57,13 +57,20 @@ describe('Router', () => { it('should pass through the transformErrors property', async () => { const transformErrorsMock = jest.fn(); - await renderInTestApp(, { - routeEntries: ['/templates/default/foo'], - }); + await renderInTestApp( + , + { + routeEntries: ['/templates/default/foo'], + }, + ); const mock = TemplateWizardPage as jest.Mock; - const [{ transformErrors }] = mock.mock.calls[0]; + const [ + { + FormProps: { transformErrors }, + }, + ] = mock.mock.calls[0]; expect(transformErrors).toEqual(transformErrors); }); diff --git a/plugins/scaffolder/src/next/Router/Router.tsx b/plugins/scaffolder/src/next/Router/Router.tsx index 9ce1ad9588..7a2d2826e7 100644 --- a/plugins/scaffolder/src/next/Router/Router.tsx +++ b/plugins/scaffolder/src/next/Router/Router.tsx @@ -45,7 +45,8 @@ export type NextRouterProps = { TaskPageComponent?: React.ComponentType<{}>; }; groups?: TemplateGroupFilter[]; -} & FormProps; + FormProps?: FormProps; +}; /** * The Scaffolder Router @@ -94,7 +95,7 @@ export const Router = (props: PropsWithChildren) => { } diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx index c8dbb0cb19..af86abf1c6 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.test.tsx @@ -174,7 +174,7 @@ describe('Stepper', () => { manifest={manifest} extensions={[]} onComplete={jest.fn()} - transformErrors={transformErrors} + FormProps={{ transformErrors }} />, ); diff --git a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx index c11fd450ee..27230b2f7b 100644 --- a/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx +++ b/plugins/scaffolder/src/next/TemplateWizardPage/Stepper/Stepper.tsx @@ -59,7 +59,8 @@ export type StepperProps = { manifest: TemplateParameterSchema; extensions: NextFieldExtensionOptions[]; onComplete: (values: Record) => Promise; -} & FormProps; + FormProps?: FormProps; +}; // TODO(blam): We require here, as the types in this package depend on @rjsf/core explicitly // which is what we're using here as the default types, it needs to depend on @rjsf/core-v5 because @@ -164,7 +165,7 @@ export const Stepper = (props: StepperProps) => { onSubmit={handleNext} fields={extensions} showErrorList={false} - transformErrors={props.transformErrors} + {...(props.FormProps ?? {})} >