Merge remote-tracking branch 'origin/master' into task-action-idempotency
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Added check for the `repository` field in the `repo fix` command.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/repo-tools': patch
|
||||
---
|
||||
|
||||
Introduced `knip` to the `knip-reports` command, which generates a `knip-report.md` file for your packages with dependency warnings, if any.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli-node': patch
|
||||
---
|
||||
|
||||
Added `repository` field to `BackstagePackageJson` type.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
---
|
||||
|
||||
adds a x-goog-api-client header to existing API requests in this plugin to clearly identify API requests from this GKE plugin. headers are formatted as follows where `libVersion` represents the current dotted version number of the Backstage GKE plugin and `libName` represent the current Google API used at backstage.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-playlist': patch
|
||||
---
|
||||
|
||||
Conditionally render playlist description only when it's non-empty
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
---
|
||||
|
||||
Organized imports in plugin.ts
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-scaffolder-entity-model': patch
|
||||
'@backstage/plugin-search-backend-module-stack-overflow-collator': patch
|
||||
'@backstage/plugin-permission-backend-module-allow-all-policy': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch
|
||||
'@backstage/plugin-auth-backend-module-oauth2-proxy-provider': patch
|
||||
'@backstage/plugin-auth-backend-module-vmware-cloud-provider': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch
|
||||
'@backstage/plugin-catalog-backend-module-backstage-openapi': patch
|
||||
'@backstage/plugin-auth-backend-module-atlassian-provider': patch
|
||||
'@backstage/plugin-auth-backend-module-microsoft-provider': patch
|
||||
'@backstage/plugin-auth-backend-module-pinniped-provider': patch
|
||||
'@backstage/plugin-auth-backend-module-github-provider': patch
|
||||
'@backstage/plugin-auth-backend-module-gitlab-provider': patch
|
||||
'@backstage/plugin-auth-backend-module-oauth2-provider': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-bitbucket': patch
|
||||
'@backstage/plugin-analytics-module-newrelic-browser': patch
|
||||
'@backstage/plugin-auth-backend-module-oidc-provider': patch
|
||||
'@backstage/plugin-auth-backend-module-okta-provider': patch
|
||||
'@backstage/plugin-catalog-backend-module-github-org': patch
|
||||
'@backstage/backend-dynamic-feature-service': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-gerrit': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-github': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-azure': patch
|
||||
'@backstage/plugin-notifications-backend': patch
|
||||
'@backstage/frontend-test-utils': patch
|
||||
'@backstage/plugin-analytics-module-ga4': patch
|
||||
'@backstage/plugin-notifications-common': patch
|
||||
'@backstage/plugin-notifications-node': patch
|
||||
'@backstage/frontend-app-api': patch
|
||||
'@backstage/plugin-kubernetes-react': patch
|
||||
'@backstage/e2e-test-utils': patch
|
||||
'@backstage/plugin-kubernetes-node': patch
|
||||
'@backstage/plugin-signals-backend': patch
|
||||
'@backstage/plugin-app-visualizer': patch
|
||||
'@backstage/plugin-notifications': patch
|
||||
'@backstage/plugin-signals-react': patch
|
||||
'@backstage/plugin-vault-backend': patch
|
||||
'@backstage/plugin-signals-node': patch
|
||||
'@backstage/plugin-vault-node': patch
|
||||
'@backstage/plugin-app-node': patch
|
||||
'@backstage/plugin-opencost': patch
|
||||
'@backstage/plugin-signals': patch
|
||||
---
|
||||
|
||||
Added or fixed the `repository` field in `package.json`.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
'@backstage/plugin-entity-validation': patch
|
||||
'@backstage/plugin-gcp-projects': patch
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-techdocs-module-addons-contrib': patch
|
||||
---
|
||||
|
||||
Updated dependency `@react-hookz/web` to `^24.0.0`.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@backstage/plugin-home-react': patch
|
||||
'@backstage/plugin-home': patch
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Updated dependency `@rjsf/utils` to `5.17.0`.
|
||||
Updated dependency `@rjsf/core` to `5.17.0`.
|
||||
Updated dependency `@rjsf/material-ui` to `5.17.0`.
|
||||
Updated dependency `@rjsf/validator-ajv8` to `5.17.0`.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-gcalendar': patch
|
||||
'@backstage/plugin-microsoft-calendar': patch
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Updated dependency `dompurify` to `^3.0.0`.
|
||||
Updated dependency `@types/dompurify` to `^3.0.0`.
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
'@backstage/plugin-catalog-node': patch
|
||||
---
|
||||
|
||||
Add support for `onProcessingError` handler at the catalog plugin (new backend system).
|
||||
|
||||
You can use `setOnProcessingErrorHandler` at the `catalogProcessingExtensionPoint`
|
||||
as replacement for
|
||||
|
||||
```ts
|
||||
catalogBuilder.subscribe({
|
||||
onProcessingError: hander,
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
---
|
||||
|
||||
On LocalKubectlProxyClusterLocator, when resolving localhost, IPv4 address is placed before IPv6 address, ignoring the order from the DNS resolver. This change is necessary since by default kubectl proxy listen on IPv4
|
||||
@@ -86,3 +86,5 @@ yarn.lock @backstage/maintainers @backst
|
||||
/plugins/tech-insights-backend-module-jsonfc @backstage/maintainers @backstage/reviewers @xantier
|
||||
/plugins/tech-insights-tech-insights-common @backstage/maintainers @backstage/reviewers @xantier
|
||||
/plugins/tech-insights-tech-insights-node @backstage/maintainers @backstage/reviewers @xantier
|
||||
|
||||
knip-report.md
|
||||
|
||||
@@ -186,6 +186,7 @@ Kaswell
|
||||
keepalive
|
||||
Keyv
|
||||
Knex
|
||||
knip
|
||||
Koyeb
|
||||
KPIs
|
||||
Kuang
|
||||
|
||||
@@ -155,7 +155,7 @@ jobs:
|
||||
name: Test ${{ matrix.node-version }}
|
||||
services:
|
||||
postgres16:
|
||||
image: postgres:16@sha256:4d1b17af6f66b852ee3a721f6691a2ca7352f9d28f570a6a48cee4ebe646b2fd
|
||||
image: postgres:16@sha256:09f23e02d76670d3b346a3c00aa33a27cf57aab8341eedfcdaed41459d14f5c4
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
options: >-
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
ports:
|
||||
- 5432/tcp
|
||||
postgres12:
|
||||
image: postgres:12@sha256:aafc7d3faafa5f95fa4709007c742864747a104c3d950f98bb606145208e4a77
|
||||
image: postgres:12@sha256:8ffdca6e9208aceb30653fa0cc1c38956303ace453944b54b4f71019cfe854c1
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
options: >-
|
||||
@@ -177,7 +177,7 @@ jobs:
|
||||
ports:
|
||||
- 5432/tcp
|
||||
mysql8:
|
||||
image: mysql:8@sha256:d7c20c5ba268c558f4fac62977f8c7125bde0630ff8946b08dde44135ef40df3
|
||||
image: mysql:8@sha256:2a9ef1075ff30c65bbcf4f96b25a03ea3b3f492c284e6c4a612c269ce4c5bb19
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
options: >-
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
services:
|
||||
postgres16:
|
||||
image: postgres:16@sha256:4d1b17af6f66b852ee3a721f6691a2ca7352f9d28f570a6a48cee4ebe646b2fd
|
||||
image: postgres:16@sha256:09f23e02d76670d3b346a3c00aa33a27cf57aab8341eedfcdaed41459d14f5c4
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
options: >-
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
ports:
|
||||
- 5432/tcp
|
||||
postgres12:
|
||||
image: postgres:12@sha256:aafc7d3faafa5f95fa4709007c742864747a104c3d950f98bb606145208e4a77
|
||||
image: postgres:12@sha256:8ffdca6e9208aceb30653fa0cc1c38956303ace453944b54b4f71019cfe854c1
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
options: >-
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
ports:
|
||||
- 5432/tcp
|
||||
mysql8:
|
||||
image: mysql:8@sha256:d7c20c5ba268c558f4fac62977f8c7125bde0630ff8946b08dde44135ef40df3
|
||||
image: mysql:8@sha256:2a9ef1075ff30c65bbcf4f96b25a03ea3b3f492c284e6c4a612c269ce4c5bb19
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
options: >-
|
||||
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
# Create/Update comment with action deployment status
|
||||
- name: Create or Update Comment with Deployment Notification
|
||||
id: notification
|
||||
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3
|
||||
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||
with:
|
||||
comment-id: ${{ steps.find-comment.outputs.comment-id }}
|
||||
issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }}
|
||||
@@ -165,7 +165,7 @@ jobs:
|
||||
echo "Access the \`backstage\` endpoint at [\`${BACKSTAGE_HOST}\`](http://${BACKSTAGE_HOST})" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Create or Update Comment with Deployment URL
|
||||
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3
|
||||
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||
with:
|
||||
comment-id: ${{ steps.notification.outputs.comment-id }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
@@ -229,7 +229,7 @@ jobs:
|
||||
direction: last
|
||||
|
||||
- name: Update Comment with Deletion
|
||||
uses: peter-evans/create-or-update-comment@23ff15729ef2fc348714a3bb66d2f655ca9066f2 # v3
|
||||
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4
|
||||
with:
|
||||
comment-id: ${{ steps.find-comment.outputs.comment-id }}
|
||||
issue-number: ${{ needs.cache-manifests-file.outputs.pr-number }}
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- 'lighthouserc.js'
|
||||
- '.github/workflows/verify_accessibility_core.yml'
|
||||
- '.github/workflows/verify_accessibility.yml'
|
||||
- 'plugins/catalog/src/**'
|
||||
- 'plugins/catalog-react/src/**'
|
||||
- 'plugins/techdocs/src/**'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
name: Accessibility
|
||||
on:
|
||||
# NOTE: If you change these you must update verify_accessibility_core-noop.yml as well
|
||||
# NOTE: If you change these you must update verify_accessibility-noop.yml as well
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths:
|
||||
- 'lighthouserc.js'
|
||||
- '.github/workflows/verify_accessibility_core.yml'
|
||||
- '.github/workflows/verify_accessibility.yml'
|
||||
- 'plugins/catalog/src/**'
|
||||
- 'plugins/catalog-react/src/**'
|
||||
- 'plugins/techdocs/src/**'
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12@sha256:aafc7d3faafa5f95fa4709007c742864747a104c3d950f98bb606145208e4a77
|
||||
image: postgres:12@sha256:8ffdca6e9208aceb30653fa0cc1c38956303ace453944b54b4f71019cfe854c1
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# NO-OP placeholder that always passes for other paths
|
||||
# This is here so that we're able to set the status check as required
|
||||
|
||||
name: Microsite Accessibility
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- '.github/workflows/verify_microsite_accessibility.yml'
|
||||
- 'microsite/scripts/**'
|
||||
- 'microsite/src/**'
|
||||
- 'microsite/data/**'
|
||||
- 'microsite/blog/**'
|
||||
- 'microsite/static/**'
|
||||
- 'beps/**'
|
||||
- 'mkdocs.yml'
|
||||
- 'docs/**'
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
noop:
|
||||
name: Microsite Accessibility
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- run: echo NOOP
|
||||
@@ -0,0 +1,40 @@
|
||||
name: Microsite Accessibility
|
||||
on:
|
||||
# NOTE: If you change these you must update verify_microsite_accessibility-noop.yml as well
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths:
|
||||
- '.github/workflows/verify_microsite_accessibility.yml'
|
||||
- 'microsite/**'
|
||||
- 'beps/**'
|
||||
- 'mkdocs.yml'
|
||||
- 'docs/**'
|
||||
jobs:
|
||||
lhci:
|
||||
name: Microsite Accessibility
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
|
||||
- name: Use Node.js 18.x
|
||||
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: top-level install
|
||||
run: yarn install --immutable
|
||||
|
||||
- name: yarn install
|
||||
run: yarn install --immutable
|
||||
working-directory: microsite
|
||||
|
||||
- name: run Lighthouse CI
|
||||
run: |
|
||||
yarn dlx @lhci/cli@0.11.x --config=microsite/lighthouserc.js autorun
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
|
||||
- run: yarn build-storybook
|
||||
|
||||
- uses: chromaui/action@05a82adb1e6919df177f54777e81a2ef3e312323 # v10
|
||||
- uses: chromaui/action@c53f50952a7b6d99666d77d8a61eb1b58944d68a # v10
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# projectToken intentionally shared to allow collaborators to run Chromatic on forks
|
||||
|
||||
+4
-1
@@ -162,4 +162,7 @@ e2e-test-report/
|
||||
*svg.dtmp
|
||||
|
||||
# Scripts
|
||||
plugins-report.csv
|
||||
plugins-report.csv
|
||||
|
||||
# Temporary knip configs
|
||||
knip.json
|
||||
|
||||
@@ -6,6 +6,7 @@ coverage
|
||||
templates
|
||||
api-report.md
|
||||
api-report-*.md
|
||||
knip-report.md
|
||||
cli-report.md
|
||||
plugins/scaffolder-backend/sample-templates
|
||||
.vscode
|
||||
|
||||
@@ -37,14 +37,13 @@ Team: @backstage/discoverability-maintainers
|
||||
|
||||
Scope: Discoverability within Backstage, including the home page, information architecture, and search
|
||||
|
||||
| Name | Organization | Team | GitHub | Discord |
|
||||
| ------------------------ | ------------ | ---- | ---------------------------------------- | ------------------ |
|
||||
| Avantika Iyer | Spotify | BUX | [tikabom](http://github.com/tikabom) | - |
|
||||
| Camila Belo | Spotify | BUX | [camilaibs](http://github.com/camilaibs) | Camila Loiola#0226 |
|
||||
| Emma Indal | Spotify | BUX | [emmaindal](http://github.com/emmaindal) | emmaindal#7503 |
|
||||
| Raghunandan Balachandran | Spotify | BUX | [soapraj](http://github.com/soapraj) | raghunandanb#1114 |
|
||||
| Renan Mendes Carvalho | Spotify | BUX | [aitherios](http://github.com/aitherios) | aitherios#0593 |
|
||||
| Bailey Brooks | Spotify | BUX | [bailey](http://github.com/bailey) | \_bailey4 |
|
||||
| Name | Organization | Team | GitHub | Discord |
|
||||
| ------------------------ | ------------ | -------------- | ---------------------------------------- | ----------------- |
|
||||
| Avantika Iyer | Spotify | Infinite Buck$ | [tikabom](http://github.com/tikabom) | - |
|
||||
| Emma Indal | Spotify | Infinite Buck$ | [emmaindal](http://github.com/emmaindal) | emmaindal#7503 |
|
||||
| Djamaile Rahamat | Spotify | Infinite Buck$ | [djamaile](http://github.com/djamaile) | dyoqi |
|
||||
| Raghunandan Balachandran | Spotify | Infinite Buck$ | [soapraj](http://github.com/soapraj) | raghunandanb#1114 |
|
||||
| Bailey Brooks | Spotify | Infinite Buck$ | [bailey](http://github.com/bailey) | \_bailey4 |
|
||||
|
||||
### Helm Charts
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ The following goals are the primary focus of this BEP:
|
||||
- Basic improvements to the service-to-service auth service interfaces such that we are confident that we do not need to break them in the near future.
|
||||
- If possible we will keep using the existing symmetrical keys that are used today, but it is likely that we will need to break compatibility of existing tokens.
|
||||
- Encapsulation of user credentials in upstream service requests, avoiding the pattern where backend plugins re-use the user token directly for their outgoing requests.
|
||||
- Separate out the ownership information out of the Backstage user tokens, since user tokens have been growing large enough to have an impact on performance and reliability.
|
||||
|
||||
### Non-Goals
|
||||
|
||||
@@ -72,6 +73,8 @@ In order to allow either unauthenticated access or cookie-based access, a plugin
|
||||
|
||||
For service-to-service communication we will move away from reusing user tokens in upstream requests. We will instead implement an "On-Behalf-Of" flow where incoming user credentials are encapsulated in a service token for the upstream request. In line with this the new auth service interfaces will aim to make it difficult to directly forward credentials from incoming requests, and instead encourage that plugin backends issue new service credentials for upstream requests.
|
||||
|
||||
An issue that has been identified in the current auth implementation is that the user information embedded in the Backstage user tokens can grow fairly large. In order to avoid that this becomes a widespread problem, especially as we implement cookie auth with a 4kb size limit, we will remove the ownership entity refs (`ent` claim) from the user tokens. There were already very few consumers of this information in practice - only the `permission-backend` and `signal-backend` plugin packages currently rely on this information. The ownership data will instead be available via a new `UserInfoService`, owned by the `auth-backend`. The implementation of this new service will keep relying on the `ent` claim of the user token initially, but we will also implement a new `/v1/userinfo` endpoint in the `auth-backend` that will migrate to transparently in the future.
|
||||
|
||||
## Design Details
|
||||
|
||||
### `AuthService` Interface
|
||||
@@ -79,29 +82,54 @@ For service-to-service communication we will move away from reusing user tokens
|
||||
The new `AuthService` interface is defined as follows:
|
||||
|
||||
```ts
|
||||
export type BackstageCredentials = {
|
||||
token: string;
|
||||
// These credential types are opaque and will also store some internal information, for example bearer tokens
|
||||
|
||||
user?: {
|
||||
userEntityRef: string;
|
||||
ownershipEntityRefs: string[];
|
||||
};
|
||||
export type BackstageUserCredentials = {
|
||||
$$type: '@backstage/BackstageCredentials';
|
||||
|
||||
service?: {
|
||||
id: string;
|
||||
};
|
||||
type: 'user';
|
||||
|
||||
userEntityRef: string;
|
||||
};
|
||||
|
||||
export type BackstageServiceCredentials = {
|
||||
$$type: '@backstage/BackstageCredentials';
|
||||
|
||||
type: 'service';
|
||||
|
||||
// Exact format TBD, possibly 'plugin:<pluginId>' or 'external:<externalServiceId>'
|
||||
subject: string;
|
||||
|
||||
// Not implemented in the first iteration, but this is how we might extend this in the future
|
||||
permissions?: string[];
|
||||
};
|
||||
|
||||
type BackstageCredentials =
|
||||
| BackstageUserCredentials
|
||||
| BackstageServiceCredentials;
|
||||
|
||||
export interface AuthService {
|
||||
authenticate(token: string): Promise<BackstageCredentials>;
|
||||
|
||||
// TODO: should the caller provide the target plugin ID?
|
||||
// TODO: how can we make it very difficult to forget to forward credentials
|
||||
issueToken(credentials: BackstageCredentials): Promise<{ token: string }>;
|
||||
}
|
||||
```
|
||||
|
||||
### `AuthService` Usage Patterns
|
||||
### `UserInfoService` Interface
|
||||
|
||||
TODO
|
||||
The new `UserInfoService` interface is defined as follows:
|
||||
|
||||
```ts
|
||||
export interface UserInfoService {
|
||||
getUserInfo(
|
||||
credentials: BackstageUserCredentials,
|
||||
): Promise<{ ownershipEntityRefs: string[] /* profile info too? */ }>;
|
||||
}
|
||||
```
|
||||
|
||||
The `UserInfoService` is exported by `@backstage/auth-node`, and the initial implementation will simply read the ownership refs from the `ent` claim of the underlying token of the user credentials. The next iteration will instead call the `/v1/userinfo` endpoint of the `auth-backend`, once that has been implemented.
|
||||
|
||||
### `HttpRouterService` Interface
|
||||
|
||||
@@ -196,14 +224,27 @@ export default createBackendPlugin({
|
||||
The new `HttpAuthService` interface is defined as follows:
|
||||
|
||||
```ts
|
||||
export type BackstageUnauthorizedCredentials = {
|
||||
$$type: '@backstage/BackstageCredentials';
|
||||
|
||||
type: 'unauthorized';
|
||||
};
|
||||
|
||||
type BackstageCredentialTypes = {
|
||||
user: BackstageUserCredentials;
|
||||
service: BackstageServiceCredentials;
|
||||
unauthorized: BackstageUnauthorizedCredentials;
|
||||
};
|
||||
|
||||
export interface HttpAuthService {
|
||||
createHttpPluginRouterMiddleware(options: OptionsTBD): Handler;
|
||||
|
||||
credentials(
|
||||
credentials<TAllowed extends keyof BackstageCredentialTypes>(
|
||||
req: Request,
|
||||
options?: HttpAuthServiceMiddlewareOptions,
|
||||
): BackstageCredentials;
|
||||
options?: HttpAuthServiceMiddlewareOptions<TAllowed>,
|
||||
): Promise<BackstageCredentialTypes[TAllowed]>;
|
||||
|
||||
// TODO: Keep an eye on this, might not be needed
|
||||
requestHeaders(
|
||||
credentials: BackstageCredentials,
|
||||
): Promise<Record<string, string>>;
|
||||
@@ -212,7 +253,7 @@ export interface HttpAuthService {
|
||||
}
|
||||
```
|
||||
|
||||
### `HttpAuthService` Usage Patterns
|
||||
### `AuthService`, `HttpAuthService` and `UserInfoService` Usage Patterns
|
||||
|
||||
All of these usages patterns are from the perspective of a plugin backend.
|
||||
|
||||
@@ -221,15 +262,10 @@ All of these usages patterns are from the perspective of a plugin backend.
|
||||
```ts
|
||||
// All routes only allow authenticated users and services by default.
|
||||
router.get('/read-data', (req, res) => {
|
||||
// TODO: user can currently be undefined, figure out best pattern to avoid that
|
||||
const { user } = httpAuth.credentials(req);
|
||||
if (!user) {
|
||||
throw new NotAllowedError(
|
||||
'Service requests are not allowed on this endpoint',
|
||||
);
|
||||
}
|
||||
const credentials = await httpAuth.credentials(req, { allow: ['user'] }); // throws if not: user (or obo), user-cookie
|
||||
const { ownershipEntityRefs } = await userInfo.getUserInfo(credentials);
|
||||
console.log(
|
||||
`User ref=${user.userEntityRef} ownership=${user.ownershipEntityRefs}`,
|
||||
`User ref=${credentials.userEntityRef} ownership=${ownershipEntityRefs} claims=${credentials.extraClaims}`,
|
||||
);
|
||||
// ...
|
||||
});
|
||||
@@ -238,11 +274,36 @@ router.get('/read-data', (req, res) => {
|
||||
#### Forward the user credentials from an incoming requests to upstream plugin backend
|
||||
|
||||
```ts
|
||||
class CatalogIntegration {
|
||||
async getEntity(
|
||||
res: string,
|
||||
options: {
|
||||
credentials: BackstageUserCredentials | BackstageServiceCredentials;
|
||||
},
|
||||
) {
|
||||
return catalogClient.getEntityByRef(req.params.entityRef, {
|
||||
token: await auth.issueToken({
|
||||
forward: options.credentials,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Earlier in the router setup
|
||||
const catalogIntegration = new CatalogIntegration();
|
||||
|
||||
router.get('/read-data', (req, res) => {
|
||||
// The catalogClient will have a reference to the (plugin scoped) HttpAuthService,
|
||||
// which it uses to create the credential headers for the upstream request.
|
||||
const entity = await catalogClient.getEntityByRef(req.params.entityRef, {
|
||||
credentials: httpAuth.credentials(req),
|
||||
credentials: httpAuth.forwardCredentials(req, {
|
||||
dangerouslyAllowUnauthenticated: true,
|
||||
}),
|
||||
});
|
||||
|
||||
// TODO: try this out in more places in plugins
|
||||
const entity = await catalogIntegration.getEntity(req.params.entityRef, {
|
||||
credentials: await httpAuth.credentials(req),
|
||||
});
|
||||
// ...
|
||||
});
|
||||
@@ -252,15 +313,17 @@ router.get('/read-data', (req, res) => {
|
||||
|
||||
```ts
|
||||
router.get('/read-data', (req, res) => {
|
||||
const credentials = httpAuth.credentials(req);
|
||||
if (credentials.user) {
|
||||
res.json(
|
||||
// Silly example just to highlight separate code paths for user and
|
||||
// service requests
|
||||
todoStore.listOwnedTodos({ owner: credentials.user.userEntityRef }),
|
||||
);
|
||||
const credentials = await httpAuth.credentials(req, {
|
||||
allow: ['user', 'service'],
|
||||
});
|
||||
if (credentials.type === 'user') {
|
||||
res.json(todoStore.listOwnedTodos({ owner: credentials.userEntityRef }));
|
||||
} else {
|
||||
res.json(todoStore.listTodos());
|
||||
res.json(
|
||||
todoStore.listTodos({
|
||||
serviceId: credentials.subject,
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
@@ -294,9 +357,10 @@ router.get(
|
||||
(req, res) => {
|
||||
// These credentials don't actually contain an underlying user token for cookie-authed requests
|
||||
// If you try to pass them to the AuthService, it'll throw.
|
||||
const { user } = httpAuth.credentials(req);
|
||||
const credentials = await httpAuth.credentials(req, { allow: ['user'] });
|
||||
const { ownershipEntityRefs } = await userInfo.getUserInfo(credentials);
|
||||
console.log(
|
||||
`User ref=${user.userEntityRef} ownership=${user.ownershipEntityRefs}`,
|
||||
`User ref=${credentials.userEntityRef} ownership=${ownershipEntityRefs}`,
|
||||
);
|
||||
// ...
|
||||
},
|
||||
@@ -309,6 +373,19 @@ The existing `IdentityService` and `TokenManagerService` will be deprecated and
|
||||
|
||||
The release plan for the `HttpAuthService` is TBD, but is likely to be shipped as a no-op for plugins using the old backend system. The goal is for all plugins using the new backend system to have endpoint security be opt-out, which will be a breaking change.
|
||||
|
||||
### Implementation Tasks
|
||||
|
||||
- [ ] Implement `AuthService`
|
||||
- [ ] Implement `HttpAuthService` - leave cookie auth as unimplemented for now
|
||||
- [ ] Add `configure()` for `HttpRouterService`, using `HttpAuthService`
|
||||
- [ ] Implement a compatibility wrapper in `backend-common` that accepts `AuthService`, `HttpAuthService`, `IdentityService`, and `TokenManagerService` (all optional), and returns implementations for `AuthService` and `HttpAuthService`, such hat existing plugins can use a single `createRouter` implementation for both the old and new backend systems.
|
||||
- [ ] Implement `UserInfoService` in `@backstage/auth-node` - for now it will just extract the ownership entity refs from the token stored in the credentials
|
||||
- [ ] Implement cookie auth in `HttpAuthService` - just put the user token in the cookie for now
|
||||
- [ ] Migrate plugins:
|
||||
- [ ] Permission backend
|
||||
- [ ] TechDocs backend
|
||||
- [ ] App backend
|
||||
|
||||
## Dependencies
|
||||
|
||||
No significant dependencies have been identified for this work, although any future security audits of Backstage are considered dependent on this work.
|
||||
@@ -316,3 +393,68 @@ No significant dependencies have been identified for this work, although any fut
|
||||
## Alternatives
|
||||
|
||||
An alternative to built-in protection from external access would be to keep relying on external mechanisms to protect access to Backstage. We feel that this is a suboptimal solution since it adds complexity to the adoption of Backstage, and increases the risk of misconfiguration and security breaches. Regardless of whether we add built-in protection or not the ability to protect API endpoints needs to be addressed in some way, since it is a requirement for the permission system to work. This means that the extra steps to ensure protection out of the box are fairly minimal when looking at just the delta for protecting API access.
|
||||
|
||||
### Access Control Patterns
|
||||
|
||||
These are the different patterns that we've considered for how plugins should control access to their endpoints.
|
||||
|
||||
#### Separate methods / configuration for `use`
|
||||
|
||||
This approach extends the `HttpRouterService` with separate methods or options for specifying the access control for different handlers.
|
||||
|
||||
Pros:
|
||||
|
||||
- We can make strict access control the default, making relaxed controls an opt-in
|
||||
- The routing setup is quite explicit in what handlers allow for what access levels
|
||||
|
||||
Cons:
|
||||
|
||||
- Forces separation of the router, splitting it into separate handlers for different levels of access.
|
||||
- Can be extremely confusing because the top-level middleware for more lax access will also apply to the more strict access levels. For example
|
||||
|
||||
```ts
|
||||
const cookieRouter = Router();
|
||||
cookieRouter.use(rateLimit());
|
||||
http.useWithCookieAuthentication(cookieRouter);
|
||||
|
||||
const mainRouter = Router();
|
||||
// rateLimit() will apply here too
|
||||
http.use(mainRouter);
|
||||
```
|
||||
|
||||
This applied to any similar way of structuring this API, such as a single `.use()` method with additional options:
|
||||
|
||||
```ts
|
||||
http.use(cookieRouter, { allow: ['user-cookie'] });
|
||||
```
|
||||
|
||||
#### Separate configuration on different paths for `use`
|
||||
|
||||
Similar to the previous approach, but also require that a path is provided. This removes much of the confusion around what middleware are applied.
|
||||
|
||||
The downside of this approach is that it still has the drawback of forcing a separation of the router, but at the same it provides very little benefit over a top-level path configuration approach like `http.configure()`. The `'/static'` path in the below example essentially has the exact same logic as `.configure({ cookieAuthPaths: ['/static'] })` since it'd be implemented in the same way. The `.configure()` approach has the benefit of allowing plugin authors to decide whether they want to keep the routes separate or not.
|
||||
|
||||
This does have the benefit of letting the framework know which exact routes are protected, which can be useful for introspection, although that benefit also applies to the `.configure()` approach.
|
||||
|
||||
```ts
|
||||
// This isn't too bad, but it's extremely similar to the configure() method since
|
||||
// we're just matching on the path. The benefit of configure is that it allows you
|
||||
// to keep everything in a singe router if desired.
|
||||
http.use('/static', cookieRouter, { allow: ['user-cookie'] });
|
||||
```
|
||||
|
||||
#### Complete opt-out
|
||||
|
||||
This approach simply enabled plugins to opt-out of the default access control, and instead require that they implement the necessary endpoint protection using `httpAuth.middleware()`.
|
||||
|
||||
This approach makes it a bit easier to make mistakes compared to the `.configure()` approach, but at the same time it has the benefit of collection all access control login in a single place (the plugin router). It also doesn't allow the framework to see which endpoints have relaxed protection, which is a downside.
|
||||
|
||||
Still, this is a pattern that is currently second in line if we don't go with the `.configure()` approach.
|
||||
|
||||
```ts
|
||||
http.dangerouslyDisableAuthentication();
|
||||
```
|
||||
|
||||
#### Leave access control to the plugin router
|
||||
|
||||
Having strict access control be the default with explicit opt-out is an explicit goal of this work, so this is not an option that we are considering.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM mcr.microsoft.com/devcontainers/typescript-node:20@sha256:185cde4e033cd68fb4c5c9eef94ba6bde0dac2f334ecd1a7cf6cd2c87f712d85
|
||||
FROM mcr.microsoft.com/devcontainers/typescript-node:20@sha256:381a1fde32704f229b439ade94816d5619f710e35698982ec35afcd9384ae6cf
|
||||
|
||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get -y install chromium \
|
||||
|
||||
@@ -46,7 +46,7 @@ RUN yarn workspace app build
|
||||
|
||||
|
||||
|
||||
FROM nginx:mainline@sha256:5f44022eab9198d75939d9eaa5341bc077eca16fa51d4ef32d33f1bd4c8cbe7d
|
||||
FROM nginx:mainline@sha256:84c52dfd55c467e12ef85cad6a252c0990564f03c4850799bf41dd738738691f
|
||||
|
||||
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
|
||||
|
||||
FROM nginx:mainline@sha256:5f44022eab9198d75939d9eaa5341bc077eca16fa51d4ef32d33f1bd4c8cbe7d
|
||||
FROM nginx:mainline@sha256:84c52dfd55c467e12ef85cad6a252c0990564f03c4850799bf41dd738738691f
|
||||
|
||||
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -220,6 +220,8 @@ clientSecret: someGithubAppClientSecret
|
||||
webhookSecret: someWebhookSecret
|
||||
privateKey: |
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
SomeRsaPrivateKey
|
||||
SomeRsaPrivateKeySecurelyStored
|
||||
-----END RSA PRIVATE KEY-----
|
||||
```
|
||||
|
||||
**Warning: Sensitive information, such as private keys, should not be hard coded**. We recommend that this entire file should be a secret and stored as such in a secure storage solution like Vault, to ensure they are neither exposed nor misused. This example key part only shows the format on how to use the yaml | syntax to make sure that the key is valid.
|
||||
|
||||
@@ -81,8 +81,6 @@ const extension = createExtension({
|
||||
|
||||
Note that while the `createExtension` is public API and used in many places, it is not typically what you use when building plugins and features. Instead there are many extension creator functions exported by both the core APIs and plugins that make it easier to create extensions for more specific usages.
|
||||
|
||||
... TODO ...
|
||||
|
||||
## Extension Data
|
||||
|
||||
Communication between extensions happens in one direction, from one child extension through the attachment point to its parent. The child extension outputs data which is then passed as inputs to the parent extension. This data is called Extension Data, where the shape of each individual piece of data is described by an Extension Data Reference. These references are created separately from the extensions themselves, and can be shared across multiple different kinds of extensions. Each reference consists of an ID and a TypeScript type that the data needs to conform to, and represents one type of data that can be shared between extensions.
|
||||
@@ -137,7 +135,7 @@ const extension = createExtension({
|
||||
|
||||
We provide default `coreExtensionData`, which provides commonly used `ExtensionDataRef`s - e.g. for `React.JSX.Element` and `RouteRef`. They can be used when creating your own extension. For example, the React Element extension data that we defined above is already provided as `coreExtensionData.reactElement`.
|
||||
|
||||
<!-- For a full list and explanations of all types of core extension data, see the [core extension data reference](#TODO). -->
|
||||
For a full list and explanations of all types of core extension data, see the [core extension data reference](../building-plugins/04-built-in-data-refs.md).
|
||||
|
||||
### Optional Extension Data
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
id: index
|
||||
title: Building Frontend Apps
|
||||
sidebar_label: Overview
|
||||
# prettier-ignore
|
||||
description: Building frontend apps using the new frontend system
|
||||
---
|
||||
|
||||
> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.**
|
||||
|
||||
To get set up quickly with your own Backstage project you can create a Backstage App.
|
||||
|
||||
A Backstage App is a monorepo setup that includes everything you need to run Backstage in your own environment.
|
||||
|
||||
## Creating a new app
|
||||
|
||||
To create a new Backstage app we recommend using the `@backstage/create-app` command line, and the easiest way to run this package is with `npx`:
|
||||
|
||||
:::note
|
||||
The create-app CLI requires Node.js Active LTS Release.
|
||||
:::
|
||||
|
||||
```sh
|
||||
# The command bellow creates a Backstage App inside the current folder.
|
||||
# The name of the app-folder is the name that was provided when prompted.
|
||||
npx @backstage/create-app@latest
|
||||
```
|
||||
|
||||
The created-app is currently templated for legacy frontend system applications, so the app wiring code it creates needs to be migrated, see [the app instance](#the-app-instance) section for an example.
|
||||
|
||||
## The app instance
|
||||
|
||||
The starting point of a frontend app is the `createApp` function, which accepts a single options object as its only parameter. It is imported from `@backstage/frontend-app-api`, which is where you will find most of the common APIs for building apps.
|
||||
|
||||
This is how to create a minimal app:
|
||||
|
||||
```tsx title="in src/index.ts"
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
import catalogPlugin from '@backstage/plugin-catalog/alpha';
|
||||
|
||||
// Create your app instance
|
||||
const app = createApp({
|
||||
// Features such as plugins can be installed explicitly, but we will explore other options later on
|
||||
features: [catalogPlugin],
|
||||
});
|
||||
|
||||
// This creates a React element that renders the entire app
|
||||
const root = app.createRoot();
|
||||
|
||||
// Just like any other React we need a root element. No server side rendering is used.
|
||||
const rootEl = document.getElementById('root')!;
|
||||
|
||||
ReactDOM.createRoot(rootEl).render(root);
|
||||
```
|
||||
|
||||
Note that `createRoot` returns the root element that is rendered by React. The above example is installing a catalog plugin and using default settings for the app, as no options other than the `features` array are passed to the `createApp` function.
|
||||
|
||||
Visit the [built-in extensions](#customize-or-override-built-in-extensions) section to see what is installed by default in a Backstage application.
|
||||
|
||||
## Configure your app
|
||||
|
||||
### Bind external routes
|
||||
|
||||
Linking routes from different plugins requires this configuration. You can do this either through a configuration file or by coding, visit [this](https://backstage.io/docs/frontend-system/architecture/routes#binding-external-route-references) page for instructions.
|
||||
|
||||
### Enable feature discovery
|
||||
|
||||
Use this setting to enable experimental feature discovery when building your app with `@backstage/cli`. With this configuration your application tries to discover and install package extensions automatically, check [here](../architecture/02-app.md#feature-discovery) for more details.
|
||||
|
||||
:::warning
|
||||
Remember that package extensions that are not auto-discovered must be manually added to the application when creating an app. See [features](#install-features-manually) for more details.
|
||||
:::
|
||||
|
||||
### Configure extensions individually
|
||||
|
||||
It is possible to enable, disable and configure extensions individually in the `app-config.yaml` config file. To get familiar with what is available for app extensions personalization, go to the [built-in extensions](./02-built-in-extensions.md) documentation. For plugin customizations, we recommend that you read the instructions in each plugin's README file.
|
||||
|
||||
### Customize or override built-in extensions
|
||||
|
||||
Previously you would customize the application route, components, apis, sidebar, etc. through the code in `App.tsx`. Now we want you to write less code and install more extensions to customize your Backstage instance. See [here](../building-plugins/03-extension-types.md) which types of extensions are available for you to customize your application.
|
||||
|
||||
## Use code to customize the app at a more granular level
|
||||
|
||||
### Install features manually
|
||||
|
||||
A manual installation is required if your packages are not discovered automatically, either because you are not using `@backstage/cli` to build your application or because the features are defined in local modules in the app package. In order to manually install a feature, you must import it and pass it to the `createApp` function:
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
// This plugin was create as a local module in the app
|
||||
import { somePlugin } from './plugins';
|
||||
|
||||
const app = createApp({
|
||||
features: [somePlugin],
|
||||
});
|
||||
|
||||
export default app.createRoot();
|
||||
```
|
||||
|
||||
:::info
|
||||
You can also pass overrides to the features array, for more details, please read the [extension overrides](../architecture/05-extension-overrides.md) documentation.
|
||||
:::
|
||||
|
||||
### Using an async features loader
|
||||
|
||||
In case you need to perform asynchronous operations before passing features to the `createApp` function, define a [feature loader](https://backstage.io/docs/reference/frontend-app-api.createappfeatureloader/) object and pass it to the `features` option:
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
|
||||
const app = createApp({
|
||||
features: {
|
||||
getLoaderName: () => '<your-custom-features-loader-name>',
|
||||
// there is a reference to the config api in the options param
|
||||
load: async _options => {
|
||||
// returning a lazy loaded plugins and overrides array
|
||||
// could be util for module federation
|
||||
return import('./features').then(m => m.default);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default app.createRoot();
|
||||
```
|
||||
|
||||
### Lazy load your configuration file
|
||||
|
||||
In some cases we want to load our configuration from a backend server and to do so, you can pass an callback to the `configLoader` option when calling the `createApp` function, the callback should return a promise of an object with the config object:
|
||||
|
||||
```tsx title="packages/app/src/App.tsx"
|
||||
import { createApp } from '@backstage/frontend-app-api';
|
||||
import { getConfigFromServer } from './utils';
|
||||
|
||||
// Example lazy loading the app configuration
|
||||
const app = createApp({
|
||||
// Returns Promise<{ config: ConfigApi }>
|
||||
configLoader: async () => {
|
||||
// Calls an async utility method that fetches the config object from the server
|
||||
const config = await getConfigFromServer();
|
||||
// Feel free to manipulate the config object before returning it
|
||||
// A common example is conditionally modify the config based on the running enviroment
|
||||
return { config };
|
||||
},
|
||||
});
|
||||
|
||||
export default app.createRoot();
|
||||
```
|
||||
@@ -0,0 +1,190 @@
|
||||
---
|
||||
id: built-in-extensions
|
||||
title: App Built-in Extensions
|
||||
sidebar_label: Built-in extensions
|
||||
# prettier-ignore
|
||||
description: Configuring or overriding built-in extensions
|
||||
---
|
||||
|
||||
Built-in extensions are default app extensions that are always installed when you create a Backstage app.
|
||||
|
||||
## Disable built-in extensions
|
||||
|
||||
All built-in extensions can be disabled in the same way as you disable any other extension:
|
||||
|
||||
```yaml title="app-config.yaml"
|
||||
extensions:
|
||||
# Disabling the built-in app root alert element
|
||||
- app-root-element:app/alert-display: false
|
||||
```
|
||||
|
||||
:::warning
|
||||
Be careful when disabling built-in extensions, as there may be other extensions depending on their existence. For example, the built-in "alert display" extension displays messages retrieved via [AlertApi](https://backstage.io/docs/reference/core-plugin-api.alertapi) and disabling this extension will cause the application to no longer display these messages unless you install another extension that displays messages from `AlertApi`.
|
||||
:::
|
||||
|
||||
## Override built-in extensions
|
||||
|
||||
You can override any built-in extension whenever their customizations, whether through configuration or input, do not meet a use case for your Backstage instance. Check out [this](../architecture/05-extension-overrides.md) documentation on how to override application extensions.
|
||||
|
||||
:::warning
|
||||
Be aware there could be some implementation requirements to properly override an built-in extension, such as using same apis and do not remove inputs or configurations otherwise you can cause a side effect in other parts of the system that expects same minimal behavior.
|
||||
:::
|
||||
|
||||
## Default built-in extensions
|
||||
|
||||
### App
|
||||
|
||||
This extension is the first extension attached to the extension tree. It is responsible for receiving the application's root element and other Frontend framework inputs.
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| root | The app root element. | [coreExtensionData.reactElement](https://backstage.io/docs/reference/frontend-plugin-api.coreextensiondata) | false | The [`App/Root`](#app-root) extension output. | No creator available, configure or override the [`App/Root`](#app-root) extension. |
|
||||
| apis | The app apis factories. | [createApiExtension.factoryDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension.factorydataref) | false | See [default apis](#default-apis-extensions). | [createApiExtension](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension) |
|
||||
| themes | The app themes list. | [createThemeExtension.themeDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension.themedataref) | false | See [default themes](#default-theme-extensions). | [createThemeExtension](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension) |
|
||||
| components | The app components list. | [createComponentExtension.componentDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension.componentdataref) | false | See [default components](#default-components-extensions). | [createComponentExtension](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension) |
|
||||
| translations | The app translations list. | [createTranslationExtension.translationDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension.translationdataref) | false | - | [createTranslationExtension](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension) |
|
||||
|
||||
#### Default theme extensions
|
||||
|
||||
Extensions that provides default theme inputs for the `App` extension.
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :---: | :-------: | :---: | :---------------: |
|
||||
| theme | app | light | `theme:app/light` |
|
||||
| theme | app | dark | `theme:app/dark` |
|
||||
|
||||
#### Default components extensions
|
||||
|
||||
Extensions that provides default components inputs for the `App` extension.
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--------: | :-------: | :-----------------------------------: | :----------------------------------------------------: |
|
||||
| components | app | core.components.progress | `components:app/core.components.progress` |
|
||||
| components | app | core.components.notFoundErrorPage | `components:app/core.components.notFoundErrorPage` |
|
||||
| components | app | core.components.errorBoundaryFallback | `components:app/core.components.errorBoundaryFallback` |
|
||||
|
||||
#### Default apis extensions
|
||||
|
||||
Extensions that provides default apis inputs for the `App` extension.
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--: | :------------------------: | :--: | :------------------------------: |
|
||||
| api | core.discovery | - | `api:core.discovery` |
|
||||
| api | core.alert | - | `api:core.alert` |
|
||||
| api | core.analytics | - | `api:core.analytics` |
|
||||
| api | core.error | - | `api:core.error` |
|
||||
| api | core.storage | - | `api:core.storage` |
|
||||
| api | core.fetch | - | `api:core.fetch` |
|
||||
| api | core.oauthrequest | - | `api:core.oauthrequest` |
|
||||
| api | core.auth.google | - | `api:core.auth.google` |
|
||||
| api | core.auth.microsoft | - | `api:core.auth.microsoft` |
|
||||
| api | core.auth.github | - | `api:core.auth.github` |
|
||||
| api | core.auth.okta | - | `api:core.auth.okta` |
|
||||
| api | core.auth.gitlab | - | `api:core.auth.gitlab` |
|
||||
| api | core.auth.onelogin | - | `api:core.auth.onelogin` |
|
||||
| api | core.auth.bitbucket | - | `api:core.auth.bitbucket` |
|
||||
| api | core.auth.bitbucket-server | - | `api:core.auth.bitbucket-server` |
|
||||
| api | core.auth.atlassian | - | `api:core.auth.atlassian` |
|
||||
| api | plugin.permission.api | - | `api:plugin.permission.api` |
|
||||
|
||||
### App root
|
||||
|
||||
This is the extension that creates the app root element, so it renders root level components such as app router and layout.
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Name | Description | Requirements | Optional | Default | Extension creator |
|
||||
| ---------- | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
||||
| router | A React component that should manager the app routes context. | It must be one [router](https://reactrouter.com/en/main/routers/picking-a-router#web-projects) component or a custom component compatible with the 'react-router' library. | true | [BrowserRouter](https://reactrouter.com/en/main/router-components/browser-router) | [createRouterExtension](https://backstage.io/docs/reference/frontend-plugin-api.createrouterextension) |
|
||||
| signInPage | A React component that should render the app sign-in page. | Should call the `onSignInSuccess` prop when the user has been successfully authorized, otherwise the user will not be correctly redirected to the application home page. | true | The default `AppRoot` extension does not use a default component for this input, it bypasses the user authentication check and always renders all routes when a login page is not installed. | [createSignInPageExtension](https://backstage.io/docs/reference/frontend-plugin-api.createsigninpageextension/) |
|
||||
| children | A React component that renders the app sidebar and main content in a particular layout. | - | false | The [`App/Layout`](#app-layout) extension output. | No creator available, configure or override the [`App/Layout`](#app-layout) extension. |
|
||||
| elements | React elements to be rendered outside of the app layout, such as shared popups. | - | false | See [default elements](#default-app-root-elements-extensions). | [createAppRootElementExtension](https://backstage.io/docs/reference/frontend-plugin-api.createapprootelementextension/) |
|
||||
| wrappers | React components that should wrap the root element. | - | true | - | [createAppRootWrapperExtension](https://backstage.io/docs/reference/frontend-plugin-api.createapprootwrapperextension/) |
|
||||
|
||||
#### Default app root elements extensions
|
||||
|
||||
##### Alert Display
|
||||
|
||||
An app root element extension that displays messages posted via the [`AlertApi`](https://backstage.io/docs/reference/core-plugin-api.alertapi).
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--------------: | :-------: | :-----------: | :----------------------------------: |
|
||||
| app-root-element | app | alert-display | `app-root-element:app/alert-display` |
|
||||
|
||||
###### Configurations
|
||||
|
||||
| Key | Type | Default value | Description |
|
||||
| -------------------- | -------------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------- |
|
||||
| `transientTimeoutMs` | number | 5000 | Time in milliseconds to wait before displaying messages. |
|
||||
| `anchorOrigin` | { vertical: 'top' \| 'bottom', horizontal: 'left' \| 'center' \| 'right' } | { vertical: 'top', horizontal: 'center' } | Position on the screen where the message alert will be displayed. |
|
||||
|
||||
###### Override or disable the extension
|
||||
|
||||
If you do not want to display alerts, disable this extension or if the available settings do not meet your needs, override this extension.
|
||||
|
||||
:::warning
|
||||
The built-in "alert display" extension displays messages retrieved via [AlertApi](https://backstage.io/docs/reference/core-plugin-api.alertapi) and disabling this extension will cause the application to no longer display these messages unless you install another extension that displays messages from `AlertApi`.
|
||||
:::
|
||||
|
||||
##### OAuth Request Dialog
|
||||
|
||||
An app root element extension that renders the oauth request dialog, it is based on the [oauthRequestApi](https://backstage.io/docs/reference/core-plugin-api.oauthrequestapi/).
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--------------: | :-------: | :------------------: | :-----------------------------------------: |
|
||||
| app-root-element | app | oauth-request-dialog | `app-root-element:app/oauth-request-dialog` |
|
||||
|
||||
### App layout
|
||||
|
||||
Renders the app's sidebar and content in a specific layout.
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--: | :-------: | :----: | :----------: |
|
||||
| - | app | layout | `app/layout` |
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------- | ------- | ------------------------------------ |
|
||||
| nav | A React element that renders the app sidebar. | [coreExtensionData.reactElement](https://backstage.io/docs/reference/frontend-plugin-api.coreextensiondata) | false | - | Override the `App/Nav` extension. |
|
||||
| content | A React element that renders the app content. | [coreExtensionData.reactElement](https://backstage.io/docs/reference/frontend-plugin-api.coreextensiondata) | false | - | Override the `App/Routes` extension. |
|
||||
|
||||
### App nav
|
||||
|
||||
Extension responsible for rendering the logo and items in the app's sidebar.
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--: | :-------: | :--: | :-------: |
|
||||
| - | app | nav | `app/nav` |
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ----- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------- | -------------------------------------------------------------------------------------------------------- |
|
||||
| logos | A nav logos object. | [createNavLogoExtension.logoElementsDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createnavlogoextension.logoelementsdataref) | true | - | [createNavLogoExtension](https://backstage.io/docs/reference/frontend-plugin-api.createnavlogoextension) |
|
||||
| items | Nav items target objects. | [createNavItemExtension.targetDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createnavitemextension.targetdataref) | true | - | [createNavItemExtension](https://backstage.io/docs/reference/frontend-plugin-api.createnavitemextension) |
|
||||
|
||||
### App routes
|
||||
|
||||
Renders a route element for each route received as input and a `NotFoundErrorPage` component.
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--: | :-------: | :----: | :----------: |
|
||||
| - | app | routes | `app/routes` |
|
||||
|
||||
#### Caveats
|
||||
|
||||
Be careful when overriding this extension, as to do so correctly you must consider these implementation requirements:
|
||||
|
||||
- The routing system is managed by more than one extension, and they all use `react-router` behind the scenes. There are also some utilities that are based on the same `routing` library like `useRouteRefParams`. Therefore, you cannot use a different library without causing side effects in these other extensions and helper utilities;
|
||||
- Don't remove configs or inputs, just extend these things yourself with optional new options, otherwise it will cause breaking changes for extensions like `createPageExtension` that depend on this type of inputs;
|
||||
- Remember to user the route refs for getting paths dynamically, otherwise if an adopter modifies a path through configuration, the route is not going to point to the configured path;
|
||||
- Adopters expect to be able to customize the `NotFoundErrorPage` component via Components API, you should render this component for routes not configured.
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | -------------------------------------------------------------------------------------------------- |
|
||||
| routes | The route objects list. | `{ path: coreExtensionData.routePath, ref: coreExtensionData.routeRef.optional(), element: coreExtensionData.reactElement }` | false | - | [createPageExtension](https://backstage.io/docs/reference/frontend-plugin-api.createpageextension) |
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
id: built-in-data-refs
|
||||
title: Built-in data refs
|
||||
sidebar_label: Built-in data refs
|
||||
# prettier-ignore
|
||||
description: Configuring or overriding built-in extension data references
|
||||
---
|
||||
|
||||
> **NOTE: The new frontend system is in alpha and is only supported by a small number of plugins.**
|
||||
|
||||
To have a better understanding of extension data references please read [the corresponding architecture section](../architecture/03-extensions.md#extension-data) first.
|
||||
|
||||
## Built-in extension data references
|
||||
|
||||
Data references help to define the inputs and outputs of an extension. A data ref is uniquely identified through its `id`. Through the data ref, strong typing is enforced for the input/output of the extension.
|
||||
|
||||
### `reactElement`
|
||||
|
||||
| id | type |
|
||||
| :-----------------: | :-----------: |
|
||||
| `core.reactElement` | `JSX.Element` |
|
||||
|
||||
The `reactElement` data reference can be used for defining the extension input/output of React elements. Example usage could be something like this:
|
||||
|
||||
```tsx
|
||||
import {
|
||||
coreExtensionData,
|
||||
createExtensionInput,
|
||||
createPageExtension,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
const homePage = createPageExtension({
|
||||
defaultPath: '/home',
|
||||
routeRef: rootRouteRef,
|
||||
inputs: {
|
||||
props: createExtensionInput({
|
||||
children: coreExtensionData.reactElement.optional(),
|
||||
}),
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### `routePath`
|
||||
|
||||
| id | type |
|
||||
| :-----------------: | :------: |
|
||||
| `core.routing.path` | `string` |
|
||||
|
||||
The `routePath` data reference can be used for defining the extension input/output of string paths.
|
||||
|
||||
### `routeRef`
|
||||
|
||||
| id | type |
|
||||
| :----------------: | :--------: |
|
||||
| `core.routing.ref` | `RouteRef` |
|
||||
|
||||
The `routeRef` data reference can be used for defining the extension input/output of route references.
|
||||
|
||||
### Other data references
|
||||
|
||||
There are other data refs in the frontend system you might stumble upon while building your plugin. Most of them were created for use cases inside the core of the system, but they can be used also in your plugin.
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Statuspage.io Plugin
|
||||
author: AxisCommunications
|
||||
authorUrl: https://github.com/AxisCommunications
|
||||
category: Monitoring
|
||||
description: The Statuspage plugin allows you to embedd https://statuspage.io components, component groups and dashboards in Backstage.
|
||||
documentation: https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/statuspage/README.md
|
||||
iconUrl: https://raw.githubusercontent.com/AxisCommunications/backstage-plugins/main/plugins/statuspage/media/logo.png
|
||||
npmPackageName: '@axis-backstage/plugin-statuspage'
|
||||
addedDate: '2024-02-06'
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
var sidebars = require('./sidebars.json');
|
||||
|
||||
module.exports = {
|
||||
ci: {
|
||||
collect: {
|
||||
url: [
|
||||
/** Home */
|
||||
'http://localhost:3000',
|
||||
/** Docs - Getting Started */
|
||||
'http://localhost:3000/docs/getting-started',
|
||||
/** Docs - Software Catalog */
|
||||
'http://localhost:3000/docs/features/software-catalog',
|
||||
/** Docs - Create a Plugin */
|
||||
'http://localhost:3000/docs/plugins/create-a-plugin',
|
||||
/** Docs - Designing for Backstage */
|
||||
'http://localhost:3000/docs/dls/design',
|
||||
/** Blog */
|
||||
'http://localhost:3000/blog',
|
||||
/** Plugins */
|
||||
'http://localhost:3000/plugins',
|
||||
/** Demos */
|
||||
'http://localhost:3000/demos',
|
||||
/** Community */
|
||||
'http://localhost:3000/community',
|
||||
/** Releases */
|
||||
...sidebars.releases['Release Notes'].map(
|
||||
path => `http://localhost:3000/docs/${path}`,
|
||||
),
|
||||
],
|
||||
settings: {
|
||||
onlyCategories: ['accessibility'],
|
||||
output: ['html', 'json'],
|
||||
outputPath: './.lighthouseci/reports',
|
||||
preset: 'desktop',
|
||||
},
|
||||
// refers to root package scripts
|
||||
startServerCommand: 'yarn run start:microsite',
|
||||
startServerReadyPattern: 'compiled successfully',
|
||||
startServerReadyTimeout: 600000,
|
||||
numberOfRuns: 1,
|
||||
},
|
||||
assert: {
|
||||
assertions: {
|
||||
'categories:performance': 'off',
|
||||
'categories:pwa': 'off',
|
||||
'categories:best-practices': 'off',
|
||||
'categories:seo': 'off',
|
||||
'categories:accessibility': ['error', { minScore: 0.95 }],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
+10
-1
@@ -413,7 +413,16 @@
|
||||
"items": [
|
||||
"frontend-system/building-plugins/index",
|
||||
"frontend-system/building-plugins/testing",
|
||||
"frontend-system/building-plugins/extension-types"
|
||||
"frontend-system/building-plugins/extension-types",
|
||||
"frontend-system/building-plugins/built-in-data-refs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Building Apps",
|
||||
"items": [
|
||||
"frontend-system/building-apps/index",
|
||||
"frontend-system/building-apps/built-in-extensions"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -88,8 +88,8 @@ const Community = () => {
|
||||
},
|
||||
{
|
||||
name: 'VMWare',
|
||||
url: 'https://www.vmware.com',
|
||||
logo: 'img/partner-logo-vmware.png',
|
||||
url: 'https://tanzu.vmware.com/',
|
||||
logo: 'img/partner-logo-tanzubybroadcom.png',
|
||||
},
|
||||
];
|
||||
//#endregion
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.4 KiB |
+52
-50
@@ -2701,90 +2701,90 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-arm64@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.3.107"
|
||||
"@swc/core-darwin-arm64@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.4.0"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-x64@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.107"
|
||||
"@swc/core-darwin-x64@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-darwin-x64@npm:1.4.0"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.107"
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.4.0"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.107"
|
||||
"@swc/core-linux-arm64-gnu@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.4.0"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.107"
|
||||
"@swc/core-linux-arm64-musl@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.4.0"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.107"
|
||||
"@swc/core-linux-x64-gnu@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.4.0"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-musl@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.107"
|
||||
"@swc/core-linux-x64-musl@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.4.0"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.107"
|
||||
"@swc/core-win32-arm64-msvc@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.4.0"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.107"
|
||||
"@swc/core-win32-ia32-msvc@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.4.0"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.107":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.107"
|
||||
"@swc/core-win32-x64-msvc@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.4.0"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:^1.3.46":
|
||||
version: 1.3.107
|
||||
resolution: "@swc/core@npm:1.3.107"
|
||||
version: 1.4.0
|
||||
resolution: "@swc/core@npm:1.4.0"
|
||||
dependencies:
|
||||
"@swc/core-darwin-arm64": 1.3.107
|
||||
"@swc/core-darwin-x64": 1.3.107
|
||||
"@swc/core-linux-arm-gnueabihf": 1.3.107
|
||||
"@swc/core-linux-arm64-gnu": 1.3.107
|
||||
"@swc/core-linux-arm64-musl": 1.3.107
|
||||
"@swc/core-linux-x64-gnu": 1.3.107
|
||||
"@swc/core-linux-x64-musl": 1.3.107
|
||||
"@swc/core-win32-arm64-msvc": 1.3.107
|
||||
"@swc/core-win32-ia32-msvc": 1.3.107
|
||||
"@swc/core-win32-x64-msvc": 1.3.107
|
||||
"@swc/core-darwin-arm64": 1.4.0
|
||||
"@swc/core-darwin-x64": 1.4.0
|
||||
"@swc/core-linux-arm-gnueabihf": 1.4.0
|
||||
"@swc/core-linux-arm64-gnu": 1.4.0
|
||||
"@swc/core-linux-arm64-musl": 1.4.0
|
||||
"@swc/core-linux-x64-gnu": 1.4.0
|
||||
"@swc/core-linux-x64-musl": 1.4.0
|
||||
"@swc/core-win32-arm64-msvc": 1.4.0
|
||||
"@swc/core-win32-ia32-msvc": 1.4.0
|
||||
"@swc/core-win32-x64-msvc": 1.4.0
|
||||
"@swc/counter": ^0.1.1
|
||||
"@swc/types": ^0.1.5
|
||||
peerDependencies:
|
||||
@@ -2813,14 +2813,14 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
"@swc/helpers":
|
||||
optional: true
|
||||
checksum: 0dccff50461fb8c0f4af053b70e555c91386cb07aa7657a7328d58e397d15640723587549416d8fa7dcc073ad11b39318146bd50ec4a82345ce2ce39c7ba4c00
|
||||
checksum: cef6459ba707362e88373f1c2c779c760a7fdf06c0123856be005bb012de91cb913b37fb49e485ac551494a1ee46fb6369c5aca9d453e1e5e391a8514c0db185
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/counter@npm:^0.1.1":
|
||||
version: 0.1.1
|
||||
resolution: "@swc/counter@npm:0.1.1"
|
||||
checksum: bb974babd493ba01c0d4a95ab610c3fc15fbf609c08cb0342798e485f57ecc0950abbf84e07124e63c5fe610b492d9a8dd03701d3b9ef7329d9e8bf3cc44980f
|
||||
"@swc/counter@npm:^0.1.1, @swc/counter@npm:^0.1.3":
|
||||
version: 0.1.3
|
||||
resolution: "@swc/counter@npm:0.1.3"
|
||||
checksum: df8f9cfba9904d3d60f511664c70d23bb323b3a0803ec9890f60133954173047ba9bdeabce28cd70ba89ccd3fd6c71c7b0bd58be85f611e1ffbe5d5c18616598
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -11500,12 +11500,14 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"swc-loader@npm:^0.2.3":
|
||||
version: 0.2.4
|
||||
resolution: "swc-loader@npm:0.2.4"
|
||||
version: 0.2.6
|
||||
resolution: "swc-loader@npm:0.2.6"
|
||||
dependencies:
|
||||
"@swc/counter": ^0.1.3
|
||||
peerDependencies:
|
||||
"@swc/core": ^1.2.147
|
||||
webpack: ">=2"
|
||||
checksum: f23bfe8900b35abdcb9910a2749f3c9d66edf5c660afc67fcf7983647eaec322e024d1edd3bd9fd48bd3191eea0616f67b5f8b5f923e3a648fa5b448683c3213
|
||||
checksum: fe90948c02a51bb8ffcff1ce3590e01dc12860b0bb7c9e22052b14fa846ed437781ae265614a5e14344bea22001108780f00a6e350e28c0b3499bc4cd11335fb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
"start-backend": "yarn workspace example-backend start",
|
||||
"start:next": "yarn workspace example-app-next start",
|
||||
"start-backend:next": "yarn workspace example-backend-next start",
|
||||
"start:microsite": "cd microsite/ && yarn start",
|
||||
"build:backend": "yarn workspace example-backend build",
|
||||
"build:all": "backstage-cli repo build --all",
|
||||
"build:api-reports": "yarn build:api-reports:only --tsc",
|
||||
"build:api-reports:only": "backstage-repo-tools api-reports --allow-warnings 'packages/core-components,plugins/+(catalog|catalog-import|git-release-manager|jenkins|kubernetes)' -o ae-wrong-input-file-type --validate-release-tags",
|
||||
"build:knip-reports": "backstage-repo-tools knip-reports",
|
||||
"build:api-docs": "LANG=en_EN yarn build:api-reports --docs --exclude 'plugins/@(adr|adr-backend|adr-common|airbrake|airbrake-backend|allure|analytics-module-ga|analytics-module-ga4|analytics-module-newrelic-browser|apache-airflow|api-docs|api-docs-module-protoc-gen-doc|apollo-explorer|app-visualizer|azure-devops|azure-devops-backend|azure-devops-common|azure-sites|azure-sites-backend|azure-sites-common|badges|badges-backend|bazaar|bazaar-backend|bitbucket-cloud-common|bitrise|catalog-graph|catalog-graphql|catalog-import|catalog-unprocessed-entities|cicd-statistics|cicd-statistics-module-gitlab|circleci|cloudbuild|code-climate|code-coverage|code-coverage-backend|codescene|config-schema|cost-insights|cost-insights-common|dynatrace|entity-feedback|entity-feedback-backend|entity-feedback-common|entity-validation|example-todo-list|example-todo-list-backend|example-todo-list-common|firehydrant|fossa|gcalendar|gcp-projects|git-release-manager|github-actions|github-deployments|github-issues|github-pull-requests-board|gitops-profiles|gocd|graphiql|graphql-backend|graphql-voyager|ilert|jenkins|jenkins-backend|jenkins-common|kafka|kafka-backend|lighthouse|lighthouse-backend|lighthouse-common|linguist|linguist-backend|linguist-common|microsoft-calendar|newrelic|newrelic-dashboard|nomad|nomad-backend|octopus-deploy|opencost|pagerduty|periskop|periskop-backend|playlist|playlist-backend|playlist-common|proxy-backend|puppetdb|rollbar|rollbar-backend|sentry|shortcuts|splunk-on-call|stack-overflow|stack-overflow-backend|stackstorm|tech-radar|tech-radar-2|todo|todo-backend|xcmetrics)'",
|
||||
"build:plugins-report": "node ./scripts/build-plugins-report",
|
||||
"tsc": "tsc",
|
||||
@@ -43,6 +45,10 @@
|
||||
"prepare": "husky",
|
||||
"postinstall": "husky || true"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*",
|
||||
@@ -86,6 +92,7 @@
|
||||
"eslint-plugin-testing-library": "^6.0.0",
|
||||
"fs-extra": "10.1.0",
|
||||
"husky": "^9.0.0",
|
||||
"knip": "^4.3.1",
|
||||
"lint-staged": "^15.0.0",
|
||||
"minimist": "^1.2.5",
|
||||
"node-gyp": "^10.0.0",
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:------------|:-------------|
|
||||
| msw | package.json |
|
||||
| cross-fetch | package.json |
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (64)
|
||||
|
||||
| Name | Location |
|
||||
|:-------------------------------------------------|:-------------|
|
||||
| lodash | package.json |
|
||||
| history | package.json |
|
||||
| react-use | package.json |
|
||||
| @octokit/rest | package.json |
|
||||
| zen-observable | package.json |
|
||||
| @material-ui/lab | package.json |
|
||||
| @backstage/theme | package.json |
|
||||
| @backstage/plugin-org | package.json |
|
||||
| @backstage/plugin-adr | package.json |
|
||||
| @backstage/plugin-todo | package.json |
|
||||
| @backstage/plugin-gocd | package.json |
|
||||
| app-next-example-plugin | package.json |
|
||||
| @backstage/plugin-kafka | package.json |
|
||||
| @backstage/app-defaults | package.json |
|
||||
| @backstage/plugin-sentry | package.json |
|
||||
| @backstage/plugin-search | package.json |
|
||||
| @backstage/plugin-badges | package.json |
|
||||
| @backstage/catalog-model | package.json |
|
||||
| @backstage/plugin-rollbar | package.json |
|
||||
| @backstage/plugin-jenkins | package.json |
|
||||
| @backstage/plugin-explore | package.json |
|
||||
| @backstage/plugin-catalog | package.json |
|
||||
| @circleci/backstage-plugin | package.json |
|
||||
| @backstage/plugin-puppetdb | package.json |
|
||||
| @backstage/plugin-playlist | package.json |
|
||||
| @backstage/plugin-newrelic | package.json |
|
||||
| @backstage/plugin-linguist | package.json |
|
||||
| @backstage/plugin-devtools | package.json |
|
||||
| @backstage/plugin-api-docs | package.json |
|
||||
| @backstage/plugin-airbrake | package.json |
|
||||
| @backstage/plugin-shortcuts | package.json |
|
||||
| @backstage/plugin-dynatrace | package.json |
|
||||
| @backstage/plugin-stackstorm | package.json |
|
||||
| @backstage/plugin-scaffolder | package.json |
|
||||
| @backstage/plugin-lighthouse | package.json |
|
||||
| @backstage/plugin-kubernetes | package.json |
|
||||
| @backstage/plugin-cloudbuild | package.json |
|
||||
| @backstage/plugin-azure-sites | package.json |
|
||||
| @backstage/plugin-search-react | package.json |
|
||||
| @backstage/plugin-gcp-projects | package.json |
|
||||
| @backstage/plugin-azure-devops | package.json |
|
||||
| @backstage/plugin-tech-insights | package.json |
|
||||
| @backstage/plugin-search-common | package.json |
|
||||
| @backstage/plugin-cost-insights | package.json |
|
||||
| @backstage/plugin-code-coverage | package.json |
|
||||
| @backstage/plugin-catalog-react | package.json |
|
||||
| @backstage/plugin-catalog-graph | package.json |
|
||||
| @backstage/plugin-techdocs-react | package.json |
|
||||
| @backstage/plugin-octopus-deploy | package.json |
|
||||
| @backstage/plugin-github-actions | package.json |
|
||||
| @backstage/plugin-catalog-common | package.json |
|
||||
| @backstage/plugin-apache-airflow | package.json |
|
||||
| @backstage/plugin-linguist-common | package.json |
|
||||
| @backstage/plugin-entity-feedback | package.json |
|
||||
| @backstage/plugin-scaffolder-react | package.json |
|
||||
| @backstage/plugin-permission-react | package.json |
|
||||
| @roadiehq/backstage-plugin-travis-ci | package.json |
|
||||
| @roadiehq/backstage-plugin-buildkite | package.json |
|
||||
| @backstage/plugin-newrelic-dashboard | package.json |
|
||||
| @oriflame/backstage-plugin-score-card | package.json |
|
||||
| @roadiehq/backstage-plugin-github-insights | package.json |
|
||||
| @backstage/plugin-catalog-unprocessed-entities | package.json |
|
||||
| @roadiehq/backstage-plugin-github-pull-requests | package.json |
|
||||
| @backstage/plugin-techdocs-module-addons-contrib | package.json |
|
||||
|
||||
## Unused devDependencies (6)
|
||||
|
||||
| Name | Location |
|
||||
|:----------------------------|:-------------|
|
||||
| cross-env | package.json |
|
||||
| @types/jquery | package.json |
|
||||
| @testing-library/dom | package.json |
|
||||
| @types/zen-observable | package.json |
|
||||
| @testing-library/react | package.json |
|
||||
| @testing-library/user-event | package.json |
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
"name": "example-app-next",
|
||||
"version": "0.0.6-next.2",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/app-next"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (15)
|
||||
|
||||
| Name | Location |
|
||||
|:----------------------------------|:-------------|
|
||||
| vite | package.json |
|
||||
| history | package.json |
|
||||
| react-router | package.json |
|
||||
| @octokit/rest | package.json |
|
||||
| zen-observable | package.json |
|
||||
| vite-plugin-html | package.json |
|
||||
| @material-ui/lab | package.json |
|
||||
| @backstage/theme | package.json |
|
||||
| @vitejs/plugin-react | package.json |
|
||||
| vite-plugin-node-polyfills | package.json |
|
||||
| @backstage/plugin-airbrake | package.json |
|
||||
| @backstage/frontend-app-api | package.json |
|
||||
| @backstage/plugin-azure-sites | package.json |
|
||||
| @backstage/plugin-search-common | package.json |
|
||||
| @backstage/plugin-linguist-common | package.json |
|
||||
|
||||
## Unused devDependencies (5)
|
||||
|
||||
| Name | Location |
|
||||
|:----------------------------|:-------------|
|
||||
| cross-env | package.json |
|
||||
| @types/jquery | package.json |
|
||||
| @testing-library/dom | package.json |
|
||||
| @types/zen-observable | package.json |
|
||||
| @testing-library/user-event | package.json |
|
||||
|
||||
## Unlisted dependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:------------|:---------------------------------------------------------|
|
||||
| @rjsf/utils | src/components/scaffolder/customScaffolderExtensions.tsx |
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:------------------|:-------------|
|
||||
| winston-transport | package.json |
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (3)
|
||||
|
||||
| Name | Location |
|
||||
|:----------------------|:-------------|
|
||||
| mysql2 | package.json |
|
||||
| @types/webpack-env | package.json |
|
||||
| @manypkg/get-packages | package.json |
|
||||
|
||||
## Unused devDependencies (3)
|
||||
|
||||
| Name | Location |
|
||||
|:-------------------|:-------------|
|
||||
| mysql2 | package.json |
|
||||
| better-sqlite3 | package.json |
|
||||
| @types/webpack-env | package.json |
|
||||
|
||||
## Referenced optional peerDependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:---------------------|:-------------|
|
||||
| pg-connection-string | package.json |
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:------------------------------|:-------------|
|
||||
| @backstage/backend-test-utils | package.json |
|
||||
|
||||
@@ -33,10 +33,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-app-api": "workspace:^",
|
||||
"@backstage/backend-common": "workspace:^",
|
||||
"@backstage/backend-plugin-api": "workspace:^"
|
||||
"@backstage/backend-common": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/backend-test-utils": "workspace:^",
|
||||
"@backstage/cli": "workspace:^"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:--------------------------------|:-------------|
|
||||
| @backstage/errors | package.json |
|
||||
| @backstage/plugin-search-common | package.json |
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/backend-dynamic-feature-service"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "node-library"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (7)
|
||||
|
||||
| Name | Location |
|
||||
|:-------------------------------------------------|:-------------|
|
||||
| @backstage/backend-tasks | package.json |
|
||||
| @backstage/plugin-auth-node | package.json |
|
||||
| @backstage/backend-plugin-api | package.json |
|
||||
| @backstage/plugin-permission-node | package.json |
|
||||
| @backstage/plugin-permission-common | package.json |
|
||||
| @backstage/plugin-search-backend-node | package.json |
|
||||
| @backstage/plugin-catalog-backend-module-openapi | package.json |
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:------------------------------|:-------------|
|
||||
| lodash | package.json |
|
||||
| @backstage/backend-plugin-api | package.json |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (5)
|
||||
|
||||
| Name | Location |
|
||||
|:------------------|:-------------|
|
||||
| pg | package.json |
|
||||
| msw | package.json |
|
||||
| mysql2 | package.json |
|
||||
| better-sqlite3 | package.json |
|
||||
| @backstage/errors | package.json |
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (12)
|
||||
|
||||
| Name | Location |
|
||||
|:--------------------------------------------------|:-------------|
|
||||
| pg | package.json |
|
||||
| luxon | package.json |
|
||||
| mysql2 | package.json |
|
||||
| example-app | package.json |
|
||||
| @octokit/rest | package.json |
|
||||
| better-sqlite3 | package.json |
|
||||
| @gitbeaker/node | package.json |
|
||||
| pg-connection-string | package.json |
|
||||
| azure-devops-node-api | package.json |
|
||||
| @backstage/plugin-tech-insights-node | package.json |
|
||||
| @backstage/plugin-azure-sites-common | package.json |
|
||||
| @backstage/plugin-scaffolder-backend-module-rails | package.json |
|
||||
|
||||
## Unused devDependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:---------------------------------|:-------------|
|
||||
| @types/luxon | package.json |
|
||||
| @types/express-serve-static-core | package.json |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:-------------------|:-------------|
|
||||
| @types/json-schema | package.json |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -55,6 +55,14 @@ export interface BackstagePackageJson {
|
||||
registry?: string;
|
||||
};
|
||||
// (undocumented)
|
||||
repository?:
|
||||
| string
|
||||
| {
|
||||
type: string;
|
||||
url: string;
|
||||
directory: string;
|
||||
};
|
||||
// (undocumented)
|
||||
scripts?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:-------|:-------------|
|
||||
| semver | package.json |
|
||||
|
||||
@@ -58,6 +58,14 @@ export interface BackstagePackageJson {
|
||||
registry?: string;
|
||||
};
|
||||
|
||||
repository?:
|
||||
| string
|
||||
| {
|
||||
type: string;
|
||||
url: string;
|
||||
directory: string;
|
||||
};
|
||||
|
||||
dependencies?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (28)
|
||||
|
||||
| Name | Location |
|
||||
|:---------------------------------|:-------------|
|
||||
| util | package.json |
|
||||
| glob | package.json |
|
||||
| buffer | package.json |
|
||||
| sucrase | package.json |
|
||||
| process | package.json |
|
||||
| postcss | package.json |
|
||||
| esbuild | package.json |
|
||||
| @swc/jest | package.json |
|
||||
| @swc/core | package.json |
|
||||
| @svgr/core | package.json |
|
||||
| cross-fetch | package.json |
|
||||
| jest-runtime | package.json |
|
||||
| @swc/helpers | package.json |
|
||||
| replace-in-file | package.json |
|
||||
| jest-css-modules | package.json |
|
||||
| @svgr/plugin-jsx | package.json |
|
||||
| @svgr/plugin-svgo | package.json |
|
||||
| @types/webpack-env | package.json |
|
||||
| eslint-plugin-react | package.json |
|
||||
| terser-webpack-plugin | package.json |
|
||||
| jest-environment-jsdom | package.json |
|
||||
| eslint-plugin-jsx-a11y | package.json |
|
||||
| @sucrase/webpack-loader | package.json |
|
||||
| eslint-plugin-react-hooks | package.json |
|
||||
| eslint-plugin-deprecation | package.json |
|
||||
| eslint-formatter-friendly | package.json |
|
||||
| @spotify/eslint-config-react | package.json |
|
||||
| @typescript-eslint/eslint-plugin | package.json |
|
||||
|
||||
## Unused devDependencies (13)
|
||||
|
||||
| Name | Location |
|
||||
|:----------------------------------------|:-------------|
|
||||
| del | package.json |
|
||||
| ts-node | package.json |
|
||||
| nodemon | package.json |
|
||||
| @types/ejs | package.json |
|
||||
| @types/svgo | package.json |
|
||||
| @backstage/theme | package.json |
|
||||
| @types/http-proxy | package.json |
|
||||
| @backstage/dev-utils | package.json |
|
||||
| @backstage/core-app-api | package.json |
|
||||
| @backstage/core-components | package.json |
|
||||
| @types/terser-webpack-plugin | package.json |
|
||||
| @backstage/backend-plugin-api | package.json |
|
||||
| @types/rollup-plugin-peer-deps-external | package.json |
|
||||
|
||||
## Referenced optional peerDependencies (4)
|
||||
|
||||
| Name | Location |
|
||||
|:---------------------------|:-------------|
|
||||
| vite | package.json |
|
||||
| vite-plugin-html | package.json |
|
||||
| @vitejs/plugin-react | package.json |
|
||||
| vite-plugin-node-polyfills | package.json |
|
||||
|
||||
## Unlisted dependencies (3)
|
||||
|
||||
| Name | Location |
|
||||
|:-------------------|:-------------------------------------------|
|
||||
| prettier | src/commands/migrate/packageLintConfigs.ts |
|
||||
| react-dom/client | src/lib/bundler/hasReactDomClient.ts |
|
||||
| react/package.json | src/lib/bundler/server.ts |
|
||||
|
||||
@@ -22,7 +22,11 @@ import {
|
||||
} from '@backstage/cli-node';
|
||||
import { OptionValues } from 'commander';
|
||||
import fs from 'fs-extra';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import {
|
||||
resolve as resolvePath,
|
||||
join as joinPath,
|
||||
relative as relativePath,
|
||||
} from 'path';
|
||||
import { paths } from '../../lib/paths';
|
||||
|
||||
/**
|
||||
@@ -189,12 +193,64 @@ export function fixSideEffects(pkg: FixablePackage) {
|
||||
pkg.changed = true;
|
||||
}
|
||||
|
||||
export function createRepositoryFieldFixer() {
|
||||
const rootPkg = require(paths.resolveTargetRoot('package.json'));
|
||||
const rootRepoField = rootPkg.repository;
|
||||
if (!rootRepoField) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const rootType = rootRepoField.type || 'git';
|
||||
const rootUrl = rootRepoField.url;
|
||||
const rootDir = rootRepoField.directory || '';
|
||||
|
||||
return (pkg: FixablePackage) => {
|
||||
const expectedPath = joinPath(
|
||||
rootDir,
|
||||
relativePath(paths.targetRoot, pkg.dir),
|
||||
);
|
||||
const repoField = pkg.packageJson.repository;
|
||||
|
||||
if (!repoField || typeof repoField === 'string') {
|
||||
const pkgEntries = Object.entries(pkg.packageJson);
|
||||
pkgEntries.splice(
|
||||
// Place it just above the backstage field
|
||||
pkgEntries.findIndex(([name]) => name === 'backstage'),
|
||||
0,
|
||||
[
|
||||
'repository',
|
||||
{
|
||||
type: rootType,
|
||||
url: rootUrl,
|
||||
directory: expectedPath,
|
||||
},
|
||||
],
|
||||
);
|
||||
pkg.packageJson = Object.fromEntries(pkgEntries) as BackstagePackageJson;
|
||||
pkg.changed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's a type or URL mismatch, leave the field as is
|
||||
if (repoField.type !== rootType || repoField.url !== rootUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (repoField.directory !== expectedPath) {
|
||||
repoField.directory = expectedPath;
|
||||
pkg.changed = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export async function command(opts: OptionValues): Promise<void> {
|
||||
const packages = await readFixablePackages();
|
||||
const fixRepositoryField = createRepositoryFieldFixer();
|
||||
|
||||
for (const pkg of packages) {
|
||||
fixPackageExports(pkg);
|
||||
fixSideEffects(pkg);
|
||||
fixRepositoryField(pkg);
|
||||
}
|
||||
|
||||
if (opts.check) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:--------|:-------------|
|
||||
| ts-node | package.json |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:--------|:-------------|
|
||||
| history | package.json |
|
||||
|
||||
## Unused devDependencies (7)
|
||||
|
||||
| Name | Location |
|
||||
|:-----------------------------|:-------------|
|
||||
| react-router-beta | package.json |
|
||||
| react-router-stable | package.json |
|
||||
| @testing-library/dom | package.json |
|
||||
| react-router-dom-beta | package.json |
|
||||
| react-router-dom-stable | package.json |
|
||||
| @testing-library/user-event | package.json |
|
||||
| @testing-library/react-hooks | package.json |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:--------------|:-------------|
|
||||
| linkifyjs | package.json |
|
||||
| @date-io/core | package.json |
|
||||
|
||||
## Unused devDependencies (4)
|
||||
|
||||
| Name | Location |
|
||||
|:------------------------|:-------------|
|
||||
| cross-fetch | package.json |
|
||||
| @testing-library/dom | package.json |
|
||||
| @types/google-protobuf | package.json |
|
||||
| @backstage/app-defaults | package.json |
|
||||
|
||||
## Unlisted dependencies (3)
|
||||
|
||||
| Name | Location |
|
||||
|:------------------|:--------------------------------------------------------|
|
||||
| csstype | src/components/Lifecycle/Lifecycle.tsx |
|
||||
| copy-to-clipboard | src/components/LogViewer/RealLogViewer.test.tsx |
|
||||
| copy-to-clipboard | src/components/LogViewer/useLogViewerSelection.test.tsx |
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.61",
|
||||
"@react-hookz/web": "^23.0.0",
|
||||
"@react-hookz/web": "^24.0.0",
|
||||
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"@types/react-sparklines": "^1.7.0",
|
||||
"@types/react-text-truncate": "^0.14.0",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:----------------------------|:-------------|
|
||||
| @testing-library/dom | package.json |
|
||||
| @testing-library/user-event | package.json |
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (3)
|
||||
|
||||
| Name | Location |
|
||||
|:----------------------|:-------------|
|
||||
| ts-node | package.json |
|
||||
| nodemon | package.json |
|
||||
| @types/command-exists | package.json |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:-----------------|:-------------|
|
||||
| @backstage/theme | package.json |
|
||||
|
||||
## Unused devDependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:---------------------|:-------------|
|
||||
| @testing-library/dom | package.json |
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Knip report
|
||||
|
||||
## Referenced optional peerDependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:-----------------|:-------------|
|
||||
| @playwright/test | package.json |
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/e2e-test-utils"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "node-library"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (3)
|
||||
|
||||
| Name | Location |
|
||||
|:-----------------|:-------------|
|
||||
| ts-node | package.json |
|
||||
| nodemon | package.json |
|
||||
| @types/puppeteer | package.json |
|
||||
|
||||
@@ -71,6 +71,20 @@ export async function run() {
|
||||
env: { ...process.env, CI: undefined },
|
||||
});
|
||||
|
||||
await switchToReact17(appDir);
|
||||
|
||||
print(`Running 'yarn install' to install React 17`);
|
||||
await runPlain(['yarn', 'install'], { cwd: appDir });
|
||||
|
||||
print(`Running 'yarn tsc' with React 17`);
|
||||
await runPlain(['yarn', 'tsc'], { cwd: appDir });
|
||||
|
||||
print(`Running 'yarn test:e2e' with React 17`);
|
||||
await runPlain(['yarn', 'test:e2e'], {
|
||||
cwd: appDir,
|
||||
env: { ...process.env, CI: undefined },
|
||||
});
|
||||
|
||||
if (
|
||||
Boolean(process.env.POSTGRES_USER) ||
|
||||
Boolean(process.env.MYSQL_CONNECTION)
|
||||
@@ -393,6 +407,35 @@ async function createPlugin(options: {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the entire project to use React 17
|
||||
*/
|
||||
async function switchToReact17(appDir: string) {
|
||||
const rootPkg = await fs.readJson(resolvePath(appDir, 'package.json'));
|
||||
rootPkg.resolutions = {
|
||||
...(rootPkg.resolutions || {}),
|
||||
react: '^17.0.0',
|
||||
'react-dom': '^17.0.0',
|
||||
'@types/react': '^17.0.0',
|
||||
'@types/react-dom': '^17.0.0',
|
||||
};
|
||||
await fs.writeJson(resolvePath(appDir, 'package.json'), rootPkg, {
|
||||
spaces: 2,
|
||||
});
|
||||
|
||||
await fs.writeFile(
|
||||
resolvePath(appDir, 'packages/app/src/index.tsx'),
|
||||
`import '@backstage/cli/asset-types';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
`,
|
||||
'utf8',
|
||||
);
|
||||
}
|
||||
|
||||
/** Drops PG databases */
|
||||
async function dropDB(database: string, client: string) {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Knip report
|
||||
|
||||
## Unlisted dependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:-------|:-------------------------------|
|
||||
| estree | lib/visitImports.js |
|
||||
| estree | rules/no-undeclared-imports.js |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/frontend-app-api"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "web-library"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (3)
|
||||
|
||||
| Name | Location |
|
||||
|:---------------------------|:-------------|
|
||||
| lodash | package.json |
|
||||
| @material-ui/core | package.json |
|
||||
| @backstage/core-components | package.json |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/frontend-test-utils"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "web-library"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:----------------------------------|:-------------|
|
||||
| @backstage/errors | package.json |
|
||||
| @aws-sdk/credential-provider-node | package.json |
|
||||
|
||||
## Unused devDependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:-------------------------|:-------------|
|
||||
| @backstage/test-utils | package.json |
|
||||
| @backstage/config-loader | package.json |
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (2)
|
||||
|
||||
| Name | Location |
|
||||
|:---------------------|:-------------|
|
||||
| msw | package.json |
|
||||
| @testing-library/dom | package.json |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Knip report
|
||||
|
||||
@@ -15,6 +15,7 @@ Commands:
|
||||
api-reports [options] [paths...]
|
||||
type-deps
|
||||
generate-catalog-info [options]
|
||||
knip-reports [options] [paths...]
|
||||
package [command]
|
||||
repo [command]
|
||||
help [command]
|
||||
@@ -49,6 +50,16 @@ Options:
|
||||
-h, --help
|
||||
```
|
||||
|
||||
### `backstage-repo-tools knip-reports`
|
||||
|
||||
```
|
||||
Usage: backstage-repo-tools knip-reports [options] [paths...]
|
||||
|
||||
Options:
|
||||
--ci
|
||||
-h, --help
|
||||
```
|
||||
|
||||
### `backstage-repo-tools package`
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Knip report
|
||||
|
||||
## Unused dependencies (6)
|
||||
|
||||
| Name | Location |
|
||||
|:------------------------------------|:-------------|
|
||||
| glob | package.json |
|
||||
| ts-node | package.json |
|
||||
| is-glob | package.json |
|
||||
| @stoplight/spectral-runtime | package.json |
|
||||
| @stoplight/spectral-functions | package.json |
|
||||
| @openapitools/openapi-generator-cli | package.json |
|
||||
|
||||
## Unused devDependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:---------------|:-------------|
|
||||
| @types/is-glob | package.json |
|
||||
|
||||
## Referenced optional peerDependencies (1)
|
||||
|
||||
| Name | Location |
|
||||
|:---------|:-------------|
|
||||
| prettier | package.json |
|
||||
|
||||
@@ -16,37 +16,36 @@
|
||||
|
||||
import { groupBy } from 'lodash';
|
||||
import {
|
||||
resolve as resolvePath,
|
||||
relative as relativePath,
|
||||
basename,
|
||||
join,
|
||||
relative as relativePath,
|
||||
resolve as resolvePath,
|
||||
} from 'path';
|
||||
import { execFile } from 'child_process';
|
||||
import fs from 'fs-extra';
|
||||
import {
|
||||
CompilerState,
|
||||
Extractor,
|
||||
ExtractorConfig,
|
||||
CompilerState,
|
||||
ExtractorLogLevel,
|
||||
ExtractorMessage,
|
||||
} from '@microsoft/api-extractor';
|
||||
import { Program } from 'typescript';
|
||||
import {
|
||||
DocNode,
|
||||
IDocNodeContainerParameters,
|
||||
TSDocTagSyntaxKind,
|
||||
TSDocConfiguration,
|
||||
Standardization,
|
||||
DocBlockTag,
|
||||
DocPlainText,
|
||||
DocLinkTag,
|
||||
DocNode,
|
||||
DocPlainText,
|
||||
IDocNodeContainerParameters,
|
||||
Standardization,
|
||||
TSDocConfiguration,
|
||||
TSDocTagSyntaxKind,
|
||||
} from '@microsoft/tsdoc';
|
||||
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
|
||||
import {
|
||||
ApiPackage,
|
||||
ApiModel,
|
||||
ApiItem,
|
||||
ApiItemKind,
|
||||
ApiModel,
|
||||
ApiPackage,
|
||||
} from '@microsoft/api-extractor-model';
|
||||
import {
|
||||
IMarkdownDocumenterOptions,
|
||||
@@ -64,6 +63,7 @@ import { AstDeclaration } from '@microsoft/api-extractor/lib/analyzer/AstDeclara
|
||||
import { paths as cliPaths } from '../../lib/paths';
|
||||
import minimatch from 'minimatch';
|
||||
import { getPackageExportNames } from '../../lib/entryPoints';
|
||||
import { createBinRunner } from '../util';
|
||||
|
||||
const tmpDir = cliPaths.resolveTargetRoot(
|
||||
'./node_modules/.cache/api-extractor',
|
||||
@@ -290,10 +290,10 @@ function logApiReportInstructions() {
|
||||
'*************************************************************************************',
|
||||
);
|
||||
console.log(
|
||||
'* You have uncommitted changes to the public API of a package. *',
|
||||
'* You have uncommitted changes to the public API or reports of a package. *',
|
||||
);
|
||||
console.log(
|
||||
'* To solve this, run `yarn build:api-reports` and commit all api-report.md changes. *',
|
||||
'* To solve this, run `yarn build:api-reports` and commit all md file changes. *',
|
||||
);
|
||||
console.log(
|
||||
'*************************************************************************************',
|
||||
@@ -1227,31 +1227,6 @@ export async function categorizePackageDirs(packageDirs: string[]) {
|
||||
return { tsPackageDirs, cliPackageDirs };
|
||||
}
|
||||
|
||||
function createBinRunner(cwd: string, path: string) {
|
||||
return async (...command: string[]) =>
|
||||
new Promise<string>((resolve, reject) => {
|
||||
execFile(
|
||||
'node',
|
||||
[path, ...command],
|
||||
{
|
||||
cwd,
|
||||
shell: true,
|
||||
timeout: 60000,
|
||||
maxBuffer: 1024 * 1024,
|
||||
},
|
||||
(err, stdout, stderr) => {
|
||||
if (err) {
|
||||
reject(new Error(`${err.message}\n${stderr}`));
|
||||
} else if (stderr) {
|
||||
reject(new Error(`Command printed error output: ${stderr}`));
|
||||
} else {
|
||||
resolve(stdout);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function parseHelpPage(helpPageContent: string) {
|
||||
const [, usage] = helpPageContent.match(/^\s*Usage: (.*)$/im) ?? [];
|
||||
const lines = helpPageContent.split(/\r?\n/);
|
||||
@@ -1443,3 +1418,66 @@ export async function runCliExtraction({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface KnipExtractionOptions {
|
||||
packageDirs: string[];
|
||||
isLocalBuild: boolean;
|
||||
}
|
||||
|
||||
export async function runKnipReports({
|
||||
packageDirs,
|
||||
isLocalBuild,
|
||||
}: KnipExtractionOptions) {
|
||||
const knipDir = cliPaths.resolveTargetRoot('./node_modules/knip/bin/');
|
||||
|
||||
for (const packageDir of packageDirs) {
|
||||
console.log(`## Processing ${packageDir}`);
|
||||
const fullDir = cliPaths.resolveTargetRoot(packageDir);
|
||||
const reportPath = resolvePath(fullDir, 'knip-report.md');
|
||||
const run = createBinRunner(fullDir, '');
|
||||
|
||||
const report = await run(
|
||||
`${knipDir}/knip.js`,
|
||||
`--directory ${fullDir}`, // Run in the package directory
|
||||
'--no-exit-code', // Removing this will end the process in case there are findings by knip
|
||||
'--no-progress', // Remove unnecessary debugging from output
|
||||
// TODO: Add more checks when dependencies start to look ok, see https://knip.dev/reference/cli#--include
|
||||
'--include dependencies,unlisted',
|
||||
'--reporter markdown',
|
||||
);
|
||||
|
||||
const existingReport = await fs
|
||||
.readFile(reportPath, 'utf8')
|
||||
.catch(error => {
|
||||
if (error.code === 'ENOENT') {
|
||||
return undefined;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
|
||||
if (existingReport !== report) {
|
||||
if (isLocalBuild) {
|
||||
console.warn(`Knip report changed for ${packageDir}`);
|
||||
await fs.writeFile(reportPath, report);
|
||||
} else {
|
||||
logApiReportInstructions();
|
||||
|
||||
if (existingReport) {
|
||||
console.log('');
|
||||
console.log(
|
||||
`The conflicting file is ${relativePath(
|
||||
cliPaths.targetRoot,
|
||||
reportPath,
|
||||
)}, expecting the following content:`,
|
||||
);
|
||||
console.log('');
|
||||
|
||||
console.log(report);
|
||||
|
||||
logApiReportInstructions();
|
||||
}
|
||||
throw new Error(`Knip report changed for ${packageDir}, `);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ import * as pathsLib from '../../lib/paths';
|
||||
|
||||
import {
|
||||
buildDocs,
|
||||
runCliExtraction,
|
||||
runApiExtraction,
|
||||
categorizePackageDirs,
|
||||
runApiExtraction,
|
||||
runCliExtraction,
|
||||
} from './api-extractor';
|
||||
|
||||
import { buildApiReports } from './api-reports';
|
||||
@@ -43,6 +43,7 @@ jest.mock('./api-extractor', () => ({
|
||||
runApiExtraction: jest.fn(),
|
||||
runCliExtraction: jest.fn(),
|
||||
buildDocs: jest.fn(),
|
||||
runKnipReports: jest.fn(),
|
||||
}));
|
||||
|
||||
const projectPaths = pathsLib.paths;
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
import { OptionValues } from 'commander';
|
||||
import {
|
||||
createTemporaryTsConfig,
|
||||
buildDocs,
|
||||
categorizePackageDirs,
|
||||
createTemporaryTsConfig,
|
||||
runApiExtraction,
|
||||
runCliExtraction,
|
||||
buildDocs,
|
||||
} from './api-extractor';
|
||||
import { paths as cliPaths, resolvePackagePaths } from '../../lib/paths';
|
||||
import { generateTypeDeclarations } from './generateTypeDeclarations';
|
||||
@@ -94,6 +94,7 @@ export const buildApiReports = async (paths: string[] = [], opts: Options) => {
|
||||
validateReleaseTags: opts.validateReleaseTags,
|
||||
});
|
||||
}
|
||||
|
||||
if (cliPackageDirs.length > 0) {
|
||||
console.log('# Generating package CLI reports');
|
||||
await runCliExtraction({
|
||||
|
||||
@@ -168,6 +168,17 @@ export function registerCommands(program: Command) {
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
program
|
||||
.command('knip-reports [paths...]')
|
||||
.option('--ci', 'CI run checks that there is no changes on knip reports')
|
||||
.description('Generate a knip report for selected packages')
|
||||
.action(
|
||||
lazy(() =>
|
||||
import('./knip-reports/knip-reports').then(m => m.buildKnipReports),
|
||||
),
|
||||
);
|
||||
|
||||
registerPackageCommand(program);
|
||||
registerRepoCommand(program);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user