Merge branch 'master' into link-button
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-azure-devops': patch
|
||||
---
|
||||
|
||||
Fixed `AssignedToCurrentUsersTeams` & `CreatedByCurrentUsersTeams` filter in `AzurePullRequestsPage` component.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
rollback `@rjsf/validator-ajv8` to `@rjsf/validator-v6`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-app-api': patch
|
||||
---
|
||||
|
||||
Fixed an issue were the log redaction didn't properly escape RegExp characters.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
lock versions of `@rjsf/*-beta` packages
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-explore-backend': patch
|
||||
---
|
||||
|
||||
Bump `msw` to `^0.49.0`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-tech-insights-backend-module-jsonfc': patch
|
||||
---
|
||||
|
||||
Surface the cause of the json rules engine
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Added the option to overwrite files in the `targetPath` of the `template:fetch` action
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
'@backstage/plugin-scaffolder-react': minor
|
||||
---
|
||||
|
||||
Embed scaffolder workflow in other components
|
||||
+179
-177
@@ -2,197 +2,199 @@
|
||||
"mode": "pre",
|
||||
"tag": "next",
|
||||
"initialVersions": {
|
||||
"example-app": "0.2.78",
|
||||
"@backstage/app-defaults": "1.0.9",
|
||||
"example-backend": "0.2.78",
|
||||
"@backstage/backend-app-api": "0.2.4",
|
||||
"@backstage/backend-common": "0.17.0",
|
||||
"@backstage/backend-defaults": "0.1.4",
|
||||
"example-backend-next": "0.0.6",
|
||||
"@backstage/backend-plugin-api": "0.2.0",
|
||||
"@backstage/backend-tasks": "0.4.0",
|
||||
"@backstage/backend-test-utils": "0.1.31",
|
||||
"@backstage/catalog-client": "1.2.0",
|
||||
"@backstage/catalog-model": "1.1.4",
|
||||
"@backstage/cli": "0.22.0",
|
||||
"example-app": "0.2.79",
|
||||
"@backstage/app-defaults": "1.1.0",
|
||||
"example-backend": "0.2.79",
|
||||
"@backstage/backend-app-api": "0.3.0",
|
||||
"@backstage/backend-common": "0.18.0",
|
||||
"@backstage/backend-defaults": "0.1.5",
|
||||
"example-backend-next": "0.0.7",
|
||||
"@backstage/backend-plugin-api": "0.3.0",
|
||||
"@backstage/backend-tasks": "0.4.1",
|
||||
"@backstage/backend-test-utils": "0.1.32",
|
||||
"@backstage/catalog-client": "1.3.0",
|
||||
"@backstage/catalog-model": "1.1.5",
|
||||
"@backstage/cli": "0.22.1",
|
||||
"@backstage/cli-common": "0.1.11",
|
||||
"@backstage/codemods": "0.1.42",
|
||||
"@backstage/config": "1.0.5",
|
||||
"@backstage/config-loader": "1.1.7",
|
||||
"@backstage/core-app-api": "1.3.0",
|
||||
"@backstage/core-components": "0.12.1",
|
||||
"@backstage/core-plugin-api": "1.2.0",
|
||||
"@backstage/create-app": "0.4.35",
|
||||
"@backstage/dev-utils": "1.0.9",
|
||||
"@backstage/config": "1.0.6",
|
||||
"@backstage/config-loader": "1.1.8",
|
||||
"@backstage/core-app-api": "1.4.0",
|
||||
"@backstage/core-components": "0.12.3",
|
||||
"@backstage/core-plugin-api": "1.3.0",
|
||||
"@backstage/create-app": "0.4.36",
|
||||
"@backstage/dev-utils": "1.0.11",
|
||||
"e2e-test": "0.2.0",
|
||||
"@backstage/errors": "1.1.4",
|
||||
"@backstage/integration": "1.4.1",
|
||||
"@backstage/integration-aws-node": "0.1.0",
|
||||
"@backstage/integration-react": "1.1.7",
|
||||
"@backstage/integration": "1.4.2",
|
||||
"@backstage/integration-aws-node": "0.1.1",
|
||||
"@backstage/integration-react": "1.1.9",
|
||||
"@backstage/release-manifests": "0.0.8",
|
||||
"@backstage/repo-tools": "0.1.0",
|
||||
"@techdocs/cli": "1.2.4",
|
||||
"techdocs-cli-embedded-app": "0.2.77",
|
||||
"@backstage/test-utils": "1.2.3",
|
||||
"@backstage/repo-tools": "0.1.1",
|
||||
"@techdocs/cli": "1.3.0",
|
||||
"techdocs-cli-embedded-app": "0.2.78",
|
||||
"@backstage/test-utils": "1.2.4",
|
||||
"@backstage/theme": "0.2.16",
|
||||
"@backstage/types": "1.0.2",
|
||||
"@backstage/version-bridge": "1.0.3",
|
||||
"@backstage/plugin-adr": "0.2.4",
|
||||
"@backstage/plugin-adr-backend": "0.2.4",
|
||||
"@backstage/plugin-adr-common": "0.2.4",
|
||||
"@backstage/plugin-airbrake": "0.3.12",
|
||||
"@backstage/plugin-airbrake-backend": "0.2.12",
|
||||
"@backstage/plugin-allure": "0.1.28",
|
||||
"@backstage/plugin-analytics-module-ga": "0.1.23",
|
||||
"@backstage/plugin-apache-airflow": "0.2.5",
|
||||
"@backstage/plugin-api-docs": "0.8.12",
|
||||
"@backstage/plugin-adr": "0.3.0",
|
||||
"@backstage/plugin-adr-backend": "0.2.5",
|
||||
"@backstage/plugin-adr-common": "0.2.5",
|
||||
"@backstage/plugin-airbrake": "0.3.14",
|
||||
"@backstage/plugin-airbrake-backend": "0.2.13",
|
||||
"@backstage/plugin-allure": "0.1.30",
|
||||
"@backstage/plugin-analytics-module-ga": "0.1.25",
|
||||
"@backstage/plugin-apache-airflow": "0.2.7",
|
||||
"@backstage/plugin-api-docs": "0.8.14",
|
||||
"@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.0",
|
||||
"@backstage/plugin-apollo-explorer": "0.1.5",
|
||||
"@backstage/plugin-app-backend": "0.3.39",
|
||||
"@backstage/plugin-auth-backend": "0.17.2",
|
||||
"@backstage/plugin-auth-node": "0.2.8",
|
||||
"@backstage/plugin-azure-devops": "0.2.3",
|
||||
"@backstage/plugin-azure-devops-backend": "0.3.18",
|
||||
"@backstage/plugin-apollo-explorer": "0.1.7",
|
||||
"@backstage/plugin-app-backend": "0.3.40",
|
||||
"@backstage/plugin-auth-backend": "0.17.3",
|
||||
"@backstage/plugin-auth-node": "0.2.9",
|
||||
"@backstage/plugin-azure-devops": "0.2.5",
|
||||
"@backstage/plugin-azure-devops-backend": "0.3.19",
|
||||
"@backstage/plugin-azure-devops-common": "0.3.0",
|
||||
"@backstage/plugin-azure-sites": "0.1.1",
|
||||
"@backstage/plugin-azure-sites-backend": "0.1.1",
|
||||
"@backstage/plugin-azure-sites": "0.1.3",
|
||||
"@backstage/plugin-azure-sites-backend": "0.1.2",
|
||||
"@backstage/plugin-azure-sites-common": "0.1.0",
|
||||
"@backstage/plugin-badges": "0.2.36",
|
||||
"@backstage/plugin-badges-backend": "0.1.33",
|
||||
"@backstage/plugin-bazaar": "0.2.1",
|
||||
"@backstage/plugin-bazaar-backend": "0.2.2",
|
||||
"@backstage/plugin-bitbucket-cloud-common": "0.2.2",
|
||||
"@backstage/plugin-bitrise": "0.1.39",
|
||||
"@backstage/plugin-catalog": "1.7.0",
|
||||
"@backstage/plugin-catalog-backend": "1.6.0",
|
||||
"@backstage/plugin-catalog-backend-module-aws": "0.1.12",
|
||||
"@backstage/plugin-catalog-backend-module-azure": "0.1.10",
|
||||
"@backstage/plugin-catalog-backend-module-bitbucket": "0.2.6",
|
||||
"@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.6",
|
||||
"@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.4",
|
||||
"@backstage/plugin-catalog-backend-module-gerrit": "0.1.7",
|
||||
"@backstage/plugin-catalog-backend-module-github": "0.2.2",
|
||||
"@backstage/plugin-catalog-backend-module-gitlab": "0.1.10",
|
||||
"@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.1.0",
|
||||
"@backstage/plugin-catalog-backend-module-ldap": "0.5.6",
|
||||
"@backstage/plugin-catalog-backend-module-msgraph": "0.4.5",
|
||||
"@backstage/plugin-catalog-backend-module-openapi": "0.1.5",
|
||||
"@backstage/plugin-catalog-common": "1.0.9",
|
||||
"@internal/plugin-catalog-customized": "0.0.5",
|
||||
"@backstage/plugin-catalog-graph": "0.2.24",
|
||||
"@backstage/plugin-catalog-graphql": "0.3.16",
|
||||
"@backstage/plugin-catalog-import": "0.9.2",
|
||||
"@backstage/plugin-catalog-node": "1.3.0",
|
||||
"@backstage/plugin-catalog-react": "1.2.2",
|
||||
"@backstage/plugin-cicd-statistics": "0.1.14",
|
||||
"@backstage/plugin-cicd-statistics-module-gitlab": "0.1.8",
|
||||
"@backstage/plugin-circleci": "0.3.12",
|
||||
"@backstage/plugin-cloudbuild": "0.3.12",
|
||||
"@backstage/plugin-code-climate": "0.1.12",
|
||||
"@backstage/plugin-code-coverage": "0.2.5",
|
||||
"@backstage/plugin-code-coverage-backend": "0.2.5",
|
||||
"@backstage/plugin-codescene": "0.1.7",
|
||||
"@backstage/plugin-config-schema": "0.1.35",
|
||||
"@backstage/plugin-cost-insights": "0.12.1",
|
||||
"@backstage/plugin-badges": "0.2.38",
|
||||
"@backstage/plugin-badges-backend": "0.1.34",
|
||||
"@backstage/plugin-bazaar": "0.2.3",
|
||||
"@backstage/plugin-bazaar-backend": "0.2.3",
|
||||
"@backstage/plugin-bitbucket-cloud-common": "0.2.3",
|
||||
"@backstage/plugin-bitrise": "0.1.41",
|
||||
"@backstage/plugin-catalog": "1.7.2",
|
||||
"@backstage/plugin-catalog-backend": "1.7.0",
|
||||
"@backstage/plugin-catalog-backend-module-aws": "0.1.13",
|
||||
"@backstage/plugin-catalog-backend-module-azure": "0.1.11",
|
||||
"@backstage/plugin-catalog-backend-module-bitbucket": "0.2.7",
|
||||
"@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.1.7",
|
||||
"@backstage/plugin-catalog-backend-module-bitbucket-server": "0.1.5",
|
||||
"@backstage/plugin-catalog-backend-module-gerrit": "0.1.8",
|
||||
"@backstage/plugin-catalog-backend-module-github": "0.2.3",
|
||||
"@backstage/plugin-catalog-backend-module-gitlab": "0.1.11",
|
||||
"@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.1.1",
|
||||
"@backstage/plugin-catalog-backend-module-ldap": "0.5.7",
|
||||
"@backstage/plugin-catalog-backend-module-msgraph": "0.4.6",
|
||||
"@backstage/plugin-catalog-backend-module-openapi": "0.1.6",
|
||||
"@backstage/plugin-catalog-common": "1.0.10",
|
||||
"@internal/plugin-catalog-customized": "0.0.6",
|
||||
"@backstage/plugin-catalog-graph": "0.2.26",
|
||||
"@backstage/plugin-catalog-graphql": "0.3.17",
|
||||
"@backstage/plugin-catalog-import": "0.9.4",
|
||||
"@backstage/plugin-catalog-node": "1.3.1",
|
||||
"@backstage/plugin-catalog-react": "1.2.4",
|
||||
"@backstage/plugin-cicd-statistics": "0.1.16",
|
||||
"@backstage/plugin-cicd-statistics-module-gitlab": "0.1.10",
|
||||
"@backstage/plugin-circleci": "0.3.14",
|
||||
"@backstage/plugin-cloudbuild": "0.3.14",
|
||||
"@backstage/plugin-code-climate": "0.1.14",
|
||||
"@backstage/plugin-code-coverage": "0.2.7",
|
||||
"@backstage/plugin-code-coverage-backend": "0.2.6",
|
||||
"@backstage/plugin-codescene": "0.1.9",
|
||||
"@backstage/plugin-config-schema": "0.1.37",
|
||||
"@backstage/plugin-cost-insights": "0.12.3",
|
||||
"@backstage/plugin-cost-insights-common": "0.1.1",
|
||||
"@backstage/plugin-dynatrace": "1.0.2",
|
||||
"@backstage/plugin-events-backend": "0.2.0",
|
||||
"@backstage/plugin-events-backend-module-aws-sqs": "0.1.1",
|
||||
"@backstage/plugin-events-backend-module-azure": "0.1.1",
|
||||
"@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.1",
|
||||
"@backstage/plugin-events-backend-module-gerrit": "0.1.1",
|
||||
"@backstage/plugin-events-backend-module-github": "0.1.1",
|
||||
"@backstage/plugin-events-backend-module-gitlab": "0.1.1",
|
||||
"@backstage/plugin-events-backend-test-utils": "0.1.1",
|
||||
"@backstage/plugin-events-node": "0.2.0",
|
||||
"@internal/plugin-todo-list": "1.0.8",
|
||||
"@internal/plugin-todo-list-backend": "1.0.8",
|
||||
"@internal/plugin-todo-list-common": "1.0.7",
|
||||
"@backstage/plugin-explore": "0.3.43",
|
||||
"@backstage/plugin-explore-backend": "0.0.1",
|
||||
"@backstage/plugin-dynatrace": "1.0.4",
|
||||
"@backstage/plugin-events-backend": "0.2.1",
|
||||
"@backstage/plugin-events-backend-module-aws-sqs": "0.1.2",
|
||||
"@backstage/plugin-events-backend-module-azure": "0.1.2",
|
||||
"@backstage/plugin-events-backend-module-bitbucket-cloud": "0.1.2",
|
||||
"@backstage/plugin-events-backend-module-gerrit": "0.1.2",
|
||||
"@backstage/plugin-events-backend-module-github": "0.1.2",
|
||||
"@backstage/plugin-events-backend-module-gitlab": "0.1.2",
|
||||
"@backstage/plugin-events-backend-test-utils": "0.1.2",
|
||||
"@backstage/plugin-events-node": "0.2.1",
|
||||
"@internal/plugin-todo-list": "1.0.9",
|
||||
"@internal/plugin-todo-list-backend": "1.0.9",
|
||||
"@internal/plugin-todo-list-common": "1.0.8",
|
||||
"@backstage/plugin-explore": "0.3.45",
|
||||
"@backstage/plugin-explore-backend": "0.0.2",
|
||||
"@backstage/plugin-explore-common": "0.0.1",
|
||||
"@backstage/plugin-explore-react": "0.0.24",
|
||||
"@backstage/plugin-firehydrant": "0.1.29",
|
||||
"@backstage/plugin-fossa": "0.2.44",
|
||||
"@backstage/plugin-gcalendar": "0.3.8",
|
||||
"@backstage/plugin-gcp-projects": "0.3.31",
|
||||
"@backstage/plugin-git-release-manager": "0.3.25",
|
||||
"@backstage/plugin-github-actions": "0.5.12",
|
||||
"@backstage/plugin-github-deployments": "0.1.43",
|
||||
"@backstage/plugin-github-issues": "0.2.1",
|
||||
"@backstage/plugin-github-pull-requests-board": "0.1.6",
|
||||
"@backstage/plugin-gitops-profiles": "0.3.30",
|
||||
"@backstage/plugin-gocd": "0.1.18",
|
||||
"@backstage/plugin-graphiql": "0.2.44",
|
||||
"@backstage/plugin-graphql-backend": "0.1.29",
|
||||
"@backstage/plugin-home": "0.4.28",
|
||||
"@backstage/plugin-ilert": "0.2.1",
|
||||
"@backstage/plugin-jenkins": "0.7.11",
|
||||
"@backstage/plugin-jenkins-backend": "0.1.29",
|
||||
"@backstage/plugin-jenkins-common": "0.1.11",
|
||||
"@backstage/plugin-kafka": "0.3.12",
|
||||
"@backstage/plugin-kafka-backend": "0.2.32",
|
||||
"@backstage/plugin-kubernetes": "0.7.5",
|
||||
"@backstage/plugin-kubernetes-backend": "0.9.0",
|
||||
"@backstage/plugin-kubernetes-common": "0.5.0",
|
||||
"@backstage/plugin-lighthouse": "0.3.12",
|
||||
"@backstage/plugin-newrelic": "0.3.30",
|
||||
"@backstage/plugin-newrelic-dashboard": "0.2.5",
|
||||
"@backstage/plugin-org": "0.6.2",
|
||||
"@backstage/plugin-org-react": "0.1.1",
|
||||
"@backstage/plugin-pagerduty": "0.5.5",
|
||||
"@backstage/plugin-periskop": "0.1.10",
|
||||
"@backstage/plugin-periskop-backend": "0.1.10",
|
||||
"@backstage/plugin-permission-backend": "0.5.14",
|
||||
"@backstage/plugin-permission-common": "0.7.2",
|
||||
"@backstage/plugin-permission-node": "0.7.2",
|
||||
"@backstage/plugin-permission-react": "0.4.8",
|
||||
"@backstage/plugin-playlist": "0.1.3",
|
||||
"@backstage/plugin-playlist-backend": "0.2.2",
|
||||
"@backstage/plugin-playlist-common": "0.1.3",
|
||||
"@backstage/plugin-proxy-backend": "0.2.33",
|
||||
"@backstage/plugin-rollbar": "0.4.12",
|
||||
"@backstage/plugin-rollbar-backend": "0.1.36",
|
||||
"@backstage/plugin-scaffolder": "1.9.0",
|
||||
"@backstage/plugin-scaffolder-backend": "1.9.0",
|
||||
"@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.14",
|
||||
"@backstage/plugin-scaffolder-backend-module-rails": "0.4.7",
|
||||
"@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.12",
|
||||
"@backstage/plugin-scaffolder-common": "1.2.3",
|
||||
"@backstage/plugin-search": "1.0.5",
|
||||
"@backstage/plugin-search-backend": "1.2.0",
|
||||
"@backstage/plugin-search-backend-module-elasticsearch": "1.1.0",
|
||||
"@backstage/plugin-search-backend-module-pg": "0.5.0",
|
||||
"@backstage/plugin-search-backend-node": "1.1.0",
|
||||
"@backstage/plugin-search-common": "1.2.0",
|
||||
"@backstage/plugin-search-react": "1.3.0",
|
||||
"@backstage/plugin-sentry": "0.4.5",
|
||||
"@backstage/plugin-shortcuts": "0.3.4",
|
||||
"@backstage/plugin-sonarqube": "0.6.0",
|
||||
"@backstage/plugin-sonarqube-backend": "0.1.4",
|
||||
"@backstage/plugin-sonarqube-react": "0.1.0",
|
||||
"@backstage/plugin-splunk-on-call": "0.4.1",
|
||||
"@backstage/plugin-stack-overflow": "0.1.8",
|
||||
"@backstage/plugin-stack-overflow-backend": "0.1.8",
|
||||
"@backstage/plugin-tech-insights": "0.3.4",
|
||||
"@backstage/plugin-tech-insights-backend": "0.5.5",
|
||||
"@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.23",
|
||||
"@backstage/plugin-explore-react": "0.0.25",
|
||||
"@backstage/plugin-firehydrant": "0.1.31",
|
||||
"@backstage/plugin-fossa": "0.2.46",
|
||||
"@backstage/plugin-gcalendar": "0.3.10",
|
||||
"@backstage/plugin-gcp-projects": "0.3.33",
|
||||
"@backstage/plugin-git-release-manager": "0.3.27",
|
||||
"@backstage/plugin-github-actions": "0.5.14",
|
||||
"@backstage/plugin-github-deployments": "0.1.45",
|
||||
"@backstage/plugin-github-issues": "0.2.3",
|
||||
"@backstage/plugin-github-pull-requests-board": "0.1.8",
|
||||
"@backstage/plugin-gitops-profiles": "0.3.32",
|
||||
"@backstage/plugin-gocd": "0.1.20",
|
||||
"@backstage/plugin-graphiql": "0.2.46",
|
||||
"@backstage/plugin-graphql-backend": "0.1.30",
|
||||
"@backstage/plugin-home": "0.4.30",
|
||||
"@backstage/plugin-ilert": "0.2.3",
|
||||
"@backstage/plugin-jenkins": "0.7.13",
|
||||
"@backstage/plugin-jenkins-backend": "0.1.30",
|
||||
"@backstage/plugin-jenkins-common": "0.1.12",
|
||||
"@backstage/plugin-kafka": "0.3.14",
|
||||
"@backstage/plugin-kafka-backend": "0.2.33",
|
||||
"@backstage/plugin-kubernetes": "0.7.7",
|
||||
"@backstage/plugin-kubernetes-backend": "0.9.1",
|
||||
"@backstage/plugin-kubernetes-common": "0.5.1",
|
||||
"@backstage/plugin-lighthouse": "0.3.14",
|
||||
"@backstage/plugin-newrelic": "0.3.32",
|
||||
"@backstage/plugin-newrelic-dashboard": "0.2.7",
|
||||
"@backstage/plugin-org": "0.6.4",
|
||||
"@backstage/plugin-org-react": "0.1.3",
|
||||
"@backstage/plugin-pagerduty": "0.5.7",
|
||||
"@backstage/plugin-periskop": "0.1.12",
|
||||
"@backstage/plugin-periskop-backend": "0.1.11",
|
||||
"@backstage/plugin-permission-backend": "0.5.15",
|
||||
"@backstage/plugin-permission-common": "0.7.3",
|
||||
"@backstage/plugin-permission-node": "0.7.3",
|
||||
"@backstage/plugin-permission-react": "0.4.9",
|
||||
"@backstage/plugin-playlist": "0.1.5",
|
||||
"@backstage/plugin-playlist-backend": "0.2.3",
|
||||
"@backstage/plugin-playlist-common": "0.1.4",
|
||||
"@backstage/plugin-proxy-backend": "0.2.34",
|
||||
"@backstage/plugin-rollbar": "0.4.14",
|
||||
"@backstage/plugin-rollbar-backend": "0.1.37",
|
||||
"@backstage/plugin-scaffolder": "1.10.0",
|
||||
"@backstage/plugin-scaffolder-backend": "1.10.0",
|
||||
"@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.2.15",
|
||||
"@backstage/plugin-scaffolder-backend-module-rails": "0.4.8",
|
||||
"@backstage/plugin-scaffolder-backend-module-sentry": "0.1.0",
|
||||
"@backstage/plugin-scaffolder-backend-module-yeoman": "0.2.13",
|
||||
"@backstage/plugin-scaffolder-common": "1.2.4",
|
||||
"@backstage/plugin-scaffolder-react": "1.0.0",
|
||||
"@backstage/plugin-search": "1.0.7",
|
||||
"@backstage/plugin-search-backend": "1.2.1",
|
||||
"@backstage/plugin-search-backend-module-elasticsearch": "1.1.1",
|
||||
"@backstage/plugin-search-backend-module-pg": "0.5.1",
|
||||
"@backstage/plugin-search-backend-node": "1.1.1",
|
||||
"@backstage/plugin-search-common": "1.2.1",
|
||||
"@backstage/plugin-search-react": "1.4.0",
|
||||
"@backstage/plugin-sentry": "0.4.7",
|
||||
"@backstage/plugin-shortcuts": "0.3.6",
|
||||
"@backstage/plugin-sonarqube": "0.6.2",
|
||||
"@backstage/plugin-sonarqube-backend": "0.1.5",
|
||||
"@backstage/plugin-sonarqube-react": "0.1.1",
|
||||
"@backstage/plugin-splunk-on-call": "0.4.3",
|
||||
"@backstage/plugin-stack-overflow": "0.1.10",
|
||||
"@backstage/plugin-stack-overflow-backend": "0.1.9",
|
||||
"@backstage/plugin-tech-insights": "0.3.6",
|
||||
"@backstage/plugin-tech-insights-backend": "0.5.6",
|
||||
"@backstage/plugin-tech-insights-backend-module-jsonfc": "0.1.24",
|
||||
"@backstage/plugin-tech-insights-common": "0.2.9",
|
||||
"@backstage/plugin-tech-insights-node": "0.3.7",
|
||||
"@backstage/plugin-tech-radar": "0.5.19",
|
||||
"@backstage/plugin-techdocs": "1.4.1",
|
||||
"@backstage/plugin-techdocs-addons-test-utils": "1.0.7",
|
||||
"@backstage/plugin-techdocs-backend": "1.5.0",
|
||||
"@backstage/plugin-techdocs-module-addons-contrib": "1.0.7",
|
||||
"@backstage/plugin-techdocs-node": "1.4.3",
|
||||
"@backstage/plugin-techdocs-react": "1.1.0",
|
||||
"@backstage/plugin-todo": "0.2.14",
|
||||
"@backstage/plugin-todo-backend": "0.1.36",
|
||||
"@backstage/plugin-user-settings": "0.6.0",
|
||||
"@backstage/plugin-user-settings-backend": "0.1.3",
|
||||
"@backstage/plugin-vault": "0.1.6",
|
||||
"@backstage/plugin-vault-backend": "0.2.5",
|
||||
"@backstage/plugin-xcmetrics": "0.2.32"
|
||||
"@backstage/plugin-tech-insights-node": "0.3.8",
|
||||
"@backstage/plugin-tech-radar": "0.6.0",
|
||||
"@backstage/plugin-techdocs": "1.4.3",
|
||||
"@backstage/plugin-techdocs-addons-test-utils": "1.0.9",
|
||||
"@backstage/plugin-techdocs-backend": "1.5.1",
|
||||
"@backstage/plugin-techdocs-module-addons-contrib": "1.0.9",
|
||||
"@backstage/plugin-techdocs-node": "1.4.4",
|
||||
"@backstage/plugin-techdocs-react": "1.1.2",
|
||||
"@backstage/plugin-todo": "0.2.16",
|
||||
"@backstage/plugin-todo-backend": "0.1.37",
|
||||
"@backstage/plugin-user-settings": "0.6.2",
|
||||
"@backstage/plugin-user-settings-backend": "0.1.4",
|
||||
"@backstage/plugin-vault": "0.1.8",
|
||||
"@backstage/plugin-vault-backend": "0.2.6",
|
||||
"@backstage/plugin-xcmetrics": "0.2.34"
|
||||
},
|
||||
"changesets": []
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-adr': patch
|
||||
---
|
||||
|
||||
Render the common `<MissingAnnotationEmptyState />` component when the `backstage.io/adr-location` annotation is missing from the component
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Fixed an issue where internal references in the catalog would stick around for longer than expected, causing entities to not be deleted or orphaned as expected.
|
||||
@@ -247,6 +247,11 @@ module.exports = {
|
||||
{
|
||||
forbid: [
|
||||
{ element: 'button', message: 'use MUI <Button> instead' },
|
||||
{ element: 'p', message: 'use MUI <Typography> instead' },
|
||||
{
|
||||
element: 'span',
|
||||
message: 'use a MUI <Typography> variant instead',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -8,11 +8,11 @@ x-uffizzi:
|
||||
services:
|
||||
backstage:
|
||||
image: '${BACKSTAGE_IMAGE}'
|
||||
|
||||
environment:
|
||||
POSTGRES_HOST: localhost
|
||||
POSTGRES_HOST: db
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: example
|
||||
GITHUB_TOKEN: abc
|
||||
NODE_ENV: production
|
||||
deploy:
|
||||
resources:
|
||||
@@ -21,7 +21,7 @@ services:
|
||||
entrypoint: '/bin/sh'
|
||||
command:
|
||||
- '-c'
|
||||
- "APP_CONFIG_app_baseUrl=$$UFFIZZI_URL APP_CONFIG_backend_baseUrl=$$UFFIZZI_URL APP_CONFIG_auth_environment='production' node packages/backend --config app-config.yaml --config app-config.production.yaml"
|
||||
- "APP_CONFIG_app_baseUrl=$$UFFIZZI_URL APP_CONFIG_backend_baseUrl=$$UFFIZZI_URL APP_CONFIG_auth_environment='production' node packages/backend --config app-config.yaml"
|
||||
|
||||
db:
|
||||
image: postgres
|
||||
|
||||
@@ -2,9 +2,271 @@ app:
|
||||
title: Backstage Uffizzi Environment
|
||||
baseUrl: ${UFFIZZI_URL}
|
||||
|
||||
organization:
|
||||
name: My Company
|
||||
|
||||
backend:
|
||||
baseUrl: ${UFFIZZI_URL}
|
||||
auth:
|
||||
keys:
|
||||
# random mock key for uffizi deployments
|
||||
- secret: 5TXvdjVZFxF7qf9K5RAYRDoGrLzJooqa
|
||||
listen:
|
||||
port: 7007
|
||||
database:
|
||||
client: better-sqlite3
|
||||
connection: ':memory:'
|
||||
cache:
|
||||
store: memory
|
||||
cors:
|
||||
origin: ${UFFIZZI_URL}
|
||||
methods: [GET, POST, PUT, DELETE]
|
||||
methods: [GET, HEAD, PATCH, POST, PUT, DELETE]
|
||||
credentials: true
|
||||
csp:
|
||||
connect-src: ["'self'", 'http:', 'https:']
|
||||
# Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference
|
||||
# Default Helmet Content-Security-Policy values can be removed by setting the key to false
|
||||
|
||||
auth:
|
||||
environment: production
|
||||
providers: {}
|
||||
proxy:
|
||||
enabled: true
|
||||
url: https://demo.backstage.io/api/auth
|
||||
|
||||
catalog:
|
||||
locations:
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/all.yaml
|
||||
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml
|
||||
rules:
|
||||
- allow: [User, Group]
|
||||
|
||||
- type: url
|
||||
target: https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/all-templates.yaml
|
||||
rules:
|
||||
- allow: [Template]
|
||||
|
||||
proxy:
|
||||
'/circleci/api':
|
||||
target: https://circleci.com/api/v1.1
|
||||
headers:
|
||||
Circle-Token: ${CIRCLECI_AUTH_TOKEN}
|
||||
|
||||
'/jenkins/api':
|
||||
target: http://localhost:8080
|
||||
headers:
|
||||
Authorization: ${JENKINS_BASIC_AUTH_HEADER}
|
||||
|
||||
'/travisci/api':
|
||||
target: https://api.travis-ci.com
|
||||
changeOrigin: true
|
||||
headers:
|
||||
Authorization: ${TRAVISCI_AUTH_TOKEN}
|
||||
travis-api-version: '3'
|
||||
|
||||
'/newrelic/apm/api':
|
||||
target: https://api.newrelic.com/v2
|
||||
headers:
|
||||
X-Api-Key: ${NEW_RELIC_REST_API_KEY}
|
||||
|
||||
'/newrelic/api':
|
||||
target: https://api.newrelic.com
|
||||
headers:
|
||||
X-Api-Key: ${NEW_RELIC_USER_KEY}
|
||||
|
||||
'/pagerduty':
|
||||
target: https://api.pagerduty.com
|
||||
headers:
|
||||
Authorization: Token token=${PAGERDUTY_TOKEN}
|
||||
|
||||
'/buildkite/api':
|
||||
target: https://api.buildkite.com/v2/
|
||||
headers:
|
||||
Authorization: ${BUILDKITE_TOKEN}
|
||||
|
||||
'/sentry/api':
|
||||
target: https://sentry.io/api/
|
||||
allowedMethods: ['GET']
|
||||
headers:
|
||||
Authorization: ${SENTRY_TOKEN}
|
||||
|
||||
'/ilert':
|
||||
target: https://api.ilert.com
|
||||
allowedMethods: ['GET', 'POST', 'PUT']
|
||||
allowedHeaders: ['Authorization']
|
||||
headers:
|
||||
Authorization: ${ILERT_AUTH_HEADER}
|
||||
|
||||
'/airflow':
|
||||
target: https://your.airflow.instance.com/api/v1
|
||||
headers:
|
||||
Authorization: ${AIRFLOW_BASIC_AUTH_HEADER}
|
||||
|
||||
'/gocd':
|
||||
target: https://your.gocd.instance.com/go/api
|
||||
allowedMethods: ['GET']
|
||||
allowedHeaders: ['Authorization']
|
||||
headers:
|
||||
Authorization: Basic ${GOCD_AUTH_CREDENTIALS}
|
||||
|
||||
'/dynatrace':
|
||||
target: https://your.dynatrace.instance.com/api/v2
|
||||
headers:
|
||||
Authorization: 'Api-Token ${DYNATRACE_ACCESS_TOKEN}'
|
||||
|
||||
techdocs:
|
||||
builder: 'local' # Alternatives - 'external'
|
||||
generator:
|
||||
runIn: 'docker'
|
||||
# dockerImage: my-org/techdocs # use a custom docker image
|
||||
# pullImage: true # or false to disable automatic pulling of image (e.g. if custom docker login is required)
|
||||
publisher:
|
||||
type: 'local' # Alternatives - 'googleGcs' or 'awsS3' or 'azureBlobStorage' or 'openStackSwift'. Read documentation for using alternatives.
|
||||
|
||||
dynatrace:
|
||||
baseUrl: https://your.dynatrace.instance.com
|
||||
|
||||
# Score-cards sample configuration.
|
||||
scorecards:
|
||||
jsonDataUrl: https://raw.githubusercontent.com/Oriflame/backstage-plugins/main/plugins/score-card/sample-data/
|
||||
wikiLinkTemplate: https://link-to-wiki/{id}
|
||||
|
||||
sentry:
|
||||
organization: my-company
|
||||
|
||||
rollbar:
|
||||
organization: my-company
|
||||
# NOTE: The rollbar-backend & accountToken key may be deprecated in the future (replaced by a proxy config)
|
||||
accountToken: my-rollbar-account-token
|
||||
|
||||
lighthouse:
|
||||
baseUrl: http://localhost:3003
|
||||
|
||||
kubernetes:
|
||||
serviceLocatorMethod:
|
||||
type: 'multiTenant'
|
||||
clusterLocatorMethods:
|
||||
- type: 'config'
|
||||
clusters: []
|
||||
|
||||
kafka:
|
||||
clientId: backstage
|
||||
clusters:
|
||||
- name: cluster
|
||||
dashboardUrl: https://akhq.io/
|
||||
brokers:
|
||||
- localhost:9092
|
||||
|
||||
allure:
|
||||
baseUrl: http://localhost:5050/allure-docker-service
|
||||
|
||||
integrations:
|
||||
github:
|
||||
- host: github.com
|
||||
token: ${GITHUB_TOKEN}
|
||||
### Example for how to add your GitHub Enterprise instance using the API:
|
||||
# - host: ghe.example.net
|
||||
# apiBaseUrl: https://ghe.example.net/api/v3
|
||||
# token: ${GHE_TOKEN}
|
||||
### Example for how to add your GitHub Enterprise instance using raw HTTP fetches (token is optional):
|
||||
# - host: ghe.example.net
|
||||
# rawBaseUrl: https://ghe.example.net/raw
|
||||
# token: ${GHE_TOKEN}
|
||||
gitlab:
|
||||
- host: gitlab.com
|
||||
token: ${GITLAB_TOKEN}
|
||||
### Example for how to add a bitbucket cloud integration
|
||||
# bitbucketCloud:
|
||||
# - username: ${BITBUCKET_USERNAME}
|
||||
# appPassword: ${BITBUCKET_APP_PASSWORD}
|
||||
### Example for how to add your bitbucket server instance using the API:
|
||||
# - host: server.bitbucket.com
|
||||
# apiBaseUrl: server.bitbucket.com
|
||||
# username: ${BITBUCKET_SERVER_USERNAME}
|
||||
# appPassword: ${BITBUCKET_SERVER_APP_PASSWORD}
|
||||
azure:
|
||||
- host: dev.azure.com
|
||||
token: ${AZURE_TOKEN}
|
||||
# googleGcs:
|
||||
# clientEmail: 'example@example.com'
|
||||
# privateKey: ${GCS_PRIVATE_KEY}
|
||||
awsS3:
|
||||
- host: amazonaws.com
|
||||
accessKeyId: ${AWS_ACCESS_KEY_ID}
|
||||
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
|
||||
|
||||
costInsights:
|
||||
engineerCost: 200000
|
||||
engineerThreshold: 0.5
|
||||
products:
|
||||
computeEngine:
|
||||
name: Compute Engine
|
||||
icon: compute
|
||||
cloudDataflow:
|
||||
name: Cloud Dataflow
|
||||
icon: data
|
||||
cloudStorage:
|
||||
name: Cloud Storage
|
||||
icon: storage
|
||||
bigQuery:
|
||||
name: BigQuery
|
||||
icon: search
|
||||
events:
|
||||
name: Events
|
||||
icon: data
|
||||
metrics:
|
||||
DAU:
|
||||
name: Daily Active Users
|
||||
default: true
|
||||
MSC:
|
||||
name: Monthly Subscribers
|
||||
currencies:
|
||||
engineers:
|
||||
label: 'Engineers 🛠'
|
||||
unit: 'engineer'
|
||||
usd:
|
||||
label: 'US Dollars 💵'
|
||||
kind: 'USD'
|
||||
unit: 'dollar'
|
||||
prefix: '$'
|
||||
rate: 1
|
||||
carbonOffsetTons:
|
||||
label: 'Carbon Offset Tons ♻️⚖️s'
|
||||
kind: 'CARBON_OFFSET_TONS'
|
||||
unit: 'carbon offset ton'
|
||||
rate: 3.5
|
||||
beers:
|
||||
label: 'Beers 🍺'
|
||||
kind: 'BEERS'
|
||||
unit: 'beer'
|
||||
rate: 4.5
|
||||
pintsIceCream:
|
||||
label: 'Pints of Ice Cream 🍦'
|
||||
kind: 'PINTS_OF_ICE_CREAM'
|
||||
unit: 'ice cream pint'
|
||||
rate: 5.5
|
||||
pagerduty:
|
||||
eventsBaseUrl: 'https://events.pagerduty.com/v2'
|
||||
jenkins:
|
||||
instances:
|
||||
- name: default
|
||||
baseUrl: https://jenkins.example.com
|
||||
username: backstage-bot
|
||||
apiKey: 123456789abcdef0123456789abcedf012
|
||||
|
||||
azureDevOps:
|
||||
host: dev.azure.com
|
||||
token: my-token
|
||||
organization: my-company
|
||||
|
||||
apacheAirflow:
|
||||
baseUrl: https://your.airflow.instance.com
|
||||
|
||||
gocd:
|
||||
baseUrl: https://your.gocd.instance.com
|
||||
|
||||
permission:
|
||||
enabled: true
|
||||
|
||||
@@ -82,6 +82,7 @@ dependabot
|
||||
deps
|
||||
destructured
|
||||
destructuring
|
||||
Deutsche
|
||||
dev
|
||||
devops
|
||||
devs
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
StylesPath = .
|
||||
Vocab = Backstage
|
||||
|
||||
[*.md]
|
||||
BasedOnStyles = Vale
|
||||
Vale.Terms = NO
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
ref: 'refs/pull/${{ github.event.pull_request.number }}/merge'
|
||||
- name: fetch base
|
||||
run: git fetch --depth 1 origin ${{ github.base_ref }}
|
||||
- uses: backstage/actions/changeset-feedback@v0.5.12
|
||||
- uses: backstage/actions/changeset-feedback@v0.5.13
|
||||
name: Generate feedback
|
||||
with:
|
||||
diffRef: 'origin/master'
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v6
|
||||
- uses: actions/stale@v7
|
||||
id: stale
|
||||
with:
|
||||
stale-issue-message: >
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
@@ -181,25 +181,14 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ 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: lint changed packages
|
||||
if: ${{ steps.yarn-lock.outcome == 'success' }}
|
||||
run: yarn backstage-cli repo lint --since origin/master
|
||||
|
||||
- name: lint all packages
|
||||
if: ${{ steps.yarn-lock.outcome == 'failure' }}
|
||||
run: yarn backstage-cli repo lint
|
||||
|
||||
- name: test changed packages
|
||||
if: ${{ steps.yarn-lock.outcome == 'success' }}
|
||||
run: yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=1300M --since origin/master
|
||||
env:
|
||||
BACKSTAGE_TEST_DISABLE_DOCKER: 1
|
||||
@@ -207,17 +196,6 @@ jobs:
|
||||
BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres9.ports[5432] }}
|
||||
BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING: mysql://root:root@localhost:${{ job.services.mysql8.ports[3306] }}/ignored
|
||||
|
||||
- name: test all packages (and upload coverage)
|
||||
if: ${{ steps.yarn-lock.outcome == 'failure' }}
|
||||
run: |
|
||||
yarn backstage-cli repo test --maxWorkers=2 --workerIdleMemoryLimit=800M --coverage
|
||||
bash <(curl -s https://codecov.io/bash) -N $(git rev-parse FETCH_HEAD)
|
||||
env:
|
||||
BACKSTAGE_TEST_DISABLE_DOCKER: 1
|
||||
BACKSTAGE_TEST_DATABASE_POSTGRES13_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres13.ports[5432] }}
|
||||
BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING: postgresql://postgres:postgres@localhost:${{ job.services.postgres9.ports[5432] }}
|
||||
BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING: mysql://root:root@localhost:${{ job.services.mysql8.ports[3306] }}/ignored
|
||||
|
||||
- name: ensure clean working directory
|
||||
run: |
|
||||
if files=$(git ls-files --exclude-standard --others --modified) && [[ -z "$files" ]]; then
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
cron:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: backstage/actions/cron@v0.5.12
|
||||
- uses: backstage/actions/cron@v0.5.13
|
||||
with:
|
||||
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
|
||||
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -10,4 +10,4 @@ jobs:
|
||||
if: github.repository == 'backstage/backstage'
|
||||
steps:
|
||||
- name: Issue sync
|
||||
uses: backstage/actions/issue-sync@v0.5.12
|
||||
uses: backstage/actions/issue-sync@v0.5.13
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
const prNumber = artifact.name.slice('pr_number-'.length)
|
||||
core.setOutput('pr-number', prNumber);
|
||||
|
||||
- uses: backstage/actions/re-review@v0.5.12
|
||||
- uses: backstage/actions/re-review@v0.5.13
|
||||
with:
|
||||
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
|
||||
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request )
|
||||
steps:
|
||||
- name: PR sync
|
||||
uses: backstage/actions/pr-sync@v0.5.12
|
||||
uses: backstage/actions/pr-sync@v0.5.13
|
||||
with:
|
||||
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
|
||||
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ on:
|
||||
|
||||
jobs:
|
||||
build-backstage:
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=4096
|
||||
UFFIZZI_URL: https://uffizzi.com
|
||||
name: Build PR image
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }}
|
||||
@@ -16,8 +19,6 @@ jobs:
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: backstage
|
||||
|
||||
- name: setup-node
|
||||
uses: actions/setup-node@v3
|
||||
@@ -25,21 +26,22 @@ jobs:
|
||||
node-version: 16.x
|
||||
registry-url: https://registry.npmjs.org/
|
||||
|
||||
- name: backstage create-app | delete if already exists
|
||||
run: |
|
||||
rm -rf ./example-app
|
||||
npx @backstage/create-app
|
||||
env:
|
||||
BACKSTAGE_APP_NAME: example-app
|
||||
|
||||
- name: yarn build
|
||||
run: |
|
||||
yarn build:all
|
||||
working-directory: ./example-app
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: linux-v16
|
||||
|
||||
- name: Use Uffizzi's backstage app config
|
||||
run: |
|
||||
cp ./backstage/.github/uffizzi/uffizzi.production.app-config.yaml ./example-app/app-config.production.yaml;
|
||||
cp -f ./.github/uffizzi/uffizzi.production.app-config.yaml ./app-config.yaml
|
||||
|
||||
- name: typescript build
|
||||
run: |
|
||||
yarn tsc
|
||||
|
||||
- name: backstage build
|
||||
run: |
|
||||
yarn workspace example-backend build
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
@@ -50,16 +52,16 @@ jobs:
|
||||
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: registry.uffizzi.com/${{ env.UUID_TAG_APP }}
|
||||
tags: type=raw,value=60d
|
||||
|
||||
- name: Build Image
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: example-app
|
||||
file: example-app/packages/backend/Dockerfile
|
||||
context: .
|
||||
file: packages/backend/Dockerfile
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
push: true
|
||||
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
name: E2E Test Tugboat
|
||||
on: deployment_status
|
||||
|
||||
jobs:
|
||||
set-pending:
|
||||
if: github.event.deployment_status.state != 'success' && github.event.deployment_status.state != 'failed'
|
||||
name: Set pending waiting for Tugboat
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Set an initial commit status message to indicate that the tests are
|
||||
# running.
|
||||
- name: set pending status
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
|
||||
debug: true
|
||||
script: |
|
||||
return github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: context.sha,
|
||||
state: 'pending',
|
||||
context: 'Backstage Tugboat E2E Tests',
|
||||
description: 'Waiting for Tugboat to complete deployment',
|
||||
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
|
||||
});
|
||||
|
||||
run-tests:
|
||||
# Only run after a successful Tugboat deployment.
|
||||
if: github.event.deployment_status.state == 'success'
|
||||
name: Run tests against Tugboat deployment
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Set an initial commit status message to indicate that the tests are
|
||||
# running.
|
||||
- name: set pending status
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
|
||||
debug: true
|
||||
script: |
|
||||
return github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: context.sha,
|
||||
state: 'pending',
|
||||
context: 'Backstage Tugboat E2E Tests',
|
||||
description: 'Running against tugboat preview',
|
||||
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
|
||||
});
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
- name: yarn install
|
||||
run: yarn --cwd cypress install
|
||||
|
||||
# This is required because the environment_url param that Tugboat uses
|
||||
# to tell us where the preview is located isn't supported unless you
|
||||
# specify the custom Accept header when getting the deployment_status,
|
||||
# and GitHub actions doesn't do that by default. So instead we have to
|
||||
# load the status object manually and get the data we need.
|
||||
# https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/
|
||||
- name: get deployment status
|
||||
id: get-status-env
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
|
||||
result-encoding: string
|
||||
script: |
|
||||
const result = await github.rest.repos.getDeploymentStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
deployment_id: context.payload.deployment.id,
|
||||
status_id: context.payload.deployment_status.id,
|
||||
headers: {
|
||||
'Accept': 'application/vnd.github.ant-man-preview+json'
|
||||
},
|
||||
});
|
||||
console.log(result);
|
||||
return result.data.environment_url;
|
||||
|
||||
- name: cypress run
|
||||
uses: cypress-io/github-action@v2
|
||||
env:
|
||||
CYPRESS_baseUrl: ${{steps.get-status-env.outputs.result}}
|
||||
with:
|
||||
config-file: ./cypress.json
|
||||
working-directory: ./cypress
|
||||
browser: chrome
|
||||
install: false
|
||||
headless: true
|
||||
|
||||
- name: update artifact
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cypress-videos
|
||||
path: ./cypress/cypress/videos
|
||||
|
||||
- name: set status
|
||||
if: ${{ failure() }}
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
|
||||
script: |
|
||||
return github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: context.sha,
|
||||
state: "error",
|
||||
context: 'Backstage Tugboat E2E Tests',
|
||||
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
|
||||
});
|
||||
|
||||
- name: set status
|
||||
if: ${{ success() }}
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{secrets.GH_SERVICE_ACCOUNT_TOKEN}}
|
||||
script: |
|
||||
return github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: context.sha,
|
||||
state: "success",
|
||||
context: 'Backstage Tugboat E2E Tests',
|
||||
target_url: "https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}"
|
||||
});
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org/ # Needed for auth
|
||||
- name: yarn install
|
||||
uses: backstage/actions/yarn-install@v0.5.12
|
||||
uses: backstage/actions/yarn-install@v0.5.13
|
||||
with:
|
||||
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
|
||||
- name: storybook yarn install
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
services:
|
||||
backstage:
|
||||
image: tugboatqa/node:lts
|
||||
expose: 7007
|
||||
default: true
|
||||
commands:
|
||||
init:
|
||||
- mkdir -p /etc/service/node
|
||||
- echo "#!/bin/sh" > /etc/service/node/run
|
||||
- echo "yarn --cwd ${TUGBOAT_ROOT} start-backend --config ${TUGBOAT_ROOT}/app-config.yaml --config ${TUGBOAT_ROOT}/.tugboat/tugboat.app-config.production.yaml" >> /etc/service/node/run
|
||||
- chmod +x /etc/service/node/run
|
||||
build:
|
||||
- yarn install --immutable
|
||||
- yarn workspace example-app build
|
||||
start:
|
||||
# wget the endpoint. Will retry every 2 seconds. 30 retries = 1m for service to come up. Plenty.
|
||||
- wget -O /dev/null -o /dev/null --tries=30 --timeout=5 --retry-connrefused http://localhost:7007
|
||||
@@ -1,10 +0,0 @@
|
||||
app:
|
||||
title: Backstage Tugboat Preview
|
||||
baseUrl: ${TUGBOAT_DEFAULT_SERVICE_URL}
|
||||
|
||||
backend:
|
||||
baseUrl: ${TUGBOAT_DEFAULT_SERVICE_URL}
|
||||
cors:
|
||||
origin: ${TUGBOAT_DEFAULT_SERVICE_URL}
|
||||
methods: [GET, POST, PUT, DELETE]
|
||||
credentials: true
|
||||
@@ -1,4 +1,7 @@
|
||||
StylesPath = .github/styles
|
||||
StylesPath = .github/vale
|
||||
|
||||
Vocab = Backstage
|
||||
|
||||
[*.md]
|
||||
BasedOnStyles = Vale
|
||||
Vale.Terms = NO
|
||||
|
||||
@@ -224,3 +224,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/
|
||||
| [FanDuel](https://fanduel.com) | [Diego Herrera](https://github.com/diegoh), [Christy Campbell](https://github.com/FD-ChristopherCampbell) | We use backstage as our developer portal to provide visibility of our software, ownership, strategy, and the state of maturity across disciplines. |
|
||||
| [Operate First](https://www.operate-first.cloud/) | [Tom Coufal](https://github.com/tumido), [Sam Kopecky](https://github.com/samokopecky) | Backstage provides us with a public service catalog and serves as a gateway to our community cloud. Our instance is publicly available to everyone [here](https://service-catalog.operate-first.cloud/) ([source](https://github.com/operate-first/service-catalog)) |
|
||||
| [Tractable AI](https://tractable.ai/) | [Stephan Schielke](https://github.com/stephanschielke) | We are hitting a critical point in our scale (100+ engineers) and need to get a handle on discoverability and ownership. The Service Catalog, TechDocs and Search are essential to us to achieve that. |
|
||||
| [Garanti BBVA Teknoloji](https://www.linkedin.com/company/garanti-teknoloji/) | [Caglar Cataloglu](https://github.com/crozwise) | We are using Backstage focusing on improving experience of developers, minimizing friction from idea to production. We call our portal as "Hyperspace" and very excited for our community (2000+ engineers) that finally we have a platform to boost our productivity!
|
||||
| [Booking.com](https://www.linkedin.com/company/booking.com/) | [Mesut Yilmazyildirim](https://www.linkedin.com/in/myilmazyildirim) | We are adopting Backstage as the new reliability platform inside the company. We are migrating UIs of our internal developer tools to Backstage for a better user experience.
|
||||
| [Swissquote Bank](https://swissquote.com/company/jobs/open-positions) | [Bruno Rocha](https://www.linkedin.com/in/bruno-rocha1/) | Integrating Backstage as the visualization layer & tactical overview of our services and teams.
|
||||
| [XP Inc.](https://www.linkedin.com/company/xpinc/) | [Gabriel Santos](https://www.linkedin.com/in/gabriel-santos-6bb740a/) | Developer Portal Catalog (components, APIs, resources, users, groups) and organization relations.
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ Changesets **are** needed for new packages, as that is what triggers the package
|
||||
6. Push the commit with your changeset to the branch associated with your PR
|
||||
7. Accept our gratitude for making the release process easier on the maintainers
|
||||
|
||||
For more information, checkout [adding a changeset](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md) documentation in the changesets repository.
|
||||
For more information, check out [adding a changeset](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md) documentation in the changesets repository.
|
||||
|
||||
## Merging to Master
|
||||
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
Hey 👋 Welcome to the Cypress tests for Backstage. They're designed to be run against the `packages/app` folder in the main repo, and be some form of smoke tests to make sure that we don't break any core functionality.
|
||||
|
||||
They run part of the PR build, and are triggered from the `.github/workflows/tugboat.yml` file.
|
||||
|
||||
The main app gets built up part of a [Tugboat Build](https://tugboat.qa), which when complete, sends a `deployment event` to the PR triggering the aforementioned workflow.
|
||||
|
||||
### Running Locally
|
||||
|
||||
In order to make typescript happy, this `cypress` package is separate from all the Jest dependencies in the monorepo workspaces setup.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 263 KiB |
@@ -37,6 +37,8 @@ auth:
|
||||
audience: ${AUTH_AUTH0_AUDIENCE}
|
||||
connection: ${AUTH_AUTH0_CONNECTION}
|
||||
connectionScope: ${AUTH_AUTH0_CONNECTION_SCOPE}
|
||||
session:
|
||||
secret: ${AUTH_SESSION_SECRET}
|
||||
```
|
||||
|
||||
The Auth0 provider is a structure with three configuration keys:
|
||||
@@ -46,6 +48,8 @@ The Auth0 provider is a structure with three configuration keys:
|
||||
page
|
||||
- `domain`: The Application domain, found on the Auth0 Application page
|
||||
|
||||
Because Auth0 requires a session you need to give the session a secret key.
|
||||
|
||||
## Optional Configuration
|
||||
|
||||
- `audience`: The intended recipients of the token
|
||||
|
||||
@@ -18,7 +18,7 @@ Settings for local development:
|
||||
|
||||
- Name: Backstage (or your custom app name)
|
||||
- Redirect URI: `http://localhost:7007/api/auth/gitlab/handler/frame`
|
||||
- Scopes: `read_user`
|
||||
- Scopes: `read_api` and `read_user`
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
@@ -110,6 +110,9 @@ value of the configured key as the secret. It must also have the following paylo
|
||||
- `sub`: "backstage-server" (only this value supported currently)
|
||||
- `exp`: one hour from the time it was generated, in epoch seconds
|
||||
|
||||
> NOTE: The JWT must encode the `alg` header as a protected header, such as with
|
||||
> [setProtectedHeader](https://github.com/panva/jose/blob/main/docs/classes/jwt_sign.SignJWT.md#setprotectedheader).
|
||||
|
||||
## Granular Access Control
|
||||
|
||||
We plan to build out the service-to-service auth to be much more powerful in the
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: index
|
||||
title: Backend System Architecture
|
||||
sidebar_label: System Architecture
|
||||
# prettier-ignore
|
||||
description: The structure and architecture of the new Backend System and its component parts
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
This section introduces the high-level building blocks upon which this new
|
||||
system is built. These are all concepts that exist in our current system in one
|
||||
way or another, but they have all been lifted up to be first class concerns in
|
||||
the new system.
|
||||
|
||||
## Building Blocks
|
||||
|
||||
This section introduces the high-level building blocks upon which this new system is built. These are all concepts that exist in our current system in one way or another, but they have all been lifted up to be first class concerns in the new system.
|
||||
|
||||
<!-- TODO: GRAPH GO HERE -->
|
||||
|
||||
### Backend
|
||||
|
||||
This is the backend instance itself, which you can think of as the unit of deployment. It does not have any functionality in and of itself, but is simply responsible for wiring things together.
|
||||
|
||||
It is up to you to decide how many different backends you want to deploy. You can have all features in a single one, or split things out into multiple smaller deployments. All depending on your need to scale and isolate individual features.
|
||||
|
||||
### Plugins
|
||||
|
||||
Plugins provide the actual features, just like in our existing system. They operate completely independently of each other. If plugins want to communicate with each other, they must do so over the wire. There can be no direct communication between plugins through code. Because of this constraint, each plugin can be considered to be its own microservice.
|
||||
|
||||
### Services
|
||||
|
||||
Services provide utilities to help make it simpler to implement plugins, so that each plugin doesn't need to implement everything from scratch. There are both many built-in services, like the ones for logging, database access, and reading configuration, but you can also import third-party services, or create your own.
|
||||
|
||||
Services are also a customization point for individual backend installations. You can both override services with your own implementations, as well as make smaller customizations to existing services.
|
||||
|
||||
### Extension Points
|
||||
|
||||
Many plugins have ways in which you can extend them, for example entity providers for the Catalog, or custom actions for the Scaffolder. These extension patterns are now encoded into Extension Points.
|
||||
|
||||
Extension Points look a little bit like services, since you depended on them just like you would a service. A key difference is that extension points are registered and provided by plugins themselves, based on what customizations each individual plugin wants to expose.
|
||||
|
||||
Extension Points are also exported separately from the plugin instance itself, and a single plugin can also expose multiple different extension points at once. This makes it easier to evolve and deprecated individual Extension Points over time, rather than dealing with a single large API surface.
|
||||
|
||||
### Modules
|
||||
|
||||
Modules use the plugin Extension Points to add new features for plugins. They might for example add an individual Catalog Entity Provider, or one or more Scaffolder Actions. Modules are basically plugins for plugins.
|
||||
|
||||
Each module may only extend a single plugin, and the module must be deployed together with that plugin in the same backend instance. Modules may however only communicate with their plugin through its registered extension points.
|
||||
|
||||
Just like plugins, modules also have access to services and can depend on their own service implementations. They will however share services with the plugin that they extend, there are no module-specific service implementations.
|
||||
|
||||
## Package structure
|
||||
|
||||
A detailed explanation of the package architecture can be found in the
|
||||
[Backstage Architecture
|
||||
Overview](../../overview/architecture-overview.md#package-architecture). The
|
||||
most important packages to consider for this system are `backend`,
|
||||
`plugin-<pluginId>-backend`, `plugin-<pluginId>-node`, and
|
||||
`plugin-<pluginId>-backend-module-<moduleId>`.
|
||||
|
||||
- `plugin-<pluginId>-backend` houses the implementation of the backend plugins
|
||||
themselves.
|
||||
- `plugin-<pluginId>-node` houses the extension points and any other utilities
|
||||
that modules or other plugins might need.
|
||||
- `plugin-<pluginId>-backend-module-<moduleId>` houses the modules that extend
|
||||
the plugins via the extension points.
|
||||
- `backend` is the backend itself that wires everything together to something
|
||||
that you can deploy.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
id: backends
|
||||
title: Backend Instances
|
||||
sidebar_label: Backend
|
||||
# prettier-ignore
|
||||
description: Service APIs for backend plugins
|
||||
---
|
||||
|
||||
The new Backstage backend system is being built to help make it simpler to install backend plugins and to keep projects up to date. It also changes the foundation to one that makes it a lot easier to evolve plugins and the system itself with minimal disruption or cause for breaking changes. You can read more about the reasoning in the [original RFC](https://github.com/backstage/backstage/issues/11611).
|
||||
|
||||
One of the goals of the new system was to reduce the code needed for setting up a Backstage backend and installing plugins. This is an example of how you create, add features, and start up your backend in the new system:
|
||||
|
||||
```ts
|
||||
import { createBackend } from '@backstage/backend-defaults';
|
||||
import { catalogPlugin } from '@backstage/plugin-catalog-backend';
|
||||
|
||||
// Create your backend instance
|
||||
const backend = createBackend();
|
||||
|
||||
// Install all desired features
|
||||
backend.add(catalogPlugin());
|
||||
|
||||
// Start up the backend
|
||||
await backend.start();
|
||||
```
|
||||
|
||||
One notable change that helped achieve this much slimmer backend setup is the introduction of a system for dependency injection, which is very similar to the one in the Backstage frontend.
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
id: services
|
||||
title: Backend Service APIs
|
||||
sidebar_label: Service APIs
|
||||
# prettier-ignore
|
||||
description: Service APIs for backend plugins
|
||||
---
|
||||
|
||||
## Backend Services
|
||||
|
||||
The default backend provides several [core services](https://github.com/backstage/backstage/blob/master/packages/backend-plugin-api/src/services/definitions/coreServices.ts) out of the box which includes access to configuration, logging, databases and more.
|
||||
Service dependencies are declared using their `ServiceRef`s in the `deps` section of the plugin or module, and the implementations are then forwarded to the `init` method of the plugin or module.
|
||||
|
||||
### Service References
|
||||
|
||||
A `ServiceRef` is a named reference to an interface which are later used to resolve the concrete service implementation. Conceptually this is very similar to `ApiRef`s in the frontend.
|
||||
Services is what provides common utilities that previously resided in the `PluginEnvironment` such as Config, Logging and Database.
|
||||
|
||||
On startup the backend will make sure that the services are initialized before being passed to the plugin/module that depend on them.
|
||||
ServiceRefs contain a scope which is used to determine if the serviceFactory creating the service will create a new instance scoped per plugin/module or if it will be shared. `plugin` scoped services will be created once per plugin/module and `root` scoped services will be created once per backend instance.
|
||||
|
||||
#### Defining a Service
|
||||
|
||||
```ts
|
||||
import {
|
||||
createServiceFactory,
|
||||
coreServices,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { ExampleImpl } from './ExampleImpl';
|
||||
|
||||
export interface ExampleApi {
|
||||
doSomething(): Promise<void>;
|
||||
}
|
||||
|
||||
export const exampleServiceRef = createServiceRef<ExampleApi>({
|
||||
id: 'example',
|
||||
scope: 'plugin', // can be 'root' or 'plugin'
|
||||
|
||||
// The defaultFactory is optional to implement but it will be used if no
|
||||
// other factory is provided to the backend. This allows for the backend
|
||||
// to provide a default implementation of the service without having to wire
|
||||
// it beforehand.
|
||||
defaultFactory: async service =>
|
||||
createServiceFactory({
|
||||
service,
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
plugin: coreServices.pluginMetadata,
|
||||
},
|
||||
// This root context method is only available for plugin scoped services.
|
||||
// It's only called once per backend instance.
|
||||
// Logger is available at the root context level as it's also a root
|
||||
// scoped service.
|
||||
createRootContext({ logger }) {
|
||||
return new ExampleImplFactory({ logger });
|
||||
},
|
||||
// Plugin is available as it's a plugin scoped service and will be
|
||||
// created once per plugin. The logger can be had here too if needed.
|
||||
// Both this anc the root context can also be async.
|
||||
factory({ logger, plugin }, rootContext) {
|
||||
// This block will be executed once for every plugin that depends on
|
||||
// this service
|
||||
logger.info('Initializing example service plugin instance');
|
||||
return rootContext.forPlugin(plugin.getId());
|
||||
},
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
### Overriding Services
|
||||
|
||||
In this example we replace the default root logger service implementation with a custom one that streams logs to GCP. The `rootLoggerServiceRef` has a `'root'` scope, meaning there are no plugin-specific instances of this service.
|
||||
|
||||
```ts
|
||||
import {
|
||||
createServiceFactory,
|
||||
rootLoggerServiceRef,
|
||||
LoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
// This custom implementation would typically live separately from
|
||||
// the backend setup code, either nearby such as in
|
||||
// packages/backend/src/services/logger/GoogleCloudLogger.ts
|
||||
// Or you can let it live in its own library package.
|
||||
class GoogleCloudLogger implements LoggerService {
|
||||
static factory = createServiceFactory({
|
||||
service: rootLoggerServiceRef,
|
||||
deps: {},
|
||||
factory() {
|
||||
return new GoogleCloudLogger();
|
||||
},
|
||||
});
|
||||
// custom implementation here ...
|
||||
}
|
||||
|
||||
// packages/backend/src/index.ts
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
// supplies additional or replacement services to the backend
|
||||
GoogleCloudLogger.factory(),
|
||||
],
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: plugins
|
||||
title: Backend Plugins
|
||||
sidebar_label: Plugins
|
||||
# prettier-ignore
|
||||
description: Backend plugins
|
||||
---
|
||||
|
||||
## Creating Plugins
|
||||
|
||||
Plugins are created using the `createBackendPlugin` function. All plugins must have an ID and a register method. Plugins may also accept an options object, which can be either optional or required. The options are passed to the second parameter of the register method, and the options type is inferred and forwarded to the returned plugin factory function.
|
||||
|
||||
```ts
|
||||
import {
|
||||
configServiceRef,
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
// export type ExamplePluginOptions = { exampleOption: boolean };
|
||||
export const examplePlugin = createBackendPlugin({
|
||||
// unique id for the plugin
|
||||
id: 'example',
|
||||
// It's possible to provide options to the plugin
|
||||
// register(env, options: ExamplePluginOptions) {
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
// logger is provided by the backend based on the dependency on loggerServiceRef above.
|
||||
async init({ logger }) {
|
||||
logger.info('Hello from example plugin');
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The plugin can then be installed in the backend using the returned plugin factory function:
|
||||
|
||||
```ts
|
||||
backend.add(examplePlugin());
|
||||
```
|
||||
|
||||
If we wanted our plugin to accept options as well, we'd accept the options as the second parameter of the register method:
|
||||
|
||||
```ts
|
||||
export const examplePlugin = createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env, options?: { silent?: boolean }) {
|
||||
env.registerInit({
|
||||
deps: { logger: coreServices.logger },
|
||||
async init({ logger }) {
|
||||
if (!options?.silent) {
|
||||
logger.info('Hello from example plugin');
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Passing the option to the plugin during installation looks like this:
|
||||
|
||||
```ts
|
||||
backend.add(examplePlugin({ silent: true }));
|
||||
```
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
id: extension-points
|
||||
title: Backend Plugin Extension Points
|
||||
sidebar_label: Extension Points
|
||||
# prettier-ignore
|
||||
description: Extension points of backend plugins
|
||||
---
|
||||
|
||||
### Extension Points
|
||||
|
||||
Modules depend on extension points just as a regular dependency by specifying it in the `deps` section.
|
||||
|
||||
#### Defining an Extension Point
|
||||
|
||||
```ts
|
||||
import { createExtensionPoint } from '@backstage/backend-plugin-api';
|
||||
|
||||
export interface ScaffolderActionsExtensionPoint {
|
||||
addAction(action: ScaffolderAction): void;
|
||||
}
|
||||
|
||||
export const scaffolderActionsExtensionPoint =
|
||||
createExtensionPoint<ScaffolderActionsExtensionPoint>({
|
||||
id: 'scaffolder.actions',
|
||||
});
|
||||
```
|
||||
|
||||
#### Registering an Extension Point
|
||||
|
||||
Extension points are registered by a plugin and extended by modules.
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
id: modules
|
||||
title: Plugin Modules
|
||||
sidebar_label: Modules
|
||||
# prettier-ignore
|
||||
description: Modules for backend plugins
|
||||
---
|
||||
|
||||
## Creating Modules
|
||||
|
||||
Some facts about modules
|
||||
|
||||
- A Module is able to extend a plugin with additional functionality using the `ExtensionPoint`s registered by the plugin.
|
||||
- A module can only extend one plugin but can interact with multiple `ExtensionPoint`s registered by that plugin.
|
||||
- A module is always initialized before the plugin it extends.
|
||||
|
||||
A module depends on the `ExtensionPoint`s exported by the target plugin's library package, for example `@backstage/plugin-catalog-node`, and does not directly declare a dependency on the plugin package itself.
|
||||
|
||||
Here's an example on how to create a module that adds a new processor using the `catalogProcessingExtensionPoint`:
|
||||
|
||||
```ts
|
||||
import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
|
||||
import { MyCustomProcessor } from './processor';
|
||||
|
||||
export const exampleCustomProcessorCatalogModule = createBackendModule({
|
||||
moduleId: 'exampleCustomProcessor',
|
||||
pluginId: 'catalog',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
catalog: catalogProcessingExtensionPoint,
|
||||
},
|
||||
async init({ catalog }) {
|
||||
catalog.addProcessor(new MyCustomProcessor());
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: index
|
||||
title: Building Backends
|
||||
sidebar_label: Overview
|
||||
# prettier-ignore
|
||||
description: Building backends using the new backend system
|
||||
---
|
||||
|
||||
> NOTE: If you have an existing backend that is not yet using the new backend
|
||||
> system, see [migrating](./08-migrating.md).
|
||||
|
||||
# Overview
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
id: migrating
|
||||
title: Migrating your Backend to the New Backend System
|
||||
sidebar_label: Migration Guide
|
||||
# prettier-ignore
|
||||
description: How to migrate existing backends to the new backend system
|
||||
---
|
||||
|
||||
# Overview
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: index
|
||||
title: Building Backend Plugins and Modules
|
||||
sidebar_label: Overview
|
||||
# prettier-ignore
|
||||
description: Building backend plugins and modules using the new backend system
|
||||
---
|
||||
|
||||
> NOTE: If you have an existing backend and/or backend plugins that are not yet
|
||||
> using the new backend system, see [migrating](./08-migrating.md).
|
||||
|
||||
# Overview
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
id: testing
|
||||
title: Testing Backend Plugins and Modules
|
||||
sidebar_label: Testing
|
||||
# prettier-ignore
|
||||
description: Learn how to test your backend plugins and modules
|
||||
---
|
||||
|
||||
Utilities for testing backend plugins and modules are available in `@backstage/backend-test-utils`.
|
||||
`startTestBackend` returns a server which can be used together with `supertest` to test the plugins.
|
||||
|
||||
```ts
|
||||
import { startTestBackend } from '@backstage/backend-test-utils';
|
||||
import request from 'supertest';
|
||||
|
||||
describe('My plugin tests', () => {
|
||||
it('should return 200', async () => {
|
||||
const { server } = await startTestBackend({
|
||||
features: [myPlugin()],
|
||||
});
|
||||
|
||||
const response = await request(server).get('/api/example/hello');
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
id: migrating
|
||||
title: Migrating your Backend Plugin to the New Backend System
|
||||
sidebar_label: Migration Guide
|
||||
# prettier-ignore
|
||||
description: How to migrate existing backend plugins to the new backend system
|
||||
---
|
||||
|
||||
# Overview
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
id: index
|
||||
title: Core Backend Service APIs
|
||||
sidebar_label: Core Services
|
||||
# prettier-ignore
|
||||
description: Core backend service APIs
|
||||
---
|
||||
|
||||
The default backend provides several [core services](https://github.com/backstage/backstage/blob/master/packages/backend-plugin-api/src/services/definitions/coreServices.ts) out of the box which includes access to configuration, logging, URL Readers, databases and more.
|
||||
|
||||
All core services are available through the `coreServices` namespace in the `@backstage/backend-plugin-api` package.
|
||||
|
||||
```ts
|
||||
import { coreServices } from '@backstage/backend-plugin-api';
|
||||
```
|
||||
|
||||
## HTTP Router Service
|
||||
|
||||
One of the most common services is the HTTP router service which is used to expose HTTP endpoints for other plugins to consume.
|
||||
|
||||
The following example shows how to register a HTTP router for the `example` plugin.
|
||||
This single route will be available at the `/api/example/hello` path.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { Router } from 'express';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: { http: coreServices.httpRouter },
|
||||
async init({ http }) {
|
||||
const router = Router();
|
||||
router.get('/hello', (_req, res) => {
|
||||
res.status(200).json({ hello: 'world' });
|
||||
});
|
||||
// Registers the router at the /api/example path
|
||||
http.use(router);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Logging and Configuration Service
|
||||
|
||||
It is common for plugins to need access to configuration values and log messages.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { Router } from 'express';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
log: coreServices.logger,
|
||||
config: coreServices.config,
|
||||
},
|
||||
async init({ config, log }) {
|
||||
log.warn('Brace yourself for more log output');
|
||||
const url = config.getString('backend.baseUrl');
|
||||
log.info(`Backend URL is running on ${url}`);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
id: index
|
||||
title: The Backend System
|
||||
sidebar_label: Overview
|
||||
# prettier-ignore
|
||||
description: The backend system
|
||||
---
|
||||
|
||||
> **DISCLAIMER: The new backend system is under active development and is not considered stable**
|
||||
|
||||
## Status
|
||||
|
||||
The new backend system is under active development, and only a small number of plugins have been migrated so far. It is possible to try it out, but it is not recommended to use this new system in production yet.
|
||||
|
||||
You can find an example backend setup in [the backend-next package](https://github.com/backstage/backstage/tree/master/packages/backend-next).
|
||||
@@ -17,7 +17,7 @@ into multiple different services, each running a different set of plugins. This
|
||||
is a more advanced approach and requires you to be able to route requests to
|
||||
the appropriate backends based on the plugin ID. Both for ingress, but also
|
||||
internal traffic between Backstage backends, which is done by creating a custom
|
||||
implementation of the [PluginEndpointDiscover](../reference/backend-common.pluginendpointdiscovery.md) interface.
|
||||
implementation of the [DiscoveryService](../reference/backend-plugin-api.discoveryservice.md) interface.
|
||||
|
||||
Lastly, you can also replicate the Backstage deployments across multiple regions.
|
||||
This is not a pattern that there is built-in support for and typically only makes
|
||||
|
||||
@@ -23,7 +23,8 @@ See the more detailed [architecture](./architecture.md) and [tech stack](./archi
|
||||
|
||||
## Project roadmap
|
||||
|
||||
No current plans.
|
||||
No current plans. Check [Backstage issues labeled `search`](https://github.com/backstage/backstage/issues?q=is%3Aopen+is%3Aissue+label%3Asearch)
|
||||
for community-led ideas and initiatives.
|
||||
|
||||
## Supported
|
||||
|
||||
@@ -42,11 +43,11 @@ The following sections show the plugins and search engines currently supported b
|
||||
See [Backstage Search Architecture](architecture.md) to get an overview of how
|
||||
the search engines are used.
|
||||
|
||||
| Search Engines | Support Status |
|
||||
| -------------------------------------------------- | -------------- |
|
||||
| [ElasticSearch](./search-engines.md#elasticsearch) | ✅ |
|
||||
| [Lunr](./search-engines.md#lunr) | ✅ |
|
||||
| [Postgres](./search-engines.md#postgres) | Community ✅ |
|
||||
| Search Engines | Support Status |
|
||||
| ------------------------------------------------------------- | -------------- |
|
||||
| [Elasticsearch/OpenSearch](./search-engines.md#elasticsearch) | ✅ |
|
||||
| [Lunr](./search-engines.md#lunr) | ✅ |
|
||||
| [Postgres](./search-engines.md#postgres) | Community ✅ |
|
||||
|
||||
[Reach out to us](#get-involved) if you want to chat about support for more plugin integrations and
|
||||
search engines.
|
||||
@@ -56,72 +57,3 @@ search engines.
|
||||
For any questions, feedback, or to help move search forward, reach out to us in
|
||||
the **#search** channel of our
|
||||
[Discord chatroom](https://github.com/backstage/backstage#community).
|
||||
|
||||
## Use Cases supported
|
||||
|
||||
#### **Backstage Search Pre-Alpha**
|
||||
|
||||
Search Frontend letting you search through the entities of the software catalog.
|
||||
|
||||
The pre-alpha is intended to solve for the following user stories, but will get
|
||||
there by means of a front-end only, non-extensible MVP.
|
||||
|
||||
- As a software engineer I should be able to navigate to a search page and
|
||||
search for entities registered in the Software Catalog.
|
||||
- As a software engineer I should be able to use the search input field in the
|
||||
sidebar to search for entities registered in the Software Catalog.
|
||||
- As a software engineer I should be able to see the number of results my search
|
||||
returned.
|
||||
- As a software engineer I should be able to filter on metadata (kind,
|
||||
lifecycle) when I’ve performed a search.
|
||||
- As a software engineer I should be able to hide the filters if I don’t need to
|
||||
use them.
|
||||
|
||||
#### **Backstage Search Alpha**
|
||||
|
||||
Basic “out-of-the-box” in-memory indexing process of entities, and their metadata, registered to the Software Catalog.
|
||||
|
||||
We will consider Backstage Search to be in alpha when the above use-cases are
|
||||
met, but built on top of a flexible, extensible platform.
|
||||
|
||||
- As an integrator, I should be able to provide all of the pre-alpha experiences
|
||||
to my users if I choose, but also be able to customize the experience using a
|
||||
composable set of components.
|
||||
- As a plugin developer, I should have a standard way to expose my plugin's data
|
||||
to Backstage Search.
|
||||
- As an integrator, I should still be able to expose everything in the Software
|
||||
Catalog in search, but it should be possible to customize what is searchable.
|
||||
- As an integrator, although I should be able to customize all of the above, it
|
||||
should be possible to have the pre-alpha user experiences covered without
|
||||
having to set up and configure a search engine.
|
||||
|
||||
#### **Backstage Search Beta**
|
||||
|
||||
At least one production-ready search engine that supports the same use-cases as in the alpha.
|
||||
|
||||
We will consider Backstage Search to be in a beta phase when the above use-cases
|
||||
are met, and can be deployed using a production-ready search engine.
|
||||
|
||||
- As an integrator, I should be able to power my Backstage Search experience
|
||||
(including querying and indexing) using a production-ready search engine like
|
||||
ElasticSearch.
|
||||
- As an integrator, I should be able to configure the connection to my search
|
||||
engine in **app_config.yaml**.
|
||||
- As an integrator, I should be able to tune the queries sent to my chosen
|
||||
search engine according to my organization's needs, but a sensible default
|
||||
query should be in place so that I am not required to do so.
|
||||
|
||||
#### **Backstage Search 1.0**
|
||||
|
||||
A stable Search API for plugin developers to add search to their plugins, and app integrators to expose that to their users.
|
||||
|
||||
We will consider Backstage Search to be 1.0 when the above
|
||||
use-cases are met, and an ecosystem of search-enabled plugins are available and
|
||||
stable.
|
||||
|
||||
- As a plugin developer, there should be at least one example of a Backstage
|
||||
plugin that integrates with search that I can use as inspiration for my own
|
||||
plugin's search capabilities (for example, the TechDocs plugin).
|
||||
- As an app integrator, there should be plenty of examples and documentation on
|
||||
how to customize and extend search in my Backstage instance to meet my
|
||||
organization's needs.
|
||||
|
||||
@@ -23,7 +23,7 @@ To get started, you should get familiar with these core concepts:
|
||||
Backstage Search isn't a search engine itself, rather, it provides an interface
|
||||
between your Backstage instance and a Search Engine of your choice. More
|
||||
concretely, a `SearchEngine` is an interface whose concrete implementations
|
||||
facilitate communication with different search engines (like ElasticSearch,
|
||||
facilitate communication with different search engines (like Elasticsearch,
|
||||
Lunr, Solr, etc). This abstraction exists in order to support your
|
||||
organization's needs.
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ an example:
|
||||
Backstage Search isn't a search engine itself, rather, it provides an interface
|
||||
between your Backstage instance and a
|
||||
[Search Engine](./concepts.md#search-engines) of your choice. Currently, we only
|
||||
support two engines, an in-memory search Engine called Lunr and ElasticSearch.
|
||||
support two engines, an in-memory search Engine called Lunr and Elasticsearch.
|
||||
See [Search Engines](./search-engines.md) documentation for more information how
|
||||
to configure these in your Backstage instance.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Choosing and configuring your search engine for Backstage
|
||||
---
|
||||
|
||||
Backstage supports 3 search engines by default, an in-memory engine called Lunr,
|
||||
ElasticSearch and Postgres. You can configure your own search engines by
|
||||
Elasticsearch and Postgres. You can configure your own search engines by
|
||||
implementing the provided interface as mentioned in the
|
||||
[search backend documentation.](./getting-started.md#Backend)
|
||||
|
||||
@@ -34,11 +34,16 @@ const searchEngine = new LunrSearchEngine({ logger: env.logger });
|
||||
const indexBuilder = new IndexBuilder({ logger: env.logger, searchEngine });
|
||||
```
|
||||
|
||||
> Note: Lunr is appropriate as a zero-config search engine when developing
|
||||
> other parts of Backstage locally, however its use is highly discouraged when
|
||||
> running Backstage in production. When deploying Backstage, use one of the
|
||||
> other search engines instead.
|
||||
|
||||
## Postgres
|
||||
|
||||
The Postgres based search engine only requires that postgres being configured as
|
||||
the database engine for Backstage. Therefore it targets setups that want to
|
||||
avoid maintaining another external service like elastic search. The search
|
||||
avoid maintaining another external service like Elasticsearch. The search
|
||||
provides decent results and performs well with ten thousands of indexed
|
||||
documents. The connection to postgres is established via the database manager
|
||||
also used by other plugins.
|
||||
@@ -91,13 +96,13 @@ search:
|
||||
|
||||
The Postgres documentation on [Highlighting Results](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-HEADLINE) has more details.
|
||||
|
||||
## ElasticSearch
|
||||
## Elasticsearch
|
||||
|
||||
Backstage supports ElasticSearch search engine connections, indexing and
|
||||
querying out of the box. Available configuration options enable usage of either
|
||||
AWS or Elastic.co hosted solutions, or a custom self-hosted solution.
|
||||
Backstage supports Elasticsearch (and OpenSearch) search engine connections,
|
||||
indexing and querying out of the box. Available configuration options enable
|
||||
usage of either AWS or Elastic.co hosted solutions, or a custom self-hosted solution.
|
||||
|
||||
Similarly to Lunr above, ElasticSearch can be set up like this:
|
||||
Similarly to Lunr above, Elasticsearch can be set up like this:
|
||||
|
||||
```typescript
|
||||
// app/backend/src/plugins/search.ts
|
||||
@@ -111,40 +116,48 @@ const indexBuilder = new IndexBuilder({ logger: env.logger, searchEngine });
|
||||
For the engine to be available, your backend package needs a dependency on
|
||||
package `@backstage/plugin-search-backend-module-elasticsearch`.
|
||||
|
||||
ElasticSearch needs some additional configuration before it is ready to use
|
||||
Elasticsearch needs some additional configuration before it is ready to use
|
||||
within your instance. The configuration options are documented in the
|
||||
[configuration schema definition file.](https://github.com/backstage/backstage/blob/master/plugins/search-backend-module-elasticsearch/config.d.ts)
|
||||
|
||||
The underlying functionality uses either the official ElasticSearch client
|
||||
version 7.x (meaning that ElasticSearch version 7 is the only one confirmed to
|
||||
The underlying functionality uses either the official Elasticsearch client
|
||||
version 7.x (meaning that Elasticsearch version 7 is the only one confirmed to
|
||||
be supported), or the OpenSearch client, when the `aws` or `opensearch `provider
|
||||
is configured.
|
||||
|
||||
Should you need to create your own bespoke search experiences that require more
|
||||
than just a query translator (such as faceted search or Relay pagination), you
|
||||
can access the configuration of the search engine in order to create new elastic
|
||||
search clients. The version of the client need not be the same as one used
|
||||
internally by the elastic search engine plugin. For example:
|
||||
can access the configuration of the search engine in order to create new
|
||||
Elasticsearch clients. The version of the client need not be the same as one
|
||||
used internally by the Elasticsearch engine plugin. For example:
|
||||
|
||||
```typescript
|
||||
import { isOpenSearchCompatible } from '@backstage/plugin-search-backend-module-elasticsearch';
|
||||
import { Client as ElasticClient } from '@elastic/elastic-search';
|
||||
import { Client as ElasticClient } from '@elastic/elasticsearch';
|
||||
import { Client as OpenSearchClient } from '@opensearch-project/opensearch';
|
||||
|
||||
const client = searchEngine.newClient(options => {
|
||||
// In reality, you would only import / instantiate one of the following, but
|
||||
// for illustrative purposes, here are both:
|
||||
if (isOpenSearchCompatible(options)) {
|
||||
return new OpenSearchClient(options);
|
||||
} else {
|
||||
// Return an Elasticsearch client
|
||||
const esClient = searchEngine.newClient<ElasticClient>(options => {
|
||||
if (!isOpenSearchCompatible(options)) {
|
||||
return new ElasticClient(options);
|
||||
}
|
||||
|
||||
throw new Error('Incompatible options');
|
||||
});
|
||||
|
||||
// Return an OpenSearch client
|
||||
const osClient = searchEngine.newClient<OpenSearchClient>(options => {
|
||||
if (isOpenSearchCompatible(options)) {
|
||||
return new OpenSearchClient(options);
|
||||
}
|
||||
|
||||
throw new Error('Incompatible options');
|
||||
});
|
||||
```
|
||||
|
||||
#### Set custom index template
|
||||
|
||||
The elasticsearch engine gives you the ability to set a custom index template if needed.
|
||||
The Elasticsearch engine gives you the ability to set a custom index template if needed.
|
||||
|
||||
> Index templates define settings, mappings, and aliases that can be applied automatically to new indices.
|
||||
|
||||
@@ -171,8 +184,8 @@ searchEngine.setIndexTemplate({
|
||||
|
||||
### AWS
|
||||
|
||||
Using AWS hosted ElasticSearch the only configuration option needed is the URL
|
||||
to the ElasticSearch service. The implementation assumes that environment
|
||||
Using AWS hosted Elasticsearch the only configuration option needed is the URL
|
||||
to the Elasticsearch service. The implementation assumes that environment
|
||||
variables for AWS access key id and secret access key are defined in accordance
|
||||
to the
|
||||
[default AWS credential chain.](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html).
|
||||
@@ -186,8 +199,8 @@ search:
|
||||
|
||||
### Elastic.co
|
||||
|
||||
Elastic Cloud hosted ElasticSearch uses a Cloud ID to determine the instance of
|
||||
hosted ElasticSearch to connect to. Additionally, username and password needs to
|
||||
Elastic Cloud hosted Elasticsearch uses a Cloud ID to determine the instance of
|
||||
hosted Elasticsearch to connect to. Additionally, username and password needs to
|
||||
be provided either directly or using environment variables like defined in
|
||||
[Backstage documentation.](https://backstage.io/docs/conf/writing#includes-and-dynamic-data)
|
||||
|
||||
@@ -217,8 +230,8 @@ search:
|
||||
|
||||
### Others
|
||||
|
||||
Other ElasticSearch instances can be connected to by using standard
|
||||
ElasticSearch authentication methods and exposed URL, provided that the cluster
|
||||
Other Elasticsearch instances can be connected to by using standard
|
||||
Elasticsearch authentication methods and exposed URL, provided that the cluster
|
||||
supports that. The configuration options needed are the URL to the node and
|
||||
authentication information. Authentication can be handled by either providing
|
||||
username/password or an API key. For more information how to create an API key,
|
||||
@@ -248,13 +261,13 @@ search:
|
||||
apiKey: base64EncodedKey
|
||||
```
|
||||
|
||||
### Elastic search batch size
|
||||
### Elasticsearch batch size
|
||||
|
||||
Default batch size of the elastic search engine is set to 1000. If you are using a lower spec computing resources (like AWS small instance),
|
||||
Default batch size of the Elasticsearch engine is set to 1000. If you are using a lower spec computing resources (like AWS small instance),
|
||||
you may get an error caused by limited `thread_pool` configuration. ( `429 Too Many Requests /_bulk` )
|
||||
|
||||
In this case you need to decrease the batch size to index the resources to prevent this kind of error. You can easily decrease
|
||||
or increase the batch size in your `app-config.yaml` using the `batchSize` option provided for elasticsearch configuration.
|
||||
or increase the batch size in your `app-config.yaml` using the `batchSize` option provided for Elasticsearch configuration.
|
||||
|
||||
#### Configuration example
|
||||
|
||||
|
||||
@@ -154,6 +154,29 @@ Some more real world usable examples:
|
||||
|
||||
`/entities?fields=kind,metadata.namespace,metadata.name`
|
||||
|
||||
### Ordering
|
||||
|
||||
By default the entities are returned in an undefined, but stable order. You can
|
||||
pass in one or more `order` query parameters to affect that ordering.
|
||||
|
||||
Each parameter starts either with `asc:` for ascending lexicographical order or
|
||||
`desc:` for descending (reverse) lexicographical order, followed by a
|
||||
dot-separated path into an entity's keys. The ordering is case insensitive. If
|
||||
more than one order directive is given, later directives have lower precedence
|
||||
(they are applied only when directives of higher precedence have equal values).
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
/entities?order=asc:kind&order=desc:metadata.name
|
||||
```
|
||||
|
||||
This will order the output first by kind ascending, and then within each kind
|
||||
(if there's more than one of a given kind) by their name descending. When given
|
||||
a field that does NOT exist on all entities in the result set, those entities
|
||||
that do not have the field will always be sorted last in that particular order
|
||||
step, no matter what the desired order was.
|
||||
|
||||
#### Pagination
|
||||
|
||||
You may pass the `offset` and `limit` query parameters to do classical
|
||||
@@ -223,6 +246,37 @@ value. These are special in that they form the entity's unique
|
||||
The return type is JSON, as a single [`Entity`](descriptor-format.md), or a 404
|
||||
error if there was no entity with that reference triplet.
|
||||
|
||||
### `POST /entities/by-refs`
|
||||
|
||||
Gets a batch of entities by their entity refs. This is useful in contexts where
|
||||
you want to fetch a large number of specific entities efficiently, for example
|
||||
in GraphQL resolvers.
|
||||
|
||||
The request body is JSON, on the form
|
||||
|
||||
```json
|
||||
{
|
||||
"entityRefs": ["component:default/foo", "api:default/bar"],
|
||||
"fields": ["kind", "metadata.name"]
|
||||
}
|
||||
```
|
||||
|
||||
where each `entityRefs` entry is an entity ref that you want to fetch. The
|
||||
`fields` array is optional and works the same way as the `GET /entities` fields
|
||||
above, e.g. it's used to fetch only certain slices of each entity.
|
||||
|
||||
The return type is JSON, on the form
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [{ "kind": "Component", "metadata": { "name": "foo" } }, null]
|
||||
}
|
||||
```
|
||||
|
||||
where the `items` array has _the same length_ and _the same order_ as the input
|
||||
`entityRefs` array. Each element contains the corresponding entity data, or
|
||||
`null` if no entity existed in the catalog with that ref.
|
||||
|
||||
## Locations
|
||||
|
||||
TODO
|
||||
|
||||
@@ -251,6 +251,23 @@ the entity belongs to the `"default"` namespace.
|
||||
Namespaces may also be part of the catalog, and are `v1` / `Namespace` entities,
|
||||
i.e. not Backstage specific but the same as in Kubernetes.
|
||||
|
||||
### `uid` [output]
|
||||
|
||||
Each entity gets an automatically generated globally unique ID when it first
|
||||
enters the database. This field is not meant to be specified as input data, but
|
||||
is rater created by the database engine itself when producing the output entity.
|
||||
|
||||
Note that `uid` values are _not_ to be seen as stable, and should _not_ be used
|
||||
as external references to an entity. The `uid` can change over time even when a
|
||||
human observer might think that it wouldn't. As one of many examples,
|
||||
unregistering and re-registering the exact same file will result in a different
|
||||
`uid` value even though everything else is the same. Therefore there is very
|
||||
little, if any, reason to read or use this field externally.
|
||||
|
||||
If you want to refer to an entity by some form of an identifier, you should
|
||||
always use [string-form entity reference](references.md#string-references)
|
||||
instead.
|
||||
|
||||
### `title` [optional]
|
||||
|
||||
A display name of the entity, to be presented in user interfaces instead of the
|
||||
@@ -1309,3 +1326,7 @@ resolved relative to the location of this Location entity itself.
|
||||
A list of targets as strings. They can all be either absolute paths/URLs
|
||||
(depending on the type), or relative paths such as `./details/catalog-info.yaml`
|
||||
which are resolved relative to the location of this Location entity itself.
|
||||
|
||||
### `spec.presence` [optional]
|
||||
|
||||
Describes whether the target of a location is required to exist or not. It defaults to `'required'` if not specified, can also be `'optional'`.
|
||||
|
||||
@@ -438,7 +438,7 @@ with a new Entity type.
|
||||
### Creating a custom entity definition
|
||||
|
||||
The first step of introducing a custom entity is to define what shape and schema
|
||||
it has. We do this both using a TypeScript type, along with a JSONSchema schema.
|
||||
it has. We do this using a TypeScript type, as well as a JSONSchema schema.
|
||||
|
||||
Most of the time you will want to have at least the TypeScript type of your
|
||||
extension available in both frontend and backend code, which means you likely
|
||||
@@ -474,23 +474,35 @@ entity might look like:
|
||||
import { CatalogProcessor, processingResult } from '@backstage/catalog-backend';
|
||||
import { entityKindSchemaValidator } from '@backstage/catalog-model';
|
||||
|
||||
// For an example of the JSONSchema format and how to use $ref markers to the
|
||||
// base definitions, see:
|
||||
// https://github.com/backstage/backstage/tree/master/packages/catalog-model/src/schema/kinds/Component.v1alpha1.schema.json
|
||||
import { foobarEntityV1alpha1Schema } from '@internal/catalog-model';
|
||||
|
||||
export class FoobarEntitiesProcessor implements CatalogProcessor {
|
||||
// You often end up wanting to support multiple versions of your kind as you
|
||||
// iterate on the definition, so we keep each version inside this array.
|
||||
// iterate on the definition, so we keep each version inside this array as a
|
||||
// convenient pattern.
|
||||
private readonly validators = [
|
||||
// This is where we use the JSONSchema that we export from our isomorphic package
|
||||
// This is where we use the JSONSchema that we export from our isomorphic
|
||||
// package
|
||||
entityKindSchemaValidator(foobarEntityV1alpha1Schema),
|
||||
];
|
||||
|
||||
// validateEntityKind is responsible for signaling to the catalog processing engine
|
||||
// that this entity is valid and should therefore be submitted for further processing.
|
||||
// validateEntityKind is responsible for signaling to the catalog processing
|
||||
// engine that this entity is valid and should therefore be submitted for
|
||||
// further processing.
|
||||
async validateEntityKind(entity: Entity): Promise<boolean> {
|
||||
for (const validator of this.validators) {
|
||||
// If the validator throws an exception, the entity will be marked as
|
||||
// invalid.
|
||||
if (validator(entity)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Returning false signals that we don't know what this is, passing the
|
||||
// responsibility to other processors to try to validate it instead.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -505,8 +517,8 @@ export class FoobarEntitiesProcessor implements CatalogProcessor {
|
||||
) {
|
||||
const foobarEntity = entity as FoobarEntityV1alpha1;
|
||||
|
||||
// Here we can modify the entity or emit results related to the entity
|
||||
// Typically you will want to emit any relations associated with the entity here
|
||||
// Typically you will want to emit any relations associated with the
|
||||
// entity here.
|
||||
emit(processingResult.relation({ ... }))
|
||||
}
|
||||
|
||||
@@ -519,8 +531,7 @@ Once the processor is created it can be wired up to the catalog via the
|
||||
`CatalogBuilder` in `packages/backend/src/plugins/catalog.ts`:
|
||||
|
||||
```diff
|
||||
+ import { FoobarEntitiesProcessor implements CatalogProcessor {
|
||||
} from '@internal/plugin-foobar-backend';
|
||||
+ import { FoobarEntitiesProcessor } from '@internal/plugin-foobar-backend';
|
||||
|
||||
// ...
|
||||
|
||||
|
||||
@@ -111,10 +111,10 @@ export class FrobsProvider implements EntityProvider {
|
||||
throw new Error('Not initialized');
|
||||
}
|
||||
|
||||
const raw = await this.reader.read(
|
||||
const response = await this.reader.readUrl(
|
||||
`https://frobs-${this.env}.example.com/data`,
|
||||
);
|
||||
const data = JSON.parse(raw.toString());
|
||||
const data = JSON.parse(await response.buffer()).toString();
|
||||
|
||||
/** [5] **/
|
||||
const entities: Entity[] = frobsToEntities(data);
|
||||
@@ -525,8 +525,8 @@ export class SystemXReaderProcessor implements CatalogProcessor {
|
||||
// API. If you prefer, you can just use plain fetch here
|
||||
// (from the node-fetch package), or any other method of
|
||||
// your choosing.
|
||||
const data = await this.reader.read(location.target);
|
||||
const json = JSON.parse(data.toString());
|
||||
const response = await this.reader.readUrl(location.target);
|
||||
const json = JSON.parse((await response.buffer()).toString());
|
||||
// Repeatedly call emit(processingResult.entity(location, <entity>))
|
||||
} catch (error) {
|
||||
const message = `Unable to read ${location.type}, ${error}`;
|
||||
@@ -627,7 +627,7 @@ export class SystemXReaderProcessor implements CatalogProcessor {
|
||||
// We send the ETag from the previous run if it exists.
|
||||
// The previous ETag will be set in the headers for the outgoing request and system-x
|
||||
// is going to throw NOT_MODIFIED (HTTP 304) if the ETag matches.
|
||||
const response = await this.reader.readUrl?.(location.target, {
|
||||
const response = await this.reader.readUrl(location.target, {
|
||||
etag: cacheItem?.etag,
|
||||
});
|
||||
if (!response) {
|
||||
|
||||
@@ -23,18 +23,19 @@ the `Scaffolder` frontend plugin in your own `App.tsx`.
|
||||
|
||||
You can create your own Field Extension by using the
|
||||
[`createScaffolderFieldExtension`](https://backstage.io/docs/reference/plugin-scaffolder.createscaffolderfieldextension)
|
||||
`API` like below:
|
||||
`API` like below.
|
||||
|
||||
As an example, we will create a component that validates whether a string is in the `Kebab-case` pattern:
|
||||
|
||||
```tsx
|
||||
//packages/app/src/scaffolder/MyCustomExtension/MyCustomExtension.tsx
|
||||
//packages/app/src/scaffolder/ValidateKebabCase/ValidateKebabCaseExtension.tsx
|
||||
import React from 'react';
|
||||
import { FieldProps, FieldValidation } from '@rjsf/core';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import { KubernetesValidatorFunctions } from '@backstage/catalog-model';
|
||||
/*
|
||||
This is the actual component that will get rendered in the form
|
||||
*/
|
||||
export const MyCustomExtension = ({
|
||||
export const ValidateKebabCaseExtension = ({
|
||||
onChange,
|
||||
rawErrors,
|
||||
required,
|
||||
@@ -45,8 +46,17 @@ export const MyCustomExtension = ({
|
||||
margin="normal"
|
||||
required={required}
|
||||
error={rawErrors?.length > 0 && !formData}
|
||||
onChange={onChange}
|
||||
/>
|
||||
>
|
||||
<InputLabel htmlFor="validateName">Name</InputLabel>
|
||||
<Input
|
||||
id="validateName"
|
||||
aria-describedby="entityName"
|
||||
onChange={e => onChange(e.target?.value)}
|
||||
/>
|
||||
<FormHelperText id="entityName">
|
||||
Use only letters, numbers, hyphens and underscores
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -55,20 +65,22 @@ export const MyCustomExtension = ({
|
||||
You will get the value from the `onChange` handler before as the value here to make sure that the types are aligned\
|
||||
*/
|
||||
|
||||
export const myCustomValidation = (
|
||||
export const validateKebabCaseValidation = (
|
||||
value: string,
|
||||
validation: FieldValidation,
|
||||
) => {
|
||||
if (!KubernetesValidatorFunctions.isValidObjectName(value)) {
|
||||
const kebabCase = /^[a-z0-9-_]+$/g.test(value);
|
||||
|
||||
if (kebabCase === false) {
|
||||
validation.addError(
|
||||
'must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.',
|
||||
`Only use letters, numbers, hyphen ("-") and underscore ("_").`,
|
||||
);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
```tsx
|
||||
// packages/app/src/scaffolder/MyCustomExtension/extensions.ts
|
||||
// packages/app/src/scaffolder/ValidateKebabCase/extensions.ts
|
||||
|
||||
/*
|
||||
This is where the magic happens and creates the custom field extension.
|
||||
@@ -81,21 +93,24 @@ import {
|
||||
scaffolderPlugin,
|
||||
createScaffolderFieldExtension,
|
||||
} from '@backstage/plugin-scaffolder';
|
||||
import { MyCustomExtension, myCustomValidation } from './MyCustomExtension';
|
||||
import {
|
||||
ValidateKebabCase,
|
||||
validateKebabCaseValidation,
|
||||
} from './ValidateKebabCase';
|
||||
|
||||
export const MyCustomFieldExtension = scaffolderPlugin.provide(
|
||||
export const ValidateKebabCaseFieldExtension = scaffolderPlugin.provide(
|
||||
createScaffolderFieldExtension({
|
||||
name: 'MyCustomExtension',
|
||||
component: MyCustomExtension,
|
||||
validation: myCustomValidation,
|
||||
name: 'ValidateKebabCase',
|
||||
component: ValidateKebabCase,
|
||||
validation: validateKebabCaseValidation,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
```tsx
|
||||
// packages/app/src/scaffolder/MyCustomExtension/index.ts
|
||||
// packages/app/src/scaffolder/ValidateKebabCase/index.ts
|
||||
|
||||
export { MyCustomFieldExtension } from './extensions';
|
||||
export { ValidateKebabCaseFieldExtension } from './extensions';
|
||||
```
|
||||
|
||||
Once all these files are in place, you then need to provide your custom
|
||||
@@ -117,7 +132,7 @@ const routes = (
|
||||
Should look something like this instead:
|
||||
|
||||
```tsx
|
||||
import { MyCustomFieldExtension } from './scaffolder/MyCustomExtension';
|
||||
import { ValidateKebabCaseFieldExtension } from './scaffolder/ValidateKebabCase';
|
||||
import { ScaffolderFieldExtensions } from '@backstage/plugin-scaffolder';
|
||||
|
||||
const routes = (
|
||||
@@ -125,7 +140,7 @@ const routes = (
|
||||
...
|
||||
<Route path="/create" element={<ScaffolderPage />}>
|
||||
<ScaffolderFieldExtensions>
|
||||
<MyCustomFieldExtension />
|
||||
<ValidateKebabCaseFieldExtension />
|
||||
</ScaffolderFieldExtensions>
|
||||
</Route>
|
||||
...
|
||||
@@ -158,7 +173,9 @@ spec:
|
||||
title: Name
|
||||
type: string
|
||||
description: My custom name for the component
|
||||
ui:field: MyCustomExtension
|
||||
ui:field: ValidateKebabCaseExtension
|
||||
steps:
|
||||
[...]
|
||||
```
|
||||
|
||||
## Access Data from other Fields
|
||||
|
||||
@@ -44,8 +44,8 @@ spec:
|
||||
description: Owner of the component
|
||||
ui:field: OwnerPicker
|
||||
ui:options:
|
||||
allowedKinds:
|
||||
- Group
|
||||
catalogFilter:
|
||||
kind: Group
|
||||
- title: Choose a location
|
||||
required:
|
||||
- repoUrl
|
||||
@@ -165,11 +165,11 @@ this:
|
||||
"firstName": {
|
||||
"ui:autofocus": true,
|
||||
"ui:emptyValue": "",
|
||||
"ui:autocomplete": "family-name"
|
||||
"ui:autocomplete": "given-name"
|
||||
},
|
||||
"lastName": {
|
||||
"ui:emptyValue": "",
|
||||
"ui:autocomplete": "given-name"
|
||||
"ui:autocomplete": "family-name"
|
||||
},
|
||||
"nicknames": {
|
||||
"ui:options":{
|
||||
@@ -211,12 +211,12 @@ spec:
|
||||
default: Chuck
|
||||
ui:autofocus: true
|
||||
ui:emptyValue: ''
|
||||
ui:autocomplete: family-name
|
||||
ui:autocomplete: given-name
|
||||
lastName:
|
||||
type: string
|
||||
title: Last name
|
||||
ui:emptyValue: ''
|
||||
ui:autocomplete: given-name
|
||||
ui:autocomplete: family-name
|
||||
nicknames:
|
||||
type: array
|
||||
items:
|
||||
@@ -459,7 +459,7 @@ an owner for them. Ideally, users should be able to select an owner when they go
|
||||
through the scaffolder form from the users and groups already known to
|
||||
Backstage. The `OwnerPicker` is a custom field that generates a searchable list
|
||||
of groups and/or users already in the catalog to pick an owner from. You can
|
||||
specify which of the two kinds are listed in the `allowedKinds` option:
|
||||
specify which of the two kinds (or both) are listed in the `catalogFilter.kind` option:
|
||||
|
||||
```yaml
|
||||
owner:
|
||||
@@ -468,8 +468,8 @@ owner:
|
||||
description: Owner of the component
|
||||
ui:field: OwnerPicker
|
||||
ui:options:
|
||||
allowedKinds:
|
||||
- Group
|
||||
catalogFilter:
|
||||
kind: [Group, User]
|
||||
```
|
||||
|
||||
## `spec.steps` - `Action[]`
|
||||
|
||||
@@ -70,6 +70,11 @@ a Backstage app server on port 3000. The Backstage app has a custom TechDocs API
|
||||
implementation, which uses the MkDocs preview server as a proxy to fetch the
|
||||
generated documentation files and assets.
|
||||
|
||||
Backstage instances might differ from the provided preview app in appearance and
|
||||
behavior. To preview documentation with a different app, use
|
||||
`--preview-app-bundle-path` with a path to the bundle of the app to use instead.
|
||||
Typically, a `dist` or `build` directory.
|
||||
|
||||
NOTE: When using a custom `techdocs` docker image, make sure the entry point is
|
||||
also `ENTRYPOINT ["mkdocs"]` or override with `--docker-entrypoint`.
|
||||
|
||||
@@ -81,14 +86,17 @@ Usage: techdocs-cli serve [options]
|
||||
Serve a documentation project locally in a Backstage app-like environment
|
||||
|
||||
Options:
|
||||
-i, --docker-image <DOCKER_IMAGE> The mkdocs docker container to use (default: "spotify/techdocs")
|
||||
--docker-entrypoint <DOCKER_ENTRYPOINT> Override the image entrypoint
|
||||
--docker-option <DOCKER_OPTION...> Extra options to pass to the docker run command, e.g. "--add-host=internal.host:192.168.11.12"
|
||||
(can be added multiple times).
|
||||
--no-docker Do not use Docker, use MkDocs executable in current user environment.
|
||||
--mkdocs-port <PORT> Port for MkDocs server to use (default: "8000")
|
||||
-v --verbose Enable verbose output. (default: false)
|
||||
-h, --help display help for command
|
||||
-i, --docker-image <DOCKER_IMAGE> The mkdocs docker container to use (default: "spotify/techdocs")
|
||||
--docker-entrypoint <DOCKER_ENTRYPOINT> Override the image entrypoint
|
||||
--docker-option <DOCKER_OPTION...> Extra options to pass to the docker run command, e.g. "--add-host=internal.host:192.168.11.12"
|
||||
(can be added multiple times).
|
||||
--no-docker Do not use Docker, use MkDocs executable in current user environment.
|
||||
--mkdocs-port <PORT> Port for MkDocs server to use (default: "8000")
|
||||
--preview-app-bundle-path <PATH_TO_BUNDLE> Preview documentation using a web app other than the included one.
|
||||
--preview-app-port <PORT> Port where the preview will be served.
|
||||
Can only be used with "--preview-app-bundle-path". (default: "3000")
|
||||
-v --verbose Enable verbose output. (default: false)
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
### Generate TechDocs site from a documentation project
|
||||
|
||||
@@ -116,7 +116,7 @@ yarn clean # Remove all output folders and @backstage/cli cache
|
||||
|
||||
yarn diff # Make sure all plugins are up to date with the latest plugin template
|
||||
|
||||
yarn create-plugin # Create a new plugin
|
||||
yarn new # Create a new module
|
||||
```
|
||||
|
||||
> See
|
||||
|
||||
@@ -49,7 +49,7 @@ installation. Running the command below will install Backstage. The wizard will
|
||||
create a subdirectory inside your current working directory.
|
||||
|
||||
```bash
|
||||
npx @backstage/create-app
|
||||
npx @backstage/create-app@latest
|
||||
```
|
||||
|
||||
The wizard will ask you for the name of the app, which will also be the name of the directory
|
||||
|
||||
@@ -47,7 +47,7 @@ For this reason, any changes made to the template are documented along with
|
||||
upgrade instructions in the
|
||||
[changelog](https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md)
|
||||
of the `@backstage/create-app` package. We recommend peeking at this changelog
|
||||
-for any applicable updates when upgrading packages. As an alternative, the
|
||||
for any applicable updates when upgrading packages. As an alternative, the
|
||||
[Backstage Upgrade Helper](https://backstage.github.io/upgrade-helper/) provides
|
||||
a consolidated view of all the changes between two versions of Backstage. You
|
||||
can find the current version of your Backstage installation in `backstage.json`.
|
||||
|
||||
@@ -101,7 +101,7 @@ are separated out into their own folder, see further down.
|
||||
|
||||
- [`cli/`](https://github.com/backstage/backstage/tree/master/packages/cli) -
|
||||
One of the biggest packages in our project, the `cli` is used to build, serve,
|
||||
diff, create-plugins and more. In the early days of this project, we started
|
||||
diff, create plugins and more. In the early days of this project, we started
|
||||
out with calling tools directly - such as `eslint` - through `package.json`.
|
||||
But as it was tricky to have a good development experience around that when we
|
||||
change named tooling, we opted for wrapping those in our own CLI. That way
|
||||
|
||||
@@ -17,7 +17,7 @@ entities that mirror your org setup.
|
||||
> provide authentication. See the
|
||||
> [GitHub auth provider](../../auth/github/provider.md) for that.
|
||||
|
||||
## Installation
|
||||
## Installation without Events Support
|
||||
|
||||
This guide will use the Entity Provider method. If you for some reason prefer
|
||||
the Processor method (not recommended), it is described separately below.
|
||||
@@ -60,6 +60,52 @@ schedule it:
|
||||
+ );
|
||||
```
|
||||
|
||||
## Installation with Events Support
|
||||
|
||||
Please follow the installation instructions at
|
||||
|
||||
- https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md
|
||||
- https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-github/README.md
|
||||
|
||||
Additionally, you need to decide how you want to receive events from external sources like
|
||||
|
||||
- [via HTTP endpoint](https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md)
|
||||
- [via an AWS SQS queue](https://github.com/backstage/backstage/tree/master/plugins/events-backend-module-aws-sqs/README.md)
|
||||
|
||||
Set up your provider
|
||||
|
||||
```diff
|
||||
// packages/backend/src/plugins/catalogEventBasedProviders.ts
|
||||
+import { GithubOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-github';
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-node';
|
||||
import { EventSubscriber } from '@backstage/plugin-events-node';
|
||||
import { PluginEnvironment } from '../types';
|
||||
export default async function createCatalogEventBasedProviders(
|
||||
- _: PluginEnvironment,
|
||||
+ env: PluginEnvironment,
|
||||
): Promise<Array<EntityProvider & EventSubscriber>> {
|
||||
const providers: Array<
|
||||
(EntityProvider & EventSubscriber) | Array<EntityProvider & EventSubscriber>
|
||||
> = [];
|
||||
- // add your event-based entity providers here
|
||||
+ providers.push(
|
||||
+ GithubOrgEntityProvider.fromConfig(env.config, {
|
||||
+ id: 'production',
|
||||
+ orgUrl: 'https://github.com/backstage',
|
||||
+ logger: env.logger,
|
||||
+ schedule: env.scheduler.createScheduledTaskRunner({
|
||||
+ frequency: { minutes: 60 },
|
||||
+ timeout: { minutes: 15 },
|
||||
+ }),
|
||||
+ }),
|
||||
+ );
|
||||
return providers.flat();
|
||||
}
|
||||
```
|
||||
|
||||
You can check the official docs to [configure your webhook](https://docs.github.com/en/developers/webhooks-and-events/webhooks/creating-webhooks) and to [secure your request](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks).
|
||||
The webhook will need to be configured to forward `organization`,`team` and `membership` events.
|
||||
|
||||
## Configuration
|
||||
|
||||
As mentioned above, you also must have some configuration in your app-config
|
||||
|
||||
@@ -201,15 +201,15 @@ Usage: backstage-cli package postpack [options]
|
||||
Restores the changes made by the prepack command
|
||||
```
|
||||
|
||||
## create
|
||||
## new
|
||||
|
||||
The `create` command opens up an interactive guide for you to create new things
|
||||
The `new` command opens up an interactive guide for you to create new things
|
||||
in your app. If you do not pass in any options it is completely interactive, but
|
||||
it is possible to pre-select what you want to create using the `--select` flag,
|
||||
and provide options using `--options`, for example:
|
||||
and provide options using `--option`, for example:
|
||||
|
||||
```bash
|
||||
backstage-cli create --select plugin --option id=foo
|
||||
backstage-cli new --select plugin --option id=foo
|
||||
```
|
||||
|
||||
This command is typically added as script in the root `package.json` to be
|
||||
|
||||
@@ -54,7 +54,7 @@ Backstage also supports authentication through a proxy where the user identity i
|
||||
|
||||
## Catalog
|
||||
|
||||
Integrators should configure `catalog.rules` and `catalog.locations[].rules` to limit the allowed entity kinds that users can define. In general it is best to restrict definition of User, Group, and Template entities so that internal users cannot register additional ones. Template entities define actions that are executed on the backend hosts, and while the goal is for these actions to be secure regardless of input, it is still a more sensitive context and it is recommended that you protect it with additional checks. It is very important to not allow registration of User and Group entities if you ingest and rely on these as organizational data in your catalog. Doing so could otherwise open up for the ability to impersonate users and confuse group membership information. You should always ingest organizational data using a statically configured catalog location or an entity provider reading from a trusted source. The entities emitted directly by an entity provider are always trusted and rules are not applied to them, but any entities produced further down the chain are still subject to the rules.
|
||||
Integrators should configure [catalog rules](https://backstage.io/docs/features/software-catalog/configuration#catalog-rules) to limit the allowed entity kinds that users can define. In general it is best to restrict definition of User, Group, and Template entities so that internal users cannot register additional ones. Template entities define actions that are executed on the backend hosts, and while the goal is for these actions to be secure regardless of input, it is still a more sensitive context and it is recommended that you protect it with additional checks. It is very important to not allow registration of User and Group entities if you ingest and rely on these as organizational data in your catalog. Doing so could otherwise open up for the ability to impersonate users and confuse group membership information. You should always ingest organizational data using a statically configured catalog location or an entity provider reading from a trusted source. The entities emitted directly by an entity provider are always trusted and rules are not applied to them, but any entities produced further down the chain are still subject to the rules.
|
||||
|
||||
The Catalog does not aim to protect against resource exhaustion attacks in its default setup. If you need to prevent your internal users from being able to register large amounts of entities, then it is recommended to disable entity registration and use a different approach for discovering entities. One way to mitigate any resource exhaustion attacks is to only allow the catalog to read from trusted SCM sources that have an audit trail. Catalog currently lacks limits for entity hierarchy depth and entity size, which we hope to address in the future.
|
||||
|
||||
|
||||
@@ -116,9 +116,8 @@ For packages at version `1.0.0` or above, the following policy also applies:
|
||||
before it can be removed.
|
||||
- The release of breaking changes document a clear upgrade path in the
|
||||
changelog, both when deprecations are introduced and when they are removed.
|
||||
- Exports that have been marked as `@alpha` or `@beta` may receive breaking
|
||||
changes without a deprecation period, but the changes must still adhere to
|
||||
semver.
|
||||
- Breaking changes to `@alpha` or `@beta` exports must result in at least a minor
|
||||
version bump, and may be done without a deprecation period.
|
||||
|
||||
### Changes that are Not Considered Breaking
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ lowercase characters separated by dashes, for example `carmen`, if it's a
|
||||
package that adds an integration with a system named Carmen, for example. The
|
||||
full NPM package name would then be something like
|
||||
`@internal/plugin-carmen-backend`, depending on the other flags passed to the
|
||||
`create-plugin` command, and your settings for the `create-plugin` command in
|
||||
`new` command, and your settings for the `new` command in
|
||||
your root `package.json`.
|
||||
|
||||
Creating the plugin will take a little while, so be patient. It will helpfully
|
||||
|
||||
@@ -11,7 +11,7 @@ A Backstage Plugin adds functionality to Backstage.
|
||||
To create a new plugin, make sure you've run `yarn install` and installed
|
||||
dependencies, then run the following on your command line (a shortcut to
|
||||
invoking the
|
||||
[`backstage-cli create-plugin`](../local-dev/cli-commands.md#create-plugin))
|
||||
[`backstage-cli new --select plugin`](../local-dev/cli-commands.md#new))
|
||||
from the root of your project.
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
---
|
||||
id: feature-flags
|
||||
title: Feature Flags
|
||||
description: Details the process of defining setting and reading a plugin feature flag.
|
||||
description: Details the process of defining setting and reading a feature flag.
|
||||
---
|
||||
|
||||
Backstage offers the ability to define feature flags inside a plugin. This allows you to restrict parts of your plugin to those individual users who have toggled the feature flag to on.
|
||||
Backstage offers the ability to define feature flags inside a plugin or during application creation. This allows you to restrict parts of your plugin to those individual users who have toggled the feature flag to on.
|
||||
|
||||
This page describes the process of defining setting and reading a plugin feature flag. If you are looking for using feature flags with software templates that can be found under [Writing Templates](https://backstage.io/docs/features/software-templates/writing-templates#remove-sections-or-fields-based-on-feature-flags).
|
||||
This page describes the process of defining setting and reading a feature flag. If you are looking for using feature flags with software templates that can be found under [Writing Templates](https://backstage.io/docs/features/software-templates/writing-templates#remove-sections-or-fields-based-on-feature-flags).
|
||||
|
||||
## Defining a Feature Flag
|
||||
|
||||
Before using a feature flag we must first define it. This is done when we create the plugin by passing the name of the feature flag into the `featureFlags` array.
|
||||
### In a plugin
|
||||
|
||||
Defining feature flag in a plugin is done by passing the name of the feature flag into the `featureFlags` array:
|
||||
|
||||
```ts
|
||||
/* src/plugin.ts */
|
||||
@@ -26,6 +28,21 @@ export const examplePlugin = createPlugin({
|
||||
});
|
||||
```
|
||||
|
||||
### In the application
|
||||
|
||||
Defining feature flag in the application is done by adding feature flags in`featureFlags` array in
|
||||
`createApp()` function call:
|
||||
|
||||
```ts
|
||||
const app = createApp({
|
||||
// ...
|
||||
featureFlags: [
|
||||
{ name: 'tech-radar', description: 'Enables the tech radar plugin' },
|
||||
],
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
## Enabling Feature Flags
|
||||
|
||||
Feature flags are defaulted to off and can be updated by individual users in the backstage interface.
|
||||
|
||||
@@ -21,7 +21,7 @@ should have a separate package in a folder, which represents your plugin.
|
||||
Example:
|
||||
|
||||
```
|
||||
$ yarn create-plugin
|
||||
$ yarn new --select plugin
|
||||
> ? Enter an ID for the plugin [required] my-plugin
|
||||
> ? Enter the owner(s) of the plugin. If specified, this will be added to CODEOWNERS for the plugin path. [optional]
|
||||
|
||||
|
||||
@@ -333,3 +333,85 @@ reading the search context.
|
||||
If you produce something generic and reusable, consider contributing your
|
||||
component upstream so that all users of the Backstage Search Platform can
|
||||
benefit. Issues and pull requests welcome.
|
||||
|
||||
#### Custom search results
|
||||
|
||||
Search results throughout Backstage are rendered as lists so that list items can easily be customized; although a [default result list item](https://backstage.io/storybook/?path=/story/plugins-search-defaultresultlistitem--default) is available, plugins are in the best position to provide custom result list items that surface relevant information only known to the plugin.
|
||||
|
||||
The example below imagines `YourCustomSearchResult` as a type of search result that contains associated `tags` which could be rendered as chips below the title/text.
|
||||
|
||||
```tsx
|
||||
import { Link } from '@backstage/core-components';
|
||||
import { useAnalytics } from '@backstage/core-plugin-api';
|
||||
import { ResultHighlight } from '@backstage/plugin-search-common';
|
||||
import { HighlightedSearchResultText } from '@backstage/plugin-search-react';
|
||||
|
||||
type CustomSearchResultListItemProps = {
|
||||
result: YourCustomSearchResult;
|
||||
rank?: number;
|
||||
highlight?: ResultHighlight;
|
||||
};
|
||||
|
||||
export const CustomSearchResultListItem = (
|
||||
props: CustomSearchResultListItemProps,
|
||||
) => {
|
||||
const { title, text, location, tags } = props.result;
|
||||
|
||||
const analytics = useAnalytics();
|
||||
const handleClick = () => {
|
||||
analytics.captureEvent('discover', title, {
|
||||
attributes: { to: location },
|
||||
value: props.rank,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Link noTrack to={location} onClick={handleClick}>
|
||||
<ListItem alignItems="center">
|
||||
<Box flexWrap="wrap">
|
||||
<ListItemText
|
||||
primaryTypographyProps={{ variant: 'h6' }}
|
||||
primary={
|
||||
highlight?.fields?.title ? (
|
||||
<HighlightedSearchResultText
|
||||
text={highlight.fields.title}
|
||||
preTag={highlight.preTag}
|
||||
postTag={highlight.postTag}
|
||||
/>
|
||||
) : (
|
||||
title
|
||||
)
|
||||
}
|
||||
secondary={
|
||||
highlight?.fields?.text ? (
|
||||
<HighlightedSearchResultText
|
||||
text={highlight.fields.text}
|
||||
preTag={highlight.preTag}
|
||||
postTag={highlight.postTag}
|
||||
/>
|
||||
) : (
|
||||
text
|
||||
)
|
||||
}
|
||||
/>
|
||||
{tags &&
|
||||
tags.map((tag: string) => (
|
||||
<Chip key={tag} label={`Tag: ${tag}`} size="small" />
|
||||
))}
|
||||
</Box>
|
||||
</ListItem>
|
||||
<Divider />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
The optional use of the `<HighlightedSearchResultText>` component makes it possible to highlight relevant parts of the result based on the user's search query.
|
||||
|
||||
**Note on Analytics**: In order for app integrators to track and improve search experiences across Backstage, it's important for them to understand when and what users search for, as well as what they click on after searching. When providing a custom result component, it's your responsibility as a plugin developer to instrument it according to search analytics conventions. In particular:
|
||||
|
||||
- You must use the `analytics.captureEvent` method, from the `useAnalytics()` hook (detailed [plugin analytics docs are here](./analytics.md)).
|
||||
- You must ensure that the action of the event, representing a click on a search result item, is `discover`, and the subject is the `title` of the clicked result. In addition, the `to` attribute should be set to the result's `location`, and the `value` of the event must be set to the `rank` (passed in as a prop).
|
||||
- You must ensure that the aforementioned `captureEvent` method is called when a user clicks the link; you should further ensure that the `noTrack` prop is added to the link (which disables default link click tracking, in favor of this custom instrumentation).
|
||||
|
||||
For other examples and inspiration on custom result list items, check out the [`<StackOverflowSearchResultListItem>`](https://github.com/backstage/backstage/blob/c981e83/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx) or [`<CatalogSearchResultListItem>`](https://github.com/backstage/backstage/blob/c981e83/plugins/catalog/src/components/CatalogSearchResultListItem/CatalogSearchResultListItem.tsx) components.
|
||||
|
||||
@@ -8,13 +8,13 @@ description: Details of the upcoming backend system
|
||||
|
||||
## Status
|
||||
|
||||
The new backend system is under active development, and only a small number of plugins and services have been migrated so far. It is possible to try it out, but it is not recommended to use this new system in production yet.
|
||||
The new backend system is under active development, and only a small number of plugins have been migrated so far. It is possible to try it out, but it is not recommended to use this new system in production yet.
|
||||
|
||||
You can find an example backend setup at https://github.com/backstage/backstage/tree/master/packages/backend-next.
|
||||
You can find an example backend setup in [the backend-next package](https://github.com/backstage/backstage/tree/master/packages/backend-next).
|
||||
|
||||
## Overview
|
||||
|
||||
The new Backstage backend system is being built to help make it simpler to install backend plugins and keep projects up to date. It also changes the foundation to one that makes it a lot easier to evolve plugins and the system itself. You can read more about the reasoning in the [original RFC](https://github.com/backstage/backstage/issues/11611).
|
||||
The new Backstage backend system is being built to help make it simpler to install backend plugins and to keep projects up to date. It also changes the foundation to one that makes it a lot easier to evolve plugins and the system itself with minimal disruption or cause for breaking changes. You can read more about the reasoning in the [original RFC](https://github.com/backstage/backstage/issues/11611).
|
||||
|
||||
One of the goals of the new system was to reduce the code needed for setting up a Backstage backend and installing plugins. This is an example of how you create, add features, and start up your backend in the new system:
|
||||
|
||||
@@ -32,21 +32,21 @@ backend.add(catalogPlugin());
|
||||
await backend.start();
|
||||
```
|
||||
|
||||
One notable change that helped achieve this much slimmer backend setup is the introduction of dependency injection, with a system that is very similar to the one in the Backstage frontend.
|
||||
One notable change that helped achieve this much slimmer backend setup is the introduction of a system for dependency injection, which is very similar to the one in the Backstage frontend.
|
||||
|
||||
## Building Blocks
|
||||
|
||||
This section introduces the high-level building blocks upon which this new system is built. These are all concepts that exist in our current system in one way or another, but the have all been lifted up to be first class concerns in the new system.
|
||||
This section introduces the high-level building blocks upon which this new system is built. These are all concepts that exist in our current system in one way or another, but they have all been lifted up to be first class concerns in the new system.
|
||||
|
||||
### Backend
|
||||
|
||||
This is the backend instance itself, which you can think of as the unit of deployment. It does not have any functionality in itself, but is simply responsible for wiring things together.
|
||||
This is the backend instance itself, which you can think of as the unit of deployment. It does not have any functionality in and of itself, but is simply responsible for wiring things together.
|
||||
|
||||
It is up to you to decide how many different backends you want to deploy. You can have all features in a single one, or split things out into multiple smaller deployments. All depending on your need to scale and isolate individual features.
|
||||
|
||||
### Plugins
|
||||
|
||||
Plugins provide the actual features, just like in our existing system. They operate completely independently of each other. If plugins what to communicate with each other, they must do so over the wire. There can be no direct communication between plugins through code. Because of this constraints, each plugins can be considered to be its own microservice.
|
||||
Plugins provide the actual features, just like in our existing system. They operate completely independently of each other. If plugins want to communicate with each other, they must do so over the wire. There can be no direct communication between plugins through code. Because of this constraint, each plugin can be considered to be its own microservice.
|
||||
|
||||
### Services
|
||||
|
||||
@@ -77,6 +77,7 @@ Plugins are created using the `createBackendPlugin` function. All plugins must h
|
||||
```ts
|
||||
import {
|
||||
configServiceRef,
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
@@ -89,7 +90,7 @@ export const examplePlugin = createBackendPlugin({
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: loggerServiceRef,
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
// logger is provided by the backend based on the dependency on loggerServiceRef above.
|
||||
async init({ logger }) {
|
||||
@@ -113,7 +114,7 @@ export const examplePlugin = createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env, options?: { silent?: boolean }) {
|
||||
env.registerInit({
|
||||
deps: { logger: loggerServiceRef },
|
||||
deps: { logger: coreServices.logger },
|
||||
async init({ logger }) {
|
||||
if (!options?.silent) {
|
||||
logger.info('Hello from example plugin');
|
||||
@@ -188,7 +189,7 @@ Extension points are registered by a plugin and extended by modules.
|
||||
|
||||
## Backend Services
|
||||
|
||||
The default backend provides several _services_ out of the box which includes access to configuration, logging, databases and more.
|
||||
The default backend provides several [core services](https://github.com/backstage/backstage/blob/master/packages/backend-plugin-api/src/services/definitions/coreServices.ts) out of the box which includes access to configuration, logging, databases and more.
|
||||
Service dependencies are declared using their `ServiceRef`s in the `deps` section of the plugin or module, and the implementations are then forwarded to the `init` method of the plugin or module.
|
||||
|
||||
### Service References
|
||||
@@ -204,8 +205,7 @@ ServiceRefs contain a scope which is used to determine if the serviceFactory cre
|
||||
```ts
|
||||
import {
|
||||
createServiceFactory,
|
||||
pluginMetadataServiceRef,
|
||||
loggerServiceRef,
|
||||
coreServices,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { ExampleImpl } from './ExampleImpl';
|
||||
|
||||
@@ -223,11 +223,11 @@ export const exampleServiceRef = createServiceRef<ExampleApi>({
|
||||
createServiceFactory({
|
||||
service,
|
||||
deps: {
|
||||
logger: loggerServiceRef,
|
||||
plugin: pluginMetadataServiceRef,
|
||||
logger: coreServices.logger,
|
||||
plugin: coreServices.pluginMetadata,
|
||||
},
|
||||
// Logger is available directly in the factory as it's a root scoped service and will be created once per backend instance.
|
||||
async factory({ logger }) {
|
||||
async factory({ logger, plugin }) {
|
||||
// plugin is available as it's a plugin scoped service and will be created once per plugin.
|
||||
return async ({ plugin }) => {
|
||||
// This block will be executed once for every plugin that depends on this service
|
||||
@@ -277,20 +277,20 @@ const backend = createBackend({
|
||||
## Testing
|
||||
|
||||
Utilities for testing backend plugins and modules are available in `@backstage/backend-test-utils`.
|
||||
`startTestBackend` returns the HTTP which can be used together with `supertest` to test the plugin.
|
||||
|
||||
```ts
|
||||
import { startTestBackend } from '@backstage/backend-test-utils';
|
||||
import request from 'supertest';
|
||||
|
||||
describe('Example', () => {
|
||||
it('should do something', async () => {
|
||||
await startTestBackend({
|
||||
// mock services can be provided to the backend
|
||||
services: [someServiceFactory],
|
||||
// plugins and modules for testing
|
||||
features: [testModule()],
|
||||
describe('My plugin tests', () => {
|
||||
it('should return 200', async () => {
|
||||
const { server } = await startTestBackend({
|
||||
features: [myPlugin()],
|
||||
});
|
||||
|
||||
// assertions
|
||||
const response = await request(server).get('/api/example/hello');
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -60,15 +60,7 @@ The generic interface of a URL Reader instance looks like this.
|
||||
```ts
|
||||
export type UrlReader = {
|
||||
/* Used to read a single file and return its content. */
|
||||
read(url: string): Promise<Buffer>;
|
||||
/**
|
||||
* A replacement for the read method that supports options and complex responses.
|
||||
*
|
||||
* Use this whenever it is available, as the read method will be deprecated and
|
||||
* eventually removed in the future.
|
||||
*/
|
||||
readUrl?(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
|
||||
|
||||
readUrl(url: string, options?: ReadUrlOptions): Promise<ReadUrlResponse>;
|
||||
/* Used to read a file tree and download as a directory. */
|
||||
readTree(url: string, options?: ReadTreeOptions): Promise<ReadTreeResponse>;
|
||||
/* Used to search a file in a tree. */
|
||||
@@ -102,8 +94,8 @@ backend plugins.
|
||||
Once the reader instance is available inside the plugin, one of its methods can
|
||||
directly be used with a URL. Some example usages -
|
||||
|
||||
- [`read`](https://github.com/backstage/backstage/blob/d5c83bb889b8142e343ebc4e4c0b90a02d1c1a3d/plugins/catalog-backend/src/ingestion/processors/codeowners/read.ts#L24-L33) -
|
||||
Catalog using the `read` method to read the CODEOWNERS file in a repository.
|
||||
- [`readUrl`](https://github.com/backstage/backstage/blob/a7607b5/plugins/catalog-backend/src/modules/codeowners/lib/read.ts#L24-L33) -
|
||||
Catalog using the `readUrl` method to read the CODEOWNERS file in a repository.
|
||||
- [`readTree`](https://github.com/backstage/backstage/blob/84a8788/plugins/techdocs-node/src/helpers.ts#L146-L167) -
|
||||
TechDocs using the `readTree` method to download markdown files in order to
|
||||
generate the documentation site.
|
||||
@@ -155,11 +147,9 @@ all the methods of the `UrlReader` interface should be implemented. However it
|
||||
is okay to start by implementing just one of them and create issues for the
|
||||
remaining.
|
||||
|
||||
#### read
|
||||
#### `readUrl`
|
||||
|
||||
NOTE: Use `readUrl` instead of `read`.
|
||||
|
||||
`read` method expects a user-friendly URL, something which can be copied from
|
||||
`readUrl` method expects a user-friendly URL, something which can be copied from
|
||||
the browser naturally when a person is browsing the provider in their browser.
|
||||
|
||||
- ✅ Valid URL :
|
||||
@@ -168,18 +158,10 @@ the browser naturally when a person is browsing the provider in their browser.
|
||||
`https://raw.githubusercontent.com/backstage/backstage/master/ADOPTERS.md`
|
||||
- ❌ Not a valid URL : `https://github.com/backstage/backstage/ADOPTERS.md`
|
||||
|
||||
Upon receiving the URL, `read` converts the user-friendly URL into an API URL
|
||||
Upon receiving the URL, `readUrl` converts the user-friendly URL into an API URL
|
||||
which can be used to request the provider's API.
|
||||
|
||||
`read` then makes an authenticated request to the provider API and returns the
|
||||
file's content.
|
||||
|
||||
#### `readUrl`
|
||||
|
||||
`readUrl` is a new interface that allows complex response objects and is
|
||||
intended to replace the `read` method. This new method is currently optional to
|
||||
implement which allows for a soft migration to `readUrl` instead of `read` in
|
||||
the future.
|
||||
`readUrl` then makes an authenticated request to the provider API and returns the response containing the file's contents and ETag(if the provider supports it).
|
||||
|
||||
#### `readTree`
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
---
|
||||
id: v1.10.0
|
||||
title: v1.10.0
|
||||
description: Backstage Release v1.10.0
|
||||
---
|
||||
|
||||
These are the release notes for the v1.10.0 release of [Backstage](https://backstage.io/).
|
||||
|
||||
A huge thanks to the whole team of maintainers and contributors as well as the amazing Backstage Community for the hard work in getting this release developed and done.
|
||||
|
||||
## Highlights
|
||||
|
||||
### `yarn new` instead of `yarn create-plugin`
|
||||
|
||||
The `create-plugin` command of the `backstage-cli` is deprecated, and we have removed its usage in newly created apps and in our documentation. We recommend that you update your root `package.json` as follows:
|
||||
|
||||
```diff
|
||||
"scripts": {
|
||||
...
|
||||
- "create-plugin": "backstage-cli create-plugin --scope internal"
|
||||
+ "new": "backstage-cli new --scope internal"
|
||||
}
|
||||
```
|
||||
|
||||
### New Package: `@backstage/plugin-scaffolder-react`
|
||||
|
||||
We’ve made it easier to re-use some of the Scaffolder components outside of the Scaffolder plugin as well as re-homing some common types that might live between other frontend modules in the future. With this change there’s been some deprecations that have been shipped which are just renaming the imports from `@backstage/plugin-scaffolder` to `@backstage/plugin-scaffolder-react`. You can find out more in the [changelog](https://github.com/backstage/backstage/blob/master/plugins/scaffolder/CHANGELOG.md#minor-changes) for the `@backstage/plugin-scaffolder`
|
||||
|
||||
### New Package: `@backstage/plugin-scaffolder-backend-module-sentry`
|
||||
|
||||
A new module has been created that allows the creation of [Sentry](https://sentry.io) projects with a new `sentry:project:create` action.
|
||||
|
||||
Contributed by [@dpfaffenbauer](https://github.com/dpfaffenbauer) in [#15639](https://github.com/backstage/backstage/pull/15639)
|
||||
|
||||
### New Package: `@backstage/repo-tools`
|
||||
|
||||
Parts of the tooling that powers the Backstage main repository are being externalized, into [the `@backstage/repo-tools` package](https://www.npmjs.com/package/@backstage/repo-tools). Documentation is sparse and so far it houses only the API extractor (which makes the `api-report.md` files) and the type dependencies check which makes sure that `@types/*` packages that are visible in the public API are added as dependencies.
|
||||
|
||||
### Scaffolder Improvements
|
||||
|
||||
Examples can now be added to `createTemplateAction` in the backend and can be browsed under `/create/actions` on your Backstage instance.
|
||||
|
||||
Contributed by [@punkle](https://github.com/punkle) in [#15341](https://github.com/backstage/backstage/pull/15341)
|
||||
|
||||
The `allowedKinds` has been deprecated from the `OwnerPicker` and `EntityPicker` in favor of a `catalogFilter` option that allows you to be more flexible in the filtering from the Catalog.
|
||||
|
||||
Contributed by [@rikez](https://github.com/rikez) in [#15063](https://github.com/backstage/backstage/pull/15063)
|
||||
|
||||
### Backend System Progress
|
||||
|
||||
We’ve made good progress towards getting the new backend system ready for broader testing. While we’re not quite there yet, you’ll see a lot of changes in the `@backstage/backend-app-api` and `@backstage/backend-plugin-api` packages as well as supporting packages like `@backstage/backend-defaults`.
|
||||
|
||||
### Event based updates in `GithubOrgEntityProvider`
|
||||
|
||||
There’s some initial support for event (web hook) based updates for GitHub org entities that are ingested using `GithubOrgEntityProvider`. We are excited to see the `events-backend` starting to power this type of functionality. More information on the setup can be found [in the documentation](https://backstage.io/docs/integrations/github/org#installation-with-events-support).
|
||||
|
||||
Contributed by [@angeliski](https://github.com/angeliski) in [#14870](https://github.com/backstage/backstage/pull/14870)
|
||||
|
||||
## Security Fixes
|
||||
|
||||
This release does not contain any security fixes.
|
||||
|
||||
## Upgrade path
|
||||
|
||||
We recommend that you keep your Backstage project up to date with this latest release. For more guidance on how to upgrade, check out the documentation for [keeping Backstage updated](https://backstage.io/docs/getting-started/keeping-backstage-updated).
|
||||
|
||||
## Links and References
|
||||
|
||||
Below you can find a list of links and references to help you learn about and start using this new release.
|
||||
|
||||
- [Backstage official website](https://backstage.io/), [documentation](https://backstage.io/docs/), and [getting started guide](https://backstage.io/docs/getting-started/)
|
||||
- [GitHub repository](https://github.com/backstage/backstage)
|
||||
- Backstage's [versioning and support policy](https://backstage.io/docs/overview/versioning-policy)
|
||||
- [Community Discord](https://discord.gg/bFESRKVt) for discussions and support
|
||||
- [Changelog](https://github.com/backstage/backstage/tree/master/docs/releases/v1.10.0-changelog.md)
|
||||
- Backstage [Demos](https://backstage.io/demos), [Blog](https://backstage.io/blog), [Roadmap](https://backstage.io/docs/overview/roadmap) and [Plugins](https://backstage.io/plugins)
|
||||
|
||||
Sign up for our [newsletter](https://mailchi.mp/spotify/backstage-community) if you want to be informed about what is happening in the world of Backstage.
|
||||
@@ -28,7 +28,7 @@ organization to easily install and add to their Backstage installation.
|
||||
# 1. A New Plugin
|
||||
|
||||
Sam chooses to develop this plugin in a standalone project and creates a new
|
||||
plugin using `npx @backstage/cli create-plugin`, which detects that it's not
|
||||
plugin using `npx @backstage/cli new --select plugin`, which detects that it's not
|
||||
being run in an existing project and therefore creates a separate plugin repo.
|
||||
|
||||
Spinning up the frontend with `yarn start`, Sam goes to work with getting the
|
||||
|
||||
@@ -29,8 +29,8 @@ title: Adding Custom Plugin to Existing Monorepo App
|
||||
|
||||
# The Skeleton Plugin
|
||||
|
||||
1. Start by using the built in creator. From the terminal and root of your
|
||||
project run: `yarn create-plugin`
|
||||
1. Start by using the built-in creator. From the terminal and root of your
|
||||
project run: `yarn new --select plugin`
|
||||
1. Enter a plugin ID. I used `github-playground`
|
||||
1. When the process finishes, let's start the backend:
|
||||
`yarn --cwd packages/backend start`
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"examples": "docusaurus-examples",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"start": "node scripts/pre-build.js && docusaurus start",
|
||||
"build": "node scripts/pre-build.js && docusaurus build",
|
||||
"prettier:check": "prettier --check .",
|
||||
"publish-gh-pages": "docusaurus-publish",
|
||||
"write-translations": "docusaurus-write-translations",
|
||||
@@ -20,7 +19,8 @@
|
||||
"devDependencies": {
|
||||
"@spotify/prettier-config": "^14.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"prettier": "^2.6.2"
|
||||
"prettier": "^2.6.2",
|
||||
"replace": "^1.2.2"
|
||||
},
|
||||
"prettier": "@spotify/prettier-config",
|
||||
"dependencies": {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2022 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const replace = require('replace');
|
||||
const { existsSync, writeFileSync, mkdirSync } = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const PLACEHOLDER = `---
|
||||
id: "index"
|
||||
title: "Package Index"
|
||||
description: "Index of all Backstage Packages"
|
||||
---
|
||||
Run \`yarn build:api-docs\` to generate the API docs.
|
||||
`;
|
||||
|
||||
async function main() {
|
||||
const referencesDir = '../docs/reference';
|
||||
if (existsSync(referencesDir)) {
|
||||
console.log('Removing HTML comments from docs/reference folder');
|
||||
replace({
|
||||
regex: '<!--(.*?)-->',
|
||||
replacement: '',
|
||||
paths: [referencesDir],
|
||||
recursive: true,
|
||||
silent: false,
|
||||
});
|
||||
} else {
|
||||
mkdirSync(referencesDir);
|
||||
writeFileSync(path.join(referencesDir, 'index.md'), PLACEHOLDER);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error(error.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1 +1,366 @@
|
||||
{}
|
||||
{
|
||||
"releases": {
|
||||
"Release Notes": [
|
||||
"releases/v1.8.0",
|
||||
"releases/v1.7.0",
|
||||
"releases/v1.6.0",
|
||||
"releases/v1.5.0",
|
||||
"releases/v1.4.0",
|
||||
"releases/v1.3.0",
|
||||
"releases/v1.2.0",
|
||||
"releases/v1.1.0",
|
||||
"releases/v1.0.0"
|
||||
]
|
||||
},
|
||||
"docs": {
|
||||
"Overview": [
|
||||
"overview/what-is-backstage",
|
||||
"overview/architecture-overview",
|
||||
"overview/roadmap",
|
||||
"overview/vision",
|
||||
"overview/background",
|
||||
"overview/adopting",
|
||||
"overview/versioning-policy",
|
||||
"overview/threat-model",
|
||||
"overview/support",
|
||||
"overview/glossary",
|
||||
"overview/logos"
|
||||
],
|
||||
"Getting Started": [
|
||||
"getting-started/index",
|
||||
"getting-started/configuration",
|
||||
"getting-started/create-an-app",
|
||||
"getting-started/running-backstage-locally",
|
||||
{
|
||||
"type": "category",
|
||||
"label": "App configuration",
|
||||
"items": [
|
||||
"getting-started/configure-app-with-plugins",
|
||||
"getting-started/app-custom-theme",
|
||||
"getting-started/homepage"
|
||||
]
|
||||
},
|
||||
"getting-started/keeping-backstage-updated",
|
||||
"getting-started/concepts",
|
||||
"getting-started/contributors",
|
||||
"getting-started/project-structure"
|
||||
],
|
||||
"Local Development": [
|
||||
{
|
||||
"type": "category",
|
||||
"label": "CLI",
|
||||
"items": [
|
||||
"local-dev/cli-overview",
|
||||
"local-dev/cli-build-system",
|
||||
"local-dev/cli-commands"
|
||||
]
|
||||
},
|
||||
"local-dev/linking-local-packages"
|
||||
],
|
||||
"Core Features": [
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Software Catalog",
|
||||
"items": [
|
||||
"features/software-catalog/software-catalog-overview",
|
||||
"features/software-catalog/life-of-an-entity",
|
||||
"features/software-catalog/configuration",
|
||||
"features/software-catalog/system-model",
|
||||
"features/software-catalog/descriptor-format",
|
||||
"features/software-catalog/references",
|
||||
"features/software-catalog/well-known-annotations",
|
||||
"features/software-catalog/well-known-relations",
|
||||
"features/software-catalog/well-known-statuses",
|
||||
"features/software-catalog/extending-the-model",
|
||||
"features/software-catalog/external-integrations",
|
||||
"features/software-catalog/catalog-customization",
|
||||
"features/software-catalog/software-catalog-api"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Kubernetes",
|
||||
"items": [
|
||||
"features/kubernetes/overview",
|
||||
"features/kubernetes/installation",
|
||||
"features/kubernetes/configuration",
|
||||
"features/kubernetes/authentication",
|
||||
"features/kubernetes/troubleshooting"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Software Templates",
|
||||
"items": [
|
||||
"features/software-templates/software-templates-index",
|
||||
"features/software-templates/configuration",
|
||||
"features/software-templates/adding-templates",
|
||||
"features/software-templates/writing-templates",
|
||||
"features/software-templates/input-examples",
|
||||
"features/software-templates/builtin-actions",
|
||||
"features/software-templates/writing-custom-actions",
|
||||
"features/software-templates/writing-custom-field-extensions",
|
||||
"features/software-templates/writing-custom-step-layouts",
|
||||
"features/software-templates/migrating-from-v1beta2-to-v1beta3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Backstage Search",
|
||||
"items": [
|
||||
"features/search/search-overview",
|
||||
"features/search/getting-started",
|
||||
"features/search/concepts",
|
||||
"features/search/architecture",
|
||||
"features/search/search-engines",
|
||||
"features/search/how-to-guides"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "TechDocs",
|
||||
"items": [
|
||||
"features/techdocs/techdocs-overview",
|
||||
"features/techdocs/getting-started",
|
||||
"features/techdocs/concepts",
|
||||
"features/techdocs/addons",
|
||||
"features/techdocs/architecture",
|
||||
"features/techdocs/creating-and-publishing",
|
||||
"features/techdocs/configuration",
|
||||
"features/techdocs/using-cloud-storage",
|
||||
"features/techdocs/configuring-ci-cd",
|
||||
"features/techdocs/cli",
|
||||
"features/techdocs/how-to-guides",
|
||||
"features/techdocs/troubleshooting",
|
||||
"features/techdocs/faqs"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Integrations": [
|
||||
"integrations/index",
|
||||
{
|
||||
"type": "category",
|
||||
"label": "AWS S3",
|
||||
"items": [
|
||||
"integrations/aws-s3/locations",
|
||||
"integrations/aws-s3/discovery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Azure",
|
||||
"items": [
|
||||
"integrations/azure/locations",
|
||||
"integrations/azure/discovery",
|
||||
"integrations/azure/org"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Bitbucket Cloud",
|
||||
"items": [
|
||||
"integrations/bitbucketCloud/locations",
|
||||
"integrations/bitbucketCloud/discovery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Bitbucket Server",
|
||||
"items": [
|
||||
"integrations/bitbucketServer/locations",
|
||||
"integrations/bitbucketServer/discovery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Datadog",
|
||||
"items": ["integrations/datadog-rum/installation"]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Gerrit",
|
||||
"items": [
|
||||
"integrations/gerrit/locations",
|
||||
"integrations/gerrit/discovery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "GitHub",
|
||||
"items": [
|
||||
"integrations/github/locations",
|
||||
"integrations/github/discovery",
|
||||
"integrations/github/org",
|
||||
"integrations/github/github-apps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "GitLab",
|
||||
"items": [
|
||||
"integrations/gitlab/locations",
|
||||
"integrations/gitlab/discovery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Gitea",
|
||||
"items": ["integrations/gitea/locations"]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Google GCS",
|
||||
"items": ["integrations/google-cloud-storage/locations"]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "LDAP",
|
||||
"items": ["integrations/ldap/org"]
|
||||
}
|
||||
],
|
||||
"Plugins": [
|
||||
"plugins/index",
|
||||
"plugins/existing-plugins",
|
||||
"plugins/create-a-plugin",
|
||||
"plugins/plugin-development",
|
||||
"plugins/structure-of-a-plugin",
|
||||
"plugins/integrating-plugin-into-software-catalog",
|
||||
"plugins/integrating-search-into-plugins",
|
||||
"plugins/composability",
|
||||
"plugins/customization",
|
||||
"plugins/analytics",
|
||||
"plugins/feature-flags",
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Backends and APIs",
|
||||
"items": [
|
||||
"plugins/proxying",
|
||||
"plugins/backend-plugin",
|
||||
"plugins/call-existing-api",
|
||||
"plugins/url-reader",
|
||||
"plugins/new-backend-system"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Testing",
|
||||
"items": ["plugins/testing"]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Publishing",
|
||||
"items": [
|
||||
"plugins/publish-private",
|
||||
"plugins/add-to-marketplace",
|
||||
"plugins/observability"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Configuration": [
|
||||
"conf/index",
|
||||
"conf/reading",
|
||||
"conf/writing",
|
||||
"conf/defining"
|
||||
],
|
||||
"Auth and identity": [
|
||||
"auth/index",
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Included providers",
|
||||
"items": [
|
||||
"auth/auth0/provider",
|
||||
"auth/atlassian/provider",
|
||||
"auth/bitbucket/provider",
|
||||
"auth/microsoft/provider",
|
||||
"auth/github/provider",
|
||||
"auth/gitlab/provider",
|
||||
"auth/google/provider",
|
||||
"auth/google/gcp-iap-auth",
|
||||
"auth/okta/provider",
|
||||
"auth/onelogin/provider",
|
||||
"auth/oauth2-proxy/provider"
|
||||
]
|
||||
},
|
||||
"auth/identity-resolver",
|
||||
"auth/oauth",
|
||||
"auth/oidc",
|
||||
"auth/add-auth-provider",
|
||||
"auth/service-to-service-auth",
|
||||
"auth/troubleshooting",
|
||||
"auth/glossary"
|
||||
],
|
||||
"Permissions": [
|
||||
"permissions/overview",
|
||||
"permissions/concepts",
|
||||
"permissions/getting-started",
|
||||
"permissions/writing-a-policy",
|
||||
"permissions/frontend-integration",
|
||||
"permissions/custom-rules",
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Tutorial: using Permissions in your plugin",
|
||||
"items": [
|
||||
"permissions/plugin-authors/01-setup",
|
||||
"permissions/plugin-authors/02-adding-a-basic-permission-check",
|
||||
"permissions/plugin-authors/03-adding-a-resource-permission-check",
|
||||
"permissions/plugin-authors/04-authorizing-access-to-paginated-data",
|
||||
"permissions/plugin-authors/05-frontend-authorization"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Deployment": [
|
||||
"deployment/index",
|
||||
"deployment/scaling",
|
||||
"deployment/docker",
|
||||
"deployment/k8s",
|
||||
"deployment/heroku"
|
||||
],
|
||||
"Designing for Backstage": [
|
||||
"dls/design",
|
||||
"dls/component-design-guidelines",
|
||||
"dls/contributing-to-storybook",
|
||||
"dls/figma"
|
||||
],
|
||||
"API Reference": [
|
||||
{
|
||||
"type": "category",
|
||||
"label": "Guides",
|
||||
"items": ["api/utility-apis"]
|
||||
},
|
||||
{
|
||||
"type": "category",
|
||||
"label": "API Reference",
|
||||
"items": ["reference/index"]
|
||||
},
|
||||
"api/deprecations"
|
||||
],
|
||||
"Tutorials": [
|
||||
"tutorials/journey",
|
||||
"tutorials/quickstart-app-plugin",
|
||||
"tutorials/react-router-stable-migration",
|
||||
"tutorials/package-role-migration",
|
||||
"tutorials/migrating-away-from-core",
|
||||
"tutorials/configuring-plugin-databases",
|
||||
"tutorials/switching-sqlite-postgres",
|
||||
"tutorials/using-backstage-proxy-within-plugin",
|
||||
"tutorials/yarn-migration"
|
||||
],
|
||||
"Architecture Decision Records (ADRs)": [
|
||||
"architecture-decisions/adrs-overview",
|
||||
"architecture-decisions/adrs-adr001",
|
||||
"architecture-decisions/adrs-adr002",
|
||||
"architecture-decisions/adrs-adr003",
|
||||
"architecture-decisions/adrs-adr004",
|
||||
"architecture-decisions/adrs-adr005",
|
||||
"architecture-decisions/adrs-adr006",
|
||||
"architecture-decisions/adrs-adr007",
|
||||
"architecture-decisions/adrs-adr008",
|
||||
"architecture-decisions/adrs-adr009",
|
||||
"architecture-decisions/adrs-adr010",
|
||||
"architecture-decisions/adrs-adr011",
|
||||
"architecture-decisions/adrs-adr012",
|
||||
"architecture-decisions/adrs-adr013"
|
||||
],
|
||||
"FAQ": ["FAQ"]
|
||||
}
|
||||
}
|
||||
|
||||
+129
-5
@@ -3573,6 +3573,7 @@ __metadata:
|
||||
prettier: ^2.6.2
|
||||
react: ^17.0.2
|
||||
react-dom: ^17.0.2
|
||||
replace: ^1.2.2
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@@ -3827,6 +3828,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"camelcase@npm:^5.0.0":
|
||||
version: 5.3.1
|
||||
resolution: "camelcase@npm:5.3.1"
|
||||
checksum: e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"camelcase@npm:^6.2.0":
|
||||
version: 6.3.0
|
||||
resolution: "camelcase@npm:6.3.0"
|
||||
@@ -3860,7 +3868,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:^2.0.0":
|
||||
"chalk@npm:2.4.2, chalk@npm:^2.0.0":
|
||||
version: 2.4.2
|
||||
resolution: "chalk@npm:2.4.2"
|
||||
dependencies:
|
||||
@@ -4021,6 +4029,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cliui@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "cliui@npm:6.0.0"
|
||||
dependencies:
|
||||
string-width: ^4.2.0
|
||||
strip-ansi: ^6.0.0
|
||||
wrap-ansi: ^6.2.0
|
||||
checksum: 4fcfd26d292c9f00238117f39fc797608292ae36bac2168cfee4c85923817d0607fe21b3329a8621e01aedf512c99b7eaa60e363a671ffd378df6649fb48ae42
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"clone-deep@npm:^4.0.1":
|
||||
version: 4.0.1
|
||||
resolution: "clone-deep@npm:4.0.1"
|
||||
@@ -4597,6 +4616,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decamelize@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "decamelize@npm:1.2.0"
|
||||
checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decompress-response@npm:^3.3.0":
|
||||
version: 3.3.0
|
||||
resolution: "decompress-response@npm:3.3.0"
|
||||
@@ -5355,7 +5381,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"find-up@npm:^4.0.0":
|
||||
"find-up@npm:^4.0.0, find-up@npm:^4.1.0":
|
||||
version: 4.1.0
|
||||
resolution: "find-up@npm:4.1.0"
|
||||
dependencies:
|
||||
@@ -5544,6 +5570,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-caller-file@npm:^2.0.1":
|
||||
version: 2.0.5
|
||||
resolution: "get-caller-file@npm:2.0.5"
|
||||
checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1":
|
||||
version: 1.1.3
|
||||
resolution: "get-intrinsic@npm:1.1.3"
|
||||
@@ -6716,11 +6749,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"json5@npm:^2.1.2, json5@npm:^2.2.1":
|
||||
version: 2.2.1
|
||||
resolution: "json5@npm:2.2.1"
|
||||
version: 2.2.3
|
||||
resolution: "json5@npm:2.2.3"
|
||||
bin:
|
||||
json5: lib/cli.js
|
||||
checksum: 74b8a23b102a6f2bf2d224797ae553a75488b5adbaee9c9b6e5ab8b510a2fc6e38f876d4c77dea672d4014a44b2399e15f2051ac2b37b87f74c0c7602003543b
|
||||
checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7164,6 +7197,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:3.0.5":
|
||||
version: 3.0.5
|
||||
resolution: "minimatch@npm:3.0.5"
|
||||
dependencies:
|
||||
brace-expansion: ^1.1.7
|
||||
checksum: a3b84b426eafca947741b864502cee02860c4e7b145de11ad98775cfcf3066fef422583bc0ffce0952ddf4750c1ccf4220b1556430d4ce10139f66247d87d69e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:3.1.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1":
|
||||
version: 3.1.2
|
||||
resolution: "minimatch@npm:3.1.2"
|
||||
@@ -8982,6 +9024,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"replace@npm:^1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "replace@npm:1.2.2"
|
||||
dependencies:
|
||||
chalk: 2.4.2
|
||||
minimatch: 3.0.5
|
||||
yargs: ^15.3.1
|
||||
bin:
|
||||
replace: bin/replace.js
|
||||
search: bin/search.js
|
||||
checksum: 1d69f43937a5fdf9dea278e78d6f3b51c1889ba5135bd201918bbda6330684adf8276e8e90e1c021034420dd4df239e51c23ca40752cb9bc6180c153d6d46a37
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"require-directory@npm:^2.1.1":
|
||||
version: 2.1.1
|
||||
resolution: "require-directory@npm:2.1.1"
|
||||
checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"require-from-string@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "require-from-string@npm:2.0.2"
|
||||
@@ -8996,6 +9059,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"require-main-filename@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "require-main-filename@npm:2.0.0"
|
||||
checksum: e9e294695fea08b076457e9ddff854e81bffbe248ed34c1eec348b7abbd22a0d02e8d75506559e2265e96978f3c4720bd77a6dad84755de8162b357eb6c778c7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"requires-port@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "requires-port@npm:1.0.0"
|
||||
@@ -10623,6 +10693,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"which-module@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "which-module@npm:2.0.0"
|
||||
checksum: 809f7fd3dfcb2cdbe0180b60d68100c88785084f8f9492b0998c051d7a8efe56784492609d3f09ac161635b78ea29219eb1418a98c15ce87d085bce905705c9c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"which@npm:^1.3.1":
|
||||
version: 1.3.1
|
||||
resolution: "which@npm:1.3.1"
|
||||
@@ -10679,6 +10756,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wrap-ansi@npm:^6.2.0":
|
||||
version: 6.2.0
|
||||
resolution: "wrap-ansi@npm:6.2.0"
|
||||
dependencies:
|
||||
ansi-styles: ^4.0.0
|
||||
string-width: ^4.1.0
|
||||
strip-ansi: ^6.0.0
|
||||
checksum: 6cd96a410161ff617b63581a08376f0cb9162375adeb7956e10c8cd397821f7eb2a6de24eb22a0b28401300bf228c86e50617cd568209b5f6775b93c97d2fe3a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wrap-ansi@npm:^7.0.0":
|
||||
version: 7.0.0
|
||||
resolution: "wrap-ansi@npm:7.0.0"
|
||||
@@ -10775,6 +10863,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"y18n@npm:^4.0.0":
|
||||
version: 4.0.3
|
||||
resolution: "y18n@npm:4.0.3"
|
||||
checksum: 014dfcd9b5f4105c3bb397c1c8c6429a9df004aa560964fb36732bfb999bfe83d45ae40aeda5b55d21b1ee53d8291580a32a756a443e064317953f08025b1aa4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yallist@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "yallist@npm:4.0.0"
|
||||
@@ -10789,6 +10884,35 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yargs-parser@npm:^18.1.2":
|
||||
version: 18.1.3
|
||||
resolution: "yargs-parser@npm:18.1.3"
|
||||
dependencies:
|
||||
camelcase: ^5.0.0
|
||||
decamelize: ^1.2.0
|
||||
checksum: 60e8c7d1b85814594d3719300ecad4e6ae3796748b0926137bfec1f3042581b8646d67e83c6fc80a692ef08b8390f21ddcacb9464476c39bbdf52e34961dd4d9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yargs@npm:^15.3.1":
|
||||
version: 15.4.1
|
||||
resolution: "yargs@npm:15.4.1"
|
||||
dependencies:
|
||||
cliui: ^6.0.0
|
||||
decamelize: ^1.2.0
|
||||
find-up: ^4.1.0
|
||||
get-caller-file: ^2.0.1
|
||||
require-directory: ^2.1.1
|
||||
require-main-filename: ^2.0.0
|
||||
set-blocking: ^2.0.0
|
||||
string-width: ^4.2.0
|
||||
which-module: ^2.0.0
|
||||
y18n: ^4.0.0
|
||||
yargs-parser: ^18.1.2
|
||||
checksum: 40b974f508d8aed28598087720e086ecd32a5fd3e945e95ea4457da04ee9bdb8bdd17fd91acff36dc5b7f0595a735929c514c40c402416bbb87c03f6fb782373
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"yocto-queue@npm:^0.1.0":
|
||||
version: 0.1.0
|
||||
resolution: "yocto-queue@npm:0.1.0"
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: Backstage Wrapped 2022
|
||||
author: Francesco Corti & Suzanne Daniels
|
||||
authorURL: https://github.com/fcorti
|
||||
---
|
||||
|
||||

|
||||
|
||||
If 2021 was the year of growth for the Backstage project and community, 2022 can be easily defined as the year of maturity. Both the project and the community continued to grow at an incredible pace and the platform is now more stable, more secure, and more powerful than ever.
|
||||
|
||||
Our community is full of people from across the globe who bring incredible engagement and positive vibes to the project. And we finally got to experience this for the first time in real life during [BackstageCon](https://www.youtube.com/playlist?list=PLj6h78yzYM2OKySsTuiip3BqmdYZQRnSf), the very first in-person conference fully dedicated to Backstage, where hundreds of enthusiasts, the maintainers, adopters, and partners joined the event confirming the great momentum and the traction in the market.
|
||||
|
||||
But before anticipating too much, let’s share some stats of this amazing 2022.
|
||||
|
||||
<!--truncate-->
|
||||
|
||||
## We grew … a lot!
|
||||
|
||||
Last year we celebrated 75 [public adopters](https://github.com/backstage/backstage/blob/master/ADOPTERS.md) and today we have over 600 adopters, confirming the interest around Backstage across all the industries, sectors, and dimensions. Companies like [Toyota North America](https://aws.amazon.com/solutions/case-studies/toyota-ecs-case-study/), Deutsche Bank, Mercedes-Benz, Procter & Gamble, Siemens, LinkedIn, and many more joined the community this year and are actively contributing in growing the product and its maturity.
|
||||
|
||||

|
||||
|
||||
Not only are our adopters growing at an exponential rate, but so too are our contributors. Our [Discord server](https://discord.gg/backstage-687207715902193673) is a perfect example of the worlds of our adopters and contributors melding. On average, at any given hour of the day or night, there are more than 500 people online available to talk and provide support on any Backstage topic. Discord discussions run a full gamut of topics – from technical support questions to best practices for onboarding engineers to Backstage – basically, anything and everything an adopter may be interested to know and learn. At the very beginning of 2022, we “only” had 4k Discord members. Today, we have a growing membership of 8.2k.
|
||||
|
||||
Isn’t it what we can call a great and vibrant community of enthusiasts?
|
||||
|
||||
The growth of the ecosystem is not limited to the adopters and contributors. The ecosystem also includes big tech companies interested in growing Backstage by including it as part of their offering and integrations. Our [collaboration with VMWare](https://youtube.com/watch?v=GAzKCQO8Vt0&si=EnSIkaIECMiOmarE) is a great example of this, and [RedHat](https://developers.redhat.com/articles/2022/10/24/red-hat-joins-backstageio-community) joined the party this year – promising even faster growth in contributions and integrations for the Backstage project.
|
||||
|
||||
Before we go any further, let’s take a quick look at some more numbers, mainly coming from the [Official Github repository](https://github.com/backstage/backstage). This year…
|
||||
|
||||
- Our contributors grew from a group of 500 to 900+
|
||||
- Contributions to the project increased from 9k to 15k+
|
||||
- The number of forks shot up from 2k to 3k+
|
||||
- Backstage stars increased from 14k to almost 20k
|
||||
- And lastly, we welcomed over 550 adopters into our community.
|
||||
|
||||
All of these people driving the enormous growth and maturity of the project are represented in the chart below, which shows cumulative activities per month for Backstage:
|
||||
|
||||

|
||||
|
||||
Wow… that’s a lot of activity. We’ve generated this animation showing all of your contributions to the Backstage repository in 2022, look at this project grow:
|
||||
|
||||
<iframe width="780" height="440" src="https://www.youtube.com/embed/GoWBvHpH5Cg" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>
|
||||
|
||||
## But wait… there’s more
|
||||
|
||||
The growth of the community is so exciting to see. And with all this community growth, comes growth and maturity of the product, making Backstage better able to support adopters in their developer experience challenges. The Backstage open source project has almost [100 plugins](https://backstage.io/plugins), each one amending Backstage with a tool or service to improve not only adopters’ Backstage apps, but their unique developer experiences. And almost every week we learn of a new one being contributed, which is amazing.
|
||||
|
||||
The Backstage platform itself is leaving 2022 more mature than ever, thanks to milestones such as these:
|
||||
|
||||
- [Backstage is now beyond version 1](https://backstage.io/blog/2022/03/17/backstage-1.0).
|
||||
- [Backstage had its first Security Audit ever and now can rely on a Threat Model](https://backstage.io/blog/2022/08/23/backstage-security-audit).
|
||||
- [Backstage Learn helps adopters get started more easily](https://backstage.spotify.com/learn/).
|
||||
- [Backstage reached incubating status as part of the CNCF ecosystem](https://www.cncf.io/blog/2022/03/15/backstage-project-joins-the-cncf-incubator/).
|
||||
|
||||
And like every mature project, now Backstage has also a mascot: Bowie the Beaver!
|
||||
|
||||

|
||||
|
||||
Additionally, we launched a new [Special Interest Groups (SIGs)](https://github.com/backstage/community/tree/main/sigs) initiative this year, following the lead of Kubernetes. We believe Backstage SIGs will better coordinate contributions, grow the platform cohesively with the open source community, and allow contributors to dig even deeper as a community member. At this moment in time there two SIGs in place:
|
||||
|
||||
- The [Catalog SIG](https://github.com/backstage/community/blob/main/sigs/sig-catalog/README.md), covering all aspects of the systems and components related to the Software Catalog.
|
||||
- The [Adoption SIG](https://github.com/backstage/community/blob/main/sigs/sig-adoption/README.md), covering all aspects of the adoption journey of Backstage.
|
||||
|
||||
Our plan is to open more SIGs in 2023 to engage more with the community and to keep driving towards cohesive growth for the community and project.
|
||||
|
||||
Last but not least, we mustn't overlook the first ever conference fully dedicated to Backstage: BackstageCon. What was special there? SO much. But in particular two things: seeing everyone in real life and the incredible mood and conversations between maintainers, adopters, partners and enthusiasts. It’s hard to express just how positive and amazing the vibes were in a blog, but you can read our recap [here](https://backstage.io/blog/2022/10/28/backstagecon-kubecon-2022) or watch the sessions [here](https://www.youtube.com/playlist?list=PLj6h78yzYM2OKySsTuiip3BqmdYZQRnSf). And in the meantime, here are some great numbers from the event:
|
||||
|
||||
- 250 attendees or a 100% full venue and packed room.
|
||||
- 14 sessions
|
||||
- 17 speakers
|
||||
|
||||
## Goodbye, 2022. Hello, 2023!
|
||||
|
||||
After this incredible year, thanks to everyone in the global Backstage community who contributed to the open source project in 2022. We are already working on the goals for 2023 – and as a roadmap teaser: we are very much committed to making the journey of adoption easier, faster, more valuable, and overall better. We would not be here today without our amazing community, so thank you for everything!
|
||||
|
||||
Looking forward to continuing collaborating together for an exciting 2023.
|
||||
|
||||
See you then! Happy holidays from everyone on the Backstage team at Spotify!
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 490 KiB |
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: AWS CodeSuite
|
||||
author: Amazon Web Services
|
||||
authorUrl: https://aws.amazon.com/
|
||||
category: CI/CD
|
||||
description: View resources related to AWS CodePipeline, AWS CodeBuild and AWS CodeDeploy for your components in Backstage.
|
||||
documentation: https://github.com/awslabs/aws-codesuite-plugins-for-backstage#readme
|
||||
iconUrl: https://github.com/awslabs/aws-codesuite-plugins-for-backstage/blob/main/docs/images/codepipeline-logo.png?raw=true
|
||||
npmPackageName: '@aws/aws-codesuite-plugin-for-backstage'
|
||||
addedDate: '2023-01-17'
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user