Merge branch 'master' of github.com:spotify/backstage into migrate-to-msw

* 'master' of github.com:spotify/backstage: (66 commits)
  chore: fix lerna linting
  v0.1.1-alpha.25
  Add Code Insights plugin to sample app and marketplace (#2833)
  Improve main CI build status badge in README (#2866)
  Update roadmap: Design System 🚢 (#2858)
  github/codecov: switch to informational mode
  github/workflows: use the tip of master as the base for comparing PR code coverage
  make saml provider path from globalConfig (#2855)
  fix(catalog-backend): limit search value lengths
  Update project Copyright (#2852)
  fix(catalog-backend): actually use modified entity output (default namespace was broken)
  remove unnecessary center keyword
  Move card header bg to up contrast, fix #2558
  Update name of env authentication env vars
  Fix feedback from dtuite
  Remove chart testing workflow for now
  Only lint charts on Pull Requests
  Move the k8s deployment docs to its own helm deployment page
  Remove line in initdb script that creates backend db
  Use app-config.development.yaml to provide configuration instead of local
  ...
This commit is contained in:
blam
2020-10-13 03:56:13 +02:00
181 changed files with 3026 additions and 1485 deletions
+1 -49
View File
@@ -2,55 +2,7 @@
"$schema": "https://unpkg.com/@changesets/config@1.3.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"linked": [
[
"example-app",
"@backstage/backend-common",
"example-backend",
"@backstage/catalog-model",
"@backstage/cli-common",
"@backstage/cli",
"@backstage/config-loader",
"@backstage/config",
"@backstage/core-api",
"@backstage/core",
"@backstage/create-app",
"@backstage/dev-utils",
"docgen",
"e2e-test",
"storybook",
"@techdocs/cli",
"@backstage/test-utils-core",
"@backstage/test-utils",
"@backstage/theme",
"@backstage/plugin-api-docs",
"@backstage/plugin-app-backend",
"@backstage/plugin-auth-backend",
"@backstage/plugin-catalog-backend",
"@backstage/plugin-catalog",
"@backstage/plugin-circleci",
"@backstage/plugin-gcp-projects",
"@backstage/plugin-github-actions",
"@backstage/plugin-gitops-profiles",
"@backstage/plugin-graphiql",
"@backstage/plugin-graphql-backend",
"@backstage/plugin-jenkins",
"@backstage/plugin-lighthouse",
"@backstage/plugin-newrelic",
"@backstage/plugin-proxy-backend",
"@backstage/plugin-register-component",
"@backstage/plugin-rollbar-backend",
"@backstage/plugin-rollbar",
"@backstage/plugin-scaffolder-backend",
"@backstage/plugin-scaffolder",
"@backstage/plugin-sentry-backend",
"@backstage/plugin-sentry",
"@backstage/plugin-tech-radar",
"@backstage/plugin-techdocs-backend",
"@backstage/plugin-techdocs",
"@backstage/plugin-welcome"
]
],
"linked": [["*"]],
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
+5
View File
@@ -0,0 +1,5 @@
---
'e2e-test': minor
---
Converted into a CLI, use `yarn e2e-test run` to run
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cost-insights': minor
---
Enable custom alert types in Cost Insights
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-common': minor
'@backstage/cli': minor
---
Use APP_ENV before NODE_ENV for determining what config to load
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Fixed duplicate help output, and print help on invalid command
+4 -7
View File
@@ -5,12 +5,9 @@
#### :heavy_check_mark: Checklist
<!--- Put an `x` in all the boxes that apply: -->
<!--- Please include the following in your Pull Request when applicable: -->
- [ ] All tests are passing `yarn test`
- [ ] A changeset describing the change and affected packages. ([more info](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md#creating-changesets))
- [ ] Added or updated documentation
- [ ] Tests for new functionality and regression tests for bug fixes
- [ ] Screenshots attached (for UI changes)
- [ ] Relevant documentation updated
- [ ] Prettier run on changed files
- [ ] Tests added for new functionality
- [ ] Regression tests added for bug fixes
- [ ] Added a changeset ([more info](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md#creating-changesets))
+1
View File
@@ -6,6 +6,7 @@ coverage:
default:
threshold: 0% # Ref: https://docs.codecov.io/docs/codecovyml-reference#coveragestatus
target: auto
informational: true # Don't block PRs
# Since Backstage is a mono repo, flags here help in getting the code coverage of individual packages.
# Documentation: https://docs.codecov.io/docs/flags
+3
View File
@@ -141,6 +141,7 @@ Raghunandan
rankdir
readme
Readme
Recharts
Redash
replicasets
repo
@@ -204,3 +205,5 @@ cloudbuild
Grafana
Iain
Snyk
www
WWW
+1 -1
View File
@@ -97,7 +97,7 @@ jobs:
if: ${{ steps.yarn-lock.outcome == 'failure' }}
run: |
yarn lerna -- run test -- --coverage
bash <(curl -s https://codecov.io/bash)
bash <(curl -s https://codecov.io/bash) -N $(git rev-parse FETCH_HEAD)
- name: verify plugin template
run: yarn lerna -- run diff -- --check
+1 -1
View File
@@ -40,4 +40,4 @@ jobs:
- name: yarn build
run: yarn build --ignore example-app --ignore example-backend --ignore @techdocs/cli
- name: run E2E test
run: yarn workspace e2e-test start
run: yarn e2e-test run
+1 -1
View File
@@ -70,7 +70,7 @@ jobs:
- name: run E2E test
run: |
sudo sysctl fs.inotify.max_user_watches=524288
yarn workspace e2e-test start
yarn e2e-test run
env:
POSTGRES_HOST: localhost
POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }}
+4
View File
@@ -8,6 +8,10 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re
> Collect changes for the next release below
### @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/spotify/backstage/pull/2697)
+4 -5
View File
@@ -3,7 +3,8 @@
# [Backstage](https://backstage.io)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
![](https://github.com/spotify/backstage/workflows/Frontend%20CI/badge.svg)
[![CNCF Status](https://img.shields.io/badge/cncf%20status-sandbox-blue.svg)](https://www.cncf.io/projects)
[![Main CI Build](https://github.com/spotify/backstage/workflows/Main%20Master%20Build/badge.svg)](https://github.com/spotify/backstage/actions?query=workflow%3A%22Main+Master+Build%22)
[![Discord](https://img.shields.io/discord/687207715902193673)](https://discord.gg/EBHEGzX)
![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)
[![Codecov](https://img.shields.io/codecov/c/github/spotify/backstage)](https://codecov.io/gh/spotify/backstage)
@@ -24,9 +25,7 @@ Out of the box, Backstage includes:
- [Backstage TechDocs](https://backstage.io/docs/features/techdocs/techdocs-overview) for making it easy to create, maintain, find, and use technical documentation, using a "docs like code" approach
- Plus, a growing ecosystem of [open source plugins](https://github.com/spotify/backstage/tree/master/plugins) that further expand Backstages customizability and functionality
For more information go to [backstage.io](https://backstage.io) or join our [Discord chatroom](https://discord.gg/EBHEGzX).
🎉 Backstage is a CNCF Sandbox project. Read the announcement [here](https://backstage.io/blog/2020/09/23/backstage-cncf-sandbox).
Backstage was created by Spotify but is now hosted by the [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io) as a Sandbox level project. Read the announcement [here](https://backstage.io/blog/2020/09/23/backstage-cncf-sandbox).
## Project roadmap
@@ -58,6 +57,6 @@ Check out [the documentation](https://backstage.io/docs/getting-started) on how
## License
Copyright 2020 Spotify AB.
Copyright 2020 © Backstage Project Authors. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page: https://www.linuxfoundation.org/trademark-usage
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
+6
View File
@@ -0,0 +1,6 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 9.4.1
digest: sha256:f949ec0fe7d146610ce2ee78fbfb4e52d235883a797968b0a1e61aa88ada2786
generated: "2020-09-25T08:59:54.255582519+02:00"
+30
View File
@@ -0,0 +1,30 @@
apiVersion: v2
name: backstage
description: A Helm chart for Spotify Backstage
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application.
appVersion: v0.1.1-alpha.23
sources:
- https://github.com/spotify/backstage
- https://github.com/spotify/lighthouse-audit-service
dependencies:
- name: postgresql
condition: postgresql.enabled
version: 9.4.1
repository: https://charts.bitnami.com/bitnami
maintainers:
- name: Martina Iglesias Fernández
email: martina@roadie.io
url: https://roadie.io
- name: David Tuite
email: david@roadie.io
url: https://roadie.io
+218
View File
@@ -0,0 +1,218 @@
# Backstage demo helm charts
This folder contains Helm charts that can easily create a Kubernetes deployment of a demo Backstage app.
### Pre-requisites
These charts depend on the `nginx-ingress` controller being present in the cluster. If it's not already installed you
can run:
```
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install nginx-ingress ingress-nginx/ingress-nginx
```
### Installing the charts
After choosing a DNS name where backstage will be hosted create a yaml file for your custom configuration.
```
appConfig:
app:
baseUrl: https://backstage.mydomain.com
title: Backstage
backend:
baseUrl: https://backstage.mydomain.com
cors:
origin: https://backstage.mydomain.com
lighthouse:
baseUrl: https://backstage.mydomain.com/lighthouse-api
techdocs:
storageUrl: https://backstage.mydomain.com/api/techdocs/static/docs
requestUrl: https://backstage.mydomain.com/api/techdocs
```
Then use it to run:
```
git clone https://github.com/spotify/backstage.git
cd contrib/chart/backstage
helm dependency update
helm install -f backstage-mydomain.yaml backstage .
```
This command will deploy the following pieces:
- Backstage frontend
- Backstage backend with scaffolder and auth plugins
- (optional) a PostgreSQL instance
- lighthouse plugin
- ingress
After a few minutes Backstage should be up and running in your cluster under the DNS specified earlier.
Make sure to create the appropriate DNS entry in your infrastructure. To find the public IP address run:
```bash
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
backstage-ingress * 123.1.2.3 80 17m
```
> **NOTE**: this is not a production ready deployment.
## Caveats
The current implementation does not generate certificates for the ingress which means the browser will alert that the
site is insecure and using self-signed certificates.
## Customization
### Custom PostgreSQL instance
Configuring a connection to an existing PostgreSQL instance is possible through the chart's values.
First create a yaml file with the configuration you want to override, for example `backstage-prod.yaml`:
```bash
postgresql:
enabled: false
appConfig:
app:
baseUrl: https://backstage-demo.mydomain.com
title: Backstage
backend:
baseUrl: https://backstage-demo.mydomain.com
cors:
origin: https://backstage-demo.mydomain.com
database:
client: pg
connection:
database: backstage_plugin_catalog
host: <host>
user: <pg user>
password: <password>
lighthouse:
baseUrl: https://backstage-demo.mydomain.com/lighthouse-api
lighthouse:
database:
client: pg
connection:
host: <host>
user: <pg user>
password: <password>
database: lighthouse_audit_service
```
For the CA, create a `configMap` named `<helm_release_name>-postgres-ca` with a file called `ca.crt`:
```
kubectl create configmap my-backstage --from-file=ca.crt"
```
Now install the helm chart:
```
cd contrib/chart/backstage
helm install -f backstage-prod.yaml my-backstage .
```
### Use your own docker images
The docker images used for the deployment can be configured through the charts values:
```
frontend:
image:
repository: <image-name>
tag: <image-tag>
backend:
image:
repository: <image-name>
tag: <image-tag>
lighthouse:
image:
repository: <image-name
tag: <image-tag>
```
### Different namespace
To install the charts a specific namespace use `--namespace <ns>`:
```
helm install -f my_values.yaml --namespace demos backstage .
```
### Disable loading of demo data
To deploy backstage with the pre-loaded demo data disable `backend.demoData`:
```
helm install -f my_values.yaml --set backend.demoData=false backstage .
```
### Other options
For more customization options take a look at the [values.yaml](/contrib/chart/backstage/values.yaml) file.
## Troubleshooting
Some resources created by these charts are meant to survive after upgrades and even after uninstalls. When
troubleshooting these charts it can be useful to delete these resources between re-installs.
Secrets:
```
<release-name>-postgresql-certs -- contains the certificates used by the deployed PostgreSQL
```
Persistent volumes:
```
data-<release-name>-postgresql-0 -- this is the data volume used by PostgreSQL to store data and configuration
```
> **NOTE**: this volume also stores the configuration for PostgreSQL which includes things like the password for the
> `postgres` user. This means that uninstalling and re-installing the charts with `postgres.enabled` set to `true` and
> auto generated passwords will fail. The solution is to delete this volume with
> `kubectl delete pvc data-<release-name>-postgresql-0`
ConfigMaps:
```
<release-name>-postgres-ca -- contains the generated CA certificate for PostgreSQL when `postgres` is enabled
```
#### Unable to verify signature
```
Backend failed to start up Error: unable to verify the first certificate
at TLSSocket.onConnectSecure (_tls_wrap.js:1501:34)
at TLSSocket.emit (events.js:315:20)
at TLSSocket._finishInit (_tls_wrap.js:936:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:710:12) {
code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
```
This error happens in the backend when it tries to connect to the configured PostgreSQL database and the specified CA is not correct. The solution is to make sure that the contents of the `configMap` that holds the certificate match the CA for the PostgreSQL instance. A workaround is to set `appConfig.backend.database.connection.ssl.rejectUnauthorized` to `false` in the chart's values.
<!-- TODO Add example command when we know the final name of the charts -->
## Uninstalling Backstage
To uninstall Backstage simply run:
```
RELEASE_NAME=<release-name> # use `helm list` to find out the name
helm uninstall ${RELEASE_NAME}
kubectl delete pvc data-${RELEASE_NAME}-postgresql-0
kubectl delete secret ${RELEASE_NAME}-postgresql-certs
kubectl delete configMap ${RELEASE_NAME}-postgres-ca
```
@@ -0,0 +1,51 @@
backend:
lighthouseHostname: {{ include "lighthouse.serviceName" . | quote }}
listen:
port: {{ .Values.appConfig.backend.listen.port | default 7000 }}
database:
client: {{ .Values.appConfig.backend.database.client | quote }}
connection:
host: {{ include "backend.postgresql.host" . | quote }}
port: {{ include "backend.postgresql.port" . | quote }}
user: {{ include "backend.postgresql.user" . | quote }}
database: {{ .Values.appConfig.backend.database.connection.database | quote }}
ssl:
rejectUnauthorized: {{ .Values.appConfig.backend.database.connection.ssl.rejectUnauthorized | quote }}
ca: {{ include "backstage.backend.postgresCaFilename" . | quote }}
catalog:
{{- if .Values.backend.demoData }}
locations:
# Backstage example components
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/all-components.yaml
# Example component for github-actions
- type: github
target: https://github.com/spotify/backstage/blob/master/plugins/github-actions/examples/sample.yaml
# Example component for techdocs
- type: github
target: https://github.com/spotify/backstage/blob/master/plugins/techdocs-backend/examples/documented-component/documented-component.yaml
# Backstage example APIs
- type: github
target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/all-apis.yaml
# Backstage example templates
- type: github
target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/all-templates.yaml
{{- else }}
locations: []
{{- end }}
auth:
providers:
microsoft: null
scaffolder:
azure: null
sentry:
organization: {{ .Values.appConfig.sentry.organization | quote }}
techdocs:
generators:
techdocs: 'local'
@@ -0,0 +1,13 @@
{{ $backendDb := .Values.appConfig.backend.database.connection.database }}
{{ $lighthouseDb := .Values.lighthouse.database.connection.database }}
{{ $user := .Values.global.postgresql.postgresqlUsername }}
grant all privileges on database {{ $backendDb }} to {{ $user }};
create database backstage_plugin_auth;
grant all privileges on database backstage_plugin_auth to {{ $user }};
{{ if not (eq $backendDb $lighthouseDb) }}
create database {{ $lighthouseDb }};
grant all privileges on database {{ $lighthouseDb }} to {{ $user }};
{{ end }}
@@ -0,0 +1,286 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "backstage.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "backstage.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "backstage.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Common App labels
*/}}
{{- define "backstage.app.labels" -}}
app.kubernetes.io/name: {{ include "backstage.name" . }}-app
helm.sh/chart: {{ include "backstage.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{/*
Common Backend labels
*/}}
{{- define "backstage.backend.labels" -}}
app.kubernetes.io/name: {{ include "backstage.name" . }}-backend
helm.sh/chart: {{ include "backstage.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{/*
Name for postgresql dependency
See https://github.com/helm/helm/issues/3920#issuecomment-686913512
*/}}
{{- define "backstage.postgresql.fullname" -}}
{{ printf "%s-%s" .Release.Name .Values.postgresql.nameOverride }}
{{- end -}}
{{/*
Create the name of the service account to use for the app
*/}}
{{- define "backstage.app.serviceAccountName" -}}
{{- if .Values.app.serviceAccount.create -}}
{{ default "default" .Values.app.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.app.serviceAccount.name }}
{{- end -}}
{{- end -}}
{{/*
Create the name of the service account to use for the backend
*/}}
{{- define "backstage.backend.serviceAccountName" -}}
{{- if .Values.backend.serviceAccount.create -}}
{{ default default .Values.backend.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.backend.serviceAccount.name }}
{{- end -}}
{{- end -}}
{{/*
Path to the CA certificate file in the backend
*/}}
{{- define "backstage.backend.postgresCaFilename" -}}
{{ include "backstage.backend.postgresCaDir" . }}/{{- required "The name for the CA certificate file for postgresql is required" .Values.global.postgresql.caFilename }}
{{- end -}}
{{/*
{{/*
Directory path to the CA certificate file in the backend
*/}}
{{- define "backstage.backend.postgresCaDir" -}}
{{- if .Values.appConfig.backend.database.connection.ssl.ca -}}
{{ .Values.appConfig.backend.database.connection.ssl.ca }}
{{- else -}}
/etc/postgresql
{{- end -}}
{{- end -}}
{{/*
Path to the CA certificate file in lighthouse
*/}}
{{- define "backstage.lighthouse.postgresCaFilename" -}}
{{ include "backstage.lighthouse.postgresCaDir" . }}/{{- required "The name for the CA certificate file for postgresql is required" .Values.global.postgresql.caFilename }}
{{- end -}}
{{/*
Directory path to the CA certificate file in lighthouse
*/}}
{{- define "backstage.lighthouse.postgresCaDir" -}}
{{- if .Values.lighthouse.database.pathToDatabaseCa -}}
{{ .Values.lighthouse.database.pathToDatabaseCa }}
{{- else -}}
/etc/postgresql
{{- end -}}
{{- end -}}
{{/*
{{/*
Generate ca for postgresql
*/}}
{{- define "backstage.postgresql.generateCA" -}}
{{- $ca := .ca | default (genCA (include "backstage.postgresql.fullname" .) 365) -}}
{{- $_ := set . "ca" $ca -}}
{{- $ca.Cert -}}
{{- end -}}
{{/*
Generate certificates for postgresql
*/}}
{{- define "generateCerts" -}}
{{- $postgresName := (include "backstage.postgresql.fullname" .) }}
{{- $altNames := list $postgresName ( printf "%s.%s" $postgresName .Release.Namespace ) ( printf "%s.%s.svc" ( $postgresName ) .Release.Namespace ) -}}
{{- $ca := .ca | default (genCA (include "backstage.postgresql.fullname" .) 365) -}}
{{- $_ := set . "ca" $ca -}}
{{- $cert := genSignedCert ( $postgresName ) nil $altNames 365 $ca -}}
tls.crt: {{ $cert.Cert | b64enc }}
tls.key: {{ $cert.Key | b64enc }}
{{- end -}}
{{/*
Generate a password for the postgres user used for the connections from the backend and lighthouse
*/}}
{{- define "postgresql.generateUserPassword" -}}
{{- $pgPassword := .pgPassword | default ( randAlphaNum 12 ) -}}
{{- $_ := set . "pgPassword" $pgPassword -}}
{{ $pgPassword}}
{{- end -}}
{{/*
Name of the backend service
*/}}
{{- define "backend.serviceName" -}}
{{ include "backstage.fullname" . }}-backend
{{- end -}}
{{/*
Name of the frontend service
*/}}
{{- define "frontend.serviceName" -}}
{{ include "backstage.fullname" . }}-frontend
{{- end -}}
{{/*
Name of the lighthouse backend service
*/}}
{{- define "lighthouse.serviceName" -}}
{{ include "backstage.fullname" . }}-lighthouse
{{- end -}}
{{/*
Name of the postgresql service
*/}}
{{- define "postgresql.serviceName" -}}
{{- include "backstage.postgresql.fullname" . }}
{{- end -}}
{{/*
Postgres host for lighthouse
*/}}
{{- define "lighthouse.postgresql.host" -}}
{{- if .Values.postgresql.enabled }}
{{- include "postgresql.serviceName" . }}
{{- else -}}
{{- required "A valid .Values.lighthouse.database.connection.host is required when postgresql is not enabled" .Values.lighthouse.database.connection.host -}}
{{- end -}}
{{- end -}}
{{/*
Postgres host for the backend
*/}}
{{- define "backend.postgresql.host" -}}
{{- if .Values.postgresql.enabled }}
{{- include "postgresql.serviceName" . }}
{{- else -}}
{{- required "A valid .Values.appConfig.backend.database.connection.host is required when postgresql is not enabled" .Values.appConfig.backend.database.connection.host -}}
{{- end -}}
{{- end -}}
{{/*
Postgres port for the backend
*/}}
{{- define "backend.postgresql.port" -}}
{{- if .Values.postgresql.enabled }}
{{- .Values.postgresql.service.port }}
{{- else if .Values.appConfig.backend.database.connection.port -}}
{{- .Values.appConfig.backend.database.connection.port }}
{{ else }}
5432
{{- end -}}
{{- end -}}
{{/*
Postgres port for lighthouse
*/}}
{{- define "lighthouse.postgresql.port" -}}
{{- if .Values.postgresql.enabled }}
{{- .Values.postgresql.service.port }}
{{- else if .Values.lighthouse.database.connection.port -}}
{{- .Values.lighthouse.database.connection.port }}
{{- else -}}
5432
{{- end -}}
{{- end -}}
{{/*
Postgres user for backend
*/}}
{{- define "backend.postgresql.user" -}}
{{- if .Values.postgresql.enabled }}
{{- .Values.global.postgresql.postgresqlUsername }}
{{- else -}}
{{- required "A valid .Values.appConfig.backend.database.connection.user is required when postgresql is not enabled" .Values.appConfig.backend.database.connection.user -}}
{{- end -}}
{{- end -}}
{{/*
Postgres user for lighthouse
*/}}
{{- define "lighthouse.postgresql.user" -}}
{{- if .Values.postgresql.enabled }}
{{- .Values.global.postgresql.postgresqlUsername }}
{{- else -}}
{{- required "A valid .Values.lighthouse.database.connection.user is required when postgresql is not enabled" .Values.lighthouse.database.connection.user -}}
{{- end -}}
{{- end -}}
{{/*
Postgres password secret for backend
*/}}
{{- define "backend.postgresql.passwordSecret" -}}
{{- if .Values.postgresql.enabled }}
{{- template "backstage.postgresql.fullname" . }}
{{- else -}}
{{ $secretName := (printf "%s-backend-postgres" (include "backstage.fullname" . )) }}
{{- required "A valid .Values.appConfig.backend.database.connection.password is required when postgresql is not enabled" $secretName -}}
{{- end -}}
{{- end -}}
{{/*
Postgres password for lighthouse
*/}}
{{- define "lighthouse.postgresql.passwordSecret" -}}
{{- if .Values.postgresql.enabled }}
{{- template "backstage.postgresql.fullname" . }}
{{- else -}}
{{ $secretName := (printf "%s-lighthouse-postgres" (include "backstage.fullname" . )) }}
{{- required "A valid .Values.lighthouse.database.connection.password is required when postgresql is not enabled" $secretName -}}
{{- end -}}
{{- end -}}
{{/*
app-config file name
*/}}
{{- define "backstage.appConfigFilename" -}}
{{- "app-config.development.yaml" -}}
{{- end -}}
@@ -0,0 +1,79 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "backstage.fullname" . }}-backend
spec:
replicas: {{ .Values.backend.replicaCount }}
selector:
matchLabels:
app: backstage
component: backend
template:
metadata:
annotations:
ad.datadoghq.com/backstage.logs: '[{"source":"backstage","service":"backend"}]'
labels:
app: backstage
component: backend
spec:
containers:
- name: {{ .Chart.Name }}-backend
image: {{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}
imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
ports:
- containerPort: {{ .Values.backend.containerPort }}
resources:
{{- toYaml .Values.backend.resources | nindent 12 }}
envFrom:
- secretRef:
name: {{ include "backstage.fullname" . }}-backend
- configMapRef:
name: {{ include "backstage.fullname" . }}-app-env
- configMapRef:
name: {{ include "backstage.fullname" . }}-auth
env:
- name: NODE_ENV
value: {{ .Values.backend.nodeEnv | default "development" }}
- name: APP_CONFIG_backend_database_connection_password
valueFrom:
secretKeyRef:
name: {{ include "backend.postgresql.passwordSecret" .}}
key: postgresql-password
volumeMounts:
- name: postgres-ca
mountPath: {{ include "backstage.backend.postgresCaDir" . }}
- name: app-config
mountPath: {{ printf "/usr/src/app/%s" (include "backstage.appConfigFilename" .) }}
subPath: {{ include "backstage.appConfigFilename" . }}
volumes:
- name: postgres-ca
configMap:
name: {{ include "backstage.fullname" . }}-postgres-ca
- name: app-config
configMap:
name: {{ include "backstage.fullname" . }}-app-config
{{- if .Values.backend.enabled }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "backend.serviceName" . }}
spec:
ports:
- port: 80
targetPort: {{ .Values.backend.containerPort }}
selector:
app: backstage
component: backend
type: ClusterIP
{{- end }}
@@ -0,0 +1,21 @@
{{- if .Values.backend.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "backstage.fullname" . }}-backend
type: Opaque
stringData:
AUTH_GOOGLE_CLIENT_SECRET: {{ .Values.auth.google.clientSecret }}
AUTH_GITHUB_CLIENT_SECRET: {{ .Values.auth.github.clientSecret }}
AUTH_GITLAB_CLIENT_SECRET: {{ .Values.auth.gitlab.clientSecret }}
AUTH_OKTA_CLIENT_SECRET: {{ .Values.auth.okta.clientSecret }}
AUTH_OAUTH2_CLIENT_SECRET: {{ .Values.auth.oauth2.clientSecret }}
AUTH_AUTH0_CLIENT_SECRET: {{ .Values.auth.auth0.clientSecret }}
AUTH_MICROSOFT_CLIENT_SECRET: {{ .Values.auth.microsoft.clientSecret }}
SENTRY_TOKEN: {{ .Values.auth.sentryToken }}
ROLLBAR_ACCOUNT_TOKEN: {{ .Values.auth.rollbarAccountToken }}
CIRCLECI_AUTH_TOKEN: {{ .Values.auth.circleciAuthToken }}
GITHUB_TOKEN: {{ .Values.auth.githubToken }}
GITLAB_TOKEN: {{ .Values.auth.gitlabToken }}
AZURE_TOKEN: {{ .Values.auth.azure.api.token }}
{{- end }}
@@ -0,0 +1,27 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "backstage.fullname" . }}-app-config
data:
{{ include "backstage.appConfigFilename" . | indent 2 }}: |
{{ tpl (.Files.Get "files/app-config.development.yaml.tpl") . | indent 4 }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "backstage.fullname" . }}-app-env
data:
APP_CONFIG_app_baseUrl: {{ .Values.appConfig.app.baseUrl | quote | quote }}
APP_CONFIG_app_title: {{ .Values.appConfig.app.title | quote | quote }}
APP_CONFIG_backend_baseUrl: {{ .Values.appConfig.backend.baseUrl | quote | quote }}
APP_CONFIG_backend_cors_origin: {{ .Values.appConfig.backend.cors.origin | quote | quote }}
APP_CONFIG_techdocs_storageUrl: {{ .Values.appConfig.techdocs.storageUrl | quote | quote }}
APP_CONFIG_techdocs_requestUrl: {{ .Values.appConfig.techdocs.requestUrl | quote | quote }}
APP_CONFIG_lighthouse_baseUrl: {{ .Values.appConfig.lighthouse.baseUrl | quote | quote }}
APP_CONFIG_backend_database_connection_ssl_rejectUnauthorized: "false"
APP_CONFIG_auth_providers_github_development_appOrigin: {{ .Values.appConfig.auth.providers.github.development.appOrigin | quote | quote }}
APP_CONFIG_auth_providers_google_development_appOrigin: {{ .Values.appConfig.auth.providers.google.development.appOrigin | quote | quote }}
APP_CONFIG_auth_providers_gitlab_development_appOrigin: {{ .Values.appConfig.auth.providers.gitlab.development.appOrigin | quote | quote }}
APP_CONFIG_auth_providers_okta_development_appOrigin: {{ .Values.appConfig.auth.providers.okta.development.appOrigin | quote | quote }}
APP_CONFIG_auth_providers_oauth2_development_appOrigin: {{ .Values.appConfig.auth.providers.oauth2.development.appOrigin | quote | quote }}
@@ -0,0 +1,21 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "backstage.fullname" . }}-auth
data:
AUTH_GOOGLE_CLIENT_ID: {{ .Values.auth.google.clientId }}
AUTH_GITHUB_CLIENT_ID: {{ .Values.auth.github.clientId }}
AUTH_GITLAB_CLIENT_ID: {{ .Values.auth.gitlab.clientId }}
# This should not be prefixed with AUTH_. This could be a typo in the Backstage app config.
# Regardless, it is not decided by me.
GITLAB_BASE_URL: {{ .Values.auth.gitlab.baseUrl }}
AUTH_OKTA_CLIENT_ID: {{ .Values.auth.okta.clientId }}
AUTH_OKTA_AUDIENCE: {{ .Values.auth.okta.audience }}
AUTH_OAUTH2_CLIENT_ID: {{ .Values.auth.oauth2.clientId }}
AUTH_OAUTH2_AUTH_URL: {{ .Values.auth.oauth2.authUrl }}
AUTH_OAUTH2_TOKEN_URL: {{ .Values.auth.oauth2.tokenUrl }}
AUTH_AUTH0_CLIENT_ID: {{ .Values.auth.auth0.clientId }}
AUTH_AUTH0_DOMAIN: {{ .Values.auth.auth0.domain }}
AUTH_MICROSOFT_CLIENT_ID: {{ .Values.auth.microsoft.clientId }}
AUTH_MICROSOFT_TENANT_ID: {{ .Values.auth.microsoft.tenantId }}
@@ -0,0 +1,59 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "backstage.fullname" . }}-frontend
spec:
replicas: {{ .Values.frontend.replicaCount }}
selector:
matchLabels:
app: backstage
component: frontend
template:
metadata:
annotations:
ad.datadoghq.com/backstage.logs: '[{"source":"backstage","service":"frontend"}]'
labels:
app: backstage
component: frontend
spec:
containers:
- name: {{ .Chart.Name }}-frontend
image: {{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
ports:
- containerPort: {{ .Values.frontend.containerPort }}
resources:
{{- toYaml .Values.backend.resources | nindent 12 }}
envFrom:
- configMapRef:
name: {{ include "backstage.fullname" . }}-app-env
volumeMounts:
- name: app-config
mountPath: {{ printf "/usr/share/nginx/html/static/%s" (include "backstage.appConfigFilename" .) }}
subPath: {{ include "backstage.appConfigFilename" . }}
volumes:
- name: app-config
configMap:
name: {{ include "backstage.fullname" . }}-app-config
{{- if .Values.frontend.enabled }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "frontend.serviceName" . }}
spec:
ports:
- port: 80
targetPort: {{ .Values.frontend.containerPort }}
selector:
app: backstage
component: frontend
type: ClusterIP
{{- end }}
@@ -0,0 +1,78 @@
{{- $frontendUrl := urlParse .Values.appConfig.app.baseUrl}}
{{- $backendUrl := urlParse .Values.appConfig.backend.baseUrl}}
{{- $lighthouseUrl := urlParse .Values.appConfig.lighthouse.baseUrl}}
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: {{ include "backstage.fullname" . }}-ingress
{{- with .Values.ingress.annotations }}
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($scheme = https) {
add_header Strict-Transport-Security "max-age=0;";
}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
rules:
- host: {{ $frontendUrl.host }}
http:
paths:
- path: /
backend:
serviceName: {{ include "frontend.serviceName" . }}
servicePort: 80
{{/* Route the backend inside the same hostname as the frontend when they are the same */}}
{{- if eq $frontendUrl.host $backendUrl.host}}
- path: /api
backend:
serviceName: {{ include "backend.serviceName" . }}
servicePort: 80
{{/* Route the backend through a different host */}}
{{- else -}}
- host: {{ $backendUrl.host }}
http:
paths:
- path: {{ $backendUrl.path | default "/" }}
backend:
serviceName: {{ include "backend.serviceName" . }}
servicePort: 80
{{- end }}
{{/* Route lighthouse through a different host */}}
{{- if not ( eq $frontendUrl.host $lighthouseUrl.host ) }}
- host: {{ $lighthouseUrl.host }}
http:
paths:
- path: {{ $lighthouseUrl.path | default "/" }}
backend:
serviceName: {{ include "lighthouse.serviceName" . }}
servicePort: 80
{{- else }}
{{/* Route lighthouse by path with re-write rules when it is hosted under the same hostname */}}
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: {{ include "backstage.fullname" . }}-ingress-lighthouse
{{- with .Values.ingress.annotations }}
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($scheme = https) {
add_header Strict-Transport-Security "max-age=0;";
}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
rules:
- host: {{ $frontendUrl.host }}
http:
paths:
- path: {{$lighthouseUrl.path}}(/|$)(.*)
backend:
serviceName: {{ include "lighthouse.serviceName" . }}
servicePort: 80
{{- end }}
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "backstage.fullname" . -}}-lighthouse
data:
PGDATABASE: {{ .Values.lighthouse.database.connection.database | quote }}
PGUSER: {{ include "lighthouse.postgresql.user" . | quote }}
PGPORT: {{ include "lighthouse.postgresql.port" . | quote }}
PGHOST: {{ include "lighthouse.postgresql.host" . | quote }}
PGPATH_TO_CA: {{ include "backstage.lighthouse.postgresCaFilename" . | quote }}
@@ -0,0 +1,74 @@
{{- if .Values.lighthouse.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "backstage.fullname" . }}-lighthouse
spec:
replicas: {{ .Values.lighthouse.replicaCount }}
selector:
matchLabels:
app: backstage
component: lighthouse-audit-service
template:
metadata:
annotations:
ad.datadoghq.com/backstage.logs: '[{"source":"backstage","service":"lighthouse"}]'
labels:
app: backstage
component: lighthouse-audit-service
spec:
containers:
- name: lighthouse-audit-service
image: {{ .Values.lighthouse.image.repository }}:{{ .Values.lighthouse.image.tag }}
imagePullPolicy: {{ .Values.lighthouse.image.pullPolicy }}
ports:
- containerPort: {{ .Values.lighthouse.containerPort }}
resources:
{{- toYaml .Values.lighthouse.resources | nindent 12 }}
envFrom:
- configMapRef:
name: {{ include "backstage.fullname" . -}}-lighthouse
- configMapRef:
name: {{ include "backstage.fullname" . }}-app-env
env:
- name: LAS_PORT
value: {{ .Values.lighthouse.containerPort | quote }}
- name: LAS_CORS
value: "true"
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: {{ include "lighthouse.postgresql.passwordSecret" . }}
key: postgresql-password
volumeMounts:
- name: postgres-ca
mountPath: {{ include "backstage.lighthouse.postgresCaDir" . }}
volumes:
- name: postgres-ca
configMap:
name: {{ include "backstage.fullname" . }}-postgres-ca
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "lighthouse.serviceName" . }}
spec:
ports:
- port: 80
targetPort: {{ .Values.lighthouse.containerPort }}
selector:
app: backstage
component: lighthouse-audit-service
type: ClusterIP
{{- end }}
@@ -0,0 +1,21 @@
{{- if .Values.postgresql.enabled }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "backstage.fullname" . }}-postgres-ca
labels:
app: {{ include "backstage.postgresql.fullname" . }}
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": "pre-install"
"helm.sh/hook-delete-policy": "before-hook-creation"
data:
{{ .Values.global.postgresql.caFilename }}: |
{{ include "backstage.postgresql.generateCA" . | indent 4}}
{{- else }}
{{- $caConfig := printf "%s-postgres-ca" (include "backstage.fullname" .) }}
{{- if not ( lookup "v1" "ConfigMap" .Release.Namespace $caConfig ) }}
{{- fail (printf "\n\nPlease create the '%s' configmap with the CA certificate for your existing postgresql: kubectl create configmap %s --from-file=ca.crt" $caConfig $caConfig) }}
{{- end }}
{{- end }}
@@ -0,0 +1,16 @@
{{- if .Values.postgresql.enabled }}
---
apiVersion: v1
kind: Secret
type: kubernetes.io/tls
metadata:
name: {{ required ".Values.postgresql.tls.certificatesSecret is required" .Values.postgresql.tls.certificatesSecret }}
labels:
app: {{ include "backstage.postgresql.fullname" . }}
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": "pre-install"
"helm.sh/hook-delete-policy": "before-hook-creation"
data:
{{ include "generateCerts" . | indent 2 }}
{{- end }}
@@ -0,0 +1,14 @@
{{- if .Values.postgresql.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ required ".Values.postgresql.initdbScriptsSecret is required" .Values.postgresql.initdbScriptsSecret }}
annotations:
"helm.sh/hook": "pre-install"
"helm.sh/hook-delete-policy": "before-hook-creation"
type: Opaque
data:
create-backend-dbs.sql: |
{{ tpl (.Files.Get "files/create-backend-dbs.sql") . | b64enc }}
{{- end }}
@@ -0,0 +1,30 @@
{{- if not .Values.postgresql.enabled }}
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: {{ include "backend.postgresql.passwordSecret" . }}
labels:
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": "pre-install"
"helm.sh/hook-delete-policy": "before-hook-creation"
data:
postgresql-password: {{ .Values.appConfig.backend.database.connection.password | b64enc }}
{{- end }}
{{- if not .Values.postgresql.enabled }}
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: {{ include "lighthouse.postgresql.passwordSecret" . }}
labels:
release: {{ .Release.Name }}
annotations:
"helm.sh/hook": "pre-install"
"helm.sh/hook-delete-policy": "before-hook-creation"
data:
postgresql-password: {{ .Values.lighthouse.database.connection.password | b64enc }}
{{- end }}
@@ -0,0 +1,23 @@
---
apiVersion: v1
kind: Pod
metadata:
name: {{ include "backstage.fullname" . -}}-test-app-connection
annotations:
"helm.sh/hook": test
spec:
containers:
- name: test-app
image: busybox
command:
- /bin/sh
- -ecx
- |
echo -e "===== Testing the connection with the frontend...\n"
wget -q -O - {{ printf "%s.%s" (include "frontend.serviceName" .) .Release.Namespace | quote }}
echo -e "\n\n===== Testing the connection with the backend...\n"
wget -q -O - {{ printf "http://%s.%s/catalog/entities" (include "backend.serviceName" .) .Release.Namespace | quote }}
echo -e "\n\n===== Testing the connection with the lighthouse plugin...\n"
wget -q -O - {{ printf "%s.%s/v1/audits" (include "lighthouse.serviceName" .) .Release.Namespace | quote }}
echo -e "\n"
restartPolicy: Never
@@ -0,0 +1,33 @@
{{- if .Values.postgresql.enabled}}
---
apiVersion: v1
kind: Pod
metadata:
name: {{ include "backstage.name" . -}}-test-postgres
annotations:
"helm.sh/hook": test
spec:
containers:
- name: postgresql-client
image: bitnami/postgresql
env:
- name: PG_HOST
value: {{ include "postgresql.serviceName" . | quote }}
- name: PG_PORT
value: {{ .Values.postgresql.service.port | quote }}
- name: PG_USER
value: {{ .Values.global.postgresql.postgresqlUsername | quote }}
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: {{ include "backend.postgresql.passwordSecret" .}}
key: postgresql-password
- name: PG_DBNAME
value: {{ .Values.appConfig.backend.database.connection.database }}
command:
- /bin/bash
- -ecx
- |
psql --host=$PG_HOST --port=$PG_PORT --username=$PG_USER --dbname=$PG_DBNAME --no-password
restartPolicy: Never
{{- end }}
+245
View File
@@ -0,0 +1,245 @@
# Default values for backstage.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
frontend:
enabled: true
replicaCount: 1
image:
repository: martinaif/backstage-k8s-demo-frontend
tag: test1
pullPolicy: IfNotPresent
containerPort: 80
resources:
requests:
memory: 128Mi
limits:
memory: 256Mi
backend:
enabled: true
nodeEnv: development
demoData: true
replicaCount: 1
image:
repository: martinaif/backstage-k8s-demo-backend
tag: test1
pullPolicy: IfNotPresent
containerPort: 7000
resources:
requests:
memory: 512Mi
limits:
memory: 1024Mi
lighthouse:
enabled: true
replicaCount: 1
image:
repository: roadiehq/lighthouse-audit-service
tag: latest
pullPolicy: IfNotPresent
containerPort: 3003
resources:
requests:
memory: 128Mi
limits:
memory: 256Mi
database:
connection:
port:
host:
user:
password:
database: lighthouse_audit_service
pathToDatabaseCa:
nameOverride: ''
fullnameOverride: ''
ingress:
annotations:
kubernetes.io/ingress.class: nginx
global:
postgresql:
postgresqlUsername: backend-user
caFilename: ca.crt
postgresql:
enabled: true
nameOverride: postgresql
tls:
enabled: true
certificatesSecret: backstage-postgresql-certs
certFilename: tls.crt
certKeyFilename: tls.key
volumePermissions:
enabled: true
initdbScriptsSecret: backstage-postgresql-initdb
appConfig:
app:
baseUrl: https://demo.example.com
title: Backstage
backend:
baseUrl: https://demo.example.com
listen:
port: 7000
cors:
origin: https://demo.example.com
database:
client: pg
connection:
database: backstage_plugin_catalog
host:
user:
port:
password:
ssl:
rejectUnauthorized: false
ca:
sentry:
organization: spotify
techdocs:
storageUrl: https://demo.example.com/api/techdocs/static/docs
requestUrl: https://demo.example.com/api/techdocs
lighthouse:
baseUrl: https://demo.example.com/lighthouse-api
rollbar:
organization: roadie
# Auth config has recently moved into the app config file in upstream Backstage. However,
# most of this config simply mandates that items like the client id and client secret should
# be picked up from the environment variables named below. Those environment variables are
# set in this helm controlled environment by the 'auth' configuration below this section.
# Thus, the only key in this config which directly controls an app config is the
# auth.providers.github.development.appOrigin property.
auth:
providers:
google:
development:
appOrigin: 'http://localhost:3000/'
secure: false
clientId:
$secret:
env: AUTH_GOOGLE_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GOOGLE_CLIENT_SECRET
github:
development:
appOrigin: 'http://localhost:3000/'
secure: false
clientId:
$secret:
env: AUTH_GITHUB_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GITHUB_CLIENT_SECRET
enterpriseInstanceUrl:
$secret:
env: AUTH_GITHUB_ENTERPRISE_INSTANCE_URL
gitlab:
development:
appOrigin: 'http://localhost:3000/'
secure: false
clientId:
$secret:
env: AUTH_GITLAB_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GITLAB_CLIENT_SECRET
audience:
$secret:
env: GITLAB_BASE_URL
okta:
development:
appOrigin: 'http://localhost:3000/'
secure: false
clientId:
$secret:
env: AUTH_OKTA_CLIENT_ID
clientSecret:
$secret:
env: AUTH_OKTA_CLIENT_SECRET
audience:
$secret:
env: AUTH_OKTA_AUDIENCE
oauth2:
development:
appOrigin: 'http://localhost:3000/'
secure: false
clientId:
$secret:
env: AUTH_OAUTH2_CLIENT_ID
clientSecret:
$secret:
env: AUTH_OAUTH2_CLIENT_SECRET
authorizationURL:
$secret:
env: AUTH_OAUTH2_AUTH_URL
tokenURL:
$secret:
env: AUTH_OAUTH2_TOKEN_URL
auth0:
development:
clientId:
$secret:
env: AUTH_AUTH0_CLIENT_ID
clientSecret:
$secret:
env: AUTH_AUTH0_CLIENT_SECRET
domain:
$secret:
env: AUTH_AUTH0_DOMAIN
microsoft:
development:
clientId:
$secret:
env: AUTH_MICROSOFT_CLIENT_ID
clientSecret:
$secret:
env: AUTH_MICROSOFT_CLIENT_SECRET
tenantId:
$secret:
env: AUTH_MICROSOFT_TENANT_ID
auth:
google:
clientId: a
clientSecret: a
github:
clientId: c
clientSecret: c
gitlab:
clientId: b
clientSecret: b
baseUrl: b
okta:
clientId: b
clientSecret: b
audience: b
oauth2:
clientId: b
clientSecret: b
authUrl: b
tokenUrl: b
auth0:
clientId: b
clientSecret: b
domain: b
microsoft:
clientId: f
clientSecret: f
tenantId: f
azure:
api:
token: h
sentryToken: e
rollbarAccountToken: f
# This is a 'Personal Access Token'
circleciAuthToken: r
# Used by the scaffolder to create GitHub repos. Must have 'repo' scope.
githubToken: g
gitlabToken: g
-12
View File
@@ -1,12 +0,0 @@
# Make sure that before you
# run the docker-compose that you have run
# $ yarn docker-build
version: '3'
services:
backstage:
image: 'example-backend:latest'
ports:
- '7000:7000'
environment:
NODE_ENV: development
+4 -3
View File
@@ -65,9 +65,10 @@ All `app-config.yaml` files inside the monorepo root and package root are
considered, as are files with additional `local` and environment affixes such as
`development`, for example `app-config.local.yaml`,
`app-config.production.yaml`, and `app-config.development.local.yaml`. Which
environment config files are loaded is determined by the `NODE_ENV` environment
variable. Local configuration files are always loaded, but are meant for local
development overrides and should typically be `.gitignore`'d.
environment config files are loaded is determined by the `APP_ENV` environment
variable, or `NODE_ENV` if it is not set. Local configuration files are always
loaded, but are meant for local development overrides and should typically be
`.gitignore`'d.
All loaded configuration files are merged together using the following rules:
+69
View File
@@ -0,0 +1,69 @@
---
id: deployment-helm
title: Helm
description: Documentation on Kubernetes and Helm Deployment
---
# Helm charts
An example Backstage app can be deployed in Kubernetes using the [Backstage Helm
charts][backstage-helm-charts]
First, choose a DNS name where backstage will be hosted create a yaml file for
your custom configuration.
```
appConfig:
app:
baseUrl: https://backstage.mydomain.com
title: Backstage
backend:
baseUrl: https://backstage.mydomain.com
cors:
origin: https://backstage.mydomain.com
lighthouse:
baseUrl: https://backstage.mydomain.com/lighthouse-api
techdocs:
storageUrl: https://backstage.mydomain.com/api/techdocs/static/docs
requestUrl: https://backstage.mydomain.com/api/techdocs
```
Then use it to run:
```
git clone https://github.com/spotify/backstage.git
cd contrib/chart/backstage
helm dependency update
helm install -f backstage-mydomain.yaml backstage .
```
This command will deploy the following pieces:
- Backstage frontend
- Backstage backend with scaffolder and auth plugins
- (optional) a PostgreSQL instance
- lighthouse plugin
- ingress
After a few minutes Backstage should be up and running in your cluster under the
DNS specified earlier.
Make sure to create the appropriate DNS entry in your infrastructure. To find
the public IP address run:
```bash
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
backstage-ingress * 123.1.2.3 80 17m
```
> **NOTE**: this is not a production ready deployment.
For more information on how to customize the deployment check the
[README][charts-readme].
[backstage-helm-charts]:
(https://github.com/spotify/backstage/tree/master/contrib/chart/backstage)
[charts-readme]:
(https://github.com/spotify/backstage/tree/master/contrib/chart/backstage/README.md)
+1 -12
View File
@@ -13,18 +13,7 @@ Run the following commands if you have Docker environment
```bash
$ yarn install
$ yarn docker-build
$ docker run --rm -it -p 7000:7000 -e NODE_ENV=development example-backend:latest
$ docker run --rm -it -p 7000:7000 -e APP_ENV=production -e NODE_ENV=development example-backend:latest
```
Then open http://localhost/ on your browser.
### Running with `docker-compose`
There is also a `docker-compose.yaml` that you can use to replace the previous
`docker run` command:
```bash
$ yarn install
$ yarn docker-build
$ docker-compose up
```
+1 -6
View File
@@ -66,12 +66,6 @@ guidelines to get started.
The platform APIs and features are stable and can be depended on for
production use. After this plugins will require little to no maintenance.
- **Backstage Design System** - By providing design guidelines for common plugin
layouts together, rich set of reusable UI components
([Storybook](https://backstage.io/storybook)) and Figma design resources. The
Design System will make it easy to design and build plugins that are
consistent across the platform -- supporting both developers and designers.
- Further improvements to platform documentation
### Plugins
@@ -115,6 +109,7 @@ Chances are that someone will jump in and help build it.
### Completed milestones ✅
- [Backstage Design System 💅](https://backstage.io/blog/2020/09/30/backstage-design-system)
- [Cost Insights plugin 💸](https://engineering.atspotify.com/2020/09/29/managing-clouds-from-the-ground-up-cost-engineering-at-spotify/)
- [Donate Backstage to the CNCF 🎉](https://backstage.io/blog/2020/09/23/backstage-cncf-sandbox)
- [TechDocs v1](https://backstage.io/blog/2020/09/08/announcing-tech-docs)
+1 -1
View File
@@ -2,5 +2,5 @@
"packages": ["packages/*", "plugins/*"],
"npmClient": "yarn",
"useWorkspaces": true,
"version": "0.1.1-alpha.24"
"version": "0.1.1-alpha.25"
}
@@ -40,4 +40,4 @@ We are really excited to see all the amazing plugins that have already been buil
What plugins would you like to see in the Plugin Marketplace? [Tell us](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME)!
_Special shout-out to community member [Iain Billett](https://github.com/iain-b) from Roadie for helping build and contribute the [Plugin Marketplace page](https://backstage.io/plugins) (as his first PR no less!)._
_Special shout-out to community member [Iain Billett](https://github.com/iain-b) from [Roadie](https://roadie.io) for helping build and contribute the [Plugin Marketplace page](https://backstage.io/plugins) (as his first PR no less!)._
+13 -13
View File
@@ -1,8 +1,17 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
/*
* Copyright 2020 Backstage Project Authors.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* 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 React = require('react');
@@ -82,15 +91,6 @@ class Footer extends React.Component {
)}
</div>
</section>
<a
href={this.props.config.fossWebsite}
target="_blank"
rel="noreferrer noopener"
className="spotifyOpenSource"
>
Made with <span></span> at {this.props.config.organizationName}
</a>
<p className="copyright">{this.props.config.copyright}</p>
</footer>
);
@@ -0,0 +1,9 @@
---
title: GitHub Insights
author: roadie.io
authorUrl: https://roadie.io
category: Monitoring
description: View GitHub Insights for your components in Backstage.
documentation: https://roadie.io/backstage/plugins/github-insights
iconUrl: https://roadie.io/static/2ad5123c425908efde0c922d707e737b/06c84/code-icon.png
npmPackageName: '@roadiehq/backstage-plugin-github-insights'
+1 -1
View File
@@ -78,7 +78,7 @@ const siteConfig = {
},
// This copyright info is used in /core/Footer.js and blog RSS/Atom feeds.
copyright: `Copyright © ${new Date().getFullYear()} Spotify AB`,
copyright: `Copyright © ${new Date().getFullYear()} Backstage Project Authors. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page: https://www.linuxfoundation.org/trademark-usage`,
highlight: {
// Highlight.js theme to use for syntax highlighting in code blocks.
+7
View File
@@ -1084,3 +1084,10 @@ code {
margin-bottom: 40px;
margin-top: 20px;
}
.nav-footer .copyright {
width: 600px;
color: #fff;
margin: auto;
font-size: 10pt;
}
+1 -1
View File
@@ -38,7 +38,7 @@
},
"version": "1.0.0",
"devDependencies": {
"@changesets/cli": "2.10.2",
"@changesets/cli": "^2.11.0",
"@spotify/eslint-config-oss": "^1.0.1",
"@spotify/prettier-config": "^8.0.0",
"concurrently": "^5.2.0",
+32 -28
View File
@@ -1,41 +1,43 @@
{
"name": "example-app",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": true,
"bundled": true,
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.24",
"@backstage/cli": "^0.1.1-alpha.24",
"@backstage/core": "^0.1.1-alpha.24",
"@backstage/plugin-api-docs": "^0.1.1-alpha.24",
"@backstage/plugin-catalog": "^0.1.1-alpha.24",
"@backstage/plugin-circleci": "^0.1.1-alpha.24",
"@backstage/plugin-cloudbuild": "^0.1.1-alpha.24",
"@backstage/plugin-cost-insights": "^0.1.1-alpha.24",
"@backstage/plugin-explore": "^0.1.1-alpha.24",
"@backstage/plugin-gcp-projects": "^0.1.1-alpha.24",
"@backstage/plugin-github-actions": "^0.1.1-alpha.24",
"@backstage/plugin-gitops-profiles": "^0.1.1-alpha.24",
"@backstage/plugin-graphiql": "^0.1.1-alpha.24",
"@backstage/plugin-jenkins": "^0.1.1-alpha.24",
"@backstage/plugin-kubernetes": "^0.1.1-alpha.24",
"@backstage/plugin-lighthouse": "^0.1.1-alpha.24",
"@backstage/plugin-newrelic": "^0.1.1-alpha.24",
"@backstage/plugin-register-component": "^0.1.1-alpha.24",
"@backstage/plugin-rollbar": "^0.1.1-alpha.24",
"@backstage/plugin-scaffolder": "^0.1.1-alpha.24",
"@backstage/plugin-sentry": "^0.1.1-alpha.24",
"@backstage/plugin-tech-radar": "^0.1.1-alpha.24",
"@backstage/plugin-techdocs": "^0.1.1-alpha.24",
"@backstage/plugin-welcome": "^0.1.1-alpha.24",
"@backstage/plugin-user-settings": "^0.1.1-alpha.24",
"@backstage/test-utils": "^0.1.1-alpha.24",
"@backstage/theme": "^0.1.1-alpha.24",
"@backstage/catalog-model": "^0.1.1-alpha.25",
"@backstage/cli": "^0.1.1-alpha.25",
"@backstage/core": "^0.1.1-alpha.25",
"@backstage/plugin-api-docs": "^0.1.1-alpha.25",
"@backstage/plugin-catalog": "^0.1.1-alpha.25",
"@backstage/plugin-circleci": "^0.1.1-alpha.25",
"@backstage/plugin-cloudbuild": "^0.1.1-alpha.25",
"@backstage/plugin-cost-insights": "^0.1.1-alpha.25",
"@backstage/plugin-explore": "^0.1.1-alpha.25",
"@backstage/plugin-gcp-projects": "^0.1.1-alpha.25",
"@backstage/plugin-github-actions": "^0.1.1-alpha.25",
"@backstage/plugin-gitops-profiles": "^0.1.1-alpha.25",
"@backstage/plugin-graphiql": "^0.1.1-alpha.25",
"@backstage/plugin-jenkins": "^0.1.1-alpha.25",
"@backstage/plugin-kubernetes": "^0.1.1-alpha.25",
"@backstage/plugin-lighthouse": "^0.1.1-alpha.25",
"@backstage/plugin-newrelic": "^0.1.1-alpha.25",
"@backstage/plugin-register-component": "^0.1.1-alpha.25",
"@backstage/plugin-rollbar": "^0.1.1-alpha.25",
"@backstage/plugin-scaffolder": "^0.1.1-alpha.25",
"@backstage/plugin-sentry": "^0.1.1-alpha.25",
"@backstage/plugin-tech-radar": "^0.1.1-alpha.25",
"@backstage/plugin-techdocs": "^0.1.1-alpha.25",
"@backstage/plugin-user-settings": "^0.1.1-alpha.25",
"@backstage/plugin-welcome": "^0.1.1-alpha.25",
"@backstage/test-utils": "^0.1.1-alpha.25",
"@backstage/theme": "^0.1.1-alpha.25",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@octokit/rest": "^18.0.0",
"@roadiehq/backstage-plugin-github-insights": "^0.2.2",
"@roadiehq/backstage-plugin-github-pull-requests": "^0.4.3",
"@roadiehq/backstage-plugin-travis-ci": "^0.2.3",
"dayjs": "^1.9.1",
"history": "^5.0.0",
"prop-types": "^15.7.2",
"react": "^16.12.0",
@@ -44,6 +46,7 @@
"react-router": "6.0.0-beta.0",
"react-router-dom": "6.0.0-beta.0",
"react-use": "^15.3.3",
"regression": "^2.0.1",
"zen-observable": "^0.8.15"
},
"devDependencies": {
@@ -55,6 +58,7 @@
"@types/jquery": "^3.3.34",
"@types/node": "^12.0.0",
"@types/react-dom": "^16.9.8",
"@types/regression": "^2.0.0",
"@types/zen-observable": "^0.8.0",
"cross-env": "^7.0.0",
"cypress": "^4.2.0",
@@ -40,6 +40,13 @@ import { Router as ApiDocsRouter } from '@backstage/plugin-api-docs';
import { Router as SentryRouter } from '@backstage/plugin-sentry';
import { EmbeddedDocsRouter as DocsRouter } from '@backstage/plugin-techdocs';
import { Router as KubernetesRouter } from '@backstage/plugin-kubernetes';
import {
Router as GitHubInsightsRouter,
isPluginApplicableToEntity as isGitHubAvailable,
ReadMeCard,
LanguagesCard,
ReleasesCard,
} from '@roadiehq/backstage-plugin-github-insights';
import React, { ReactNode } from 'react';
import {
AboutCard,
@@ -120,6 +127,17 @@ const OverviewContent = ({ entity }: { entity: Entity }) => (
<AboutCard entity={entity} />
</Grid>
<RecentCICDRunsSwitcher entity={entity} />
{isGitHubAvailable(entity) && (
<>
<Grid item md={6}>
<LanguagesCard entity={entity} />
<ReleasesCard entity={entity} />
</Grid>
<Grid item md={6}>
<ReadMeCard entity={entity} maxHeight={350} />
</Grid>
</>
)}
{isLighthouseAvailable(entity) && (
<Grid item sm={4}>
<LastLighthouseAuditCard />
@@ -160,6 +178,11 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => (
title="Kubernetes"
element={<KubernetesRouter entity={entity} />}
/>
<EntityPageLayout.Content
path="/code-insights"
title="Code Insights"
element={<GitHubInsightsRouter entity={entity} />}
/>
</EntityPageLayout>
);
@@ -195,6 +218,11 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => (
title="Kubernetes"
element={<KubernetesRouter entity={entity} />}
/>
<EntityPageLayout.Content
path="/code-insights"
title="Code Insights"
element={<GitHubInsightsRouter entity={entity} />}
/>
</EntityPageLayout>
);
const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
+1
View File
@@ -36,4 +36,5 @@ export { plugin as GcpProjects } from '@backstage/plugin-gcp-projects';
export { plugin as Kubernetes } from '@backstage/plugin-kubernetes';
export { plugin as Cloudbuild } from '@backstage/plugin-cloudbuild';
export { plugin as CostInsights } from '@backstage/plugin-cost-insights';
export { plugin as GitHubInsights } from '@roadiehq/backstage-plugin-github-insights';
export { plugin as UserSettings } from '@backstage/plugin-user-settings';
@@ -15,16 +15,84 @@
*/
/* eslint-disable no-restricted-imports */
import dayjs from 'dayjs';
import regression, { DataPoint } from 'regression';
import {
CostInsightsApi,
Alert,
ChangeStatistic,
Cost,
CostInsightsApi,
DateAggregation,
Duration,
Project,
ProductCost,
exclusiveEndDateOf,
Group,
inclusiveStartDateOf,
Maybe,
ProductCost,
Project,
ProjectGrowthAlert,
ProjectGrowthData,
Trendline,
UnlabeledDataflowAlert,
UnlabeledDataflowData,
} from '@backstage/plugin-cost-insights';
function durationOf(intervals: string): Duration {
const match = intervals.match(/\/(?<duration>P\d+[DM])\//);
const { duration } = match!.groups!;
return duration as Duration;
}
function aggregationFor(
duration: Duration,
baseline: number,
): DateAggregation[] {
const days = dayjs(exclusiveEndDateOf(duration)).diff(
inclusiveStartDateOf(duration),
'day',
);
return [...Array(days).keys()].reduce(
(values: DateAggregation[], i: number): DateAggregation[] => {
const last = values.length ? values[values.length - 1].amount : baseline;
values.push({
date: dayjs(inclusiveStartDateOf(duration))
.add(i, 'day')
.format('YYYY-MM-DD'),
amount: last + (baseline / 20) * (Math.random() * 2 - 1),
});
return values;
},
[],
);
}
function trendlineOf(aggregation: DateAggregation[]): Trendline {
const data: ReadonlyArray<DataPoint> = aggregation.map(a => [
Date.parse(a.date) / 1000,
a.amount,
]);
const result = regression.linear(data, { precision: 5 });
return {
slope: result.equation[0],
intercept: result.equation[1],
};
}
function changeOf(aggregation: DateAggregation[]): ChangeStatistic {
const half = Math.ceil(aggregation.length / 2);
const before = aggregation
.slice(0, half)
.reduce((sum, a) => sum + a.amount, 0);
const after = aggregation
.slice(half, aggregation.length)
.reduce((sum, a) => sum + a.amount, 0);
return {
ratio: (after - before) / before,
amount: after - before,
};
}
export class ExampleCostInsightsClient implements CostInsightsApi {
private request(_: any, res: any): Promise<any> {
return new Promise(resolve => setTimeout(resolve, 0, res));
@@ -53,30 +121,17 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
metric: string | null,
intervals: string,
): Promise<Cost> {
const aggregation = aggregationFor(
durationOf(intervals),
metric ? 0.3 : 8_000,
);
const groupDailyCost: Cost = await this.request(
{ group, metric, intervals },
{
id: metric, // costs with null ids will appear as "All Projects" in Cost Overview panel
aggregation: [
{ date: '2020-08-01', amount: 75_000 / (metric ? 200_000 : 1) },
{ date: '2020-08-02', amount: 120_000 / (metric ? 200_000 : 1) },
{ date: '2020-08-03', amount: 110_000 / (metric ? 200_000 : 1) },
{ date: '2020-08-04', amount: 90_000 / (metric ? 200_000 : 1) },
{ date: '2020-08-05', amount: 80_000 / (metric ? 200_000 : 1) },
{ date: '2020-08-06', amount: 85_000 / (metric ? 200_000 : 1) },
{ date: '2020-08-07', amount: 82_500 / (metric ? 200_000 : 1) },
{ date: '2020-08-08', amount: 100_000 / (metric ? 200_000 : 1) },
{ date: '2020-08-09', amount: 130_000 / (metric ? 200_000 : 1) },
{ date: '2020-08-10', amount: 140_000 / (metric ? 200_000 : 1) },
],
change: {
ratio: 0.86,
amount: 65_000,
},
trendline: {
slope: 0,
intercept: 90_000,
},
aggregation: aggregation,
change: changeOf(aggregation),
trendline: trendlineOf(aggregation),
},
);
@@ -88,30 +143,17 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
metric: string | null,
intervals: string,
): Promise<Cost> {
const aggregation = aggregationFor(
durationOf(intervals),
metric ? 0.1 : 1_500,
);
const projectDailyCost: Cost = await this.request(
{ project, metric, intervals },
{
id: 'project-a',
aggregation: [
{ date: '2020-08-01', amount: 1000 },
{ date: '2020-08-02', amount: 2000 },
{ date: '2020-08-03', amount: 3000 },
{ date: '2020-08-04', amount: 4000 },
{ date: '2020-08-05', amount: 5000 },
{ date: '2020-08-06', amount: 6000 },
{ date: '2020-08-07', amount: 7000 },
{ date: '2020-08-08', amount: 8000 },
{ date: '2020-08-09', amount: 9000 },
{ date: '2020-08-10', amount: 10_000 },
],
change: {
ratio: 0.5,
amount: 10000,
},
trendline: {
slope: 0,
intercept: 0,
},
aggregation: aggregation,
change: changeOf(aggregation),
trendline: trendlineOf(aggregation),
},
);
@@ -122,9 +164,38 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
product: string,
group: string,
duration: Duration,
project: Maybe<string>,
): Promise<ProductCost> {
const projectProductInsights = await this.request(
{ product, group, duration, project },
{
aggregation: [80_000, 110_000],
change: {
ratio: 0.375,
amount: 30_000,
},
entities: [
{
id: null, // entities with null ids will be appear as "Unlabeled" in product panels
aggregation: [45_000, 50_000],
},
{
id: 'entity-a',
aggregation: [15_000, 20_000],
},
{
id: 'entity-b',
aggregation: [20_000, 30_000],
},
{
id: 'entity-e',
aggregation: [0, 10_000],
},
],
},
);
const productInsights: ProductCost = await this.request(
{ product, group, duration },
{ product, group, duration, project },
{
aggregation: [200_000, 250_000],
change: {
@@ -134,7 +205,7 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
entities: [
{
id: null, // entities with null ids will be appear as "Unlabeled" in product panels
aggregation: [45_000, 50_000],
aggregation: [15_000, 30_000],
},
{
id: 'entity-a',
@@ -172,36 +243,48 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
},
);
return productInsights;
return project ? projectProductInsights : productInsights;
}
async getAlerts(group: string): Promise<Alert[]> {
const alerts: Alert[] = await this.request({ group }, [
{
id: 'projectGrowth',
project: 'example-project',
periodStart: 'Q1 2020',
periodEnd: 'Q2 2020',
aggregation: [60_000, 120_000],
change: {
ratio: 1,
amount: 60000,
},
products: [
{
id: 'Compute Engine',
aggregation: [58_000, 118_000],
},
{
id: 'Cloud Dataflow',
aggregation: [1200, 1500],
},
{
id: 'Cloud Storage',
aggregation: [800, 500],
},
],
const projectGrowthData: ProjectGrowthData = {
project: 'example-project',
periodStart: 'Q2 2020',
periodEnd: 'Q3 2020',
aggregation: [60_000, 120_000],
change: {
ratio: 1,
amount: 60000,
},
products: [
{ id: 'Compute Engine', aggregation: [58_000, 118_000] },
{ id: 'Cloud Dataflow', aggregation: [1200, 1500] },
{ id: 'Cloud Storage', aggregation: [800, 500] },
],
};
const unlabeledDataflowData: UnlabeledDataflowData = {
periodStart: '2020-09-01',
periodEnd: '2020-09-30',
labeledCost: 6_200,
unlabeledCost: 7_000,
projects: [
{
id: 'example-project-1',
unlabeledCost: 5_000,
labeledCost: 3_000,
},
{
id: 'example-project-2',
unlabeledCost: 2_000,
labeledCost: 3_200,
},
],
};
const alerts: Alert[] = await this.request({ group }, [
new ProjectGrowthAlert(projectGrowthData),
new UnlabeledDataflowAlert(unlabeledDataflowData),
]);
return alerts;
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -29,10 +29,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/cli-common": "^0.1.1-alpha.24",
"@backstage/config": "^0.1.1-alpha.24",
"@backstage/config-loader": "^0.1.1-alpha.24",
"@backstage/test-utils": "^0.1.1-alpha.24",
"@backstage/cli-common": "^0.1.1-alpha.25",
"@backstage/config": "^0.1.1-alpha.25",
"@backstage/config-loader": "^0.1.1-alpha.25",
"@backstage/test-utils": "^0.1.1-alpha.25",
"@types/cors": "^2.8.6",
"@types/express": "^4.17.6",
"compression": "^1.7.4",
@@ -61,7 +61,7 @@
}
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.24",
"@backstage/cli": "^0.1.1-alpha.25",
"@types/compression": "^1.7.0",
"@types/http-errors": "^1.6.3",
"@types/morgan": "^1.9.0",
+2 -1
View File
@@ -21,9 +21,10 @@ import { loadConfig } from '@backstage/config-loader';
* Load configuration for a Backend
*/
export async function loadBackendConfig() {
/* eslint-disable-next-line no-restricted-syntax */
const paths = findPaths(__dirname);
const configs = await loadConfig({
env: process.env.NODE_ENV ?? 'development',
env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development',
rootPaths: [paths.targetRoot, paths.targetDir],
shouldReadSecrets: true,
});
+16 -16
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"private": true,
@@ -18,24 +18,24 @@
"migrate:create": "knex migrate:make -x ts"
},
"dependencies": {
"@backstage/backend-common": "^0.1.1-alpha.24",
"@backstage/catalog-model": "^0.1.1-alpha.24",
"@backstage/config": "^0.1.1-alpha.24",
"@backstage/plugin-app-backend": "^0.1.1-alpha.24",
"@backstage/plugin-auth-backend": "^0.1.1-alpha.24",
"@backstage/plugin-catalog-backend": "^0.1.1-alpha.24",
"@backstage/plugin-graphql-backend": "^0.1.1-alpha.24",
"@backstage/plugin-kubernetes-backend": "^0.1.1-alpha.24",
"@backstage/plugin-proxy-backend": "^0.1.1-alpha.24",
"@backstage/plugin-rollbar-backend": "^0.1.1-alpha.24",
"@backstage/plugin-scaffolder-backend": "^0.1.1-alpha.24",
"@backstage/plugin-sentry-backend": "^0.1.1-alpha.24",
"@backstage/plugin-techdocs-backend": "^0.1.1-alpha.24",
"@backstage/backend-common": "^0.1.1-alpha.25",
"@backstage/catalog-model": "^0.1.1-alpha.25",
"@backstage/config": "^0.1.1-alpha.25",
"@backstage/plugin-app-backend": "^0.1.1-alpha.25",
"@backstage/plugin-auth-backend": "^0.1.1-alpha.25",
"@backstage/plugin-catalog-backend": "^0.1.1-alpha.25",
"@backstage/plugin-graphql-backend": "^0.1.1-alpha.25",
"@backstage/plugin-kubernetes-backend": "^0.1.1-alpha.25",
"@backstage/plugin-proxy-backend": "^0.1.1-alpha.25",
"@backstage/plugin-rollbar-backend": "^0.1.1-alpha.25",
"@backstage/plugin-scaffolder-backend": "^0.1.1-alpha.25",
"@backstage/plugin-sentry-backend": "^0.1.1-alpha.25",
"@backstage/plugin-techdocs-backend": "^0.1.1-alpha.25",
"@gitbeaker/node": "^23.5.0",
"@octokit/rest": "^18.0.0",
"azure-devops-node-api": "^10.1.1",
"dockerode": "^3.2.0",
"example-app": "^0.1.1-alpha.24",
"example-app": "^0.1.1-alpha.25",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"knex": "^0.21.1",
@@ -45,7 +45,7 @@
"winston": "^3.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.24",
"@backstage/cli": "^0.1.1-alpha.25",
"@types/dockerode": "^2.5.32",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/catalog-model",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -20,7 +20,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/config": "^0.1.1-alpha.24",
"@backstage/config": "^0.1.1-alpha.25",
"@types/json-schema": "^7.0.5",
"@types/yup": "^0.28.2",
"json-schema": "^0.2.5",
@@ -29,7 +29,7 @@
"yup": "^0.29.1"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.24",
"@backstage/cli": "^0.1.1-alpha.25",
"@types/express": "^4.17.6",
"@types/jest": "^26.0.7",
"@types/lodash": "^4.14.151",
+8 -5
View File
@@ -40,10 +40,13 @@ class AllEntityPolicies implements EntityPolicy {
async enforce(entity: Entity): Promise<Entity> {
let result = entity;
for (const policy of this.policies) {
const output = await policy.enforce(entity);
if (output) {
result = output;
const output = await policy.enforce(result);
if (!output) {
throw new Error(
`Policy ${policy.constructor.name} did not return a result`,
);
}
result = output;
}
return result;
}
@@ -54,10 +57,10 @@ class AllEntityPolicies implements EntityPolicy {
class AnyEntityPolicy implements EntityPolicy {
constructor(private readonly policies: EntityPolicy[]) {}
async enforce(entity: Entity): Promise<Entity | undefined> {
async enforce(entity: Entity): Promise<Entity> {
for (const policy of this.policies) {
const output = await policy.enforce(entity);
if (output !== null) {
if (output) {
return output;
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/cli-common",
"description": "Common functionality used by cli, backend, and create-app",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": false,
"main": "src/index.ts",
"types": "src/index.ts",
+1
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
/* eslint-disable no-restricted-syntax */
import { resolve as resolvePath } from 'path';
import { findPaths, findRootPath, findOwnDir, findOwnRootDir } from './paths';
+2
View File
@@ -18,6 +18,7 @@
const path = require('path');
// Figure out whether we're running inside the backstage repo or as an installed dependency
/* eslint-disable-next-line no-restricted-syntax */
const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src'));
if (!isLocal || process.env.BACKSTAGE_E2E_CLI_TEST) {
@@ -25,6 +26,7 @@ if (!isLocal || process.env.BACKSTAGE_E2E_CLI_TEST) {
} else {
require('ts-node').register({
transpileOnly: true,
/* eslint-disable-next-line no-restricted-syntax */
project: path.resolve(__dirname, '../../../tsconfig.json'),
compilerOptions: {
module: 'CommonJS',
+5
View File
@@ -67,6 +67,11 @@ module.exports = {
selector:
'ImportDeclaration[source.value="winston"] ImportDefaultSpecifier',
},
{
message:
"`__dirname` doesn't refer to the same dir in production builds, try `resolvePackagePath()` from `@backstage/backend-common` instead.",
selector: 'Identifier[name="__dirname"]',
},
],
},
overrides: [
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/cli",
"description": "CLI for developing Backstage plugins and apps",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": false,
"publishConfig": {
"access": "public"
@@ -28,9 +28,9 @@
"backstage-cli": "bin/backstage-cli"
},
"dependencies": {
"@backstage/cli-common": "^0.1.1-alpha.24",
"@backstage/config": "^0.1.1-alpha.24",
"@backstage/config-loader": "^0.1.1-alpha.24",
"@backstage/cli-common": "^0.1.1-alpha.25",
"@backstage/config": "^0.1.1-alpha.25",
"@backstage/config-loader": "^0.1.1-alpha.25",
"@hot-loader/react-dom": "^16.13.0",
"@lerna/package-graph": "^3.18.5",
"@lerna/project": "^3.18.0",
+1 -1
View File
@@ -22,7 +22,7 @@ import { buildBundle } from '../../lib/bundler';
export default async (cmd: Command) => {
const appConfigs = await loadConfig({
env: process.env.NODE_ENV ?? 'production',
env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'production',
rootPaths: [paths.targetRoot, paths.targetDir],
});
await buildBundle({
+1 -1
View File
@@ -22,7 +22,7 @@ import { serveBundle } from '../../lib/bundler';
export default async (cmd: Command) => {
const appConfigs = await loadConfig({
env: process.env.NODE_ENV ?? 'development',
env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development',
rootPaths: [paths.targetRoot, paths.targetDir],
});
const waitForExit = await serveBundle({
+1 -1
View File
@@ -22,7 +22,7 @@ import { serveBackend } from '../../lib/bundler/backend';
export default async (cmd: Command) => {
const appConfigs = await loadConfig({
env: process.env.NODE_ENV ?? 'development',
env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development',
rootPaths: [paths.targetRoot, paths.targetDir],
});
+2 -1
View File
@@ -22,7 +22,8 @@ import { stringify as stringifyYaml } from 'yaml';
export default async (cmd: Command) => {
const appConfigs = await loadConfig({
env: cmd.env ?? process.env.NODE_ENV ?? 'development',
env:
cmd.env ?? process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development',
shouldReadSecrets: cmd.withSecrets ?? false,
rootPaths: [paths.targetRoot, paths.targetDir],
});
+1 -1
View File
@@ -133,7 +133,7 @@ export function registerCommands(program: CommanderStatic) {
.option('--with-secrets', 'Include secrets in the printed configuration')
.option(
'--env <env>',
'The environment to print configuration for [NODE_ENV or development]',
'The environment to print configuration for [APP_ENV or NODE_ENV or development]',
)
.option(
'--format <format>',
+1 -1
View File
@@ -22,7 +22,7 @@ import { buildBundle } from '../../lib/bundler';
export default async (cmd: Command) => {
const appConfigs = await loadConfig({
env: process.env.NODE_ENV ?? 'production',
env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'production',
rootPaths: [paths.targetRoot, paths.targetDir],
});
await buildBundle({
+1 -1
View File
@@ -22,7 +22,7 @@ import { serveBundle } from '../../lib/bundler';
export default async (cmd: Command) => {
const appConfigs = await loadConfig({
env: process.env.NODE_ENV ?? 'development',
env: process.env.APP_ENV ?? process.env.NODE_ENV ?? 'development',
rootPaths: [paths.targetRoot, paths.targetDir],
});
const waitForExit = await serveBundle({
+2 -8
View File
@@ -27,18 +27,12 @@ const main = (argv: string[]) => {
program.on('command:*', () => {
console.log();
console.log(
chalk.red(`Invalid command: ${chalk.cyan(program.args.join(' '))}`),
);
console.log(chalk.red('See --help for a list of available commands.'));
console.log(chalk.red(`Invalid command: ${program.args.join(' ')}`));
console.log();
program.outputHelp();
process.exit(1);
});
if (!process.argv.slice(2).length) {
program.outputHelp(chalk.yellow);
}
program.parse(argv);
};
+1
View File
@@ -209,6 +209,7 @@ export async function createBackendConfig(
],
target: 'node' as const,
node: {
/* eslint-disable-next-line no-restricted-syntax */
__dirname: true,
__filename: true,
global: true,
+1
View File
@@ -16,4 +16,5 @@
import { findPaths } from '@backstage/cli-common';
/* eslint-disable-next-line no-restricted-syntax */
export const paths = findPaths(__dirname);
@@ -23,8 +23,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^{{version}}",
"@backstage/config": "^{{version}}",
"@backstage/backend-common": "^{{backstageVersion}}",
"@backstage/config": "^{{backstageVersion}}",
"@types/express": "^4.17.6",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
@@ -33,7 +33,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^{{version}}",
"@backstage/cli": "^{{backstageVersion}}",
"@types/supertest": "^2.0.8",
"supertest": "^4.0.2",
"msw": "^0.21.2"
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/config-loader",
"description": "Config loading functionality used by Backstage backend, and CLI",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": false,
"publishConfig": {
"access": "public",
@@ -30,7 +30,7 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/config": "^0.1.1-alpha.24",
"@backstage/config": "^0.1.1-alpha.25",
"fs-extra": "^9.0.0",
"yaml": "^1.9.2",
"yup": "^0.29.1"
+1 -1
View File
@@ -28,7 +28,7 @@ type ResolveOptions = {
* Resolves all configuration files that should be loaded in the given environment.
*
* For each root directory, search for the default app-config.yaml, along with suffixed
* NODE_ENV and local variants, e.g. app-config.production.yaml or app-config.development.local.yaml
* APP_ENV and local variants, e.g. app-config.production.yaml or app-config.development.local.yaml
*
* The priority order of config loaded through suffixes is `env > local > none`, meaning that
* for example app-config.development.yaml has higher priority than `app-config.local.yaml`.
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/config",
"description": "Config API used by Backstage core, backend, and CLI",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": false,
"publishConfig": {
"access": "public",
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core-api",
"description": "Internal Core API used by Backstage plugins and apps",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,8 +29,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/config": "^0.1.1-alpha.24",
"@backstage/theme": "^0.1.1-alpha.24",
"@backstage/config": "^0.1.1-alpha.25",
"@backstage/theme": "^0.1.1-alpha.25",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@types/react": "^16.9",
@@ -41,8 +41,8 @@
"zen-observable": "^0.8.15"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.24",
"@backstage/test-utils-core": "^0.1.1-alpha.24",
"@backstage/cli": "^0.1.1-alpha.25",
"@backstage/test-utils-core": "^0.1.1-alpha.25",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/core",
"description": "Core API used by Backstage plugins and apps",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,9 +29,9 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/config": "^0.1.1-alpha.24",
"@backstage/core-api": "^0.1.1-alpha.24",
"@backstage/theme": "^0.1.1-alpha.24",
"@backstage/config": "^0.1.1-alpha.25",
"@backstage/core-api": "^0.1.1-alpha.25",
"@backstage/theme": "^0.1.1-alpha.25",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
@@ -55,8 +55,8 @@
"react-use": "^15.3.3"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.24",
"@backstage/test-utils": "^0.1.1-alpha.24",
"@backstage/cli": "^0.1.1-alpha.25",
"@backstage/test-utils": "^0.1.1-alpha.25",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.4.1",
"@testing-library/user-event": "^12.0.7",
@@ -60,7 +60,7 @@ const CHECKBOX_TREE_ITEMS = [
];
export default {
title: 'CheckboxTree',
title: 'Inputs/CheckboxTree',
component: CheckboxTree,
};
@@ -18,7 +18,7 @@ import React from 'react';
import { Select } from '.';
export default {
title: 'Select',
title: 'Inputs/Select',
component: Select,
};
@@ -76,19 +76,6 @@ const VARIANT_STYLES = {
height: 'calc(100% - 10px)', // for pages without content header
marginBottom: '10px',
},
contentheader: {
height: 'calc(100% - 40px)', // for pages with content header
},
contentheadertabs: {
height: 'calc(100% - 97px)', // for pages with content header and tabs (Tingle)
},
noShrink: {
flexShrink: 0,
},
minheight300: {
minHeight: 300,
overflow: 'initial',
},
},
cardContent: {
fullHeight: {
@@ -97,10 +84,6 @@ const VARIANT_STYLES = {
height100: {
flex: 1,
},
contentRow: {
display: 'flex',
flexDirection: 'row',
},
},
};
@@ -120,10 +103,6 @@ const VARIANT_STYLES = {
* Display the card full height suitable for DataGrid:
*
* <InfoCard variant="height100">...</InfoCard>
*
* Variants can be combined in a whitespace delimited list like so:
*
* <InfoCard variant="noShrink">...</InfoCard>
*/
type Props = {
title?: ReactNode;
@@ -24,7 +24,7 @@ export default {
export const Default = () => (
<Grid container spacing={4}>
<Grid item xs={6} sm={4} md={2}>
<Grid item xs={3}>
<ItemCard
title="Item Card"
description="This is the description of an Item Card"
@@ -33,7 +33,7 @@ export const Default = () => (
onClick={() => {}}
/>
</Grid>
<Grid item xs={6} sm={4} md={2}>
<Grid item xs={3}>
<ItemCard
title="Item Card"
description="This is the description of an Item Card"
@@ -47,7 +47,7 @@ export const Default = () => (
export const Tags = () => (
<Grid container spacing={4}>
<Grid item xs={6} sm={4} md={2}>
<Grid item xs={3}>
<ItemCard
title="Item Card"
description="This is a Item Card"
@@ -55,7 +55,7 @@ export const Tags = () => (
label="Button"
/>
</Grid>
<Grid item xs={6} sm={4} md={2}>
<Grid item xs={3}>
<ItemCard
title="Item Card"
description="This is a Item Card"
@@ -36,7 +36,7 @@ import {
import { Box, Typography, Link, Chip, Grid } from '@material-ui/core';
export default {
title: 'Layout/Example Plugin',
title: 'Plugins/Examples',
component: Page,
};
@@ -15,6 +15,7 @@
* limitations under the License.
*/
/* eslint-disable no-restricted-syntax */
const path = require('path');
// Figure out whether we're running inside the backstage repo or as an installed dependency
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/create-app",
"description": "Create app package for Backstage",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": false,
"publishConfig": {
"access": "public"
@@ -27,7 +27,7 @@
"start": "nodemon --"
},
"dependencies": {
"@backstage/cli-common": "^0.1.1-alpha.24",
"@backstage/cli-common": "^0.1.1-alpha.25",
"chalk": "^4.0.0",
"commander": "^6.1.0",
"fs-extra": "^9.0.0",
+1
View File
@@ -87,6 +87,7 @@ async function moveApp(tempDir: string, destination: string, id: string) {
}
export default async (cmd: Command): Promise<void> => {
/* eslint-disable-next-line no-restricted-syntax */
const paths = findPaths(__dirname);
const questions: Question[] = [
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/dev-utils",
"description": "Utilities for developing Backstage plugins.",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,10 +29,10 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/cli": "^0.1.1-alpha.24",
"@backstage/core": "^0.1.1-alpha.24",
"@backstage/test-utils": "^0.1.1-alpha.24",
"@backstage/theme": "^0.1.1-alpha.24",
"@backstage/cli": "^0.1.1-alpha.25",
"@backstage/core": "^0.1.1-alpha.25",
"@backstage/test-utils": "^0.1.1-alpha.25",
"@backstage/theme": "^0.1.1-alpha.25",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@testing-library/jest-dom": "^5.10.1",
+1
View File
@@ -15,6 +15,7 @@
* limitations under the License.
*/
/* eslint-disable no-restricted-syntax */
const path = require('path');
// Figure out whether we're running inside the backstage repo or as an installed dependency
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "docgen",
"description": "Tool for generating API Documentation for itself",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": true,
"homepage": "https://backstage.io",
"repository": {
+1
View File
@@ -37,6 +37,7 @@ export async function generate(
);
}
/* eslint-disable-next-line no-restricted-syntax */
const rootDir = resolvePath(__dirname, '../../..');
const srcDir = resolvePath(rootDir, 'packages', 'core-api', 'src');
const targetDir = resolvePath(targetPath);
+1
View File
@@ -21,6 +21,7 @@ import fs from 'fs-extra';
import { generate } from './generate';
const main = (argv: string[]) => {
/* eslint-disable-next-line no-restricted-syntax */
const pkgJson = fs.readJsonSync(resolvePath(__dirname, '../package.json'));
program.name('docgen').version(pkgJson.version);
+1 -1
View File
@@ -14,7 +14,7 @@ yarn tsc
yarn build
```
Once those tasks have completed, you can now run the test using `yarn start` inside this package.
Once those tasks have completed, you can now run the test using `yarn e2e-test run`.
If you make changes to other packages you will need to rerun `yarn tsc && yarn build`. Changes to this package do not require a rebuild.
+6 -2
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env node
/*
* Copyright 2020 Spotify AB
*
@@ -14,12 +15,15 @@
* limitations under the License.
*/
const path = require('path');
require('ts-node').register({
transpileOnly: true,
project: require('path').resolve(__dirname, '../../../tsconfig.json'),
/* eslint-disable-next-line no-restricted-syntax */
project: path.resolve(__dirname, '../../../tsconfig.json'),
compilerOptions: {
module: 'CommonJS',
},
});
require('./e2e-test');
require('../src');
+8 -3
View File
@@ -1,7 +1,7 @@
{
"name": "e2e-test",
"description": "E2E test for verifying Backstage packages",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"private": true,
"homepage": "https://backstage.io",
"repository": {
@@ -13,17 +13,22 @@
"backstage"
],
"license": "Apache-2.0",
"main": "src/index.js",
"main": "src/index.ts",
"scripts": {
"start": "node .",
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"test:e2e": "yarn start"
},
"bin": {
"e2e-test": "bin/e2e-test"
},
"devDependencies": {
"@backstage/cli-common": "^0.1.1-alpha.24",
"@backstage/cli-common": "^0.1.1-alpha.25",
"@types/fs-extra": "^9.0.1",
"@types/node": "^13.7.2",
"chalk": "^4.0.0",
"commander": "^6.1.0",
"fs-extra": "^9.0.0",
"handlebars": "^4.7.3",
"cross-fetch": "^3.0.6",
@@ -13,24 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { Box } from '@material-ui/core';
type CostOverviewFooterProps = {
children?: React.ReactNode;
};
import { CommanderStatic } from 'commander';
import { run } from './run';
const CostOverviewFooter = ({ children }: CostOverviewFooterProps) => (
<Box
display="flex"
flexDirection="row"
justifyContent="space-between"
alignItems="center"
>
{React.Children.map(children, child => (
<Box marginY={1}>{child}</Box>
))}
</Box>
);
export default CostOverviewFooter;
export function registerCommands(program: CommanderStatic) {
program.command('run').description('Run e2e tests').action(run);
}
@@ -24,15 +24,15 @@ import Browser from 'zombie';
import {
spawnPiped,
runPlain,
handleError,
waitForPageWithText,
waitFor,
waitForExit,
print,
} from './helpers';
} from '../lib/helpers';
import pgtools from 'pgtools';
import { findPaths } from '@backstage/cli-common';
// eslint-disable-next-line no-restricted-syntax
const paths = findPaths(__dirname);
const templatePackagePaths = [
@@ -41,7 +41,7 @@ const templatePackagePaths = [
'packages/create-app/templates/default-app/packages/backend/package.json.hbs',
];
async function main() {
export async function run() {
const rootDir = await fs.mkdtemp(resolvePath(os.tmpdir(), 'backstage-e2e-'));
print(`CLI E2E test root: ${rootDir}\n`);
@@ -412,16 +412,3 @@ async function testBackendStart(appDir: string, isPostgres: boolean) {
print('Backend startup test finished successfully');
}
}
process.on('unhandledRejection', (error: Error) => {
// Try to avoid exiting if the unhandled error is coming from jsdom, i.e. zombie.
// Those are typically errors on the page that should be benign, at least in the
// context of this test. We have other ways of asserting that the page is being
// rendered correctly.
if (error?.stack?.includes('node_modules/jsdom/lib')) {
console.log(`Ignored error inside jsdom, ${error}`);
} else {
handleError(error);
}
});
main().catch(handleError);
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright 2020 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 program from 'commander';
import chalk from 'chalk';
import { registerCommands } from './commands';
import { version } from '../package.json';
import { exitWithError } from './lib/helpers';
async function main(argv: string[]) {
program.name('e2e-test').version(version);
registerCommands(program);
program.on('command:*', () => {
console.log();
console.log(chalk.red(`Invalid command: ${program.args.join(' ')}`));
console.log();
program.outputHelp();
process.exit(1);
});
program.parse(argv);
}
process.on('unhandledRejection', (rejection: unknown) => {
// Try to avoid exiting if the unhandled error is coming from jsdom, i.e. zombie.
// Those are typically errors on the page that should be benign, at least in the
// context of this test. We have other ways of asserting that the page is being
// rendered correctly.
if (
rejection instanceof Error &&
rejection?.stack?.includes('node_modules/jsdom/lib')
) {
console.log(`Ignored error inside jsdom, ${rejection?.stack ?? rejection}`);
} else {
if (rejection instanceof Error) {
exitWithError(rejection);
} else {
exitWithError(new Error(`Unknown rejection: '${rejection}'`));
}
}
});
main(process.argv).catch(exitWithError);
@@ -42,7 +42,7 @@ export function spawnPiped(cmd: string[], options?: SpawnOptions) {
shell: true,
...options,
});
child.on('error', handleError);
child.on('error', exitWithError);
const logPrefix = cmd.map(s => s.replace(/.+\//, '')).join(' ');
child.stdout?.on(
@@ -75,7 +75,7 @@ export async function runPlain(cmd: string[], options?: SpawnOptions) {
}
}
export function handleError(err: Error & { code?: unknown }) {
export function exitWithError(err: Error & { code?: unknown }) {
process.stdout.write(`${err.name}: ${err.stack || err.message}\n`);
if (typeof err.code === 'number') {
+1
View File
@@ -14,6 +14,7 @@ module.exports = {
'storybook-dark-mode/register',
],
webpackFinal: async config => {
/* eslint-disable-next-line no-restricted-syntax */
const coreSrc = path.resolve(__dirname, '../../core/src');
// Mirror config in packages/cli/src/lib/bundler
+1 -12
View File
@@ -28,18 +28,7 @@ addParameters({
export const parameters = {
options: {
storySort: {
order: [
'Example Plugin',
'Header',
'Sidebar',
'Tabs',
'Information Card',
'Tabbed Card',
'Table',
'Status',
'Trendline',
'Progress Card',
],
order: ['Plugins', 'Layout', 'Navigation'],
},
},
};
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "storybook",
"version": "0.1.1-alpha.24",
"version": "0.1.1-alpha.25",
"description": "Storybook build for core package",
"private": true,
"scripts": {
@@ -14,7 +14,7 @@
]
},
"dependencies": {
"@backstage/theme": "^0.1.1-alpha.24"
"@backstage/theme": "^0.1.1-alpha.25"
},
"devDependencies": {
"@storybook/addon-actions": "^6.0.21",

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