Merge branch 'master' of github.com:spotify/backstage into feat/backend-plugin

* 'master' of github.com:spotify/backstage: (1118 commits)
  test(catalog/gql): added some test for the catalog graphql module
  Fix Dockerfile comments and README instructions
  Fix prettier on multi-stage-fontend README.md
  Move standalone.Dockerfile to contrib directory
  Update quickstart-app-auth.md
  test(catalog/gql): added some tests as i couldn't get codecov to ignore
  Update changelog
  v0.1.1-alpha.22
  v0.1.1-alpha.21
  chore(codecov): trying again?
  chore(codecov): prettier why do you hate me
  TechDocs: Use a flag to determine if we should use a local mkdocs or techdocs-container (#2503)
  ignore graphql plugins from codecov
  feat(catalog-backend): delete log entries older than a cutoff
  chore(catalog/gql): making the backend start
  [microsite] Add CNCF logo (#2511)
  feat: use title for API type in table
  fix(workflows): do not run e2e when contrib or docs change
  chore(contrib): form the basic contrib hierarchy
  fix(catalog-backend): address comments and add docs
  ...
This commit is contained in:
blam
2020-09-20 23:43:56 +02:00
1306 changed files with 68343 additions and 12102 deletions
+8
View File
@@ -0,0 +1,8 @@
comment: false # Ref: https://docs.codecov.io/docs/pull-request-comments
coverage:
status:
project:
default:
threshold: 0% # Ref: https://docs.codecov.io/docs/codecovyml-reference#coveragestatus
target: auto
+4
View File
@@ -1,7 +1,11 @@
**/node_modules/**
**/dist/**
**/dist-types/**
**/storybook-static/**
**/coverage/**
**/build/**
**/.git/**
**/public/**
**/microsite/**
**/templates/**
**/sample-templates/**
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: 'Feature Request'
about: 'Suggest new features and changes'
labels: help wanted
labels: enhancement
---
<!--- Provide a general summary of the feature request in the Title above -->
+26
View File
@@ -0,0 +1,26 @@
---
name: 'RFC'
about: 'Request For Comments (RFC) from the community'
labels: rfc
title: '[RFC] <name>'
---
**Status:** Open for comments
<!--- Open for comments |Closed for comments (RFC no longer maintained) --->
## Need
<!--- Why are we proposing this change? Why is this the problem were trying to address and what benefits/impact do we expect to get from this --->
## Proposal
<!--- The proposed approach. Describe the proposal in as much detail as needed for reviewers to give concrete feedback. Take special care in this section to describe any implications on data privacy or security. --->
## Alternatives
<!--- What alternatives to the proposed solution were considered? What criteria/data was used to discard these --->
## Risks
<!--- What other things happening could conflict or compete (for example for resources) with the proposal? What risk are there and how do we plan to handle them --->
+2
View File
@@ -4,7 +4,9 @@
That makes it easier to understand the change so we can :shipit: faster. -->
#### :heavy_check_mark: Checklist
<!--- Put an `x` in all the boxes that apply: -->
- [ ] All tests are passing `yarn test`
- [ ] Screenshots attached (for UI changes)
- [ ] Relevant documentation updated
+18
View File
@@ -0,0 +1,18 @@
version: 2
updates:
- package-ecosystem: npm
directory: '/'
schedule:
interval: daily
time: '04:00'
open-pull-requests-limit: 5
labels:
- dependencies
- package-ecosystem: npm
directory: '/microsite/'
schedule:
interval: daily
time: '04:00'
open-pull-requests-limit: 2
labels:
- dependencies
+31 -1
View File
@@ -14,7 +14,37 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # Required to retrieve git history
- run: yarn install && yarn build-storybook
# Beginning of yarn setup, keep in sync between all workflows, see ci.yml
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: cache all node_modules
id: cache-modules
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }}
- name: find location of global yarn cache
id: yarn-cache
if: steps.cache-modules.outputs.cache-hit != 'true'
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
if: steps.cache-modules.outputs.cache-hit != 'true'
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: yarn install
run: yarn install --frozen-lockfile
# End of yarn setup
- run: yarn build-storybook
- uses: chromaui/action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
+116
View File
@@ -0,0 +1,116 @@
name: CI
on:
pull_request:
paths-ignore:
- 'microsite/**'
jobs:
verify:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096
steps:
- uses: actions/checkout@v2
- name: fetch branch master
run: git fetch origin master
# Beginning of yarn setup, keep in sync between all workflows.
# TODO(Rugvip): move this to composite action once all features we use are supported
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
# Cache every node_modules folder inside the monorepo
- name: cache all node_modules
id: cache-modules
uses: actions/cache@v2
with:
path: '**/node_modules'
# We use both yarn.lock and package.json as cache keys to ensure that
# changes to local monorepo packages bust the cache.
key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }}
# If we get a cache hit for node_modules, there's no need to bring in the global
# yarn cache or run yarn install, as all dependencies will be installed already.
- name: find location of global yarn cache
id: yarn-cache
if: steps.cache-modules.outputs.cache-hit != 'true'
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
if: steps.cache-modules.outputs.cache-hit != 'true'
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: yarn install
if: steps.cache-modules.outputs.cache-hit != 'true'
run: yarn install --frozen-lockfile
# End of yarn setup
- name: check for yarn.lock changes
id: yarn-lock
run: git diff --quiet origin/master HEAD -- yarn.lock
continue-on-error: true
- name: verify doc links
run: node docs/verify-links.js
- name: prettier
run: yarn prettier:check
- name: lint
run: yarn lerna -- run lint --since origin/master
- name: type checking and declarations
run: yarn tsc:full
- name: build changed packages
if: ${{ steps.yarn-lock.outcome == 'success' }}
run: yarn lerna -- run build --since origin/master
- name: build all packages
if: ${{ steps.yarn-lock.outcome == 'failure' }}
run: yarn lerna -- run build
- name: verify type dependencies
run: yarn lint:type-deps
- name: test changed packages
if: ${{ steps.yarn-lock.outcome == 'success' }}
run: yarn lerna -- run test --since origin/master -- --coverage
- name: test all packages (and upload coverage)
if: ${{ steps.yarn-lock.outcome == 'failure' }}
run: |
yarn lerna -- run test -- --coverage
bash <(curl -s https://codecov.io/bash)
- name: verify plugin template
run: yarn lerna -- run diff -- --check
- name: ensure clean working directory
run: |
if files=$(git ls-files --exclude-standard --others --modified) && [[ -z "$files" ]]; then
exit 0
else
echo ""
echo "Working directory has been modified:"
echo ""
git status --short
echo ""
exit 1
fi
-49
View File
@@ -1,49 +0,0 @@
name: CLI Test
on:
pull_request:
paths:
- '.github/workflows/cli.yml'
- 'packages/cli/**'
- 'packages/core/**'
- 'packages/core-api/**'
- 'yarn.lock'
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
node-version: [12.x]
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096
name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: find location of global yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: yarn install
run: yarn install --frozen-lockfile
- run: yarn tsc
- run: yarn build
- name: verify app and plugin creation
run: |
sudo sysctl fs.inotify.max_user_watches=524288
node ${{ github.workspace }}/packages/cli/e2e-test/cli-e2e-test.js
@@ -1,12 +1,14 @@
name: CLI Test Windows
name: E2E Test Windows
# Building on windows is really slow, so this workflow is separate from cli.yml and only builds on changes
# Building on windows is really slow, so this workflow is separate from e2e.yml and only builds on changes
# to the cli itself. They're more likely to introduce issues on windows, compared to changes to core and yarn.lock.
on:
pull_request:
paths:
- '.github/workflows/cli-win.yml'
- '.github/workflows/e2e-win.yml'
- 'packages/cli/**'
- 'packages/e2e/**'
- 'packages/create-app/**'
jobs:
build:
@@ -24,23 +26,16 @@ jobs:
name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: find location of global yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: yarn install
run: yarn install --frozen-lockfile
- run: yarn tsc
- run: yarn build
- name: verify app and plugin creation
run: node ${{ github.workspace }}/packages/cli/e2e-test/cli-e2e-test.js
- 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
+78
View File
@@ -0,0 +1,78 @@
name: E2E Test Linux
on:
pull_request:
paths-ignore:
- 'contrib/**'
- 'docs/**'
- 'microsite/**'
jobs:
build:
runs-on: ${{ matrix.os }}
services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432/tcp
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
matrix:
os: [ubuntu-latest]
node-version: [12.x]
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096
name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
# Beginning of yarn setup, keep in sync between all workflows, see ci.yml
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: cache all node_modules
id: cache-modules
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }}
- name: find location of global yarn cache
id: yarn-cache
if: steps.cache-modules.outputs.cache-hit != 'true'
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
if: steps.cache-modules.outputs.cache-hit != 'true'
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: yarn install
run: yarn install --frozen-lockfile
# End of yarn setup
- run: yarn tsc
- name: yarn build
run: yarn build --ignore example-app --ignore example-backend --ignore @techdocs/cli
- name: run E2E test
run: |
sudo sysctl fs.inotify.max_user_watches=524288
yarn workspace e2e-test start
env:
POSTGRES_HOST: localhost
POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }}
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
-83
View File
@@ -1,83 +0,0 @@
name: Frontend CI
on:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096
steps:
- uses: actions/checkout@v2
- name: fetch branch master
run: git fetch origin master
- name: find location of global yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: cache node_modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: check for yarn.lock changes
id: yarn-lock
run: git diff --quiet origin/master HEAD -- yarn.lock
continue-on-error: true
- name: yarn install
run: yarn install --frozen-lockfile
- name: lint
run: yarn lerna -- run lint --since origin/master
- name: type checking and declarations
run: yarn tsc --incremental false
- name: build changed packages
if: ${{ steps.yarn-lock.outcome == 'success' }}
# Need to build all dependencies as well to be able to run tests later
run: yarn lerna -- run build --since origin/master --include-dependencies
- name: build all packages
if: ${{ steps.yarn-lock.outcome == 'failure' }}
run: yarn lerna -- run build
- name: verify type dependencies
run: yarn lint:type-deps
- name: test changed packages
if: ${{ steps.yarn-lock.outcome == 'success' }}
run: yarn lerna -- run test --since origin/master -- --coverage
- name: test all packages
if: ${{ steps.yarn-lock.outcome == 'failure' }}
run: yarn lerna -- run test -- --coverage
- name: verify plugin template
run: yarn lerna -- run diff -- --check
- name: bundle example app
run: yarn bundle
- name: verify storybook
run: yarn workspace storybook build-storybook
@@ -1,17 +1,12 @@
name: Deploy Storybook
name: Master Build Windows
on:
push:
branches:
- master
paths:
- '.github/workflows/storybook-deploy.yml'
- 'packages/storybook/**'
- 'packages/core/src/**'
branches: [master]
jobs:
deploy-storybook:
runs-on: ubuntu-latest
build:
runs-on: windows-latest
strategy:
matrix:
@@ -23,6 +18,13 @@ jobs:
steps:
- uses: actions/checkout@v2
# Beginning of yarn setup, keep in sync between all workflows, see ci.yml
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: find location of global yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
@@ -30,27 +32,29 @@ jobs:
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: cache node_modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
run: yarn install --frozen-lockfile
- name: build storybook
run: yarn workspace storybook build-storybook
- name: deploy storybook to gh-pages
uses: JamesIves/github-pages-deploy-action@3.4.2
# End of yarn setup
- name: lint
run: yarn lerna -- run lint
- name: type checking and declarations
run: yarn tsc:full
- name: verify type dependencies
run: yarn lint:type-deps
- name: test
run: yarn lerna -- run test
- name: Discord notification
if: ${{ failure() }}
uses: Ilshidur/action-discord@0.2.0
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages
FOLDER: packages/storybook/dist
args: 'Windows master build failed https://github.com/{{GITHUB_REPOSITORY}}/actions/runs/{{GITHUB_RUN_ID}}'
+38 -23
View File
@@ -1,4 +1,4 @@
name: Master Build
name: Main Master Build
on:
push:
@@ -18,35 +18,40 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: find location of global yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: cache node_modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
# Beginning of yarn setup, keep in sync between all workflows, see ci.yml
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: cache all node_modules
id: cache-modules
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }}
- name: find location of global yarn cache
id: yarn-cache
if: steps.cache-modules.outputs.cache-hit != 'true'
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: cache global yarn cache
uses: actions/cache@v2
if: steps.cache-modules.outputs.cache-hit != 'true'
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: yarn install
run: yarn install --frozen-lockfile
# End of yarn setup
- name: lint
run: yarn lerna -- run lint
- name: type checking and declarations
run: yarn tsc --incremental false
run: yarn tsc:full
- name: build
run: yarn build
@@ -54,8 +59,10 @@ jobs:
- name: verify type dependencies
run: yarn lint:type-deps
- name: test
run: yarn lerna -- run test -- --coverage
- name: test (and upload coverage)
run: |
yarn lerna -- run test -- --coverage
bash <(curl -s https://codecov.io/bash)
# Publishes current version of packages that are not already present in the registry
- name: publish
@@ -66,6 +73,14 @@ jobs:
# Tags the commit with the version in the core package if the tag doesn't exist
- uses: Klemensas/action-autotag@1.2.3
with:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
package_root: "packages/core"
tag_prefix: "v"
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
package_root: 'packages/core'
tag_prefix: 'v'
- name: Discord notification
if: ${{ failure() }}
uses: Ilshidur/action-discord@0.2.0
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
with:
args: 'Master build failed https://github.com/{{GITHUB_REPOSITORY}}/actions/runs/{{GITHUB_RUN_ID}}'
@@ -0,0 +1,38 @@
name: Build microsite
on:
pull_request:
paths:
- '.github/workflows/microsite-build-check.yml'
- 'microsite/**'
- 'docs/**'
jobs:
build-microsite:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096
steps:
- uses: actions/checkout@v2
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
# Skip caching of microsite dependencies, it keeps the global cache size
# smaller, which make Windows builds a lot faster for the rest of the project.
- name: yarn install
run: yarn install --frozen-lockfile
working-directory: microsite
- name: build microsite
run: yarn build
working-directory: microsite
@@ -0,0 +1,62 @@
name: Deploy Microsite and Storybook
on:
push:
branches:
- master
paths:
- '.github/workflows/microsite-with-storybook-deploy.yml'
- 'packages/storybook/**'
- 'packages/core/src/**'
- 'microsite/**'
- 'docs/**'
jobs:
deploy-microsite-and-storybook:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
env:
CI: true
NODE_OPTIONS: --max-old-space-size=4096
steps:
- uses: actions/checkout@v2
- name: use node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
# We avoid caching in this workflow, as we're running an install of both the top-level
# dependencies and the microsite. We leave it to the main master workflow to produce the
# cache, as that results in a smaller bundle.
- name: top-level yarn install
run: yarn install --frozen-lockfile
- name: microsite yarn install
run: yarn install --frozen-lockfile
working-directory: microsite
- name: build microsite
run: yarn build
working-directory: microsite
- name: build storybook
run: yarn workspace storybook build-storybook
- name: move storybook dist into microsite
run: mv packages/storybook/dist/ microsite/build/backstage/storybook
- name: Check the build output
run: ls microsite/build/backstage && ls microsite/build/backstage/storybook
- name: Deploy both microsite and storybook to gh-pages
uses: JamesIves/github-pages-deploy-action@3.4.2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages
FOLDER: microsite/build/backstage
@@ -0,0 +1,53 @@
name: Automatically add new TechDocs Issues and PRs to the GitHub project board
# Development of TechDocs in Backstage is managed by this Kanban board - https://github.com/spotify/backstage/projects/5
# New issues with TechDocs in their title or docs-like-code label will be added to the board.
on:
issues:
types: [opened, reopened, labeled, edited]
pull_request:
types: [opened, reopened, labeled, edited]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
assign_issue_or_pr_to_project:
runs-on: ubuntu-latest
name: Triage
steps:
- name: Assign new issue to Incoming based on its title.
uses: srggrs/assign-one-project-github-action@1.2.0
if: |
contains(github.event.issue.title, 'TechDocs') ||
contains(github.event.issue.title, 'techdocs') ||
contains(github.event.issue.title, 'Techdocs')
with:
project: 'https://github.com/spotify/backstage/projects/5'
column_name: 'Incoming'
- name: Assign new issue to Incoming based on its label.
uses: srggrs/assign-one-project-github-action@1.2.0
if: |
contains(github.event.issue.labels.*.name, 'docs-like-code')
with:
project: 'https://github.com/spotify/backstage/projects/5'
column_name: 'Incoming'
- name: Assign new PR to Incoming based on its title.
uses: srggrs/assign-one-project-github-action@1.2.0
if: |
contains(github.event.pull_request.title, 'TechDocs') ||
contains(github.event.pull_request.title, 'techdocs') ||
contains(github.event.pull_request.title, 'Techdocs')
with:
project: 'https://github.com/spotify/backstage/projects/5'
column_name: 'Incoming'
- name: Assign new PR to Incoming based on its label.
uses: srggrs/assign-one-project-github-action@1.2.0
if: |
contains(github.event.pull_request.labels.*.name, 'docs-like-code')
with:
project: 'https://github.com/spotify/backstage/projects/5'
column_name: 'Incoming'
+4 -6
View File
@@ -3,12 +3,6 @@
.vscode/
.vsls.json
# @spotify/web-script build output
cjs/
esm/
types/
build/
# Logs
logs
*.log
@@ -95,6 +89,7 @@ typings/
# Nuxt.js build / generate output
.nuxt
dist
dist-types
# Gatsby files
.cache/
@@ -125,3 +120,6 @@ dist
# MkDocs build output
site
# Local configuration files
*.local.yaml
+8
View File
@@ -0,0 +1,8 @@
.yarn
dist
microsite/build
coverage
*.hbs
templates
plugins/scaffolder-backend/sample-templates
.vscode
+15 -12
View File
@@ -1,12 +1,15 @@
| Organization | Contact | Description of Use |
| ---------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------- |
| [Spotify](https://www.spotify.com) | [@stefanalund](https://github.com/stefanalund) | Main interface towards all of Spotify's infrastructure and technical documentation. |
| [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. |
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| Organization | Contact | Description of Use |
| -------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ |
| [Spotify](https://www.spotify.com) | [@stefanalund](https://github.com/stefanalund) | Main interface towards all of Spotify's infrastructure and technical documentation. |
| [bol.com](https://www.bol.com) | [@RoyJacobs](https://github.com/RoyJacobs) | Initial work being done to unify platform tooling. |
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@Fox32](https://github.com/Fox32) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
+117
View File
@@ -0,0 +1,117 @@
# Backstage Changelog
This is a best-effort changelog where we manually collect breaking changes. It is not an exhaustive list of all changes or even features added.
If you encounter issues while upgrading to a newer version, don't hesitate to reach out on [Discord](https://discord.gg/EBHEGzX) or [open an issue](https://github.com/spotify/backstage/issues/new/choose)!
## Next Release
> Collect changes for the next release below
## v0.1.1-alpha.22
### @backstage/core
- Introduced initial version of an inverted app/plugin relationship, where plugins export components for apps to use, instead registering themselves directly into the app. This enables more fine-grained control of plugin features, and also composition of plugins such as catalog pages with additional cards and tabs. This breaks the use of `RouteRef`s, and there will be more changes related to this in the future, but this change lays the initial foundation. See `packages/app` and followup PRs for how to update plugins for this change. [#2076](https://github.com/spotify/backstage/pull/2076)
- Switch to an automatic dependency injection mechanism for all Utility APIs, allowing plugins to ship default implementations of their APIs. See [https://backstage.io/docs/api/utility-apis](https://backstage.io/docs/api/utility-apis). [#2285](https://github.com/spotify/backstage/pull/2285)
### @backstage/cli
- Change `backstage-cli backend:build-image` to forward all args to `docker image build`, instead of just tag. Also add `--build` flag for building all dependent packages before packaging the workspace for the docker build. [#2299](https://github.com/spotify/backstage/pull/2299)
### @backstage/create-app
- Change root `tsc` output dir to `dist-types`, in order to allow for standalone plugin repos. [#2278](https://github.com/spotify/backstage/pull/2278)
### @backstage/catalog-backend
- We have simplified the way that GitHub ingestion works. The `catalog.processors.githubApi` key is deprecated, in favor of `catalog.processors.github`. At the same time, the location type `github/api` is likewise deprecated, in favor of `github`. This location type now serves both raw HTTP reads and APIv3 reads, depending on how you configure it. It also supports having several providers at once - for example, both public GitHub and an internal GitHub Enterprise, with different keys. If you still use the `catalog.processors.githubApi` config key, things will work but you will get a deprecation warning at startup. In a later release, support for the old key will go away entirely. See the [configuration section in the docs](https://backstage.io/docs/features/software-catalog/configuration) for more details.
## v0.1.1-alpha.21
- Added many more frontend plugins to the template along with the sidebar. [#1942](https://github.com/spotify/backstage/pull/1942), [#2084](https://github.com/spotify/backstage/pull/2084)
### @backstage/core
- Material-UI: Bumped to 4.11.0, which is the version that create-app will
resolve to, because we wanted to get the renaming of ExpansionPanel to
Accordion into place. This gets rid of a lot of console deprecation warnings
in newly scaffolded apps.
### @backstage/cli
- Set `NODE_ENV` to `test` when running test. [#2214](https://github.com/spotify/backstage/pull/2214)
- Fix for backend plugins names requiring to be prefixed with `@backstage` to build. [#2224](https://github.com/spotify/backstage/pull/2224)
### @backstage/backend-common
- The backend plugin
[service builder](https://github.com/spotify/backstage/blob/master/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts)
no longer adds `express.json()` automatically to all routes. While convenient
in a lot of cases, it also led to problems where for example the proxy
middleware could hang because the body had already been altered and could not
be streamed. Also, plugins that rather wanted to handle e.g. form encoded data
still had to cater to that manually. We therefore decided to let plugins add
`express.json()` themselves if they happen to deal with JSON data.
### @backstage/catalog-backend
- Add rules configuration for catalog location and entity kinds. The default rules should cover most use-cases, but you may need to allow specific entity kinds when using things like Template or Group entities. [#2118](https://github.com/spotify/backstage/pull/2118)
## v0.1.1-alpha.20
### @backstage/cli
- Use config files according to `NODE_ENV` when serving and building frontend packages. [#2077](https://github.com/spotify/backstage/pull/2077)
- Pin `rollup-plugin-dts` to avoid a later broken version. [#2097](https://github.com/spotify/backstage/pull/2097)
## v0.1.1-alpha.19
### @backstage/backend-common
- Allow listen host and port to be configured separately, in order to support PORT environment variables. [#1950](https://github.com/spotify/backstage/pull/1950)
### @backstage/core
- Added new `DiscoveryApi` for discovering backend endpoint in the frontend, and use in most plugins. See [packages/app/src/apis.ts](https://github.com/spotify/backstage/blob/master/packages/app/src/apis.ts) for how to register in your app. [#2074](https://github.com/spotify/backstage/pull/2074)
### @backstage/create-app
- Added catalog and scaffolder frontend plugins to the template along with the sidebar. [#1942](https://github.com/spotify/backstage/pull/1942), [#2084](https://github.com/spotify/backstage/pull/2084)
- Many plugins have been added to the catalog and will for now be required to be added to separate apps as well. This will be solved as [#1536](https://github.com/spotify/backstage/issues/1536) gets sorted out, but for now you may need to install some plugins just to get pages to work.
### @backstage/catalog-backend
- Added the possibility to add static locations via `app-config.yaml`. This changed the signature of `new LocationReaders(logger)` inside `packages/backend/src/plugins/catalog.ts` to `new LocationReaders({config, logger})`. [#1890](https://github.com/spotify/backstage/pull/1890)
### @backstage/theme
- Changed the type signature of the palette, removing `sidebar: string` and adding `navigation: { background: string; indicator: string}`. [#1880](https://github.com/spotify/backstage/pull/1880)
## v0.1.1-alpha.18
### @backstage/catalog-backend
- Fixed an issue with duplicated location logs. Applying the database migrations from this fix will clear the existing migration logs. [#1836](https://github.com/spotify/backstage/pull/1836)
### @backstage/auth-backend
This version fixes a breakage in CSP policies set by the auth backend. If you're facing trouble with auth in alpha.17, upgrade to alpha.18.
- OAuth redirect URLs no longer receive the `env` parameter, as it is now passed through state instead. This will likely require a reconfiguration of the OAuth app, where a redirect URL like `http://localhost:7000/auth/google/handler/frame?env=development` should now be configured as `http://localhost:7000/auth/google/handler/frame`. [#1812](https://github.com/spotify/backstage/pull/1812)
### @backstage/core
- `SignInPage` props have been changed to receive a list of provider objects instead of simple string identifiers for all but the `'guest'` and `'custom'` providers. This opens up for configuration of custom providers, but may break existing configurations. See [packages/app/src/App.tsx](https://github.com/spotify/backstage/blob/032ba401af36a760efdac41668d7000ccf09bc57/packages/app/src/App.tsx#L36) and [packages/app/src/identityProviders.ts](https://github.com/spotify/backstage/blob/032ba401af36a760efdac41668d7000ccf09bc57/packages/app/src/identityProviders.ts#L24) for how to bring back the existing providers. [#1816](https://github.com/spotify/backstage/pull/1816)
## v0.1.1-alpha.17
### @backstage/techdocs-backend
- The techdocs backend now requires more configuration to be supplied when creating the router. See [packages/backend/src/plugins/techdocs.ts](https://github.com/spotify/backstage/blob/0201fd9b4a52429519dd59e9184106ba69456deb/packages/backend/src/plugins/techdocs.ts#L42) for an example. [#1736](https://github.com/spotify/backstage/pull/1736)
### @backstage/cli
- The `create-app` command was moved out from the CLI to a standalone package. It's now invoked with `npx @backstage/create-app` instead. [#1745](https://github.com/spotify/backstage/pull/1745)
+15 -16
View File
@@ -4,12 +4,12 @@ This code of conduct outlines our expectations for participants within the **Spo
Our open source community strives to:
* **Be friendly and patient.**
* **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
* **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
* **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. Its important to remember that a community where people feel uncomfortable or threatened is not a productive one.
* **Be careful in the words that we choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable.
* **Try to understand why we disagree**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that were different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesnt mean that theyre wrong. Dont forget that it is human to err and blaming each other doesnt get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
- **Be friendly and patient.**
- **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
- **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
- **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. Its important to remember that a community where people feel uncomfortable or threatened is not a productive one.
- **Be careful in the words that we choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable.
- **Try to understand why we disagree**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that were different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesnt mean that theyre wrong. Dont forget that it is human to err and blaming each other doesnt get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
## Definitions
@@ -18,7 +18,7 @@ Harassment includes, but is not limited to:
- Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, race, age, regional discrimination, political or religious affiliation
- Unwelcome comments regarding a persons lifestyle choices and practices, including those related to food, health, parenting, drugs, and employment
- Deliberate misgendering. This includes deadnaming or persistently using a pronoun that does not correctly reflect a person's gender identity. You must address people by the name they give you when not addressing them by their username or handle
- Physical contact and simulated physical contact (eg, textual descriptions like “*hug*” or “*backrub*”) without consent or after a request to stop
- Physical contact and simulated physical contact (eg, textual descriptions like “_hug_” or “_backrub_”) without consent or after a request to stop
- Threats of violence, both physical and psychological
- Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm
- Deliberate intimidation
@@ -39,7 +39,6 @@ Our open source community prioritizes marginalized peoples safety over privil
- Communicating in a tone you dont find congenial
- Criticizing racist, sexist, cissexist, or otherwise oppressive behavior or assumptions
### Diversity Statement
We encourage everyone to participate and are committed to building a community for all. Although we will fail at times, we seek to treat everyone both as fairly and equally as possible. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong.
@@ -53,18 +52,18 @@ If you experience or witness unacceptable behavior—or have any other concerns
- Your contact information.
- Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please
include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link.
include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link.
- Any additional information that may be helpful.
After filing a report, a representative will contact you personally, review the incident, follow up with any additional questions, and make a decision as to how to respond. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. If the complaint originates from a member of the response team, it will be handled by a different member of the response team. We will respect confidentiality requests for the purpose of protecting victims of abuse.
### Attribution & Acknowledgements
We all stand on the shoulders of giants across many open source communities. We'd like to thank the communities and projects that established code of conducts and diversity statements as our inspiration:
We all stand on the shoulders of giants across many open source communities. We'd like to thank the communities and projects that established code of conducts and diversity statements as our inspiration:
* [Django](https://www.djangoproject.com/conduct/reporting/)
* [Python](https://www.python.org/community/diversity/)
* [Ubuntu](http://www.ubuntu.com/about/about-ubuntu/conduct)
* [Contributor Covenant](http://contributor-covenant.org/)
* [Geek Feminism](http://geekfeminism.org/about/code-of-conduct/)
* [Citizen Code of Conduct](http://citizencodeofconduct.org/)
- [Django](https://www.djangoproject.com/conduct/reporting/)
- [Python](https://www.python.org/community/diversity/)
- [Ubuntu](http://www.ubuntu.com/about/about-ubuntu/conduct)
- [Contributor Covenant](http://contributor-covenant.org/)
- [Geek Feminism](http://geekfeminism.org/about/code-of-conduct/)
- [Citizen Code of Conduct](http://citizencodeofconduct.org/)
+13 -5
View File
@@ -1,4 +1,4 @@
# Contributing
# Contributing to Backstage
Our vision for Backstage is for it to become the trusted standard toolbox (read: UX layer) for the open source infrastructure landscape. Think of it like Kubernetes for developer experience. We realize this is an ambitious goal. We cant do it alone.
@@ -28,7 +28,7 @@ What kind of plugins should/could be created? Some inspiration from the 120+ plu
## Suggesting a plugin
If you start developing a plugin that you aim to release as open source, we suggest that you create a new [new Issue](https://github.com/spotify/backstage/issues/new?template=plugin_template.md). This helps the community know what plugins are in development.
If you start developing a plugin that you aim to release as open source, we suggest that you create a new [new Issue](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME). This helps the community know what plugins are in development.
You can also use this process if you have an idea for a good plugin but you hope that someone else will pick up the work.
@@ -38,7 +38,7 @@ The current documentation is very limited. Help us make the `/docs` folder come
## Contribute to Storybook
We think the best way to ensure different plugins provide a consistent experience is through a solid set of reusable UI/UX components. Backstage uses [Storybook](http://storybook.backstage.io).
We think the best way to ensure different plugins provide a consistent experience is through a solid set of reusable UI/UX components. Backstage uses [Storybook](http://backstage.io/storybook).
Either help us [create new components](https://github.com/spotify/backstage/labels/help%20wanted) or improve stories for the existing ones (look for files with `*.stories.tsx`).
@@ -60,9 +60,17 @@ Have you started using Backstage? Adding your company to [ADOPTERS](ADOPTERS.md)
# Get Started!
So...feel ready to jump in? Let's do this. Head over to the [Getting Started guide](https://github.com/spotify/backstage#getting-started) 👏🏻💯
So...feel ready to jump in? Let's do this. 👏🏻💯
If you need help, just jump into our [Discord chatroom](https://discord.gg/MUpMjP2).
Start by reading our [Getting Started](https://backstage.io/docs/getting-started/) page. If you need help, just jump into our [Discord chatroom](https://discord.gg/MUpMjP2).
# Coding Guidelines
All code is formatted with `prettier` using the configuration in the repo. If possible we recommend configuring your editor to format automatically, but you can also use the `yarn prettier --write <file>` command to format files.
If you're contributing to the backend or CLI tooling, be mindful of cross-platform support. [This](https://shapeshed.com/writing-cross-platform-node/) blog post is a good guide of what to keep in mind when writing cross-platform NodeJS.
Also be sure to skim through our [ADRs](https://github.com/spotify/backstage/tree/master/docs/architecture-decisions) to see if they cover what you're working on. In particular [ADR006: Avoid React.FC and React.SFC](https://github.com/spotify/backstage/blob/master/docs/architecture-decisions/adr006-avoid-react-fc.md) is one to look out for.
# Code of Conduct
+6 -1
View File
@@ -1,9 +1,14 @@
FROM nginx:mainline
# The purpose of this image is to serve the frontend app content separately.
# By default the Backstage backend uses the app-backend plugin to serve the
# app from the backend itself, but it may be desirable to move the frontend
# content serving to a separate deployment, in which case this image can be used.
# This dockerfile requires the app to be built on the host first, as it
# simply copies in the build output into the image.
# The safest way to build this image is to use `yarn docker-build`
# The safest way to build this image is to use `yarn docker-build:app`
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
+19
View File
@@ -0,0 +1,19 @@
# Owners
- See [CONTRIBUTING.md](CONTRIBUTING.md) for general contribution guidelines.
## Maintainers 🏓
- Patrik Oldsberg (@Rugvip, Spotify)
- Fredrik Adelöw (@freben, Spotify)
- Raghunandan Balachandran (@soapraj, Spotify)
- Ben Lambert (@benjdlambert, Spotify)
- Marcus Eide (@marcuseide, Spotify)
- Niklas Ek (@nikek, Spotify)
- Stefan Ålund (@stefanalund, Spotify)
- Kat Zhou (@katz95, Spotify)
## Hall of Fame 👏
- Andrew Thauer (@andrewthauer, Wealthsimple)
- Oliver Sand (@Fox32, SDA-SE)
+21 -78
View File
@@ -1,4 +1,4 @@
![headline](docs/headline.png)
![headline](docs/assets/headline.png)
# [Backstage](https://backstage.io)
@@ -6,105 +6,48 @@
![](https://github.com/spotify/backstage/workflows/Frontend%20CI/badge.svg)
[![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)
[![](https://img.shields.io/npm/v/@backstage/core?label=Version)](https://github.com/spotify/backstage/releases)
## What is Backstage?
[Backstage](https://backstage.io/) is an open platform for building developer portals. Its based on the developer portal weve been using internally at Spotify for over four years. Backstage can be as simple as a services catalog or as powerful as the UX layer for your entire tech infrastructure.
[Backstage](https://backstage.io/) is an open platform for building developer portals. Powered by a centralized service catalog, Backstage restores order to your microservices and infrastructure. So your product teams can ship high-quality code quickly — without compromising autonomy.
For more information go to [backstage.io](https://backstage.io) or join our [Discord chatroom](https://discord.gg/EBHEGzX).
### Features
- Create and manage all of your organizations software and microservices in one place.
- Services catalog keeps track of all software and its ownership.
- Visualizations provide information about your backend services and tooling, and help you monitor them.
- A unified method for managing microservices offers both visibility and control.
- Preset templates allow engineers to quickly create microservices in a standardized way ([coming soon](https://github.com/spotify/backstage/milestone/11)).
- Centralized, full-featured technical documentation with integrated tooling that makes it easy for developers to set up, publish, and maintain alongside their code ([coming soon](https://github.com/spotify/backstage/milestone/15)).
### Benefits
- For _engineering managers_, it allows you to maintain standards and best practices across the organization, and can help you manage your whole tech ecosystem, from migrations to test certification.
- For _end users_ (developers), it makes it fast and simple to build software components in a standardized way, and it provides a central place to manage all projects and documentation.
- For _platform engineers_, it enables extensibility and scalability by letting you easily integrate new tools and services (via plugins), as well as extending the functionality of existing ones.
- For _everyone_, its a single, consistent experience that ties all your infrastructure tooling, resources, standards, owners, contributors, and administrators together in one place.
## Backstage Service Catalog (alpha)
The Backstage Service Catalog — actually, a software catalog, since it includes more than just services — is a centralized system that keeps track of ownership and metadata for all the software in your ecosystem (services, websites, libraries, data pipelines, etc). The catalog is built around the concept of [metadata yaml files](https://github.com/spotify/backstage/blob/master/docs/architecture-decisions/adr002-default-catalog-file-format.md#format) stored together with the code, which are then harvested and visualized in Backstage.
Backstage unifies all your infrastructure tooling, services, and documentation to create a streamlined development environment from end to end.
![service-catalog](https://backstage.io/blog/assets/6/header.png)
We have also found that the service catalog is a great way to organise the infrastructure tools you use to manage the software as well. This is how Backstage creates one developer portal for all your tools. Rather than asking teams to jump between different infrastructure UIs (and incurring additional cognitive overhead each time they make a context switch), most of these tools can be organised around the entities in the catalog.
Out of the box, Backstage includes:
- [Backstage Service Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview) for managing all your software (microservices, libraries, data pipelines, websites, ML models, etc.)
- [Backstage Software Templates](https://backstage.io/docs/features/software-templates/software-templates-index) for quickly spinning up new projects and standardizing your tooling with your organizations best practices
- [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).
## Project roadmap
We created Backstage about 4 years ago. While our internal version of Backstage has had the benefit of time to mature and evolve, the first iteration of our open source version is still nascent. We are envisioning three phases of the project and we have already begun work on various aspects of these phases:
A detailed project roadmap, including already delivered milestones, is available [here](https://backstage.io/docs/overview/roadmap).
- 🐣 **Phase 1:** Extensible frontend platform (Done ✅) - You will be able to easily create a single consistent UI layer for your internal infrastructure and tools. A set of reusable [UX patterns and components](http://storybook.backstage.io) help ensure a consistent experience between tools.
## Getting Started
- 🐢 **Phase 2:** Service Catalog ([alpha released](https://backstage.io/blog/2020/06/22/backstage-service-catalog-alpha)) - With a single catalog, Backstage makes it easy for a team to manage ten services — and makes it possible for your company to manage thousands of them. Developers can get a uniform overview of all their software and related resources, regardless of how and where they are running, as well as an easy way to onboard and manage those resources.
- 🐇 **Phase 3:** Ecosystem (later) - Everyone's infrastructure stack is different. By fostering a vibrant community of contributors we hope to provide an ecosystem of Open Source plugins/integrations that allows you to pick the tools that match your stack.
Check out our [Milestones](https://github.com/spotify/backstage/milestones) and open [RFCs](https://github.com/spotify/backstage/labels/rfc) how they relate to the three Phases outlined above.
Our vision for Backstage is for it to become the trusted standard toolbox (read: UX layer) for the open source infrastructure landscape. Think of it like Kubernetes for developer experience. We realize this is an ambitious goal. We cant do it alone. If this sounds interesting or you'd like to help us shape our product vision, we'd love to talk. You can email me directly: [alund@spotify.com](mailto:alund@spotify.com).
## Overview
The Backstage platform consists of a number of different components:
- **app** - Main web application that users interact with. It's built up by a number of different _Plugins_. This repo contains an example implementation of an app (located in `packages/app`) and you can easily get started with your own app by [creating one](docs/create-an-app.md).
- [**plugins**](https://github.com/spotify/backstage/tree/master/plugins) - Each plugin is treated as a self-contained web app and can include almost any type of content. Plugins all use a common set of platform API's and reusable UI components. Plugins can fetch data either from the _backend_ or through any RESTful API exposed through the _proxy_.
- [**service catalog**](https://github.com/spotify/backstage/tree/master/packages/backend) - Service that holds the model of your software ecosystem, including organisational information and what team owns what software. The backend also has a Plugin model for extending its graph.
- [**proxy**](https://github.com/spotify/backstage/tree/master/plugins/proxy-backend) - Terminates HTTPS and exposes any RESTful API to Plugins.
- **identity** - A backend service that holds your organisation's metadata.
## Getting started
To run a Backstage app, you will need to have the following installed:
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- [NodeJS](https://nodejs.org/en/download/) - Active LTS Release, currently v12
- [yarn](https://classic.yarnpkg.com/en/docs/install)
After cloning this repo, open a terminal window and start the example app using the following commands from the project root:
```bash
yarn install # Install dependencies
yarn start # Start dev server, use --check to enable linting and type-checks
```
The final `yarn start` command should open a local instance of Backstage in your browser, otherwise open one of the URLs printed in the terminal.
And that's it! You are good to go 👍
### Next step
Take a look at the [Getting Started](docs/getting-started/index.md) guide to learn how to set up Backstage, and how to develop on the platform.
Check out [the documentation](https://backstage.io/docs/getting-started) on how to start using Backstage.
## Documentation
- [Main documentation](docs/README.md)
- [Service Catalog](docs/features/software-catalog/index.md)
- [Create a Backstage App](docs/getting-started/create-an-app.md)
- [Architecture](docs/overview/architecture-terminology.md) ([Decisions](docs/architecture-decisions/index.md))
- [Designing for Backstage](docs/dls/design.md)
- [Storybook - UI components](http://storybook.backstage.io)
## Contributing
We would love your help in building Backstage! See [CONTRIBUTING](CONTRIBUTING.md) for more information.
- [Main documentation](https://backstage.io/docs)
- [Service Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview)
- [Architecture](https://backstage.io/docs/overview/architecture-terminology) ([Decisions](https://backstage.io/docs/architecture-decisions/adrs-overview))
- [Designing for Backstage](https://backstage.io/docs/dls/design)
- [Storybook - UI components](https://backstage.io/storybook)
## Community
- [Discord chatroom](https://discord.gg/MUpMjP2) - Get support or discuss the project
- [Good First Issues](https://github.com/spotify/backstage/contribute) - Start here if you want to contribute
- [RFCs](https://github.com/spotify/backstage/labels/rfc) - Help shape the technical direction
- [FAQ](docs/FAQ.md) - Frequently Asked Questions
- [FAQ](https://backstage.io/docs/FAQ) - Frequently Asked Questions
- [Code of Conduct](CODE_OF_CONDUCT.md) - This is how we roll
- [Adopters](ADOPTERS.md) - Companies already using Backstage
- [Blog](https://backstage.io/blog/) - Announcements and updates
+11
View File
@@ -0,0 +1,11 @@
app:
baseUrl: http://localhost:3000
backend:
baseUrl: http://localhost:7000
listen:
port: 7000
cors:
origin: http://localhost:3000
methods: [GET, POST, PUT, DELETE]
credentials: true
+194 -10
View File
@@ -1,27 +1,211 @@
app:
title: Backstage Example App
baseUrl: http://localhost:3000
baseUrl: http://localhost:7000
backend:
baseUrl: http://localhost:7000
listen: 0.0.0.0:7000
cors:
origin: http://localhost:3000
methods: [GET, POST, PUT, DELETE]
credentials: true
listen:
port: 7000
database:
client: sqlite3
connection: ':memory:'
# See README.md in the proxy-backend plugin for information on the configuration format
proxy:
"/circleci/api":
target: "https://circleci.com/api/v1.1"
'/circleci/api':
target: https://circleci.com/api/v1.1
changeOrigin: true
pathRewrite:
"^/proxy/circleci/api/": "/"
'^/proxy/circleci/api/': '/'
headers:
Circle-Token:
$secret:
env: CIRCLECI_AUTH_TOKEN
'/jenkins/api':
target: http://localhost:8080
headers:
Authorization:
$secret:
env: JENKINS_BASIC_AUTH_HEADER
organization:
name: Spotify
techdocs:
storageUrl: https://techdocs-mock-sites.storage.googleapis.com
storageUrl: http://localhost:7000/techdocs/static/docs
requestUrl: http://localhost:7000/techdocs/docs
generators:
techdocs: 'docker'
sentry:
organization: spotify
rollbar:
organization: spotify
accountToken:
$secret:
env: ROLLBAR_ACCOUNT_TOKEN
newrelic:
api:
baseUrl: 'https://api.newrelic.com/v2'
key: NEW_RELIC_REST_API_KEY
lighthouse:
baseUrl: http://localhost:3003
catalog:
rules:
- allow: [Component, API, Group, Template, Location]
processors:
github:
providers:
- target: https://github.com
token:
$secret:
env: GITHUB_PRIVATE_TOKEN
#### Example for how to add your GitHub Enterprise instance using the API:
# - target: https://ghe.example.net
# apiBaseUrl: https://ghe.example.net/api/v3
# token:
# $secret:
# env: GHE_PRIVATE_TOKEN
#### Example for how to add your GitHub Enterprise instance using raw HTTP fetches (token is optional):
# - target: https://ghe.example.net
# rawBaseUrl: https://ghe.example.net/raw
# token:
# $secret:
# env: GHE_PRIVATE_TOKEN
bitbucketApi:
username:
$secret:
env: BITBUCKET_USERNAME
appPassword:
$secret:
env: BITBUCKET_APP_PASSWORD
gitlabApi:
privateToken:
$secret:
env: GITLAB_PRIVATE_TOKEN
azureApi:
privateToken:
$secret:
env: AZURE_PRIVATE_TOKEN
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
scaffolder:
github:
token:
$secret:
env: GITHUB_ACCESS_TOKEN
visibility: public # or 'internal' or 'private'
gitlab:
api:
baseUrl: https://gitlab.com
token:
$secret:
env: GITLAB_ACCESS_TOKEN
auth:
providers:
google:
development:
clientId:
$secret:
env: AUTH_GOOGLE_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GOOGLE_CLIENT_SECRET
github:
development:
clientId:
$secret:
env: AUTH_GITHUB_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GITHUB_CLIENT_SECRET
enterpriseInstanceUrl:
$secret:
env: AUTH_GITHUB_ENTERPRISE_INSTANCE_URL
gitlab:
development:
clientId:
$secret:
env: AUTH_GITLAB_CLIENT_ID
clientSecret:
$secret:
env: AUTH_GITLAB_CLIENT_SECRET
audience:
$secret:
env: GITLAB_BASE_URL
saml:
entryPoint: 'http://localhost:7001/'
issuer: 'passport-saml'
okta:
development:
clientId:
$secret:
env: AUTH_OKTA_CLIENT_ID
clientSecret:
$secret:
env: AUTH_OKTA_CLIENT_SECRET
audience:
$secret:
env: AUTH_OKTA_AUDIENCE
oauth2:
development:
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
+13
View File
@@ -0,0 +1,13 @@
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: backstage
description: |
Backstage is an open-source developer portal that puts the developer experience first.
annotations:
github.com/project-slug: spotify/backstage
backstage.io/techdocs-ref: github:https://github.com/spotify/backstage.git
spec:
type: library
owner: Spotify
lifecycle: experimental
+9
View File
@@ -0,0 +1,9 @@
# Backstage Contrib
This directory contains various community contributions related to Backstage.
Unless otherwise specified, all content in this hierarchy fall under the same
[licensing terms](../LICENSE) as in the rest of the repository, and come with
no guarantees of functionality or fitness of purpose. That being said, we
really appreciate contributions in here and encourage them being kept up to
date.
@@ -0,0 +1,23 @@
FROM node:12 AS build
RUN mkdir /app
COPY . /app
WORKDIR /app
RUN yarn install
RUN yarn workspace example-app build
# Contruct backstage-frontend image
FROM nginx:mainline
RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/*
# Copy from build stage
COPY --from=build /app/packages/app/dist /usr/share/nginx/html
COPY docker/default.conf.template /etc/nginx/conf.d/default.conf.template
COPY docker/run.sh /usr/local/bin/run.sh
CMD run.sh
ENV PORT 80
@@ -0,0 +1,19 @@
# Standalone Dockerfile for frontend
This directory contains the resources which will help you build backstage without any requirements
other than docker itself. It uses a multi-stage Dockerfile to build and ship backstage.
## Usage
You can simply run the following command to build backstage.
```
# Make sure you are in the root directory of backstage then run
docker build -t backstage-frontend -f ./contrib/docker/multi-stage-frontend/Dockerfile .
```
After a successful build, You can simply run backstage frontend with the following command.
```
docker run -it --rm -p 3080:80 backstage-frontend
```
@@ -0,0 +1 @@
# Basic Kubernetes example with Helm
@@ -11,17 +11,17 @@ spec:
matchLabels:
app: backstage
component: frontend
template:
metadata:
labels:
app: backstage
component: frontend
spec:
containers:
template:
metadata:
labels:
app: backstage
component: frontend
spec:
containers:
- name: app
image: spotify/backstage:latest
imagePullPolicy: Always
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: app
protocol: TCP
- containerPort: 80
name: app
protocol: TCP
@@ -11,17 +11,17 @@ spec:
matchLabels:
app: backstage
component: backend
template:
metadata:
labels:
app: backstage
component: backend
spec:
containers:
template:
metadata:
labels:
app: backstage
component: backend
spec:
containers:
- name: backend
image: spotify/backstage-backend:latest
imagePullPolicy: Always
imagePullPolicy: IfNotPresent
ports:
- containerPort: 7000
name: backend
protocol: TCP
- containerPort: 7000
name: backend
protocol: TCP
@@ -1,5 +1,5 @@
apiVersion: v1
appVersion: "1.0"
appVersion: '1.0'
description: A Helm chart for Spotify Backstage
name: backstage
version: 0.1.1-alpha.12
@@ -23,7 +23,7 @@
| app.resources | Kubernetes Pod resource requests/limits | `{}` |
| app.nodeSelector | Node selectors for scheduling app/frontend pods | `{}` |
| app.tolerations | Tolerations for scheduling app/frontend pods | `{}` |
| app.affinity | Affinity setttings for scheduling app/frontend pods | `{}` |
| app.affinity | Affinity settings for scheduling app/frontend pods | `{}` |
## Backend Values
@@ -48,4 +48,4 @@
| backend.resources | Kubernetes Pod resource requests/limits | `{}` |
| backend.nodeSelector | Node selectors for scheduling backend pods | `{}` |
| backend.tolerations | Tolerations for scheduling backend pods | `{}` |
| backend.affinity | Affinity setttings for scheduling backend pods | `{}` |
| backend.affinity | Affinity settings for scheduling backend pods | `{}` |
@@ -1,12 +1,12 @@
app:
enabled: true
nameOverride: ""
fullnameOverride: ""
nameOverride: ''
fullnameOverride: ''
replicaCount: 1
serviceAccount:
create: false
Name: ""
image:
Name: ''
image:
repository: spotify/backstage
tag: latest
pullPolicy: Always
@@ -15,20 +15,23 @@ app:
port: 80
ingress:
enabled: false
annotations: {}
annotations:
{}
# kubernetes.io/ingress.class: "nginx"
hosts:
- host: backstage.local
paths:
- /
- host: backstage.local
paths:
- /
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
imagePullSecrets: []
podSecurityContext: {}
podSecurityContext:
{}
# fsGroup: 2000
securityContext: {}
securityContext:
{}
# capabilities:
# drop:
# - ALL
@@ -48,12 +51,12 @@ app:
backend:
enabled: false
nameOverride: ""
fullnameOverride: ""
nameOverride: ''
fullnameOverride: ''
replicaCount: 1
serviceAccount:
create: false
Name: ""
Name: ''
image:
repository: spotify/backstage-backend
tag: latest
@@ -63,20 +66,23 @@ backend:
port: 7000
ingress:
enabled: false
annotations: {}
annotations:
{}
# kubernetes.io/ingress.class: "nginx"
hosts:
- host: backstage.local
paths:
- /backend
- host: backstage.local
paths:
- /backend
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
imagePullSecrets: []
podSecurityContext: {}
podSecurityContext:
{}
# fsGroup: 2000
securityContext: {}
securityContext:
{}
# capabilities:
# drop:
# - ALL
@@ -0,0 +1,20 @@
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: backstage
labels:
app: backstage
component: ingress
spec:
rules:
- host: <HOSTNAME>
http:
paths:
- backend:
serviceName: backstage
servicePort: frontend
path: /
- backend:
serviceName: backstage-backend
servicePort: backend
path: /backend
@@ -11,10 +11,10 @@ spec:
app: backstage
component: frontend
ports:
- name: frontend
port: 80
protocol: TCP
targetPort: app
- name: frontend
port: 80
protocol: TCP
targetPort: app
---
apiVersion: v1
kind: Service
@@ -29,7 +29,7 @@ spec:
app: backstage
component: backend
ports:
- name: backend
port: 7000
protocol: TCP
targetPort: backend
- name: backend
port: 7000
protocol: TCP
targetPort: backend
+2 -6
View File
@@ -1,14 +1,10 @@
# Make sure that before you
# run the docker-compose that you have run
# $ yarn docker-build:all
# $ yarn docker-build
version: '3'
services:
frontend:
image: 'spotify/backstage:latest'
ports:
- '3000:80'
backend:
backstage:
image: 'example-backend:latest'
ports:
- '7000:7000'
+4
View File
@@ -11,6 +11,10 @@ server {
try_files $uri /index.html;
}
location /healthcheck {
return 204;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
+2 -2
View File
@@ -16,13 +16,13 @@ function inject_config() {
with_entries(select(.key | startswith("APP_CONFIG_")) | .key |= sub("APP_CONFIG_"; "")) |
to_entries |
reduce .[] as $item (
{}; setpath($item.key | split("_"); $item.value | fromjson)
{}; setpath($item.key | split("_"); $item.value | try fromjson catch $item.value)
)')"
>&2 echo "Runtime app config: $config"
local main_js
if ! main_js="$(grep -l __APP_INJECTED_RUNTIME_CONFIG__ /usr/share/nginx/html/*.chunk.js)"; then
if ! main_js="$(grep -l __APP_INJECTED_RUNTIME_CONFIG__ /usr/share/nginx/html/static/*.js)"; then
echo "Runtime config already written"
return
fi
+53 -32
View File
@@ -1,6 +1,10 @@
# FAQ
---
id: FAQ
title: FAQ
description: All FAQ related to Backstage
---
## Product FAQ:
## Product FAQ
### Can we call Backstage something different? So that it fits our company better?
@@ -14,8 +18,7 @@ brand.
No, but it can be! Backstage is designed to be a developer portal for all your
infrastructure tooling, services, and documentation. So, it's not a monitoring
platform — but that doesn't mean you can't integrate a monitoring tool into
Backstage by writing
[a plugin](/docs/FAQ.md#what-is-a-plugin-in-backstage).
Backstage by writing [a plugin](#what-is-a-plugin-in-backstage).
### How is Backstage licensed?
@@ -36,12 +39,11 @@ more, read our blog post,
Yes, we've already started releasing open source versions of some of the plugins
we use here, and we'll continue to do so.
[Plugins](/docs/FAQ.md#what-is-a-plugin-in-backstage) are the
building blocks of functionality in Backstage. We have over 120 plugins inside
Spotify — many of those are specialized for our use, so will remain internal and
proprietary to us. But we estimate that about a third of our existing plugins
make good open source candidates. (And we'll probably end up writing some brand
new ones, too.)
[Plugins](#what-is-a-plugin-in-backstage) are the building blocks of
functionality in Backstage. We have over 120 plugins inside Spotify — many of
those are specialized for our use, so will remain internal and proprietary to
us. But we estimate that about a third of our existing plugins make good open
source candidates. (And we'll probably end up writing some brand new ones, too.)
### What's the roadmap for Backstage?
@@ -66,7 +68,7 @@ valuable as you grow.
Yes! The Backstage UI is built using Material-UI. With the theming capabilities
of Material-UI, you are able to adapt the interface to your brand guidelines.
## Technical FAQ:
## Technical FAQ
### Why Material-UI?
@@ -91,21 +93,31 @@ Node.js and GraphQL.
### What is the end-to-end user flow? The happy path story.
There are three main user profiles for Backstage: the integrator, the
contributor, and the software engineer.
contributor, and the software engineer.
The **integrator** hosts the Backstage app and configures which plugins are available to use in the app.
The **integrator** hosts the Backstage app and configures which plugins are
available to use in the app.
The **contributor** adds functionality to the app by writing plugins.
The **software engineer** uses the app's functionality and interacts with its plugins.
The **software engineer** uses the app's functionality and interacts with its
plugins.
### What is a "plugin" in Backstage?
Plugins are what provide the feature functionality in Backstage. They are used to integrate different systems into Backstage's frontend, so that the developer gets a consistent UX, no matter what tool or service is being accessed on the other side.
Plugins are what provide the feature functionality in Backstage. They are used
to integrate different systems into Backstage's frontend, so that the developer
gets a consistent UX, no matter what tool or service is being accessed on the
other side.
Each plugin is treated as a self-contained web app and can include almost any type of content. Plugins all use a common set of platform APIs and reusable UI components. Plugins can fetch data either from the backend or an API exposed through the proxy.
Each plugin is treated as a self-contained web app and can include almost any
type of content. Plugins all use a common set of platform APIs and reusable UI
components. Plugins can fetch data either from the backend or an API exposed
through the proxy.
Learn more about [the different components](https://github.com/spotify/backstage#overview) that make up Backstage.
Learn more about
[the different components](https://github.com/spotify/backstage#overview) that
make up Backstage.
### Do I have to write plugins in TypeScript?
@@ -127,7 +139,15 @@ can browse and search for all available plugins.
### Which plugin is used the most at Spotify?
By far, our most-used plugin is our TechDocs plugin, which we use for creating technical documentation. Our philosophy at Spotify is to treat "docs like code", where you write documentation using the same workflow as you write your code. This makes it easier to create, find, and update documentation. We hope to release [the open source version](https://github.com/spotify/backstage/issues/687) in the future. (See also: "[Will Spotify's internal plugins be open sourced, too?](/docs/FAQ.md#will-spotifys-internal-plugins-be-open-sourced-too)" above)
By far, our most-used plugin is our TechDocs plugin, which we use for creating
technical documentation. Our philosophy at Spotify is to treat "docs like code",
where you write documentation using the same workflow as you write your code.
This makes it easier to create, find, and update documentation. We hope to
release
[the open source version](https://github.com/spotify/backstage/issues/687) in
the future. (See also:
"[Will Spotify's internal plugins be open sourced, too?](#will-spotifys-internal-plugins-be-open-sourced-too)"
above)
### Are you planning to have plugins baked into the repo? Or should they be developed in separate repos?
@@ -135,10 +155,10 @@ Contributors can add open source plugins to the plugins directory in
[this monorepo](https://github.com/spotify/backstage). Integrators can then
configure which open source plugins are available to use in their instance of
the app. Open source plugins are downloaded as npm packages published in the
open source repository. While we encourage using the open source model, we
know there are cases where contributors might want to experiment internally or
keep their plugins closed source. Contributors writing closed source plugins
should develop them in the plugins directory in their own Backstage repository.
open source repository. While we encourage using the open source model, we know
there are cases where contributors might want to experiment internally or keep
their plugins closed source. Contributors writing closed source plugins should
develop them in the plugins directory in their own Backstage repository.
Integrators also configure closed source plugins locally from the monorepo.
### Any plans for integrating with other repository managers, such as GitLab or Bitbucket?
@@ -149,7 +169,8 @@ stage. Hosting this project on GitHub does not exclude integrations with
alternatives, such as
[GitLab](https://github.com/spotify/backstage/issues?q=is%3Aissue+is%3Aopen+GitLab)
or Bitbucket. We believe that in time there will be plugins that will provide
functionality for these tools as well. Hopefully, contributed by the community! Also note, implementations of Backstage can be hosted wherever you feel suits
functionality for these tools as well. Hopefully, contributed by the community!
Also note, implementations of Backstage can be hosted wherever you feel suits
your needs best.
### Who maintains Backstage?
@@ -165,8 +186,8 @@ maintains Backstage in your own environment.
### Does Spotify provide a managed version of Backstage?
No, this is not a service offering. We build the piece of software, and
someone in your infrastructure team is responsible for
No, this is not a service offering. We build the piece of software, and someone
in your infrastructure team is responsible for
[deploying](https://github.com/spotify/backstage/blob/master/DEPLOYMENT.md) and
maintaining it.
@@ -186,16 +207,16 @@ Please report sensitive security issues via Spotify's
No. Backstage does not collect any telemetry from any third party using the
platform. Spotify, and the open source community, does have access to
[GitHub Insights](https://github.com/features/insights), which contains
information such as contributors, commits, traffic, and dependencies.
Backstage is an open platform, but you are in control of your own data. You
control who has access to any data you provide to your version of Backstage and
who that data is shared with.
information such as contributors, commits, traffic, and dependencies. Backstage
is an open platform, but you are in control of your own data. You control who
has access to any data you provide to your version of Backstage and who that
data is shared with.
### Can Backstage be used to build something other than a developer portal?
Yes. The core frontend framework could be used for building any large-scale
web application where (1) multiple teams are building separate parts of the app,
and (2) you want the overall experience to be consistent. That being said, in
Yes. The core frontend framework could be used for building any large-scale web
application where (1) multiple teams are building separate parts of the app, and
(2) you want the overall experience to be consistent. That being said, in
[Phase 2](https://github.com/spotify/backstage#project-roadmap) of the project
we will add features that are needed for developer portals and systems for
managing software ecosystems. Our ambition will be to keep Backstage modular.
+2 -97
View File
@@ -1,98 +1,3 @@
# Documentation structure
# Documentation
**Note!** This documentation structure is very much work in progress. If (when,
really 😆) you find broken links or missing content, please create an issue or,
better yet, a pull request.
- Overview
- [What is Backstage?](overview/what-is-backstage.md)
- [Backstage architecture](overview/architecture-overview.md)
- [Architecture and terminology](overview/architecture-terminology.md)
- [Roadmap](overview/roadmap.md)
- Getting started
- [Running Backstage locally](getting-started/index.md)
- [Installation](getting-started/installation.md)
- [Local development](getting-started/development-environment.md)
- [Demo deployment](https://backstage-demo.roadie.io)
- Production deployments
- [Create an App](getting-started/create-an-app.md)
- App configuration
- [Configuring App with plugins](getting-started/configure-app-with-plugins.md)
- [Customize the look-and-feel of your App](getting-started/app-custom-theme.md)
- Deployment scenarios
- [Kubernetes](getting-started/deployment-k8s.md)
- [Other](getting-started/deployment-other.md)
- Features
- Software Catalog
- [Overview](features/software-catalog/index.md)
- [System model](features/software-catalog/system-model.md)
- [YAML File Format](features/software-catalog/descriptor-format.md)
- [Populating the catalog](features/software-catalog/populating.md)
- [Extending the model](features/software-catalog/extending-the-model.md)
- [External integrations](features/software-catalog/external-integrations.md)
- [API](features/software-catalog/api.md)
- Software creation templates
- [Overview](features/software-templates/index.md)
- [Adding templates](features/software-templates/adding-templates.md)
- Extending the Scaffolder:
- [Overview](features/software-templates/extending/index.md)
- [Create your own Templater](features/software-templates/extending/create-your-own-templater.md)
- [Create your own Publisher](features/software-templates/extending/create-your-own-publisher.md)
- [Create your own Preparer](features/software-templates/extending/create-your-own-preparer.md)
- Docs-like-code
- [Overview](features/techdocs/README.md)
- [Getting Started](features/techdocs/getting-started.md)
- [Concepts](features/techdocs/concepts.md)
- [Reading Documentation](features/techdocs/reading-documentation.md)
- [Writing Documentation](features/techdocs/writing-documentation.md)
- [Publishing Documentation](features/techdocs/publishing-documentation.md)
- [Contributing](features/techdocs/contributing.md)
- [Debugging](features/techdocs/debugging.md)
- [FAQ](features/techdocs/FAQ.md)
- Plugins
- [Overview](plugins/index.md)
- [Existing plugins](plugins/existing-plugins.md)
- [Creating a new plugin](plugins/create-a-plugin.md)
- [Developing a plugin](plugins/plugin-development.md)
- [Structure of a plugin](plugins/structure-of-a-plugin.md)
- Backends and APIs
- [Proxying](plugins/proxying.md)
- [Backstage backend plugin](plugins/backend-plugin.md)
- [Call existing API](plugins/call-existing-api.md)
- Testing
- [Overview](plugins/testing.md)
- Publishing
- [Open source and NPM](plugins/publishing.md)
- [Private/internal (non-open source)](plugins/publish-private.md)
- Authentication and identity
- [Overview](auth/index.md)
- [Add auth provider](auth/add-auth-provider.md)
- [Auth backend](auth/auth-backend.md)
- [OAuth](auth/oauth.md)
- [Glossary](auth/glossary.md)
- Designing for Backstage
- [Backstage Design Language System (DLS)](dls/design.md)
- [Storybook -- reusable UI components](http://storybook.backstage.io)
- [Contributing to Storybook](dls/contributing-to-storybook.md)
- [Figma resources](dls/figma.md)
- API references
- TypeScript API
- [Utilities](api/utility-apis.md)
- [createPlugin](reference/createPlugin.md)
- [createPlugin-feature-flags](reference/createPlugin-feature-flags.md)
- [createPlugin-router](reference/createPlugin-router.md)
- Backend APIs
- [Backend](api/backend.md)
- Tutorials
- [Overview](tutorials/index.md)
- Architecture Decision Records (ADRs)
- [Overview](architecture-decisions/index.md)
- [ADR001 - Architecture Decision Record (ADR) log](architecture-decisions/adr001-add-adr-log.md)
- [ADR002 - Default Software Catalog File Format](architecture-decisions/adr002-default-catalog-file-format.md)
- [ADR003 - Avoid Default Exports and Prefer Named Exports](architecture-decisions/adr003-avoid-default-exports.md)
- [ADR004 - Module Export Structure](architecture-decisions/adr004-module-export-structure.md)
- [ADR005 - Catalog Core Entities](architecture-decisions/adr005-catalog-core-entities.md)
- [ADR006 - Avoid React.FC and React.SFC](architecture-decisions/adr006-avoid-react-fc.md)
- [Contribute](../CONTRIBUTING.md)
- [Support](overview/support.md)
- [FAQ](FAQ.md)
The Backstage documentation is available at https://backstage.io/docs
+7
View File
@@ -0,0 +1,7 @@
---
id: backend
title: Backend
description: About Backend
---
## TODO
+134 -50
View File
@@ -1,4 +1,8 @@
# Utility APIs
---
id: utility-apis
title: Utility APIs
description: Backstage Utility APIs
---
## Introduction
@@ -14,12 +18,13 @@ Utility APIs. While the `createPlugin` API is focused on the initialization
plugins and the app, the Utility APIs provide ways for plugins to communicate
during their entire life cycle.
## Usage
## Consuming APIs
Each Utility API is tied to an `ApiRef` instance, which is a global singleton
object without any additional state or functionality, its only purpose is to
reference Utility APIs. `ApiRef`s are create using `createApiRef`, which is
exported by `@backstage/core`. There are many predefined Utility APIs defined in
exported by `@backstage/core`. There are many
[predefined Utility APIs](../reference/utility-apis/README.md) defined in
`@backstage/core`, and they're all exported with a name of the pattern
`*ApiRef`, for example `errorApiRef`.
@@ -51,47 +56,112 @@ from any component inside Backstage, including the ones in `@backstage/core`.
The only requirement is that they are beneath the `AppProvider` in the react
tree.
## Registering Utility API Implementations
## Supplying APIs
The Backstage App is responsible for providing implementations for all Utility
APIs required by plugins. The example app in this repo registers its APIs inside
[src/apis.ts](/packages/app/src/apis.ts). Here's an example of how to wire up
the `ErrorApi` inside an app:
### API Factories
APIs are registered in the form of `ApiFactories`, which encapsulate the process
of instantiating an API. It is a collection of three things: the `ApiRef` of the
API to instantiate, a list of all required dependencies, and a factory function
that returns a new API instance.
For example, this is the default `ApiFactory` for the `ErrorApi`:
```ts
import {
ApiRegistry,
createApp,
alertApiRef,
errorApiRef,
AlertApiForwarder,
ErrorApiForwarder,
ErrorAlerter,
} from '@backstage/core';
const builder = ApiRegistry.builder();
// The alert API is a self-contained implementation that shows alerts to the user.
const alertApi = builder.add(alertApiRef, new AlertApiForwarder());
// The error API uses the alert API to send error notifications to the user.
builder.add(errorApiRef, new ErrorAlerter(alertApi, new ErrorApiForwarder()));
const app = createApp({
apis: apiBuilder.build(),
// ... other config
createApiFactory({
api: errorApiRef,
deps: { alertApi: alertApiRef },
factory: ({ alertApi }) =>
new ErrorAlerter(alertApi, new ErrorApiForwarder()),
});
```
The `ApiRegistry` is used to register all Utility APIs in the app and associate
them with `ApiRef`s. It implements the `ApiHolder` interface, which enables it
to provide an API implementation given an `ApiRef`.
In this example the `errorApiRef` is our API, which encapsulates the `ErrorApi`
type. The `alertApiRef` is our single dependency, which we give the name
`alertApi`, and is then passed on to the factory function, which returns an
implementation of the `ErrorApi`.
Note that our `ErrorApi` implementation depends on another Utility API, the
`AlertApi`. This is the method with which APIs can depend on other APIs, using
manual dependency injection at the initialization of the app. In general, if you
want to depend on another Utility API in an implementation of an API, you import
the type for that API and make it a constructor parameter.
The `createApiFactory` function is a thin wrapper that enables TypeScript type
inference. You may notice that there are no type annotations in the above
example, and that is because we're able to infer all types from the `ApiRef`s.
TypeScript will make sure that the return value of the `factory` function
matches the type embedded in `api`'s `ApiRef`, in this case the `ErrorApi`. It
will also match the types between the `deps` and the parameters of the `factory`
function, again using the type embedded within the `ApiRef`s.
## Registering API Factories
The responsibility for adding Utility APIs to a Backstage app lies in three
different locations: the Backstage core library, each plugin included in the
app, and the app itself.
### Core APIs
Starting with the Backstage core library, it provides implementation for all of
the core APIs. The core APIs are the ones exported by `@backstage/core`, such as
the `errorApiRef` and `configApiRef`. You can find a full list of them
[here](../reference/utility-apis/README.md).
The core APIs are loaded for any app created with `createApp` from
`@backstage/core`, which means that there is no step that needs to be taken to
include these APIs in an app.
### Plugin APIs
In addition to the core APIs, plugins can define and export their own APIs.
While doing so they should usually also provide default implementations of their
own APIs, for example, the `catalog` plugin exports `catalogApiRef`, and also
supplies a default `ApiFactory` of that API using the `CatalogClient`. There is
one restriction to plugin-provided API Factories: plugins may not supply
factories for core APIs, trying to do so will cause the app to crash.
Plugins supply their APIs through the `apis` option of `createPlugin`, for
example:
```ts
export const plugin = createPlugin({
id: 'techdocs',
apis: [
createApiFactory({
api: techdocsStorageApiRef,
deps: { configApi: configApiRef },
factory({ configApi }) {
return new TechDocsStorageApi({
apiOrigin: configApi.getString('techdocs.storageUrl'),
});
},
}),
],
});
```
### App APIs
Lastly, the app itself is the final point where APIs can be added, and what has
the final say in what APIs will be loaded at runtime. The app may override the
factories for any of the core or plugin APIs, with the exception of the config,
app theme, and identity APIs. These are static APIs that are tied into the
`createApp` implementation, and therefore not possible to override.
Overriding APIs is useful for apps that want to switch out behavior to tailor it
to their environment. In some cases plugins may also export multiple
implementations of the same API, where they each have their own different
requirements on for example backend storage and surrounding environment.
Supplying APIs to the app works just like for plugins:
```ts
const app = createApp({
apis: [
/* ApiFactories */
],
// ... other options
});
```
A common pattern is to export a list of all APIs from `apis.ts`, next to
`App.tsx`. See the [example app in this repo](../../packages/app/src/apis.ts)
for an example.
## Custom implementations of Utility APIs
@@ -119,19 +189,33 @@ implement the `ErrorApi`, as it is checked by the type embedded in the
## Defining custom Utility APIs
The pattern for plugins defining their own Utility APIs is not fully established
yet. The current way is for the plugin to export its own `ApiRef` and type for
the API, along with one or more implementations. It is then up to the app to
import, and register those APIs. See for example the
[lighthouse](/plugins/lighthouse/src/api.ts) or
[graphiql](/plugins/graphiql/src/lib/api/types.ts) plugins for examples of this.
Plugins are free to define their own Utility APIs. Simply define the TypeScript
interface for the API, and create an `ApiRef` using `createApiRef` exported from
`@backstage/core`. Also be sure to provide at least one implementation of the
API, and to declare a default factory for the API in `createPlugin`.
The goal is to make this process a bit smoother, but that requires work in other
parts of Backstage, like configuration management. So it remains as a TODO. If
you have more questions regarding this, or have an idea for an API that you want
to share outside your plugin, hit us up in
[GitHub issues](https://github.com/spotify/backstage/issues/new/choose) or the
[Backstage Discord server](https://discord.gg/EBHEGzX).
Custom Utility APIs can be either public or private, which it is up to the
plugin to choose. Private APIs do not expose an external API surface, and it's
therefore possible to make breaking changes to the API without affecting other
users of the plugin. If an API is made public however, it opens up for other
plugins to make use of the API, and it also makes it possible for users for your
plugin to override the API in the app. It is however important to maintain
backwards compatibility of public APIs, as you may otherwise break apps that are
using your plugin.
To make an API public, simply export the `ApiRef` of the API, and any associated
types. To make an API private, just avoid exporting the `ApiRef`, but still be
sure to supply a default factory to `createPlugin`.
Private APIs are useful for plugins that want to depend on other APIs outside of
React components, but not have to expose an entire API surface to maintain. When
using private APIs, it is fine to use the `typeof` of an implementing class as
the type parameter passed to `createApiRef`, while public APIs should always
define a separate TypeScript interface type.
Plugins may depend on APIs from other plugins, both in React components and as
dependencies to API factories. Do however be sure to not cause circular
dependencies between plugins.
## Architecture
@@ -152,7 +236,7 @@ The figure below shows the relationship between
<span style="color: #b85450">fooApiRef</span>.
<div style="text-align:center">
<img src="utility-apis-fig1.svg" alt="Figure showing the relationship between utility APIs, the apps that provide them, and the plugins that consume them">
<img src="../assets/utility-apis-fig1.svg" alt="Figure showing the relationship between utility APIs, the apps that provide them, and the plugins that consume them">
</div>
The current method for connecting Utility API providers and consumers is via the
@@ -1,4 +1,8 @@
# ADR001: Architecture Decision Record (ADR) log
---
id: adrs-adr001
title: ADR001: Architecture Decision Record (ADR) log
description: Architecture Decision Record (ADR) logs as a reference point for the team
---
| Created | Status |
| ---------- | ------ |
@@ -1,4 +1,8 @@
# ADR002: Default Software Catalog File Format
---
id: adrs-adr002
title: ADR002: Default Software Catalog File Format
description: Architecture Decision Record (ADR) log on Default Software Catalog File Format
---
| Created | Status |
| ---------- | ------ |
@@ -64,7 +68,7 @@ metadata:
lifecycle: production
example.com/service-discovery-name: frobsawesome
annotations:
circleci.com/project-slug: gh/example-org/frobs-awesome
circleci.com/project-slug: github/example-org/frobs-awesome
spec:
type: service
```
@@ -1,4 +1,8 @@
# ADR003: Avoid Default Exports and Prefer Named Exports
---
id: adrs-adr003
title: ADR003: Avoid Default Exports and Prefer Named Exports
description: Architecture Decision Record (ADR) log on Avoid Default Exports and Prefer Named Exports
---
| Created | Status |
| ---------- | ------ |
@@ -1,4 +1,8 @@
# ADR004: Module Export Structure
---
id: adrs-adr004
title: ADR004: Module Export Structure
description: Architecture Decision Record (ADR) log on Module Export Structure
---
| Created | Status |
| ---------- | ------ |
@@ -1,4 +1,8 @@
# ADR005: Catalog Core Entities
---
id: adrs-adr005
title: ADR005: Catalog Core Entities
description: Architecture Decision Record (ADR) log on Catalog Core Entities
---
| Created | Status |
| ---------- | ------ |
@@ -18,7 +22,7 @@ Backstage should eventually support the following core entities:
- **Resources** are physical or virtual infrastructure needed to operate a
component
![Catalog Core Entities](catalog-core-entities.png)
![Catalog Core Entities](../assets/architecture-decisions/catalog-core-entities.png)
For now, we'll start by only implementing support for the Component entity in
the Backstage catalog. This can later be extended to APIs, Resources and other
@@ -1,4 +1,8 @@
# ADR006: Avoid React.FC and React.SFC
---
id: adrs-adr006
title: ADR006: Avoid React.FC and React.SFC
description: Architecture Decision Record (ADR) log on Avoid React.FC and React.SFC
---
## Context
@@ -0,0 +1,64 @@
---
id: adrs-adr007
title: ADR007: Use MSW to mock http requests
description: Architecture Decision Record (ADR) log on Use MSW to mock http requests
---
## Context
Network request mocking can be a total pain sometimes, in all different types of
tests, unit tests to e2e tests always have their own implementation of mocking
these requests. There's been traction in the outer community towards using this
library to mock network requests by using an express style declaration for
routes. react-testing-library suggests using this library instead of mocking
fetch directly wether this be in a browser or in node.
https://github.com/mswjs/msw
## Decision
Moving forward, we have decided that any `fetch` or `XMLHTTPRequest` that
happens, should be mocked by using `msw`.
Here is an example:
```ts
import { setupWorker, rest } from 'msw';
const worker = setupWorker(
rest.get('*/user/:userId', (req, res, ctx) => {
return res(
ctx.json({
firstName: 'John',
lastName: 'Maverick',
}),
);
}),
);
// Start the Mock Service Worker
worker.start();
```
and in a more real life scenario, taken from
[CatalogClient.test.ts](https://github.com/spotify/backstage/blob/f3245c4f8f0b6b2625c4a6d5d50161b612fb4757/plugins/catalog/src/api/CatalogClient.test.ts)
```ts
beforeEach(() => {
server.use(
rest.get(`${mockApiOrigin}${mockBasePath}/entities`, (_, res, ctx) => {
return res(ctx.json(defaultResponse));
}),
);
});
it('should entities from correct endpoint', async () => {
const entities = await client.getEntities();
expect(entities).toEqual(defaultResponse);
});
```
## Consequences
- A little more code to write
- Gradually will replace the codebase with `msw`
@@ -0,0 +1,26 @@
---
id: adrs-adr008
title: ADR008: Default Catalog File Name
description: Architecture Decision Record (ADR) log on Default Catalog File Name
---
## Background
While the spec for the catalog file format is well described in
[ADR002](./adr002-default-catalog-file-format.md), guidance was note provided as
to the name of the catalog file.
Following discussion in
[Issue 1822](https://github.com/spotify/backstage/pull/1822#pullrequestreview-461253670),
a decision was made.
## Name
The catalog file should be named
```shell
catalog-info.yaml
```
This name is a default, **not a requirement**. The catalog file will work with
Backstage irregardless of its name.
+11 -3
View File
@@ -1,6 +1,11 @@
# Architecture Decision Records (ADR)
---
id: adrs-overview
title: Architecture Decision Records (ADR)
sidebar_label: Overview
description: Overview of Architecture Decision Records (ADR)
---
The substantial architecture decisions made in the Backstage project lives here.
The substantial architecture decisions made in the Backstage project live here.
For more information about ADRs, when to write them, and why, please see
[this blog post](https://engineering.atspotify.com/2020/04/14/when-should-i-write-an-architecture-decision-record/).
@@ -19,7 +24,10 @@ Records should be stored under the `architecture-decisions` directory.
- Submit a pull request
- Address and integrate feedback from the community
- Eventually, assign a number
- Add the full path of the ADR to the [`mkdocs.yml`](/mkdocs.yml)
- Add the path of the ADR to the microsite sidebar in
[`sidebars.json`](https://github.com/spotify/backstage/blob/master/microsite/sidebars.json)
- Add the path of the ADR to the
[`mkdocs.yml`](https://github.com/spotify/backstage/blob/master/mkdocs.yml)
- Merge the pull request
## Superseding an ADR

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 181 KiB

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Before

Width:  |  Height:  |  Size: 265 KiB

After

Width:  |  Height:  |  Size: 265 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 204 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 293 KiB

After

Width:  |  Height:  |  Size: 293 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Before

Width:  |  Height:  |  Size: 269 KiB

After

Width:  |  Height:  |  Size: 269 KiB

Before

Width:  |  Height:  |  Size: 691 KiB

After

Width:  |  Height:  |  Size: 691 KiB

Before

Width:  |  Height:  |  Size: 389 KiB

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 KiB

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