From 009da479d54861114771c6279738cf6313f91878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20R=C3=A4ntil=C3=A4?= Date: Mon, 22 Apr 2024 14:16:52 +0200 Subject: [PATCH 01/14] fix: Fix versions-check cli command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gustaf Räntilä --- .changeset/wild-doors-cheat.md | 5 ++ packages/cli-node/package.json | 2 +- packages/cli/package.json | 2 +- packages/cli/src/lib/versioning/Lockfile.ts | 80 +++++++++++++++++---- plugins/devtools-backend/package.json | 2 +- yarn.lock | 14 ++-- 6 files changed, 82 insertions(+), 23 deletions(-) create mode 100644 .changeset/wild-doors-cheat.md diff --git a/.changeset/wild-doors-cheat.md b/.changeset/wild-doors-cheat.md new file mode 100644 index 0000000000..c302dde467 --- /dev/null +++ b/.changeset/wild-doors-cheat.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix `versions:check --fix` when `yarn.lock` has multiple joint versions in the same section diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index 3bd9a98f60..a786d71949 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -35,7 +35,7 @@ "@backstage/errors": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", - "@yarnpkg/parsers": "^3.0.0-rc.4", + "@yarnpkg/parsers": "^3.0.0", "fs-extra": "^11.2.0", "semver": "^7.5.3", "zod": "^3.22.4" diff --git a/packages/cli/package.json b/packages/cli/package.json index d6fe116248..02a57980e9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -79,7 +79,7 @@ "@typescript-eslint/eslint-plugin": "^6.12.0", "@typescript-eslint/parser": "^6.7.2", "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "^3.0.0-rc.4", + "@yarnpkg/parsers": "^3.0.0", "bfj": "^8.0.0", "buffer": "^6.0.3", "chalk": "^4.0.0", diff --git a/packages/cli/src/lib/versioning/Lockfile.ts b/packages/cli/src/lib/versioning/Lockfile.ts index 50d0a77cfd..6af115a4da 100644 --- a/packages/cli/src/lib/versioning/Lockfile.ts +++ b/packages/cli/src/lib/versioning/Lockfile.ts @@ -98,6 +98,24 @@ export class Lockfile { return Lockfile.parse(lockfileContents); } + static #getRangesFromDataKey(key: string): string[] { + const [, name, ranges] = key.match(ENTRY_PATTERN) ?? []; + if (!name) { + throw new Error(`Failed to parse yarn.lock entry '${key}'`); + } + + return ranges.split(/\s*,\s*/).map(rangePart => { + let range = rangePart; + if (range.startsWith(`${name}@`)) { + range = range.slice(`${name}@`.length); + } + if (range.startsWith('npm:')) { + range = range.slice('npm:'.length); + } + return range; + }); + } + static parse(content: string) { const legacy = LEGACY_REGEX.test(content); @@ -113,7 +131,7 @@ export class Lockfile { for (const [key, value] of Object.entries(data)) { if (SPECIAL_OBJECT_KEYS.includes(key)) continue; - const [, name, ranges] = ENTRY_PATTERN.exec(key) ?? []; + const [, name] = ENTRY_PATTERN.exec(key) ?? []; if (!name) { throw new Error(`Failed to parse yarn.lock entry '${key}'`); } @@ -123,13 +141,8 @@ export class Lockfile { queries = []; packages.set(name, queries); } - for (let range of ranges.split(/\s*,\s*/)) { - if (range.startsWith(`${name}@`)) { - range = range.slice(`${name}@`.length); - } - if (range.startsWith('npm:')) { - range = range.slice('npm:'.length); - } + const ranges = Lockfile.#getRangesFromDataKey(key); + for (const range of ranges) { queries.push({ range, version: value.version, dataKey: key }); } } @@ -276,9 +289,34 @@ export class Lockfile { } remove(name: string, range: string): boolean { - const query = `${name}@${range}`; + const simpleQuery = `${name}@${range}`; + const query = this.getEntryOf(name, range); + const existed = Boolean(this.data[query]); - delete this.data[query]; + + if (simpleQuery === query) { + // Single-versioned entry, just delete + delete this.data[query]; + } else { + // Remove this version from the entry key. This modifies the key, so the + // package queries' needs to be updated too. + const newRanges = Lockfile.#getRangesFromDataKey(query).filter( + q => q !== simpleQuery, + ); + const newQuery = newRanges.join(', '); + + // Replace the entry with a new one without this particular range + const entry = this.data[query]; + delete this.data[query]; + this.data[newQuery] = entry; + + // Fix all package queries pointing to the old query + this.packages.get(name)?.forEach(q => { + if (q.dataKey === query) { + q.dataKey = newQuery; + } + }); + } const newEntries = this.packages.get(name)?.filter(e => e.range !== range); if (newEntries) { @@ -288,19 +326,35 @@ export class Lockfile { return existed; } + getEntryOf(name: string, range: string) { + const query = this.packages.get(name)?.find(q => q.range === range); + if (!query) { + throw new Error(`No entry data for ${name}@${range}`); + } + + return query.dataKey; + } + /** Modifies the lockfile by bumping packages to the suggested versions */ replaceVersions(results: AnalyzeResultNewVersion[]) { + // When replacing versions, we might replace the same version multiple times, + // as a query may contain multiple versions. This keeps the original version, + // to ensure we don't make mistakes. + const oldVersions = Object.fromEntries( + Object.entries(this.data).map(([key, val]) => [key, val.version]), + ); + for (const { name, range, oldVersion, newVersion } of results) { - const query = `${name}@${range}`; + const query = this.getEntryOf(name, range); // Update the backing data const entryData = this.data[query]; if (!entryData) { throw new Error(`No entry data for ${query}`); } - if (entryData.version !== oldVersion) { + if (oldVersions[query] !== oldVersion) { throw new Error( - `Expected existing version data for ${query} to be ${oldVersion}, was ${entryData.version}`, + `Expected existing version data for ${query} to be ${oldVersion}, was ${oldVersions[query]}`, ); } diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index fd2c8eac4a..6c440b66f0 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -41,7 +41,7 @@ "@manypkg/get-packages": "^1.1.3", "@types/express": "*", "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "^3.0.0-rc.4", + "@yarnpkg/parsers": "^3.0.0", "express": "^4.18.1", "express-promise-router": "^4.1.0", "fs-extra": "^11.0.0", diff --git a/yarn.lock b/yarn.lock index 9c9a730679..bcf0790899 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3642,7 +3642,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": ^1.1.3 - "@yarnpkg/parsers": ^3.0.0-rc.4 + "@yarnpkg/parsers": ^3.0.0 fs-extra: ^11.2.0 semver: ^7.5.3 zod: ^3.22.4 @@ -3716,7 +3716,7 @@ __metadata: "@typescript-eslint/parser": ^6.7.2 "@vitejs/plugin-react": ^4.0.4 "@yarnpkg/lockfile": ^1.1.0 - "@yarnpkg/parsers": ^3.0.0-rc.4 + "@yarnpkg/parsers": ^3.0.0 bfj: ^8.0.0 buffer: ^6.0.3 chalk: ^4.0.0 @@ -5777,7 +5777,7 @@ __metadata: "@types/supertest": ^2.0.8 "@types/yarnpkg__lockfile": ^1.1.4 "@yarnpkg/lockfile": ^1.1.0 - "@yarnpkg/parsers": ^3.0.0-rc.4 + "@yarnpkg/parsers": ^3.0.0 express: ^4.18.1 express-promise-router: ^4.1.0 fs-extra: ^11.0.0 @@ -19325,13 +19325,13 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/parsers@npm:^3.0.0-rc.4": - version: 3.0.0-rc.21 - resolution: "@yarnpkg/parsers@npm:3.0.0-rc.21" +"@yarnpkg/parsers@npm:^3.0.0": + version: 3.0.0 + resolution: "@yarnpkg/parsers@npm:3.0.0" dependencies: js-yaml: ^3.10.0 tslib: ^2.4.0 - checksum: c0741ef01089a7d452dfb75b8c24a82ddcc3e218dac22b794a06f2e50c7070378c460f63f63fb7ed0f62f634114e448e3d85a75ccd4db84e1526242ae9b4a7d5 + checksum: fefe5ecafb5bfa2b678ac9ba9259810fdda40142afd9d0b7e0e5cc1cce1fd824dffc52217c5e429807481d8fd18ead074bd317e64fd626335d3c9f1a320bade2 languageName: node linkType: hard From f7edc833204e8ccdf79cc676af906b80a1112ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20R=C3=A4ntil=C3=A4?= Date: Mon, 22 Apr 2024 16:12:41 +0200 Subject: [PATCH 02/14] Revert package upgrade from devtools-backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gustaf Räntilä --- plugins/devtools-backend/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index 6c440b66f0..fd2c8eac4a 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -41,7 +41,7 @@ "@manypkg/get-packages": "^1.1.3", "@types/express": "*", "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "^3.0.0", + "@yarnpkg/parsers": "^3.0.0-rc.4", "express": "^4.18.1", "express-promise-router": "^4.1.0", "fs-extra": "^11.0.0", diff --git a/yarn.lock b/yarn.lock index bcf0790899..f3b60bc781 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5777,7 +5777,7 @@ __metadata: "@types/supertest": ^2.0.8 "@types/yarnpkg__lockfile": ^1.1.4 "@yarnpkg/lockfile": ^1.1.0 - "@yarnpkg/parsers": ^3.0.0 + "@yarnpkg/parsers": ^3.0.0-rc.4 express: ^4.18.1 express-promise-router: ^4.1.0 fs-extra: ^11.0.0 @@ -19325,7 +19325,7 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/parsers@npm:^3.0.0": +"@yarnpkg/parsers@npm:^3.0.0, @yarnpkg/parsers@npm:^3.0.0-rc.4": version: 3.0.0 resolution: "@yarnpkg/parsers@npm:3.0.0" dependencies: From 17ed7bc6f92ca10c4697013b0420548384ab0890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20R=C3=A4ntil=C3=A4?= Date: Tue, 23 Apr 2024 06:08:32 +0200 Subject: [PATCH 03/14] Back to the future MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gustaf Räntilä --- plugins/devtools-backend/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index fd2c8eac4a..6c440b66f0 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -41,7 +41,7 @@ "@manypkg/get-packages": "^1.1.3", "@types/express": "*", "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "^3.0.0-rc.4", + "@yarnpkg/parsers": "^3.0.0", "express": "^4.18.1", "express-promise-router": "^4.1.0", "fs-extra": "^11.0.0", diff --git a/yarn.lock b/yarn.lock index f3b60bc781..bcf0790899 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5777,7 +5777,7 @@ __metadata: "@types/supertest": ^2.0.8 "@types/yarnpkg__lockfile": ^1.1.4 "@yarnpkg/lockfile": ^1.1.0 - "@yarnpkg/parsers": ^3.0.0-rc.4 + "@yarnpkg/parsers": ^3.0.0 express: ^4.18.1 express-promise-router: ^4.1.0 fs-extra: ^11.0.0 @@ -19325,7 +19325,7 @@ __metadata: languageName: node linkType: hard -"@yarnpkg/parsers@npm:^3.0.0, @yarnpkg/parsers@npm:^3.0.0-rc.4": +"@yarnpkg/parsers@npm:^3.0.0": version: 3.0.0 resolution: "@yarnpkg/parsers@npm:3.0.0" dependencies: From 93be042a86d12ad22435599ebd904993f06e606a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20R=C3=A4ntil=C3=A4?= Date: Mon, 13 May 2024 14:34:58 +0200 Subject: [PATCH 04/14] fix: Added changeset to cli-node dependency upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gustaf Räntilä --- .changeset/breezy-badgers-train.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/breezy-badgers-train.md diff --git a/.changeset/breezy-badgers-train.md b/.changeset/breezy-badgers-train.md new file mode 100644 index 0000000000..8f747b8602 --- /dev/null +++ b/.changeset/breezy-badgers-train.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-node': patch +--- + +Upgraded @yarnpkg/parsers to stable 3.0 From c65938d64d769cb3e8f27f495756544897a5ea31 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 14 May 2024 16:58:20 +0200 Subject: [PATCH 05/14] docs/overview: update roadmap for fall 2024 Signed-off-by: Patrik Oldsberg --- docs/overview/roadmap.md | 120 +++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 62 deletions(-) diff --git a/docs/overview/roadmap.md b/docs/overview/roadmap.md index 186619d1df..f53f79f431 100644 --- a/docs/overview/roadmap.md +++ b/docs/overview/roadmap.md @@ -6,91 +6,87 @@ description: Roadmap of Backstage ## The Backstage Roadmap -Backstage is currently under rapid development. This page details the project's -public roadmap, the result of ongoing collaboration between the core maintainers -and the broader Backstage community. +Backstage is still under rapid development, and this page details the project's +public roadmap. This not a complete list of all work happening in and around the +project, it only highlights the highest priority initiatives worked on by the +core maintainers. -The Backstage roadmap lays out both [“what's next”](#whats-next) and ["future work"](#future-work). With "next" we mean features planned for release within -the ongoing quarter from July through September 2022. With "future" we mean -features on the radar, but not yet scheduled. +## 2024 Fall Roadmap -| [What's next](#whats-next) | [Future work](#future-work) | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -| [Backend Services (MVP)](#backend-services-mvp)
[Backstage Security Audit](#backstage-security-audit)
[Backstage Threat Model](#backstage-threat-model)
[Software Catalog pagination](#software-catalog-pagination)
[More SIGs](#more-sigs) | Ease of onboarding
Composable Homepage 1.0
Creator experience
GraphQL
Telemetry | +The initiatives listed below are planned for release within the next half-year, starting in May 2024. The roadmap is updated every 6 months, and the next update is planned for November 2024. -The long-term roadmap (12 - 36 months) is not detailed in the public roadmap. -Third-party contributions are also not currently included in the roadmap. Let us -know about any ongoing developments and we're happy to include them here as -well. +### Backend System 1.0 -## What's next +The goal of this initiative is the stable 1.0 release of the [new backend system](../backend-system/index.md). +This includes ensuring that all documentation is up to date, and includes API +reviews and refactoring efforts to ensure that what is released is both stable +and evolvable. You can follow along with this work in the [meta issue](https://github.com/backstage/backstage/issues/24493). -The feature set below is planned for the ongoing quarter, and grouped by theme. -The list order doesn't necessarily reflect priority, and the development/release -cycle will vary based on maintainer schedules. +As part of this initiative, there will also be and exploration on how to +simplify extension of backend services. It is not currently possible to augment +backend services through declarative integration, they are instead only +customizable through complete replacement. This also limits the ability to +modularize services and scale ownership of the implementations. The goal is to +provide a more flexible and scalable way to extend backend services. -### Backend Services (MVP) +### New Frontend System - Ready for Adoption -To better scale and maintain the Backstage instances, a backend services system -is planned to be introduced as part of the software architecture. This layer of -backend services will help in decoupling the various modules (e.g. Catalog and -Scaffolder) from the frontend experience. +The [new fronted system](../frontend-system/index.md) still needs more work, and +the next milestone is to improve it to the point where there is enough +confidence in the design to start encouraging adoption in the community. You can +follow along with this work in the [meta issue](https://github.com/backstage/backstage/issues/19545). +This milestone also includes reaching and executing [rollout phase 2](https://github.com/backstage/backstage/issues/19545#issuecomment-1766069146). -After the experimentation and design happened in the past quarter, soon we plan to release a first version to start providing the first benefits to adopters and developers. +Once the initial milestone is reached, the goal is to also build out broader +support for the new frontend system in the core plugins. ### Backstage Security Audit -This is the continuation of the initiative started in the previous quarters. This -quarter will see the publication of the report describing the outcome of the -audit, together the first fixes and the development of some of the changes -required to address the vulnerabilities. +This is the second security audit of the Backstage project. It is done together, +and with the support of the [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io/). +This time the audit will in particular focus on the recently introduced +[authentication system](https://github.com/backstage/backstage/tree/master/beps/0003-auth-architecture-evolution), +but also cover other parts of the project. -This initiative is the first of a broader Security Strategy for Backstage. The -purpose of the Security Audit is to involve third-party companies in auditing -the platform. The benefit for the adopters is clear: we want Backstage to be as -secure as possible, and we want to make it reliable through a specific -initiative. +### Plugin Metadata -This initiative is done together with, and with the support of, the [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io/). +The goal of this initiative is to provide better machine readable metadata for +Backstage packages, available both at runtime, at build-time and as part of +package registries. We want to surface information such as what packages make up +a particular plugin, what features it provides, and more generally laying the +foundation for an evolvable plugin metadata system. -### Backstage Threat Model +### MUI v5 Green-light -This is another (relevant) initiative planned to make Backstage a secure product for the adopters. The goals of this initiative are: +Material-UI v4 is still the officially supported version of MUI in Backstage. +While we have heard that adopters have had success using MUI 5, this is still an +untested path with known bugs. The goal of this initiative is to iron out any +remaining issues of gaps, and then provide a green light for migration to MUI 5. -1. Understand where security investment and attention is needed. -2. Guide the upcoming security audit. -3. Communicate expectations to Backstage adopters and inform and attract security researchers. +### Configuration Improvements -The planned artifacts are: +This initiative aims to improve the configuration experience and reliability in +Backstage. Areas for improvement include the way that configuration schema is +loaded, the way that plugins access configuration that is not owned by them, how +plugins read configuration, and how configuration visibility is handled. -- Concise high level threat model that will be included as part of the Backstage security documentation. -- Granular threat model created in conjunction with the security audit to inform further security investment areas for Backstage. +### Versioned Documentation -### Software Catalog pagination +The goal of this initiative is to provide versioned documentation at +[backstage.io](https://backstage.io). This lets us provide documentation that is +both up-to-date while at the same time not ahead of the latest release. -Today adopters with a big catalog (with several thousands of software components) might not have an ideal end-user experience when viewing the `/catalog` page. The issue is related to how the entities are fetched by the frontend. In order to provide a better end-user experience the pagination of the catalog’s entities needs to be enforced. Some experimentation is already completed but in this quarter we plan to continue, and hopefully complete, this relevant enhancement. +### Rework Pull Request & Issue Process -### More SIGs +Our current review and issue triage process is centered around either core- or +project area maintainers. The goal of this initiative is to make it simpler for +more members of the community to be involved and contribute to this process. -In the last quarter we launched the [Catalog SIG (Special Interest Group)](https://github.com/backstage/community/tree/main/sigs/sig-catalog) to better coordinate the increasing number of contributions to the project. We think that this is the proper path to follow to engage more with the contributors. For this reason we will launch other SIGs dedicated to the most interesting topics for the community. +### Catalog Observability -## Future work - -The following feature list doesn't represent a commitment to develop, and the -list order doesn't reflect any priority or importance, but these features are on -the maintainers' radar, with clear interest expressed by the community. - -- **Ease of onboarding:** A faster (with less development) and easier setup of - Backstage and the most relevant/adopted plugins. -- **Composable Homepage 1.0:** Driving this to 1.0 by adding some composable - components. -- **Creator experience:** Provide a better Backstage user experience through - visual guidelines and templates, especially navigation across plug-ins and - portal functionalities. -- **[GraphQL](https://graphql.org/) support:** Introduce the ability to query - Backstage backend services with a standard query language for APIs. -- **Telemetry:** To efficiently generate logging and metrics in such a way that - adopters can get insights so that Backstage can be monitored and improved. +The goal of this initiative is to provide better tools for debugging catalog +ingestion issues and to more generally reduce friction for setting up and +maintaining the software catalog. ## How to influence the roadmap From bab063c8d1143ce09a7f9465034f58d134a43c23 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 14 May 2024 17:26:01 +0200 Subject: [PATCH 06/14] Apply suggestions from code review Co-authored-by: Phil Kuang Signed-off-by: Patrik Oldsberg --- docs/overview/roadmap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/overview/roadmap.md b/docs/overview/roadmap.md index f53f79f431..1a41eedd63 100644 --- a/docs/overview/roadmap.md +++ b/docs/overview/roadmap.md @@ -22,7 +22,7 @@ This includes ensuring that all documentation is up to date, and includes API reviews and refactoring efforts to ensure that what is released is both stable and evolvable. You can follow along with this work in the [meta issue](https://github.com/backstage/backstage/issues/24493). -As part of this initiative, there will also be and exploration on how to +As part of this initiative, there will also be an exploration on how to simplify extension of backend services. It is not currently possible to augment backend services through declarative integration, they are instead only customizable through complete replacement. This also limits the ability to @@ -61,7 +61,7 @@ foundation for an evolvable plugin metadata system. Material-UI v4 is still the officially supported version of MUI in Backstage. While we have heard that adopters have had success using MUI 5, this is still an untested path with known bugs. The goal of this initiative is to iron out any -remaining issues of gaps, and then provide a green light for migration to MUI 5. +remaining issues or gaps, and then provide a green light for migration to MUI 5. ### Configuration Improvements From e74c615bd610b99931921bf4d94c6cbb4d97a4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 15 May 2024 13:04:54 +0200 Subject: [PATCH 07/14] remove last remnants of react-text-truncate from test mocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../Group/MembersList/MembersListCard.test.tsx | 13 ------------- .../Cards/OwnershipCard/OwnershipCard.test.tsx | 13 ------------- .../TechDocsSearchResultListItem.test.tsx | 5 ----- 3 files changed, 31 deletions(-) diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx index 06ec3b0ebd..793ffe274b 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx @@ -36,19 +36,6 @@ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { Observable } from '@backstage/types'; -// Mock needed because jsdom doesn't correctly implement box-sizing -// https://github.com/ShinyChang/React-Text-Truncate/issues/70 -// https://stackoverflow.com/questions/71916701/how-to-mock-a-react-function-component-that-takes-a-ref-prop -jest.mock('react-text-truncate', () => { - const { forwardRef } = jest.requireActual('react'); - return { - __esModule: true, - default: forwardRef((props: any, ref: any) => ( -
{props.text}
- )), - }; -}); - const mockedStarredEntitiesApi: Partial = { starredEntitie$: () => { return { diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 72a912e16e..f2b949f768 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -120,19 +120,6 @@ const getEntitiesMock = ( } as GetEntitiesResponse); }; -// Mock needed because jsdom doesn't correctly implement box-sizing -// https://github.com/ShinyChang/React-Text-Truncate/issues/70 -// https://stackoverflow.com/questions/71916701/how-to-mock-a-react-function-component-that-takes-a-ref-prop -jest.mock('react-text-truncate', () => { - const { forwardRef } = jest.requireActual('react'); - return { - __esModule: true, - default: forwardRef((props: any, ref: any) => ( -
{props.text}
- )), - }; -}); - describe('OwnershipCard', () => { const groupEntity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', diff --git a/plugins/techdocs/src/search/components/TechDocsSearchResultListItem.test.tsx b/plugins/techdocs/src/search/components/TechDocsSearchResultListItem.test.tsx index 15444fca9e..9ba88a78ff 100644 --- a/plugins/techdocs/src/search/components/TechDocsSearchResultListItem.test.tsx +++ b/plugins/techdocs/src/search/components/TechDocsSearchResultListItem.test.tsx @@ -18,11 +18,6 @@ import React from 'react'; import { TechDocsSearchResultListItem } from './TechDocsSearchResultListItem'; import { renderInTestApp } from '@backstage/test-utils'; -// Using canvas to render text.. -jest.mock('react-text-truncate', () => { - return ({ text }: { text: string }) => {text}; -}); - const validResult = { location: 'https://backstage.io/docs', title: 'Documentation', From 6e9f4d480c1a3db3fd8fdc13d3cb1e6877fd93a8 Mon Sep 17 00:00:00 2001 From: Jaeeun Lee Date: Wed, 15 May 2024 17:03:20 -0400 Subject: [PATCH 08/14] Update setup-opentelemetry.md Signed-off-by: Jaeeun Lee --- docs/tutorials/setup-opentelemetry.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/setup-opentelemetry.md b/docs/tutorials/setup-opentelemetry.md index c49eef26a2..30dde79db8 100644 --- a/docs/tutorials/setup-opentelemetry.md +++ b/docs/tutorials/setup-opentelemetry.md @@ -65,13 +65,19 @@ You can now start your Backstage instance as usual, using `yarn dev`. ## Production Setup -In your `Dockerfile` add the `--require` flag which points to the `instrumentation.js` file +In your `Dockerfile`, copy `instrumentation.js` file into the root of the working directory. + +```Dockerfile +COPY --chown=${NOT_ROOT_USER}:${NOT_ROOT_USER} packages/backend/src/instrumentation.js ./ +``` + +And then add the `--require` flag that points to the file to the CMD array. ```Dockerfile // highlight-remove-next-line CMD ["node", "packages/backend", "--config", "app-config.yaml"] // highlight-add-next-line -CMD ["node", "--require", "./src/instrumentation.js", "packages/backend", "--config", "app-config.yaml"] +CMD ["node", "--require", "./instrumentation.js", "packages/backend", "--config", "app-config.yaml"] ``` If you need to disable/configure some OpenTelemetry feature there are lots of [environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/) which you can tweak. From f6e2d96a1cdcb3e969f44f9e32292b164e0cbd80 Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Wed, 15 May 2024 23:46:54 -0400 Subject: [PATCH 09/14] chore: Fix typo in error logging Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- .../src/manager/plugin-manager.test.ts | 24 +++++++++---------- .../src/manager/plugin-manager.ts | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts index 487729687f..340991b11f 100644 --- a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.test.ts @@ -59,7 +59,7 @@ describe('backend-dynamic-feature-service', () => { name: string; packageManifest: ScannedPluginManifest; indexFile?: { - retativePath: string[]; + relativePath: string[]; content: string; }; expectedLogs?(location: URL): { @@ -83,7 +83,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'exports.dynamicPluginInstaller={ kind: "new", install: () => [] }', }, @@ -127,7 +127,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: `const alpha = { $$type: '@backstage/BackendFeature' }; exports["default"] = alpha;`, }, expectedLogs(location) { @@ -170,7 +170,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: `const alpha = () => { return { $$type: '@backstage/BackendFeature' } }; alpha.$$type = '@backstage/BackendFeatureFactory'; exports["default"] = alpha;`, @@ -215,7 +215,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'exports.dynamicPluginInstaller={ kind: "new", install: () => [] }', }, @@ -262,7 +262,7 @@ describe('backend-dynamic-feature-service', () => { return { errors: [ { - message: `an error occured while loading dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, + message: `an error occurred while loading dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, meta: { name: 'Error', message: expect.stringContaining( @@ -305,7 +305,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: '', }, expectedLogs(location) { @@ -332,7 +332,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'exports.dynamicPluginInstaller={ something: "else", unexpectedMethod() {} }', }, @@ -360,14 +360,14 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'strange text with syntax error', }, expectedLogs(location) { return { errors: [ { - message: `an error occured while loading dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, + message: `an error occurred while loading dynamic backend plugin 'backend-dynamic-plugin-test' from '${location}'`, meta: { message: expect.stringContaining('Unexpected identifier'), name: 'SyntaxError', @@ -391,7 +391,7 @@ describe('backend-dynamic-feature-service', () => { main: 'dist/index.cjs.js', }, indexFile: { - retativePath: ['dist', 'index.cjs.js'], + relativePath: ['dist', 'index.cjs.js'], content: 'exports.dynamicPluginInstaller={ kind: "legacy", scaffolder: (env)=>[] }', }, @@ -458,7 +458,7 @@ describe('backend-dynamic-feature-service', () => { mockedFiles[ path.join( url.fileURLToPath(plugin.location), - ...tc.indexFile.retativePath, + ...tc.indexFile.relativePath, ) ] = tc.indexFile.content; } diff --git a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts index edc3e20f72..95b0c6592c 100644 --- a/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts +++ b/packages/backend-dynamic-feature-service/src/manager/plugin-manager.ts @@ -188,7 +188,7 @@ export class DynamicPluginManager implements DynamicPluginProvider { }; } catch (error) { this.logger.error( - `an error occured while loading dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`, + `an error occurred while loading dynamic backend plugin '${plugin.manifest.name}' from '${plugin.location}'`, error, ); return undefined; From 9478fbb64c4b894c31629df42155356b68eefdcf Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Wed, 15 May 2024 23:55:55 -0400 Subject: [PATCH 10/14] chore(catalog-model): Remove useless test The metadata field is required by schema, and this was testing if it was optional, passing only because it was misspelled. Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- .../src/entity/policies/FieldFormatEntityPolicy.test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/catalog-model/src/entity/policies/FieldFormatEntityPolicy.test.ts b/packages/catalog-model/src/entity/policies/FieldFormatEntityPolicy.test.ts index f32236e977..9fe041a839 100644 --- a/packages/catalog-model/src/entity/policies/FieldFormatEntityPolicy.test.ts +++ b/packages/catalog-model/src/entity/policies/FieldFormatEntityPolicy.test.ts @@ -65,11 +65,6 @@ describe('FieldFormatEntityPolicy', () => { await expect(policy.enforce(data)).rejects.toThrow(/kind/); }); - it('handles missing metadata gracefully', async () => { - delete data.medatata; - await expect(policy.enforce(data)).resolves.toBe(data); - }); - it('handles missing spec gracefully', async () => { delete data.spec; await expect(policy.enforce(data)).resolves.toBe(data); From d2c36c08964e920d1d1a317be66cc1cc2ed13e2b Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Wed, 15 May 2024 23:56:18 -0400 Subject: [PATCH 11/14] chore: Fix minor typo in a test Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- packages/backend-common/src/reading/FetchUrlReader.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-common/src/reading/FetchUrlReader.test.ts b/packages/backend-common/src/reading/FetchUrlReader.test.ts index 7b5e4ebc05..8a0b24002e 100644 --- a/packages/backend-common/src/reading/FetchUrlReader.test.ts +++ b/packages/backend-common/src/reading/FetchUrlReader.test.ts @@ -77,7 +77,7 @@ describe('FetchUrlReader', () => { worker.use( rest.get('https://backstage.io/error', (_req, res, ctx) => { - return res(ctx.status(500), ctx.body('An internal error occured')); + return res(ctx.status(500), ctx.body('An internal error occurred')); }), ); }); From cfa0afb3074687dbe736558dc28726dc486a71a4 Mon Sep 17 00:00:00 2001 From: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> Date: Wed, 15 May 2024 23:56:48 -0400 Subject: [PATCH 12/14] chore(backend-common): Fix typo in error message Signed-off-by: Adam Harvey <33203301+adamdmharvey@users.noreply.github.com> --- packages/backend-common/src/database/connectors/mysql.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-common/src/database/connectors/mysql.ts b/packages/backend-common/src/database/connectors/mysql.ts index 1ad8b0b3be..2fb3545047 100644 --- a/packages/backend-common/src/database/connectors/mysql.ts +++ b/packages/backend-common/src/database/connectors/mysql.ts @@ -304,7 +304,7 @@ export class MysqlConnector implements Connector { const pluginDivisionMode = this.getPluginDivisionModeConfig(); if (pluginDivisionMode !== 'database') { throw new Error( - `The MySQL driver does not suppoert plugin division mode '${pluginDivisionMode}'`, + `The MySQL driver does not support plugin division mode '${pluginDivisionMode}'`, ); } From 582099e4d1754bb7f7625f19ffa1380abc7e7966 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Date: Thu, 16 May 2024 09:56:47 +0530 Subject: [PATCH 13/14] Updated the deployment documents Signed-off-by: Aditya Kumar --- docs/deployment/docker.md | 20 ++++++++++++++------ docs/deployment/index.md | 8 ++++++-- docs/deployment/k8s.md | 12 ++++++++---- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index 9ec5460a88..f16a2ad13e 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -141,8 +141,12 @@ browser at `http://localhost:7007` ## Multi-stage Build -> NOTE: The `.dockerignore` is different in this setup, read on for more -> details. +:::note Note + +The `.dockerignore` is different in this setup, read on for more +details. + +::: This section describes how to set up a multi-stage Docker build that builds the entire project within Docker. This is typically slower than a host build, but is @@ -293,10 +297,14 @@ browser at `http://localhost:7007` ## Separate Frontend -> NOTE: This is an optional step, and you will lose out on the features of the -> `@backstage/plugin-app-backend` plugin. Most notably the frontend configuration -> will no longer be injected by the backend, you will instead need to use the -> correct configuration when building the frontend bundle. +:::note Note + +This is an optional step, and you will lose out on the features of the +`@backstage/plugin-app-backend` plugin. Most notably the frontend configuration +will no longer be injected by the backend, you will instead need to use the +correct configuration when building the frontend bundle. + +::: It is sometimes desirable to serve the frontend separately from the backend, either from a separate image or for example a static file serving provider. The diff --git a/docs/deployment/index.md b/docs/deployment/index.md index da2c29ba23..0524e71db8 100644 --- a/docs/deployment/index.md +++ b/docs/deployment/index.md @@ -13,8 +13,12 @@ This documentation shows common examples that may be useful when deploying Backstage for the first time, or for those without established deployment practices. -> Note: The _easiest_ way to explore Backstage is to visit the -> [live demo site](https://demo.backstage.io). +:::note Note + +The _easiest_ way to explore Backstage is to visit the +[live demo site](https://demo.backstage.io). + +::: At Spotify, we deploy software generally by: diff --git a/docs/deployment/k8s.md b/docs/deployment/k8s.md index 00bf7464e3..46ba273e14 100644 --- a/docs/deployment/k8s.md +++ b/docs/deployment/k8s.md @@ -107,10 +107,14 @@ $ echo -n "backstage" | base64 YmFja3N0YWdl ``` -> Note: Secrets are base64-encoded, but not encrypted. Be sure to enable -> [Encryption at Rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) -> for the cluster. For storing secrets in Git, consider -> [SealedSecrets or other solutions](https://learnk8s.io/kubernetes-secrets-in-git). +:::note Note + +Secrets are base64-encoded, but not encrypted. Be sure to enable +[Encryption at Rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) +for the cluster. For storing secrets in Git, consider +[SealedSecrets or other solutions](https://learnk8s.io/kubernetes-secrets-in-git). + +::: The secrets can now be applied to the Kubernetes cluster: From 702fa7d17cc34c8d5c414529e21f7c1b775d9316 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 16 May 2024 11:32:58 +0200 Subject: [PATCH 14/14] theme: fix v5 prefix tree shaking Signed-off-by: Patrik Oldsberg --- .changeset/lovely-hats-pay.md | 5 ++++ .../theme/src/unified/MuiClassNameSetup.ts | 24 ------------------- .../src/unified/UnifiedThemeProvider.test.tsx | 1 - .../src/unified/UnifiedThemeProvider.tsx | 15 +++++++++--- 4 files changed, 17 insertions(+), 28 deletions(-) create mode 100644 .changeset/lovely-hats-pay.md delete mode 100644 packages/theme/src/unified/MuiClassNameSetup.ts diff --git a/.changeset/lovely-hats-pay.md b/.changeset/lovely-hats-pay.md new file mode 100644 index 0000000000..117f50e5db --- /dev/null +++ b/.changeset/lovely-hats-pay.md @@ -0,0 +1,5 @@ +--- +'@backstage/theme': patch +--- + +Internal refactor to fix an issue where the MUI 5 `v5-` class prefixing gets removed by tree shaking. diff --git a/packages/theme/src/unified/MuiClassNameSetup.ts b/packages/theme/src/unified/MuiClassNameSetup.ts deleted file mode 100644 index 5d7e0b26fe..0000000000 --- a/packages/theme/src/unified/MuiClassNameSetup.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className'; - -/** - * This API is introduced in @mui/material (v5.0.5) as a replacement of deprecated createGenerateClassName & only affects v5 Material UI components from `@mui/*` - */ -ClassNameGenerator.configure(componentName => { - return `v5-${componentName}`; -}); diff --git a/packages/theme/src/unified/UnifiedThemeProvider.test.tsx b/packages/theme/src/unified/UnifiedThemeProvider.test.tsx index da4af5abab..98fc73505d 100644 --- a/packages/theme/src/unified/UnifiedThemeProvider.test.tsx +++ b/packages/theme/src/unified/UnifiedThemeProvider.test.tsx @@ -22,7 +22,6 @@ import { useTheme as useV5Theme } from '@mui/material/styles'; import { makeStyles as makeV5Styles } from '@mui/styles'; import { render, screen } from '@testing-library/react'; import React from 'react'; -import './MuiClassNameSetup'; import { UnifiedThemeProvider } from './UnifiedThemeProvider'; import { themes } from './themes'; diff --git a/packages/theme/src/unified/UnifiedThemeProvider.tsx b/packages/theme/src/unified/UnifiedThemeProvider.tsx index 35abbe57d8..465a4dda24 100644 --- a/packages/theme/src/unified/UnifiedThemeProvider.tsx +++ b/packages/theme/src/unified/UnifiedThemeProvider.tsx @@ -15,7 +15,6 @@ */ import React, { ReactNode } from 'react'; -import './MuiClassNameSetup'; import { CssBaseline } from '@material-ui/core'; import { ThemeProvider, @@ -29,6 +28,7 @@ import { Theme as Mui5Theme, } from '@mui/material/styles'; import { UnifiedTheme } from './types'; +import { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className'; /** * Props for {@link UnifiedThemeProvider}. @@ -41,10 +41,19 @@ export interface UnifiedThemeProviderProps { noCssBaseline?: boolean; } +/** + * This API is introduced in @mui/material (v5.0.5) as a replacement of deprecated createGenerateClassName & only affects v5 Material UI components from `@mui/*`. + * + * This call needs to be in the same module as the `UnifiedThemeProvider` to ensure that it doesn't get removed by tree shaking + */ +ClassNameGenerator.configure(componentName => { + return `v5-${componentName}`; +}); + // Background at https://mui.com/x/migration/migration-data-grid-v4/#using-mui-core-v4-with-v5 // Rather than disabling globals and custom seed, we instead only set a production prefix that -// won't collide with Material UI 5 styles. We've already got a separate class name generator for v5 set -// up in MuiClassNameSetup.ts, so only the production JSS needs deduplication. +// won't collide with Material UI 5 styles. We've already got the separate class name generator +// for v5 set up in just above, so only the production JSS needs deduplication. const generateV4ClassName = createGenerateClassName({ productionPrefix: 'jss4-', });