Merge branch 'master' into system-diagram

This commit is contained in:
Adam Harvey
2021-03-25 11:07:32 -04:00
committed by GitHub
498 changed files with 13016 additions and 2949 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-kubernetes-backend': patch
'@backstage/plugin-kubernetes': patch
---
Bump `@kubernetes/client-node` from `^0.13.2` to `^0.14.0`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Fixes bug in the `github:publish` action causing repositories to be set as private even if the visibility is set to internal
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-badges': patch
---
Update badge dialog formatting
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-api': patch
---
Changed the signature of `createRoutableExtension` to include null
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/catalog-client': patch
---
Throw the new `ResponseError` from `@backstage/errors`
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cost-insights': patch
---
fix missing type exports of public components
+31
View File
@@ -0,0 +1,31 @@
---
'@backstage/create-app': patch
---
(fix) Adds locationAnalyzer to default-app template
The locationAnalyzer was missing from the default-app template.
This resulted in 404 errors in newly bootstrapped backstage applications,
when adding components without configuration.
To fix this in an existing backstage application, the locationAnalyzer needs
to be carried from the builder to the router in the
`packages/backend/src/plugins/catalog.ts` file.
```diff
const builder = new CatalogBuilder(env);
const {
entitiesCatalog,
locationsCatalog,
higherOrderOperation,
+ locationAnalyzer,
} = await builder.build();
// ...
return await createRouter({
entitiesCatalog,
locationsCatalog,
higherOrderOperation,
+ locationAnalyzer,
logger: env.logger,
});
```
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/core-api': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-github-actions': patch
'@backstage/plugin-jenkins': patch
---
Introduce `useRouteRefParams` to `core-api` to retrieve typed route parameters.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-graphiql': patch
---
Export `GraphiQLIcon`.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-search-backend': patch
'@backstage/plugin-search-backend-node': patch
---
Bump to use the in-repo latest `backend-common`, and the correct version of `express-promise-router`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-badges': patch
---
Get the current entity using `useEntity` from `@backstage/plugin-catalog-react`
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-user-settings': patch
---
Avoid using `ApiRef` descriptions in the UI.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': patch
---
Temporarily add `UNSTABLE_extraContextMenuItems` to the entity layout, so that we could detach the catalog plugin from the dependency on the badges plugin
+41
View File
@@ -0,0 +1,41 @@
---
'@backstage/create-app': patch
---
Adds plugin-org and more capability to the default EntityPage to display Users, Groups and Systems.
To update an existing application, add the org plugin:
```shell
cd packages/app
yarn add @backstage/plugin-org
```
Then add the example systems locations to your `app-config.yaml`:
```diff
catalog:
rules:
- - allow: [Component, API, Group, User, Template, Location]
+ - allow: [Component, System, API, Group, User, Template, Location]
locations:
# Backstage example components
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all-components.yaml
+ # Backstage example systems
+ - type: url
+ target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all-systems.yaml
+
# Backstage example APIs
```
Additionally, the default app sidebar was updated to parity with the Backstage
repo. You can see these changes in the template
[App.tsx](https://github.com/backstage/backstage/blob/8817a87cdd5c881fbe8a43557ba7f9df0f9e3258/packages/create-app/templates/default-app/packages/app/src/App.tsx#L70)
referencing a new `Root` component.
Finally, compare your `packages/app/src/components/catalog/EntityPage.tsx` to
[EntityPage](https://github.com/backstage/backstage/blob/8817a87cdd5c881fbe8a43557ba7f9df0f9e3258/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx)
from the `@backstage/create-app` default template to pick up additional
changes there.
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-techdocs': minor
'@backstage/plugin-techdocs-backend': minor
---
When newer documentation available but not built, show older documentation while async building newer
TechDocs backend: /sync endpoint added to support above, returns immediate success if docs don't need a build, returns delayed success after build if needed
TechDocs backend: /docs endpoint removed as frontend can directly request to techdocs.storageUrl or /static/docs
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-sonarqube': patch
---
Support SonarQube project keys containing special characters like colons.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-kubernetes': patch
---
Add tests for kubernetes custom hook
-31
View File
@@ -1,31 +0,0 @@
---
'@backstage/backend-common': minor
---
Encode thrown errors in the backend as a JSON payload. This is technically a breaking change, since the response format even of errors are part of the contract. If you relied on the response being text, you will now have some extra JSON "noise" in it. It should still be readable by end users though.
Before:
```
NotFoundError: No entity named 'tara.macgovern2' found, with kind 'user' in namespace 'default'
at eval (webpack-internal:///../../plugins/catalog-backend/src/service/router.ts:117:17)
```
After:
```json
{
"error": {
"name": "NotFoundError",
"message": "No entity named 'tara.macgovern2' found, with kind 'user' in namespace 'default'",
"stack": "NotFoundError: No entity named 'tara.macgovern2' found, with kind 'user' in namespace 'default'\n at eval (webpack-internal:///../../plugins/catalog-backend/src/service/router.ts:117:17)"
},
"request": {
"method": "GET",
"url": "/entities/by-name/user/default/tara.macgovern2"
},
"response": {
"statusCode": 404
}
}
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
Lint storybook files, i.e. `*.stories.*`, as if they were tests.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-auth-backend': patch
---
The `auth` config types now properly accept any declared auth environment. Previously only `development` was accepted.
The `audience` configuration is no longer required for GitLab auth; this will default to `https://gitlab.com`
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core': patch
---
Add a `ResponseErrorPanel` to render `ResponseError` from `@backstage/errors`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Add inputs for action `fetch:cookiecutter`: copyWithoutRender, extensions, imageName
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
Introduce workaround for admonition icons of MkDocs.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-todo-backend': patch
---
Forward authorization on todo backend requests
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/create-app': patch
---
Update the create-app template to use the correct latest version of `express-promise-router`.
To apply the same change in your own repository, update all of your repo's dependencies on `express-promise-router` to `"^4.1.0"`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core': patch
---
Reuse ResponseErrorList for non ResponseErrors
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': patch
---
Add icon for entity badge menu
-10
View File
@@ -1,10 +0,0 @@
---
'@backstage/techdocs-common': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-techdocs-backend': patch
---
Use errors from `@backstage/errors`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
TechDocs: links at sidebar and bottom reset scroll position to top
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Added a `publish:file` action to use for local development. The action is not installed by default.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Log how many repositories were actually matching in `GithubDiscoveryProcessor`
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/core': patch
'@backstage/theme': patch
---
Changed color for Add Item, Support & Choose buttons with low contrast/readability in dark mode
@@ -1,15 +0,0 @@
---
'@backstage/techdocs-common': patch
'@backstage/plugin-techdocs-backend': patch
---
Applies only if you use TechDocs local builder instead of building on CI/CD i.e. if `techdocs.builder` in your `app-config.yaml` is set to `'local'`
Improvements
1. Do not check for updates in the repository if a check has been made in the last 60 seconds. This is to prevent the annoying check for update on every page switch or load.
2. No need to maintain an in-memory etag storage, and use the one stored in `techdocs_metadata.json` file alongside generated docs.
New feature
1. You can now use a mix of basic and recommended setup i.e. `techdocs.builder` is `'local'` but using an external cloud storage instead of local storage. Previously, in this setup, the docs would never get updated.
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': minor
---
Add sticky sidebars and footer navigation links to TechDocs Reader
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-techdocs': patch
---
Extended TechDocs HomePage with owned documents
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-api': patch
---
Added new Docs Icon to Core Icons
+32
View File
@@ -0,0 +1,32 @@
---
'@backstage/plugin-catalog-backend': patch
---
Introduce pagination in the /entities catalog endpoint.
Pagination is requested using query parameters. Currently supported parameters, all optional, are:
- `limit` - an integer number of entities to return, at most
- `offset` - an integer number of entities to skip over at the start
- `after` - an opaque string cursor as returned by a previous paginated request
Example request:
`GET /entities?limit=100`
Example response:
```
200 OK
Content-Type: application/json; charset=utf-8
Link: </entities?limit=100&after=eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ%3D%3D>; rel="next"
<more headers>
[{"metadata":{...
```
Note the Link header. It contains the URL (path and query part, relative to the catalog root) to use for requesting the next page.
It uses the `after` cursor to point out the end of the previous page. If the Link header is not present, there is no more data to read.
The current implementation is naive and encodes offset/limit in the cursor implementation, so it is not robust in the face of overlapping
changes to the catalog. This can be improved separately in the future without having to change the calling patterns.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Make the backend plugin template use the correct latest version of `express-promise-router`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core': patch
---
Fix PropTypes error with OverflowTooltip component
-10
View File
@@ -1,10 +0,0 @@
---
'@backstage/backend-common': minor
---
Removed the custom error types (e.g. `NotFoundError`). Those are now instead in the new `@backstage/errors` package. This is a breaking change, and you will have to update your imports if you were using these types.
```diff
-import { NotFoundError } from '@backstage/backend-common';
+import { NotFoundError } from '@backstage/errors';
```
+1
View File
@@ -11,6 +11,7 @@
/plugins/cost-insights @backstage/silver-lining
/plugins/cloudbuild @trivago/ebarrios
/plugins/search @backstage/techdocs-core
/plugins/search-* @backstage/techdocs-core
/plugins/techdocs @backstage/techdocs-core
/plugins/techdocs-backend @backstage/techdocs-core
/packages/techdocs-common @backstage/techdocs-core
+17
View File
@@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
+8
View File
@@ -33,6 +33,7 @@ Grafana
GraphQL
Gustavsson
Hackathons
Haughwout
Henneke
Heroku
Hostname
@@ -42,7 +43,9 @@ JavaScript
Kaewkasi
Knex
Kumar
Leasot
Lerna
Lindgren
Lundberg
Luxon
Malus
@@ -58,6 +61,7 @@ Oldsberg
Olle
Onboarding
Patrik
Peloton
Phoen
Platformize
Pomaceous
@@ -88,6 +92,7 @@ Telenor
Templater
Templaters
Thauer
todo
Tolerations
Tuite
Trendyol
@@ -138,6 +143,7 @@ css
dariddler
dataflow
deadnaming
declaratively
destructured
dev
devops
@@ -239,6 +245,7 @@ ruleset
sam
scaffolded
scaffolder
seb
semlas
semver
sourcemaps
@@ -263,6 +270,7 @@ templated
templater
templaters
theia
thumbsup
toc
tolerations
toolchain
+5 -5
View File
@@ -1,10 +1,10 @@
name: Check Markdown files quality
on:
pull_request:
branches: [master]
paths:
- '**.md'
# on:
# pull_request:
# branches: [master]
# paths:
# - '**.md'
jobs:
check-all-files:
+26 -24
View File
@@ -1,24 +1,26 @@
| Organization | Contact | Description of Use |
| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
| [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. |
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
| [Expedia Group](https://www.expediagroup.com) | [Mike Turner](mailto:miturner@expediagroup.com), [Sneha Kumar](mailto:snkumar@expediagroup.com), [@guillermomanzo](https://github.com/guillermomanzo) | EG Common Developer Toolkit |
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling |
| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
| [Trendyol](https://trendyol.com) | [Erdogan Oksuz](https://github.com/erdoganoksuz) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. |
| Organization | Contact | Description of Use |
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
| [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. |
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
| [Expedia Group](https://www.expediagroup.com) | [Mike Turner](mailto:miturner@expediagroup.com), [Sneha Kumar](mailto:snkumar@expediagroup.com), [@guillermomanzo](https://github.com/guillermomanzo), [Erik Lindgren](https://github.com/lindgren) | EG Common Developer Toolkit |
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling |
| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
| [Trendyol](https://trendyol.com) | [Erdogan Oksuz](https://github.com/erdoganoksuz) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. |
| [Peloton](https://www.onepeloton.com/) | [Jim Haughwout](https://github.com/JimHaughwout) | Creating our first developer portal and tech-docs. Exploring Service Catalog, Tech Insights and Cost Insights as well. |
| [TELUS](https://telus.com) | [Seb Barre](https://github.com/sbarre) | The Go-to place to find answers about development and delivery at TELUS. |
+3
View File
@@ -14,6 +14,9 @@ This page lists all active sponsors and maintainers.
- Patrik Oldsberg ([rugvip](https://github.com/rugvip)) (Discord: @Rugvip)
- Fredrik Adelöw ([freben](https://github.com/freben)) (Discord: @freben)
- Ben Lambert ([benjdlambert](https://github.com/benjdlambert)) (Discord: @blam)
# Emeritus maintainers
- Stefan Ålund ([stefanalund](https://github.com/stefanalund)) (Discord: @stalund)
# Friends of Backstage
+21
View File
@@ -236,6 +236,27 @@ Backend failed to start up Error: unable to verify the first certificate
This error happens in the backend when it tries to connect to the configured PostgreSQL database and the specified CA is not correct. The solution is to make sure that the contents of the `configMap` that holds the certificate match the CA for the PostgreSQL instance. A workaround is to set `appConfig.backend.database.connection.ssl.rejectUnauthorized` to `false` in the chart's values.
#### Multi-Platform Kubernetes Services
If you are running a multi-platform Kubernetes service with Windows and Linux nodes then you will need to apply a `nodeSelector` to the Helm chart to ensure that pods are scheduled onto the correct platform nodes.
Add the following to your Helm values file:
```yaml
global:
nodeSelector:
kubernetes.io/os: linux
# If using Postgres Chart also add
postgresql:
master:
nodeSelector:
kubernetes.io/os: linux
slave:
nodeSelector:
kubernetes.io/os: linux
```
<!-- TODO Add example command when we know the final name of the charts -->
## Uninstalling Backstage
@@ -63,6 +63,10 @@ spec:
configMap:
name: {{ include "backstage.fullname" . }}-app-config
{{- if .Values.global.nodeSelector }}
nodeSelector: {{- toYaml .Values.global.nodeSelector | nindent 8 }}
{{- end }}
{{- if .Values.backend.enabled }}
---
apiVersion: v1
@@ -43,6 +43,9 @@ spec:
- name: app-config
configMap:
name: {{ include "backstage.fullname" . }}-app-config
{{- if .Values.global.nodeSelector }}
nodeSelector: {{- toYaml .Values.global.nodeSelector | nindent 8 }}
{{- end }}
{{- if .Values.frontend.enabled }}
---
apiVersion: v1
@@ -59,6 +59,10 @@ spec:
- name: postgres-ca
configMap:
name: {{ include "backstage.fullname" . }}-postgres-ca
{{- if .Values.global.nodeSelector }}
nodeSelector: {{- toYaml .Values.global.nodeSelector | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
+1
View File
@@ -69,6 +69,7 @@ global:
postgresql:
postgresqlUsername: backend-user
caFilename: ca.crt
nodeSelector: {}
postgresql:
enabled: true
@@ -0,0 +1,11 @@
FROM alpine:3.7
RUN apk add --update \
git \
python \
python-dev \
py-pip \
g++ && \
pip install cookiecutter jinja2_custom_filters_extension && \
apk del g++ py-pip python-dev && \
rm -rf /var/cache/apk/*
@@ -0,0 +1,73 @@
# Using Cookiecutter with Jinja2 extensions
Jinja2 extensions can be used with the scaffolder's `fetch:cookiecutter` built-in action to add filters, tests, or to extend the parser.
Using Cookiecutter extensions is a two-step process:
- [Installing the extension](#installing-the-extension), and
- [Instructing Cookiecutter to use the extension](#instructing-cookiecutter-to-use-the-extension)
### Installing the extension
This step depends on how the scaffolder is setup to use Cookiecutter:
- Using a local Cookiecutter, or
- Using a Cookiecutter Docker image, e.g. [spotify/backstage-cookiecutter](https://github.com/backstage/backstage/blob/37e35b91/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile).
Say we want to install [`jinja2_custom_filters_extension`](https://pypi.org/project/jinja2-custom-filters-extension/) to use the `upper_case_first_letter` filter in a Cookiecutter template.
#### Using a local Cookiecutter
The scaffolder is able to execute a locally installed Cookiecutter, and doesn't pull a Docker image in that case. If that's your setup, just ensure that the Jinja2 extensions, available via `pip` are installed alongside Cookiecutter, e.g. if Cookiecutter is baked into a custom Backstage image using `pip` and a `requirements.txt`:
In the custom Backstage Dockerfile:
```Dockerfile
...
RUN pip3 install -r requirements.txt
...
```
In requirements.txt:
```python
...
cookiecutter==1.7.2
jinja2_custom_filters_extension==0.0.2
...
```
#### Using a Cookiecutter Docker image
If the scaffolder doesn't find a local Cookiecutter, it pulls down the `spotify/backstage-cookiecutter` image. You can create a custom Cookiecutter image based on that, install extensions into it, and specify that customised image as an input `imageName` to the `fetch:cookiecutter` action:
```yaml
steps:
- id: fetch-base
name: Fetch Base
action: fetch:cookiecutter
input:
url: https://github.com/spotify/cookiecutter-golang
imageName: 'foo/custom-built-cookiecutter-image-with-extensions'
```
See for example, the [`Dockerfile`](./Dockerfile) in this directory.
### Instructing Cookiecutter to use the extension
Cookiecutter enables extensions mentioned in `cookiecutter.json`. `fetch:cookiecutter` generates a `cookiecutter.json`, deriving its values from `inputs` to `fetch:cookiecutter` in the scaffolder [Template](https://backstage.io/docs/features/software-templates/writing-templates), as:
```yaml
steps:
- id: fetch-base
name: Fetch Base
action: fetch:cookiecutter
input:
extensions:
- jinja2_custom_filters_extension.string_filters_extension.StringFilterExtension
url: https://github.com/spotify/cookiecutter-golang
values:
name: '{{ parameters.name }}'
```
Cookiecutter enables a few extensions by default. See the official Cookiecutter documentation for [Template Extensions](https://cookiecutter.readthedocs.io/en/1.7.2/advanced/template_extensions.html) for a list of such extensions, and more information.
@@ -6,7 +6,7 @@ API requests from frontend plugins include an authorization header with a Backst
Note that this means Backstage will stop working for guests, as no token is issued for them.
Caveat: as of writing this, Backstage does not refresh the identity token so eventually users will get a 401 response on API calls (not on loading the web page as only the API calls are authenticated) and have to logout/login again to get a new token.
As techdocs HTML pages load assets without an Authorization header the code below also sets a token cookie when the user logs in (and when the token is about to expire).
```typescript
// packages/backend/src/index.ts from a create-app deployment
@@ -82,6 +82,10 @@ async function main() {
apiRouter.use(cookieParser());
// The auth route must be publically available as it is used during login
apiRouter.use('/auth', await auth(authEnv));
// Add a simple endpoint to be used when setting a token cookie
apiRouter.use('/cookie', authMiddleware, (_req, res) => {
res.status(200).send(`Coming right up`);
});
// Only authenticated requests are allowed to the routes below
apiRouter.use('/catalog', authMiddleware, await catalog(catalogEnv));
apiRouter.use('/techdocs', authMiddleware, await techdocs(techdocsEnv));
@@ -91,3 +95,89 @@ async function main() {
// ...
}
```
```typescript
// packages/app/src/App.tsx from a create-app deployment
import { discoveryApiRef, useApi } from '@backstage/core';
// ...
// Parses supplied JWT token and returns the payload
function parseJwt(token: string): { exp: number } {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(
atob(base64)
.split('')
.map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
})
.join(''),
);
return JSON.parse(jsonPayload);
}
// Returns milliseconds until the supplied JWT token expires
function msUntilExpiry(token: string): number {
const payload = parseJwt(token);
const remaining =
new Date(payload.exp * 1000).getTime() - new Date().getTime();
return remaining;
}
// Calls the specified url regularly using an auth token to set a token cookie
// to authorize regular HTTP requests when loading techdocs
async function setTokenCookie(url: string, getIdToken: () => Promise<string>) {
const token = await getIdToken();
await fetch(url, {
mode: 'cors',
credentials: 'include',
headers: {
Authorization: `Bearer ${token}`,
},
});
// Call this function again a few minutes before the token expires
const ms = msUntilExpiry(token) - 4 * 60 * 1000;
setTimeout(
() => {
setTokenCookie(url, getIdToken);
},
ms > 0 ? ms : 10000,
);
}
const app = createApp({
// ...
components: {
SignInPage: props => {
const discoveryApi = useApi(discoveryApiRef);
return (
<SignInPage
{...props}
providers={['guest', 'custom', ...providers]}
title="Select a sign-in method"
align="center"
onResult={async result => {
// When logged in, set a token cookie
if (typeof result.getIdToken !== 'undefined') {
setTokenCookie(
await discoveryApi.getBaseUrl('cookie'),
result.getIdToken,
);
}
// Forward results
props.onResult(result);
}}
/>
);
},
},
// ...
});
// ...
```
+1 -1
View File
@@ -23,7 +23,7 @@ describe('Catalog', () => {
cy.visit('/catalog');
cy.contains('Owned (7)').should('be.visible');
cy.contains('Owned (8)').should('be.visible');
});
});
});
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

+6 -6
View File
@@ -1,4 +1,4 @@
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="789px" height="766px" viewBox="-0.5 -0.5 789 766" content="&lt;mxfile host=&quot;be2f1433-9da5-431b-92db-92882262d7d1&quot; modified=&quot;2021-02-10T13:37:29.724Z&quot; agent=&quot;5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.53.0 Chrome/87.0.4280.141 Electron/11.2.1 Safari/537.36&quot; etag=&quot;EtMH9Eo_7GPdazvr9TBW&quot; version=&quot;14.2.4&quot; type=&quot;embed&quot;&gt;&lt;diagram id=&quot;AOZgdlUmH_6GT6Gt5u4e&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);">
<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="789px" height="766px" viewBox="-0.5 -0.5 789 766" content="&lt;mxfile&gt;&lt;diagram id=&quot;AOZgdlUmH_6GT6Gt5u4e&quot; name=&quot;Page-1&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);">
<defs/>
<g>
<rect x="560" y="484" width="140" height="140" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
@@ -268,7 +268,7 @@
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 220px; margin-left: 350px;">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 220px; margin-left: 351px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
Pass Search
@@ -282,7 +282,7 @@
</div>
</div>
</foreignObject>
<text x="350" y="223" fill="#5C5C5C" font-family="Helvetica" font-size="11px" text-anchor="middle">
<text x="351" y="223" fill="#5C5C5C" font-family="Helvetica" font-size="11px" text-anchor="middle">
Pass Search...
</text>
</switch>
@@ -368,7 +368,7 @@
</g>
<path d="M 444.17 349.5 C 444.17 341.22 453.31 334.5 464.59 334.5 C 470.01 334.5 475.2 336.08 479.03 338.89 C 482.86 341.71 485.01 345.52 485.01 349.5 L 485.01 379 C 485.01 387.28 475.87 394 464.59 394 C 453.31 394 444.17 387.28 444.17 379 Z" fill="#21c0a5" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 485.01 349.5 C 485.01 357.78 475.87 364.5 464.59 364.5 C 453.31 364.5 444.17 357.78 444.17 349.5" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="all"/>
<path d="M 550 364.25 L 517.5 364.3 L 485.01 364.25" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
<path d="M 550 364.25 L 517.5 364.3 L 485.01 364.3" fill="none" stroke="#006658" stroke-miterlimit="10" pointer-events="stroke"/>
<rect x="550" y="324.25" width="80" height="80" fill="#21c0a5" stroke="#006658" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
@@ -529,7 +529,7 @@
</text>
</switch>
</g>
<rect x="565" y="80" width="130" height="30" fill="none" stroke="none" pointer-events="all"/>
<rect x="565" y="80" width="170" height="30" fill="none" stroke="none" pointer-events="all"/>
<g transform="translate(-0.5 -0.5)">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
@@ -538,7 +538,7 @@
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #5C5C5C; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
@backstage/
<br/>
plugin-search-indexer
plugin-search-backend-node
</div>
</div>
</div>

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

+36 -77
View File
@@ -6,84 +6,18 @@ description: Documentation on Software Catalog Configuration
## Processors
The catalog makes use of so called processors to perform all kinds of ingestion
tasks, such as reading raw entity data from a remote source, parsing it,
transforming it, and validating it. These processors are configured under the
`catalog.processors` key.
The catalog has a concept of _processors_ to perform catalog ingestion tasks,
such as reading raw entity data from a remote source, parsing it, transforming
it, and validating it. These processors are configured under the
`catalog.processors` configuration key.
### Processor: url
### Static Location Configuration
The `url` processor is responsible for fetching entity data from files in any
external provider like GitHub, GitLab, Bitbucket, etc. The configuration of this
processor lives under the top-level `integrations` key, as it is used by other
parts of Backstage too.
The simplest configuration for the catalog, as shown in the default
`@backstage/create-app` template, is to declaratively add locations pointing to
YAML files with [static configuration](../../conf/index.md).
```yaml
integrations:
github:
- host: github.com
token:
$env: GITHUB_TOKEN
- host: ghe.example.net
apiBaseUrl: https://ghe.example.net/api/v3
rawBaseUrl: https://ghe.example.net/raw
token:
$env: GHE_TOKEN
gitlab:
- host: gitlab.com
token:
$env: GITLAB_TOKEN
bitbucket:
- host: bitbucket.org
username:
$env: BITBUCKET_USERNAME
appPassword:
$env: BITBUCKET_APP_PASSWORD
azure:
- host: dev.azure.com
token:
$env: AZURE_TOKEN
```
Each key under `integrations` is a separate configuration for each external
provider. The providers each have their own configuration, so let's look at the
GitHub section as an example.
Directly under the `github` key is a list of provider configurations, where you
can list the various GitHub compatible providers you want to be able to fetch
data from. Each entry is a structure with up to four elements:
- `host` (optional): The host of the location target that you want to match on.
The default host is `github.com`.
- `token` (optional): An authentication token as expected by GitHub. If
supplied, it will be passed along with all calls to this provider, both API
and raw. If it is not supplied, anonymous access will be used.
- `apiBaseUrl` (optional): If you want to communicate using the APIv3 method
with this provider, specify the base URL for its endpoint here, with no
trailing slash. Specifically when the target is GitHub, you can leave it out
to be inferred automatically. For a GitHub Enterprise installation, it is
commonly at `https://api.<host>` or `https://<host>/api/v3`.
- `rawBaseUrl` (optional): If you want to communicate using the raw HTTP method
with this provider, specify the base URL for its endpoint here, with no
trailing slash. Specifically when the target is public GitHub, you can leave
it out to be inferred automatically. For a GitHub Enterprise installation, it
is commonly at `https://api.<host>` or `https://<host>/api/v3`.
You need to supply either `apiBaseUrl` or `rawBaseUrl` or both (except for
public GitHub, for which we can infer them). The `apiBaseUrl` will always be
preferred over the other if a `token` is given, otherwise `rawBaseUrl` will be
preferred.
If you do not supply a public GitHub provider, one will be added automatically,
silently at startup for convenience. So you only have to list it if you want to
supply a token for it - and if you do, you can also leave out the `apiBaseUrl`
and `rawBaseUrl` fields.
## Static Location Configuration
To enable declarative catalog setups, it is possible to add locations to the
catalog via [static configuration](../../conf/index.md). Locations are added to
the catalog under the `catalog.locations` key, for example:
Locations are added to the catalog under the `catalog.locations` key:
```yaml
catalog:
@@ -92,10 +26,35 @@ catalog:
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml
```
The locations added through static configuration can not be removed through the
catalog locations API. To remove the locations, you have to remove them from the
The `url` type locations are handled by a standard processor included with the
catalog (`UrlReaderProcessor`), so no processor configuration is needed. This
processor _does however_ need an [integration](../../integrations/index.md) to
understand how to retrieve a given URL. For the example above, you would need to
configure the [GitHub integration](../../integrations/github/locations.md) to
read files from github.com.
The locations added through static configuration cannot be removed through the
catalog locations API. To remove these locations, you must remove them from the
configuration.
### Integration Processors
Integrations may simply provide a mechanism to handle `url` location type for an
external provider, or they may also include additional processors out of the
box, such as the GitHub [discovery](../../integrations/github/discovery.md)
processor that scans a GitHub organization for
[entity descriptor files](descriptor-format.md).
Check the [integrations](../../integrations/index.md) documentation to see what
is offered by each integration.
### Custom Processors
To ingest entities from an existing system already tracking software, you can
also write a _custom processor_ to convert between the existing system and
Backstage's descriptor format. This is documented in
[External Integrations](external-integrations.md).
## Catalog Rules
By default the catalog will only allow ingestion of entities with the kind
@@ -35,8 +35,32 @@ we recommend that you name them `catalog-info.yaml`.
## Overall Shape Of An Entity
The following is an example of the shape of an entity as returned from the
software catalog API.
The following is an example of a descriptor file for a Component entity:
```yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: artist-web
description: The place to be, for great artists
labels:
system: public-websites
annotations:
example.com/service-discovery: artistweb
circleci.com/project-slug: github/example-org/artist-website
tags:
- java
links:
- url: https://admin.example-org.com
title: Admin Dashboard
icon: dashboard
spec:
type: website
lifecycle: production
owner: artist-relations-team
```
This is the same entity as returned in JSON from the software catalog API:
```js
{
@@ -71,31 +95,6 @@ software catalog API.
}
```
The corresponding descriptor file that generated it may look as follows:
```yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: artist-web
description: The place to be, for great artists
labels:
system: public-websites
annotations:
example.com/service-discovery: artistweb
circleci.com/project-slug: github/example-org/artist-website
tags:
- java
links:
- url: https://admin.example-org.com
title: Admin Dashboard
icon: dashboard
spec:
type: website
lifecycle: production
owner: artist-relations-team
```
The root fields `apiVersion`, `kind`, `metadata`, and `spec` are part of the
_envelope_, defining the overall structure of all kinds of entity. Likewise,
some metadata fields like `name`, `labels`, and `annotations` are of special
+32 -75
View File
@@ -10,8 +10,9 @@ outlined below.
## Installing @backstage/plugin-catalog
> **Note that if you used `npx @backstage/create-app`, the plugin may already be
> present**
> **Note that if you used `npx @backstage/create-app`, the plugin is already
> installed and you can skip to
> [adding entries to the catalog](#adding-entries-to-the-catalog)**
The catalog frontend plugin should be installed in your `app` package, which is
created as a part of `@backstage/create-app`. To install the package, run:
@@ -21,10 +22,6 @@ cd packages/app
yarn add @backstage/plugin-catalog
```
Make sure the version of `@backstage/plugin-catalog` matches the version of
other `@backstage` packages. You can update it in `packages/app/package.json` if
it doesn't.
### Adding the Plugin to your `packages/app`
Add the following entry to the head of your `packages/app/src/plugins.ts`:
@@ -37,6 +34,7 @@ Next we need to install the two pages that the catalog plugin provides. You can
choose any name for these routes, but we recommend the following:
```tsx
// packages/app/src/App.tsx
import {
catalogPlugin,
CatalogIndexPage,
@@ -60,6 +58,7 @@ user can create components. In a typical setup the create component route will
be linked to the Scaffolder plugin's template index page:
```ts
// packages/app/src/App.tsx
import { catalogPlugin } from '@backstage/plugin-catalog';
import { scaffolderPlugin } from '@backstage/plugin-scaffolder';
@@ -76,6 +75,7 @@ const app = createApp({
You may also want to add a link to the catalog index page to your sidebar:
```tsx
// packages/app/src/components/Root.tsx
import HomeIcon from '@material-ui/icons/Home';
// Somewhere within the <Sidebar>
@@ -88,7 +88,7 @@ This is all that is needed for the frontend part of the Catalog plugin to work!
Since the catalog plugin currently ships with a sentry plugin `InfoCard`
installed by default, you'll need to set `sentry.organization` in your
`app-yaml.yaml`. For example:
`app-config.yaml`. For example:
```yaml
sentry:
@@ -101,8 +101,9 @@ as that will conflict with the catalog routes.
## Installing @backstage/plugin-catalog-backend
> **Note that if you used `npx @backstage/create-app`, the plugin may already be
> present**
> **Note that if you used `npx @backstage/create-app`, the plugin is already
> installed and you can skip to
> [adding entries to the catalog](#adding-entries-to-the-catalog)**
The catalog backend should be installed in your `backend` package, which is
created as a part of `@backstage/create-app`. To install the package, run:
@@ -112,59 +113,12 @@ cd packages/backend
yarn add @backstage/plugin-catalog-backend
```
Make sure the version of `@backstage/plugin-catalog-backend` matches the version
of other `@backstage` packages. You can update it in
`packages/backend/package.json` if it doesn't.
### Adding the Plugin to your `packages/backend`
You'll need to add the plugin to the `backend`'s router. You can do this by
creating a file called `packages/backend/src/plugins/catalog.ts` with the
following contents to get you up and running quickly.
```ts
import {
createRouter,
DatabaseEntitiesCatalog,
DatabaseLocationsCatalog,
DatabaseManager,
HigherOrderOperations,
LocationReaders,
runPeriodically,
} from '@backstage/plugin-catalog-backend';
import { PluginEnvironment } from '../types';
import { useHotCleanup } from '@backstage/backend-common';
export default async function createPlugin({
logger,
database,
}: PluginEnvironment) {
const locationReader = new LocationReaders(logger);
const db = await DatabaseManager.createDatabase(database, { logger });
const entitiesCatalog = new DatabaseEntitiesCatalog(db);
const locationsCatalog = new DatabaseLocationsCatalog(db);
const higherOrderOperation = new HigherOrderOperations(
entitiesCatalog,
locationsCatalog,
locationReader,
db,
logger,
);
useHotCleanup(
module,
runPeriodically(() => higherOrderOperation.refreshAllLocations(), 10000),
);
return await createRouter({
entitiesCatalog,
locationsCatalog,
higherOrderOperation,
logger,
});
}
```
creating a file called `packages/backend/src/plugins/catalog.ts` with contents
matching
[catalog.ts in the create-app template](https://github.com/backstage/backstage/blob/master/packages/create-app/templates/default-app/packages/backend/src/plugins/catalog.ts).
Once the `catalog.ts` router setup file is in place, add the router to
`packages/backend/src/index.ts`:
@@ -174,10 +128,9 @@ import catalog from './plugins/catalog';
const catalogEnv = useHotMemoize(module, () => createEnv('catalog'));
const service = createServiceBuilder(module)
.loadConfig(configReader)
/** several different routers */
.addRouter('/catalog', await catalog(catalogEnv));
const apiRouter = Router();
/** several different routers */
apiRouter.use('/catalog', await catalog(catalogEnv));
```
### Adding Entries to the Catalog
@@ -192,33 +145,37 @@ our example templates through static configuration. Add the following to the
```yaml
catalog:
locations:
# Backstage Example Component
# Backstage Example Components
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/artist-lookup-component.yaml
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/playback-order-component.yaml
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/playback-order-component.yaml
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/podcast-api-component.yaml
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/podcast-api-component.yaml
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/queue-proxy-component.yaml
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/queue-proxy-component.yaml
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/searcher-component.yaml
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/searcher-component.yaml
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/playback-lib-component.yaml
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/playback-lib-component.yaml
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/www-artist-component.yaml
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/www-artist-component.yaml
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/shuffle-api-component.yaml
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/components/shuffle-api-component.yaml
```
### Running the Backend
Finally, start up the backend with the new configuration:
Finally, start up Backstage with the new configuration:
```bash
# Run from the root to start both backend and frontend
yarn dev
# Alternatively, run only the backend from its own package
cd packages/backend
yarn start
```
If you've also set up the frontend plugin, so you should be ready to go browse
the catalog at [localhost:3000](http://localhost:3000) now!
If you've also set up the frontend plugin, you should be ready to go browse the
catalog at [localhost:3000](http://localhost:3000) now!
@@ -108,8 +108,3 @@ domain would come with some documentation on how to accept payments for a new
product or use-case, share the same entity types in their APIs, and integrate
well with each other. Other domains could be “Content Ingestion”, “Ads” or
“Search”.
## Links
- [Original RFC](https://github.com/backstage/backstage/issues/390)
- [YAML file format](../../architecture-decisions/adr002-default-catalog-file-format.md)
@@ -24,10 +24,6 @@ cd packages/app
yarn add @backstage/plugin-scaffolder
```
Make sure the version of `@backstage/plugin-scaffolder` matches the version of
other `@backstage` packages. You can update it in `packages/app/package.json` if
it doesn't.
### Adding the Plugin to your `packages/app`
Add the following entry to the head of your `packages/app/src/plugins.ts`:
@@ -71,10 +67,6 @@ cd packages/backend
yarn add @backstage/plugin-scaffolder-backend
```
Make sure the version of `@backstage/plugin-scaffolder-backend` matches the
version of other `@backstage` packages. You can update it in
`packages/backend/package.json` if it doesn't.
### Adding the Plugin to your `packages/backend`
You'll need to add the plugin to the `backend`'s router. You can do this by
@@ -16,7 +16,8 @@ alongside your `backend` package in `packages/backend`.
Let's create a simple action that adds a new file and some contents that are
passed as `input` to the function.
In `packages/backend/src/actions/custom.ts` we can create a new action.
In `packages/backend/src/plugins/scaffolder/actions/custom.ts` we can create a
new action.
```ts
import { createTemplateAction } from '@backstage/plugin-scaffolder-backend';
@@ -56,7 +57,7 @@ export const createNewFileAction = () => {
So let's break this down. The `createNewFileAction` is a function that returns a
`createTemplateAction`, and it's a good place to pass in dependencies which
close over the `TemplateAction`. Take a look at our
[built-in actions](https://github.com/backstage/backstage/blob/7f5716081f45a41dc8a4246134b50c893e15c5e1/../plugins/scaffolder-backend/src/scaffolder/actions/builtin/publish/github.ts)
[built-in actions](https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/src/scaffolder/actions/builtin)
for reference.
We set the type generic to `{ contents: string, filename: string}` which is
@@ -265,7 +265,7 @@ The main two that are used are the following:
```yaml
output:
remoteUrl: '{{ steps.publish.output.remoteUrl }}' # link to the remote repository
entityRef: '{{ steps.register.output.entityRef }}' # link to the entitiy that has been ingested to the catalog
entityRef: '{{ steps.register.output.entityRef }}' # link to the entity that has been ingested to the catalog
```
### The templating syntax
+10 -11
View File
@@ -35,20 +35,19 @@ Add the following to `packages/app/src/plugins.ts`:
export { plugin as TechDocs } from '@backstage/plugin-techdocs';
```
Now let us embed the TechDocs router in our main Backstage frontend router. In
`packages/app/src/App.tsx`, import the TechDocs router and add the following to
`AppRoutes`:
Now we can add a route for the TechDocs page. In `packages/app/src/App.tsx`,
import TechDocsPage and add the following to `FlatRoutes`:
```tsx
import { Router as DocsRouter } from '@backstage/plugin-techdocs';
import { TechDocsPage } from '@backstage/plugin-techdocs';
// ...
const AppRoutes = () => {
<Routes>
<FlatRoutes>
// ... other plugin routes
<Route path="/docs/*" element={<DocsRouter />} />
</Routes>;
<Route path="/docs" element={<TechdocsPage />} />
</FlatRoutes>;
};
```
@@ -72,12 +71,12 @@ add the following
```typescript
import {
createRouter,
Preparers,
Generators,
Preparers,
Publisher,
} from '@backstage/plugin-techdocs-backend';
import { PluginEnvironment } from '../types';
import Docker from 'dockerode';
import { PluginEnvironment } from '../types';
export default async function createPlugin({
logger,
@@ -126,8 +125,8 @@ it.
See [Concepts](concepts.md) and [TechDocs Architecture](architecture.md) to
learn more about how preparers, generators and publishers work.
Final step is to import the techdocs backend plugin in Backstage app backend.
Add the following to your `packages/backend/src/index.ts`:
The final step is to import the techdocs backend plugin in Backstage app
backend. Add the following to your `packages/backend/src/index.ts`:
```typescript
import techdocs from './plugins/techdocs';
+21
View File
@@ -0,0 +1,21 @@
---
id: concepts
title: Key Concepts
# prettier-ignore
description: High level key concepts used in the Backstage project
---
For users of Backstage, there are certain concepts which are central to its
design and functionality. Being an expert in each of these concepts is not
necessary, however having a base understanding of each will make administering,
configuring, and operating Backstage easier.
- CHANGELOG - https://keepachangelog.com
- Docker - https://www.docker.com/
- Monorepo - https://semaphoreci.com/blog/what-is-monorepo
- Node.js - https://nodejs.org
- React - https://reactjs.org
- Semantic Versioning - https://semver.org
- TypeScript - https://www.typescriptlang.org
- YAML - https://yaml.org
- Yarn - https://www.pluralsight.com/guides/yarn-a-package-manager-for-node-js
@@ -68,8 +68,8 @@ proxy:
In a standard Backstage app created with
[@backstage/create-app](./create-an-app.md), the sidebar is managed inside
`packages/app/src/sidebar.tsx`. The file exports the entire `Sidebar` element of
your app, which you can extend with additional entries by adding new
`packages/app/src/components/Root.tsx`. The file exports the entire `Sidebar`
element of your app, which you can extend with additional entries by adding new
`SidebarItem` elements.
For example, if you install the `api-docs` plugin, a matching `SidebarItem`
+12
View File
@@ -15,6 +15,14 @@ are stateless, so for a production deployment you will want to set up and
connect to an external PostgreSQL instance where the backend plugins can store
their state, rather than using SQLite.
By default, in an app created with `@backstage/create-app`, the frontend is
bundled and served from the backend. This is done using the
`@backstage/plugin-app-backend` plugin, which also injects the frontend
configuration into the app. This means you that you only need to build and
deploy a single container in a minimal setup of Backstage. If you wish to
separate the serving of the frontend out from the backend, see
[the section on that topic below](#separate-frontend).
### Host Build
This section describes how to build a Docker image from a Backstage repo with
@@ -224,3 +232,7 @@ Once the `app-backend` is removed from the backend, you can use your favorite
static file serving method for serving the frontend. An example of how to set up
an NGINX image is available in the
[contrib folder in the main repo](https://github.com/backstage/backstage/blob/master/contrib/docker/frontend-with-nginx/Dockerfile)
Note that if you're building a separate docker build of the frontend you
probably need to adjust `.dockerignore` appropriately. Most likely by making
sure `packages/app/dist` is not ignored.
+1 -1
View File
@@ -33,7 +33,7 @@ Then use it to run:
```bash
git clone https://github.com/backstage/backstage.git
cd contrib/chart/backstage
cd backstage/contrib/chart/backstage
helm dependency update
helm install -f backstage-mydomain.yaml backstage .
```
+7
View File
@@ -42,6 +42,13 @@ this process in [Create an app](./create-an-app.md).
### Contributing to Backstage
If you intend to make changes to the core project's packages, certain plugins,
or project documentation, then you can fork and clone
[https://github.com/backstage/backstage](https://github.com/backstage/backstage).
This will let you run the latest code off of the `master` branch, fix bugs or
contribute new features, run test suites, etc.
You can read more in our
[CONTRIBUTING](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md)
guide, which can help you get setup with a Backstage development environment.
+30
View File
@@ -0,0 +1,30 @@
---
id: locations
title: Azure DevOps Locations
sidebar_label: Locations
description:
Integrating source code stored in Azure DevOps into the Backstage catalog
---
The Azure integration supports loading catalog entities from Azure DevOps.
Entities can be added to
[static catalog configuration](../../features/software-catalog/configuration.md),
or registered with the
[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import)
plugin.
```yaml
integrations:
azure:
- host: dev.azure.com
token: ${AZURE_TOKEN}
```
> Note: An Azure DevOps provider is added automatically at startup for
> convenience, so you only need to list it if you want to supply a
> [token](https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate).
The configuration is a structure with two elements:
- `host`: The DevOps host; only `dev.azure.com` is supported.
- `token` (optional): A personal access token as expected by Azure DevOps.
+41
View File
@@ -0,0 +1,41 @@
---
id: locations
title: BitBucket Locations
sidebar_label: Locations
description:
Integrating source code stored in BitBucket into the Backstage catalog
---
The BitBucket integration supports loading catalog entities from bitbucket.com
or a self-hosted BitBucket. Entities can be added to
[static catalog configuration](../../features/software-catalog/configuration.md),
or registered with the
[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import)
plugin.
```yaml
integrations:
bitbucket:
- host: bitbucket.org
username: ${BITBUCKET_USERNAME}
token: ${BITBUCKET_TOKEN}
```
> Note: A public BitBucket provider is added automatically at startup for
> convenience, so you only need to list it if you want to supply a
> [token](https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html).
Directly under the `bitbucket` key is a list of provider configurations, where
you can list the BitBucket providers you want to fetch data from. Each entry is
a structure with up to four elements:
- `host`: The host of the BitBucket instance, e.g. `bitbucket.company.com`.
- `token` (optional): An personal access token as expected by BitBucket. Either
an access token **or** a username + appPassword may be supplied.
- `username`: The BitBucket username to use in API requests. If neither a
username nor token are supplied, anonymous access will be used.
- `appPassword` (optional): The password for the BitBucket user. Only needed
when using `username` instead of `token`.
- `apiBaseUrl` (optional): The URL of the GitLab API. For self-hosted
installations, it is commonly at `https://<host>/api/v4`. For gitlab.com, this
configuration is not needed as it can be inferred.
+55
View File
@@ -0,0 +1,55 @@
---
id: discovery
title: GitHub Discovery
sidebar_label: Discovery
description:
Automatically discovering catalog entities from repositories in a GitHub
organization
---
The GitHub integration has a special discovery processor for discovering catalog
entities within a GitHub organization. The processor will crawl the GitHub
organization and register entities matching the configured path. This can be
useful as an alternative to static locations or manually adding things to the
catalog.
To use the discovery processor, you'll need a GitHub integration
[set up](locations.md) with a `GITHUB_TOKEN`. Then you can add a location target
to the catalog configuration:
```yaml
catalog:
locations:
- type: github-discovery
target: https://github.com/myorg/service-*/blob/main/catalog-info.yaml
```
Note the `github-discovery` type, as this is not a regular `url` processor.
The target is composed of three parts:
- The base organization URL, `https://github.com/myorg` in this case
- The repository blob to scan, which accepts \* wildcard tokens. This can simply
be `*` to scan all repositories in the organization. This example only looks
for repositories prefixed with `service-`.
- The path within each repository to find the catalog YAML file. This will
usually be `/blob/main/catalog-info.yaml`, `/blob/master/catalog-info.yaml` or
a similar variation for catalog files stored in the root directory of each
repository.
## GitHub API Rate Limits
GitHub
[rate limits](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting)
API requests to 5,000 per hour (or more for Enterprise accounts). The default
Backstage catalog backend refreshes data every 100 seconds, which issues an API
request for each discovered location.
This means if you have more than ~140 catalog entities, you may get throttled by
rate limiting. This will soon be resolved once catalog refreshes make use of
ETags; to work around this in the meantime, you can change the refresh rate of
the catalog in your `packages/backend/src/plugins/catalog.ts` file, or configure
Backstage to use the [github-apps plugin](../../plugins/github-apps.md).
This is true for any method of adding GitHub entities to the catalog, but
especially easy to hit with automatic discovery.
+64
View File
@@ -0,0 +1,64 @@
---
id: locations
title: GitHub Locations
sidebar_label: Locations
description: Integrating source code stored in GitHub into the Backstage catalog
---
The GitHub integration supports loading catalog entities from github.com or
GitHub Enterprise. Entities can be added to
[static catalog configuration](../../features/software-catalog/configuration.md),
registered with the
[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import)
plugin, or [discovered](discovery.md) from a GitHub organization. Users and
Groups can also be [loaded from an organization](org.md).
## Configuration
To use this integration, add configuration to your root `app-config.yaml`:
```yaml
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
- host: ghe.example.net
apiBaseUrl: https://ghe.example.net/api/v3
rawBaseUrl: https://ghe.example.net/raw
token: ${GHE_TOKEN}
```
> Note: A public GitHub provider is added automatically at startup for
> convenience, so you only need to list it if you want to supply a
> [token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
Directly under the `github` key is a list of provider configurations, where you
can list the various GitHub-compatible providers you want to be able to fetch
data from. Each entry is a structure with up to four elements:
- `host` (optional): The host of the location target that you want to match on.
The default host is `github.com`.
- `token` (optional): An authentication token as expected by GitHub. If
supplied, it will be passed along with all calls to this provider, both API
and raw. If it is not supplied, anonymous access will be used.
- `apiBaseUrl` (optional): If you want to communicate using the APIv3 method
with this provider, specify the base URL for its endpoint here, with no
trailing slash. Specifically when the target is GitHub, you can leave it out
to be inferred automatically. For a GitHub Enterprise installation, it is
commonly at `https://api.<host>` or `https://<host>/api/v3`.
- `rawBaseUrl` (optional): If you want to communicate using the raw HTTP method
with this provider, specify the base URL for its endpoint here, with no
trailing slash. Specifically when the target is public GitHub, you can leave
it out to be inferred automatically. For a GitHub Enterprise installation, it
is commonly at `https://<host>/raw`.
You need to supply either `apiBaseUrl` or `rawBaseUrl` or both (except for
public GitHub, for which we can infer them). The `apiBaseUrl` will always be
preferred over the other if a `token` is given, otherwise `rawBaseUrl` will be
preferred.
## Authentication with GitHub Apps
Alternatively, Backstage can use GitHub Apps for backend authentication. This
has higher rate limits, and a clearer authorization model. See the
[github-apps plugin](../../plugins/github-apps.md) for how to set this up.
+4 -5
View File
@@ -3,11 +3,11 @@ id: org
title: GitHub Organizational Data
sidebar_label: Org Data
# prettier-ignore
description: Setting up ingestion of organizational data from GitHub
description: Importing users and groups from a GitHub organization into Backstage
---
The Backstage catalog can be set up to ingest organizational data - teams and
users - directly from an organization in GitHub or GitHub Enterprise. The result
The Backstage catalog can be set up to ingest organizational data - users and
teams - directly from an organization in GitHub or GitHub Enterprise. The result
is a hierarchy of
[`User`](../../features/software-catalog/descriptor-format.md#kind-user) and
[`Group`](../../features/software-catalog/descriptor-format.md#kind-group) kind
@@ -46,8 +46,7 @@ catalog:
providers:
- target: https://github.com
apiBaseUrl: https://api.github.com
token:
$env: GITHUB_TOKEN
token: ${GITHUB_TOKEN}
```
Locations point out the specific org(s) you want to import. The `type` of these
+38
View File
@@ -0,0 +1,38 @@
---
id: locations
title: GitLab Locations
sidebar_label: Locations
description: Integrating source code stored in GitLab into the Backstage catalog
---
The GitLab integration supports loading catalog entities from gitlab.com or a
self-hosted GitLab. Entities can be added to
[static catalog configuration](../../features/software-catalog/configuration.md),
or registered with the
[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import)
plugin.
```yaml
integrations:
gitlab:
- host: gitlab.com
token: ${GITLAB_TOKEN}
```
> Note: A public GitLab provider is added automatically at startup for
> convenience, so you only need to list it if you want to supply a
> [token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html).
Directly under the `gitlab` key is a list of provider configurations, where you
can list the GitLab providers you want to fetch data from. Each entry is a
structure with up to four elements:
- `host`: The host of the GitLab instance, e.g. `gitlab.company.com`.
- `token` (optional): An authentication token as expected by GitLab. If this is
not supplied, anonymous access will be used.
- `apiBaseUrl` (optional): The URL of the GitLab API. For self-hosted
installations, it is commonly at `https://<host>/api/v4`. For gitlab.com, this
configuration is not needed as it can be inferred.
- `baseUrl` (optional): The base URL for this provider, e.g.
`https://gitlab.com`. If this is not provided, it is assumed to be
`https://{host}`.
@@ -6,19 +6,18 @@ sidebar_label: Installation
description: Adding Google Analytics to Your App
---
There is a basic Google Analytics integration built into Backstage. You can
enable it by adding the following to your app configuration:
There is a basic
[Google Analytics](https://marketingplatform.google.com/about/analytics/)
integration built into Backstage. You can enable it by adding the following to
your app configuration:
```yaml
app:
googleAnalyticsTrackingId: UA-000000-0
```
Replace the tracking ID with your own.
Replace the tracking ID with the one generated for you after signing up for the
Google Analytics service.
For more information, learn about Google Analytics
[here](https://marketingplatform.google.com/about/analytics/).
The default behavior is only to send a pageview hit to Google Analytics. To
record more, look at the developer documentation
[here](https://developers.google.com/analytics/devguides/collection/gtagjs).
The default behavior is only to send a pageview hit. To record more, review the
[Google Analytics developer documentation](https://developers.google.com/analytics/devguides/collection/gtagjs).
+34
View File
@@ -0,0 +1,34 @@
---
id: index
title: Integrations
sidebar_label: Overview
description:
Configuring Backstage to read or publish data with external providers using
integrations
---
Integrations allow Backstage to read or publish data using external providers
such as GitHub, GitLab, BitBucket, LDAP, or cloud providers.
## Configuration
Integrations are configured at the root level of `app-config.yaml` since
integrations are used by many Backstage core features and other plugins.
Each key under `integrations` is a separate configuration for a single external
provider. Providers each have different configuration; here's an example of
configuration to use both GitHub and BitBucket:
```yaml
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
bitbucket:
- host: bitbucket.org
username: ${BITBUCKET_USERNAME}
appPassword: ${BITBUCKET_APP_PASSWORD}
```
See documentation for each type of integration for full details on
configuration.
+13 -15
View File
@@ -6,8 +6,8 @@ sidebar_label: Org Data
description: Setting up ingestion of organizational data from LDAP
---
The Backstage catalog can be set up to ingest organizational data - groups and
users - directly from an LDAP compatible service. The result is a hierarchy of
The Backstage catalog can be set up to ingest organizational data - users and
groups - directly from an LDAP compatible service. The result is a hierarchy of
[`User`](../../features/software-catalog/descriptor-format.md#kind-user) and
[`Group`](../../features/software-catalog/descriptor-format.md#kind-group) kind
entities that mirror your org setup.
@@ -46,8 +46,7 @@ catalog:
- target: ldaps://ds.example.net
bind:
dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net
secret:
$env: LDAP_SECRET
secret: ${LDAP_SECRET}
users:
dn: ou=people,ou=example,dc=example,dc=net
options:
@@ -93,11 +92,10 @@ authenticate) towards the server. It has the following fields.
```yaml
dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net
secret:
$env: LDAP_SECRET
secret: ${LDAP_SECRET}
```
The `dn` is the full LDAP DN (distinguished name) for the user that the plugin
The `dn` is the full LDAP Distinguished Name for the user that the plugin
authenticates itself as. At this point, only regular user based authentication
is supported.
@@ -110,12 +108,12 @@ backend starts.
The `users` block defines the settings that govern the reading and
interpretation of users. Its fields are explained in separate sections below.
### users.dn
#### users.dn
The DN under which users are stored, e.g.
`ou=people,ou=example,dc=example,dc=net`.
### users.options
#### users.options
The search options to use when sending the query to the server, when reading all
users. All of the options are shown below, with their default values, but they
@@ -138,7 +136,7 @@ options:
paged: false
```
### users.set
#### users.set
This optional piece lets you specify a number of JSON paths (on a.b.c form) and
hard coded values to set on those paths. This can be useful for example if you
@@ -150,7 +148,7 @@ set:
metadata.namespace: 'ldap'
```
### users.map
#### users.map
Mappings from well known entity fields, to LDAP attribute names. This is where
you are able to define how to interpret the attributes of each LDAP result item,
@@ -192,12 +190,12 @@ map:
The `groups` block defines the settings that govern the reading and
interpretation of groups. Its fields are explained in separate sections below.
### groups.dn
#### groups.dn
The DN under which groups are stored, e.g.
`ou=people,ou=example,dc=example,dc=net`.
### groups.options
#### groups.options
The search options to use when sending the query to the server, when reading all
groups. All of the options are shown below, with their default values, but they
@@ -220,7 +218,7 @@ options:
paged: false
```
### groups.set
#### groups.set
This optional piece lets you specify a number of JSON paths (on a.b.c form) and
hard coded values to set on those paths. This can be useful for example if you
@@ -232,7 +230,7 @@ set:
metadata.namespace: 'ldap'
```
### groups.map
#### groups.map
Mappings from well known entity fields, to LDAP attribute names. This is where
you are able to define how to interpret the attributes of each LDAP result item,
+11 -9
View File
@@ -393,24 +393,26 @@ export const myPlugin = createPlugin({
routes: {
root: rootRouteRef,
details: detailsRouteRef,
}
})
},
});
export const MyPage = plugin.provide(createRoutableExtension({
component: () => import('./components/MyPage').then(m => m.MyPage),
mountPoint: rootRouteRef,
}))
export const MyPage = myPlugin.provide(
createRoutableExtension({
component: () => import('./components/MyPage').then(m => m.MyPage),
mountPoint: rootRouteRef,
}),
);
// components/MyPage.tsx
const MyPage = () => (
<Routes>
{/* myPlugin.routes.root will take the user to this page */}
<Route path='/' element={<IndexPage />}>
<Route path="/" element={<IndexPage />} />
{/* myPlugin.routes.details will take the user to this page */}
<Route path='/details' element={<DetailsPage />}>
<Route path="/details" element={<DetailsPage />} />
</Routes>
)
);
```
### New Catalog Components
+1 -1
View File
@@ -49,7 +49,7 @@ title: Adding Custom Plugin to Existing Monorepo App
Let's add a shortcut.
1. Open and modify `root: packages > app > src > sidebar.tsx` with the
1. Open and modify `root: packages > app > src > components > Root.tsx` with the
following:
```tsx
@@ -0,0 +1,61 @@
---
id: switching-sqlite-postgres
title: Switching Backstage from SQLite to PostgreSQL
description:
How to get ready for deploying Backstage to production with PostgreSQL
---
The default `@backstage/create-app` database is SQLite, an in-memory database
that's perfect for initial experimentation as it requires no environment setup.
Once you're ready to deploy Backstage in production, or to have a more
persistent development setup, you can switch the Backstage database to
PostgreSQL.
Backstage uses the [Knex](http://knexjs.org/) library, making it fairly easy to
switch between database backends.
## Install PostgreSQL
First, swap out SQLite for PostgreSQL in your `backend` package:
```shell
cd packages/backend
yarn remove sqlite3
yarn add pg
```
## Add PostgreSQL configuration
Next, modify `app-config.yaml` in the root folder to add PostgreSQL
configuration for the backend:
```diff
backend:
database:
- client: sqlite3
- connection: ':memory:'
+ # config options: https://node-postgres.com/api/client
+ client: pg
+ connection:
+ host:
+ $env: POSTGRES_HOST
+ port:
+ $env: POSTGRES_PORT
+ user:
+ $env: POSTGRES_USER
+ password:
+ $env: POSTGRES_PASSWORD
+ # https://node-postgres.com/features/ssl
+ #ssl: require # see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
+ #ca: # if you have a CA file and want to verify it you can uncomment this section
+ #$file: <file-path>/ca/server.crt
```
If you have a `app-config.local.yaml` for local development, a similar update
should be made there. You can set the `POSTGRES_` environment variables prior to
launching Backstage, or remove the $env keys and simply set values directly for
development.
The Backstage App is now ready to start up with a PostgreSQL backing database.
+9
View File
@@ -0,0 +1,9 @@
---
title: TODO
author: Spotify
authorUrl: https://github.com/spotify
category: Discovery
description: Browse TODO comments in your project's source code.
documentation: https://github.com/backstage/backstage/tree/master/plugins/todo
iconUrl: https://backstage.io/img/todo-logo.png
npmPackageName: '@backstage/plugin-todo'
+27 -5
View File
@@ -33,6 +33,7 @@
]
},
"getting-started/keeping-backstage-updated",
"getting-started/concepts",
"getting-started/contributors"
],
"CLI": ["cli/index", "cli/commands"],
@@ -104,20 +105,40 @@
}
],
"Integrations": [
"integrations/index",
{
"type": "subcategory",
"label": "GitHub",
"ids": ["integrations/github/org"]
"label": "Azure DevOps",
"ids": ["integrations/azure/locations"]
},
{
"type": "subcategory",
"label": "LDAP",
"ids": ["integrations/ldap/org"]
"label": "BitBucket",
"ids": ["integrations/bitbucket/locations"]
},
{
"type": "subcategory",
"label": "GitHub",
"ids": [
"integrations/github/locations",
"integrations/github/discovery",
"integrations/github/org"
]
},
{
"type": "subcategory",
"label": "GitLab",
"ids": ["integrations/gitlab/locations"]
},
{
"type": "subcategory",
"label": "Google Analytics",
"ids": ["integrations/google-analytics/installation"]
},
{
"type": "subcategory",
"label": "LDAP",
"ids": ["integrations/ldap/org"]
}
],
"Plugins": [
@@ -193,7 +214,8 @@
"Tutorials": [
"tutorials/journey",
"tutorials/quickstart-app-auth",
"tutorials/quickstart-app-plugin"
"tutorials/quickstart-app-plugin",
"tutorials/switching-sqlite-postgres"
],
"Architecture Decision Records (ADRs)": [
"architecture-decisions/adrs-overview",
+1 -1
View File
@@ -105,7 +105,7 @@ const siteConfig = {
// enableUpdateBy: true,
// Show documentation's last update time.
// enableUpdateTime: true,
enableUpdateTime: true,
// You may provide arbitrary config keys to be used as needed by your
// template. For example, if you need your repo's URL...
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

+44
View File
@@ -1,5 +1,49 @@
# example-app
## 0.2.20
### Patch Changes
- Updated dependencies [633a31fec]
- Updated dependencies [34e6bb409]
- Updated dependencies [b56815b40]
- Updated dependencies [09eb54e01]
- Updated dependencies [147b4c5b1]
- Updated dependencies [83bfc98a3]
- Updated dependencies [7d8c4c97c]
- Updated dependencies [e7baa0d2e]
- Updated dependencies [1df417bd3]
- Updated dependencies [84972540b]
- Updated dependencies [3385b374b]
- Updated dependencies [a0dacc184]
- Updated dependencies [8686eb38c]
- Updated dependencies [9ca0e4009]
- Updated dependencies [34ff49b0f]
- Updated dependencies [8686eb38c]
- Updated dependencies [c8b54c370]
- Updated dependencies [1f98a6ff8]
- Updated dependencies [e8b2ed9cc]
- @backstage/plugin-catalog@0.5.0
- @backstage/plugin-tech-radar@0.3.8
- @backstage/plugin-graphiql@0.2.9
- @backstage/plugin-user-settings@0.2.8
- @backstage/plugin-techdocs@0.6.2
- @backstage/plugin-catalog-import@0.5.0
- @backstage/plugin-kubernetes@0.4.1
- @backstage/cli@0.6.5
- @backstage/plugin-scaffolder@0.8.0
- @backstage/core@0.7.2
- @backstage/plugin-api-docs@0.4.9
- @backstage/plugin-catalog-react@0.1.2
- @backstage/plugin-circleci@0.2.12
- @backstage/plugin-cloudbuild@0.2.13
- @backstage/plugin-explore@0.3.2
- @backstage/plugin-github-actions@0.4.1
- @backstage/plugin-jenkins@0.4.0
- @backstage/plugin-lighthouse@0.2.14
- @backstage/plugin-org@0.3.10
- @backstage/plugin-search@0.3.4
## 0.2.19
### Patch Changes
+26 -23
View File
@@ -1,45 +1,48 @@
{
"name": "example-app",
"version": "0.2.19",
"version": "0.2.20",
"private": true,
"bundled": true,
"dependencies": {
"@backstage/catalog-model": "^0.7.4",
"@backstage/cli": "^0.6.4",
"@backstage/core": "^0.7.1",
"@backstage/plugin-api-docs": "^0.4.8",
"@backstage/plugin-catalog": "^0.4.2",
"@backstage/plugin-catalog-import": "^0.4.3",
"@backstage/plugin-catalog-react": "^0.1.1",
"@backstage/plugin-circleci": "^0.2.11",
"@backstage/plugin-cloudbuild": "^0.2.12",
"@backstage/cli": "^0.6.5",
"@backstage/core": "^0.7.2",
"@backstage/integration-react": "^0.1.1",
"@backstage/plugin-api-docs": "^0.4.9",
"@backstage/plugin-badges": "^0.1.1",
"@backstage/plugin-catalog": "^0.5.0",
"@backstage/plugin-catalog-import": "^0.5.0",
"@backstage/plugin-catalog-react": "^0.1.2",
"@backstage/plugin-circleci": "^0.2.12",
"@backstage/plugin-cloudbuild": "^0.2.13",
"@backstage/plugin-cost-insights": "^0.8.3",
"@backstage/plugin-explore": "^0.3.1",
"@backstage/plugin-explore": "^0.3.2",
"@backstage/plugin-gcp-projects": "^0.2.5",
"@backstage/plugin-github-actions": "^0.4.0",
"@backstage/plugin-github-actions": "^0.4.1",
"@backstage/plugin-gitops-profiles": "^0.2.6",
"@backstage/plugin-graphiql": "^0.2.8",
"@backstage/plugin-jenkins": "^0.3.12",
"@backstage/plugin-graphiql": "^0.2.9",
"@backstage/plugin-jenkins": "^0.4.0",
"@backstage/plugin-kafka": "^0.2.6",
"@backstage/plugin-kubernetes": "^0.4.0",
"@backstage/plugin-lighthouse": "^0.2.13",
"@backstage/plugin-kubernetes": "^0.4.1",
"@backstage/plugin-lighthouse": "^0.2.14",
"@backstage/plugin-newrelic": "^0.2.6",
"@backstage/plugin-org": "^0.3.9",
"@backstage/plugin-org": "^0.3.10",
"@backstage/plugin-pagerduty": "0.3.2",
"@backstage/plugin-register-component": "^0.2.12",
"@backstage/plugin-rollbar": "^0.3.3",
"@backstage/plugin-scaffolder": "^0.7.1",
"@backstage/plugin-scaffolder": "^0.8.0",
"@backstage/plugin-search": "^0.3.4",
"@backstage/plugin-sentry": "^0.3.8",
"@backstage/plugin-search": "^0.3.3",
"@backstage/plugin-tech-radar": "^0.3.7",
"@backstage/plugin-techdocs": "^0.6.1",
"@backstage/plugin-user-settings": "^0.2.7",
"@backstage/plugin-tech-radar": "^0.3.8",
"@backstage/plugin-techdocs": "^0.6.2",
"@backstage/plugin-todo": "^0.1.0",
"@backstage/plugin-user-settings": "^0.2.8",
"@backstage/theme": "^0.2.4",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@octokit/rest": "^18.0.12",
"@roadiehq/backstage-plugin-buildkite": "^0.1.3",
"@roadiehq/backstage-plugin-github-insights": "^0.2.16",
"@roadiehq/backstage-plugin-github-insights": "^0.3.2",
"@roadiehq/backstage-plugin-github-pull-requests": "^0.7.6",
"@roadiehq/backstage-plugin-travis-ci": "^0.4.5",
"history": "^5.0.0",
@@ -53,7 +56,7 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/test-utils": "^0.1.8",
"@backstage/test-utils": "^0.1.9",
"@testing-library/cypress": "^7.0.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
+6 -2
View File
@@ -39,7 +39,7 @@ import { GraphiQLPage } from '@backstage/plugin-graphiql';
import { LighthousePage } from '@backstage/plugin-lighthouse';
import { NewRelicPage } from '@backstage/plugin-newrelic';
import { ScaffolderPage, scaffolderPlugin } from '@backstage/plugin-scaffolder';
import { SearchPage } from '@backstage/plugin-search';
import { SearchPage, SearchPageNext } from '@backstage/plugin-search';
import { TechRadarPage } from '@backstage/plugin-tech-radar';
import { TechdocsPage } from '@backstage/plugin-techdocs';
import { UserSettingsPage } from '@backstage/plugin-user-settings';
@@ -49,7 +49,7 @@ import { hot } from 'react-hot-loader/root';
import { Navigate, Route } from 'react-router';
import { apis } from './apis';
import { EntityPage } from './components/catalog/EntityPage';
import Root from './components/Root';
import { Root } from './components/Root';
import { providers } from './identityProviders';
import * as plugins from './plugins';
@@ -112,6 +112,10 @@ const routes = (
<Route path="/gcp-projects" element={<GcpProjectsPage />} />
<Route path="/newrelic" element={<NewRelicPage />} />
<Route path="/search" element={<SearchPage />} />
<Route
path="/search-next"
element={<SearchPageNext /* TODO: illustrate customization */ />}
/>
<Route path="/cost-insights" element={<CostInsightsPage />} />
<Route
path="/cost-insights/investigating-growth"
+17 -7
View File
@@ -15,22 +15,32 @@
*/
import {
AnyApiFactory,
configApiRef,
createApiFactory,
errorApiRef,
githubAuthApiRef,
createApiFactory,
} from '@backstage/core';
import {
ScmIntegrationsApi,
scmIntegrationsApiRef,
} from '@backstage/integration-react';
import {
costInsightsApiRef,
ExampleCostInsightsClient,
} from '@backstage/plugin-cost-insights';
import {
graphQlBrowseApiRef,
GraphQLEndpoints,
} from '@backstage/plugin-graphiql';
import {
costInsightsApiRef,
ExampleCostInsightsClient,
} from '@backstage/plugin-cost-insights';
export const apis: AnyApiFactory[] = [
createApiFactory({
api: scmIntegrationsApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),
}),
export const apis = [
createApiFactory({
api: graphQlBrowseApiRef,
deps: { errorApi: errorApiRef, githubAuthApi: githubAuthApiRef },
+1 -3
View File
@@ -73,7 +73,7 @@ const SidebarLogo = () => {
);
};
const Root = ({ children }: PropsWithChildren<{}>) => (
export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
<SidebarLogo />
@@ -98,5 +98,3 @@ const Root = ({ children }: PropsWithChildren<{}>) => (
{children}
</SidebarPage>
);
export default Root;
+1 -1
View File
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { default } from './Root';
export { Root } from './Root';
@@ -31,6 +31,7 @@ import {
ProvidedApisCard,
ProvidingComponentsCard,
} from '@backstage/plugin-api-docs';
import { EntityBadgesDialog } from '@backstage/plugin-badges';
import {
AboutCard,
EntityHasComponentsCard,
@@ -82,6 +83,7 @@ import {
} from '@backstage/plugin-rollbar';
import { Router as SentryRouter } from '@backstage/plugin-sentry';
import { EmbeddedDocsRouter as DocsRouter } from '@backstage/plugin-techdocs';
import { EntityTodoContent } from '@backstage/plugin-todo';
import { Button, Grid } from '@material-ui/core';
import {
isPluginApplicableToEntity as isBuildkiteAvailable,
@@ -104,7 +106,8 @@ import {
RecentTravisCIBuildsWidget,
Router as TravisCIRouter,
} from '@roadiehq/backstage-plugin-travis-ci';
import React, { ReactNode } from 'react';
import React, { ReactNode, useMemo, useState } from 'react';
import BadgeIcon from '@material-ui/icons/CallToAction';
export const CICDSwitcher = ({ entity }: { entity: Entity }) => {
// This component is just an example of how you can implement your company's logic in entity page.
@@ -178,6 +181,32 @@ export const ErrorsSwitcher = ({ entity }: { entity: Entity }) => {
}
};
const EntityPageLayoutWrapper = (props: { children?: React.ReactNode }) => {
const [badgesDialogOpen, setBadgesDialogOpen] = useState(false);
const extraMenuItems = useMemo(() => {
return [
{
title: 'Badges',
Icon: BadgeIcon,
onClick: () => setBadgesDialogOpen(true),
},
];
}, []);
return (
<>
<EntityPageLayout UNSTABLE_extraContextMenuItems={extraMenuItems}>
{props.children}
</EntityPageLayout>
<EntityBadgesDialog
open={badgesDialogOpen}
onClose={() => setBadgesDialogOpen(false)}
/>
</>
);
};
const ComponentOverviewContent = ({ entity }: { entity: Entity }) => (
<Grid container spacing={3} alignItems="stretch">
<Grid item md={6}>
@@ -233,7 +262,7 @@ const ComponentApisContent = ({ entity }: { entity: Entity }) => (
);
const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
<EntityPageLayout>
<EntityPageLayoutWrapper>
<EntityPageLayout.Content
path="/"
title="Overview"
@@ -279,11 +308,16 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
title="Kafka"
element={<KafkaRouter entity={entity} />}
/>
</EntityPageLayout>
<EntityPageLayout.Content
path="/todos"
title="TODOs"
element={<EntityTodoContent />}
/>
</EntityPageLayoutWrapper>
);
const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
<EntityPageLayout>
<EntityPageLayoutWrapper>
<EntityPageLayout.Content
path="/"
title="Overview"
@@ -324,11 +358,16 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
title="Code Insights"
element={<GitHubInsightsRouter entity={entity} />}
/>
</EntityPageLayout>
<EntityPageLayout.Content
path="/todos"
title="TODOs"
element={<EntityTodoContent />}
/>
</EntityPageLayoutWrapper>
);
const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
<EntityPageLayout>
<EntityPageLayoutWrapper>
<EntityPageLayout.Content
path="/*"
title="Overview"
@@ -339,7 +378,12 @@ const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
title="Docs"
element={<DocsRouter entity={entity} />}
/>
</EntityPageLayout>
<EntityPageLayout.Content
path="/todos"
title="TODOs"
element={<EntityTodoContent />}
/>
</EntityPageLayoutWrapper>
);
export const ComponentEntityPage = ({ entity }: { entity: Entity }) => {
@@ -378,7 +422,7 @@ const ApiDefinitionContent = ({ entity }: { entity: ApiEntity }) => (
);
const ApiEntityPage = ({ entity }: { entity: Entity }) => (
<EntityPageLayout>
<EntityPageLayoutWrapper>
<EntityPageLayout.Content
path="/*"
title="Overview"
@@ -389,7 +433,7 @@ const ApiEntityPage = ({ entity }: { entity: Entity }) => (
title="Definition"
element={<ApiDefinitionContent entity={entity as ApiEntity} />}
/>
</EntityPageLayout>
</EntityPageLayoutWrapper>
);
const UserOverviewContent = ({ entity }: { entity: UserEntity }) => (
@@ -404,13 +448,13 @@ const UserOverviewContent = ({ entity }: { entity: UserEntity }) => (
);
const UserEntityPage = ({ entity }: { entity: Entity }) => (
<EntityPageLayout>
<EntityPageLayoutWrapper>
<EntityPageLayout.Content
path="/*"
title="Overview"
element={<UserOverviewContent entity={entity as UserEntity} />}
/>
</EntityPageLayout>
</EntityPageLayoutWrapper>
);
const GroupOverviewContent = ({ entity }: { entity: GroupEntity }) => (
@@ -428,13 +472,13 @@ const GroupOverviewContent = ({ entity }: { entity: GroupEntity }) => (
);
const GroupEntityPage = ({ entity }: { entity: Entity }) => (
<EntityPageLayout>
<EntityPageLayoutWrapper>
<EntityPageLayout.Content
path="/*"
title="Overview"
element={<GroupOverviewContent entity={entity as GroupEntity} />}
/>
</EntityPageLayout>
</EntityPageLayoutWrapper>
);
const SystemOverviewContent = ({ entity }: { entity: SystemEntity }) => (
@@ -452,7 +496,7 @@ const SystemOverviewContent = ({ entity }: { entity: SystemEntity }) => (
);
const SystemEntityPage = ({ entity }: { entity: Entity }) => (
<EntityPageLayout>
<EntityPageLayoutWrapper>
<EntityPageLayout.Content
path="/*"
title="Overview"
@@ -463,7 +507,7 @@ const SystemEntityPage = ({ entity }: { entity: Entity }) => (
title="Diagram"
element={<EntitySystemDiagramCard />}
/>
</EntityPageLayout>
</EntityPageLayoutWrapper>
);
const DomainOverviewContent = ({ entity }: { entity: DomainEntity }) => (
@@ -478,19 +522,19 @@ const DomainOverviewContent = ({ entity }: { entity: DomainEntity }) => (
);
const DomainEntityPage = ({ entity }: { entity: Entity }) => (
<EntityPageLayout>
<EntityPageLayoutWrapper>
<EntityPageLayout.Content
path="/*"
title="Overview"
element={<DomainOverviewContent entity={entity as DomainEntity} />}
/>
</EntityPageLayout>
</EntityPageLayoutWrapper>
);
export const EntityPage = () => {
const { entity } = useEntity();
switch (entity?.kind?.toLowerCase()) {
switch (entity?.kind?.toLocaleLowerCase('en-US')) {
case 'component':
return <ComponentEntityPage entity={entity} />;
case 'api':
@@ -503,6 +547,9 @@ export const EntityPage = () => {
return <SystemEntityPage entity={entity} />;
case 'domain':
return <DomainEntityPage entity={entity} />;
case 'location':
case 'resource':
case 'template':
default:
return <DefaultEntityPage entity={entity} />;
}
+2
View File
@@ -43,3 +43,5 @@ export { plugin as Buildkite } from '@roadiehq/backstage-plugin-buildkite';
export { plugin as Search } from '@backstage/plugin-search';
export { plugin as Org } from '@backstage/plugin-org';
export { plugin as Kafka } from '@backstage/plugin-kafka';
export { todoPlugin } from '@backstage/plugin-todo';
export { badgesPlugin } from '@backstage/plugin-badges';
+44
View File
@@ -1,5 +1,49 @@
# @backstage/backend-common
## 0.6.0
### Minor Changes
- 8686eb38c: Encode thrown errors in the backend as a JSON payload. This is technically a breaking change, since the response format even of errors are part of the contract. If you relied on the response being text, you will now have some extra JSON "noise" in it. It should still be readable by end users though.
Before:
```
NotFoundError: No entity named 'tara.macgovern2' found, with kind 'user' in namespace 'default'
at eval (webpack-internal:///../../plugins/catalog-backend/src/service/router.ts:117:17)
```
After:
```json
{
"error": {
"name": "NotFoundError",
"message": "No entity named 'tara.macgovern2' found, with kind 'user' in namespace 'default'",
"stack": "NotFoundError: No entity named 'tara.macgovern2' found, with kind 'user' in namespace 'default'\n at eval (webpack-internal:///../../plugins/catalog-backend/src/service/router.ts:117:17)"
},
"request": {
"method": "GET",
"url": "/entities/by-name/user/default/tara.macgovern2"
},
"response": {
"statusCode": 404
}
}
```
- 8686eb38c: Removed the custom error types (e.g. `NotFoundError`). Those are now instead in the new `@backstage/errors` package. This is a breaking change, and you will have to update your imports if you were using these types.
```diff
-import { NotFoundError } from '@backstage/backend-common';
+import { NotFoundError } from '@backstage/errors';
```
### Patch Changes
- Updated dependencies [0434853a5]
- @backstage/config@0.1.4
## 0.5.6
### Patch Changes
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.5.6",
"version": "0.6.0",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -30,7 +30,7 @@
},
"dependencies": {
"@backstage/cli-common": "^0.1.1",
"@backstage/config": "^0.1.2",
"@backstage/config": "^0.1.4",
"@backstage/config-loader": "^0.5.1",
"@backstage/errors": "^0.1.1",
"@backstage/integration": "^0.5.1",
@@ -45,7 +45,7 @@
"cross-fetch": "^3.0.6",
"dockerode": "^3.2.1",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"express-promise-router": "^4.1.0",
"fs-extra": "^9.0.1",
"git-url-parse": "^11.4.4",
"helmet": "^4.0.0",
@@ -71,8 +71,8 @@
}
},
"devDependencies": {
"@backstage/cli": "^0.6.4",
"@backstage/test-utils": "^0.1.7",
"@backstage/cli": "^0.6.5",
"@backstage/test-utils": "^0.1.9",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
"@types/concat-stream": "^1.6.0",
+33
View File
@@ -1,5 +1,38 @@
# example-backend
## 0.2.20
### Patch Changes
- Updated dependencies [010aed784]
- Updated dependencies [8686eb38c]
- Updated dependencies [e7baa0d2e]
- Updated dependencies [8b4f7e42a]
- Updated dependencies [8686eb38c]
- Updated dependencies [0434853a5]
- Updated dependencies [4bc98a5b9]
- Updated dependencies [d2f4efc5d]
- Updated dependencies [8686eb38c]
- Updated dependencies [424742dc1]
- Updated dependencies [1f98a6ff8]
- Updated dependencies [8b5e59750]
- Updated dependencies [8686eb38c]
- @backstage/plugin-catalog-backend@0.6.6
- @backstage/catalog-client@0.3.8
- @backstage/plugin-techdocs-backend@0.6.5
- @backstage/plugin-scaffolder-backend@0.9.2
- @backstage/backend-common@0.6.0
- @backstage/config@0.1.4
- @backstage/plugin-auth-backend@0.3.5
- @backstage/plugin-kubernetes-backend@0.3.1
- example-app@0.2.20
- @backstage/plugin-app-backend@0.3.10
- @backstage/plugin-graphql-backend@0.1.6
- @backstage/plugin-kafka-backend@0.2.2
- @backstage/plugin-proxy-backend@0.2.6
- @backstage/plugin-rollbar-backend@0.1.8
- @backstage/plugin-todo-backend@0.1.1
## 0.2.19
### Patch Changes
+21 -17
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend",
"version": "0.2.19",
"version": "0.2.20",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -27,27 +27,31 @@
"migrate:create": "knex migrate:make -x ts"
},
"dependencies": {
"@backstage/backend-common": "^0.5.6",
"@backstage/catalog-client": "^0.3.7",
"@backstage/backend-common": "^0.6.0",
"@backstage/catalog-client": "^0.3.8",
"@backstage/catalog-model": "^0.7.4",
"@backstage/config": "^0.1.3",
"@backstage/plugin-app-backend": "^0.3.9",
"@backstage/plugin-auth-backend": "^0.3.4",
"@backstage/plugin-catalog-backend": "^0.6.5",
"@backstage/plugin-graphql-backend": "^0.1.5",
"@backstage/plugin-kubernetes-backend": "^0.3.0",
"@backstage/plugin-kafka-backend": "^0.2.1",
"@backstage/plugin-proxy-backend": "^0.2.5",
"@backstage/plugin-rollbar-backend": "^0.1.7",
"@backstage/plugin-scaffolder-backend": "^0.9.1",
"@backstage/plugin-techdocs-backend": "^0.6.4",
"@backstage/config": "^0.1.4",
"@backstage/plugin-app-backend": "^0.3.10",
"@backstage/plugin-auth-backend": "^0.3.5",
"@backstage/plugin-badges-backend": "^0.1.1",
"@backstage/plugin-catalog-backend": "^0.6.6",
"@backstage/plugin-graphql-backend": "^0.1.6",
"@backstage/plugin-kubernetes-backend": "^0.3.1",
"@backstage/plugin-kafka-backend": "^0.2.2",
"@backstage/plugin-proxy-backend": "^0.2.6",
"@backstage/plugin-rollbar-backend": "^0.1.8",
"@backstage/plugin-scaffolder-backend": "^0.9.2",
"@backstage/plugin-search-backend": "^0.1.1",
"@backstage/plugin-search-backend-node": "^0.1.1",
"@backstage/plugin-techdocs-backend": "^0.6.5",
"@backstage/plugin-todo-backend": "^0.1.1",
"@gitbeaker/node": "^28.0.2",
"@octokit/rest": "^18.0.12",
"azure-devops-node-api": "^10.1.1",
"dockerode": "^3.2.1",
"example-app": "^0.2.19",
"example-app": "^0.2.20",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"express-promise-router": "^4.1.0",
"knex": "^0.95.1",
"pg": "^8.3.0",
"pg-connection-string": "^2.3.0",
@@ -55,7 +59,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.6.4",
"@backstage/cli": "^0.6.5",
"@types/dockerode": "^3.2.1",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5"
+9
View File
@@ -42,9 +42,12 @@ import kafka from './plugins/kafka';
import rollbar from './plugins/rollbar';
import scaffolder from './plugins/scaffolder';
import proxy from './plugins/proxy';
import search from './plugins/search';
import techdocs from './plugins/techdocs';
import todo from './plugins/todo';
import graphql from './plugins/graphql';
import app from './plugins/app';
import badges from './plugins/badges';
import { PluginEnvironment } from './types';
function makeCreateEnv(config: Config) {
@@ -76,22 +79,28 @@ async function main() {
const authEnv = useHotMemoize(module, () => createEnv('auth'));
const proxyEnv = useHotMemoize(module, () => createEnv('proxy'));
const rollbarEnv = useHotMemoize(module, () => createEnv('rollbar'));
const searchEnv = useHotMemoize(module, () => createEnv('search'));
const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs'));
const todoEnv = useHotMemoize(module, () => createEnv('todo'));
const kubernetesEnv = useHotMemoize(module, () => createEnv('kubernetes'));
const kafkaEnv = useHotMemoize(module, () => createEnv('kafka'));
const graphqlEnv = useHotMemoize(module, () => createEnv('graphql'));
const appEnv = useHotMemoize(module, () => createEnv('app'));
const badgesEnv = useHotMemoize(module, () => createEnv('badges'));
const apiRouter = Router();
apiRouter.use('/catalog', await catalog(catalogEnv));
apiRouter.use('/rollbar', await rollbar(rollbarEnv));
apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv));
apiRouter.use('/auth', await auth(authEnv));
apiRouter.use('/search', await search(searchEnv));
apiRouter.use('/techdocs', await techdocs(techdocsEnv));
apiRouter.use('/todo', await todo(todoEnv));
apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv));
apiRouter.use('/kafka', await kafka(kafkaEnv));
apiRouter.use('/proxy', await proxy(proxyEnv));
apiRouter.use('/graphql', await graphql(graphqlEnv));
apiRouter.use('/badges', await badges(badgesEnv));
apiRouter.use(notFoundHandler());
const service = createServiceBuilder(module)
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
createRouter,
createDefaultBadgeFactories,
} from '@backstage/plugin-badges-backend';
import { PluginEnvironment } from '../types';
export default async function createPlugin({
config,
discovery,
}: PluginEnvironment) {
return await createRouter({
config,
discovery,
badgeFactories: createDefaultBadgeFactories(),
});
}

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