Merge branch 'master' into yarn-workspaces-foreach

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-03-19 14:23:25 +01:00
548 changed files with 5985 additions and 4454 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-vault-backend': patch
---
Removed lock inside recursion to avoid deadlocks
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-import': patch
---
Added the `no-top-level-material-ui-4-imports` ESLint rule to aid with the migration to Material UI v5
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-shortcuts': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `shortcuts` plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-bitrise': patch
---
Added the `no-top-level-material-ui-4-import` ESLint rule to the Bitrise plugin to aid with the migration to Material UI v5.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Added a `EXPERIMENTAL_LAZY_COMPILATION` flag, which enables the experimental Webpack lazy compilation option in frontend builds.
+16
View File
@@ -0,0 +1,16 @@
---
'@backstage/plugin-code-coverage-backend': patch
'@backstage/plugin-notifications-backend': patch
'@backstage/plugin-azure-devops-backend': patch
'@backstage/plugin-azure-sites-backend': patch
'@backstage/plugin-permission-backend': patch
'@backstage/plugin-airbrake-backend': patch
'@backstage/plugin-devtools-backend': patch
'@backstage/plugin-linguist-backend': patch
'@backstage/plugin-periskop-backend': patch
'@backstage/plugin-signals-backend': patch
'@backstage/plugin-nomad-backend': patch
'@backstage/plugin-vault-backend': patch
---
Allow unauthenticated access to health check endpoint.
+10
View File
@@ -0,0 +1,10 @@
---
'@backstage/plugin-notifications-backend': patch
'@backstage/plugin-signals-backend': minor
'@backstage/plugin-signals-node': minor
---
**BREAKING** Type definition added to signal recipients
Update to use `{type: 'broadcast'}` instead `null` and `{type: 'user', entityRef: ''}`
instead string entity references
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-rollbar': patch
---
Adjusted MUI imports for better tree shaking.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-react': patch
---
Create a generic React component for refreshing user cookie.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-sonarqube': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `sonarqube` plugin to migrate the Material UI imports.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-scaffolder-node': patch
---
Fixing the lost of the initial state after a task recovery.
+9
View File
@@ -0,0 +1,9 @@
---
'@techdocs/cli': patch
'@backstage/create-app': patch
'@backstage/repo-tools': patch
'@backstage/codemods': patch
'@backstage/cli': patch
---
Removed the `ts-node` dev dependency.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Migrated the backend of the create app template to use the new backend system. For information on how to migrate your existing backend, see the [migration guide](https://backstage.io/docs/backend-system/building-backends/migrating).
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-gcalendar': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `gcalendar` plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-user-settings': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `user-settings` plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-badges': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` to aid with the migration to Material UI v5.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend-module-guest-provider': patch
---
Fix issue for issuing a token when `guest` user does not exist in catalog
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-unprocessed-entities': patch
---
Added the `no-top-level-material-ui-4-imports` ESLint rule to aid with the migration to Material UI v5
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-codescene': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the Codescene plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': patch
---
Added the `no-top-level-material-ui-4-imports` ESLint rule to aid with the migration to Material UI v5
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cost-insights': patch
---
Added the `no-top-level-material-ui-4-imports` ESLint rule to aid with the migration to Material UI v5
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-stackstorm': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `stackstorm` plugin to migrate the Material UI imports.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-notifications-backend': minor
'@backstage/plugin-notifications': minor
---
Notifications-backend URL query parameters changed from `sort/sortOrder` to `orderField` and `created_after` to `createdAfter` to unify with other plugins.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-insights-backend-module-jsonfc': patch
---
Fixes an invalid line in the schema that was causing AJV to complain.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-xcmetrics': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `xcmetrics` plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-playlist': patch
---
Adjusted MUI imports for better tree shaking.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Updated dependency `react-idle-timer` to `5.7.2`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-api-docs': patch
---
Updated dependency `graphiql` to `3.1.1`.
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/cli': patch
---
Updated dependency `@spotify/prettier-config` to `^15.0.0`.
Updated dependency `@spotify/eslint-config-base` to `^15.0.0`.
Updated dependency `@spotify/eslint-config-react` to `^15.0.0`.
Updated dependency `@spotify/eslint-config-typescript` to `^15.0.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-lighthouse': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the Lighthouse plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-sentry': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `sentry` plugin to migrate the Material UI imports.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-techdocs': patch
'@backstage/plugin-techdocs-addons-test-utils': patch
---
Use the new generic refresh user cookie provider.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-adr': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the ADR plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-vault': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `vault` plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-home': patch
---
Added the `no-top-level-material-ui-4-imports` ESLint rule to aid with the migration to Material UI v5
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': minor
---
The backend devlopment server transpilation has been replaced with a simplified solution based on SWC, which is already the transpiler used for tests. This fixed an issue where never versions of the `tsx` dependency had a new contract for signalling dependencies, breaking watch mode. This change fixed file watches as well as enables sourcemaps.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-org': patch
---
Add `relationsType` argument to `MembersListCard`.
This can be used to display an aggregated user list for groups by default.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-code-climate': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the Code-Climate plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` to aid with the migration to Material UI v5.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-insights': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `tech-insights` plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend-module-atlassian-provider': patch
---
Addressed OAuth flow issue in Atlassian auth module
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-stack-overflow': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `stack-overflow` plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-github': patch
---
Add location analyzer when installing the module
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Added the `no-top-level-material-ui-4-imports` ESLint rule to aid with the migration to Material UI v5
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-splunk-on-call': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `splunk-on-call` plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-app-api': patch
---
The experimental feature discovery service exported at the `/alpha` sub-path will no longer attempt to load packages that are not Backstage backend packages.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-signals': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the `signals` plugin to migrate the Material UI imports.
+28
View File
@@ -0,0 +1,28 @@
---
'@backstage/plugin-catalog-backend-module-unprocessed': minor
'@backstage/plugin-catalog-unprocessed-entities': minor
'@backstage/plugin-catalog-unprocessed-entities-common': patch
---
**BREAKING**- the `@backstage/plugin-catalog-backend-module-unprocessed` constructor is now private, and have been moved to using the static `.create` method instead which now requires a `PermissionService` and `DiscoveryService`.
If you're using this module in the old backend system you'll need to migrate to using the `.create` method and pass in the new required parameters in `packages/backend/src/plugins/catalog.ts`.
No changes should be required if you're using the new backend system.
```diff
- const unprocessed = new UnprocessedEntitiesModule(
- await env.database.getClient(),
- router,
- );
+ const unprocessed = UnprocessedEntitiesModule.create({
+ database: await env.database.getClient(),
+ router,
+ permissions: env.permissions,
+ discovery: env.discovery,
+ });
unprocessed.registerRoutes();
```
Adds the ability to delete an unprocessed entity from the `refresh_state` table. This change requires enabling permissions for your Backstage instance.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-graph': patch
---
Added the `no-top-level-material-ui-4-imports` ESLint rule to aid with the migration to Material UI v5
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-kafka': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the Kafka plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-jenkins': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the Jenkins plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-code-coverage': patch
---
Added ESLint rule `no-top-level-material-ui-4-imports` in the Code-Coverage plugin to migrate the Material UI imports.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-fossa': patch
---
Adjusted MUI imports for better tree shaking
+3 -3
View File
@@ -51,17 +51,17 @@ jobs:
working-directory: ./example-app
- name: Login to GitHub Container Registry
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
uses: docker/setup-buildx-action@2b51285047da1547ffb1b2203d8be4c0af6b1f20 # v3.2.0
- name: Build and push
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
with:
context: './example-app'
file: ./example-app/packages/backend/Dockerfile
+1 -1
View File
@@ -66,6 +66,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
uses: github/codeql-action/upload-sarif@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
uses: github/codeql-action/upload-sarif@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
with:
sarif_file: results.sarif
@@ -43,6 +43,6 @@ jobs:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
NODE_OPTIONS: --max-old-space-size=7168
- name: Update Github issues
run: yarn ts-node scripts/snyk-github-issue-sync.ts
run: ./scripts/snyk-github-issue-sync.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+1 -1
View File
@@ -58,6 +58,6 @@ jobs:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
NODE_OPTIONS: --max-old-space-size=7168
- name: Upload Snyk report
uses: github/codeql-action/upload-sarif@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
uses: github/codeql-action/upload-sarif@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
with:
sarif_file: snyk.sarif
+2 -2
View File
@@ -53,7 +53,7 @@ jobs:
yarn workspace example-backend build
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
uses: docker/setup-buildx-action@2b51285047da1547ffb1b2203d8be4c0af6b1f20 # v3.2.0
- name: Generate UUID image name
id: uuid
@@ -67,7 +67,7 @@ jobs:
tags: type=raw,value=60d
- name: Build Image
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
with:
context: .
file: packages/backend/Dockerfile
+3 -3
View File
@@ -55,7 +55,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
uses: github/codeql-action/init@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -66,7 +66,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
uses: github/codeql-action/autobuild@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -80,4 +80,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5
uses: github/codeql-action/analyze@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7
+1 -1
View File
@@ -51,7 +51,7 @@ jobs:
- run: yarn build-storybook
- uses: chromaui/action@fd0e276c344bab4dc69a023fdf89ffb9b79b3b31 # v11
- uses: chromaui/action@306092d42c0743800aadf544ee263cbc56598b1b # v11
with:
token: ${{ secrets.GITHUB_TOKEN }}
# projectToken intentionally shared to allow collaborators to run Chromatic on forks
+26 -6
View File
@@ -95,6 +95,7 @@ The role of the notifications plugin is to manage the lifecycle of notifications
The notification backend stores notification using the [database service](https://backstage.io/docs/backend-system/core-services/index#database). In particular it needs to store the following information for each notification:
- ID
- Recipients
- Read date
- Saved status
- Creation date
@@ -105,7 +106,6 @@ The notification backend stores notification using the [database service](https:
- Origin
- Link (optional)
- Additional links (optional)
- Recipients
- Severity (optional, default normal)
- Topic (optional)
- Scope (optional)
@@ -153,7 +153,9 @@ The `notification-backend` does not provide any new permissions, since creating
The `notification-backend` shall provide necessary parameters for paging and filtering notifications from the frontend.
The notification frontend plugin provides a UI for viewing notifications, which in the initial implementation can be as simple as needed. The only requirement is that a user is able to view recent notifications and distinguish between read and unread notifications. A notification as marked as read once it has been interacted with. The frontend plugin also subscribes to the notifications signal channel and alerts the user when a new notification is received.
The notification frontend plugin provides a UI for viewing notifications, which in the initial implementation can be as simple as needed. The only requirement is that a user is able to view recent notifications and distinguish between read and unread notifications. The frontend plugin also subscribes to the notifications signal channel and alerts the user when a new notification is received.
Both the individual and broadcasted messages are rendered together in a single list. There will be a filter choosing of of those types or `all`.
### Architecture Overview
@@ -165,11 +167,12 @@ The components that are presented with dashed lines are not directly part of thi
Let's walk through the process of sending of a notification to a user:
1. A backend plugin that wants to send a notification to a user uses the `NotificationService`, which in turn makes a POST request to the notification backend. The request contains a filter to select the target users, as well as the notification payload.
1. A backend plugin that wants to send a notification to a user uses the `NotificationService`, which in turn makes a POST request to the notification backend. The request contains either a filter to select the target users or type `broadcast`, as well as the notification payload.
1b. As the notification backend handles the request it could optionally invoke a series of notification processors. These processors can be used to transform the notification payload, send the notification through other channels, and decide whether the regular notification flow should continue or not. This step is not in scope for this proposal.
2. The notification backend stores the received notification in its database. At this point the notification is available from the notification backend's read API.
3. The notification backend published an event to the event bus on the `'signal'` topic. This event payload contains the signaling channel, in this case `'notifications'`, as well as the target user ID and the notification ID, but not the notification payload.
4. Each instance of the signal backend plugin subscribes to the `'signal'` topic and receives the event.
5. Each signal backend instance has a set of push channels set up to online users. The incoming event is filtered based on the target user ID and the signaling is pushed through all connections with a matching user ID.
@@ -214,6 +217,7 @@ export type NotificationPayload = {
export type Notification = {
id: string;
userRef: string;
broadcasted: boolean;
created: Date;
saved?: Date;
read?: Date;
@@ -232,12 +236,29 @@ interface NotificationService {
}
```
Each notification is always routed to individual users unless it's a broadcast. The `notification-backend` will figure out which users will receive a notification based on the `recipients` parameter, resolving it to the concrete list of users at the time of sending the notification.
Each notification contains a human readable `title`, `origin` and optionally `link` for additional details. The `created`, `id`, `read` and `saved` properties are handled by the backend based and cannot be passed during the notification creation.
Calling `sendNotification` should never throw an error so that it doesn't block the current processing. Notifications should be considered as second-level citizens that are not critical if not delivered.
Each notification is always routed to individual users unless its type is `broadcast`.
##### Individual user notifications
The `notification-backend` will figure out which users will receive a notification based on the `recipients` parameter, resolving it to the concrete list of users at the time of sending the notification.
##### Broadcasted notifications
Broadcasted messages are stored in a separate database table for performance reasons and simplicity of queries.
There is only one record per message.
To maintain flags, there will be another table with 1:N relation. This table will contain `user`, `read`, `saved` and `updated` columns, linked via message ID foreign-key.
This table of flags is not prefilled on a broadcast message creation but a record is added when there is an updating POST by a particular user.
When notifications are queried, two (main) database queries are issued - for both the individual and broadcasted messages.
Their results are merged into a single response but setting the `broadcasted` flag based on source.
If an individual message is queried (via GET `/notifications/:id`), both the individual and broadcasted tables are searched. The first result found is used for the response.
#### `SignalService`
```ts
@@ -269,7 +290,6 @@ Example signal payload for a new notification:
#### Future considerations and BEP TODO
- Broadcast messages are to be saved to a separate table for performance reasons
- OpenAPI tooling is taken into use for the notification router and client
- Allow using dynamic values in notification payload, for example entity references `{{ user:default/john.doe }}` should be rendered by the frontend with `EntityRefLink` component. Defining the dynamic data values should be done before implementation.
- Add configurable automatic clean-up of old notifications to save storage space
@@ -4,8 +4,8 @@ status: provisional
authors:
- 'bnechyporenko@bol.com'
- 'benjaminl@spotify.com'
owners:
- @backstage/scaffolder-maintainers
owners:
- '@backstage/scaffolder-maintainers'
project-areas:
- scaffolder
creation-date: 2024-01-31
@@ -0,0 +1,84 @@
---
title: Scaffolder Action Rollback
status: provisional
authors:
- 'bnechyporenko@bol.com'
- 'benjaminl@spotify.com'
owners:
- '@backstage/scaffolder-maintainers'
project-areas:
- scaffolder
creation-date: 2024-03-13
---
# BEP: <!-- Your short, descriptive title -->
[**Discussion Issue**](https://github.com/backstage/backstage/issues/NNNNN)
- [Summary](#summary)
- [Motivation](#motivation)
- [Goals](#goals)
- [Non-Goals](#non-goals)
- [Proposal](#proposal)
- [Design Details](#design-details)
- [Release Plan](#release-plan)
- [Dependencies](#dependencies)
- [Alternatives](#alternatives)
## Summary
Introducing the rollback to scaffolder actions provides the mean to come back to the initial state.
## Motivation
The aim is to help to mitigate the issue of manual clean up the partially created resources.
### Goals
- We will extend action's API to be able to run rollback for failed tasks
- Rollback will be optional
### Non-Goals
We will not cover all built-in actions with a rollback functionality
## Proposal
Rollback is going to be performed:
- when user manually decide to perform this action.
- task has to be recovered and TaskRecoverStrategy set to 'rollback'
## Design Details
We are going to introduce an extra function in action API which will look like:
```typescript
const createPublishGitHubAction = createTemplateAction({
id: 'publish:github',
async handler() {},
async rollback() {},
});
```
## Release Plan
<!--
This section should describe the rollout process for any new features. It must take our version policies into account and plan for a phased rollout if this change affects any existing stable APIs.
If there is any particular feedback to be gathered during the rollout, this should be described here as well.
-->
## Dependencies
<!--
List any dependencies that this work has on other BEPs or features.
-->
## Alternatives
<!--
What other approaches did you consider, and why did you rule them out? These do
not need to be as detailed as the proposal, but should include enough
information to express the idea and why it was not acceptable.
-->
+2
View File
@@ -40,6 +40,7 @@ choice below.
| [Google Analytics 4][ga4] | Yes ✅ |
| [New Relic Browser][newrelic-browser] | Community ✅ |
| [Matomo][matomo] | Community ✅ |
| [Quantum Metric][qm] | Community ✅ |
To suggest an integration, please [open an issue][add-tool] for the analytics
tool your organization uses. Or jump to [Writing Integrations][int-howto] to
@@ -48,6 +49,7 @@ learn how to contribute the integration yourself!
[ga]: https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md
[ga4]: https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga4/README.md
[newrelic-browser]: https://github.com/backstage/backstage/blob/master/plugins/analytics-module-newrelic-browser/README.md
[qm]: https://github.com/quantummetric/analytics-module-qm/blob/main/README.md
[matomo]: https://github.com/janus-idp/backstage-plugins/blob/main/plugins/analytics-module-matomo/README.md
[add-tool]: https://github.com/backstage/backstage/issues/new?assignees=&labels=plugin&template=plugin_template.md&title=%5BAnalytics+Module%5D+THE+ANALYTICS+TOOL+TO+INTEGRATE
[int-howto]: #writing-integrations
@@ -0,0 +1,10 @@
---
title: 'Analytics Module: Quantum Metric'
author: Quantum Metric
authorUrl: https://github.com/quantummetric
category: Monitoring
description: Track usage of your Backstage instance using Quantum Metric.
documentation: https://github.com/quantummetric/analytics-module-qm/blob/main/README.md
iconUrl: /img/qm-icon.png
npmPackageName: '@quantum-metric/plugin-analytics-module-qm'
addedDate: '2024-03-15'
+1 -1
View File
@@ -19,7 +19,7 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.1.1",
"@spotify/prettier-config": "^14.0.0",
"@spotify/prettier-config": "^15.0.0",
"@tsconfig/docusaurus": "^2.0.0",
"@types/luxon": "^3.0.0",
"@types/webpack-env": "^1.18.0",
+5
View File
@@ -81,6 +81,11 @@ const Community = () => {
url: 'https://roadie.io/',
logo: 'img/partner-logo-roadie.png',
},
{
name: 'solo.io',
url: 'https://www.solo.io/spotlight/',
logo: 'img/partner-logo-solo.png',
},
{
name: 'ThoughtWorks',
url: 'https://www.thoughtworks.com/about-us/partnerships/technology/backstage-by-spotify',
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

+54 -54
View File
@@ -2532,12 +2532,12 @@ __metadata:
languageName: node
linkType: hard
"@spotify/prettier-config@npm:^14.0.0":
version: 14.1.3
resolution: "@spotify/prettier-config@npm:14.1.3"
"@spotify/prettier-config@npm:^15.0.0":
version: 15.0.0
resolution: "@spotify/prettier-config@npm:15.0.0"
peerDependencies:
prettier: 2.x
checksum: 0c64ec0de9be5ae24a9b2a8f5c3af6c02306a47f54fffbd014852b00245fc939f3131eeeac8e906dfbb6aa86a5c0213b7f35623badad072979068f8cd69c316f
checksum: aa5ec5739427f9acdb9d62ae6c04f04a344898567239f7ee45c75c6205ebdffbc61747ea8de6e83baf0bc3785359967de4b7097a8723c4b4063ff57dc5cb6c44
languageName: node
linkType: hard
@@ -2697,90 +2697,90 @@ __metadata:
languageName: node
linkType: hard
"@swc/core-darwin-arm64@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-darwin-arm64@npm:1.4.2"
"@swc/core-darwin-arm64@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-darwin-arm64@npm:1.4.8"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@swc/core-darwin-x64@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-darwin-x64@npm:1.4.2"
"@swc/core-darwin-x64@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-darwin-x64@npm:1.4.8"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@swc/core-linux-arm-gnueabihf@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.4.2"
"@swc/core-linux-arm-gnueabihf@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.4.8"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
"@swc/core-linux-arm64-gnu@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-linux-arm64-gnu@npm:1.4.2"
"@swc/core-linux-arm64-gnu@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-linux-arm64-gnu@npm:1.4.8"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@swc/core-linux-arm64-musl@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-linux-arm64-musl@npm:1.4.2"
"@swc/core-linux-arm64-musl@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-linux-arm64-musl@npm:1.4.8"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@swc/core-linux-x64-gnu@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-linux-x64-gnu@npm:1.4.2"
"@swc/core-linux-x64-gnu@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-linux-x64-gnu@npm:1.4.8"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@swc/core-linux-x64-musl@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-linux-x64-musl@npm:1.4.2"
"@swc/core-linux-x64-musl@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-linux-x64-musl@npm:1.4.8"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@swc/core-win32-arm64-msvc@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-win32-arm64-msvc@npm:1.4.2"
"@swc/core-win32-arm64-msvc@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-win32-arm64-msvc@npm:1.4.8"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@swc/core-win32-ia32-msvc@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-win32-ia32-msvc@npm:1.4.2"
"@swc/core-win32-ia32-msvc@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-win32-ia32-msvc@npm:1.4.8"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"@swc/core-win32-x64-msvc@npm:1.4.2":
version: 1.4.2
resolution: "@swc/core-win32-x64-msvc@npm:1.4.2"
"@swc/core-win32-x64-msvc@npm:1.4.8":
version: 1.4.8
resolution: "@swc/core-win32-x64-msvc@npm:1.4.8"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@swc/core@npm:^1.3.46":
version: 1.4.2
resolution: "@swc/core@npm:1.4.2"
version: 1.4.8
resolution: "@swc/core@npm:1.4.8"
dependencies:
"@swc/core-darwin-arm64": 1.4.2
"@swc/core-darwin-x64": 1.4.2
"@swc/core-linux-arm-gnueabihf": 1.4.2
"@swc/core-linux-arm64-gnu": 1.4.2
"@swc/core-linux-arm64-musl": 1.4.2
"@swc/core-linux-x64-gnu": 1.4.2
"@swc/core-linux-x64-musl": 1.4.2
"@swc/core-win32-arm64-msvc": 1.4.2
"@swc/core-win32-ia32-msvc": 1.4.2
"@swc/core-win32-x64-msvc": 1.4.2
"@swc/core-darwin-arm64": 1.4.8
"@swc/core-darwin-x64": 1.4.8
"@swc/core-linux-arm-gnueabihf": 1.4.8
"@swc/core-linux-arm64-gnu": 1.4.8
"@swc/core-linux-arm64-musl": 1.4.8
"@swc/core-linux-x64-gnu": 1.4.8
"@swc/core-linux-x64-musl": 1.4.8
"@swc/core-win32-arm64-msvc": 1.4.8
"@swc/core-win32-ia32-msvc": 1.4.8
"@swc/core-win32-x64-msvc": 1.4.8
"@swc/counter": ^0.1.2
"@swc/types": ^0.1.5
peerDependencies:
@@ -2809,7 +2809,7 @@ __metadata:
peerDependenciesMeta:
"@swc/helpers":
optional: true
checksum: b17afda692b2627d3a82e589f1b29cef31bdee626a2dd997d78312dcbfc6eb701850fbab22e85f02b1261da39f0b0afb6a236c6065f6d0d7478cff939ca5a888
checksum: 3284e64fe72896d1be8637f7fdcbba575d86e02da056a8c5208c93877250bfb1922fc5194281926650d5694e2434b7906efc0db8925769a4558f5fbd93028fd6
languageName: node
linkType: hard
@@ -3855,7 +3855,7 @@ __metadata:
"@docusaurus/module-type-aliases": ^3.1.1
"@docusaurus/plugin-client-redirects": ^3.1.1
"@docusaurus/preset-classic": ^3.1.1
"@spotify/prettier-config": ^14.0.0
"@spotify/prettier-config": ^15.0.0
"@swc/core": ^1.3.46
"@tsconfig/docusaurus": ^2.0.0
"@types/luxon": ^3.0.0
@@ -5770,12 +5770,12 @@ __metadata:
linkType: hard
"follow-redirects@npm:^1.0.0":
version: 1.15.4
resolution: "follow-redirects@npm:1.15.4"
version: 1.15.6
resolution: "follow-redirects@npm:1.15.6"
peerDependenciesMeta:
debug:
optional: true
checksum: e178d1deff8b23d5d24ec3f7a94cde6e47d74d0dc649c35fc9857041267c12ec5d44650a0c5597ef83056ada9ea6ca0c30e7c4f97dbf07d035086be9e6a5b7b6
checksum: a62c378dfc8c00f60b9c80cab158ba54e99ba0239a5dd7c81245e5a5b39d10f0c35e249c3379eae719ff0285fff88c365dd446fab19dee771f1d76252df1bbf5
languageName: node
linkType: hard
@@ -10392,15 +10392,15 @@ __metadata:
linkType: hard
"sass@npm:^1.57.1":
version: 1.71.1
resolution: "sass@npm:1.71.1"
version: 1.72.0
resolution: "sass@npm:1.72.0"
dependencies:
chokidar: ">=3.0.0 <4.0.0"
immutable: ^4.0.0
source-map-js: ">=0.6.2 <2.0.0"
bin:
sass: sass.js
checksum: 19c4939d3042eb9459d462bbd27b1f576fa18034e23c87ca0005b87effdee431c16503b5a785edcdcde1a76dfb804716d9ad42c85a78968ac3825d515e45cb53
checksum: f420079c7d51660b7256ee52463c1499ede36f7fd5c8ef50c687451777ad641509001454dea45244073cedd7c00e7a3bc1c362e55206ac6686171b994edb41e4
languageName: node
linkType: hard
+2 -3
View File
@@ -104,8 +104,8 @@
"@changesets/cli": "^2.14.0",
"@octokit/rest": "^19.0.3",
"@playwright/test": "^1.32.3",
"@spotify/eslint-plugin": "^14.1.3",
"@spotify/prettier-config": "^14.0.0",
"@spotify/eslint-plugin": "^15.0.0",
"@spotify/prettier-config": "^15.0.0",
"@techdocs/cli": "workspace:*",
"@types/node": "^18.17.8",
"@types/webpack": "^5.28.0",
@@ -127,7 +127,6 @@
"shx": "^0.3.2",
"sloc": "^0.3.1",
"sort-package-json": "^2.8.0",
"ts-node": "^10.4.0",
"typescript": "~5.1.0"
},
"packageManager": "yarn@3.8.1",
+25 -25
View File
@@ -1,17 +1,39 @@
{
"name": "example-app",
"version": "0.2.93-next.2",
"private": true,
"backstage": {
"role": "frontend"
},
"bundled": true,
"private": true,
"homepage": "https://backstage.io",
"repository": {
"type": "git",
"url": "https://github.com/backstage/backstage",
"directory": "packages/app"
},
"license": "Apache-2.0",
"files": [
"dist"
],
"scripts": {
"build": "backstage-cli package build",
"clean": "backstage-cli package clean",
"lint": "backstage-cli package lint",
"start": "cross-env EXPERIMENTAL_LAZY_COMPILATION=1 backstage-cli package start",
"test": "backstage-cli package test"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"dependencies": {
"@backstage/app-defaults": "workspace:^",
"@backstage/catalog-model": "workspace:^",
@@ -121,27 +143,5 @@
"@types/zen-observable": "^0.8.0",
"cross-env": "^7.0.0"
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"clean": "backstage-cli package clean",
"test": "backstage-cli package test",
"lint": "backstage-cli package lint"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"files": [
"dist"
],
"license": "Apache-2.0"
"bundled": true
}
@@ -29,6 +29,13 @@ import { resolve as resolvePath, dirname } from 'path';
import fs from 'fs-extra';
import { BackstagePackageJson } from '@backstage/cli-node';
const DETECTED_PACKAGE_ROLES = [
'node-library',
'backend',
'backend-plugin',
'backend-plugin-module',
];
/** @internal */
async function findClosestPackageDir(
searchDir: string,
@@ -106,8 +113,11 @@ class PackageDiscoveryService implements FeatureDiscoveryService {
const depPkg = require(require.resolve(`${name}/package.json`, {
paths: [packageDir],
})) as BackstagePackageJson;
if (!depPkg?.backstage || depPkg?.backstage?.role === 'cli') {
continue; // Not a backstage package, ignore
if (
!depPkg?.backstage?.role ||
!DETECTED_PACKAGE_ROLES.includes(depPkg.backstage.role)
) {
continue; // Not a backstage backend package, ignore
}
const exportedModulePaths = [
@@ -246,7 +246,7 @@ describe('ZipArchiveResponse', () => {
const filesPromise = res.files();
await expect(filesPromise).rejects.toThrow(
'invalid comment length. expected: 55. found: 0',
/Invalid comment length. Expected: 55. Found: 0/,
);
});
+7 -3
View File
@@ -37,11 +37,15 @@ export default async function createPlugin(
const { processingEngine, router } = await builder.build();
const unprocessed = new UnprocessedEntitiesModule(
await env.database.getClient(),
const unprocessed = UnprocessedEntitiesModule.create({
database: await env.database.getClient(),
router,
);
permissions: env.permissions,
discovery: env.discovery,
});
unprocessed.registerRoutes();
await processingEngine.start();
return router;
}
+1 -9
View File
@@ -24,14 +24,6 @@ const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src'));
if (!isLocal || process.env.BACKSTAGE_E2E_CLI_TEST) {
require('..');
} else {
require('ts-node').register({
transpileOnly: true,
/* eslint-disable-next-line no-restricted-syntax */
project: path.resolve(__dirname, '../../../tsconfig.json'),
compilerOptions: {
module: 'CommonJS',
},
});
require('@backstage/cli/config/nodeTransform.cjs');
require('../src');
}
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { transformSync } = require('@swc/core');
const { addHook } = require('pirates');
addHook(
(code, filename) => {
const transformed = transformSync(code, {
filename,
sourceMaps: 'inline',
module: { type: 'commonjs' },
jsc: {
target: 'es2022',
parser: {
syntax: 'typescript',
},
},
});
process.send?.({ type: 'watch', path: filename });
return transformed.code;
},
{ extensions: ['.ts', '.cts'], ignoreNodeModules: true },
);
addHook(
(code, filename) => {
process.send?.({ type: 'watch', path: filename });
return code;
},
{ extensions: ['.js', '.cjs'], ignoreNodeModules: true },
);
+3 -3
View File
@@ -1,6 +1,6 @@
# Knip report
## Unused dependencies (27)
## Unused dependencies (28)
| Name | Location | Severity |
| :------------------------------- | :----------- | :------- |
@@ -25,6 +25,7 @@
| @swc/core | package.json | error |
| @swc/jest | package.json | error |
| esbuild | package.json | error |
| pirates | package.json | error |
| postcss | package.json | error |
| process | package.json | error |
| sucrase | package.json | error |
@@ -32,7 +33,7 @@
| glob | package.json | error |
| util | package.json | error |
## Unused devDependencies (12)
## Unused devDependencies (11)
| Name | Location | Severity |
| :-------------------------------------- | :----------- | :------- |
@@ -46,7 +47,6 @@
| @types/svgo | package.json | error |
| @types/ejs | package.json | error |
| nodemon | package.json | error |
| ts-node | package.json | error |
| del | package.json | error |
## Referenced optional peerDependencies (4)
+8 -5
View File
@@ -50,9 +50,9 @@
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-yaml": "^4.0.0",
"@spotify/eslint-config-base": "^14.0.0",
"@spotify/eslint-config-react": "^14.0.0",
"@spotify/eslint-config-typescript": "^14.0.0",
"@spotify/eslint-config-base": "^15.0.0",
"@spotify/eslint-config-react": "^15.0.0",
"@spotify/eslint-config-typescript": "^15.0.0",
"@sucrase/webpack-loader": "^2.0.0",
"@svgr/core": "6.5.x",
"@svgr/plugin-jsx": "6.5.x",
@@ -114,6 +114,7 @@
"ora": "^5.3.0",
"p-limit": "^3.1.0",
"p-queue": "^6.6.2",
"pirates": "^4.0.6",
"postcss": "^8.1.0",
"process": "^0.11.10",
"react-dev-utils": "^12.0.0-next.60",
@@ -131,7 +132,6 @@
"swc-loader": "^0.2.3",
"tar": "^6.1.12",
"terser-webpack-plugin": "^5.1.3",
"tsx": "^4.0.0",
"util": "^0.12.3",
"webpack": "^5.70.0",
"webpack-dev-server": "^4.7.3",
@@ -168,10 +168,13 @@
"@types/tar": "^6.1.1",
"@types/terser-webpack-plugin": "^5.0.4",
"@types/yarnpkg__lockfile": "^1.1.4",
"@vitejs/plugin-react": "^4.0.4",
"del": "^7.0.0",
"msw": "^1.0.0",
"nodemon": "^3.0.1",
"ts-node": "^10.0.0"
"vite": "^4.4.9",
"vite-plugin-html": "^3.2.0",
"vite-plugin-node-polyfills": "^0.21.0"
},
"peerDependencies": {
"@vitejs/plugin-react": "^4.0.4",
+3
View File
@@ -224,6 +224,9 @@ export async function createConfig(
}
: {}),
},
experiments: {
lazyCompilation: yn(process.env.EXPERIMENTAL_LAZY_COMPILATION),
},
plugins,
...(withCache
? {
@@ -22,22 +22,16 @@ import { ctrlc } from 'ctrlc-windows';
import { IpcServer } from './IpcServer';
import { ServerDataStore } from './ServerDataStore';
import debounce from 'lodash/debounce';
import { fileURLToPath, pathToFileURL } from 'url';
import { fileURLToPath } from 'url';
import { isAbsolute as isAbsolutePath } from 'path';
import { paths } from '../paths';
import spawn from 'cross-spawn';
const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(Number);
const supportsModuleLoaderRegister =
nodeMajor > 20 ||
(nodeMajor === 20 && nodeMinor >= 6) ||
(nodeMajor === 18 && nodeMinor >= 19);
const loaderArgs = [
'--enable-source-maps',
'--require',
require.resolve('tsx/preflight'),
supportsModuleLoaderRegister ? '--import' : '--loader',
pathToFileURL(require.resolve('tsx')).toString(), // Windows prefers a URL here
require.resolve('@backstage/cli/config/nodeTransform.cjs'),
// TODO: Support modules, although there's currently no way to load them since import() is transpiled tp require()
];
export async function startBackendExperimental(options: BackendServeOptions) {
@@ -51,11 +45,21 @@ export async function startBackendExperimental(options: BackendServeOptions) {
ServerDataStore.bind(server);
let exiting = false;
let firstStart = true;
let child: ChildProcess | undefined;
let watcher: FSWatcher | undefined = undefined;
let shutdownPromise: Promise<void> | undefined = undefined;
const watchedPaths = new Set<string>();
const restart = debounce(async () => {
if (firstStart) {
firstStart = false;
} else {
console.log();
console.log('Change detected, restarting the development server...');
console.log();
}
// If a re-trigger happens during an existing shutdown, we just ignore it
if (shutdownPromise) {
return;
@@ -115,14 +119,18 @@ export async function startBackendExperimental(options: BackendServeOptions) {
// This captures messages sent by @esbuild-kit/cjs-loader
child.on('message', (data: { type?: string } | null) => {
if (typeof data === 'object' && data?.type === 'dependency') {
if (!watcher) {
return;
}
if (typeof data === 'object' && data?.type === 'watch') {
let path = (data as { path: string }).path;
if (path.startsWith('file:')) {
path = fileURLToPath(path);
}
if (isAbsolutePath(path)) {
watcher?.add(path);
if (isAbsolutePath(path) && !watchedPaths.has(path)) {
watchedPaths.add(path);
watcher.add(path);
}
}
});
@@ -130,7 +138,7 @@ export async function startBackendExperimental(options: BackendServeOptions) {
restart();
watcher = watch([], {
watcher = watch(['./package.json'], {
cwd: process.cwd(),
ignoreInitial: true,
ignorePermissionErrors: true,
+1 -9
View File
@@ -24,14 +24,6 @@ const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src'));
if (!isLocal) {
require('..');
} else {
require('ts-node').register({
transpileOnly: true,
/* eslint-disable-next-line no-restricted-syntax */
project: path.resolve(__dirname, '../../../tsconfig.json'),
compilerOptions: {
module: 'CommonJS',
},
});
require('@backstage/cli/config/nodeTransform.cjs');
require('../src');
}
-6
View File
@@ -1,8 +1,2 @@
# Knip report
## Unused devDependencies (1)
| Name | Location | Severity |
| :------ | :----------- | :------- |
| ts-node | package.json | error |
+1 -2
View File
@@ -52,7 +52,6 @@
"devDependencies": {
"@backstage/cli": "workspace:^",
"@types/jscodeshift": "^0.11.0",
"@types/node": "^18.17.8",
"ts-node": "^10.0.0"
"@types/node": "^18.17.8"
}
}
+1 -1
View File
@@ -78,7 +78,7 @@
"rc-progress": "3.5.1",
"react-helmet": "6.1.0",
"react-hook-form": "^7.12.2",
"react-idle-timer": "5.6.2",
"react-idle-timer": "5.7.2",
"react-markdown": "^8.0.0",
"react-sparklines": "^1.7.0",
"react-syntax-highlighter": "^15.4.5",
+1 -10
View File
@@ -24,15 +24,6 @@ const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src'));
if (!isLocal || process.env.BACKSTAGE_E2E_CLI_TEST) {
require('..');
} else {
// Only used for development, so should be a devDependency
// eslint-disable-next-line @backstage/no-undeclared-imports
require('ts-node').register({
transpileOnly: true,
project: path.resolve(__dirname, '../../../tsconfig.json'),
compilerOptions: {
module: 'CommonJS',
},
});
require('@backstage/cli/config/nodeTransform.cjs');
require('../src');
}
+1 -2
View File
@@ -1,10 +1,9 @@
# Knip report
## Unused devDependencies (3)
## Unused devDependencies (2)
| Name | Location | Severity |
| :-------------------- | :----------- | :------- |
| @types/command-exists | package.json | error |
| nodemon | package.json | error |
| ts-node | package.json | error |
+1 -2
View File
@@ -52,8 +52,7 @@
"@types/node": "^18.17.8",
"@types/recursive-readdir": "^2.2.0",
"msw": "^1.0.0",
"nodemon": "^3.0.1",
"ts-node": "^10.0.0"
"nodemon": "^3.0.1"
},
"nodemonConfig": {
"watch": "./src",
@@ -51,6 +51,7 @@ jest.mock('./versions', () => ({
root: '1.2.3',
'@backstage/cli': '1.0.0',
'@backstage/backend-common': '1.0.0',
'@backstage/backend-defaults': '1.0.0',
'@backstage/backend-tasks': '1.0.0',
'@backstage/catalog-model': '1.0.0',
'@backstage/catalog-client': '1.0.0',
@@ -58,10 +59,14 @@ jest.mock('./versions', () => ({
'@backstage/plugin-app-backend': '1.0.0',
'@backstage/plugin-auth-backend': '1.0.0',
'@backstage/plugin-auth-node': '1.0.0',
'@backstage/plugin-auth-backend-module-github-provider': '1.0.0',
'@backstage/plugin-auth-backend-module-guest-provider': '1.0.0',
'@backstage/plugin-catalog-backend': '1.0.0',
'@backstage/plugin-catalog-backend-module-scaffolder-entity-model': '1.0.0',
'@backstage/plugin-permission-common': '1.0.0',
'@backstage/plugin-permission-node': '1.0.0',
'@backstage/plugin-permission-backend': '1.0.0',
'@backstage/plugin-permission-backend-module-allow-all-policy': '1.0.0',
'@backstage/plugin-proxy-backend': '1.0.0',
'@backstage/plugin-scaffolder-backend': '1.0.0',
'@backstage/plugin-search-backend': '1.0.0',
+13
View File
@@ -33,6 +33,7 @@ import { version as root } from '../../../../package.json';
import { version as appDefaults } from '../../../app-defaults/package.json';
import { version as backendCommon } from '../../../backend-common/package.json';
import { version as backendDefaults } from '../../../backend-defaults/package.json';
import { version as backendTasks } from '../../../backend-tasks/package.json';
import { version as catalogClient } from '../../../catalog-client/package.json';
import { version as catalogModel } from '../../../catalog-model/package.json';
@@ -50,6 +51,8 @@ import { version as theme } from '../../../theme/package.json';
import { version as pluginApiDocs } from '../../../../plugins/api-docs/package.json';
import { version as pluginAppBackend } from '../../../../plugins/app-backend/package.json';
import { version as pluginAuthBackend } from '../../../../plugins/auth-backend/package.json';
import { version as pluginAuthBackendModuleGithubProvider } from '../../../../plugins/auth-backend-module-github-provider/package.json';
import { version as pluginAuthBackendModuleGuestProvider } from '../../../../plugins/auth-backend-module-guest-provider/package.json';
import { version as pluginAuthNode } from '../../../../plugins/auth-node/package.json';
import { version as pluginCatalog } from '../../../../plugins/catalog/package.json';
import { version as pluginCatalogCommon } from '../../../../plugins/catalog-common/package.json';
@@ -62,6 +65,8 @@ import { version as pluginExplore } from '../../../../plugins/explore/package.js
import { version as pluginGithubActions } from '../../../../plugins/github-actions/package.json';
import { version as pluginLighthouse } from '../../../../plugins/lighthouse/package.json';
import { version as pluginOrg } from '../../../../plugins/org/package.json';
import { version as pluginPermissionBackend } from '../../../../plugins/permission-backend/package.json';
import { version as pluginPermissionBackendModulePolicyAllowAll } from '../../../../plugins/permission-backend-module-policy-allow-all/package.json';
import { version as pluginPermissionCommon } from '../../../../plugins/permission-common/package.json';
import { version as pluginPermissionReact } from '../../../../plugins/permission-react/package.json';
import { version as pluginPermissionNode } from '../../../../plugins/permission-node/package.json';
@@ -87,6 +92,7 @@ export const packageVersions = {
root,
'@backstage/app-defaults': appDefaults,
'@backstage/backend-common': backendCommon,
'@backstage/backend-defaults': backendDefaults,
'@backstage/backend-tasks': backendTasks,
'@backstage/catalog-client': catalogClient,
'@backstage/catalog-model': catalogModel,
@@ -101,6 +107,10 @@ export const packageVersions = {
'@backstage/plugin-api-docs': pluginApiDocs,
'@backstage/plugin-app-backend': pluginAppBackend,
'@backstage/plugin-auth-backend': pluginAuthBackend,
'@backstage/plugin-auth-backend-module-github-provider':
pluginAuthBackendModuleGithubProvider,
'@backstage/plugin-auth-backend-module-guest-provider':
pluginAuthBackendModuleGuestProvider,
'@backstage/plugin-auth-node': pluginAuthNode,
'@backstage/plugin-catalog': pluginCatalog,
'@backstage/plugin-catalog-common': pluginCatalogCommon,
@@ -114,6 +124,9 @@ export const packageVersions = {
'@backstage/plugin-github-actions': pluginGithubActions,
'@backstage/plugin-lighthouse': pluginLighthouse,
'@backstage/plugin-org': pluginOrg,
'@backstage/plugin-permission-backend': pluginPermissionBackend,
'@backstage/plugin-permission-backend-module-allow-all-policy':
pluginPermissionBackendModulePolicyAllowAll,
'@backstage/plugin-permission-common': pluginPermissionCommon,
'@backstage/plugin-permission-node': pluginPermissionNode,
'@backstage/plugin-permission-react': pluginPermissionReact,
@@ -28,6 +28,10 @@ backend:
# ca: # if you have a CA file and want to verify it you can uncomment this section
# $file: <file-path>/ca/server.crt
auth:
providers:
guest: null
catalog:
# Overrides the default list locations from app-config.yaml as these contain example data.
# See https://backstage.io/docs/features/software-catalog/#adding-components-to-the-catalog for more details
@@ -64,7 +64,9 @@ techdocs:
auth:
# see https://backstage.io/docs/auth/ to learn about auth providers
providers: {}
providers:
# See https://backstage.io/docs/auth/guest/provider
guest: {}
scaffolder:
# see https://backstage.io/docs/features/software-templates/configuration for software template options
@@ -19,5 +19,9 @@ import { test, expect } from '@playwright/test';
test('App should render the welcome page', async ({ page }) => {
await page.goto('/');
const enterButton = page.getByRole('button', { name: 'Enter' });
await expect(enterButton).toBeVisible();
await enterButton.click();
await expect(page.getByText('My Company Catalog')).toBeVisible();
});
@@ -27,7 +27,11 @@ import { entityPage } from './components/catalog/EntityPage';
import { searchPage } from './components/search/SearchPage';
import { Root } from './components/Root';
import { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components';
import {
AlertDisplay,
OAuthRequestDialog,
SignInPage,
} from '@backstage/core-components';
import { createApp } from '@backstage/app-defaults';
import { AppRouter, FlatRoutes } from '@backstage/core-app-api';
import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
@@ -53,6 +57,9 @@ const app = createApp({
catalogIndex: catalogPlugin.routes.catalogIndex,
});
},
components: {
SignInPage: props => <SignInPage {...props} auto providers={['guest']} />,
},
});
const routes = (
@@ -17,30 +17,30 @@
},
"dependencies": {
"@backstage/backend-common": "^{{version '@backstage/backend-common'}}",
"@backstage/backend-defaults": "^{{version '@backstage/backend-defaults'}}",
"@backstage/backend-tasks": "^{{version '@backstage/backend-tasks'}}",
"@backstage/catalog-client": "^{{version '@backstage/catalog-client'}}",
"@backstage/catalog-model": "^{{version '@backstage/catalog-model'}}",
"@backstage/config": "^{{version '@backstage/config'}}",
"@backstage/plugin-app-backend": "^{{version '@backstage/plugin-app-backend'}}",
"@backstage/plugin-auth-backend": "^{{version '@backstage/plugin-auth-backend'}}",
"@backstage/plugin-auth-backend-module-github-provider": "^{{version '@backstage/plugin-auth-backend-module-github-provider'}}",
"@backstage/plugin-auth-backend-module-guest-provider": "^{{version '@backstage/plugin-auth-backend-module-guest-provider'}}",
"@backstage/plugin-auth-node": "^{{version '@backstage/plugin-auth-node'}}",
"@backstage/plugin-catalog-backend": "^{{version '@backstage/plugin-catalog-backend'}}",
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "^{{version '@backstage/plugin-catalog-backend-module-scaffolder-entity-model'}}",
"@backstage/plugin-permission-backend": "^{{version '@backstage/plugin-permission-backend'}}",
"@backstage/plugin-permission-backend-module-allow-all-policy": "^{{version '@backstage/plugin-permission-backend-module-allow-all-policy'}}",
"@backstage/plugin-permission-common": "^{{version '@backstage/plugin-permission-common'}}",
"@backstage/plugin-permission-node": "^{{version '@backstage/plugin-permission-node'}}",
"@backstage/plugin-proxy-backend": "^{{version '@backstage/plugin-proxy-backend'}}",
"@backstage/plugin-scaffolder-backend": "^{{version '@backstage/plugin-scaffolder-backend'}}",
"@backstage/plugin-search-backend": "^{{version '@backstage/plugin-search-backend'}}",
"@backstage/plugin-search-backend-module-catalog": "^{{version '@backstage/plugin-search-backend-module-catalog'}}",
"@backstage/plugin-search-backend-module-pg": "^{{version '@backstage/plugin-search-backend-module-pg'}}",
"@backstage/plugin-search-backend-module-techdocs": "^{{version '@backstage/plugin-search-backend-module-techdocs'}}",
"@backstage/plugin-search-backend-node": "^{{version '@backstage/plugin-search-backend-node'}}",
"@backstage/plugin-techdocs-backend": "^{{version '@backstage/plugin-techdocs-backend'}}",
"app": "link:../app",
"better-sqlite3": "^9.0.0",
"dockerode": "^3.3.1",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"node-gyp": "^9.0.0",
"pg": "^8.11.3",
"winston": "^3.2.1"
@@ -6,110 +6,36 @@
* Happy hacking!
*/
import Router from 'express-promise-router';
import {
createServiceBuilder,
loadBackendConfig,
getRootLogger,
useHotMemoize,
notFoundHandler,
CacheManager,
DatabaseManager,
HostDiscovery,
UrlReaders,
ServerTokenManager,
} from '@backstage/backend-common';
import { TaskScheduler } from '@backstage/backend-tasks';
import { Config } from '@backstage/config';
import app from './plugins/app';
import auth from './plugins/auth';
import catalog from './plugins/catalog';
import scaffolder from './plugins/scaffolder';
import proxy from './plugins/proxy';
import techdocs from './plugins/techdocs';
import search from './plugins/search';
import { PluginEnvironment } from './types';
import { ServerPermissionClient } from '@backstage/plugin-permission-node';
import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
import { createBackend } from '@backstage/backend-defaults';
function makeCreateEnv(config: Config) {
const root = getRootLogger();
const reader = UrlReaders.default({ logger: root, config });
const discovery = HostDiscovery.fromConfig(config);
const cacheManager = CacheManager.fromConfig(config);
const databaseManager = DatabaseManager.fromConfig(config, { logger: root });
const tokenManager = ServerTokenManager.noop();
const taskScheduler = TaskScheduler.fromConfig(config, { databaseManager });
const backend = createBackend();
const identity = DefaultIdentityClient.create({
discovery,
});
const permissions = ServerPermissionClient.fromConfig(config, {
discovery,
tokenManager,
});
backend.add(import('@backstage/plugin-app-backend/alpha'));
backend.add(import('@backstage/plugin-proxy-backend/alpha'));
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
backend.add(import('@backstage/plugin-techdocs-backend/alpha'));
root.info(`Created UrlReader ${reader}`);
// auth plugin
backend.add(import('@backstage/plugin-auth-backend'));
// See https://backstage.io/docs/backend-system/building-backends/migrating#the-auth-plugin
backend.add(import('@backstage/plugin-auth-backend-module-guest-provider'));
// See https://github.com/backstage/backstage/blob/master/docs/auth/guest/provider.md
return (plugin: string): PluginEnvironment => {
const logger = root.child({ type: 'plugin', plugin });
const database = databaseManager.forPlugin(plugin);
const cache = cacheManager.forPlugin(plugin);
const scheduler = taskScheduler.forPlugin(plugin);
return {
logger,
database,
cache,
config,
reader,
discovery,
tokenManager,
scheduler,
permissions,
identity,
};
};
}
// catalog plugin
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
async function main() {
const config = await loadBackendConfig({
argv: process.argv,
logger: getRootLogger(),
});
const createEnv = makeCreateEnv(config);
// permission plugin
backend.add(import('@backstage/plugin-permission-backend/alpha'));
backend.add(
import('@backstage/plugin-permission-backend-module-allow-all-policy'),
);
const catalogEnv = useHotMemoize(module, () => createEnv('catalog'));
const scaffolderEnv = useHotMemoize(module, () => createEnv('scaffolder'));
const authEnv = useHotMemoize(module, () => createEnv('auth'));
const proxyEnv = useHotMemoize(module, () => createEnv('proxy'));
const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs'));
const searchEnv = useHotMemoize(module, () => createEnv('search'));
const appEnv = useHotMemoize(module, () => createEnv('app'));
// search plugin
backend.add(import('@backstage/plugin-search-backend/alpha'));
backend.add(import('@backstage/plugin-search-backend-module-catalog/alpha'));
backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha'));
const apiRouter = Router();
apiRouter.use('/catalog', await catalog(catalogEnv));
apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv));
apiRouter.use('/auth', await auth(authEnv));
apiRouter.use('/techdocs', await techdocs(techdocsEnv));
apiRouter.use('/proxy', await proxy(proxyEnv));
apiRouter.use('/search', await search(searchEnv));
// Add backends ABOVE this line; this 404 handler is the catch-all fallback
apiRouter.use(notFoundHandler());
const service = createServiceBuilder(module)
.loadConfig(config)
.addRouter('/api', apiRouter)
.addRouter('', await app(appEnv));
await service.start().catch(err => {
console.log(err);
process.exit(1);
});
}
module.hot?.accept();
main().catch(error => {
console.error('Backend failed to start up', error);
process.exit(1);
});
backend.start();
@@ -1,14 +0,0 @@
import { createRouter } from '@backstage/plugin-app-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
return await createRouter({
logger: env.logger,
config: env.config,
database: env.database,
appPackageName: 'app',
});
}
@@ -1,54 +0,0 @@
import {
createRouter,
providers,
defaultAuthProviderFactories,
} from '@backstage/plugin-auth-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
return await createRouter({
logger: env.logger,
config: env.config,
database: env.database,
discovery: env.discovery,
tokenManager: env.tokenManager,
providerFactories: {
...defaultAuthProviderFactories,
// This replaces the default GitHub auth provider with a customized one.
// The `signIn` option enables sign-in for this provider, using the
// identity resolution logic that's provided in the `resolver` callback.
//
// This particular resolver makes all users share a single "guest" identity.
// It should only be used for testing and trying out Backstage.
//
// If you want to use a production ready resolver you can switch to
// the one that is commented out below, it looks up a user entity in the
// catalog using the GitHub username of the authenticated user.
// That resolver requires you to have user entities populated in the catalog,
// for example using https://backstage.io/docs/integrations/github/org
//
// There are other resolvers to choose from, and you can also create
// your own, see the auth documentation for more details:
//
// https://backstage.io/docs/auth/identity-resolver
github: providers.github.create({
signIn: {
resolver(_, ctx) {
const userRef = 'user:default/guest'; // Must be a full entity reference
return ctx.issueToken({
claims: {
sub: userRef, // The user's own identity
ent: [userRef], // A list of identities that the user claims ownership through
},
});
},
// resolver: providers.github.resolvers.usernameMatchingUserEntityName(),
},
}),
},
});
}
@@ -1,14 +0,0 @@
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
import { ScaffolderEntitiesProcessor } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const builder = await CatalogBuilder.create(env);
builder.addProcessor(new ScaffolderEntitiesProcessor());
const { processingEngine, router } = await builder.build();
await processingEngine.start();
return router;
}
@@ -1,13 +0,0 @@
import { createRouter } from '@backstage/plugin-proxy-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
return await createRouter({
logger: env.logger,
config: env.config,
discovery: env.discovery,
});
}

Some files were not shown because too many files have changed in this diff Show More