Merge remote-tracking branch 'origin/master' into natasha/b2b-auth
Signed-off-by: Mike Lewis <mtlewis@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/errors': patch
|
||||
---
|
||||
|
||||
Deprecate `parseErrorResponse` in favour of `parseErrorResponseBody`. Deprecate `data` field inside `ErrorResponse` in favour of `body`.
|
||||
Rename the error name for unknown errors from `unknown` to `error`.
|
||||
@@ -23,13 +23,13 @@ const {
|
||||
async function getDependencyReleaseLine(changesets, dependenciesUpdated) {
|
||||
if (dependenciesUpdated.length === 0) return '';
|
||||
|
||||
const updatedDepenenciesList = dependenciesUpdated.map(
|
||||
const updatedDependenciesList = dependenciesUpdated.map(
|
||||
dependency => ` - ${dependency.name}@${dependency.newVersion}`,
|
||||
);
|
||||
|
||||
// Return one `Updated dependencies` bullet instead of repeating for each changeset; this
|
||||
// sacrifices the commit shas for brevity.
|
||||
return ['- Updated dependencies', ...updatedDepenenciesList].join('\n');
|
||||
return ['- Updated dependencies', ...updatedDependenciesList].join('\n');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights-backend': patch
|
||||
'@backstage/plugin-tech-insights-backend-module-jsonfc': patch
|
||||
---
|
||||
|
||||
Update README docs to use correct function/parameter names
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Switched to using the standardized JSON error responses for all provider endpoints.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Switch the default test coverage provider from the jest default one to `'v8'`, which provides much better coverage information when using the default Backstage test setup. This is considered a bug fix as the current coverage information is often very inaccurate.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Disable ES transforms in tests transformed by the `jestSucraseTransform.js`. This is not considered a breaking change since all code is already transpiled this way in the development setup.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
DefaultTechDocsCollator is now included in the search backend, and the Search Page updated with the SearchType component that includes the techdocs type
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/cli': patch
|
||||
'@backstage/core-app-api': patch
|
||||
'@backstage/create-app': patch
|
||||
'@backstage/techdocs-common': patch
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
'@backstage/plugin-azure-devops-backend': patch
|
||||
'@backstage/plugin-badges-backend': patch
|
||||
'@backstage/plugin-bazaar-backend': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
'@backstage/plugin-code-coverage-backend': patch
|
||||
'@backstage/plugin-github-actions': patch
|
||||
'@backstage/plugin-jenkins-backend': patch
|
||||
'@backstage/plugin-proxy-backend': patch
|
||||
'@backstage/plugin-rollbar-backend': patch
|
||||
'@backstage/plugin-search-backend': patch
|
||||
'@backstage/plugin-techdocs': patch
|
||||
'@backstage/plugin-techdocs-backend': patch
|
||||
---
|
||||
|
||||
Change default port of backend from 7000 to 7007.
|
||||
|
||||
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
|
||||
|
||||
You can change the port back to 7000 or any other value by providing an `app-config.yaml` with the following values:
|
||||
|
||||
```
|
||||
backend:
|
||||
listen: 0.0.0.0:7123
|
||||
baseUrl: http://localhost:7123
|
||||
```
|
||||
|
||||
More information can be found here: https://backstage.io/docs/conf/writing
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-permission-common': minor
|
||||
---
|
||||
|
||||
Accept configApi rather than enabled flag in PermissionClient constructor.
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
**BREAKING** EntitiesSearchFilter fields have changed.
|
||||
|
||||
EntitiesSearchFilter now has only two fields: `key` and `value`. The `matchValueIn` and `matchValueExists` fields are no longer are supported. Previous filters written using the `matchValueIn` and `matchValueExists` fields can be rewritten as follows:
|
||||
|
||||
Filtering by existence of key only:
|
||||
|
||||
```diff
|
||||
filter: {
|
||||
{
|
||||
key: 'abc',
|
||||
- matchValueExists: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Filtering by key and values:
|
||||
|
||||
```diff
|
||||
filter: {
|
||||
{
|
||||
key: 'abc',
|
||||
- matchValueExists: true,
|
||||
- matchValueIn: ['xyz'],
|
||||
+ values: ['xyz'],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Negation of filters can now be achieved through a `not` object:
|
||||
|
||||
```
|
||||
filter: {
|
||||
not: {
|
||||
key: 'abc',
|
||||
values: ['xyz'],
|
||||
},
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Index User entities by displayName to be able to search by full name. Added displayName (if present) to the 'text' field in the indexed document.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Update the default routes to use id instead of title
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
'@backstage/test-utils': patch
|
||||
---
|
||||
|
||||
The `ApiRegistry` from `@backstage/core-app-api` class has been deprecated and will be removed in a future release. To replace it, we have introduced two new helpers that are exported from `@backstage/test-utils`, namely `TestApiProvider` and `TestApiRegistry`.
|
||||
|
||||
These two new helpers are more tailored for writing tests and development setups, as they allow for partial implementations of each of the APIs.
|
||||
|
||||
When migrating existing code it is typically best to prefer usage of `TestApiProvider` when possible, so for example the following code:
|
||||
|
||||
```tsx
|
||||
render(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.from([
|
||||
[identityApiRef, mockIdentityApi as unknown as IdentityApi]
|
||||
])}
|
||||
>
|
||||
{...}
|
||||
</ApiProvider>
|
||||
)
|
||||
```
|
||||
|
||||
Would be migrated to this:
|
||||
|
||||
```tsx
|
||||
render(
|
||||
<TestApiProvider apis={[[identityApiRef, mockIdentityApi]]}>
|
||||
{...}
|
||||
</TestApiProvider>
|
||||
)
|
||||
```
|
||||
|
||||
In cases where the `ApiProvider` is used in a more standalone way, for example to reuse a set of APIs across multiple tests, the `TestApiRegistry` can be used instead. Note that the `TestApiRegistry` only has a single static factory method, `.from()`, and it is slightly different from the existing `.from()` method on `ApiRegistry` in that it doesn't require the API pairs to be wrapped in an outer array.
|
||||
|
||||
Usage that looks like this:
|
||||
|
||||
```ts
|
||||
const apis = ApiRegistry.with(
|
||||
identityApiRef,
|
||||
mockIdentityApi as unknown as IdentityApi,
|
||||
).with(configApiRef, new ConfigReader({}));
|
||||
```
|
||||
|
||||
OR like this:
|
||||
|
||||
```ts
|
||||
const apis = ApiRegistry.from([
|
||||
[identityApiRef, mockIdentityApi as unknown as IdentityApi],
|
||||
[configApiRef, new ConfigReader({})],
|
||||
]);
|
||||
```
|
||||
|
||||
Would be migrated to this:
|
||||
|
||||
```ts
|
||||
const apis = TestApiRegistry.from(
|
||||
[identityApiRef, mockIdentityApi],
|
||||
[configApiRef, new ConfigReader({})],
|
||||
);
|
||||
```
|
||||
|
||||
If your app is still using the `ApiRegistry` to construct the `apis` for `createApp`, we recommend that you move over to use the new method of supplying API factories instead, using `createApiFactory`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Pin sidebar by default for easier navigation
|
||||
@@ -6,6 +6,8 @@ on:
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
if: github.repository == 'backstage/backstage' # prevent running on forks
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
backstage:
|
||||
image: tugboatqa/node:lts
|
||||
expose: 7000
|
||||
expose: 7007
|
||||
default: true
|
||||
commands:
|
||||
init:
|
||||
@@ -14,4 +14,4 @@ services:
|
||||
- yarn workspace example-app build
|
||||
start:
|
||||
# wget the endpoint. Will retry every 2 seconds. 30 retries = 1m for service to come up. Plenty.
|
||||
- wget -O /dev/null -o /dev/null --tries=30 --timeout=5 --retry-connrefused http://localhost:7000
|
||||
- wget -O /dev/null -o /dev/null --tries=30 --timeout=5 --retry-connrefused http://localhost:7007
|
||||
|
||||
@@ -69,3 +69,5 @@
|
||||
| [Unity](https://unity.com) | [Ted Cordery](https://github.com/TeddyBallGame) | A centralized service catalog with documentation for our service engineers. |
|
||||
| [PicPay](https://www.picpay.com) | [Luis Baroni](https://github.com/lcsbaroni), [Renata Poluceno](https://github.com/renatapoluceno), [PicPay](https://github.com/picpay) | Developer portal for building services throught templates, service catalog with ownership of services, documentation and metrics providing autonomy and visibility for all. |
|
||||
| [Epic Games](https://www.epicgames.com) | [Brian Jung](https://github.com/brian-at-epic), [Jeff Goldian](https://github.com/jeffgoldian-Epic) | Developer Portal: Service Catalog, Documentation, Software Templates and more making our internal teams' lives easier! |
|
||||
| [Globo](https://globo.com) | [Carlos Gusmão](https://github.com/caeugusmao), [Guilherme Vierno](https://github.com/vierno), [Denis Aoki](https://github.com/dnsaoki2), [Maycon Dionisio](https://github.com/MayconDionisio), | Reduce the friction of accessing the information engineers need about Globo's digital services through a coherent and centralized experience. |
|
||||
| [QBE](https://www.qbe.com/) | [Daniel Steel](https://github.com/danielsteelqbe), [Pete Jespers](https://github.com/petejespersqbe) | Developer portal allowing our global teams to explore and create applications, documentation and cloud infrastructure easily and quickly 🚀 |
|
||||
+3
-1
@@ -122,7 +122,9 @@ We use [changesets](https://github.com/atlassian/changesets) to help us prepare
|
||||
|
||||
Any time a patch, minor, or major change aligning to [Semantic Versioning](https://semver.org) is made to any published package in `packages/` or `plugins/`, a changeset should be used. It helps to align your change to the [Backstage stability index](https://backstage.io/docs/overview/stability-index) for the package you are changing, for example, when to provide additional clarity on deprecation or impacting changes which will then be included into CHANGELOGs.
|
||||
|
||||
In general, changesets are not needed for the documentation, build utilities, contributed samples in `contrib/`, or the [example `packages/app`](packages/app).
|
||||
In general, changesets are only needed for changes to packages within `packages/` or `plugins/` directories, and only for the packages that are not marked as `private`. Changesets are also not needed for changes that do not affect the published version of each package, for example changes to tests or in-line source code comments.
|
||||
|
||||
Changesets **are** needed for new packages, as that is what triggers the package to be part of the next release.
|
||||
|
||||
### How to create a changeset
|
||||
|
||||
|
||||
+2
-2
@@ -27,9 +27,9 @@ backend:
|
||||
# See authenticate-api-requests.md in the contrib docs for information on the format
|
||||
# authorization:
|
||||
# secret: ${BACKEND_SECRET}
|
||||
baseUrl: http://localhost:7000
|
||||
baseUrl: http://localhost:7007
|
||||
listen:
|
||||
port: 7000
|
||||
port: 7007
|
||||
database:
|
||||
client: sqlite3
|
||||
connection: ':memory:'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
backend:
|
||||
lighthouseHostname: {{ include "lighthouse.serviceName" . | quote }}
|
||||
listen:
|
||||
port: {{ .Values.appConfig.backend.listen.port | default 7000 }}
|
||||
port: {{ .Values.appConfig.backend.listen.port | default 7007 }}
|
||||
database:
|
||||
client: {{ .Values.appConfig.backend.database.client | quote }}
|
||||
connection:
|
||||
|
||||
@@ -26,7 +26,7 @@ backend:
|
||||
repository: martinaif/backstage-k8s-demo-backend
|
||||
tag: 20210423T1550
|
||||
pullPolicy: IfNotPresent
|
||||
containerPort: 7000
|
||||
containerPort: 7007
|
||||
serviceType: ClusterIP
|
||||
postgresCertMountEnabled: true
|
||||
resources:
|
||||
@@ -96,7 +96,7 @@ appConfig:
|
||||
backend:
|
||||
baseUrl: https://demo.example.com
|
||||
listen:
|
||||
port: 7000
|
||||
port: 7007
|
||||
cors:
|
||||
origin: https://demo.example.com
|
||||
database:
|
||||
|
||||
@@ -9,8 +9,8 @@ docker_name_prefix := backstage-make
|
||||
# to the host computer
|
||||
frontend_port := 3000
|
||||
frontend_host_port := 3000
|
||||
backend_port := 7000
|
||||
backend_host_port := 7000
|
||||
backend_port := 7007
|
||||
backend_host_port := 7007
|
||||
|
||||
# path to this "makefile"
|
||||
my_dir_path = $(dir $(CURDIR)/$(firstword $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
|
||||
@@ -191,10 +191,10 @@ test: check-tests
|
||||
check: check-code check-docs check-type-dependencies check-styles
|
||||
|
||||
# run development instance
|
||||
# BUG: the frontend seems to run on "$(backend_port)" (7000 default).
|
||||
# BUG: the frontend seems to run on "$(backend_port)" (7007 default).
|
||||
# The documentation states "This is going to start two things,
|
||||
# the frontend (:3000) and the backend (:7000)."
|
||||
# However, the frontend seems to end up running on 7000.
|
||||
# the frontend (:3000) and the backend (:7007)."
|
||||
# However, the frontend seems to end up running on 7007.
|
||||
.PHONY: dev
|
||||
dev: build
|
||||
@docker run --rm -it \
|
||||
|
||||
@@ -22,6 +22,6 @@ spec:
|
||||
image: spotify/backstage-backend:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 7000
|
||||
- containerPort: 7007
|
||||
name: backend
|
||||
protocol: TCP
|
||||
|
||||
@@ -63,7 +63,7 @@ backend:
|
||||
pullPolicy: IfNotPresent
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 7000
|
||||
port: 7007
|
||||
ingress:
|
||||
enabled: false
|
||||
annotations:
|
||||
|
||||
@@ -30,6 +30,6 @@ spec:
|
||||
component: backend
|
||||
ports:
|
||||
- name: backend
|
||||
port: 7000
|
||||
port: 7007
|
||||
protocol: TCP
|
||||
targetPort: backend
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:7000",
|
||||
"baseUrl": "http://localhost:7007",
|
||||
"integrationFolder": "./src/integration",
|
||||
"supportFile": "./src/support",
|
||||
"fixturesFolder": "./src/fixtures",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
id: adrs-adr012
|
||||
title: ADR000: Use Luxon.toLocaleString and date/time presets
|
||||
title: ADR012: Use Luxon.toLocaleString and date/time presets
|
||||
description: Architecture Decision Record (ADR) for using Luxon's toLocaleString method and date/time presets for displaying dates and times
|
||||
---
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ name.
|
||||
|
||||
### Test the new provider
|
||||
|
||||
You can `curl -i localhost:7000/api/auth/providerA/start` and which should
|
||||
You can `curl -i localhost:7007/api/auth/providerA/start` and which should
|
||||
provide a `302` redirect with a `Location` header. Paste the url from that
|
||||
header into a web browser and you should be able to trigger the authorization
|
||||
flow.
|
||||
|
||||
@@ -28,7 +28,7 @@ Name your integration and click on the `Create` button.
|
||||
|
||||
Settings for local development:
|
||||
|
||||
- Callback URL: `http://localhost:7000/api/auth/atlassian`
|
||||
- Callback URL: `http://localhost:7007/api/auth/atlassian`
|
||||
- Use rotating refresh tokens
|
||||
- For permissions, you **must** enable `View user profile` for the currently
|
||||
logged-in user, under `User identity API`
|
||||
|
||||
@@ -17,7 +17,7 @@ provider that can authenticate users using OAuth.
|
||||
- Application type: Single Page Web Application
|
||||
4. Click on the Settings tab
|
||||
5. Add under `Application URIs` > `Allowed Callback URLs`:
|
||||
`http://localhost:7000/api/auth/auth0/handler/frame`
|
||||
`http://localhost:7007/api/auth/auth0/handler/frame`
|
||||
6. Click `Save Changes`
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -20,7 +20,7 @@ Click Add Consumer.
|
||||
Settings for local development:
|
||||
|
||||
- Application name: Backstage (or your custom app name)
|
||||
- Callback URL: `http://localhost:7000/api/auth/bitbucket`
|
||||
- Callback URL: `http://localhost:7007/api/auth/bitbucket`
|
||||
- Other are optional
|
||||
- (IMPORTANT) **Permissions: Account - Read, Workspace membership - Read**
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Settings for local development:
|
||||
|
||||
- Application name: Backstage (or your custom app name)
|
||||
- Homepage URL: `http://localhost:3000`
|
||||
- Authorization callback URL: `http://localhost:7000/api/auth/github`
|
||||
- Authorization callback URL: `http://localhost:7007/api/auth/github`
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ should point to your Backstage backend auth handler.
|
||||
Settings for local development:
|
||||
|
||||
- Name: Backstage (or your custom app name)
|
||||
- Redirect URI: `http://localhost:7000/api/auth/gitlab/handler/frame`
|
||||
- Redirect URI: `http://localhost:7007/api/auth/gitlab/handler/frame`
|
||||
- Scopes: read_user
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -26,7 +26,7 @@ To support Google authentication, you must create OAuth credentials:
|
||||
- `Name`: Backstage (or your custom app name)
|
||||
- `Authorized JavaScript origins`: http://localhost:3000
|
||||
- `Authorized Redirect URIs`:
|
||||
http://localhost:7000/api/auth/google/handler/frame
|
||||
http://localhost:7007/api/auth/google/handler/frame
|
||||
7. Click Create
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -21,7 +21,7 @@ To support Azure authentication, you must create an App Registration:
|
||||
4. Register an application
|
||||
- Name: Backstage (or your custom app name)
|
||||
- Redirect URI: Web >
|
||||
`http://localhost:7000/api/auth/microsoft/handler/frame`
|
||||
`http://localhost:7007/api/auth/microsoft/handler/frame`
|
||||
5. Navigate to **Certificates & secrets > New client secret** to create a secret
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -22,8 +22,8 @@ To add Okta authentication, you must create an Application from Okta:
|
||||
- `App integration name`: `Backstage` (or your custom app name)
|
||||
- `Grant type`: `Authorization Code` & `Refresh Token`
|
||||
- `Sign-in redirect URIs`:
|
||||
`http://localhost:7000/api/auth/okta/handler/frame`
|
||||
- `Sign-out redirect URIs`: `http://localhost:7000`
|
||||
`http://localhost:7007/api/auth/okta/handler/frame`
|
||||
- `Sign-out redirect URIs`: `http://localhost:7007`
|
||||
- `Controlled access`: (select as appropriate)
|
||||
- Click Save
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ To support OneLogin authentication, you must create an Application:
|
||||
3. Click Save
|
||||
4. Go to the Configuration tab for the Application and set:
|
||||
- `Login Url`: `http://localhost:3000`
|
||||
- `Redirect URIs`: `http://localhost:7000/api/auth/onelogin/handler/frame`
|
||||
- `Redirect URIs`: `http://localhost:7007/api/auth/onelogin/handler/frame`
|
||||
5. Click Save
|
||||
6. Go to the SSO tab for the Application and set:
|
||||
- `Token Endpoint` > `Authentication Method`: `POST`
|
||||
|
||||
@@ -16,8 +16,8 @@ app:
|
||||
baseUrl: http://localhost:3000
|
||||
|
||||
backend:
|
||||
listen: 0.0.0.0:7000
|
||||
baseUrl: http://localhost:7000
|
||||
listen: 0.0.0.0:7007
|
||||
baseUrl: http://localhost:7007
|
||||
|
||||
organization:
|
||||
name: CNCF
|
||||
|
||||
@@ -105,11 +105,11 @@ docker image build . -f packages/backend/Dockerfile --tag backstage
|
||||
To try out the image locally you can run the following:
|
||||
|
||||
```sh
|
||||
docker run -it -p 7000:7000 backstage
|
||||
docker run -it -p 7007:7007 backstage
|
||||
```
|
||||
|
||||
You should then start to get logs in your terminal, and then you can open your
|
||||
browser at `http://localhost:7000`
|
||||
browser at `http://localhost:7007`
|
||||
|
||||
## Multi-stage Build
|
||||
|
||||
@@ -208,11 +208,11 @@ docker image build -t backstage .
|
||||
To try out the image locally you can run the following:
|
||||
|
||||
```sh
|
||||
docker run -it -p 7000:7000 backstage
|
||||
docker run -it -p 7007:7007 backstage
|
||||
```
|
||||
|
||||
You should then start to get logs in your terminal, and then you can open your
|
||||
browser at `http://localhost:7000`
|
||||
browser at `http://localhost:7007`
|
||||
|
||||
## Separate Frontend
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ spec:
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 7000
|
||||
containerPort: 7007
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: postgres-secrets
|
||||
@@ -361,11 +361,11 @@ spec:
|
||||
# https://backstage.io/docs/plugins/observability#health-checks
|
||||
# readinessProbe:
|
||||
# httpGet:
|
||||
# port: 7000
|
||||
# port: 7007
|
||||
# path: /healthcheck
|
||||
# livenessProbe:
|
||||
# httpGet:
|
||||
# port: 7000
|
||||
# port: 7007
|
||||
# path: /healthcheck
|
||||
```
|
||||
|
||||
@@ -449,7 +449,7 @@ spec:
|
||||
```
|
||||
|
||||
The `selector` here is telling the Service which pods to target, and the port
|
||||
mapping translates normal HTTP port 80 to the backend http port (7000) on the
|
||||
mapping translates normal HTTP port 80 to the backend http port (7007) on the
|
||||
pod.
|
||||
|
||||
Apply this Service to the Kubernetes cluster:
|
||||
@@ -464,10 +464,10 @@ reveal**_, you can forward a local port to the service:
|
||||
|
||||
```shell
|
||||
$ sudo kubectl port-forward --namespace=backstage svc/backstage 80:80
|
||||
Forwarding from 127.0.0.1:80 -> 7000
|
||||
Forwarding from 127.0.0.1:80 -> 7007
|
||||
```
|
||||
|
||||
This shows port 7000 since `port-forward` doesn't _really_ support services, so
|
||||
This shows port 7007 since `port-forward` doesn't _really_ support services, so
|
||||
it cheats by looking up the first pod for a service and connecting to the mapped
|
||||
pod port.
|
||||
|
||||
@@ -486,7 +486,7 @@ organization:
|
||||
backend:
|
||||
baseUrl: http://localhost
|
||||
listen:
|
||||
port: 7000
|
||||
port: 7007
|
||||
cors:
|
||||
origin: http://localhost
|
||||
```
|
||||
|
||||
@@ -138,11 +138,11 @@ techdocs:
|
||||
# (Optional and Legacy) TechDocs makes API calls to techdocs-backend using this URL. e.g. get docs of an entity, get metadata, etc.
|
||||
# You don't have to specify this anymore.
|
||||
|
||||
requestUrl: http://localhost:7000/api/techdocs
|
||||
requestUrl: http://localhost:7007/api/techdocs
|
||||
|
||||
# (Optional and Legacy) Just another route in techdocs-backend where TechDocs requests the static files from. This URL uses an HTTP middleware
|
||||
# to serve files from either a local directory or an External storage provider.
|
||||
# You don't have to specify this anymore.
|
||||
|
||||
storageUrl: http://localhost:7000/api/techdocs/static/docs
|
||||
storageUrl: http://localhost:7007/api/techdocs/static/docs
|
||||
```
|
||||
|
||||
@@ -43,7 +43,7 @@ the project root. Make sure you have run the above mentioned commands first.
|
||||
$ yarn dev
|
||||
```
|
||||
|
||||
This is going to start two things, the frontend (:3000) and the backend (:7000).
|
||||
This is going to start two things, the frontend (:3000) and the backend (:7007).
|
||||
|
||||
This should open a local instance of Backstage in your browser, otherwise open
|
||||
one of the URLs printed in the terminal.
|
||||
|
||||
@@ -37,7 +37,7 @@ guide to do a repository-based installation.
|
||||
- `docker` [installation](https://docs.docker.com/engine/install/)
|
||||
- `git` [installation](https://github.com/git-guides/install-git)
|
||||
- If the system is not directly accessible over your network, the following
|
||||
ports need to be opened: 3000, 7000
|
||||
ports need to be opened: 3000, 7007
|
||||
|
||||
### Create your Backstage App
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ cd packages/backend
|
||||
yarn start
|
||||
```
|
||||
|
||||
That starts up a backend instance on port 7000.
|
||||
That starts up a backend instance on port 7007.
|
||||
|
||||
In the other window, we will then launch the frontend. This command is run from
|
||||
the project root, not inside the backend directory.
|
||||
|
||||
@@ -21,7 +21,7 @@ externalDocs:
|
||||
description: Backstage official documentation
|
||||
url: https://github.com/backstage/backstage/blob/master/docs/README.md
|
||||
servers:
|
||||
- url: http://localhost:7000/api/auth/
|
||||
- url: http://localhost:7007/api/auth/
|
||||
tags:
|
||||
- name: provider
|
||||
description: List of endpoints per provider
|
||||
|
||||
@@ -44,11 +44,11 @@ cd plugins/carmen-backend
|
||||
yarn start
|
||||
```
|
||||
|
||||
This will think for a bit, and then say `Listening on :7000`. In a different
|
||||
This will think for a bit, and then say `Listening on :7007`. In a different
|
||||
terminal window, now run
|
||||
|
||||
```sh
|
||||
curl localhost:7000/carmen/health
|
||||
curl localhost:7007/carmen/health
|
||||
```
|
||||
|
||||
This should return `{"status":"ok"}`. Success! Press `Ctrl + c` to kill it
|
||||
@@ -107,7 +107,7 @@ root), you should be able to fetch data from it.
|
||||
|
||||
```sh
|
||||
# Note the extra /api here
|
||||
curl localhost:7000/api/carmen/health
|
||||
curl localhost:7007/api/carmen/health
|
||||
```
|
||||
|
||||
This should return `{"status":"ok"}` like before. Success!
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@
|
||||
"packages": ["packages/*", "plugins/*"],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "0.1.0"
|
||||
"version": "0.0.0"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Starting Phase 2: The Service Catalog
|
||||
title: 'Starting Phase 2: The Service Catalog'
|
||||
author: Stefan Ålund, Spotify
|
||||
authorURL: http://twitter.com/stalund
|
||||
authorImageURL: https://pbs.twimg.com/profile_images/121166861/6919c047c0d0edaace78c3009b28e917-user-full-200-130.generated_400x400.jpg
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Announcing TechDocs: Spotify’s docs-like-code plugin for Backstage
|
||||
title: 'Announcing TechDocs: Spotify’s docs-like-code plugin for Backstage'
|
||||
author: Gary Niemen, Spotify
|
||||
authorURL: https://github.com/garyniemen
|
||||
---
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: New Cost Insights plugin: The engineer’s solution to taming cloud costs
|
||||
title: 'New Cost Insights plugin: The engineer’s solution to taming cloud costs'
|
||||
author: Janisa Anandamohan, Spotify
|
||||
authorURL: https://twitter.com/janisa_a
|
||||
---
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: New Backstage feature: Kubernetes for Service owners
|
||||
title: 'New Backstage feature: Kubernetes for Service owners'
|
||||
author: Matthew Clarke, Spotify
|
||||
authorURL: https://github.com/mclarke47
|
||||
---
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Announcing the Backstage Search platform: a customizable search tool built just for you
|
||||
title: 'Announcing the Backstage Search platform: a customizable search tool built just for you'
|
||||
author: Emma Indal, Spotify
|
||||
authorURL: https://www.linkedin.com/in/emma-indal
|
||||
---
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const API_ENDPOINT = 'http://localhost:7000/api/search/query';
|
||||
const API_ENDPOINT = 'http://localhost:7007/api/search/query';
|
||||
|
||||
describe('SearchPage', () => {
|
||||
describe('Given a search context with a term, results, and filter values', () => {
|
||||
|
||||
@@ -27,14 +27,14 @@ describe('App', () => {
|
||||
data: {
|
||||
app: {
|
||||
title: 'Test',
|
||||
support: { url: 'http://localhost:7000/support' },
|
||||
support: { url: 'http://localhost:7007/support' },
|
||||
},
|
||||
backend: { baseUrl: 'http://localhost:7000' },
|
||||
backend: { baseUrl: 'http://localhost:7007' },
|
||||
lighthouse: {
|
||||
baseUrl: 'http://localhost:3003',
|
||||
},
|
||||
techdocs: {
|
||||
storageUrl: 'http://localhost:7000/api/techdocs/static/docs',
|
||||
storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
|
||||
},
|
||||
},
|
||||
context: 'test',
|
||||
|
||||
@@ -37,7 +37,7 @@ export class SingleHostDiscovery implements PluginEndpointDiscovery {
|
||||
* for the internal one.
|
||||
*
|
||||
* The basePath defaults to `/api`, meaning the default full internal
|
||||
* path for the `catalog` plugin will be `http://localhost:7000/api/catalog`.
|
||||
* path for the `catalog` plugin will be `http://localhost:7007/api/catalog`.
|
||||
*/
|
||||
static fromConfig(config: Config, options?: { basePath?: string }) {
|
||||
const basePath = options?.basePath ?? '/api';
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
} from './config';
|
||||
import { createHttpServer, createHttpsServer } from './hostFactory';
|
||||
|
||||
export const DEFAULT_PORT = 7000;
|
||||
export const DEFAULT_PORT = 7007;
|
||||
// '' is express default, which listens to all interfaces
|
||||
const DEFAULT_HOST = '';
|
||||
// taken from the helmet source code - don't seem to be exported
|
||||
|
||||
@@ -63,8 +63,8 @@ type CustomOrigin = (
|
||||
* @example
|
||||
* ```json
|
||||
* {
|
||||
* baseUrl: "http://localhost:7000",
|
||||
* listen: "0.0.0.0:7000"
|
||||
* baseUrl: "http://localhost:7007",
|
||||
* listen: "0.0.0.0:7007"
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
|
||||
@@ -34,7 +34,7 @@ export type ServiceBuilder = {
|
||||
*
|
||||
* If no port is specified, the service will first look for an environment
|
||||
* variable named PORT and use that if present, otherwise it picks a default
|
||||
* port (7000).
|
||||
* port (7007).
|
||||
*
|
||||
* @param port - The port to listen on
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,7 @@ Substitute `x` for actual values, or leave them as
|
||||
dummy values just to try out the backend without using the auth or sentry features.
|
||||
You can also, instead of using dummy values for a huge number of environment variables, remove those config directly from app-config.yaml file located in the root folder.
|
||||
|
||||
The backend starts up on port 7000 per default.
|
||||
The backend starts up on port 7007 per default.
|
||||
|
||||
### Debugging
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ async function getProjectConfig(targetPath, displayName) {
|
||||
...(displayName && { displayName }),
|
||||
rootDir: path.resolve(targetPath, 'src'),
|
||||
coverageDirectory: path.resolve(targetPath, 'coverage'),
|
||||
coverageProvider: 'v8',
|
||||
collectCoverageFrom: ['**/*.{js,jsx,ts,tsx}', '!**/*.d.ts'],
|
||||
moduleNameMapper: {
|
||||
'\\.(css|less|scss|sss|styl)$': require.resolve('jest-css-modules'),
|
||||
|
||||
@@ -46,7 +46,11 @@ function process(source, filePath) {
|
||||
}
|
||||
|
||||
if (transforms) {
|
||||
return transform(source, { transforms, filePath }).code;
|
||||
return transform(source, {
|
||||
transforms,
|
||||
filePath,
|
||||
disableESTransforms: true,
|
||||
}).code;
|
||||
}
|
||||
|
||||
return source;
|
||||
|
||||
@@ -18,7 +18,7 @@ import { getRootLogger } from '@backstage/backend-common';
|
||||
import yn from 'yn';
|
||||
import { startStandaloneServer } from './service/standaloneServer';
|
||||
|
||||
const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000;
|
||||
const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
|
||||
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
|
||||
const logger = getRootLogger();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createRouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
title: '{{ id }}',
|
||||
id: '{{ id }}',
|
||||
});
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/core-app-api
|
||||
|
||||
## 0.1.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Reverted the `createApp` TypeScript type to match the one before version `0.1.21`, as it was an accidental breaking change.
|
||||
|
||||
## 0.1.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -27,6 +27,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { bitbucketAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { createApp as createApp_2 } from '@backstage/app-defaults';
|
||||
import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { ErrorApi } from '@backstage/core-plugin-api';
|
||||
import { ErrorApiError } from '@backstage/core-plugin-api';
|
||||
@@ -45,7 +46,6 @@ import { Observable } from '@backstage/types';
|
||||
import { oktaAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { oneloginAuthApiRef } from '@backstage/core-plugin-api';
|
||||
import { OpenIdConnectApi } from '@backstage/core-plugin-api';
|
||||
import { OptionalAppOptions } from '@backstage/app-defaults';
|
||||
import { PendingAuthRequest } from '@backstage/core-plugin-api';
|
||||
import { PluginOutput } from '@backstage/core-plugin-api';
|
||||
import { ProfileInfo } from '@backstage/core-plugin-api';
|
||||
@@ -126,7 +126,7 @@ export type ApiProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export class ApiRegistry implements ApiHolder {
|
||||
constructor(apis: Map<string, unknown>);
|
||||
// Warning: (ae-forgotten-export) The symbol "ApiRegistryBuilder" needs to be exported by the entry point index.d.ts
|
||||
@@ -332,7 +332,9 @@ export type BootErrorPageProps = {
|
||||
export { ConfigReader };
|
||||
|
||||
// @public @deprecated
|
||||
export function createApp(options?: OptionalAppOptions): BackstageApp;
|
||||
export function createApp(
|
||||
options?: Parameters<typeof createApp_2>[0],
|
||||
): BackstageApp & AppContext;
|
||||
|
||||
// @public
|
||||
export function createSpecializedApp(options: AppOptions): BackstageApp;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/core-app-api",
|
||||
"description": "Core app API used by Backstage apps",
|
||||
"version": "0.1.21",
|
||||
"version": "0.1.22",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
+2
-2
@@ -26,10 +26,10 @@ describe('UrlPatternDiscovery', () => {
|
||||
|
||||
it('should use a plain pattern', async () => {
|
||||
const discoveryApi = UrlPatternDiscovery.compile(
|
||||
'http://localhost:7000/{{ pluginId }}',
|
||||
'http://localhost:7007/{{ pluginId }}',
|
||||
);
|
||||
await expect(discoveryApi.getBaseUrl('my-plugin')).resolves.toBe(
|
||||
'http://localhost:7000/my-plugin',
|
||||
'http://localhost:7007/my-plugin',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export class UrlPatternDiscovery implements DiscoveryApi {
|
||||
* interpolation done for the template is to replace instances of `{{pluginId}}`
|
||||
* with the ID of the plugin being requested.
|
||||
*
|
||||
* Example pattern: `http://localhost:7000/api/{{ pluginId }}`
|
||||
* Example pattern: `http://localhost:7007/api/{{ pluginId }}`
|
||||
*/
|
||||
static compile(pattern: string): UrlPatternDiscovery {
|
||||
const parts = pattern.split(/\{\{\s*pluginId\s*\}\}/);
|
||||
|
||||
@@ -36,6 +36,7 @@ class ApiRegistryBuilder {
|
||||
* A registry for utility APIs.
|
||||
*
|
||||
* @public
|
||||
* @deprecated Will be removed, use {@link @backstage/test-utils#TestApiProvider} or {@link @backstage/test-utils#TestApiRegistry} instead.
|
||||
*/
|
||||
export class ApiRegistry implements ApiHolder {
|
||||
static builder() {
|
||||
|
||||
@@ -14,10 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
createApp as createDefaultApp,
|
||||
OptionalAppOptions,
|
||||
} from '@backstage/app-defaults';
|
||||
import { createApp as createDefaultApp } from '@backstage/app-defaults';
|
||||
import { AppContext, BackstageApp } from './types';
|
||||
|
||||
/**
|
||||
* Creates a new Backstage App.
|
||||
@@ -26,7 +24,9 @@ import {
|
||||
* @param options - A set of options for creating the app
|
||||
* @public
|
||||
*/
|
||||
export function createApp(options?: OptionalAppOptions) {
|
||||
export function createApp(
|
||||
options?: Parameters<typeof createDefaultApp>[0],
|
||||
): BackstageApp & AppContext {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
'DEPRECATION WARNING: The createApp function from @backstage/core-app-api will soon be removed, ' +
|
||||
@@ -34,5 +34,5 @@ export function createApp(options?: OptionalAppOptions) {
|
||||
'If you do not wish to use a standard app configuration but instead supply all options yourself ' +
|
||||
' you can use createSpecializedApp from @backstage/core-app-api instead.',
|
||||
);
|
||||
return createDefaultApp(options);
|
||||
return createDefaultApp(options) as BackstageApp & AppContext;
|
||||
}
|
||||
|
||||
@@ -16,14 +16,15 @@
|
||||
import React from 'react';
|
||||
import { FeatureFlagged } from './FeatureFlagged';
|
||||
import { render } from '@testing-library/react';
|
||||
import { ApiProvider, ApiRegistry, LocalStorageFeatureFlags } from '../apis';
|
||||
import { LocalStorageFeatureFlags } from '../apis';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { featureFlagsApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
const mockFeatureFlagsApi = new LocalStorageFeatureFlags();
|
||||
const Wrapper = ({ children }: { children?: React.ReactNode }) => (
|
||||
<ApiProvider apis={ApiRegistry.with(featureFlagsApiRef, mockFeatureFlagsApi)}>
|
||||
<TestApiProvider apis={[[featureFlagsApiRef, mockFeatureFlagsApi]]}>
|
||||
{children}
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
);
|
||||
|
||||
describe('FeatureFlagged', () => {
|
||||
|
||||
@@ -17,17 +17,18 @@
|
||||
import { render, RenderResult } from '@testing-library/react';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { MemoryRouter, Route, Routes, useOutlet } from 'react-router-dom';
|
||||
import { ApiProvider, ApiRegistry, LocalStorageFeatureFlags } from '../apis';
|
||||
import { LocalStorageFeatureFlags } from '../apis';
|
||||
import { featureFlagsApiRef } from '@backstage/core-plugin-api';
|
||||
import { AppContext } from '../app';
|
||||
import { AppContextProvider } from '../app/AppContext';
|
||||
import { FlatRoutes } from './FlatRoutes';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
|
||||
const mockFeatureFlagsApi = new LocalStorageFeatureFlags();
|
||||
const Wrapper = ({ children }: { children?: React.ReactNode }) => (
|
||||
<ApiProvider apis={ApiRegistry.with(featureFlagsApiRef, mockFeatureFlagsApi)}>
|
||||
<TestApiProvider apis={[[featureFlagsApiRef, mockFeatureFlagsApi]]}>
|
||||
{children}
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
);
|
||||
|
||||
function makeRouteRenderer(node: ReactNode) {
|
||||
|
||||
@@ -17,78 +17,66 @@
|
||||
import React from 'react';
|
||||
import { AlertDisplay } from './AlertDisplay';
|
||||
import { alertApiRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
ApiProvider,
|
||||
ApiRegistry,
|
||||
AlertApiForwarder,
|
||||
} from '@backstage/core-app-api';
|
||||
import { AlertApiForwarder } from '@backstage/core-app-api';
|
||||
import Observable from 'zen-observable';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
|
||||
const TEST_MESSAGE = 'TEST_MESSAGE';
|
||||
|
||||
describe('<AlertDisplay />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const apiRegistry = ApiRegistry.from([
|
||||
[alertApiRef, new AlertApiForwarder()],
|
||||
]);
|
||||
|
||||
const { queryByText } = await renderInTestApp(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<TestApiProvider apis={[[alertApiRef, new AlertApiForwarder()]]}>
|
||||
<AlertDisplay />
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
expect(queryByText(TEST_MESSAGE)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders with message', async () => {
|
||||
const apiRegistry = ApiRegistry.from([
|
||||
[
|
||||
alertApiRef,
|
||||
{
|
||||
post() {},
|
||||
alert$() {
|
||||
return Observable.of({ message: TEST_MESSAGE });
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
const { queryByText } = await renderInTestApp(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<TestApiProvider
|
||||
apis={[
|
||||
[
|
||||
alertApiRef,
|
||||
{
|
||||
post() {},
|
||||
alert$() {
|
||||
return Observable.of({ message: TEST_MESSAGE });
|
||||
},
|
||||
},
|
||||
],
|
||||
]}
|
||||
>
|
||||
<AlertDisplay />
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
expect(queryByText(TEST_MESSAGE)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe('with multiple messages', () => {
|
||||
let apiRegistry: ApiRegistry;
|
||||
|
||||
beforeEach(() => {
|
||||
apiRegistry = ApiRegistry.from([
|
||||
[
|
||||
alertApiRef,
|
||||
{
|
||||
post() {},
|
||||
alert$() {
|
||||
return Observable.of(
|
||||
{ message: 'message one' },
|
||||
{ message: 'message two' },
|
||||
{ message: 'message three' },
|
||||
);
|
||||
},
|
||||
const apis = [
|
||||
[
|
||||
alertApiRef,
|
||||
{
|
||||
post() {},
|
||||
alert$() {
|
||||
return Observable.of(
|
||||
{ message: 'message one' },
|
||||
{ message: 'message two' },
|
||||
{ message: 'message three' },
|
||||
);
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
},
|
||||
] as const,
|
||||
] as const;
|
||||
|
||||
it('renders first message', async () => {
|
||||
const { queryByText } = await renderInTestApp(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<AlertDisplay />
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
expect(queryByText('message one')).toBeInTheDocument();
|
||||
@@ -96,9 +84,9 @@ describe('<AlertDisplay />', () => {
|
||||
|
||||
it('renders a count of remaining messages', async () => {
|
||||
const { queryByText } = await renderInTestApp(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<AlertDisplay />
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
expect(queryByText('(2 older messages)')).toBeInTheDocument();
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
import React from 'react';
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
import { CopyTextButton } from './CopyTextButton';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import { errorApiRef, ErrorApi } from '@backstage/core-plugin-api';
|
||||
import { errorApiRef } from '@backstage/core-plugin-api';
|
||||
import { useCopyToClipboard } from 'react-use';
|
||||
|
||||
jest.mock('popper.js', () => {
|
||||
@@ -51,22 +50,18 @@ const props = {
|
||||
tooltipText: 'mockTooltip',
|
||||
};
|
||||
|
||||
const apiRegistry = ApiRegistry.from([
|
||||
[
|
||||
errorApiRef,
|
||||
{
|
||||
post: jest.fn(),
|
||||
error$: jest.fn(),
|
||||
} as ErrorApi,
|
||||
],
|
||||
]);
|
||||
const mockErrorApi = {
|
||||
post: jest.fn(),
|
||||
error$: jest.fn(),
|
||||
};
|
||||
const apis = [[errorApiRef, mockErrorApi] as const] as const;
|
||||
|
||||
describe('<CopyTextButton />', () => {
|
||||
it('renders without exploding', async () => {
|
||||
const { getByTitle, queryByText } = await renderInTestApp(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<CopyTextButton {...props} />
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
expect(getByTitle('mockTooltip')).toBeInTheDocument();
|
||||
expect(queryByText('mockTooltip')).not.toBeInTheDocument();
|
||||
@@ -80,9 +75,9 @@ describe('<CopyTextButton />', () => {
|
||||
spy.mockReturnValue([{}, copy]);
|
||||
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<CopyTextButton {...props} />
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
const button = rendered.getByTitle('mockTooltip');
|
||||
fireEvent.click(button);
|
||||
@@ -101,10 +96,10 @@ describe('<CopyTextButton />', () => {
|
||||
spy.mockReturnValue([{ error }, jest.fn()]);
|
||||
|
||||
await renderInTestApp(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<CopyTextButton {...props} />
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
expect(apiRegistry.get(errorApiRef)?.post).toHaveBeenCalledWith(error);
|
||||
expect(mockErrorApi.post).toHaveBeenCalledWith(error);
|
||||
});
|
||||
});
|
||||
|
||||
+15
-14
@@ -18,12 +18,13 @@ import React from 'react';
|
||||
import { DismissableBanner } from './DismissableBanner';
|
||||
import Link from '@material-ui/core/Link';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { ApiProvider, ApiRegistry, WebStorage } from '@backstage/core-app-api';
|
||||
import { WebStorage } from '@backstage/core-app-api';
|
||||
import {
|
||||
ErrorApi,
|
||||
storageApiRef,
|
||||
StorageApi,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
|
||||
export default {
|
||||
title: 'Feedback/DismissableBanner',
|
||||
@@ -37,47 +38,47 @@ const createWebStorage = (): StorageApi => {
|
||||
return WebStorage.create({ errorApi });
|
||||
};
|
||||
|
||||
const apis = ApiRegistry.from([[storageApiRef, createWebStorage()]]);
|
||||
const apis = [[storageApiRef, createWebStorage()] as const];
|
||||
|
||||
export const Default = () => (
|
||||
<div style={containerStyle}>
|
||||
<ApiProvider apis={apis}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<DismissableBanner
|
||||
message="This is a dismissable banner"
|
||||
variant="info"
|
||||
id="default_dismissable"
|
||||
/>
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Error = () => (
|
||||
<div style={containerStyle}>
|
||||
<ApiProvider apis={apis}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<DismissableBanner
|
||||
message="This is a dismissable banner with an error message"
|
||||
variant="error"
|
||||
id="error_dismissable"
|
||||
/>
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const EmojisIncluded = () => (
|
||||
<div style={containerStyle}>
|
||||
<ApiProvider apis={apis}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<DismissableBanner
|
||||
message="This is a dismissable banner with emojis: 🚀 💚 😆 "
|
||||
variant="info"
|
||||
id="emojis_dismissable"
|
||||
/>
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const WithLink = () => (
|
||||
<div style={containerStyle}>
|
||||
<ApiProvider apis={apis}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<DismissableBanner
|
||||
message={
|
||||
<Typography>
|
||||
@@ -90,29 +91,29 @@ export const WithLink = () => (
|
||||
variant="info"
|
||||
id="linked_dismissable"
|
||||
/>
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
</div>
|
||||
);
|
||||
export const Fixed = () => (
|
||||
<div style={containerStyle}>
|
||||
<ApiProvider apis={apis}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<DismissableBanner
|
||||
message="This is a dismissable banner with a fixed position fixed at the bottom of the page"
|
||||
variant="info"
|
||||
id="fixed_dismissable"
|
||||
fixed
|
||||
/>
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
</div>
|
||||
);
|
||||
export const Warning = () => (
|
||||
<div style={containerStyle}>
|
||||
<ApiProvider apis={apis}>
|
||||
<TestApiProvider apis={apis}>
|
||||
<DismissableBanner
|
||||
message="This is a dismissable banner with a warning message"
|
||||
variant="warning"
|
||||
id="warning_dismissable"
|
||||
/>
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
</div>
|
||||
);
|
||||
|
||||
+8
-4
@@ -16,13 +16,17 @@
|
||||
|
||||
import React from 'react';
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils';
|
||||
import {
|
||||
renderWithEffects,
|
||||
TestApiRegistry,
|
||||
wrapInTestApp,
|
||||
} from '@backstage/test-utils';
|
||||
import { DismissableBanner } from './DismissableBanner';
|
||||
import { ApiRegistry, ApiProvider, WebStorage } from '@backstage/core-app-api';
|
||||
import { ApiProvider, WebStorage } from '@backstage/core-app-api';
|
||||
import { storageApiRef, StorageApi } from '@backstage/core-plugin-api';
|
||||
|
||||
describe('<DismissableBanner />', () => {
|
||||
let apis: ApiRegistry;
|
||||
let apis: TestApiRegistry;
|
||||
const mockErrorApi = { post: jest.fn(), error$: jest.fn() };
|
||||
const createWebStorage = (): StorageApi => {
|
||||
return WebStorage.create({
|
||||
@@ -31,7 +35,7 @@ describe('<DismissableBanner />', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
apis = ApiRegistry.from([[storageApiRef, createWebStorage()]]);
|
||||
apis = TestApiRegistry.from([storageApiRef, createWebStorage()]);
|
||||
});
|
||||
|
||||
it('renders the message and the popover', async () => {
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
import React from 'react';
|
||||
import { render, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { MockAnalyticsApi, wrapInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import {
|
||||
MockAnalyticsApi,
|
||||
TestApiProvider,
|
||||
wrapInTestApp,
|
||||
} from '@backstage/test-utils';
|
||||
import { analyticsApiRef } from '@backstage/core-plugin-api';
|
||||
import { isExternalUri, Link } from './Link';
|
||||
import { Route, Routes } from 'react-router';
|
||||
@@ -48,11 +51,11 @@ describe('<Link />', () => {
|
||||
|
||||
const { getByText } = render(
|
||||
wrapInTestApp(
|
||||
<ApiProvider apis={ApiRegistry.from([[analyticsApiRef, analyticsApi]])}>
|
||||
<TestApiProvider apis={[[analyticsApiRef, analyticsApi]]}>
|
||||
<Link to="/test" onClick={customOnClick}>
|
||||
{linkText}
|
||||
</Link>
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ import { ErrorBoundary } from './ErrorBoundary';
|
||||
import {
|
||||
MockErrorApi,
|
||||
renderInTestApp,
|
||||
TestApiProvider,
|
||||
withLogCollector,
|
||||
} from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import { errorApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
type BombProps = {
|
||||
@@ -41,25 +41,25 @@ const Bomb = ({ shouldThrow }: BombProps) => {
|
||||
describe('<ErrorBoundary/>', () => {
|
||||
it('should render error boundary with and without error', async () => {
|
||||
const { error } = await withLogCollector(['error'], async () => {
|
||||
const apis = ApiRegistry.with(errorApiRef, new MockErrorApi());
|
||||
const errorApi = new MockErrorApi();
|
||||
const { rerender, queryByRole, getByRole, getByText } =
|
||||
await renderInTestApp(
|
||||
<ApiProvider apis={apis}>
|
||||
<TestApiProvider apis={[[errorApiRef, errorApi]]}>
|
||||
<ErrorBoundary>
|
||||
<Bomb />
|
||||
</ErrorBoundary>
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
expect(queryByRole('alert')).not.toBeInTheDocument();
|
||||
expect(getByText(/working component/i)).toBeInTheDocument();
|
||||
|
||||
rerender(
|
||||
<ApiProvider apis={apis}>
|
||||
<TestApiProvider apis={[[errorApiRef, errorApi]]}>
|
||||
<ErrorBoundary>
|
||||
<Bomb shouldThrow />
|
||||
</ErrorBoundary>
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
expect(getByRole('alert')).toBeInTheDocument();
|
||||
|
||||
@@ -15,13 +15,9 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
import { Header } from './Header';
|
||||
import {
|
||||
ApiRegistry,
|
||||
ConfigReader,
|
||||
ApiProvider,
|
||||
} from '@backstage/core-app-api';
|
||||
import { ConfigReader } from '@backstage/core-app-api';
|
||||
import { configApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
jest.mock('react-helmet', () => {
|
||||
@@ -72,14 +68,12 @@ describe('<Header/>', () => {
|
||||
});
|
||||
|
||||
it('should use app.title', async () => {
|
||||
const apiRegistry = ApiRegistry.with(
|
||||
configApiRef,
|
||||
new ConfigReader({ app: { title: 'Blah' } }),
|
||||
);
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider apis={apiRegistry}>
|
||||
<TestApiProvider
|
||||
apis={[[configApiRef, new ConfigReader({ app: { title: 'Blah' } })]]}
|
||||
>
|
||||
<Header title="Title" type="tool" typeLink="/tool" />,
|
||||
</ApiProvider>,
|
||||
</TestApiProvider>,
|
||||
);
|
||||
rendered.getAllByText(/Title | Blah/);
|
||||
});
|
||||
|
||||
@@ -14,16 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { renderWithEffects } from '@backstage/test-utils';
|
||||
import { renderWithEffects, TestApiProvider } from '@backstage/test-utils';
|
||||
import { HomepageTimer } from './HomepageTimer';
|
||||
import React from 'react';
|
||||
import { lightTheme } from '@backstage/theme';
|
||||
import { ThemeProvider } from '@material-ui/core/styles';
|
||||
import {
|
||||
ApiProvider,
|
||||
ApiRegistry,
|
||||
ConfigReader,
|
||||
} from '@backstage/core-app-api';
|
||||
import { ConfigReader } from '@backstage/core-app-api';
|
||||
import { ConfigApi, configApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
it('changes default timezone to GMT', async () => {
|
||||
@@ -41,9 +37,9 @@ it('changes default timezone to GMT', async () => {
|
||||
|
||||
const rendered = await renderWithEffects(
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<ApiProvider apis={ApiRegistry.from([[configApiRef, configApi]])}>
|
||||
<TestApiProvider apis={[[configApiRef, configApi]]}>
|
||||
<HomepageTimer />
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
</ThemeProvider>,
|
||||
);
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export type SidebarPinStateContextType = {
|
||||
|
||||
export const SidebarPinStateContext = createContext<SidebarPinStateContextType>(
|
||||
{
|
||||
isPinned: false,
|
||||
isPinned: true,
|
||||
toggleSidebarPinState: () => {},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -24,10 +24,10 @@ export const LocalStorage = {
|
||||
try {
|
||||
value = JSON.parse(
|
||||
window.localStorage.getItem(LocalStorageKeys.SIDEBAR_PIN_STATE) ||
|
||||
'false',
|
||||
'true',
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return !!value;
|
||||
},
|
||||
|
||||
@@ -18,11 +18,8 @@ import { useElementFilter } from './useElementFilter';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { attachComponentData } from './componentData';
|
||||
import { featureFlagsApiRef } from '../apis';
|
||||
import {
|
||||
ApiProvider,
|
||||
ApiRegistry,
|
||||
LocalStorageFeatureFlags,
|
||||
} from '@backstage/core-app-api';
|
||||
import { LocalStorageFeatureFlags } from '@backstage/core-app-api';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
|
||||
const WRAPPING_COMPONENT_KEY = 'core.blob.testing';
|
||||
const INNER_COMPONENT_KEY = 'core.blob2.testing';
|
||||
@@ -45,9 +42,9 @@ const FeatureFlagComponent = (_props: {
|
||||
attachComponentData(FeatureFlagComponent, 'core.featureFlagged', true);
|
||||
const mockFeatureFlagsApi = new LocalStorageFeatureFlags();
|
||||
const Wrapper = ({ children }: { children?: React.ReactNode }) => (
|
||||
<ApiProvider apis={ApiRegistry.with(featureFlagsApiRef, mockFeatureFlagsApi)}>
|
||||
<TestApiProvider apis={[[featureFlagsApiRef, mockFeatureFlagsApi]]}>
|
||||
{children}
|
||||
</ApiProvider>
|
||||
</TestApiProvider>
|
||||
);
|
||||
|
||||
describe('useElementFilter', () => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
app:
|
||||
# Should be the same as backend.baseUrl when using the `app-backend` plugin
|
||||
baseUrl: http://localhost:7000
|
||||
baseUrl: http://localhost:7007
|
||||
|
||||
backend:
|
||||
baseUrl: http://localhost:7000
|
||||
baseUrl: http://localhost:7007
|
||||
listen:
|
||||
port: 7000
|
||||
port: 7007
|
||||
|
||||
@@ -10,9 +10,9 @@ backend:
|
||||
# See authenticate-api-requests.md in the contrib docs for information on the format
|
||||
# authorization:
|
||||
# secret: ${BACKEND_SECRET}
|
||||
baseUrl: http://localhost:7000
|
||||
baseUrl: http://localhost:7007
|
||||
listen:
|
||||
port: 7000
|
||||
port: 7007
|
||||
csp:
|
||||
connect-src: ["'self'", 'http:', 'https:']
|
||||
# Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference
|
||||
|
||||
@@ -10,9 +10,9 @@ describe('App', () => {
|
||||
{
|
||||
data: {
|
||||
app: { title: 'Test' },
|
||||
backend: { baseUrl: 'http://localhost:7000' },
|
||||
backend: { baseUrl: 'http://localhost:7007' },
|
||||
techdocs: {
|
||||
storageUrl: 'http://localhost:7000/api/techdocs/static/docs',
|
||||
storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
|
||||
},
|
||||
},
|
||||
context: 'test',
|
||||
|
||||
+15
@@ -2,10 +2,13 @@ import React from 'react';
|
||||
import { makeStyles, Theme, Grid, List, Paper } from '@material-ui/core';
|
||||
|
||||
import { CatalogResultListItem } from '@backstage/plugin-catalog';
|
||||
import { DocsResultListItem } from '@backstage/plugin-techdocs';
|
||||
|
||||
import {
|
||||
SearchBar,
|
||||
SearchFilter,
|
||||
SearchResult,
|
||||
SearchType,
|
||||
DefaultResultListItem,
|
||||
} from '@backstage/plugin-search';
|
||||
import { Content, Header, Page } from '@backstage/core-components';
|
||||
@@ -39,6 +42,11 @@ const SearchPage = () => {
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Paper className={classes.filters}>
|
||||
<SearchType
|
||||
values={['techdocs', 'software-catalog']}
|
||||
name="type"
|
||||
defaultValue="software-catalog"
|
||||
/>
|
||||
<SearchFilter.Select
|
||||
className={classes.filter}
|
||||
name="kind"
|
||||
@@ -64,6 +72,13 @@ const SearchPage = () => {
|
||||
result={document}
|
||||
/>
|
||||
);
|
||||
case 'techdocs':
|
||||
return (
|
||||
<DocsResultListItem
|
||||
key={document.location}
|
||||
result={document}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<DefaultResultListItem
|
||||
|
||||
@@ -36,7 +36,7 @@ yarn start
|
||||
Substitute `x` for actual values, or leave them as dummy values just to try out
|
||||
the backend without using the auth or sentry features.
|
||||
|
||||
The backend starts up on port 7000 per default.
|
||||
The backend starts up on port 7007 per default.
|
||||
|
||||
## Populating The Catalog
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from '@backstage/plugin-search-backend-node';
|
||||
import { PluginEnvironment } from '../types';
|
||||
import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
|
||||
import { DefaultTechDocsCollator } from '@backstage/plugin-techdocs-backend';
|
||||
|
||||
export default async function createPlugin({
|
||||
logger,
|
||||
@@ -18,7 +19,7 @@ export default async function createPlugin({
|
||||
const indexBuilder = new IndexBuilder({ logger, searchEngine });
|
||||
|
||||
// Collators are responsible for gathering documents known to plugins. This
|
||||
// particular collator gathers entities from the software catalog.
|
||||
// collator gathers entities from the software catalog.
|
||||
indexBuilder.addCollator({
|
||||
defaultRefreshIntervalSeconds: 600,
|
||||
collator: DefaultCatalogCollator.fromConfig(config, {
|
||||
@@ -27,6 +28,12 @@ export default async function createPlugin({
|
||||
}),
|
||||
});
|
||||
|
||||
// collator gathers entities from techdocs.
|
||||
indexBuilder.addCollator({
|
||||
defaultRefreshIntervalSeconds: 600,
|
||||
collator: DefaultTechDocsCollator.fromConfig(config, { discovery, logger }),
|
||||
});
|
||||
|
||||
// The scheduler controls when documents are gathered from collators and sent
|
||||
// to the search engine for indexing.
|
||||
const { scheduler } = await indexBuilder.build();
|
||||
|
||||
@@ -471,7 +471,7 @@ async function testBackendStart(appDir: string, isPostgres: boolean) {
|
||||
|
||||
print('Try to fetch entities from the backend');
|
||||
// Try fetch entities, should be ok
|
||||
await fetch('http://localhost:7000/api/catalog/entities').then(res =>
|
||||
await fetch('http://localhost:7007/api/catalog/entities').then(res =>
|
||||
res.json(),
|
||||
);
|
||||
print('Entities fetched successfully');
|
||||
|
||||
@@ -5,8 +5,8 @@ app:
|
||||
baseUrl: http://localhost:3000
|
||||
|
||||
backend:
|
||||
baseUrl: http://localhost:7000
|
||||
baseUrl: http://localhost:7007
|
||||
|
||||
techdocs:
|
||||
builder: 'external'
|
||||
requestUrl: http://localhost:7000/api
|
||||
requestUrl: http://localhost:7007/api
|
||||
|
||||
@@ -26,9 +26,9 @@ describe('App', () => {
|
||||
{
|
||||
data: {
|
||||
app: { title: 'Test' },
|
||||
backend: { baseUrl: 'http://localhost:7000' },
|
||||
backend: { baseUrl: 'http://localhost:7007' },
|
||||
techdocs: {
|
||||
storageUrl: 'http://localhost:7000/api/techdocs/static/docs',
|
||||
storageUrl: 'http://localhost:7007/api/techdocs/static/docs',
|
||||
},
|
||||
},
|
||||
context: 'test',
|
||||
|
||||
@@ -33,8 +33,11 @@ export type ErrorLike = {
|
||||
[unknownKeys: string]: unknown;
|
||||
};
|
||||
|
||||
// @public @deprecated
|
||||
export type ErrorResponse = ErrorResponseBody;
|
||||
|
||||
// @public
|
||||
export type ErrorResponse = {
|
||||
export type ErrorResponseBody = {
|
||||
error: SerializedError;
|
||||
request?: {
|
||||
method: string;
|
||||
@@ -65,19 +68,27 @@ export class NotFoundError extends CustomErrorBase {}
|
||||
// @public
|
||||
export class NotModifiedError extends CustomErrorBase {}
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export function parseErrorResponse(response: Response): Promise<ErrorResponse>;
|
||||
|
||||
// @public
|
||||
export function parseErrorResponseBody(
|
||||
response: Response,
|
||||
): Promise<ErrorResponseBody>;
|
||||
|
||||
// @public
|
||||
export class ResponseError extends Error {
|
||||
// @deprecated
|
||||
constructor(props: {
|
||||
message: string;
|
||||
response: Response;
|
||||
data: ErrorResponse;
|
||||
data: ErrorResponseBody;
|
||||
cause: Error;
|
||||
});
|
||||
readonly body: ErrorResponseBody;
|
||||
readonly cause: Error;
|
||||
readonly data: ErrorResponse;
|
||||
// @deprecated
|
||||
get data(): ErrorResponseBody;
|
||||
static fromResponse(response: Response): Promise<ResponseError>;
|
||||
readonly response: Response;
|
||||
}
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { deserializeError } from '../serialization';
|
||||
import {
|
||||
parseErrorResponse,
|
||||
ErrorResponse,
|
||||
deserializeError,
|
||||
} from '../serialization';
|
||||
ErrorResponseBody,
|
||||
parseErrorResponseBody,
|
||||
} from '../serialization/response';
|
||||
|
||||
/**
|
||||
* An error thrown as the result of a failed server request.
|
||||
*
|
||||
* The server is expected to respond on the ErrorResponse format.
|
||||
* The server is expected to respond on the ErrorResponseBody format.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ export class ResponseError extends Error {
|
||||
/**
|
||||
* The parsed JSON error body, as sent by the server.
|
||||
*/
|
||||
readonly data: ErrorResponse;
|
||||
readonly body: ErrorResponseBody;
|
||||
|
||||
/**
|
||||
* The Error cause, as seen by the remote server. This is parsed out of the
|
||||
@@ -60,7 +60,7 @@ export class ResponseError extends Error {
|
||||
* been consumed before.
|
||||
*/
|
||||
static async fromResponse(response: Response): Promise<ResponseError> {
|
||||
const data = await parseErrorResponse(response);
|
||||
const data = await parseErrorResponseBody(response);
|
||||
|
||||
const status = data.response.statusCode || response.status;
|
||||
const statusText = data.error.name || response.statusText;
|
||||
@@ -75,16 +75,28 @@ export class ResponseError extends Error {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated will be removed.
|
||||
**/
|
||||
constructor(props: {
|
||||
message: string;
|
||||
response: Response;
|
||||
data: ErrorResponse;
|
||||
data: ErrorResponseBody;
|
||||
cause: Error;
|
||||
}) {
|
||||
super(props.message);
|
||||
this.name = 'ResponseError';
|
||||
this.response = props.response;
|
||||
this.data = props.data;
|
||||
this.body = props.data;
|
||||
this.cause = props.cause;
|
||||
}
|
||||
/**
|
||||
* The parsed JSON error body, as sent by the server.
|
||||
* @deprecated use body instead.
|
||||
*/
|
||||
get data(): ErrorResponseBody {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('ErrorResponse.data is deprecated, use .body instead.');
|
||||
return this.body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
|
||||
export { deserializeError, serializeError, stringifyError } from './error';
|
||||
export type { SerializedError } from './error';
|
||||
export { parseErrorResponse } from './response';
|
||||
export type { ErrorResponse } from './response';
|
||||
export { parseErrorResponse, parseErrorResponseBody } from './response';
|
||||
export type { ErrorResponse, ErrorResponseBody } from './response';
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { parseErrorResponse, ErrorResponse } from './response';
|
||||
import { parseErrorResponseBody, ErrorResponseBody } from './response';
|
||||
|
||||
describe('parseErrorResponse', () => {
|
||||
describe('parseErrorResponseBody', () => {
|
||||
it('handles the happy path', async () => {
|
||||
const body: ErrorResponse = {
|
||||
const body: ErrorResponseBody = {
|
||||
error: { name: 'Fours', message: 'Expected fives', stack: 'lines' },
|
||||
request: { method: 'GET', url: '/' },
|
||||
response: { statusCode: 444 },
|
||||
@@ -31,13 +31,13 @@ describe('parseErrorResponse', () => {
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
};
|
||||
|
||||
await expect(parseErrorResponse(response as Response)).resolves.toEqual(
|
||||
await expect(parseErrorResponseBody(response as Response)).resolves.toEqual(
|
||||
body,
|
||||
);
|
||||
});
|
||||
|
||||
it('uses request header and text body when wrong content type, even if parsable', async () => {
|
||||
const body: ErrorResponse = {
|
||||
const body: ErrorResponseBody = {
|
||||
error: { name: 'Threes', message: 'Expected twos' },
|
||||
request: { method: 'GET', url: '/' },
|
||||
response: { statusCode: 333 },
|
||||
@@ -50,19 +50,21 @@ describe('parseErrorResponse', () => {
|
||||
headers: new Headers({ 'Content-Type': 'not-application/not-json' }),
|
||||
};
|
||||
|
||||
await expect(parseErrorResponse(response as Response)).resolves.toEqual({
|
||||
error: {
|
||||
name: 'Unknown',
|
||||
message: `Request failed with status 444 Fours, ${JSON.stringify(
|
||||
body,
|
||||
)}`,
|
||||
await expect(parseErrorResponseBody(response as Response)).resolves.toEqual(
|
||||
{
|
||||
error: {
|
||||
name: 'Error',
|
||||
message: `Request failed with status 444 Fours, ${JSON.stringify(
|
||||
body,
|
||||
)}`,
|
||||
},
|
||||
response: { statusCode: 444 },
|
||||
},
|
||||
response: { statusCode: 444 },
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
it('uses request header and text body when not parsable', async () => {
|
||||
const body: ErrorResponse = {
|
||||
const body: ErrorResponseBody = {
|
||||
error: { name: 'Threes', message: 'Expected twos' },
|
||||
request: { method: 'GET', url: '/' },
|
||||
response: { statusCode: 333 },
|
||||
@@ -75,15 +77,17 @@ describe('parseErrorResponse', () => {
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
};
|
||||
|
||||
await expect(parseErrorResponse(response as Response)).resolves.toEqual({
|
||||
error: {
|
||||
name: 'Unknown',
|
||||
message: `Request failed with status 444 Fours, ${JSON.stringify(
|
||||
body,
|
||||
).substring(1)}`,
|
||||
await expect(parseErrorResponseBody(response as Response)).resolves.toEqual(
|
||||
{
|
||||
error: {
|
||||
name: 'Error',
|
||||
message: `Request failed with status 444 Fours, ${JSON.stringify(
|
||||
body,
|
||||
).substring(1)}`,
|
||||
},
|
||||
response: { statusCode: 444 },
|
||||
},
|
||||
response: { statusCode: 444 },
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
it('uses request header when failing to get body', async () => {
|
||||
@@ -96,12 +100,14 @@ describe('parseErrorResponse', () => {
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
};
|
||||
|
||||
await expect(parseErrorResponse(response as Response)).resolves.toEqual({
|
||||
error: {
|
||||
name: 'Unknown',
|
||||
message: `Request failed with status 444 Fours`,
|
||||
await expect(parseErrorResponseBody(response as Response)).resolves.toEqual(
|
||||
{
|
||||
error: {
|
||||
name: 'Error',
|
||||
message: `Request failed with status 444 Fours`,
|
||||
},
|
||||
response: { statusCode: 444 },
|
||||
},
|
||||
response: { statusCode: 444 },
|
||||
});
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,8 +20,16 @@ import { SerializedError } from './error';
|
||||
* A standard shape of JSON data returned as the body of backend errors.
|
||||
*
|
||||
* @public
|
||||
* @deprecated - Use {@link ErrorResponseBody} instead.
|
||||
*/
|
||||
export type ErrorResponse = {
|
||||
export type ErrorResponse = ErrorResponseBody;
|
||||
|
||||
/**
|
||||
* A standard shape of JSON data returned as the body of backend errors.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type ErrorResponseBody = {
|
||||
/** Details of the error that was caught */
|
||||
error: SerializedError;
|
||||
|
||||
@@ -51,10 +59,29 @@ export type ErrorResponse = {
|
||||
*
|
||||
* @public
|
||||
* @param response - The response of a failed request
|
||||
* @deprecated - Use {@link parseErrorResponseBody} instead.
|
||||
*/
|
||||
export async function parseErrorResponse(
|
||||
response: Response,
|
||||
): Promise<ErrorResponse> {
|
||||
return parseErrorResponseBody(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to construct an ErrorResponseBody out of a failed server request.
|
||||
* Assumes that the response has already been checked to be not ok. This
|
||||
* function consumes the body of the response, and assumes that it hasn't
|
||||
* been consumed before.
|
||||
*
|
||||
* The code is forgiving, and constructs a useful synthetic body as best it can
|
||||
* if the response body wasn't on the expected form.
|
||||
*
|
||||
* @public
|
||||
* @param response - The response of a failed request
|
||||
*/
|
||||
export async function parseErrorResponseBody(
|
||||
response: Response,
|
||||
): Promise<ErrorResponseBody> {
|
||||
try {
|
||||
const text = await response.text();
|
||||
if (text) {
|
||||
@@ -73,7 +100,7 @@ export async function parseErrorResponse(
|
||||
|
||||
return {
|
||||
error: {
|
||||
name: 'Unknown',
|
||||
name: 'Error',
|
||||
message: `Request failed with status ${response.status} ${response.statusText}, ${text}`,
|
||||
},
|
||||
response: {
|
||||
@@ -87,7 +114,7 @@ export async function parseErrorResponse(
|
||||
|
||||
return {
|
||||
error: {
|
||||
name: 'Unknown',
|
||||
name: 'Error',
|
||||
message: `Request failed with status ${response.status} ${response.statusText}`,
|
||||
},
|
||||
response: {
|
||||
|
||||
@@ -50,7 +50,7 @@ const oauthRequestApi = builder.add(
|
||||
builder.add(
|
||||
googleAuthApiRef,
|
||||
GoogleAuth.create({
|
||||
apiOrigin: 'http://localhost:7000',
|
||||
apiOrigin: 'http://localhost:7007',
|
||||
basePath: '/auth/',
|
||||
oauthRequestApi,
|
||||
}),
|
||||
@@ -59,7 +59,7 @@ builder.add(
|
||||
builder.add(
|
||||
githubAuthApiRef,
|
||||
GithubAuth.create({
|
||||
apiOrigin: 'http://localhost:7000',
|
||||
apiOrigin: 'http://localhost:7007',
|
||||
basePath: '/auth/',
|
||||
oauthRequestApi,
|
||||
}),
|
||||
@@ -68,7 +68,7 @@ builder.add(
|
||||
builder.add(
|
||||
gitlabAuthApiRef,
|
||||
GitlabAuth.create({
|
||||
apiOrigin: 'http://localhost:7000',
|
||||
apiOrigin: 'http://localhost:7007',
|
||||
basePath: '/auth/',
|
||||
oauthRequestApi,
|
||||
}),
|
||||
@@ -77,7 +77,7 @@ builder.add(
|
||||
builder.add(
|
||||
oktaAuthApiRef,
|
||||
OktaAuth.create({
|
||||
apiOrigin: 'http://localhost:7000',
|
||||
apiOrigin: 'http://localhost:7007',
|
||||
basePath: '/auth/',
|
||||
oauthRequestApi,
|
||||
}),
|
||||
@@ -86,7 +86,7 @@ builder.add(
|
||||
builder.add(
|
||||
auth0AuthApiRef,
|
||||
Auth0Auth.create({
|
||||
apiOrigin: 'http://localhost:7000',
|
||||
apiOrigin: 'http://localhost:7007',
|
||||
basePath: '/auth/',
|
||||
oauthRequestApi,
|
||||
}),
|
||||
@@ -95,7 +95,7 @@ builder.add(
|
||||
builder.add(
|
||||
oauth2ApiRef,
|
||||
OAuth2.create({
|
||||
apiOrigin: 'http://localhost:7000',
|
||||
apiOrigin: 'http://localhost:7007',
|
||||
basePath: '/auth/',
|
||||
oauthRequestApi,
|
||||
}),
|
||||
|
||||
@@ -36,7 +36,7 @@ export default async function serve(cmd: Command) {
|
||||
// a backstage app, we define app.baseUrl in the app-config.yaml.
|
||||
// Hence, it is complicated to make this configurable.
|
||||
const backstagePort = 3000;
|
||||
const backstageBackendPort = 7000;
|
||||
const backstageBackendPort = 7007;
|
||||
|
||||
const mkdocsDockerAddr = `http://0.0.0.0:${cmd.mkdocsPort}`;
|
||||
const mkdocsLocalAddr = `http://127.0.0.1:${cmd.mkdocsPort}`;
|
||||
|
||||
@@ -55,9 +55,9 @@ export class PublisherConfig {
|
||||
return new ConfigReader({
|
||||
// This backend config is not used at all. Just something needed a create a mock discovery instance.
|
||||
backend: {
|
||||
baseUrl: 'http://localhost:7000',
|
||||
baseUrl: 'http://localhost:7007',
|
||||
listen: {
|
||||
port: 7000,
|
||||
port: 7007,
|
||||
},
|
||||
},
|
||||
techdocs: {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user