Merge branch 'master' into statuses-for-github-deployments-plugin

This commit is contained in:
Sam Robson
2021-06-08 10:11:16 +01:00
committed by GitHub
1152 changed files with 51839 additions and 6920 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': patch
---
A `<CatalogResultListItem />` component is now available for use in custom Search Experiences.
-13
View File
@@ -1,13 +0,0 @@
---
'@backstage/core-api': patch
---
Updated the `Observable` type to provide interoperability with `Symbol.observable`, making it compatible with at least `zen-observable` and `RxJS 7`.
In cases where this change breaks tests that mocked the `Observable` type, the following addition to the mock should fix the breakage:
```ts
[Symbol.observable]() {
return this;
},
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cost-insights': patch
---
Move `canvas` package to `devDependencies`.
+41
View File
@@ -0,0 +1,41 @@
---
'@backstage/create-app': patch
---
Updated the `@gitbeaker/node` dependency past the broken one without a `dist` folder.
See [this issue](https://github.com/jdalrymple/gitbeaker/issues/1861) for more details.
If you get build errors that look like the following in your Backstage instance, you may want to also bump all of your `@gitbeaker/*` dependencies to at least `^30.2.0`.
```
node:internal/modules/cjs/loader:356
throw err;
^
Error: Cannot find module '/path/to/project/node_modules/@gitbeaker/node/dist/index.js'. Please verify that the package.json has a valid "main" entry
at tryPackage (node:internal/modules/cjs/loader:348:19)
at Function.Module._findPath (node:internal/modules/cjs/loader:561:18)
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:926:27)
at Function.Module._load (node:internal/modules/cjs/loader:773:27)
at Module.require (node:internal/modules/cjs/loader:1012:19)
at require (node:internal/modules/cjs/helpers:93:18)
at Object.<anonymous> (/path/to/project/test.js:4:18)
at Module._compile (node:internal/modules/cjs/loader:1108:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
at Module.load (node:internal/modules/cjs/loader:988:32) {
code: 'MODULE_NOT_FOUND',
path: '/path/to/project/node_modules/@gitbeaker/node/package.json',
requestPath: '@gitbeaker/node'
}
```
you could also consider pinning the version to an older one in your `package.json`, before the breakage occurred.
```json
"resolutions": {
"@gitbeaker/node": "29.2.4",
"@gitbeaker/core": "29.2.4",
"@gitbeaker/requester-utils": "29.2.4"
}
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Restructure the next catalog types and files a bit
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-github-actions': patch
---
Add missing token on job list call to GitHub API
+23
View File
@@ -0,0 +1,23 @@
---
'@backstage/backend-common': patch
---
Omits the `upgrade-insecure-requests` Content-Security-Policy directive by default, to prevent automatic HTTPS request upgrading for HTTP-deployed Backstage sites.
If you previously disabled this using `false` in your `app-config.yaml`, this line is no longer necessary:
```diff
backend:
csp:
- upgrade-insecure-requests: false
```
To keep the existing behavior of `upgrade-insecure-requests` Content-Security-Policy being _enabled_, add the key with an empty array as the value in your `app-config.yaml`:
```diff
backend:
+ csp:
+ upgrade-insecure-requests: []
```
Read more on [upgrade-insecure-requests here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests).
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-badges-backend': patch
---
Fix generated badge links
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/catalog-model': patch
---
Add the `status` field to the Entity envelope
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Updated dependencies
+17
View File
@@ -0,0 +1,17 @@
---
'@backstage/create-app': patch
'@backstage/plugin-scaffolder-backend': patch
---
Migrating old `backstage.io/v1alpha1` templates to `backstage.io/v1beta2`
Deprecating the `create-react-app` Template. We're planning on removing the `create-react-app` templater, as it's been a little tricky to support and takes 15mins to run in a container. We've currently cached a copy of the output for `create-react-app` and ship that under our sample templates folder. If you want to continue using it, we suggest copying the template out of there and putting it in your own repository as it will be removed in upcoming releases.
We also recommend removing this entry from your `app-config.yaml` if it exists:
```diff
- - type: url
- target: https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml
- rules:
- - allow: [Template]
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/config-loader': patch
---
Updated dependencies
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/catalog-client': patch
'@backstage/plugin-catalog-import': patch
---
Display preview result final step.
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/search-common': patch
'@backstage/plugin-search-backend-node': patch
'@backstage/plugin-search': patch
---
The `<Search...Next /> set of components exported by the Search Plugin are now updated to use the Search Backend API. These will be made available as the default non-"next" versions in a follow-up release.
The interfaces for decorators and collators in the Search Backend have also seen minor, breaking revisions ahead of a general release. If you happen to be building on top of these interfaces, check and update your implementations accordingly. The APIs will be considered more stable in a follow-up release.
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/plugin-git-release-manager': patch
'@backstage/plugin-ilert': patch
---
[ImgBot] Optimize images
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend': patch
---
Skip adding entries to the `entities_search` table if their `key` exceeds a length limit.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/dev-utils': patch
---
Fix a bug where an instance of the SCM integrations API wasn't being provided properly to the dev app.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-techdocs': patch
---
Bug fix on sidebar position when Tab-Bar is enabled
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/test-utils': patch
---
Updated `MockErrorApi` to work with new `Observable` type in `@backstage/core`.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-github-deployments': patch
---
Support GHE by properly parsing enterprise instance hosts
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-techdocs': patch
---
Handle URLs with a `#hash` correctly when rewriting link URLs.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Update gitbeaker past the broken version without a dist folder
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': patch
---
Exported AboutCard contents and utility functions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-proxy-backend': patch
---
Fixed proxy requests to the base URL of routes without a trailing slash redirecting to the `target` with the full path appended.
+29 -1
View File
@@ -1,4 +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.
*/
var path = require('path');
module.exports = {
root: true,
extends: ['@spotify/eslint-config-oss'],
plugins: ['notice'],
rules: {
'notice/notice': [
'error',
{
// eslint-disable-next-line no-restricted-syntax
templateFile: path.resolve(__dirname, './scripts/copyright-header.txt'),
onNonMatchingHeader: 'replace',
},
],
},
};
+1
View File
@@ -9,6 +9,7 @@ exemptLabels:
- plugin
- help wanted
- good first issue
- rfc
# 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
+98 -87
View File
@@ -1,126 +1,58 @@
Apdex
Api
Autoscaling
Avro
Bigtable
Billett
Bitrise
Blackbox
Chai
Changesets
Chanwit
Cloudformation
Cobertura
Codecov
Codehilite
Config
Datadog
Debounce
Discoverability
Dockerfile
dockerfiles
Dockerize
Docusaurus
Env
Expedia
Fargate
Figma
Firekube
Fiverr
GitHub
GitLab
Grafana
GraphQL
Hackathons
Heroku
Hostname
Iain
JaCoCo
JavaScript
Kaewkasi
Knex
Leasot
Lerna
LocalStack
Luxon
Minikube
Minio
Mkdocs
Monorepo
Namespaces
OAuth
Okta
Onboarding
Platformize
Podman
Preprarer
Protobuf
Proxying
Readme
readonly
rebase
Recharts
Redash
Repo
Rollbar
Rollup
Routable
Scaffolder
Serverless
Sinon
Snyk
Splunk
Spotifiers
Spotify
Superfences
Talkdesk
Telenor
Templater
Templaters
todo
Tolerations
WWW
Weaveworks
Webpack
XML
Zalando
Zhou
abc
accessors
Apdex
api
Api
apis
args
asciidoc
async
automations
autoscaling
Autoscaling
Avro
backrub
Bigtable
Billett
Bitrise
Blackbox
bool
boolean
builtins
Chai
changeset
changesets
Changesets
chanwit
Chanwit
ci
cisphobia
cissexist
classname
cli
cloudbuild
Cloudformation
cncf
Cobertura
codeblocks
Codecov
codehilite
Codehilite
codeowners
composability
composable
config
Config
configmaps
configs
const
cookiecutter
css
Datadog
dataflow
deadnaming
debounce
Debounce
declaratively
deps
destructured
@@ -128,60 +60,99 @@ dev
devops
devs
discoverability
Discoverability
dls
docgen
Dockerfile
dockerfiles
Dockerize
dockerode
Docusaurus
env
Env
esbuild
eslint
etag
Expedia
facto
failover
Fargate
Figma
Firekube
Fiverr
gitbeaker
GitHub
GitLab
Grafana
graphql
GraphQL
graphviz
Hackathons
haproxy
Helidon
Heroku
hoc
horizontalpodautoscalers
Hostname
hotspots
html
http
https
Iain
img
incentivised
inlined
inlinehilite
interop
JaCoCo
JavaScript
Jira
jq
js
json
jsonnet
jsx
Kaewkasi
Keyv
Knex
kubectl
kubernetes
kubernetes
learnings
Leasot
lerna
Lerna
LocalStack
lockfile
lunr
Luxon
magiclink
mailto
maintainership
makefile
md
memcache
microservice
microservices
microsite
middleware
minikube
Minikube
Minio
misconfiguration
misconfigured
misgendering
mkdocs
Mkdocs
monorepo
Monorepo
monorepos
msw
mysql
namespace
namespaced
namespaces
Namespaces
namespacing
neuro
newrelic
@@ -193,43 +164,68 @@ noop
npm
nvarchar
nvm
OAuth
octokit
oidc
Okta
onboarding
Onboarding
pagerduty
pageview
parallelization
plantuml
Platformize
Podman
postgres
postpack
pre
prebaked
preconfigured
prepack
Preprarer
productional
Protobuf
proxying
Proxying
pygments
pymdownx
rankdir
readme
Readme
readonly
rebase
Recharts
Redash
replicasets
repo
Repo
repos
rerender
rollbar
Rollbar
Rollup
routable
Routable
rst
rsync
ruleset
sam
sanitization
scaffolded
scaffolder
Scaffolder
seb
semlas
semver
Serverless
Sinon
Snyk
sourcemaps
sparklines
Splunk
Spotifiers
spotify
Spotify
sqlite
squidfunk
src
@@ -240,17 +236,25 @@ subkey
subroutes
subtree
superfences
Superfences
superset
supertype
talkdesk
Talkdesk
tasklist
techdocs
Telenor
templated
templater
Templater
templaters
Templaters
theia
thumbsup
toc
todo
tolerations
Tolerations
toolchain
toolsets
tooltip
@@ -266,11 +270,18 @@ untracked
upvote
url
utils
validator
validators
varchar
Weaveworks
Webpack
winston
www
WWW
XML
xyz
yaml
Zalando
Zhou
zoomable
zsh
+1
View File
@@ -20,3 +20,4 @@ jobs:
version: yarn release
env:
GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
HUSKY: '0'
+3
View File
@@ -76,6 +76,9 @@ jobs:
- name: prettier
run: yarn prettier:check
- name: lock
run: yarn lock:check
- name: validate config
run: yarn backstage-cli config:check --lax
+2
View File
@@ -55,6 +55,8 @@ jobs:
- name: test
run: yarn lerna -- run test
env:
BACKSTAGE_TEST_DISABLE_DOCKER: 1
# credit: https://github.com/appleboy/discord-action/issues/3#issuecomment-731426861
- name: Discord notification
+39
View File
@@ -16,6 +16,41 @@ jobs:
matrix:
node-version: [12.x, 14.x]
services:
postgres13:
image: postgres:13
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432/tcp
postgres9:
image: postgres:9
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432/tcp
mysql8:
image: mysql:8
env:
MYSQL_ROOT_PASSWORD: root
options: >-
--health-cmd "mysqladmin ping -h localhost"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 3306/tcp
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096
@@ -86,6 +121,10 @@ jobs:
# Upload code coverage for some specific flags. Also see .codecov.yml
bash <(curl -s https://codecov.io/bash) -f packages/core/coverage/* -F core
bash <(curl -s https://codecov.io/bash) -f packages/core-api/coverage/* -F core-api
env:
BACKSTAGE_TEST_DATABASE_POSTGRES13_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres13.ports[5432] }}
BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres9.ports[5432] }}
BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING: mysql://root:root@localhost:${{ job.services.mysql8.ports[3306] }}/ignored
- name: Discord notification
if: ${{ failure() }}
@@ -40,6 +40,10 @@ jobs:
run: yarn prettier:check
working-directory: microsite
- name: lock
run: yarn lock:check
working-directory: microsite
- name: build microsite
run: yarn build
working-directory: microsite
+32 -28
View File
@@ -1,28 +1,32 @@
| 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. |
| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a teams engineering dependencies. |
| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. |
| 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. |
| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a teams engineering dependencies. |
| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. |
| [Booz Allen Hamilton](https://www.boozallen.com/) | [Jason Miller](https://github.com/JasonMiller-BAH) | Developer portal for a full-stack software development ecosystem that accelerates consistent and repeatable Modern Software Development practices for internal innovation and investments. |
| [Netflix](https://www.netflix.com/) | [bleathem](https://github.com/bleathem) | Our Backstage implementation will be the front door to a unified experience connecting our internal platform products across important workflows with integrated knowledge and support. |
| [b.well](https://www.icanbwell.com/) | [Jacob Rosales](https://github.com/jrosales) | Foundation for our engineering portal and cloud insights. |
| [PagerDuty](https://www.pagerduty.com/) | [Mark Shaw](https://github.com/markshawtoronto) | Developer portal, initially focused on software templates and tech-docs. |
-163
View File
@@ -1,163 +0,0 @@
# Backstage Changelog
This changelog is no longer being updated and will be removed in the future, as each package now has its own changelog instead. It was a best-effort changelog where we manually collected breaking changes during the `v0.1.1-alpha.<n>` releases.
If you encounter issues while upgrading to a newer version, don't hesitate to reach out on [Discord](https://discord.gg/EBHEGzX) or [open an issue](https://github.com/backstage/backstage/issues/new/choose)!
## v0.1.1-alpha.26
### @backstage/cli
- Configuration files are no longer selected through `APP_ENV` or `NODE_ENV`. The default configuration files are `app-config.yaml` and, fix it exists, `app-config.local.yaml` in the repo root. To load a different set of files, use `--config <path>` arguments.
### @backstage/backend-common
- Configuration files are no longer selected through `APP_ENV` or `NODE_ENV`. The default configuration files are `app-config.yaml` and, fix it exists, `app-config.local.yaml` in the repo root. To load a different set of files, use `--config <path>` arguments.
## v0.1.1-alpha.25
### @backstage/cli
- The recommended way to set the configuration environment is now to use `APP_ENV` instead of `NODE_ENV`.
### Backend (example-backend, or backends created with @backstage/create-app)
- A plugin database manager has been created, and plugins can now accept that interface as an argument during initialisation. Notably, the `auth` plugin has a [`createRouter` signature change](./plugins/auth-backend/src/service/router.ts). See [packages/backend/src/index.ts](./packages/backend/src/index.ts) on how to set it up. [#2697](https://github.com/backstage/backstage/pull/2697)
## v0.1.1-alpha.24
### Backend (example-backend, or backends created with @backstage/create-app)
- The default mount point for backend plugins have been changed to `/api`. These changes are done in the backend package itself, so it is recommended that you sync up existing backend packages with this new pattern. [#2562](https://github.com/backstage/backstage/pull/2562)
- A service discovery mechanism for backend plugins has been added, and is now a requirement for several backend plugins. See [packages/backend/src/index.ts](./packages/backend/src/index.ts) for how to set it up using `SingleHostDiscovery` from `@backstage/backend-common`. Note that the default base path for plugins is set to `/api` to that change, but it can be set to use the old behavior via the `basePath` option. [#2600](https://github.com/backstage/backstage/pull/2600)
### @backstage/auth-backend
- The default mount path of backend plugins was changed to `/api/:pluginId`, and as part of that it was needed to enable configuration of the base path of the auth backend, so that it can construct redirect URLs correctly. Note that you will also need to reconfigure any allowed redirect URLs to include `/api` if you switch to the new recommended pattern. [#2562](https://github.com/backstage/backstage/pull/2562)
- The auth backend now requires an implementation of `PluginEndpointDiscovery` from `@backstage/backend-common` to be passed in as `discovery`. See the changes to `@backstage/backend`.
### @backstage/proxy-backend
- The proxy backend now requires an implementation of `PluginEndpointDiscovery` from `@backstage/backend-common` to be passed in as `discovery`. See the changes to `@backstage/backend`.
### @backstage/techdocs-backend
- The TechDocs backend now requires an implementation of `PluginEndpointDiscovery` from `@backstage/backend-common` to be passed in as `discovery`. See the changes to `@backstage/backend`.
### @backstage/plugin-identity-backend
- This plugin was removed, remove it from your backend if it's there. [#2616](https://github.com/backstage/backstage/pull/2616)
## v0.1.1-alpha.23
### @backstage/core
- Renamed `SessionStateApi` to `SessionApi` and `logout` to `signOut`. Custom implementations of the `SingInPage` app-component will need to rename their `logout` function. The different auth provider items for the `UserSettingsMenu` have been consolidated into a single `ProviderSettingsItem`, meaning you need to replace existing usages of `OAuthProviderSettings` and `OIDCProviderSettings`. [#2555](https://github.com/backstage/backstage/pull/2555).
## v0.1.1-alpha.22
### @backstage/core
- Introduced initial version of an inverted app/plugin relationship, where plugins export components for apps to use, instead registering themselves directly into the app. This enables more fine-grained control of plugin features, and also composition of plugins such as catalog pages with additional cards and tabs. This breaks the use of `RouteRef`s, and there will be more changes related to this in the future, but this change lays the initial foundation. See `packages/app` and followup PRs for how to update plugins for this change. [#2076](https://github.com/backstage/backstage/pull/2076)
- Switch to an automatic dependency injection mechanism for all Utility APIs, allowing plugins to ship default implementations of their APIs. See [https://backstage.io/docs/api/utility-apis](https://backstage.io/docs/api/utility-apis). [#2285](https://github.com/backstage/backstage/pull/2285)
### @backstage/cli
- Change `backstage-cli backend:build-image` to forward all args to `docker image build`, instead of just tag. Also add `--build` flag for building all dependent packages before packaging the workspace for the docker build. [#2299](https://github.com/backstage/backstage/pull/2299)
### @backstage/create-app
- Change root `tsc` output dir to `dist-types`, in order to allow for standalone plugin repos. [#2278](https://github.com/backstage/backstage/pull/2278)
### @backstage/catalog-backend
- We have simplified the way that GitHub ingestion works. The `catalog.processors.githubApi` key is deprecated, in favor of `catalog.processors.github`. At the same time, the location type `github/api` is likewise deprecated, in favor of `github`. This location type now serves both raw HTTP reads and APIv3 reads, depending on how you configure it. It also supports having several providers at once - for example, both public GitHub and an internal GitHub Enterprise, with different keys. If you still use the `catalog.processors.githubApi` config key, things will work but you will get a deprecation warning at startup. In a later release, support for the old key will go away entirely. See the [configuration section in the docs](https://backstage.io/docs/features/software-catalog/configuration) for more details.
## v0.1.1-alpha.21
- Added many more frontend plugins to the template along with the sidebar. [#1942](https://github.com/backstage/backstage/pull/1942), [#2084](https://github.com/backstage/backstage/pull/2084)
### @backstage/core
- Material-UI: Bumped to 4.11.0, which is the version that create-app will
resolve to, because we wanted to get the renaming of ExpansionPanel to
Accordion into place. This gets rid of a lot of console deprecation warnings
in newly scaffolded apps.
### @backstage/cli
- Set `NODE_ENV` to `test` when running test. [#2214](https://github.com/backstage/backstage/pull/2214)
- Fix for backend plugins names requiring to be prefixed with `@backstage` to build. [#2224](https://github.com/backstage/backstage/pull/2224)
### @backstage/backend-common
- The backend plugin
[service builder](https://github.com/backstage/backstage/blob/master/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts)
no longer adds `express.json()` automatically to all routes. While convenient
in a lot of cases, it also led to problems where for example the proxy
middleware could hang because the body had already been altered and could not
be streamed. Also, plugins that rather wanted to handle e.g. form encoded data
still had to cater to that manually. We therefore decided to let plugins add
`express.json()` themselves if they happen to deal with JSON data.
### @backstage/catalog-backend
- Add rules configuration for catalog location and entity kinds. The default rules should cover most use-cases, but you may need to allow specific entity kinds when using things like Template or Group entities. [#2118](https://github.com/backstage/backstage/pull/2118)
## v0.1.1-alpha.20
### @backstage/cli
- Use config files according to `NODE_ENV` when serving and building frontend packages. [#2077](https://github.com/backstage/backstage/pull/2077)
- Pin `rollup-plugin-dts` to avoid a later broken version. [#2097](https://github.com/backstage/backstage/pull/2097)
## v0.1.1-alpha.19
### @backstage/backend-common
- Allow listen host and port to be configured separately, in order to support PORT environment variables. [#1950](https://github.com/backstage/backstage/pull/1950)
### @backstage/core
- Added new `DiscoveryApi` for discovering backend endpoint in the frontend, and use in most plugins. See [packages/app/src/apis.ts](https://github.com/backstage/backstage/blob/master/packages/app/src/apis.ts) for how to register in your app. [#2074](https://github.com/backstage/backstage/pull/2074)
### @backstage/create-app
- Added catalog and scaffolder frontend plugins to the template along with the sidebar. [#1942](https://github.com/backstage/backstage/pull/1942), [#2084](https://github.com/backstage/backstage/pull/2084)
- Many plugins have been added to the catalog and will for now be required to be added to separate apps as well. This will be solved as [#1536](https://github.com/backstage/backstage/issues/1536) gets sorted out, but for now you may need to install some plugins just to get pages to work.
### @backstage/catalog-backend
- Added the possibility to add static locations via `app-config.yaml`. This changed the signature of `new LocationReaders(logger)` inside `packages/backend/src/plugins/catalog.ts` to `new LocationReaders({config, logger})`. [#1890](https://github.com/backstage/backstage/pull/1890)
### @backstage/theme
- Changed the type signature of the palette, removing `sidebar: string` and adding `navigation: { background: string; indicator: string}`. [#1880](https://github.com/backstage/backstage/pull/1880)
## v0.1.1-alpha.18
### @backstage/catalog-backend
- Fixed an issue with duplicated location logs. Applying the database migrations from this fix will clear the existing migration logs. [#1836](https://github.com/backstage/backstage/pull/1836)
### @backstage/auth-backend
This version fixes a breakage in CSP policies set by the auth backend. If you're facing trouble with auth in alpha.17, upgrade to alpha.18.
- OAuth redirect URLs no longer receive the `env` parameter, as it is now passed through state instead. This will likely require a reconfiguration of the OAuth app, where a redirect URL like `http://localhost:7000/auth/google/handler/frame?env=development` should now be configured as `http://localhost:7000/auth/google/handler/frame`. [#1812](https://github.com/backstage/backstage/pull/1812)
### @backstage/core
- `SignInPage` props have been changed to receive a list of provider objects instead of simple string identifiers for all but the `'guest'` and `'custom'` providers. This opens up for configuration of custom providers, but may break existing configurations. See [packages/app/src/App.tsx](https://github.com/backstage/backstage/blob/032ba401af36a760efdac41668d7000ccf09bc57/packages/app/src/App.tsx#L36) and [packages/app/src/identityProviders.ts](https://github.com/backstage/backstage/blob/032ba401af36a760efdac41668d7000ccf09bc57/packages/app/src/identityProviders.ts#L24) for how to bring back the existing providers. [#1816](https://github.com/backstage/backstage/pull/1816)
## v0.1.1-alpha.17
### @backstage/techdocs-backend
- The techdocs backend now requires more configuration to be supplied when creating the router. See [packages/backend/src/plugins/techdocs.ts](https://github.com/backstage/backstage/blob/0201fd9b4a52429519dd59e9184106ba69456deb/packages/backend/src/plugins/techdocs.ts#L42) for an example. [#1736](https://github.com/backstage/backstage/pull/1736)
### @backstage/cli
- The `create-app` command was moved out from the CLI to a standalone package. It's now invoked with `npx @backstage/create-app` instead. [#1745](https://github.com/backstage/backstage/pull/1745)
+4
View File
@@ -29,12 +29,16 @@ backend:
database:
client: sqlite3
connection: ':memory:'
cache:
store: memory
cors:
origin: http://localhost:3000
methods: [GET, POST, PUT, DELETE]
credentials: true
csp:
connect-src: ["'self'", 'http:', 'https:']
# Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference
# Default Helmet Content-Security-Policy values can be removed by setting the key to false
reading:
allow:
- host: example.com
@@ -167,4 +167,4 @@ Once it's deployed, after going through the AAD authentication flow, Backstage s
<!-- links -->
[monorepo-app-setup-with-auth-ms]: https://backstage.io/docs/tutorials/quickstart-app-auth#the-auth-configuration
[monorepo-app-setup-with-auth-ms]: https://backstage.io/docs/auth/microsoft/provider
@@ -80,6 +80,4 @@ backend:
origin: https://your-public-url.com:3000
```
If the protocol is `http`, you will need to set `backend.csp.upgrade-insecure-requests` to `false` as well.
The app port must proxy web socket connections in order to make hot reloading work.
+1 -1
View File
@@ -5,7 +5,7 @@
"license": "MIT",
"private": true,
"dependencies": {
"cypress": "^6.4.0",
"cypress": "^7.3.0",
"typescript": "^4.1.3"
}
}
+89 -82
View File
@@ -53,7 +53,12 @@
dependencies:
any-observable "^0.3.0"
"@types/sinonjs__fake-timers@^6.0.1":
"@types/node@^14.14.31":
version "14.17.0"
resolved "https://registry.npmjs.org/@types/node/-/node-14.17.0.tgz#3ba770047723b3eeb8dc9fca02cce8a7fb6378da"
integrity sha512-w8VZUN/f7SSbvVReb9SWp6cJFevxb4/nkG65yLAya//98WgocKm5PLDAtSs5CtJJJM+kHmJjO/6mmYW4MHShZA==
"@types/sinonjs__fake-timers@^6.0.2":
version "6.0.2"
resolved "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae"
integrity sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==
@@ -117,7 +122,7 @@ any-observable@^0.3.0:
resolved "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b"
integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==
arch@^2.1.2:
arch@^2.2.0:
version "2.2.0"
resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
@@ -171,7 +176,7 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
blob-util@2.0.2:
blob-util@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb"
integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==
@@ -242,10 +247,10 @@ check-more-types@^2.24.0:
resolved "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600"
integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=
ci-info@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
ci-info@^3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.1.1.tgz#9a32fcefdf7bcdb6f0a7e1c0f8098ec57897b80a"
integrity sha512-kdRWLBIJwdsYJWYJFtAFFYxybguqeF91qpZaggjG5Nf8QKdizFG2hjqvaTXbxFIcYbSaD74KpAXv6BSm17DHEQ==
cli-cursor@^1.0.2:
version "1.0.2"
@@ -359,18 +364,19 @@ cross-spawn@^7.0.0:
shebang-command "^2.0.0"
which "^2.0.1"
cypress@^6.4.0:
version "6.4.0"
resolved "https://registry.npmjs.org/cypress/-/cypress-6.4.0.tgz#432c516bf4f1a0f042a6aa1f2c3a4278fa35a8b2"
integrity sha512-SrsPsZ4IBterudkoFYBvkQmXOVxclh1/+ytbzpV8AH/D2FA+s2Qy5ISsaRzOFsbQa4KZWoi3AKwREmF1HucYkg==
cypress@^7.3.0:
version "7.3.0"
resolved "https://registry.npmjs.org/cypress/-/cypress-7.3.0.tgz#17345b8d18681c120f033e7d8fd0f0271e9d0d51"
integrity sha512-aseRCH1tRVCrM6oEfja6fR/bo5l6e4SkHRRSATh27UeN4f/ANC8U7tGIulmrISJVy9xuOkOdbYKbUb2MNM+nrw==
dependencies:
"@cypress/listr-verbose-renderer" "^0.4.1"
"@cypress/request" "^2.88.5"
"@cypress/xvfb" "^1.2.4"
"@types/sinonjs__fake-timers" "^6.0.1"
"@types/node" "^14.14.31"
"@types/sinonjs__fake-timers" "^6.0.2"
"@types/sizzle" "^2.3.2"
arch "^2.1.2"
blob-util "2.0.2"
arch "^2.2.0"
blob-util "^2.0.2"
bluebird "^3.7.2"
cachedir "^2.3.0"
chalk "^4.1.0"
@@ -378,27 +384,26 @@ cypress@^6.4.0:
cli-table3 "~0.6.0"
commander "^5.1.0"
common-tags "^1.8.0"
dayjs "^1.9.3"
debug "^4.1.1"
eventemitter2 "^6.4.2"
execa "^4.0.2"
dayjs "^1.10.4"
debug "4.3.2"
eventemitter2 "^6.4.3"
execa "4.1.0"
executable "^4.1.1"
extract-zip "^1.7.0"
fs-extra "^9.0.1"
fs-extra "^9.1.0"
getos "^3.2.1"
is-ci "^2.0.0"
is-installed-globally "^0.3.2"
is-ci "^3.0.0"
is-installed-globally "~0.4.0"
lazy-ass "^1.6.0"
listr "^0.14.3"
lodash "^4.17.19"
lodash "^4.17.21"
log-symbols "^4.0.0"
minimist "^1.2.5"
moment "^2.29.1"
ospath "^1.2.2"
pretty-bytes "^5.4.1"
ramda "~0.26.1"
pretty-bytes "^5.6.0"
ramda "~0.27.1"
request-progress "^3.0.0"
supports-color "^7.2.0"
supports-color "^8.1.1"
tmp "~0.2.1"
untildify "^4.0.0"
url "^0.11.0"
@@ -416,11 +421,18 @@ date-fns@^1.27.2:
resolved "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
dayjs@^1.9.3:
dayjs@^1.10.4:
version "1.10.4"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz#8e544a9b8683f61783f570980a8a80eaf54ab1e2"
integrity sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==
debug@4.3.2:
version "4.3.2"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
dependencies:
ms "2.1.2"
debug@^2.6.9:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -435,13 +447,6 @@ debug@^3.1.0:
dependencies:
ms "^2.1.1"
debug@^4.1.1:
version "4.3.1"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
ms "2.1.2"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@@ -477,12 +482,12 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
eventemitter2@^6.4.2:
version "6.4.3"
resolved "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.3.tgz#35c563619b13f3681e7eb05cbdaf50f56ba58820"
integrity sha512-t0A2msp6BzOf+QAcI6z9XMktLj52OjGQg+8SJH6v5+3uxNpWYRR3wQmfA+6xtMU9kOC59qk9licus5dYcrYkMQ==
eventemitter2@^6.4.3:
version "6.4.4"
resolved "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.4.tgz#aa96e8275c4dbeb017a5d0e03780c65612a1202b"
integrity sha512-HLU3NDY6wARrLCEwyGKRBvuWYyvW6mHYv72SJJAH3iJN3a6eVUvkjFkcxah1bcTgGVBBrFdIopBJPhCQFMLyXw==
execa@^4.0.2:
execa@4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a"
integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
@@ -580,7 +585,7 @@ form-data@~2.3.2:
combined-stream "^1.0.6"
mime-types "^2.1.12"
fs-extra@^9.0.1:
fs-extra@^9.1.0:
version "9.1.0"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
@@ -628,12 +633,12 @@ glob@^7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
global-dirs@^2.0.1:
version "2.1.0"
resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d"
integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==
global-dirs@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686"
integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==
dependencies:
ini "1.3.7"
ini "2.0.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.5"
@@ -702,17 +707,17 @@ inherits@2, inherits@^2.0.3, inherits@~2.0.3:
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
ini@1.3.7:
version "1.3.7"
resolved "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
is-ci@^2.0.0:
ini@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==
resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5"
integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
is-ci@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz#c7e7be3c9d8eef7d0fa144390bd1e4b88dc4c994"
integrity sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==
dependencies:
ci-info "^2.0.0"
ci-info "^3.1.1"
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
@@ -731,13 +736,13 @@ is-fullwidth-code-point@^3.0.0:
resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
is-installed-globally@^0.3.2:
version "0.3.2"
resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==
is-installed-globally@~0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520"
integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==
dependencies:
global-dirs "^2.0.1"
is-path-inside "^3.0.1"
global-dirs "^3.0.0"
is-path-inside "^3.0.2"
is-observable@^1.1.0:
version "1.1.0"
@@ -746,10 +751,10 @@ is-observable@^1.1.0:
dependencies:
symbol-observable "^1.1.0"
is-path-inside@^3.0.1:
version "3.0.2"
resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017"
integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==
is-path-inside@^3.0.2:
version "3.0.3"
resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-promise@^2.1.0:
version "2.2.2"
@@ -879,10 +884,10 @@ lodash.once@^4.1.1:
resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
lodash@^4.17.19:
version "4.17.20"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@^1.0.2:
version "1.0.2"
@@ -953,11 +958,6 @@ mkdirp@^0.5.4:
dependencies:
minimist "^1.2.5"
moment@^2.29.1:
version "2.29.1"
resolved "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -1056,10 +1056,10 @@ pify@^2.2.0:
resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
pretty-bytes@^5.4.1:
version "5.5.0"
resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.5.0.tgz#0cecda50a74a941589498011cf23275aa82b339e"
integrity sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA==
pretty-bytes@^5.6.0:
version "5.6.0"
resolved "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
process-nextick-args@~2.0.0:
version "2.0.1"
@@ -1099,10 +1099,10 @@ querystring@0.2.0:
resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
ramda@~0.26.1:
version "0.26.1"
resolved "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==
ramda@~0.27.1:
version "0.27.1"
resolved "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz#66fc2df3ef873874ffc2da6aa8984658abacf5c9"
integrity sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==
readable-stream@^2.2.2:
version "2.3.7"
@@ -1277,13 +1277,20 @@ supports-color@^5.3.0:
dependencies:
has-flag "^3.0.0"
supports-color@^7.1.0, supports-color@^7.2.0:
supports-color@^7.1.0:
version "7.2.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
supports-color@^8.1.1:
version "8.1.1"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
symbol-observable@^1.1.0:
version "1.2.0"
resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
@@ -125,8 +125,8 @@ entity, and for machines and other components to reference the entity (e.g. in
URLs or from other entity specification files).
Names must be unique per kind, within a given namespace (if specified), at any
point in time. Names may be reused at a later time, after an entity is deleted
from the registry.
point in time. This uniqueness constraint is also case insensitive. Names may be
reused at a later time, after an entity is deleted from the registry.
Names are required to follow a certain format. Entities that do not follow those
rules will not be accepted for registration in the catalog. The ruleset is
@@ -139,18 +139,6 @@ follows.
Example: `visits-tracking-service`, `CircleciBuildsDs_avro_gcs`
In addition to this, names are passed through a normalization function and then
compared to the same normalized form of other entity names and made sure to not
collide. This rule of uniqueness exists to avoid situations where e.g. both
`my-component` and `MyComponent` are registered side by side, which leads to
confusion and risk. The normalization function is also configurable, but the
default behavior is as follows.
- Strip out all characters outside of the set `[a-zA-Z0-9]`
- Convert to lowercase
Example: `CircleciBuildsDs_avro_gcs` -> `circlecibuildsdsavrogcs`
### `namespace`
The `name` of a namespace that the entity belongs to. This field is optional,
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

+2 -2
View File
@@ -31,8 +31,8 @@ auth:
providers:
gitlab:
development:
clientId: ${AUTH_GITLAB_APPLICATION_ID}
clientSecret: ${AUTH_GITLAB_SECRET}
clientId: ${AUTH_GITLAB_CLIENT_ID}
clientSecret: ${AUTH_GITLAB_CLIENT_SECRET}
## uncomment if using self-hosted GitLab
# audience: https://gitlab.company.com
```
-2
View File
@@ -77,7 +77,6 @@ built-in providers:
+
const app = createApp({
apis,
plugins: Object.values(plugins),
+ components: {
+ SignInPage: props => (
+ <SignInPage
@@ -96,7 +95,6 @@ To also allow unauthenticated guest access, use the `providers` prop for
```diff
const app = createApp({
apis,
plugins: Object.values(plugins),
+ components: {
+ SignInPage: props => (
+ <SignInPage
+12 -2
View File
@@ -6,8 +6,9 @@ description: Documentation on Writing Backstage Configuration Files
## File Format
Configuration is stored in YAML format in `app-config.yaml` files, looking
something like this:
Configuration is stored in YAML format in `app-config.yaml` files. This
configuration is shared between the frontend and backend and it looks something
like this:
```yaml
app:
@@ -32,6 +33,15 @@ proxy:
Configuration files are typically checked in and stored in the repo that houses
the rest of the Backstage application.
The particular configuration that is available to each Backstage app depends on
what plugins and packages are installed. To view the configuration reference for
your own project, including what configuration keys available and whether they
are needed by the frontend, use the following command:
```sh
yarn backstage-cli config:docs
```
## Environment Variable Overrides
Individual configuration values can be overridden using environment variables
@@ -0,0 +1,183 @@
---
id: catalog-customization
title: Catalog Customization
# prettier-ignore
description: How to add custom filters or interface elements to the Backstage software catalog
---
The Backstage software catalog comes with a default `CatalogIndexPage` to filter
and find catalog entities. This is already set up by default by
`@backstage/create-app`.
If you want to change the default index page - such as to add a custom filter to
the catalog - you can replace the routing in `App.tsx` to point to your own
`CatalogIndexPage`.
> Note: The catalog index page is designed to have a minimal code footprint to
> support easy customization, but creating a copy does introduce a possibility
> of drifting out of date over time. Be sure to check the catalog
> [CHANGELOG](https://github.com/backstage/backstage/blob/master/plugins/catalog/CHANGELOG.md)
> periodically.
For example, suppose that I want to allow filtering by a custom annotation added
to entities, `company.com/security-tier`. To start, I'll copy the code for the
default catalog page and create a component in a
[new plugin](../../plugins/create-a-plugin.md):
```tsx
// imports, etc omitted for brevity. for full source see:
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx
export const CustomCatalogPage = () => {
return (
<CatalogLayout>
<Content>
<ContentHeader title="Components">
<CreateComponentButton />
<SupportButton>All your software catalog entities</SupportButton>
</ContentHeader>
<div className={styles.contentWrapper}>
<EntityListProvider>
<div>
<EntityKindPicker initialFilter="component" hidden />
<EntityTypePicker />
<UserListPicker />
<EntityTagPicker />
</div>
<CatalogTable />
</EntityListProvider>
</div>
</Content>
</CatalogLayout>
);
};
```
The `EntityListProvider` shown here provides a list of entities from the
`catalog-backend`, and a way to hook in filters.
Now we're ready to create a new filter that implements the `EntityFilter`
interface:
```ts
import { EntityFilter } from '@backstage/plugin-catalog-react';
import { Entity } from '@backstage/catalog-model';
class EntitySecurityTierFilter implements EntityFilter {
constructor(readonly values: string[]) {}
filterEntity(entity: Entity): boolean {
const tier = entity.metadata.annotations?.['company.com/security-tier'];
return tier !== undefined && this.values.includes(tier);
}
}
```
The `EntityFilter` interface permits backend filters, which are passed along to
the `catalog-backend` - or frontend filters, which are applied after entities
are loaded from the backend.
We'll use this filter to extend the default filters in a type-safe way. Let's
create the custom filter shape extending the default somewhere alongside this
filter:
```ts
export type CustomFilters = DefaultEntityFilters & {
securityTiers?: EntitySecurityTierFilter;
};
```
To control this filter, we can create a React component that shows checkboxes
for the security tiers. This component will make use of the
`useEntityListProvider` hook, which accepts this extended filter type as a
[generic](https://www.typescriptlang.org/docs/handbook/2/generics.html)
parameter:
```tsx
export const EntitySecurityTierPicker = () => {
// The securityTiers key is recognized due to the CustomFilter generic
const {
filters: { securityTiers },
updateFilters,
} = useEntityListProvider<CustomFilters>();
// Toggles the value, depending on whether it's already selected
function onChange(value: string) {
const newTiers = securityTiers?.values.includes(value)
? securityTiers.values.filter(tier => tier !== value)
: [...(securityTiers?.values ?? []), value];
updateFilters({
securityTiers: newTiers.length
? new EntitySecurityTierFilter(newTiers)
: undefined,
});
}
const tierOptions = ['1', '2', '3'];
return (
<FormControl component="fieldset">
<Typography variant="button">Security Tier</Typography>
<FormGroup>
{tierOptions.map(tier => (
<FormControlLabel
key={tier}
control={
<Checkbox
checked={securityTiers?.values.includes(tier)}
onChange={() => onChange(tier)}
/>
}
label={`Tier ${tier}`}
/>
))}
</FormGroup>
</FormControl>
);
};
```
Now we can add the component to `CustomCatalogPage`:
```diff
export const CustomCatalogPage = () => {
return (
...
<EntityListProvider>
<div>
<EntityKindPicker initialFilter="component" hidden />
<EntityTypePicker />
<UserListPicker />
+ <EntitySecurityTierPicker />
<EntityTagPicker />
</div>
<CatalogTable />
</EntityListProvider>
...
};
```
This page itself can be exported as a routable extension in the plugin:
```ts
export const CustomCatalogIndexPage = myPlugin.provide(
createRoutableExtension({
component: () =>
import('./components/CustomCatalogPage').then(m => m.CustomCatalogPage),
mountPoint: catalogRouteRef,
}),
);
```
Finally, we can replace the catalog route in the Backstage application with our
new `CustomCatalogIndexPage`.
```diff
# packages/app/src/App.tsx
const routes = (
<FlatRoutes>
<Navigate key="/" to="/catalog" />
- <Route path="/catalog" element={<CatalogIndexPage />} />
+ <Route path="/catalog" element={<CustomCatalogIndexPage />} />
```
The same method can be used to customize the _default_ filters with a different
interface - for such usage, the generic argument isn't needed since the filter
shape remains the same as the default.
@@ -399,16 +399,17 @@ well-known / common relations and their semantics.
## Common to All Kinds: Status
The `status` root field is a read-only set of statuses, pertaining to the
The `status` root object is a read-only set of statuses, pertaining to the
current state or health of the entity, described in the
[well-known statuses section](well-known-statuses.md). Each status field
contains a specific blob of data that describes some aspect of the state of the
entity, as seen from the point of view of some specific system. Different
systems may contribute to this status object, under their own respective keys.
[well-known statuses section](well-known-statuses.md).
Currently, the only defined field is the `items` array. Each of its items
contains a specific data structure that describes some aspect of the state of
the entity, as seen from the point of view of some specific system. Different
systems may contribute to this array, under their own respective `type` keys.
The current main use case for this field is for the ingestion processes of the
catalog itself to convey information about failures and warnings back to the
user.
catalog itself to convey information about errors and warnings back to the user.
A status field as part of a single entity that's read out of the API may look as
follows.
@@ -417,9 +418,18 @@ follows.
{
// ...
"status": {
"backstage.io/catalog-processing": {
"errors": []
}
"items": [
{
"type": "backstage.io/catalog-processing",
"level": "error",
"message": "NotFoundError: File not found",
"error": {
"name": "NotFoundError",
"message": "File not found",
"stack": "..."
}
}
]
},
"spec": {
// ...
@@ -427,23 +437,27 @@ follows.
}
```
The keys of the `status` object are arbitrary strings. We recommend that any
statuses that are not strictly private within the organization be namespaced to
avoid collisions. Statuses emitted by Backstage core processes will for example
be prefixed with `backstage.io/` as in the example above.
The fields of a status item are:
The values of the `status` object are currently left unrestricted, except that
they must be objects. We reserve the right to extend this model in the future,
such that some fields of those value objects gain standardized meaning. We may
for example want to add a standard concept of "severity" or "level" to these.
| Field | Type | Description |
| --------- | ------ | ------------------------------------------------------------------------------------------------ |
| `type` | String | The type of status as a unique key per source. Each type may appear more than once in the array. |
| `level` | String | The level / severity of the status item: 'info', 'warning, or 'error'. |
| `message` | String | A brief message describing the status, intended for human consumption. |
| `error` | Object | An optional serialized error object related to the status. |
Entity descriptor YAML files are not supposed to contain this field. Instead,
catalog processors analyze the entity descriptor data and its surroundings, and
deduce status entries that are then attached onto the entity as read from the
catalog.
The `type` is an arbitrary string, but we recommend that types that are not
strictly private within the organization be namespaced to avoid collisions.
Types emitted by Backstage core processes will for example be prefixed with
`backstage.io/` as in the example above.
Entity descriptor YAML files are not supposed to contain a `status` root key.
Instead, catalog processors analyze the entity descriptor data and its
surroundings, and deduce status entries that are then attached onto the entity
as read from the catalog.
See the [well-known statuses section](well-known-statuses.md) for a list of
well-known / common relations and their semantics.
well-known / common status types.
## Kind: Component
@@ -706,6 +720,25 @@ You can find out more about the `parameters` key
You can find out more about the `steps` key
[here](../software-templates/writing-templates.md)
### `spec.owner` [optional]
An [entity reference](#string-references) to the owner of the component, e.g.
`artist-relations-team`. This field is required.
In Backstage, the owner of a Template is the singular entity (commonly a team)
that bears ultimate responsibility for the Template, and has the authority and
capability to develop and maintain it. They will be the point of contact if
something goes wrong, or if features are to be requested. The main purpose of
this field is for display purposes in Backstage, so that people looking at
catalog items can get an understanding of to whom this Template belongs. It is
not to be used by automated processes to for example assign authorization in
runtime systems. There may be others that also develop or otherwise touch the
Template, but there will always be one ultimate owner.
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
| ------------------------------------------------------ | ------------------------------------------ | ------------------------------------------------------------------------------- |
| [`Group`](#kind-group) (default), [`User`](#kind-user) | Same as this entity, typically `default` | [`ownerOf`, and reverse `ownedBy`](well-known-relations.md#ownedby-and-ownerof) |
## Kind: API
Describes the following entity kind:
@@ -353,18 +353,43 @@ relation could be considered for addition to the core.
## Adding a New Status field
Example intents:
Example intent:
> "We would like to convey entity statuses through the catalog in a generic way,
> as an integration layer. Our monitoring and alerting system has a plugin with
> Backstage, and it would be useful if the entity's status field contained the
> current alert state close to the actual entity data for anyone to consume.
> current alert state close to the actual entity data for anyone to consume. We
> find the `status.items` semantics a poor fit, so we would prefer to make our
> own custom field under `status` for these purposes."
While we are considering a mechanism for contributing generic statuses to
entities, no such mechanism has yet been built. If you are interested in that
topic, [this issue](https://github.com/backstage/backstage/issues/2292) contains
We have not yet ventured to define any generic semantics for the `status`
object. We recommend sticking with the `status.items` mechanism where possible
(see below), since third party consumers will not be able to consume your status
information otherwise. Please reach out to the maintainers on Discord or by
making a GitHub issue describing your use case if you are interested in this
topic.
## Adding a New Status Item Type
Example intent:
> "The semantics of the entity `status.items` field are fine for our needs, but
> we want to contribute our own type of status into that array instead of the
> catalog specific one."
This is a simple, low risk way of adding your own status information to
entities. Consumers will be able to easily track and display the status together
with other types / sources.
We recommend that any status type that are not strictly private within the
organization be namespaced to avoid collisions. Statuses emitted by Backstage
core processes will for example be prefixed with `backstage.io/`, your
organization may prefix with `my-org.net/`, and `pagerduty.com/active-alerts`
could be a sensible complete status item type for that particular external
system.
The mechanics for how to emit custom statuses is not in place yet, so if this is
of interest to you, you might consider contacting the maintainers on Discord or
my making a GitHub issue describing your use case.
[This issue](https://github.com/backstage/backstage/issues/2292) also contains
more context.
But in general, errors emitted (and exceptions thrown) by any processor
including custom ones, end up in the [well known key](well-known-statuses.md)
for ingestion status.
@@ -6,35 +6,37 @@ sidebar_label: Well-known Statuses
description: Lists a number of well known entity statuses, that have defined semantics. They can be attached to catalog entities and consumed by plugins as needed.
---
This section lists a number of well known
[entity status fields](descriptor-format.md#common-to-all-kinds-status), that
have defined semantics. They can be attached to catalog entities and consumed by
This section lists well known
[entity statuses](descriptor-format.md#common-to-all-kinds-status), that have
defined semantics. They can be attached to catalog entities and consumed by
plugins as needed.
If you are looking to extend the set of statuses, see
If you are looking to extend the statuses, see
[Extending the model](extending-the-model.md).
## Common Fields
The values of statuses are currently left unrestricted, except that they must be
objects. They therefore currently formally have no common fields.
The `status` object of an entity is currently left unrestricted, except for the
`items` field. Its structure is defined in the
[descriptor format](descriptor-format.md#common-to-all-kinds-status) section.
We reserve the right to extend this model in the future, such that some fields
of those value objects gain standardized meaning. We may for example want to add
a standard concept of "severity" or "level" to these.
We reserve the right to extend this model in the future. This status is in
active development and its format will change unexpectedly. Do not consume it in
your own code until such a time that this documentation has been updated.
## Statuses
## Status Item Types
This is a (non-exhaustive) list of statuses that are known to be in active use.
This is a (non-exhaustive) list of `status.items.[].type` values that are known
to be in active use.
### `backstage.io/catalog-processing`
Contains the current status of the catalog's ingestion of this entity. Errors
that may appear here include inability to read from the remote SCM provider,
syntax errors in the YAML file, and similar.
Expresses an aspect of the current status of the catalog's ingestion of this
entity. Errors that may appear here include inability to read from the remote
SCM provider, syntax errors in the YAML file, and similar.
Note that the entity data itself may be of an older version, when errors are
present. The ingestion system keeps the old, valid entity data untouched when
present. The ingestion system keeps the old valid entity data untouched when
possible, so the errors described in this state may not seem to align with the
rest of the entity, because they pertain to a remote that could not be
successfully ingested. This is normal.
@@ -42,10 +44,12 @@ successfully ingested. This is normal.
```yaml
# Example:
status:
backstage.io/catalog-processing:
errors: []
items:
- type: backstage.io/catalog-processing
level: error
message: 'NotFoundError: File not found'
error:
name: NotFoundError
message: File not found
stack: ...
```
This status is in active development and its format will change unexpectedly. Do
not consume it in your own code until such a time that this documentation has
been updated.
@@ -0,0 +1,334 @@
---
id: migrating-from-v1alpha1-to-v1beta2
title: Migrating to v1beta2 templates
# prettier-ignore
description:
How to move your old templates from v1alpha1 to the more declarative v1beta2
---
# What's new?
Previously, the scaffolder was very restricted in what you could do when
creating new software components from templates. There were three scaffolding
steps which was pretty hard to extend and add new functionality to, difficult to
re-use logic between templates. There used to be a fixed pipeline of
`preparers`, `templaters`, and `publishers`, which were defined by the backend
and needed to be run for each template. This is now changed, to give the
template total control over what should be executed as part of the templating
run. This makes templates a little more declarative as you can now register
different `actions` or `functions` with the `scaffolder-backend` which you then
can decide how, and in what order, to run using the template definition YAML
file.
We've also made some improvements, and added some helpers to work with
cookiecutter. The skeleton for a template can now be stored in a different place
to where your entity definition is: previously you needed to have your
`template.yaml` next to the skeleton source (`{{cookiecutter.component_id}}`
directory), but now that's not the case. Part of the changes with the `v1beta2`
syntax is that you can grab your template source from any repository, and re-use
them between templates.
We've also renamed the `schema` property to `parameters` as this makes more
sense when using them as parameters to the actions or steps that you've setup
for your templates. There's the added benefit that you can now assign an array
to the `parameters` property, which will then give you multiple steps in the UI,
so you can split apart your input parameters and group them as needed rather
than having one long list of input fields.
## The `parameters` property
The `schema` key has now been renamed to `parameters` with a few more features.
You can pass an array now to break apart the input form into different steps in
the UI. You can also specify `ui:schema` fields that are passed along to
[`react-jsonschema-form`](https://rjsf-team.github.io/react-jsonschema-form/)
inline with the JSON schema.
```yaml
spec:
parameters:
- title: Fill in some steps
required:
- name
properties:
name:
title: Name
type: string
description: Unique name of the component
ui:autofocus: true
ui:options:
rows: 5
```
## The `steps` property
`v1beta2` template syntax introduces the new `steps` property, which is an array
of `actions` that the scaffolder will run in combination with the user input
that is declared in the `schema`. Actions look like the following:
```yaml
spec:
steps:
- id: publish # a unique id for the step, can be anything you like
name: Publish # a user friendly name for the step, this is what is shown in the frontend
action: publish:github # the action ID that has been registered with the scaffolder-backend
input: # parameters that are passed as input to the action handler function
allowedHosts: ['github.com']
description: 'This is {{ parameters.name }}' # handlebars templating is supported with the values from the parameters section in the same file.
repoUrl: '{{ parameters.repoUrl }}'
```
# Migrating a `v1alpha1` template
## The template definition (.yaml)
### `parameters`
Because of the changes to invert the control to the `template.yaml` definition
for running the workflow, we need to adjust the `schema` property and we also
now need to define what the template is actually going to do as part of the
template run.
A simple migration would move the following yaml:
```yaml
apiVersion: backstage.io/v1alpha1
kind: Template
metadata:
name: react-ssr-template
title: React SSR Template
description: Create a website powered with Next.js
tags:
- recommended
- react
spec:
owner: web@example.com
templater: cookiecutter
type: website
path: '.'
schema:
required:
- component_id
- description
properties:
component_id:
title: Name
type: string
description: Unique name of the component
description:
title: Description
type: string
description: Help others understand what this website is for.
```
To something that looks like the following:
```yaml
apiVersion: backstage.io/v1beta2
kind: Template
metadata:
name: react-ssr-template
title: React SSR Template
description: Create a website powered with Next.js
tags:
- recommended
- react
spec:
owner: web@example.com
type: website
parameters:
- title: Add some input
required:
- component_id
- description
properties:
component_id:
title: Name
type: string
description: Unique name of the component
description:
title: Description
type: string
description: Help others understand what this website is for.
- title: Some more additional info that was previously provided automatically
required:
- owner
- repoUrl
properties:
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
allowedKinds:
- Group
- title: Choose a location
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
```
There are a few things to note here. On the `alpha` version, the second step of
the template flow in the frontend was provided by Backstage for free, so we used
to collect the user input for the `owner` field and the `repositoryUrl` that you
were going to publish to. Now because `actions` can have any workflow they like,
it doesn't make sense to still provide these fields for every scaffolding
workflow, as you might not need these anymore. That's why we now manually add
those fields back into the template parameters that are shown to the user:
```yaml
- title: Some more additional info that was previously provided automatically
required:
- owner
- repoUrl
properties:
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
allowedKinds:
- Group
- title: Choose a location
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
```
Maybe you also don't need to publish to `github.com`, you should replace this
with your VCS provider URL that is listed in your `integrations` config instead.
### `steps`
So now we should have all the required information that we need from the user in
a much more extensible way. We now need to tell the scaffolder what to do with
these parameters and what to do with the user input.
We've made templating using `cookiecutter` a little simpler. You don't need to
store the `cookiecutter` skeleton in the same directory as the `template.yaml`
definition, it can live wherever you like - maybe a shared repository somewhere
so you can re-use the skeletons but apply different actions for different
templates depending on your use case.
We also no longer need to have a directory called
`{{cookiecutter.component_id}}`. This is because now we can't ensure that
`component_id` will be a parameter that is provided from the frontend, this
could break `cookiecutter`. If your directory structure used to look like this:
```
my-awesome-template
-> {{cookiecutter.component_id}}
-> file.txt
-> some_more_files.ts
-> hooks
-> post_gen_project.sh
-> template.yaml
```
We now recommend that you move to the following structure:
```
my-awesome-template
-> skeleton
-> file.txt
-> some_more_files.ts
-> template.yaml
```
This migration renames the skeleton folder to something more semantic, and also
drops support for `cookiecutter` hooks. We've dropped support for `cookiecutter`
hooks for now, as hopefully everything that is stored in these hooks can be
moved to `actions` instead, and for security reasons, it's more secure to run
trusted code that you ship with Backstage as an action rather than some script
that can be pulled in from anywhere which doesn't get vetted first. It's a
pretty big security risk that those scripts will be run on Backstage instances
inside your infrastructure, especially `.sh` files.
If you really need hooks and can't find a suitable solution by using actions
please reach out to us through a ticket and we'll see what we can do to assist
:)
You'll notice that we removed the `templater` property from the `spec`
definition in the template `yaml`, so there's no way to define that this is a
`cookiecutter` `templater`.
We've created a built-in action that you can use which will when run, go grab a
directory from anywhere and run `cookiecutter` on top of it, and then extract
the contents into the working directory for the scaffolder.
Adding the `steps` for a simple template should look something like the
following:
```yaml
spec:
steps:
# this action will go use cookiecutter to template some files into the working directory
- id: template # an ID for the templating step
name: Create skeleton # A user friendly name for the action
action: fetch:cookiecutter
input:
url: ./skeleton # this is the directory for your skeleton files.
# If it's located next to the `template.yaml` then you can use a relative path,
# otherwise you can use absolute URLs that point at the VCS: https://github.com/backstage/backstage/tree/master/some_folder_somewhere
values:
# for each value that you need to pass to cookiecutter, they should be listed here and set in this values object.
# You can use the handlebars templating syntax to pull them from the input parameters listed in the same file
name: '{{ parameters.name }}'
owner: '{{ parameters.owner }}'
destination: '{{ parseRepoUrl parameters.repoUrl }}'
# this action is for publishing the working directory to the VCS
- id: publish
name: Publish
action: publish:github
input:
allowedHosts: ['github.com']
description: 'This is {{ parameters.name }}'
repoUrl: '{{ parameters.repoUrl }}'
# this action will then register the created component in Backstage
- id: register
name: Register
action: catalog:register
input:
repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}'
catalogInfoPath: '/catalog-info.yaml'
```
### `output`
Steps can output values, and so can the template itself. This is good for
returning values to the frontend, so we can make the buttons like
`Go to catalog` and `Go to repo` work correctly. You can add the following to
your `template.yaml` to make sure you return the right values from the steps:
```yaml
spec:
output:
remoteUrl: '{{ steps.publish.output.remoteUrl }}'
entityRef: '{{ steps.register.output.entityRef }}'
```
Or you can return a `links` array with text and a URL explicitly:
```yaml
spec:
output:
links:
- url: '{{steps.publish.output.remoteUrl}}'
text: 'Go to Repo'
```
## Questions?
If you have any questions or feedback, please reach out to us on GitHub or
Discord and we will do our best to help!
@@ -142,6 +142,12 @@ this:
"type": "string",
"title": "Last name"
},
"nicknames":{
"type": "array",
"items": {
"type": "string"
}
},
"telephone": {
"type": "string",
"title": "Telephone",
@@ -161,6 +167,11 @@ this:
"ui:emptyValue": "",
"ui:autocomplete": "given-name"
},
"nicknames": {
"ui:options":{
"orderable": false
}
},
"telephone": {
"ui:options": {
"inputType": "tel"
@@ -202,6 +213,12 @@ spec:
title: Last name
ui:emptyValue: ''
ui:autocomplete: given-name
nicknames:
type: array
items:
type: string
ui:options:
orderable: false
telephone:
type: string
title: Telephone
@@ -222,17 +239,17 @@ You can see it in the above full example which is a separate step and it looks a
little like this:
```yaml
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
```
The `allowedHosts` part should be set to where you wish to enable this template
@@ -304,7 +321,10 @@ You might have noticed in the examples that there are `{{ }}`, and these are a
`yaml` together. All the form inputs from the `parameters` section, when passed
to the steps will be available by using the template syntax
`{{ parameters.something }}`. This is great for passing the values from the form
into different steps and reusing these input variables.
into different steps and reusing these input variables. To pass arrays or
objects use the syntax `{{ json paramaters.something }}` where
`paramaters.something` is of type `object` or `array` in the `jsonSchema`, such
as the `nicknames` parameter in the previous example.
As you can see above in the `Outputs` section, `actions` and `steps` can also
output things. So you can grab that output by using
+2 -1
View File
@@ -23,7 +23,8 @@ Backstage provides a utility for creating new apps. It guides you through the
initial setup of selecting the name of the app and a database for the backend.
The database options are either SQLite or PostgreSQL, where the latter requires
you to set up a separate database instance. If in doubt, choose SQLite, but
don't worry about the choice, it's easy to change later!
don't worry about the choice, it's easy to change later! Here is a
[tutorial](../tutorials/switching-sqlite-postgres.md) for it.
The easiest way to run the create app package is with `npx`:
+17 -24
View File
@@ -22,8 +22,8 @@ entities that mirror your org setup.
The processor that performs the import, `GithubOrgReaderProcessor`, comes
installed with the default setup of Backstage.
If you replace the set of processors in your installation using that facility of
the catalog builder class, you can import and add it as follows.
If you have _replaced_ the set of processors in your installation using
`replaceProcessors`, you can import and add it as follows:
```ts
// Typically in packages/backend/src/plugins/catalog.ts
@@ -45,30 +45,23 @@ catalog:
locations:
- type: github-org
target: https://github.com/my-org-name
processors:
githubOrg:
providers:
- target: https://github.com
apiBaseUrl: https://api.github.com
token: ${GITHUB_TOKEN}
```
If Backstage is configured to use GitHub Apps authentication you must grant
`Read-Only` access for `Members` under `Organization` in order to ingest users
correctly. You can modify the app's permissions under the organization settings,
`https://github.com/organizations/{ORG}/settings/apps/{APP_NAME}/permissions`.
![permissions](../../assets/integrations/github/permissions.png)
**Please note that when you change permissions, the app owner will get an email
that must be approved first before the changes are applied.**
![email](../../assets/integrations/github/email.png)
Locations point out the specific org(s) you want to import. The `type` of these
locations must be `github-org`, and the `target` must point to the exact URL of
some organization. You can have several such location entries if you want, but
typically you will have just one.
some organization. You can have several such location entries if needed.
The processor itself is configured in the other block, under
`catalog.processors.githubOrg`. There may be many providers, each targeting a
specific `target` which is supposed to be the address of the home page of GitHub
or your GitHub Enterprise installation.
The example above assumes that the backend is started with an environment
variable called `GITHUB_TOKEN` that contains a Personal Access Token. The token
needs to have at least the scopes `read:org`, `read:user`, and `user:email` in
the given `target`.
If you want to address your own GitHub Enterprise instance, replace occurrences
of `https://github.com` in the configuration above with the address of your
GitHub Enterprise home page, and the `apiBaseUrl` to where your API endpoint
lives - commonly on the form `https://<host>/api/v3`.
The authorization for loading org information comes from a configured
[GitHub integration](locations.md#configuration). When using a personal access
token, the token needs to have at least the scopes `read:org`, `read:user`, and
`user:email` in the given `target`.
+20 -5
View File
@@ -43,13 +43,13 @@ this.
The UI is a thin, client-side wrapper around a set of plugins. It provides some
core UI components and libraries for shared activities such as config
management. [[live demo](https://backstage-demo.roadie.io/)]
management. [[live demo](https://demo.backstage.io/catalog)]
![UI with different components highlighted](../assets/architecture-overview/core-vs-plugin-components-highlighted.png)
Each plugin typically makes itself available in the UI on a dedicated URL. For
example, the Lighthouse plugin is registered with the UI on `/lighthouse`.
[[live demo](https://backstage-demo.roadie.io/lighthouse)]
[[learn more](https://backstage.io/blog/2020/04/06/lighthouse-plugin)]
![The lighthouse plugin UI](../assets/architecture-overview/lighthouse-plugin.png)
@@ -116,9 +116,9 @@ Architecturally, plugins can take three forms:
#### Standalone plugins
Standalone plugins run entirely in the browser.
[The Tech Radar plugin](https://backstage-demo.roadie.io/tech-radar), for
example, simply renders hard-coded information. It doesn't make any API requests
to other services.
[The Tech Radar plugin](https://demo.backstage.io/tech-radar), for example,
simply renders hard-coded information. It doesn't make any API requests to other
services.
![tech radar plugin ui](../assets/architecture-overview/tech-radar-plugin.png)
@@ -182,6 +182,21 @@ work but
[aren't tested as fully](https://github.com/backstage/backstage/issues/2460)
yet.
## Cache
The Backstage backend and its builtin plugins are also able to leverage cache
stores as a means of improving performance or reliability. Similar to how
databases are supported, plugins receive logically separated cache connections,
which are powered by [Keyv](https://github.com/lukechilds/keyv) under the hood.
At this time of writing, Backstage can be configured to use one of two cache
stores: memory, which is mainly used for local testing, and memcache, which is a
cache store better suited for production deployment. The right cache store for
your Backstage instance will depend on your own run-time constraints and those
required of the plugins you're running.
Contributions supporting other cache stores are welcome!
## Containerization
The example Backstage architecture shown above would Dockerize into three
+20 -37
View File
@@ -108,50 +108,33 @@ Stability: `1`. Mainly intended for internal use.
### `core` [GitHub](https://github.com/backstage/backstage/tree/master/packages/core/)
#### Section: React Components
The `@backstage/core` and `@backstage/core-api` packages are being phased out
and replaced by other `@backstage/core-*` packages. They are still in use but
will not receive any breaking changes.
All of the React components exported from `src/components/` and `src/layout/`
### `core-api` [GitHub](https://github.com/backstage/backstage/tree/master/packages/core-api/)
Stability: See `@backstage/core` above
### `core-app-api` [GitHub](https://github.com/backstage/backstage/tree/master/packages/core-app-api/)
The APIs used exclusively in the app, such as `createApp` and the system icons.
Stability: `2`.
### `core-components` [GitHub](https://github.com/backstage/backstage/tree/master/packages/core-components/)
A collection of React components for use in Backstage plugins and apps.
Previously exported by `@backstage/core`.
Stability: `1`. These components have not received a proper review of the API,
but we also want to ensure stability.
#### Section: Plugin API
### `core-plugin-api` [GitHub](https://github.com/backstage/backstage/tree/master/packages/core-plugin-api/)
The parts of the core API that are used by plugins, and the way plugins expose
functionality to apps and other plugins. Includes for example `createPlugin`,
`createRouteRef`, `createApiRef`.
The core API used to build Backstage plugins and apps.
Stability: `2`. There are planned breaking changes around the way that plugins
expose features and do routing. We still commit to keeping a short deprecation
period so that plugins outside of the main repo have time to migrate.
#### Section: App API
The APIs used exclusively in the app, such as `createApp` and the system icons.
Stability: `2`
#### Section: Utility API Definitions
The type declarations of the core Utility APIs.
Stability: `2`. Changes to the Utility API type declarations need time to
propagate.
#### Section: Utility API Implementations
The interfaces and default implementations for various Utility APIs, such as
ErrorApi, IdentityApi, the auth APIs, etc.
Stability: `1`. Most changes to the core utility APIs will not lead to
widespread breaking changes since most apps rely on the default implementations.
### `core-api` [GitHub](https://github.com/backstage/backstage/tree/master/packages/core-api/)
The non-visual parts of @backstage/core. Everything in this packages is
re-exported from @backstage/core, and this package should not be used directly.
Stability: See @backstage/core
Stability: `2`.
### `cost-insights` [GitHub](https://github.com/backstage/backstage/tree/master/plugins/cost-insights)
+109 -3
View File
@@ -1,7 +1,113 @@
---
id: backend-plugin
title: Backend plugin
description: Documentation on Backend plugin
title: Backend plugins
description: Creating and Developing Backend plugins
---
## TODO
This page describes the process of creating and managing backend plugins in your
Backstage repository.
## Creating a Backend Plugin
A new, bare-bones backend plugin package can be created by issuing the following
command in your Backstage repository root:
```sh
yarn create-plugin --backend
```
Please also see the `--help` flag for the `create-plugin` command for some
further options that are available, notably the `--scope` and `--no-private`
flags that control naming and publishing of the newly created package. Your repo
root `package.json` will probably also have some default values already set up
for these.
You will be asked to supply a name for the plugin. This is an identifier that
will be part of the NPM package name, so make it short and containing only
lowercase characters separated by dashes, for example `carmen`, if it's a
package that adds an integration with a system named Carmen, for example. The
full NPM package name would then be something like
`@internal/plugin-carmen-backend`, depending on the other flags passed to the
`create-plugin` command, and your settings for the `create-plugin` command in
your root `package.json`.
Creating the plugin will take a little while, so be patient. It will helpfully
run the initial installation and build commands, so that your package is ready
to be hacked on! It will be located in a new folder in your `plugins` directory,
in this example `plugins/carmen-backend`.
For simple development purposes, a backend plugin can actually be started in a
standalone mode. You can do a first-light test of your service:
```sh
cd plugins/carmen-backend
yarn start
```
This will think for a bit, and then say `Listening on :7000`. In a different
terminal window, now run
```sh
curl localhost:7000/carmen/health
```
This should return `{"status":"ok"}`. Success! Press `Ctrl + c` to kill it
again.
## Developing your Backend Plugin
A freshly created backend plugin does basically nothing, in terms of the overall
app. It has a small set of basic dependencies and exposes an Express router in
`src/service/router.ts`. This is where you will start adding routes and
connecting those to actual underlying functionality. But nothing in your
Backstage application / backend exposes it.
To actually attach and run the plugin router, you will make some modifications
to your backend.
```sh
# From the Backstage root directory
cd packages/backend
yarn add @internal/plugin-carmen-backend@^0.1.1 # Change this to match the plugin's package.json
```
Create a new file named `packages/backend/src/plugins/carmen.ts`, and add the
following to it
```ts
import { createRouter } from '@internal/plugin-carmen-backend';
import { PluginEnvironment } from '../types';
export default async function createPlugin(env: PluginEnvironment) {
// Here is where you will add all of the required initialization code that
// your backend plugin needs to be able to start!
// The env contains a lot of goodies, but our router currently only
// needs a logger
return await createRouter({
logger: env.logger,
});
}
```
And finally, wire this into the overall backend router. Edit
`packages/backend/src/index.ts`:
```ts
import carmen from './plugins/carmen';
// ...
async function main() {
// ...
const carmenEnv = useHotMemoize(module, () => createEnv('carmen'));
apiRouter.use('/carmen', await carmen(badgesEnv));
```
After you start the backend (e.g. using `yarn start-backend` from the repo
root), you should be able to fetch data from it.
```sh
# Note the extra /api here
curl localhost:7000/api/carmen/health
```
This should return `{"status":"ok"}` like before. Success!
-371
View File
@@ -1,371 +0,0 @@
---
id: quickstart-app-auth
title: Monorepo App Setup With Authentication
---
###### January 8th 2021 - @backstage/create-app - v0.4.5
<br />
> This document takes you through setting up a Backstage app that runs in your
> own environment. It starts with a skeleton install and verifying of the
> monorepo's functionality. Next, authentication is added and tested.
>
> This document assumes you have Node.js 12 or 14 active along with Yarn and
> Python. Please note, that at the time of this writing, the current version is
> v0.4.5. This guide can still be used with future versions, just, verify as you
> go.
# The Skeleton Application
From the terminal:
1. Create a (monorepo) application: `npx @backstage/create-app`
1. Enter an `id` for your new app like `mybiz-backstage` I went with
`simple-backstage-app`
1. Choose `SQLite` as your database. This is the quickest way to get started as
PostgreSQL requires additional setup not covered here.
1. Start your backend: `yarn --cwd packages/backend start`
```zsh
# You should see positive verbiage in your terminal output
2020-09-11T22:20:26.712Z backstage info Listening on :7000
```
5. Finally, start the frontend. Open a new terminal window and from the root of
your project, run: `yarn start`
```zsh
# You should see positive verbiage in your terminal output
「wds」: Project is running at http://localhost:3000/
```
Once the app compiles, a browser window should have popped with your stand-alone
application loaded at `localhost:3000`. This could take a couple minutes.
```zsh
# You should see positive verbiage in your terminal output
ℹℹ 「wdm」: Compiled successfully.
```
Since there is no auth currently configured, you are automatically entered as a
guest. Let's fix that now and add auth.
# The Auth Configuration
A default Backstage installation includes multiple authentication providers out
of the box. The steps to enable new authentication providers in Backstage are
very similar to each other, the biggest difference is usually configuring the
external authentication provider. Please see a subset of possible providers and
instructions to integrate them below. Steps 1 & 2 are described separately for
each provider and steps beyond that are common for all.
<details><summary>GitHub</summary>
<p>
### 1. Open `app-config.yaml` and change it as follows
_from:_
```yaml
auth:
providers: {}
```
_to:_
```yaml
auth:
providers:
github:
development:
clientId: ${AUTH_GITHUB_CLIENT_ID}
clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
## uncomment the following line if using enterprise
# enterpriseInstanceUrl: ${AUTH_GITHUB_ENTERPRISE_INSTANCE_URL}
```
### 2. Generate a GitHub client ID and secret
- Log into http://github.com
- Navigate to (Settings > Developer Settings > OAuth Apps > New OAuth
App)[https://github.com/settings/applications/new]
- Set Homepage URL = `http://localhost:3000`
- Set Callback URL = `http://localhost:7000/api/auth/github`
- Click [Register application]
- On the next page, copy and paste your new Client ID and Client Secret to
environment variables defined in the `app-config.yaml` file,
`AUTH_GITHUB_CLIENT_ID` & `AUTH_GITHUB_CLIENT_SECRET`
</p>
</details>
<details><summary>GitLab</summary>
<p>
### 1. Open `app-config.yaml` and change it as follows
_from:_
```yaml
auth:
providers: {}
```
_to:_
```yaml
auth:
providers:
gitlab:
development:
clientId: ${AUTH_GITLAB_CLIENT_ID}
clientSecret: ${AUTH_GITLAB_CLIENT_SECRET}
audience: https://gitlab.com # Or your self-hosted GitLab instance URL
```
### 2. Generate a GitLab Application client ID and secret
- Log into GitLab
- Navigate to (Profile > Settings >
Applications)[https://gitlab.com/-/profile/applications]
- Name your application
- Set Callback URL = `http://localhost:7000/api/auth/gitlab/handler/frame`
- Select the following values:
- `read_user` (Read the authenticated user's personal information)
- `read_repository` (Allows read-only access to the repository)
- `write_repository` (Allows read-write access to the repository)
- `openid` (Authenticate using OpenID Connect)
- `profile` (Allows read-only access to the user's personal information using
OpenID Connect)
- `email` (Allows read-only access to the user's primary email address using
OpenID Connect)
- Click [Save application]
- On the next page, copy and paste your new Application ID and Secret to
environment variables defined in the `app-config.yaml` file,
`AUTH_GITLAB_CLIENT_ID` & `AUTH_GITLAB_CLIENT_SECRET`
</p>
</details>
<details><summary>Google</summary>
<p>
### 1. Open `app-config.yaml` and change it as follows
_from:_
```yaml
auth:
providers: {}
```
_to:_
```yaml
auth:
providers:
google:
development:
clientId: ${AUTH_GOOGLE_CLIENT_ID}
clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET}
```
### 2. Generate Google Credentials in Google Cloud console
- Log into https://console.cloud.google.com
- Select or create a new project from the dropdown on the top bar
- Navigate to (APIs & Services >
Credentials)[https://console.cloud.google.com/apis/credentials]
- Click Create Credentials and select [OAuth client ID]
- Select Web Application as the application type
- Add new Authorised JavaScript origin = `http://localhost:3000`
- Add new Authorised redirect URI =
`http://localhost:7000/api/auth/google/handler/frame`
- Click [Save application]
- Google should display a modal with your Client ID and Secret. Copy and paste
those to environment variables defined in the `app-config.yaml` file,
`AUTH_GOOGLE_CLIENT_ID` & `AUTH_GOOGLE_CLIENT_SECRET`
</p>
</details>
<details><summary>Microsoft</summary>
<p>
### 1. Open `app-config.yaml` and change it as follows
_from:_
```yaml
auth:
providers: {}
```
_to:_
```yaml
auth:
providers:
microsoft:
development:
clientId: ${AUTH_MICROSOFT_CLIENT_ID}
clientSecret: ${AUTH_MICROSOFT_CLIENT_SECRET}
tenantId: ${AUTH_MICROSOFT_TENANT_ID}
```
### 2. Create a Microsoft App Registration in Microsoft Portal
- Log into https://portal.azure.com
- Navigate to (Azure Active Directory > App
Registrations)[https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps]
- Create a New Registration
- Add new Redirect URI = `http://localhost:3000`
- Add new Authorised redirect URI =
`http://localhost:7000/api/auth/microsoft/handler/frame`
- Click [Save application]
- Set environment variable `AUTH_MICROSOFT_CLIENT_ID` from
`Application (client) Id` displayed on the directory page
- Set environment variable `AUTH_MICROSOFT_TENANT_ID` from
`Directory (tenant) ID` displayed on the directory page
- Navigate to Certificates & Secrets section and click [Create a new secret]
- Set environment variable `AUTH_MICROSOFT_CLIENT_SECRET` from the `value` field
created.
</p>
</details>
<details><summary>Auth0</summary>
<p>
### 1. Open `app-config.yaml` and change it as follows
_from:_
```yaml
auth:
providers: {}
```
_to:_
```yaml
auth:
providers:
auth0:
development:
clientId: ${AUTH_AUTH0_CLIENT_ID}
clientSecret: ${AUTH_AUTH0_CLIENT_SECRET}
domain: ${AUTH_AUTH0_DOMAIN_ID}
```
### 2. Create an Auth0 application in the Auth0 management console
- Log into https://manage.auth0.com/dashboard/
- Navigate to Applications
- Create a New Application
- Select Single Page Web Application
- Go to Settings tab
- Add new line to Allowed Callback URLs =
`http://localhost:7000/api/auth/auth0/handler/frame`
- Click [Save Changes]
- Set environment variables displayed on the Basic Information page
- `AUTH_AUTH0_CLIENT_ID` from `Client ID` displayed on Auth0 application page
- `AUTH_AUTH0_CLIENT_SECRET` from `Client Secret` displayed on Auth0
application page
- `AUTH_AUTH0_DOMAIN_ID` from `Domain` displayed on Auth0 application page
</p>
</details>
### 3. Set environment variables in whatever fashion is easiest for you. I chose to
add mine to my `.zshrc` profile.
```zsh
# For macOS Catalina & Z Shell
# ------ simple-backstage-app GitHub
#
# (Change the name of the environment variables based on your auth setup above)
export AUTH_GITHUB_CLIENT_ID=xxx
export AUTH_GITHUB_CLIENT_SECRET=xxx
# export AUTH_GITHUB_ENTERPRISE_INSTANCE_URL=https://github.{MY_BIZ}.com
```
### 4. And of course I need to source that file.
```zsh
# Loading the new variables
% source ~/.zshrc
# Any other currently opened terminals need to be restarted to pick up the new values
# verify your setup by running env
% env
# should output something like
> ...
> AUTH_GITHUB_CLIENT_ID=xxx
> AUTH_GITHUB_CLIENT_SECRET=xxx
> ...
```
### 5. Open and change _root > packages > app > src >_ `App.tsx` to use correct
authentication provider reference
```tsx
import { githubAuthApiRef, SignInPage } from '@backstage/core';
```
Modify the imported reference based on the authentication method you selected
above:
| Auth Provider | Import Name |
| ------------- | ------------------- |
| GitHub | githubAuthApiRef |
| GitLab | gitlabAuthApiRef |
| Google | googleAuthApiRef |
| Microsoft | microsoftAuthApiRef |
| Auth0 | auth0AuthApiRef |
### 6. In the same file, modify createApp
Remember to modify the provider information based on the table above.
```tsx
const app = createApp({
apis,
plugins: Object.values(plugins),
components: {
SignInPage: props => (
<SignInPage
{...props}
auto
provider={{
id: 'github-auth-provider',
title: 'GitHub',
message: 'Simple Backstage Application Login',
apiRef: githubAuthApiRef,
}}
/>
),
},
});
```
After finishing setting up one (or multiple) authentication providers defined
above you can start the backend and frontend as before
When the browser loads, you should be presented with a login page for GitHub.
Login as usual with your GitHub account. If this is your first time, you will be
asked to authorize and then are redirected to the catalog page if all is well.
For more information you can clone
[the backstage-auth-example repository](https://github.com/RoadieHQ/backstage-auth-example).
Each authentication setting is set up there on a branch named after the
authentication provider.
# Where to go from here
> You're probably eager to write your first custom plugin. Follow this next
> tutorial for an in-depth look at a custom GitHub repository browser plugin.
> [Adding Custom Plugin to Existing Monorepo App](quickstart-app-plugin.md).
+2 -2
View File
@@ -35,8 +35,8 @@ title: Adding Custom Plugin to Existing Monorepo App
1. When the process finishes, let's start the backend:
`yarn --cwd packages/backend start`
1. If you see errors starting, refer to
[Auth Configuration](https://backstage.io/docs/tutorials/quickstart-app-auth#the-auth-configuration)
for more information on environment variables.
[Auth Configuration](https://backstage.io/docs/auth/) for more information on
environment variables.
1. And now the frontend, from a new terminal window and the root of your
project: `yarn start`
1. As usual, a browser window should popup loading the App.
+2
View File
@@ -0,0 +1,2 @@
registry=https://registry.npmjs.org/
engine-strict=true
@@ -0,0 +1,135 @@
---
title: Where do you start when adopting Backstage?
author: Austin Lamon, Spotify
authorURL: https://www.linkedin.com/in/austinlamon
---
![Create, Manage, Explore](assets/21-05-20/create-manage-explore.gif)
One of the greatest strengths of Backstage also presents a never-ending challenge: Backstage is highly customizable and allows you to easily build a unique developer portal suited to your organizations needs. The downside of this flexibility is that it can be hard to know where to start. Backstage can do so many things — integrating every part of your tech infrastructure and developer experience — but if you set off building a developer portal without a plan, its easy to get overwhelmed by all the possibilities. To help you form your plan, this post will detail how Spotify came to design our internal portal and recommend potential models for you to use when designing and building your own.
<!--truncate-->
## Infrastructure as tech culture
Before providing recommendations on getting started with Backstage, its helpful to have a bit of context as to why Spotify made the design decisions we did. No two companies are identical — and thus, no two Backstage implementations are the same.
Rolling back the clock just a few years, [Spotify was challenged](https://engineering.atspotify.com/2021/05/18/a-product-story-the-lessons-of-backstage-and-spotifys-autonomous-culture/) to continue to scale our engineering team (and the number of features and components built) but retain the speed of product development. Some user research with Spotify developers highlighted a clear problem: there was simply too much non-documented institutional knowledge needed to get things done. No one could find anything and everyone was interrupting everyone else trying to figure things out.
Spotifys developers were facing three big challenges on a daily basis:
- They not only needed to build software quickly, they also needed to pass along knowledge to new joiners about how best to create new components.
- They needed to somehow maintain a mental model of the systems their squad owned. (Or, if they were lucky, they found a hopefully-up-to-date spreadsheet tracking this information.)
- They needed to keep an eye on what squads around them might be building to ensure they could reuse systems when they needed to solve similar problems in the future.
In short, Spotify developers needed to continue building industry leading features at breakneck speed, while simultaneously maintaining a mental model for all the software at Spotify (oh, and help every new joiner develop that mental model as well!).
<br>
## Three jobs: Create, manage, explore
Around the same time, the [jobs to be done](https://hbr.org/2016/09/know-your-customers-jobs-to-be-done) framework was becoming popular and luckily, a few Spotifiers helped guide the vision for a _sense-making tool for developers_ toward using it. After user research and many failed attempts, we landed on three jobs Spotify developers needed to do consistently:
<br>
- **Create**: Spotify developers want to delight their customers with incredible features. They create new software to do that.
- **Manage**: Spotify developers are proud of their work and treat their software and data like products. That requires maintaining all the software they own on an ongoing basis.
- **Explore**: Spotify developers want to solve new, yet unsolved problems. They try to build on existing systems to help them do that.
So: make software, maintain the software you own throughout its lifecycle, and integrate with other peoples software.
Within todays complex development environments, there are barriers both big and small that get in the way of those three jobs. Backstage provides the building blocks for removing those barriers, streamlining your development cycle, and letting developers do what they really want to do: build great features. Lets take a closer look at each of these jobs.
![Backstage Software Templates rocket](assets/21-05-20/create.gif)
### Create
**Job:** Youre an engineer, ready to start building a new microservice. Do you just pick whatever framework you want? How do you reserve capacity to run your service in production? What about managing CI/CD?
**Tool:** At Spotify, we use **Backstage Software Templates** to simplify all of this, reducing timetoHello World to just a few clicks. Instead of researching Spring Boot versus Helidon, opening a Jira ticket, rummaging through docs, and configuring CI automations, you just choose a template and your project is automatically set up in the repo for you, with the CI already running your first build.
**Result:** By making it easier to start new projects, your engineers get to the good part of coding features faster. And your organizations best practices are built into the templates, encouraging standards and reducing complexity in your tech ecosystem.
![Backstage Service Catalog system](assets/21-05-20/manage.gif)
### Manage
**Job:** Youre on a small team that owns a dozen services. Whenever you update and deploy those services, youre switching between your CI, the AWS console, a security dashboard, and a CLI so you can try to figure out which Kubernetes cluster your service ended up on. In other words, you have a lot of open windows and tabs, and each step means switching to a new interface.
**Tool:** All of your teams software components are organized together on one page in the **Backstage Service Catalog**. Go to any services page from there and its CI/CD status, [Kubernetes deployment status](https://backstage.io/blog/2021/01/12/new-backstage-feature-kubernetes-for-service-owners), documentation, security checks — and everything else related to that service — is grouped together in one seamless interface that shows you only the info you want.
**Result**: One page in Backstage has everything you need to manage the software you own. No more context-switching. No more digging through your cloud providers obscure admin features. Outside the repo and your IDE, everything you need to manage your service is right inside Backstage.
![Backstage explorer](assets/21-05-20/explore.gif)
### Explore
**Job:** You're building a new mobile feature that needs to ensure a user is paying for the premium version of your product — but someone mustve already built a library that handles that, right? A company-wide email and a few calls for help on Slack yield no response, so you resign yourself to building the capability yourself. Turns out someone did build the library you needed. They were just on vacation so they didnt see your messages. How do you enable better discovery and collaboration across your org?
**Tools:** At Spotify, anyone can find everyone elses software — because everything is centralized inside Backstage, organized by the **Backstage Service Catalog** and accessible by **search**. Go to any library or services page, and youll find the owners and documentation, even its API and how to extend it if need be.
**Result:** One place for everything, one place to search. Developers can more easily share components, build on top of each others work, and discover tools, libraries, frameworks, documentation, system designs, org charts, and more.
## Sounds great. Where do I start?
After talking with companies who have already adopted Backstage, weve seen a few common strategies for getting started. The different strategies are based on the size of your engineering org (which often also corresponds with how fast youre growing).
![200 engineers](assets/21-05-20/200-engineers_v.2.png)
<br>
### My org has ~200 engineers (and is growing fast)
Youre big enough to start feeling the pain, and only getting bigger. Onboarding and discoverability are your biggest challenges.
**Pain points:**
- This size seems to be the tipping point — where complexity is taking hold, collaboration starts breaking down, and ad hoc solutions stop working.
- Often this is also when youre growing so fast (doubling in size every 612 months) that there are now more new engineers than old engineers.
- New engineers cant find anything, so they ask around, which pulls all your other engineers off-task with interruptions.
- Logjams form. One company told us how it was taking 34 days for pull requests to get merged.
**Recommendation — Explore, then create:**
- New engineers need an easy way to find out how to do things, so youre not just adding bodies, youre adding happy, productive contributors.
- To streamline onboarding, start with centralizing your documentation and making your tools and software components discoverable in Backstage.
- At this size, you might not have a dedicated platform/infra team in place yet, but Backstage can provide the framework for centralizing and sharing knowledge — from managing compliance requirements to finding the right API documentation.
- This allows both new and old engineers to collaborate more efficiently, easily discover best practices, and cuts down on duplicated work (e.g., a new team doesnt end up rebuilding a database that already exists but nobody can find).
![1,000 engineers](assets/21-05-20/1000-engineers_v.2.png)
### My org has ~1,000 engineers
Youre officially big. Lots and lots of teams are managing lots and lots of software — and the frustration of switching between all the various tools to do that is growing exponentially.
**Pain points:**
- Fragmentation and entropy are real threats to productivity. From security requirements to cluster management to a thousand data endpoints, theres too much to keep track of, leading to cognitive overload.
- A death by a thousand cuts: constantly logging into new interfaces — from your cloud providers console to some brand new security tool then back to your CI/CD — is bogging your engineers down with too much context-switching and a lot of noise.
- Every day, its getting more and more difficult for one team to manage their own microservices, data, and documentation, let alone share their knowledge with other teams.
**Recommendation — Manage, then explore, then create:**
- Backstage will allow your teams to get a handle on the software they own, since everything they need to manage it is in one place.
- From CI/CD status to documentation to deciphering a monorepo, Backstage makes it easy to manage a service (or other software component) on a day-to-day basis.
- The service catalog also helps your developers visualize your existing software ecosystem, beyond the software they own. And with Backstage Software Templates, every new software component is already added to the catalog.
- Even at this scale, a small platform team should be all it takes to build and maintain your own version of Backstage. At Spotify, we have a 4-person team responsible for our internal version of Backstage, which is used by all of Spotifys 1,600+ developers.
![More than 1,000 engineers](assets/21-05-20/1000-plus-engineers_v.2.png)
### My org has 1,000+ engineers
Integrating infrastructure of this size and complexity can seem overwhelming. Its an even bigger challenge to bring this level of change to a well-established culture with ingrained processes.
**Pain points:**
- When youre this large, youve incorporated a lot of technology and processes, as well as a lot of partners, each with their own technologies and processes.
- Youre focussed on “replacing cruft” and bringing discoverability and order to your vast ecosystem of components and tools.
- Getting your tools adopted by your engineers while modernizing your tech stack and coordinating with your infra teams to improve your engineering practices across the whole company… its a lot.
**Recommendation — Create, then manage, then explore:**
- The fastest way to bring change to your ecosystem is to start at the beginning of the chain with Backstage Software Templates.
- With every new component created with your templates, youre establishing best practices and rewarding your developers with a streamlined experience focused on their needs — all the while building up your new service catalog.
- The more the templates ease the process of starting up a project, the more your engineers will adopt them, and the faster the other benefits of Backstage will build up, transforming productivity across your organization. ([Thats how we did it at Spotify](https://open.spotify.com/episode/7iuQ3ew1Wwpuiq6LbBKzCl).)
## More questions about adopting Backstage?
[Contact the Backstage team at Spotify.](https://calendly.com/spotify-backstage) Well share more about what weve learned from our experience here at Spotify — and from other companies who are already using Backstage to transform their developer experience.
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

+1 -1
View File
@@ -85,7 +85,7 @@ class Footer extends React.Component {
</div>
</section>
<p style={{ textAlign: 'center' }}>
<a href="https://spotify.github.io">Made with &nbsp; at Spotify</a>
<a href="https://spotify.github.io">Made with &nbsp;at Spotify</a>
</p>
<p className="copyright">{this.props.config.copyright}</p>
</footer>
+13
View File
@@ -0,0 +1,13 @@
---
title: Cortex Service Quality Scorecards
author: Cortex
authorUrl: https://www.getcortexapp.com
category: Monitoring
description: Grade the quality of your Backstage services using Scorecards. Automate production readiness, migrations, security audits, and more with CQL (Cortex Query Language).
documentation: https://github.com/cortexapps/backstage-plugin
iconUrl: img/cortex.png
npmPackageName: '@cortexapps/backstage-plugin'
tags:
- web
- monitoring
- sre
+4 -2
View File
@@ -12,13 +12,15 @@
"write-translations": "docusaurus-write-translations",
"version": "docusaurus-version",
"rename-version": "docusaurus-rename-version",
"verify:sidebars": "node ./scripts/verify-sidebars"
"verify:sidebars": "node ./scripts/verify-sidebars",
"lock:check": "yarn-lock-check"
},
"devDependencies": {
"@spotify/prettier-config": "^10.0.0",
"docusaurus": "^2.0.0-alpha.70",
"js-yaml": "^4.1.0",
"prettier": "^2.3.0"
"prettier": "^2.3.1",
"yarn-lock-check": "^1.0.4"
},
"prettier": "@spotify/prettier-config"
}
+19 -7
View File
@@ -18,12 +18,6 @@ const Background = props => {
<Block.Container style={{ justifyContent: 'flex-start' }}>
<Block.TextBox>
<Block.Title>See us in action</Block.Title>
<Block.Paragraph>
To explore the UI and basic features of Backstage firsthand, go
to: <a href="https://demo.backstage.io">demo.backstage.io</a>.
(Tip: click All to view all the example components in the
service catalog.)
</Block.Paragraph>
<Block.Paragraph>
Watch the videos below to get an introduction to Backstage and to
see how we use different plugins to customize{' '}
@@ -32,13 +26,31 @@ const Background = props => {
</a>
.
</Block.Paragraph>
<Block.Paragraph>
To see how other companies have already started using Backstage,
watch these presentations from{' '}
<a href="https://youtu.be/rRphwXeq33Q?t=1508">Expedia</a>,{' '}
<a href="https://youtu.be/6sg5uMCLxTA?t=153">Zalando</a>, and{' '}
<a href="https://youtu.be/UZTVjv-AvZA?t=188">TELUS</a>. For more,
join our{' '}
<a href="https://github.com/backstage/community">
Community Sessions
</a>
.
</Block.Paragraph>
<Block.Paragraph>
To explore the UI and basic features of Backstage firsthand, go
to: <a href="https://demo.backstage.io">demo.backstage.io</a>.
(Tip: click All to view all the example components in the
service catalog.)
</Block.Paragraph>
</Block.TextBox>
<Block.Graphics>
<Block.Graphic
x={-7}
y={-12}
width={120}
src={`${baseUrl}img/demo-illustration.svg`}
src={`${baseUrl}img/demo-screen.png`}
/>
</Block.Graphics>
</Block.Container>
+3 -2
View File
@@ -43,6 +43,7 @@
"features/software-catalog/well-known-statuses",
"features/software-catalog/extending-the-model",
"features/software-catalog/external-integrations",
"features/software-catalog/catalog-customization",
"features/software-catalog/software-catalog-api"
]
},
@@ -66,7 +67,8 @@
"features/software-templates/writing-templates",
"features/software-templates/builtin-actions",
"features/software-templates/writing-custom-actions",
"features/software-templates/template-legacy"
"features/software-templates/template-legacy",
"features/software-templates/migrating-from-v1alpha1-to-v1beta2"
]
},
{
@@ -238,7 +240,6 @@
],
"Tutorials": [
"tutorials/journey",
"tutorials/quickstart-app-auth",
"tutorials/quickstart-app-plugin",
"tutorials/switching-sqlite-postgres"
],
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

+167 -37
View File
@@ -9,6 +9,13 @@
dependencies:
"@babel/highlight" "^7.0.0"
"@babel/code-frame@^7.0.0":
version "7.12.13"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==
dependencies:
"@babel/highlight" "^7.12.13"
"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.11":
version "7.12.11"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
@@ -220,6 +227,11 @@
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
"@babel/helper-validator-identifier@^7.14.0":
version "7.14.0"
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288"
integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==
"@babel/helper-validator-option@^7.12.1", "@babel/helper-validator-option@^7.12.11":
version "7.12.11"
resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz#d66cb8b7a3e7fe4c6962b32020a131ecf0847f4f"
@@ -253,6 +265,15 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/highlight@^7.12.13":
version "7.14.0"
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf"
integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==
dependencies:
"@babel/helper-validator-identifier" "^7.14.0"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7":
version "7.12.11"
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79"
@@ -911,7 +932,7 @@
"@spotify/prettier-config@^10.0.0":
version "10.0.0"
resolved "https://registry.yarnpkg.com/@spotify/prettier-config/-/prettier-config-10.0.0.tgz#fa076d98d2e7e6c53dd3d86a696307a7010bd056"
resolved "https://registry.npmjs.org/@spotify/prettier-config/-/prettier-config-10.0.0.tgz#fa076d98d2e7e6c53dd3d86a696307a7010bd056"
integrity sha512-VYOdo8P7lIScAkl02nB9KpUAuOYMManryBIBuKJkAw5D3aVtLobfmdIKvdV6MqEmGMEQPbn7w/UpnjJYhUH+IA==
"@types/cheerio@^0.22.8":
@@ -921,16 +942,39 @@
dependencies:
"@types/node" "*"
"@types/glob@^7.1.3":
version "7.1.3"
resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==
dependencies:
"@types/minimatch" "*"
"@types/node" "*"
"@types/minimatch@*":
version "3.0.4"
resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
"@types/node@*":
version "14.14.20"
resolved "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz#f7974863edd21d1f8a494a73e8e2b3658615c340"
integrity sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==
"@types/node@^15.6.1":
version "15.9.0"
resolved "https://registry.npmjs.org/@types/node/-/node-15.9.0.tgz#0b7f6c33ca5618fe329a9d832b478b4964d325a8"
integrity sha512-AR1Vq1Ei1GaA5FjKL5PBqblTZsL5M+monvGSZwe6sSIdGiuu7Xr/pNwWJY+0ZQuN8AapD/XMB5IzBAyYRFbocA==
"@types/q@^1.5.1":
version "1.5.4"
resolved "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@yarnpkg/lockfile@^1.1.0":
version "1.1.0"
resolved "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
@@ -1039,7 +1083,7 @@ argparse@^1.0.10, argparse@^1.0.7:
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
arr-diff@^4.0.0:
@@ -1359,15 +1403,15 @@ browserslist@4.7.0:
node-releases "^1.1.29"
browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.0:
version "4.16.0"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz#410277627500be3cb28a1bfe037586fbedf9488b"
integrity sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==
version "4.16.6"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==
dependencies:
caniuse-lite "^1.0.30001165"
colorette "^1.2.1"
electron-to-chromium "^1.3.621"
caniuse-lite "^1.0.30001219"
colorette "^1.2.2"
electron-to-chromium "^1.3.723"
escalade "^3.1.1"
node-releases "^1.1.67"
node-releases "^1.1.71"
buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
@@ -1405,6 +1449,11 @@ buffer@^5.2.1:
base64-js "^1.3.1"
ieee754 "^1.1.13"
builtin-modules@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
bytes@1:
version "1.0.0"
resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8"
@@ -1498,10 +1547,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001165:
version "1.0.30001173"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001173.tgz#3c47bbe3cd6d7a9eda7f50ac016d158005569f56"
integrity sha512-R3aqmjrICdGCTAnSXtNyvWYMK3YtV5jwudbq0T7nN9k4kmE4CBuwPqyJ+KBzepSTh0huivV2gLbSMEzTTmfeYw==
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001219:
version "1.0.30001235"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001235.tgz#ad5ca75bc5a1f7b12df79ad806d715a43a5ac4ed"
integrity sha512-zWEwIVqnzPkSAXOUlQnPW2oKoYb2aLQ4Q5ejdjBcnH63rfypaW34CxaeBn1VMya2XaEU3P/R2qHpWyj+l0BT1A==
caseless@~0.12.0:
version "0.12.0"
@@ -1518,7 +1567,7 @@ caw@^2.0.0, caw@^2.0.1:
tunnel-agent "^0.6.0"
url-to-options "^1.0.1"
chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
chalk@2.4.2, chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -1697,10 +1746,10 @@ color@^3.0.0:
color-convert "^1.9.1"
color-string "^1.5.4"
colorette@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
colorette@^1.2.1, colorette@^1.2.2:
version "1.2.2"
resolved "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
@@ -1709,7 +1758,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
commander@^2.8.1:
commander@^2.12.1, commander@^2.8.1:
version "2.20.3"
resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -2181,6 +2230,11 @@ diacritics-map@^0.1.0:
resolved "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz#6dfc0ff9d01000a2edf2865371cac316e94977af"
integrity sha1-bfwP+dAQAKLt8oZTccrDFulJd68=
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
dir-glob@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
@@ -2355,10 +2409,10 @@ ee-first@1.1.1:
resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.621:
version "1.3.634"
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.634.tgz#82ea400f520f739c4f6ff00c1f7524827a917d25"
integrity sha512-QPrWNYeE/A0xRvl/QP3E0nkaEvYUvH3gM04ZWYtIa6QlSpEetRlRI1xvQ7hiMIySHHEV+mwDSX8Kj4YZY6ZQAw==
electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.723:
version "1.3.749"
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz#0ecebc529ceb49dd2a7c838ae425236644c3439a"
integrity sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A==
"emoji-regex@>=6.0.0 <=6.1.1":
version "6.1.1"
@@ -3049,6 +3103,18 @@ glob@^7.0.0, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.1, glob@^7.1.7:
version "7.1.7"
resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
global-modules@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
@@ -3460,6 +3526,11 @@ ini@^1.3.4, ini@^1.3.5:
resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
ini@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5"
integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
inquirer@6.5.0:
version "6.5.0"
resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42"
@@ -3567,6 +3638,13 @@ is-core-module@^2.1.0:
dependencies:
has "^1.0.3"
is-core-module@^2.2.0:
version "2.4.0"
resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==
dependencies:
has "^1.0.3"
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@@ -3864,7 +3942,7 @@ js-yaml@^3.13.1, js-yaml@^3.8.1:
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
@@ -4142,9 +4220,9 @@ lodash.uniq@^4.5.0:
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@~4.17.10:
version "4.17.20"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
logalot@^2.0.0:
version "2.1.0"
@@ -4379,7 +4457,7 @@ mixin-deep@^1.1.3, mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1:
mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1:
version "0.5.5"
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
@@ -4448,10 +4526,10 @@ node-modules-regexp@^1.0.0:
resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40"
integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=
node-releases@^1.1.29, node-releases@^1.1.67:
version "1.1.69"
resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.69.tgz#3149dbde53b781610cd8b486d62d86e26c3725f6"
integrity sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA==
node-releases@^1.1.29, node-releases@^1.1.71:
version "1.1.72"
resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe"
integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
version "2.5.0"
@@ -5197,10 +5275,10 @@ prepend-http@^2.0.0:
resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
prettier@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==
prettier@^2.3.1:
version "2.3.1"
resolved "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6"
integrity sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==
prismjs@^1.22.0:
version "1.23.0"
@@ -5603,6 +5681,14 @@ resolve@^1.1.6, resolve@^1.10.0:
is-core-module "^2.1.0"
path-parse "^1.0.6"
resolve@^1.3.2:
version "1.20.0"
resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
is-core-module "^2.2.0"
path-parse "^1.0.6"
responselike@1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
@@ -6351,11 +6437,37 @@ truncate-html@^1.0.3:
"@types/cheerio" "^0.22.8"
cheerio "0.22.0"
tslib@^1.9.0, tslib@^1.9.3:
tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.14.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslint@^6.1.3:
version "6.1.3"
resolved "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904"
integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==
dependencies:
"@babel/code-frame" "^7.0.0"
builtin-modules "^1.1.1"
chalk "^2.3.0"
commander "^2.12.1"
diff "^4.0.1"
glob "^7.1.1"
js-yaml "^3.13.1"
minimatch "^3.0.4"
mkdirp "^0.5.3"
resolve "^1.3.2"
semver "^5.3.0"
tslib "^1.13.0"
tsutils "^2.29.0"
tsutils@^2.29.0:
version "2.29.0"
resolved "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
dependencies:
tslib "^1.8.1"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
@@ -6381,6 +6493,11 @@ typedarray@^0.0.6:
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^4.3.2:
version "4.3.2"
resolved "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
unbzip2-stream@^1.0.9:
version "1.4.3"
resolved "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7"
@@ -6650,6 +6767,19 @@ yargs@^2.3.0:
dependencies:
wordwrap "0.0.2"
yarn-lock-check@^1.0.4:
version "1.0.4"
resolved "https://registry.npmjs.org/yarn-lock-check/-/yarn-lock-check-1.0.4.tgz#a0373de051be0c8442d8933070df7a45595263b4"
integrity sha512-Gj0wRN85c4OPZUlE7WsQ0a1COv38uyeWWR0YAvJr2Vxw1f32bwK19xySjUZlxt9o4QopJkd8g6x6CLv81OHwYg==
dependencies:
"@types/glob" "^7.1.3"
"@types/node" "^15.6.1"
"@yarnpkg/lockfile" "^1.1.0"
glob "^7.1.7"
ini "^2.0.0"
tslint "^6.1.3"
typescript "^4.3.2"
yauzl@^2.4.2:
version "2.10.0"
resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
+3 -1
View File
@@ -40,6 +40,7 @@ nav:
- Well-known Statuses: 'features/software-catalog/well-known-statuses.md'
- Extending the model: 'features/software-catalog/extending-the-model.md'
- External integrations: 'features/software-catalog/external-integrations.md'
- Catalog Customization: 'features/software-catalog/catalog-customization.md'
- API: 'features/software-catalog/api.md'
- Kubernetes:
- Overview: 'features/kubernetes/index.md'
@@ -54,6 +55,8 @@ nav:
- Builtin Actions: 'features/software-templates/builtin-actions.md'
- Writing Custom Actions: 'features/software-templates/writing-custom-actions.md'
- Writing Templates (Legacy): 'features/software-templates/legacy.md'
- Migrating from v1alpha1 to v1beta2 templates: 'features/software-templates/migrating-from-v1alpha1-to-v1beta2.md'
- Backstage Search:
- Overview: 'features/search/README.md'
- Search Architecture: 'features/search/architecture.md'
@@ -152,7 +155,6 @@ nav:
- Backend: 'api/backend.md'
- Tutorials:
- Future developer journey: 'tutorials/journey.md'
- Monorepo App Setup With Authentication: 'tutorials/quickstart-app-auth.md'
- Adding Custom Plugin to Existing Monorepo App: 'tutorials/quickstart-app-plugin.md'
- Switching Backstage from SQLite to PostgreSQL: 'tutorials/switching-sqlite-postgres.md'
- Architecture Decision Records (ADRs):
+7 -5
View File
@@ -31,7 +31,8 @@
"lerna": "lerna",
"storybook": "yarn workspace storybook start",
"build-storybook": "yarn workspace storybook build-storybook",
"prepare": "husky install"
"prepare": "husky install",
"lock:check": "yarn-lock-check"
},
"workspaces": {
"packages": [
@@ -49,24 +50,25 @@
},
"version": "1.0.0",
"dependencies": {
"@microsoft/api-extractor": "7.13.2-pr1916.0",
"@microsoft/api-documenter": "^7.12.16",
"@microsoft/api-extractor": "7.13.2-pr1916.0",
"@microsoft/api-extractor-model": "^7.12.5"
},
"devDependencies": {
"@changesets/cli": "^2.14.0",
"@octokit/openapi-types": "^2.2.0",
"@spotify/eslint-config-oss": "^1.0.1",
"@spotify/prettier-config": "^9.0.0",
"@spotify/prettier-config": "^10.0.0",
"command-exists": "^1.2.9",
"concurrently": "^6.0.0",
"eslint-plugin-notice": "^0.9.10",
"fs-extra": "^9.0.0",
"husky": "^6.0.0",
"lerna": "^4.0.0",
"lint-staged": "^10.1.0",
"prettier": "^2.2.1",
"recursive-readdir": "^2.2.2",
"shx": "^0.3.2"
"shx": "^0.3.2",
"yarn-lock-check": "^1.0.4"
},
"prettier": "@spotify/prettier-config",
"lint-staged": {
+106
View File
@@ -1,5 +1,111 @@
# example-app
## 0.2.31
### Patch Changes
- Updated dependencies [497f4ce18]
- Updated dependencies [ee4eb5b40]
- Updated dependencies [84160313e]
- Updated dependencies [3772de8ba]
- Updated dependencies [7e7c71417]
- Updated dependencies [f430b6c6f]
- Updated dependencies [2a942cc9e]
- Updated dependencies [e7c5e4b30]
- Updated dependencies [ebe802bc4]
- Updated dependencies [1cf1d351f]
- Updated dependencies [90a505a77]
- Updated dependencies [76f99a1a0]
- Updated dependencies [deaba2e13]
- Updated dependencies [1157fa307]
- Updated dependencies [8e919a6f8]
- Updated dependencies [2305ab8fc]
- Updated dependencies [054bcd029]
- Updated dependencies [aad98c544]
- Updated dependencies [f46a9e82d]
- @backstage/plugin-scaffolder@0.9.7
- @backstage/cli@0.6.14
- @backstage/plugin-catalog@0.6.1
- @backstage/theme@0.2.8
- @backstage/catalog-model@0.8.1
- @backstage/core@0.7.12
- @backstage/plugin-tech-radar@0.4.0
- @backstage/plugin-catalog-react@0.2.1
- @backstage/plugin-techdocs@0.9.5
## 0.2.30
### Patch Changes
- Updated dependencies [41c3ec421]
- Updated dependencies [add62a455]
- Updated dependencies [cc592248b]
- Updated dependencies [17c497b81]
- Updated dependencies [1cd0cacd9]
- Updated dependencies [4ea9df9d3]
- Updated dependencies [7a7da5146]
- Updated dependencies [5baf2ff0f]
- Updated dependencies [bf805b467]
- Updated dependencies [203ce6f6f]
- Updated dependencies [7ab5bfe68]
- Updated dependencies [704875e26]
- Updated dependencies [3a181cff1]
- @backstage/plugin-cost-insights@0.10.1
- @backstage/catalog-model@0.8.0
- @backstage/core@0.7.11
- @backstage/plugin-catalog@0.6.0
- @backstage/plugin-catalog-react@0.2.0
- @backstage/cli@0.6.13
- @backstage/plugin-techdocs@0.9.4
- @backstage/plugin-jenkins@0.4.4
- @backstage/plugin-api-docs@0.4.15
- @backstage/plugin-badges@0.2.2
- @backstage/plugin-catalog-import@0.5.8
- @backstage/plugin-circleci@0.2.15
- @backstage/plugin-cloudbuild@0.2.16
- @backstage/plugin-code-coverage@0.1.4
- @backstage/plugin-explore@0.3.6
- @backstage/plugin-github-actions@0.4.8
- @backstage/plugin-kafka@0.2.8
- @backstage/plugin-kubernetes@0.4.5
- @backstage/plugin-lighthouse@0.2.17
- @backstage/plugin-org@0.3.14
- @backstage/plugin-pagerduty@0.3.5
- @backstage/plugin-rollbar@0.3.6
- @backstage/plugin-scaffolder@0.9.6
- @backstage/plugin-search@0.3.7
- @backstage/plugin-sentry@0.3.11
- @backstage/plugin-todo@0.1.2
## 0.2.29
### Patch Changes
- Updated dependencies [7cbfcae48]
- Updated dependencies [2bfec55a6]
- Updated dependencies [f7f7783a3]
- Updated dependencies [65e6c4541]
- Updated dependencies [68fdbf014]
- Updated dependencies [5da6a561d]
- Updated dependencies [ca6e0ab69]
- Updated dependencies [5914a76d5]
- Updated dependencies [81d7b9c6f]
- Updated dependencies [a62cfe068]
- Updated dependencies [35e091604]
- Updated dependencies [a53f3d603]
- Updated dependencies [b203699e9]
- @backstage/plugin-cost-insights@0.10.0
- @backstage/cli@0.6.12
- @backstage/catalog-model@0.7.10
- @backstage/plugin-scaffolder@0.9.5
- @backstage/core@0.7.10
- @backstage/plugin-api-docs@0.4.14
- @backstage/plugin-cloudbuild@0.2.15
- @backstage/plugin-github-actions@0.4.7
- @backstage/plugin-techdocs@0.9.3
- @backstage/plugin-catalog-import@0.5.7
- @backstage/plugin-catalog@0.5.8
## 0.2.28
### Patch Changes
@@ -0,0 +1,121 @@
/*
* 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.
*/
const API_ENDPOINT = 'http://localhost:7000/api/search/query';
describe('SearchPage', () => {
describe('Given a search context with a term, results, and filter values', () => {
it('The results are rendered as expected', () => {
const results = [
{
type: 'software-catalog',
document: {
title: 'backstage',
text: 'Backstage system documentation',
location: '/result/location/path',
},
},
];
cy.enterAsGuest();
cy.visit('/search-next', {
onBeforeLoad(win) {
cy.stub(win, 'fetch')
.withArgs(`${API_ENDPOINT}?term=&pageCursor=`)
.resolves({
ok: true,
json: () => ({ results }),
});
},
});
cy.contains('Search');
cy.contains(results[0].document.title);
cy.contains(results[0].document.text);
cy.get(`a[href="${results[0].document.location}"]`).should('be.visible');
});
it('The filters are rendered as expected', () => {
cy.enterAsGuest();
cy.visit(
'/search-next?filters%5Bkind%5D=Component&filters%5Blifecycle%5D%5B%5D=experimental',
{
onBeforeLoad(win) {
cy.stub(win, 'fetch')
.withArgs(
`${API_ENDPOINT}?term=&filters%5Bkind%5D=Component&filters%5Blifecycle%5D%5B0%5D=experimental&pageCursor=`,
)
.resolves({
ok: true,
json: () => ({ results: [] }),
});
},
},
);
cy.contains('Search');
// lifecycle
cy.contains('lifecycle');
cy.contains('experimental');
cy.get(
'[data-testid="search-checkboxfilter-next"] input[value="experimental"]',
).should('have.attr', 'checked');
cy.contains('production');
cy.get(
'[data-testid="search-checkboxfilter-next"] input[value="production"]',
).should('not.have.attr', 'checked');
// kind
cy.contains('kind');
cy.get(
'[data-testid="search-selectfilter-next"] [role="button"][aria-haspopup="listbox"]',
).click();
cy.contains('All');
cy.contains('Template');
cy.contains('Component');
cy.get('[role="option"][data-value="Component"]').should(
'have.attr',
'aria-selected',
'true',
);
});
it('The search bar is rendered as expected', () => {
cy.enterAsGuest();
cy.visit('/search-next?query=backstage', {
onBeforeLoad(win) {
cy.stub(win, 'fetch')
.withArgs(`${API_ENDPOINT}?term=backstage&pageCursor=`)
.resolves({
ok: true,
json: () => ({ results: [] }),
});
},
});
cy.contains('Search');
cy.get('[data-testid="search-bar-next"] input').should(
'have.attr',
'value',
'backstage',
);
});
});
});
+19
View File
@@ -0,0 +1,19 @@
/*
* 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.
*/
Cypress.Commands.add('enterAsGuest', () => {
cy.visit('/');
cy.get('button').contains('Enter').click();
});
+1
View File
@@ -14,3 +14,4 @@
* limitations under the License.
*/
import '@testing-library/cypress/add-commands';
import './commands';
+34 -34
View File
@@ -1,49 +1,49 @@
{
"name": "example-app",
"version": "0.2.28",
"version": "0.2.31",
"private": true,
"bundled": true,
"dependencies": {
"@backstage/catalog-model": "^0.7.9",
"@backstage/cli": "^0.6.11",
"@backstage/core": "^0.7.9",
"@backstage/catalog-model": "^0.8.1",
"@backstage/cli": "^0.6.14",
"@backstage/core": "^0.7.12",
"@backstage/integration-react": "^0.1.2",
"@backstage/plugin-api-docs": "^0.4.13",
"@backstage/plugin-badges": "^0.2.1",
"@backstage/plugin-catalog": "^0.5.7",
"@backstage/plugin-catalog-import": "^0.5.6",
"@backstage/plugin-catalog-react": "^0.1.6",
"@backstage/plugin-circleci": "^0.2.14",
"@backstage/plugin-cloudbuild": "^0.2.14",
"@backstage/plugin-code-coverage": "^0.1.3",
"@backstage/plugin-cost-insights": "^0.9.1",
"@backstage/plugin-explore": "^0.3.5",
"@backstage/plugin-api-docs": "^0.4.15",
"@backstage/plugin-badges": "^0.2.2",
"@backstage/plugin-catalog": "^0.6.1",
"@backstage/plugin-catalog-import": "^0.5.8",
"@backstage/plugin-catalog-react": "^0.2.1",
"@backstage/plugin-circleci": "^0.2.15",
"@backstage/plugin-cloudbuild": "^0.2.16",
"@backstage/plugin-code-coverage": "^0.1.4",
"@backstage/plugin-cost-insights": "^0.10.1",
"@backstage/plugin-explore": "^0.3.6",
"@backstage/plugin-gcp-projects": "^0.2.6",
"@backstage/plugin-github-actions": "^0.4.6",
"@backstage/plugin-github-actions": "^0.4.8",
"@backstage/plugin-graphiql": "^0.2.11",
"@backstage/plugin-jenkins": "^0.4.3",
"@backstage/plugin-kafka": "^0.2.7",
"@backstage/plugin-kubernetes": "^0.4.4",
"@backstage/plugin-lighthouse": "^0.2.16",
"@backstage/plugin-jenkins": "^0.4.4",
"@backstage/plugin-kafka": "^0.2.8",
"@backstage/plugin-kubernetes": "^0.4.5",
"@backstage/plugin-lighthouse": "^0.2.17",
"@backstage/plugin-newrelic": "^0.2.7",
"@backstage/plugin-org": "^0.3.13",
"@backstage/plugin-pagerduty": "0.3.4",
"@backstage/plugin-rollbar": "^0.3.5",
"@backstage/plugin-scaffolder": "^0.9.4",
"@backstage/plugin-search": "^0.3.6",
"@backstage/plugin-sentry": "^0.3.10",
"@backstage/plugin-org": "^0.3.14",
"@backstage/plugin-pagerduty": "0.3.5",
"@backstage/plugin-rollbar": "^0.3.6",
"@backstage/plugin-scaffolder": "^0.9.7",
"@backstage/plugin-search": "^0.3.7",
"@backstage/plugin-sentry": "^0.3.11",
"@backstage/plugin-shortcuts": "^0.1.2",
"@backstage/plugin-tech-radar": "^0.3.11",
"@backstage/plugin-techdocs": "^0.9.2",
"@backstage/plugin-todo": "^0.1.1",
"@backstage/plugin-tech-radar": "^0.4.0",
"@backstage/plugin-techdocs": "^0.9.5",
"@backstage/plugin-todo": "^0.1.2",
"@backstage/plugin-user-settings": "^0.2.10",
"@backstage/theme": "^0.2.7",
"@backstage/theme": "^0.2.8",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@octokit/rest": "^18.5.3",
"@roadiehq/backstage-plugin-buildkite": "^1.0.0",
"@roadiehq/backstage-plugin-github-insights": "^1.0.0",
"@roadiehq/backstage-plugin-github-pull-requests": "^1.0.0",
"@roadiehq/backstage-plugin-buildkite": "^1.0.3",
"@roadiehq/backstage-plugin-github-insights": "^1.1.11",
"@roadiehq/backstage-plugin-github-pull-requests": "^1.0.5",
"@roadiehq/backstage-plugin-travis-ci": "^1.0.0",
"history": "^5.0.0",
"prop-types": "^15.7.2",
@@ -56,7 +56,7 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/test-utils": "^0.1.11",
"@backstage/test-utils": "^0.1.13",
"@testing-library/cypress": "^7.0.1",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
@@ -67,7 +67,7 @@
"@types/react-dom": "^16.9.8",
"@types/zen-observable": "^0.8.0",
"cross-env": "^7.0.0",
"cypress": "^4.2.0",
"cypress": "^7.3.0",
"eslint-plugin-cypress": "^2.10.3",
"start-server-and-test": "^1.10.11"
},
+4 -4
View File
@@ -54,6 +54,7 @@ import { Navigate, Route } from 'react-router';
import { apis } from './apis';
import { Root } from './components/Root';
import { entityPage } from './components/catalog/EntityPage';
import { searchPage } from './components/search/SearchPage';
import { providers } from './identityProviders';
import * as plugins from './plugins';
@@ -119,10 +120,9 @@ 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="/search-next" element={<SearchPageNext />}>
{searchPage}
</Route>
<Route path="/cost-insights" element={<CostInsightsPage />} />
<Route
path="/cost-insights/investigating-growth"
@@ -44,6 +44,7 @@ describe('EntityPage Test', () => {
getWorkflow: jest.fn(),
getWorkflowRun: jest.fn(),
reRunWorkflow: jest.fn(),
listJobsForWorkflowRun: jest.fn(),
downloadJobLogsForWorkflowRun: jest.fn(),
} as jest.Mocked<typeof githubActionsApiRef.T>;
@@ -28,6 +28,8 @@ import {
import { EntityBadgesDialog } from '@backstage/plugin-badges';
import {
EntityAboutCard,
EntityDependsOnComponentsCard,
EntityDependsOnResourcesCard,
EntityHasComponentsCard,
EntityHasSubcomponentsCard,
EntityHasSystemsCard,
@@ -37,6 +39,9 @@ import {
EntitySwitch,
isComponentType,
isKind,
EntityHasResourcesCard,
EntityOrphanWarning,
isOrphan,
} from '@backstage/plugin-catalog';
import {
EntityCircleCIContent,
@@ -211,7 +216,15 @@ const errorsContent = (
const overviewContent = (
<Grid container spacing={3} alignItems="stretch">
<Grid item md={6}>
<EntitySwitch>
<EntitySwitch.Case if={isOrphan}>
<Grid item xs={12}>
<EntityOrphanWarning />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
<Grid item md={8} xs={12}>
<EntityAboutCard variant="gridItem" />
</Grid>
@@ -223,7 +236,7 @@ const overviewContent = (
</EntitySwitch.Case>
</EntitySwitch>
<Grid item md={4} sm={6}>
<Grid item md={4} xs={12}>
<EntityLinksCard />
</Grid>
@@ -257,7 +270,7 @@ const overviewContent = (
</EntitySwitch.Case>
</EntitySwitch>
<Grid item md={6}>
<Grid item md={8} xs={12}>
<EntityHasSubcomponentsCard variant="gridItem" />
</Grid>
</Grid>
@@ -288,6 +301,17 @@ const serviceEntityPage = (
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="/dependencies" title="Dependencies">
<Grid container spacing={3} alignItems="stretch">
<Grid item md={6}>
<EntityDependsOnComponentsCard variant="gridItem" />
</Grid>
<Grid item md={6}>
<EntityDependsOnResourcesCard variant="gridItem" />
</Grid>
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="/docs" title="Docs">
<EntityTechdocsContent />
</EntityLayout.Route>
@@ -336,6 +360,17 @@ const websiteEntityPage = (
{errorsContent}
</EntityLayout.Route>
<EntityLayout.Route path="/dependencies" title="Dependencies">
<Grid container spacing={3} alignItems="stretch">
<Grid item md={6}>
<EntityDependsOnComponentsCard variant="gridItem" />
</Grid>
<Grid item md={6}>
<EntityDependsOnResourcesCard variant="gridItem" />
</Grid>
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="/docs" title="Docs">
<EntityTechdocsContent />
</EntityLayout.Route>
@@ -466,6 +501,9 @@ const systemPage = (
<Grid item md={6}>
<EntityHasApisCard variant="gridItem" />
</Grid>
<Grid item md={6}>
<EntityHasResourcesCard variant="gridItem" />
</Grid>
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="/diagram" title="Diagram">
@@ -0,0 +1,102 @@
/*
* 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 React from 'react';
import { makeStyles, Theme, Grid, List, Paper } from '@material-ui/core';
import { Content, Header, Lifecycle, Page } from '@backstage/core';
import { CatalogResultListItem } from '@backstage/plugin-catalog';
import {
SearchBarNext as SearchBar,
SearchFilterNext as SearchFilter,
SearchResultNext as SearchResult,
DefaultResultListItem,
} from '@backstage/plugin-search';
const useStyles = makeStyles((theme: Theme) => ({
bar: {
padding: theme.spacing(1, 0),
},
filters: {
padding: theme.spacing(2),
},
filter: {
'& + &': {
marginTop: theme.spacing(2.5),
},
},
}));
const SearchPage = () => {
const classes = useStyles();
return (
<Page themeId="home">
<Header title="Search" subtitle={<Lifecycle alpha />} />
<Content>
<Grid container direction="row">
<Grid item xs={12}>
<Paper className={classes.bar}>
<SearchBar debounceTime={100} />
</Paper>
</Grid>
<Grid item xs={3}>
<Paper className={classes.filters}>
<SearchFilter.Select
className={classes.filter}
name="kind"
values={['Component', 'Template']}
/>
<SearchFilter.Checkbox
className={classes.filter}
name="lifecycle"
values={['experimental', 'production']}
/>
</Paper>
</Grid>
<Grid item xs={9}>
<SearchResult>
{({ results }) => (
<List>
{results.map(({ type, document }) => {
switch (type) {
case 'software-catalog':
return (
<CatalogResultListItem
key={document.location}
result={document}
/>
);
default:
return (
<DefaultResultListItem
key={document.location}
result={document}
/>
);
}
})}
</List>
)}
</SearchResult>
</Grid>
</Grid>
</Content>
</Page>
);
};
export const searchPage = <SearchPage />;
+25
View File
@@ -1,5 +1,30 @@
# @backstage/backend-common
## 0.8.1
### Patch Changes
- c7dad9218: All cache-related connection errors are now handled and logged by the cache manager. App Integrators may provide an optional error handler when instantiating the cache manager if custom error handling is needed.
```typescript
// Providing an error handler
const cacheManager = CacheManager.fromConfig(config, {
onError: e => {
if (isSomehowUnrecoverable(e)) {
gracefullyShutThingsDown();
process.exit(1);
}
},
});
```
- 65e6c4541: Remove circular dependencies
- 5001de908: Change GitlabUrlReader to SHA timestamp compare using only commits that modify given file path, if file path given
- Updated dependencies [65e6c4541]
- Updated dependencies [290405276]
- @backstage/integration@0.5.3
- @backstage/config-loader@0.6.2
## 0.8.0
### Minor Changes
+1 -1
View File
@@ -73,7 +73,7 @@ export interface CacheClient {
// @public
export class CacheManager {
forPlugin(pluginId: string): PluginCacheManager;
static fromConfig(config: Config): CacheManager;
static fromConfig(config: Config, options?: CacheManagerOptions): CacheManager;
}
// @public (undocumented)
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.8.0",
"version": "0.8.1",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -31,9 +31,9 @@
"dependencies": {
"@backstage/cli-common": "^0.1.1",
"@backstage/config": "^0.1.5",
"@backstage/config-loader": "^0.6.1",
"@backstage/config-loader": "^0.6.2",
"@backstage/errors": "^0.1.1",
"@backstage/integration": "^0.5.2",
"@backstage/integration": "^0.5.3",
"@google-cloud/storage": "^5.8.0",
"@octokit/rest": "^18.5.3",
"@types/cors": "^2.8.6",
@@ -76,8 +76,8 @@
}
},
"devDependencies": {
"@backstage/cli": "^0.6.11",
"@backstage/test-utils": "^0.1.11",
"@backstage/cli": "^0.6.12",
"@backstage/test-utils": "^0.1.12",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
"@types/concat-stream": "^1.6.0",
+2 -1
View File
@@ -92,7 +92,8 @@ export class DefaultCacheClient implements CacheClient {
const wellFormedKey = Buffer.from(candidateKey).toString('base64');
// Memcache in particular doesn't do well with keys > 250 bytes.
if (wellFormedKey.length < 250) {
// Padded because a plugin ID is also prepended to the key.
if (wellFormedKey.length < 200) {
return wellFormedKey;
}
+59
View File
@@ -86,6 +86,16 @@ describe('CacheManager', () => {
expect(client).toHaveBeenCalledTimes(1);
});
it('attaches error handler to client', () => {
const pluginId = 'error-test';
manager.forPlugin(pluginId).getClient();
const client = DefaultCacheClient as jest.Mock;
const mockCalls = client.mock.calls.splice(-1);
const realClient = mockCalls[0][0].client as Keyv;
expect(realClient.on).toHaveBeenCalledWith('error', expect.any(Function));
});
it('provides different plugins different cache clients', async () => {
const plugin1Id = 'test1';
const plugin2Id = 'test2';
@@ -163,4 +173,53 @@ describe('CacheManager', () => {
expect(mockMemcacheCalls[0][0]).toEqual(expectedHost);
});
});
describe('connection errors', () => {
it('uses provided logger', () => {
// Set up and inject mock logger.
const mockLogger = { child: jest.fn(), error: jest.fn() };
mockLogger.child.mockImplementation(() => mockLogger as any);
const manager = CacheManager.fromConfig(defaultConfig(), {
logger: mockLogger as any,
});
// Set up a cache client using the configured manager.
manager.forPlugin('error-logger-test').getClient();
// Retrieve the error handler attached to the cache client.
const client = DefaultCacheClient as jest.Mock;
const mockCalls = client.mock.calls.splice(-1);
const realClient = mockCalls[0][0].client as Keyv;
const realOnError = realClient.on as jest.Mock;
const realHandler = realOnError.mock.calls.splice(-1)[0][1];
// Invoke the actual error handler.
const expectedError = new Error('some error');
realHandler(expectedError);
expect(mockLogger.error).toHaveBeenCalledWith(expectedError);
});
it('calls provided handler', () => {
// Set up and inject mock logger.
const mockHandler = jest.fn();
const manager = CacheManager.fromConfig(defaultConfig(), {
onError: mockHandler,
});
// Set up a cache client using the configured manager.
manager.forPlugin('error-handler-test').getClient();
// Retrieve the error handler attached to the cache client.
const client = DefaultCacheClient as jest.Mock;
const mockCalls = client.mock.calls.splice(-1);
const realClient = mockCalls[0][0].client as Keyv;
const realOnError = realClient.on as jest.Mock;
const realHandler = realOnError.mock.calls.splice(-1)[0][1];
// Invoke the actual error handler.
const expectedError = new Error('some error');
realHandler(expectedError);
expect(mockHandler).toHaveBeenCalledWith(expectedError);
});
});
});
+38 -5
View File
@@ -18,9 +18,15 @@ import { Config } from '@backstage/config';
import Keyv from 'keyv';
// @ts-expect-error
import KeyvMemcache from 'keyv-memcache';
import { Logger } from 'winston';
import { getRootLogger } from '../logging';
import { DefaultCacheClient, CacheClient } from './CacheClient';
import { NoStore } from './NoStore';
import { PluginCacheManager } from './types';
import {
CacheManagerOptions,
OptionalOnError,
PluginCacheManager,
} from './types';
/**
* Implements a Cache Manager which will automatically create new cache clients
@@ -38,8 +44,10 @@ export class CacheManager {
none: this.getNoneClient,
};
private readonly logger: Logger;
private readonly store: keyof CacheManager['storeFactories'];
private readonly connection: string;
private readonly errorHandler: OptionalOnError;
/**
* Creates a new CacheManager instance by reading from the `backend` config
@@ -47,25 +55,38 @@ export class CacheManager {
*
* @param config The loaded application configuration.
*/
static fromConfig(config: Config): CacheManager {
static fromConfig(
config: Config,
options: CacheManagerOptions = {},
): CacheManager {
// If no `backend.cache` config is provided, instantiate the CacheManager
// with a "NoStore" cache client.
const store = config.getOptionalString('backend.cache.store') || 'none';
const connectionString =
config.getOptionalString('backend.cache.connection') || '';
return new CacheManager(store, connectionString);
const logger = (options.logger || getRootLogger()).child({
type: 'cacheManager',
});
return new CacheManager(store, connectionString, logger, options.onError);
}
private constructor(store: string, connectionString: string) {
private constructor(
store: string,
connectionString: string,
logger: Logger,
errorHandler: OptionalOnError,
) {
if (!this.storeFactories.hasOwnProperty(store)) {
throw new Error(`Unknown cache store: ${store}`);
}
this.logger = logger;
this.store = store as keyof CacheManager['storeFactories'];
this.connection = connectionString;
this.errorHandler = errorHandler;
}
/**
* Generates a CacheManagerInstance for consumption by plugins.
* Generates a PluginCacheManager for consumption by plugins.
*
* @param pluginId The plugin that the cache manager should be created for. Plugin names should be unique.
*/
@@ -73,6 +94,18 @@ export class CacheManager {
return {
getClient: (opts = {}): CacheClient => {
const concreteClient = this.getClientWithTtl(pluginId, opts.defaultTtl);
// Always provide an error handler to avoid killing the process.
concreteClient.on('error', (err: Error) => {
// In all cases, just log the error.
this.logger.error(err);
// Invoke any custom error handler if provided.
if (typeof this.errorHandler === 'function') {
this.errorHandler(err);
}
});
return new DefaultCacheClient({
client: concreteClient,
});
+16
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { Logger } from 'winston';
import { CacheClient } from './CacheClient';
type ClientOptions = {
@@ -25,6 +26,21 @@ type ClientOptions = {
defaultTtl?: number;
};
export type OptionalOnError = ((err: Error) => void) | undefined;
export type CacheManagerOptions = {
/**
* An optional logger for use by the PluginCacheManager.
*/
logger?: Logger;
/**
* An optional handler for connection errors emitted from the underlying data
* store.
*/
onError?: OptionalOnError;
};
/**
* The PluginCacheManager manages access to cache stores that Plugins get.
*/
@@ -29,11 +29,11 @@ import path from 'path';
import { NotModifiedError } from '@backstage/errors';
import { getVoidLogger } from '../logging';
import { AzureUrlReader } from './AzureUrlReader';
import { ReadTreeResponseFactory } from './tree';
import { DefaultReadTreeResponseFactory } from './tree';
const logger = getVoidLogger();
const treeResponseFactory = ReadTreeResponseFactory.create({
const treeResponseFactory = DefaultReadTreeResponseFactory.create({
config: new ConfigReader({}),
});
@@ -27,9 +27,9 @@ import parseGitUrl from 'git-url-parse';
import { Minimatch } from 'minimatch';
import { Readable } from 'stream';
import { NotFoundError, NotModifiedError } from '@backstage/errors';
import { ReadTreeResponseFactory } from './tree';
import { stripFirstDirectoryFromPath } from './tree/util';
import {
ReadTreeResponseFactory,
ReaderFactory,
ReadTreeOptions,
ReadTreeResponse,
@@ -28,9 +28,9 @@ import os from 'os';
import path from 'path';
import { NotModifiedError } from '@backstage/errors';
import { BitbucketUrlReader } from './BitbucketUrlReader';
import { ReadTreeResponseFactory } from './tree';
import { DefaultReadTreeResponseFactory } from './tree';
const treeResponseFactory = ReadTreeResponseFactory.create({
const treeResponseFactory = DefaultReadTreeResponseFactory.create({
config: new ConfigReader({}),
});
@@ -27,9 +27,9 @@ import parseGitUrl from 'git-url-parse';
import { Minimatch } from 'minimatch';
import { Readable } from 'stream';
import { NotFoundError, NotModifiedError } from '@backstage/errors';
import { ReadTreeResponseFactory } from './tree';
import { stripFirstDirectoryFromPath } from './tree/util';
import {
ReadTreeResponseFactory,
ReaderFactory,
ReadTreeOptions,
ReadTreeResponse,

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