Merge branch 'master' of github.com:jonathan-ash/backstage into techdocs-reader-custom-error-page

This commit is contained in:
Jonathan Ash
2022-02-15 12:12:19 +00:00
803 changed files with 24437 additions and 7307 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs-backend': patch
---
Do not use cross-fetch in the backend
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
The `versions:bump --release next` command is updated to compare the `main` and `next` release manifests and prefer the latest.
+13
View File
@@ -0,0 +1,13 @@
---
'@backstage/plugin-catalog-backend': patch
---
The following processors now properly accept an `ScmIntegrationRegistry` (an
interface) instead of an `ScmIntegrations` (which is a concrete class).
- `AzureDevOpsDiscoveryProcessor`
- `CodeOwnersProcessor`
- `GitLabDiscoveryProcessor`
- `GithubDiscoveryProcessor`
- `GithubMultiOrgReaderProcessor`
- `GithubOrgReaderProcessor`
-27
View File
@@ -1,27 +0,0 @@
---
'@backstage/plugin-auth-backend': minor
---
**BREAKING** Added `tokenManager` as a required property for the auth-backend `createRouter` function. This dependency is used to issue server tokens that are used by the `CatalogIdentityClient` when looking up users and their group membership during authentication.
These changes are **required** to `packages/backend/src/plugins/auth.ts`:
```diff
export default async function createPlugin({
logger,
database,
config,
discovery,
+ tokenManager,
}: PluginEnvironment): Promise<Router> {
return await createRouter({
logger,
config,
database,
discovery,
+ tokenManager,
});
}
```
**BREAKING** The `CatalogIdentityClient` constructor now expects a `TokenManager` instead of a `TokenIssuer`. The `TokenManager` interface is used to generate a server token when [resolving a user's identity and membership through the catalog](https://backstage.io/docs/auth/identity-resolver). Using server tokens for these requests allows the auth-backend to bypass authorization checks when permissions are enabled for Backstage. This change will break apps that rely on the user tokens that were previously used by the client. Refer to the ["Backend-to-backend Authentication" tutorial](https://backstage.io/docs/tutorials/backend-to-backend-auth) for more information on server token usage.
+24
View File
@@ -0,0 +1,24 @@
---
'@backstage/create-app': patch
---
Remove SearchContextProvider from `<Root />`
The `SidebarSearchModal` exported from `plugin-search` internally renders `SearchContextProvider`, so it can be removed from `Root.tsx`:
```diff
-import {
- SidebarSearchModal,
- SearchContextProvider,
-} from '@backstage/plugin-search';
+import { SidebarSearchModal } from '@backstage/plugin-search';
... omitted ...
<SidebarGroup label="Search" icon={<SearchIcon />} to="/search">
- <SearchContextProvider>
- <SidebarSearchModal />
- </SearchContextProvider>
+ <SidebarSearchModal />
</SidebarGroup>
```
+78
View File
@@ -0,0 +1,78 @@
---
'@backstage/backend-common': patch
'@backstage/catalog-client': patch
'@backstage/cli': patch
'@backstage/config-loader': patch
'@backstage/core-app-api': patch
'@backstage/core-components': patch
'@backstage/core-plugin-api': patch
'@backstage/errors': patch
'@backstage/integration': patch
'@backstage/integration-react': patch
'@backstage/release-manifests': patch
'@backstage/test-utils': patch
'@backstage/plugin-airbrake': patch
'@backstage/plugin-allure': patch
'@backstage/plugin-analytics-module-ga': patch
'@backstage/plugin-apache-airflow': patch
'@backstage/plugin-api-docs': patch
'@backstage/plugin-auth-backend': patch
'@backstage/plugin-auth-node': patch
'@backstage/plugin-azure-devops': patch
'@backstage/plugin-badges': patch
'@backstage/plugin-bazaar': patch
'@backstage/plugin-bitrise': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-catalog-graphql': patch
'@backstage/plugin-catalog-import': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-circleci': patch
'@backstage/plugin-cloudbuild': patch
'@backstage/plugin-code-coverage': patch
'@backstage/plugin-config-schema': patch
'@backstage/plugin-cost-insights': patch
'@backstage/plugin-explore': patch
'@backstage/plugin-explore-react': patch
'@backstage/plugin-firehydrant': patch
'@backstage/plugin-fossa': patch
'@backstage/plugin-gcp-projects': patch
'@backstage/plugin-git-release-manager': patch
'@backstage/plugin-github-actions': patch
'@backstage/plugin-github-deployments': patch
'@backstage/plugin-gitops-profiles': patch
'@backstage/plugin-gocd': patch
'@backstage/plugin-graphiql': patch
'@backstage/plugin-home': patch
'@backstage/plugin-ilert': patch
'@backstage/plugin-jenkins': patch
'@backstage/plugin-kafka': patch
'@backstage/plugin-kubernetes': patch
'@backstage/plugin-lighthouse': patch
'@backstage/plugin-newrelic': patch
'@backstage/plugin-newrelic-dashboard': patch
'@backstage/plugin-org': patch
'@backstage/plugin-pagerduty': patch
'@backstage/plugin-permission-backend': patch
'@backstage/plugin-permission-common': patch
'@backstage/plugin-permission-react': patch
'@backstage/plugin-rollbar': patch
'@backstage/plugin-rollbar-backend': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-search': patch
'@backstage/plugin-sentry': patch
'@backstage/plugin-shortcuts': patch
'@backstage/plugin-sonarqube': patch
'@backstage/plugin-splunk-on-call': patch
'@backstage/plugin-tech-insights': patch
'@backstage/plugin-tech-radar': patch
'@backstage/plugin-techdocs': patch
'@backstage/plugin-techdocs-backend': patch
'@backstage/plugin-todo': patch
'@backstage/plugin-user-settings': patch
'@backstage/plugin-xcmetrics': patch
---
Bump `node-fetch` to version 2.6.7 and `cross-fetch` to version 3.1.5
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Fix error handling of the `runCommand` helper to return `Error`
instance.
+11
View File
@@ -0,0 +1,11 @@
---
'@backstage/plugin-catalog': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-graph': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-org': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-tech-insights-backend': patch
---
Use updated type names from `@backstage/catalog-client`
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/catalog-model': patch
---
Deprecated `parseLocationReference` and `stringifyLocationReference`,
introducing `parseLocationRef` and `stringifyLocationRef` in their place.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-model': patch
---
Deprecates the `Location` type export from this package. Imports of the `Location` type should now be done from the `@backstage/catalog-client` package instead.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search-backend-module-elasticsearch': patch
---
chore(deps-dev): bump `@elastic/elasticsearch-mock` from 0.3.0 to 1.0.0
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend': patch
---
chore(deps): bump `prom-client` from 13.2.0 to 14.0.1
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-todo-backend': patch
---
Replace usage of `serializeEntityRef` with `stringifyEntityRef`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Support "dependencyOf" relation in Resource entities
@@ -2,4 +2,4 @@
'@backstage/plugin-auth-backend': patch
---
chore(deps): bump `passport` from 0.4.1 to 0.5.2
Bump `passport-oauth2` to version 1.6.1
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-catalog': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-catalog-backend-module-ldap': patch
---
Import `Location` from the `@backstage/catalog-client` package.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-components': patch
---
Change subtitle of Header style to use palette.bursts.fontColor
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
The `versions:bump` command now filters out `npm_` environment configuration when running `yarn install`. This has the effect of allowing it to consider local configuration files within the repository, which is the behavior that one would expect.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/core-components': patch
---
Fix an issue where changes related to the `MobileSidebar` prevented scrolling pages. Additionally improve the menu of the `MobileSidebar` to not overlay the `BottomNavigation`.
+22
View File
@@ -0,0 +1,22 @@
---
'@backstage/plugin-permission-backend': minor
---
Add a warning if the permission backend is used without setting `permission.enabled=true`.
**BREAKING** Permission backend's `createRouter` now requires a `config` option.
```diff
// packages/backend/src/plugins/permission.ts
...
export default async function createPlugin({
...
+ config,
}: PluginEnvironment) {
return createRouter({
...
+ config,
});
}
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-permission-common': minor
---
**BREAKING** `PermissionCriteria` now requires at least one condition in `anyOf` and `allOf` arrays. This addresses some ambiguous behavior outlined in #9280.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs-backend': patch
---
Fix bug where tech docs collator stores search indices with wrong entity ref casing. Make the collator to conform legacyPathCasing configuration option.
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/catalog-client': minor
---
**BREAKING**: Removed the explicit `DiscoveryApi` and `FetchApi` export symbols,
which were unnecessary duplicates from the well known core ones.
The `CATALOG_FILTER_EXISTS` symbol's value has changed. However, this should not
affect any code in practice.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Update internal `Location` validation.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
The `versions:bump` command now also considers the root `package.json` when searching for updates. It has also received updates to its output, including a link the [Backstage upgrade helper](https://backstage.github.io/upgrade-helper) and silenced `yarn install` output.
+11
View File
@@ -0,0 +1,11 @@
---
'@backstage/catalog-client': patch
'@backstage/techdocs-common': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-github-deployments': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-todo-backend': patch
---
Updated to use new names for `parseLocationRef` and `stringifyLocationRef`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cicd-statistics': patch
---
Updated `@backstage/core-plugin-api` dependency.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-org': patch
---
Added `relations.memberof` filter to the catalog api call in `MemberListCard` to avoid fetching all the User entity kinds from catalog-backend.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/catalog-model': minor
---
**BREAKING**: Remove deprecated validation methods `analyzeLocationSchema`, `locationSchema` and `locationSpecSchema`.
This functionality was primarily used internally by the `catalog-backend`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-permission-node': minor
---
**BREAKING** `PermissionCriteria` now requires at least one condition in `anyOf` and `allOf` arrays. This addresses some ambiguous behavior outlined in #9280.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': minor
---
**BREAKING** Completely removed the `EntitySystemDiagramCard` component which was deprecated in a previous release. Any remaining references to this component are now broken and should be replaced with `EntityCatalogGraphCard`, which can be imported from package `@backstage/plugin-catalog-graph`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-model': minor
---
**BREAKING**: Remove deprecated `serializeEntityRef` which is replaced by `stringifyEntityRef`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-yeoman': patch
---
Bump `yeoman-environment` dependency from `^3.6.0` to `^3.9.1`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-client': patch
---
Export the `Location` type that was previously exported by the `@backstage/catalog-model` package.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/integration-react': patch
---
Updated the `ScmAuth` error message for missing provider configurations to link to `ScmAuthApi` setup documentation.
-5
View File
@@ -1,5 +0,0 @@
---
'@techdocs/cli': patch
---
Use a local file dependency for embedded-techdocs-app, to ensure that it's always pulled out of the workspace
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
Improve overall appearance of highlighted code in docs.
-25
View File
@@ -1,25 +0,0 @@
---
'@backstage/create-app': patch
---
Added `tokenManager` as a required property for the auth-backend `createRouter` function. This dependency is used to issue server tokens that are used by the `CatalogIdentityClient` when looking up users and their group membership during authentication.
These changes are **required** to `packages/backend/src/plugins/auth.ts`:
```diff
export default async function createPlugin({
logger,
database,
config,
discovery,
+ tokenManager,
}: PluginEnvironment): Promise<Router> {
return await createRouter({
logger,
config,
database,
discovery,
+ tokenManager,
});
}
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': patch
---
Updated `isDatabaseConflictError` to handle modern sqlite conflict errors
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-model': patch
---
Deprecates the following exports which all have very limited and internal use. `ENTITY_META_GENERATED_FIELDS`, `entityHasChanges`, `generateEntityEtag`, `generateEntityUid`, `generateUpdatedEntity`, `ENTITY_META_GENERATED_FIELDS`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Updated the default [sucrase](https://github.com/alangpierce/sucrase)-based Jest transform to include source maps if the environment variable `ENABLE_SOURCE_MAPS` is non-empty. This can be used to better support editor test debugging integrations.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-pagerduty': patch
---
Fix change events tab error when change events exist
-34
View File
@@ -1,34 +0,0 @@
---
'@backstage/plugin-catalog-import': minor
---
Make filename, branch name and examples URLs used in catalog import customizable.
Catalog backend ingestion loop can be already configured to fetch targets with custom catalog filename (other than `catalog-info.yaml`). It's now possible to customize said filename and branch name used in pull requests created by catalog import flow too. This allows organizations to further customize Backstage experience and to better reflect their branding.
Filename (default: `catalog-info.yaml`) and branch name (default: `backstage-integration`) used in pull requests can be configured in `app-config.yaml` as follows:
```yaml
// app-config.yaml
catalog:
import:
entityFilename: anvil.yaml
pullRequestBranchName: anvil-integration
```
Following React components have also been updated to accept optional props for providing example entity and repository paths:
```tsx
<StepInitAnalyzeUrl
...
exampleLocationUrl="https://github.com/acme-corp/our-awesome-api/blob/main/anvil.yaml"
/>
```
```tsx
<ImportInfoCard
exampleLocationUrl="https://github.com/acme-corp/our-awesome-api/blob/main/anvil.yaml"
exampleRepositoryUrl="https://github.com/acme-corp/our-awesome-api"
/>
```
+11
View File
@@ -0,0 +1,11 @@
---
'@backstage/catalog-client': patch
---
Deprecated the following types used by the catalog client, and created new
corresponding types to make them more consistent:
- `CatalogEntitiesRequest` -> `GetEntitiesRequest`
- `CatalogListResponse` was removed and generally replaced with `GetEntitiesResponse` (which does not use a type parameter argument)
- `CatalogEntityAncestorsRequest`-> `GetEntityAncestorsRequest`
- `CatalogEntityAncestorsResponse` -> `GetEntityAncestorsResponse`
+14
View File
@@ -0,0 +1,14 @@
---
'@backstage/catalog-client': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-backend-module-ldap': patch
'@backstage/plugin-catalog-backend-module-msgraph': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-github-deployments': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-todo': patch
'@backstage/plugin-todo-backend': patch
---
Replaces use of deprecated catalog-model constants.
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-catalog-backend': patch
---
Pass authorization token to location service inside location api routes
+18
View File
@@ -0,0 +1,18 @@
---
'@backstage/plugin-search': minor
---
**BREAKING**: `useSearch` doesn't return anymore `open` and `toggleModal`.
The two properties have been moved to the `useSearchModal` hook.
```
import { SearchModal, useSearchModal } from '@backstage/plugin-search';
const Foo = () => {
const { state, setOpen, toggleModal } = useSearchModal();
return (
<SearchModal {...state} toggleModal={toggleModal} />
);
};
```
-6
View File
@@ -1,6 +0,0 @@
---
'@backstage/core-components': patch
'@backstage/plugin-scaffolder': patch
---
Make linkTarget configurable for MarkdownContent component
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Optimized entity provider mutations with large numbers of new additions, such as big initial startup commits
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/catalog-model': patch
---
Deprecates `EDIT_URL_ANNOTATION`, `LOCATION_ANNOTATION`, `ORIGIN_LOCATION_ANNOTATION`, `SOURCE_LOCATION_ANNOTATION`, `VIEW_URL_ANNOTATION`
and replaces these constants all prefixed with ANNOTATION\_ `ANNOTATION_EDIT_URL`, `ANNOTATION_LOCATION`, `ANNOTATION_ORIGIN_LOCATION`, `ANNOTATION_SOURCE_LOCATION`, `ANNOTATION_VIEW_URL`
-13
View File
@@ -1,13 +0,0 @@
---
'@backstage/create-app': patch
---
Switched the `app` dependency in the backend to use a file target rather than version.
To apply this change to an existing app, make the following change to `packages/backend/package.json`:
```diff
"dependencies": {
- "app": "0.0.0",
+ "app": "file:../app",
```
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/cli': patch
---
Log warning if unable to parse yarn.lock
+47 -40
View File
@@ -4,43 +4,50 @@
# The last matching pattern takes precedence.
# https://help.github.com/articles/about-codeowners/
* @backstage/reviewers
/docs/features/techdocs @backstage/techdocs-core
/docs/features/search @backstage/techdocs-core
/docs/assets/search @backstage/techdocs-core
/plugins/allure @backstage/reviewers @deepak-bhardwaj-ps
/plugins/circleci @backstage/reviewers @adamdmharvey
/plugins/code-coverage @backstage/reviewers @alde @nissayeva
/plugins/code-coverage-backend @backstage/reviewers @alde @nissayeva
/plugins/cost-insights @backstage/silver-lining
/plugins/cloudbuild @backstage/reviewers @trivago/ebarrios
/plugins/search @backstage/techdocs-core
/plugins/search-* @backstage/techdocs-core
/plugins/techdocs @backstage/techdocs-core
/plugins/techdocs-backend @backstage/techdocs-core
/plugins/ilert @backstage/reviewers @yacut
/plugins/home @backstage/techdocs-core
/plugins/azure-devops @backstage/reviewers @marleypowell @awanlin
/plugins/azure-devops-backend @backstage/reviewers @marleypowell @awanlin
/plugins/azure-devops-common @backstage/reviewers @marleypowell @awanlin
/plugins/jenkins @backstage/reviewers @timja
/plugins/jenkins-backend @backstage/reviewers @timja
/plugins/kafka @backstage/reviewers @nirga
/plugins/kafka-backend @backstage/reviewers @nirga
/plugins/scaffolder-backend-module-yeoman @backstage/reviewers @pawelmitka
/plugins/scaffolder-backend-module-rails @backstage/reviewers @angeliski
/plugins/git-release-manager @backstage/reviewers @erikengervall
/tech-insights-backend @backstage/reviewers @xantier @iain-b
/tech-insights-backend-module-jsonfc @backstage/reviewers @xantier @iain-b
/tech-insights-tech-insights-common @backstage/reviewers @xantier @iain-b
/tech-insights-tech-insights-node @backstage/reviewers @xantier @iain-b
/packages/embedded-techdocs-app @backstage/techdocs-core
/packages/search-common @backstage/techdocs-core
/packages/techdocs-cli @backstage/techdocs-core
/packages/techdocs-common @backstage/techdocs-core
/.changeset/cost-insights-* @backstage/reviewers @backstage/silver-lining
/.changeset/search-* @backstage/techdocs-core
/.changeset/techdocs-* @backstage/techdocs-core
/cypress/src/integration/plugins/techdocs.spec.ts @backstage/techdocs-core
/plugins/apache-airflow @backstage/reviewers @cmpadden
/plugins/newrelic-dashboard @backstage/reviewers @mufaddal7
* @backstage/reviewers
/.changeset/cost-insights-* @backstage/reviewers @backstage/silver-lining
/.changeset/search-* @backstage/reviewers @backstage/techdocs-core
/.changeset/techdocs-* @backstage/reviewers @backstage/techdocs-core
/cypress/src/integration/plugins/techdocs.spec.ts @backstage/reviewers @backstage/techdocs-core
/docs/assets/search @backstage/reviewers @backstage/techdocs-core
/docs/features/search @backstage/reviewers @backstage/techdocs-core
/docs/features/techdocs @backstage/reviewers @backstage/techdocs-core
/packages/search-common @backstage/reviewers @backstage/techdocs-core
/packages/techdocs-cli @backstage/reviewers @backstage/techdocs-core
/packages/techdocs-cli-embedded-app @backstage/reviewers @backstage/techdocs-core
/packages/techdocs-common @backstage/reviewers @backstage/techdocs-core
/plugins/allure @backstage/reviewers @deepak-bhardwaj-ps
/plugins/apache-airflow @backstage/reviewers @cmpadden
/plugins/api-docs @backstage/reviewers @backstage/sda-se-reviewers
/plugins/azure-devops @backstage/reviewers @marleypowell @awanlin
/plugins/azure-devops-backend @backstage/reviewers @marleypowell @awanlin
/plugins/azure-devops-common @backstage/reviewers @marleypowell @awanlin
/plugins/bitrise @backstage/reviewers @backstage/sda-se-reviewers
/plugins/catalog-graph @backstage/reviewers @backstage/sda-se-reviewers
/plugins/circleci @backstage/reviewers @adamdmharvey
/plugins/cloudbuild @backstage/reviewers @trivago/ebarrios
/plugins/code-coverage @backstage/reviewers @alde @nissayeva
/plugins/code-coverage-backend @backstage/reviewers @alde @nissayeva
/plugins/cost-insights @backstage/reviewers @backstage/silver-lining
/plugins/explore @backstage/reviewers @backstage/sda-se-reviewers
/plugins/explore-react @backstage/reviewers @backstage/sda-se-reviewers
/plugins/fossa @backstage/reviewers @backstage/sda-se-reviewers
/plugins/git-release-manager @backstage/reviewers @erikengervall
/plugins/home @backstage/reviewers @backstage/techdocs-core
/plugins/ilert @backstage/reviewers @yacut
/plugins/jenkins @backstage/reviewers @timja
/plugins/jenkins-backend @backstage/reviewers @timja
/plugins/kafka @backstage/reviewers @nirga
/plugins/kafka-backend @backstage/reviewers @nirga
/plugins/newrelic-dashboard @backstage/reviewers @mufaddal7
/plugins/scaffolder-backend-module-rails @backstage/reviewers @angeliski
/plugins/scaffolder-backend-module-yeoman @backstage/reviewers @pawelmitka
/plugins/search @backstage/reviewers @backstage/techdocs-core
/plugins/search-* @backstage/reviewers @backstage/techdocs-core
/plugins/sonarqube @backstage/reviewers @backstage/sda-se-reviewers
/plugins/techdocs @backstage/reviewers @backstage/techdocs-core
/plugins/techdocs-backend @backstage/reviewers @backstage/techdocs-core
/tech-insights-backend @backstage/reviewers @xantier @iain-b
/tech-insights-backend-module-jsonfc @backstage/reviewers @xantier @iain-b
/tech-insights-tech-insights-common @backstage/reviewers @xantier @iain-b
/tech-insights-tech-insights-node @backstage/reviewers @xantier @iain-b
+11 -12
View File
@@ -4,20 +4,17 @@ about: 'Create Bug Report'
labels: bug
---
<!--- Provide a general summary of the issue in the Title above -->
<!---
Please use this template when reporting bugs. Thank you!
-->
## Expected Behavior
<!--- Tell us what should happen -->
## Current Behavior
## Actual Behavior
<!--- Tell us what happens instead of the expected behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas as to the implementation of the addition or change -->
<!--- Tell us what happens instead -->
## Steps to Reproduce
@@ -38,8 +35,10 @@ labels: bug
<!--- Include as many relevant details about the environment you experienced the bug in -->
<!-- ProTip: You can use `yarn backstage-cli info` command in your Backstage App for this section. -->
- Browser Information: <!--- For example Google Chrome 97.0.4692.99 -->
- NodeJS Version (v14):
- Operating System and Version (e.g. Ubuntu 14.04):
- Browser Information:
- Output of `yarn backstage-cli info`: <!--- Paste into the code block below -->
```text
```
+12
View File
@@ -0,0 +1,12 @@
---
blank_issues_enabled: false
contact_links:
- about: 'Please ask and answer usage questions in GitHub Discussions'
name: Question
url: 'https://github.com/backstage/backstage/discussions'
- about: 'Alternatively, you can use the Backstage Community Discord'
name: Chat
url: 'https://discord.gg/MUpMjP2'
- about: 'Please check the FAQ before filing new issues'
name: 'Backstage FAQ'
url: 'https://backstage.io/docs/FAQ'
+4 -1
View File
@@ -28,6 +28,7 @@ Blackbox
bool
boolean
builtins
callout
Chai
changeset
changesets
@@ -223,6 +224,7 @@ productional
Protobuf
proxying
Proxying
pseudonymized
pubsub
pygments
pymdownx
@@ -314,6 +316,7 @@ unbreak
Unconference
unmanaged
unregister
unregistering
unregistration
untracked
upsert
@@ -337,4 +340,4 @@ Zalando
Zhou
zoomable
zsh
Alef
Alef
@@ -1,57 +0,0 @@
name: Automate TechDocs project board
# Development of TechDocs in Backstage is managed by this Kanban board - https://github.com/orgs/backstage/projects/1
# New issues and PRs with TechDocs in their title or docs-like-code label will be added to the board.
# Caveat: New PRs created from forks will not be added since GitHub Actions don't share credentials with forks.
on:
issues:
types: [opened, reopened, labeled, edited]
pull_request:
types: [opened, reopened, labeled, edited]
jobs:
assign_issue_or_pr_to_project:
runs-on: ubuntu-latest
name: Triage
env:
MY_GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
steps:
- name: Assign new issue to Incoming based on its title.
uses: srggrs/assign-one-project-github-action@1.2.0
if: |
env.MY_GITHUB_TOKEN != null &&
contains(github.event.issue.title, 'TechDocs') ||
contains(github.event.issue.title, 'techdocs') ||
contains(github.event.issue.title, 'Techdocs')
with:
project: 'https://github.com/orgs/backstage/projects/1'
column_name: 'Incoming'
- name: Assign new issue to Incoming based on its label.
uses: srggrs/assign-one-project-github-action@1.2.0
if: |
env.MY_GITHUB_TOKEN != null &&
contains(github.event.issue.labels.*.name, 'docs-like-code')
with:
project: 'https://github.com/orgs/backstage/projects/1'
column_name: 'Incoming'
- name: Assign new PR to Incoming based on its title.
uses: srggrs/assign-one-project-github-action@1.2.0
if: |
env.MY_GITHUB_TOKEN != null &&
contains(github.event.pull_request.title, 'TechDocs') ||
contains(github.event.pull_request.title, 'techdocs') ||
contains(github.event.pull_request.title, 'Techdocs')
with:
project: 'https://github.com/orgs/backstage/projects/1'
column_name: 'Incoming'
- name: Assign new PR to Incoming based on its label.
uses: srggrs/assign-one-project-github-action@1.2.0
if: |
env.MY_GITHUB_TOKEN != null &&
contains(github.event.pull_request.labels.*.name, 'docs-like-code')
with:
project: 'https://github.com/orgs/backstage/projects/1'
column_name: 'Incoming'
+3 -2
View File
@@ -3,7 +3,7 @@ name: Deploy Packages
on:
workflow_dispatch:
push:
branches: [master, release-*-patch]
branches: [master, patch/*]
jobs:
build:
@@ -123,6 +123,7 @@ jobs:
bash <(curl -s https://codecov.io/bash) -f packages/core-components/coverage/* -F core-components
bash <(curl -s https://codecov.io/bash) -f packages/core-plugin-api/coverage/* -F core-plugin-api
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
@@ -204,7 +205,7 @@ jobs:
# Grabs the version in the root package.json and creates a tag on GitHub
- name: Create a release tag
id: create_tag
run: node scripts/create-release-tag.js
run: node scripts/create-release-tag.js --dispatch-workflows
env:
GITHUB_TOKEN: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
@@ -48,3 +48,31 @@ jobs:
git add .
git commit -am "${{ github.event.inputs.version }}"
git push
- name: Dispatch update-helper update
uses: actions/github-script@v5
with:
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
# TODO(Rugvip): Remove the create-app dispatch once we've been on the release version for a while
script: |
console.log('Dispatching upgrade helper sync - release version');
await github.rest.actions.createWorkflowDispatch({
owner: 'backstage',
repo: 'upgrade-helper-diff',
workflow_id: 'release.yml',
ref: 'master',
inputs: {
version: require('./backstage/package.json').version,
},
});
console.log('Dispatching upgrade helper sync - create-app version');
await github.rest.actions.createWorkflowDispatch({
owner: 'backstage',
repo: 'upgrade-helper-diff',
workflow_id: 'release.yml',
ref: 'master',
inputs: {
version: require('./backstage/packages/create-app/package.json').version,
},
});
+65
View File
@@ -0,0 +1,65 @@
name: Verify DCO
on:
schedule:
- cron: '*/15 * * * *'
jobs:
dco-helper:
runs-on: ubuntu-latest
steps:
- name: Verify DCO status for open pull requests
uses: actions/github-script@v5
with:
script: |
const owner = "backstage";
const repo = "backstage";
const pulls = await github.paginate(github.rest.pulls.list, {
state: "open",
owner,
repo,
});
for (const pull of pulls) {
// Pick out the PRs that have the DCO check
const checks = await github.rest.checks.listForRef({
owner,
repo,
ref: pull.head.sha,
check_name: "DCO",
status: "completed",
});
// Skip if there are no checks
if (!checks.data.check_runs.length) {
continue;
}
// Skip if the conclusion is not action_required
if (checks.data.check_runs[0].conclusion !== "action_required") {
console.log(`No checks found for PR #${pull.number}, skipping`);
continue;
}
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: pull.number,
});
if (comments.find((c) =>
c.user.login === "github-actions[bot]" &&
c.body.includes("<!-- dco -->")
)
) {
console.log(`already commented on PR #${pull.number}, skipping`);
continue;
}
console.log(`creating comment on PR #${pull.number}`);
const body = `
Thanks for the contribution!
All commits need to be DCO signed before merging. Please refer to the the [DCO section in CONTRIBUTING.md](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#developer-certificate-of-origin) or the [DCO](${checks.data.check_runs[0].html_url}) status for more info.
<!-- dco -->`;
await github.rest.issues.createComment({
repo,
owner,
issue_number: pull.number,
body,
});
}
+2
View File
@@ -78,3 +78,5 @@ jobs:
run: |
sudo sysctl fs.inotify.max_user_watches=524288
yarn e2e-test run
env:
BACKSTAGE_TEST_DISABLE_DOCKER: 1
@@ -44,3 +44,5 @@ jobs:
- name: techdocs-cli e2e test
working-directory: packages/techdocs-cli
run: yarn test:e2e:ci
env:
BACKSTAGE_TEST_DISABLE_DOCKER: 1
+95 -87
View File
@@ -1,87 +1,95 @@
| Organization | Contact | Description of Use |
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
| [bol.com](https://www.bol.com) | [@sagacity](https://github.com/sagacity) | Initial work being done to unify platform tooling. |
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@dschwank](https://github.com/dschwank), [@iammnils](https://github.com/iammnils) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
| [Expedia Group](https://www.expediagroup.com) | [Mike Turner](mailto:miturner@expediagroup.com), [Sneha Kumar](mailto:snkumar@expediagroup.com), [@guillermomanzo](https://github.com/guillermomanzo), [Erik Lindgren](https://github.com/lindgren) | EG Common Developer Toolkit |
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling |
| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
| [Trendyol](https://trendyol.com) | [Gamze Senturk](https://github.com/gmzsenturk), [Mert Can Bilgic](https://github.com/mertcb) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. |
| [Peloton](https://www.onepeloton.com/) | [Jim Haughwout](https://github.com/JimHaughwout) | Creating our first developer portal and tech-docs. Exploring Service Catalog, Tech Insights and Cost Insights as well. |
| [TELUS](https://telus.com) | [Seb Barre](https://github.com/sbarre) | The Go-to place to find answers about development and delivery at TELUS. |
| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a teams engineering dependencies. |
| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. |
| [Booz Allen Hamilton](https://www.boozallen.com/) | [Jason Miller](https://github.com/JasonMiller-BAH) | Developer portal for a full-stack software development ecosystem that accelerates consistent and repeatable Modern Software Development practices for internal innovation and investments. |
| [Netflix](https://www.netflix.com/) | [bleathem](https://github.com/bleathem) | Our Backstage implementation will be the front door to a unified experience connecting our internal platform products across important workflows with integrated knowledge and support. |
| [b.well](https://www.icanbwell.com/) | [Jacob Rosales](https://github.com/jrosales) | Foundation for our engineering portal and cloud insights. |
| [PagerDuty](https://www.pagerduty.com/) | [Mark Shaw](https://github.com/markshawtoronto) | Developer portal, initially focused on software templates and tech-docs. |
| [MoonShiner](https://moonshiner.at) | [Fabian Hippmann](https://github.com/FabianHippmann) | Developer portal - helps us keep track of our customer projects, onboard new developers & improve our development process 🌕🚀🧑‍🚀 |
| [FundApps](https://www.fundapps.co/) | [Elliot Greenwood](https://github.com/egnwd) | Developer Portal - A place for us to keep track of our projects and documentation for all services and processes |
| [DAZN](https://dazn.com/) | [Lou Bichard](https://twitter.com/loujaybee), [Marco Crivellaro](https://github.com/crivetechie), [Alex Hollerith](mailto:alex.hollerith@dazn.com) | Ingesting all of DAZN's repos for the catalog, migrating our internal platform apps (pull request boards, release information, inner source marketplace etc) to Backstage plugins (where applicable). |
| [HelloFresh](https://www.hellofresh.de/) | [@iammuho](https://github.com/iammuho), [@ElenaForester](https://github.com/ElenaForester), [@diegomarangoni](https://github.com/diegomarangoni) | Our developer portal at HelloFresh - Spread across an organisation of 500+ engineers globally. |
| [FactSet](https://www.factset.com/) | [@kuangp](https://github.com/kuangp) | Developer portal to provide discoverability to all internal components, APIs, documentation, and scaffold templates with integrations to our internal infrastructure tools. |
| [Workrise](https://www.workrise.com/) | [Michael Rode](https://github.com/michaelrode) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [RedVentures](https://www.redventures.com/) | [Chris Diaz](https://github.com/codingdiaz) | Developer portal that brings everything an engineer needs to provide value into a single pane of glass. |
| [MavTek](https://www.mavtek.com/) | [@fgascon](https://github.com/fgascon) | Developer portal focused on standardizing practices, centralizing documentation and streamlining developer practices. |
| [QuintoAndar](https://www.quintoandar.com.br/) | [@quintoandar](https://github.com/quintoandar) | Developer portal, services catalog and centralization of service metrics. |
| [empathy.co](https://empathy.co/) | [@guillermotti](https://github.com/guillermotti) | Developer portal for tech docs, service catalog, plugin discovery and much more. |
| [creditas.com](https://creditas.com/) | [@aureliosaraiva](https://github.com/aureliosaraiva) [@Creditas](https://github.com/creditas) | Centralization of all services, standards, documentation, etc. We started the deployment process. |
| [Prisjakt](https://www.prisjakt.nu) / [PriceSpy](https://pricespy.co.uk) | [@kennylindahl](https://github.com/kennylindahl) | Internal developer portal - Documentation, scaffolding, software catalog, TechRadar, Gitlab org data integration |
| [Powerspike](https://powerspike.tv/) | [@trelore](https://github.com/trelore) | Developer portal for documentation of core libraries and repositories. |
| [2U](https://2u.com) | [Andrew Thal](https://github.com/athal7) | Development team home-base, promoting service discoverability, resource dependencies, and tech radar |
| [Taxfix](https://taxfix.de/) | [Sami Ur Rehman](https://github.com/samiurrehman92) | Developer's portal with software catalog at it's core. Hosts API Specs, Tech Docs, Tech Radar and some custom plugins. |
| [Busuu](https://busuu.com/) | [Adam Tester](https://github.com/adamtester) | Developer portal with service catalog, API docs, Event docs, service templating, and cost insights. |
| [Loadsmart](https://loadsmart.com/) | [Loadsmart](https://github.com/loadsmart) | Improve services visibility and operations for service owners and developers. |
| [Monzo](https://monzo.com/) | [@WillSewell](https://github.com/WillSewell), [@joechrisellis](https://github.com/joechrisellis) | Developer portal showing metadata and docs for over 2000 microservices. We have built a number of plugins such as a UI for our system to measure [software excellence](https://monzo.com/blog/2021/09/15/how-we-measure-software-excellence), and a UI to show deployment and config change events. |
| [Vaimo](https://www.vaimo.com) | [@vaimo-magnus](https://github.com/vaimo-magnus) | Developer Portal for our developers at Vaimo, currently docs and self-service towards our internal PaaS based on k8s. Plans to extend the catalog into Projects, Environments etc |
| [Wayfair](https://www.wayfair.com) | [@fransan](https://github.com/fransan), [@errskipower](https://github.com/errskipower), [@hrrs](https://github.com/hrrs) | Developer portal for service catalog, technical documentation, and APIs. |
| [CircleHD](https://www.circlehd.com) | [@circlehddev](https://github.com/circlehddev) | Developer Portal for internal dev team across the globe |
| [CastDesk](https://castdesk.com) | [@circlehddev](https://github.com/circlehddev) | Developer Portal for internal dev team across the globe |
| [Santagostino](https://santagostino.it) | [@santagostino](https://github.com/santagostino) | Developer portal, gateway to our infrastructure, documentation, service catalog and internal tooling. |
| [Peak](https://peak.ai) | [Luke Beamish](https://github.com/lukebeamish-peak) | Developer portal for all internal engineers to access documentation and tooling. |
| [Gelato](https://gelato.com/) | [Dmitry Makarenko](https://github.com/dmitry-makarenko-gelato) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal and third-party systems🚀. |
| [GoCardless](https://gocardless.com/) | [James Turley](https://github.com/tragiclifestories) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal systems. |
| [Box](https://www.box.com) | [@kielosz](https://github.com/kielosz), [@jluk-box](https://github.com/jluk-box), [@ptychu](https://github.com/ptychu), [@alexrybch](https://github.com/alexrybch), [@szubster](https://github.com/szubster) | Developer portal for service catalog, integration with internal systems, new service onboarding. |
| [Bazaarvoice](https://www.bazaarvoice.com) | [@niallmccullagh](https://github.com/niallmccullagh) | Developer portal for service catalog and scaffolds, publishing Github docs and API documentation, visualising our internal tech radar and our product engineering org structure. |
| [Krateo PlatformOps](https://www.krateo.io) | [@projectkerberus](https://github.com/projectkerberus) | A multi-cloud control plane to create, manage and deploy any kind of resource easily and centrally via a Developer Portal that centralizes via a self-service catalog the templating and ownership of services, the available documentation, the overview of the components that compose an entire domain and all the data of the service lifecycle. |
| [Adevinta](https://www.adevinta.com) | [Ray Sinnema](https://github.com/RemonSinnema) | Showcase shared services to our internal customers. |
| [Splunk](https://www.splunk.com) | [@tonytamsf](https://github.com/tonytamsf) | Developer portal as a centralized place to find people, services, documentation, escalation policies and give bravos. This portal is also being used as a centralized search engine for engineering specific documentation. |
| [SoundCloud](https://www.soundcloud.com) | [Julio Zynger](https://github.com/julioz) | Developer portal as a [humane registry](https://martinfowler.com/bliki/HumaneRegistry.html) for the organization: catalog of people, services, documentation, feature toggles, escalation policies, etc. |
| [Volvofinans Bank](https://www.volvofinans.se) | [Johan Hammar](https://github.com/johanhammar) | Developer portal enabling engineers to manage and explore software and documentation. |
| [Palo Alto Networks](https://www.paloaltonetworks.com) | [Jeremy Guarini](https://github.com/jeremyguarini), [Brian Lomeland](https://github.com/bbbmmmlll), [Palo Alto Networks](https://github.com/PaloAltoNetworks) | Developer portal, service catalog, documentation and tooling |
| [Signal Iduna Group](https://www.signal-iduna.de/) | [Jonas Thomsen](https://github.com/JoThomsen) | Developer Portal, documentation, monitoring, service catalog for our insurance ecosystem |
| [Tradeshift](https://www.tradeshift.com/) | [Soren Mathiasen](https://github.com/sorenmat) | Developer Portal: documentation, monitoring, service templates, service catalog for our micro services |
| [Unity](https://unity.com) | [Ted Cordery](https://github.com/TeddyBallGame) | A centralized service catalog with documentation for our service engineers. |
| [PicPay](https://www.picpay.com) | [Luis Baroni](https://github.com/lcsbaroni), [Renata Poluceno](https://github.com/renatapoluceno), [PicPay](https://github.com/picpay) | Developer portal for building services throught templates, service catalog with ownership of services, documentation and metrics providing autonomy and visibility for all. |
| [Epic Games](https://www.epicgames.com) | [Brian Jung](https://github.com/brian-at-epic), [Jeff Goldian](https://github.com/jeffgoldian-Epic) | Developer Portal: Service Catalog, Documentation, Software Templates and more making our internal teams' lives easier! |
| [Globo](https://globo.com) | [Carlos Gusmão](https://github.com/caeugusmao), [Guilherme Vierno](https://github.com/vierno), [Denis Aoki](https://github.com/dnsaoki2), [Maycon Dionisio](https://github.com/MayconDionisio), | Reduce the friction of accessing the information engineers need about Globo's digital services through a coherent and centralized experience. |
| [QBE](https://www.qbe.com/) | [Daniel Steel](https://github.com/danielsteelqbe), [Pete Jespers](https://github.com/petejespersqbe) | Developer portal allowing our global teams to explore and create applications, documentation and cloud infrastructure easily and quickly 🚀 |
| [LogMeIn](https://www.logmein.com) | [Lorenzo Orsatti](https://github.com/lorsatti) | Improve onboarding experience of new developers. Discover faster and painlessly developer documentation, API definitions and team information. Provide useful dev metrics in a central place. Provide easy-to-use templates for new services. |
| [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates<br/> Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc |
| [Mosaico](https://www.mosaico.com.br/) | [Wédney Yuri](https://github.com/wedneyyuri),[@tino.milton](https://github.com/miltonjacomini) | A centralized service catalog of our documentation for our service engineers. |
| [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon), [Gauthier Roebroeck](https://github.com/gauthier-roebroeck-mox) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 |
| [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 |
| [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. |
| [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding |
| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. |
| [EF Education First](https://www.ef.com) | [Daan Boerlage](https://github.com/runebaas), [Rafał Nowosielski](https://github.com/rnowosielski) | Our developer portal - primarily used for cataloging and scaffolding with the ambition to expand with more feature adoptions over time |
| [Power Home Remodeling](https://www.techatpower.com) | [Ben Langfeld](https://github.com/benlangfeld) | Developer portal to our internal services, build on open-source software (including Kubernetes) in our own datacenters. Our Portal allows our team members to navigate inherant complexity and standardise. |
| [Livspace](https://www.livspace.com) | [Praveen Kumar](https://github.com/praveen-livspace) | Developer portal, service catalog, tech docs, API docs and plugins |
| [Just Eat Takeaway](https://www.justeattakeaway.com) | [Kim Wilson](https://github.com/kwilson541) | Our developer portal which centralises applications, reduces cognitive load and provides teams insights. |
| [Hopin](https://hopin.com) | [Vladimir Glafirov](https://github.com/vglafirov), [Chloe Lee](https://github.com/msfuko) | Developer portal to streamline the development practices. Integrated with service catalog, software templates, application monitoring, tech docs and plugins. |
| [HBO Max](https://hbomax.com) | [@mdb](https://github.com/mdb), [@nesta219](https://github.com/nesta219), [@nmische](https://github.com/nmische), [@hbomark](https://github.com/hbomark) | Developer portal hosting service catalog and API documentation, as well as cloud infrastructure details, operational visibility tools, and a custom plugin for browsing notable platform change events, such as deployments and configuration updates. |
| Organization | Contact | Description of Use |
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Spotify](https://www.spotify.com) | [@leemills83](https://github.com/leemills83) | Main interface towards all of Spotify's infrastructure and technical documentation. |
| [bol.com](https://www.bol.com) | [@sagacity](https://github.com/sagacity) | Initial work being done to unify platform tooling. |
| [DFDS](https://www.dfds.com) | [@carlsendk](https://github.com/carlsendk) | V2 self-service platform. |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Hosted, managed Backstage with easy set-up |
| [Roku](https://www.roku.com) | [@timurista](https://github.com/timurista) | Initial work on Cloud engineering service platform. |
| [SDA SE](https://sda.se) | [@dschwank](https://github.com/dschwank), [@iammnils](https://github.com/iammnils) | Central place for developing and sharing services in our insurance ecosystem. |
| [H-E-B](https://www.heb.com) | [@german-j-rodriguez](https://github.com/german-j-rodriguez) | Initial work on Engineering Portal service platform. |
| [American Airlines](https://www.aa.com) | [@paulpach](https://github.com/paulpach) | Central place for developers to develop and maintain applications |
| [Kiwi.com](https://kiwi.com) | [@aexvir](https://github.com/aexvir) | Replacing the frontend of [The Zoo](https://github.com/kiwicom/the-zoo), their service registry. |
| [Voi](https://www.voiscooters.com/) | [@K-Phoen](https://github.com/K-Phoen) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [Talkdesk](https://www.talkdesk.com) | [@jaime-talkdesk](https://github.com/jaime-talkdesk) | Initial work for Engineering Portal and Self Provisioning to R&D |
| [Wealthsimple](https://www.wealthsimple.com) | [@andrewthauer](https://github.com/andrewthauer) | Developer portal, service catalog, documentation and tooling |
| [Grab](https://www.grab.com) | [@althafh](https://github.com/althafh) | Initial work as a unified interface for all of Grab's internal tooling |
| [Telenor Sweden](https://www.telenor.se) | [@O5ten](https://github.com/O5ten) | Building a developer portal for scaffolding projects towards our unified build environment and microservice stacks |
| [Fiverr](https://www.fiverr.com) | [@nirga](https://github.com/nirga) | Unifying separate tools that developers are using today (i.e. monitoring, dead letter queues management, etc.) into a single platform. |
| [Zalando SE](https://www.zalando.de) | [@leviferreira](https://github.com/leviferreira) | Building V2 of the Internal Development Portal. |
| [LegalZoom](https://legalzoom.com) | [@backjo](https://github.com/backjo) | Developer portal - hub for all engineering projects and metadata. |
| [Expedia Group](https://www.expediagroup.com) | [Mike Turner](mailto:miturner@expediagroup.com), [Sneha Kumar](mailto:snkumar@expediagroup.com), [@guillermomanzo](https://github.com/guillermomanzo), [Erik Lindgren](https://github.com/lindgren) | EG Common Developer Toolkit |
| [Paddle.com](https://paddle.com) | [Ioannis Georgoulas](https://github.com/geototti21) | Developer portal (Tech Docs, Service Catalog, Internal Tooling), we use vanilla Backstage FE and custom BE implementation in Go |
| [Acast.com](https://acast.com) | [Olle Lundberg](https://github.com/lndbrg) | Developer portal with tech docs, service catalog and a bunch of other internal tooling |
| [Lunar](https://lunar.app) | [Jacob Valdemar](https://github.com/JacobValdemar) | Internal developer portal for service overview and insights, API documentation, technical guides, onboarding guides and RFC's. |
| [Trendyol](https://trendyol.com) | [Gamze Senturk](https://github.com/gmzsenturk), [Mert Can Bilgic](https://github.com/mertcb) | The Developer Portal has been called `Pandora`. Provides an overview of Trendyol tech ecosystem. TechDocs, Catalog, Custom Plugins and Theme. |
| [Peloton](https://www.onepeloton.com/) | [Jim Haughwout](https://github.com/JimHaughwout) | Creating our first developer portal and tech-docs. Exploring Service Catalog, Tech Insights and Cost Insights as well. |
| [TELUS](https://telus.com) | [Seb Barre](https://github.com/sbarre) | The Go-to place to find answers about development and delivery at TELUS. |
| [Brex](https://www.brex.com/) | [Vamsi Chitters](https://github.com/vamsikc) | A centralized UI to understand how a service fits in the whole Brex architecture and manage a teams engineering dependencies. |
| [Oriflame](https://www.oriflame.com/) | [Oriflame](https://github.com/oriflame) | Internal developer portal for services, single page apps and packages overview, API documentation, technical guides, tech-radar and more. |
| [Booz Allen Hamilton](https://www.boozallen.com/) | [Jason Miller](https://github.com/JasonMiller-BAH) | Developer portal for a full-stack software development ecosystem that accelerates consistent and repeatable Modern Software Development practices for internal innovation and investments. |
| [Netflix](https://www.netflix.com/) | [bleathem](https://github.com/bleathem) | Our Backstage implementation will be the front door to a unified experience connecting our internal platform products across important workflows with integrated knowledge and support. |
| [b.well](https://www.icanbwell.com/) | [Jacob Rosales](https://github.com/jrosales) | Foundation for our engineering portal and cloud insights. |
| [PagerDuty](https://www.pagerduty.com/) | [Mark Shaw](https://github.com/markshawtoronto) | Developer portal, initially focused on software templates and tech-docs. |
| [MoonShiner](https://moonshiner.at) | [Fabian Hippmann](https://github.com/FabianHippmann) | Developer portal - helps us keep track of our customer projects, onboard new developers & improve our development process 🌕🚀🧑‍🚀 |
| [FundApps](https://www.fundapps.co/) | [Elliot Greenwood](https://github.com/egnwd) | Developer Portal - A place for us to keep track of our projects and documentation for all services and processes |
| [DAZN](https://dazn.com/) | [Lou Bichard](https://twitter.com/loujaybee), [Marco Crivellaro](https://github.com/crivetechie), [Alex Hollerith](mailto:alex.hollerith@dazn.com) | Ingesting all of DAZN's repos for the catalog, migrating our internal platform apps (pull request boards, release information, inner source marketplace etc) to Backstage plugins (where applicable). |
| [HelloFresh](https://www.hellofresh.de/) | [@iammuho](https://github.com/iammuho), [@ElenaForester](https://github.com/ElenaForester), [@diegomarangoni](https://github.com/diegomarangoni) | Our developer portal at HelloFresh - Spread across an organisation of 500+ engineers globally. |
| [FactSet](https://www.factset.com/) | [@kuangp](https://github.com/kuangp) | Developer portal to provide discoverability to all internal components, APIs, documentation, and scaffold templates with integrations to our internal infrastructure tools. |
| [Workrise](https://www.workrise.com/) | [Michael Rode](https://github.com/michaelrode) | Developer portal, main gateway to our infrastructure, documentation and internal tooling. |
| [RedVentures](https://www.redventures.com/) | [Chris Diaz](https://github.com/codingdiaz) | Developer portal that brings everything an engineer needs to provide value into a single pane of glass. |
| [MavTek](https://www.mavtek.com/) | [@fgascon](https://github.com/fgascon) | Developer portal focused on standardizing practices, centralizing documentation and streamlining developer practices. |
| [QuintoAndar](https://www.quintoandar.com.br/) | [@quintoandar](https://github.com/quintoandar) | Developer portal, services catalog and centralization of service metrics. |
| [empathy.co](https://empathy.co/) | [@guillermotti](https://github.com/guillermotti) | Developer portal for tech docs, service catalog, plugin discovery and much more. |
| [creditas.com](https://creditas.com/) | [@aureliosaraiva](https://github.com/aureliosaraiva) [@Creditas](https://github.com/creditas) | Centralization of all services, standards, documentation, etc. We started the deployment process. |
| [Prisjakt](https://www.prisjakt.nu) / [PriceSpy](https://pricespy.co.uk) | [@kennylindahl](https://github.com/kennylindahl) | Internal developer portal - Documentation, scaffolding, software catalog, TechRadar, Gitlab org data integration |
| [Powerspike](https://powerspike.tv/) | [@trelore](https://github.com/trelore) | Developer portal for documentation of core libraries and repositories. |
| [2U](https://2u.com) | [Andrew Thal](https://github.com/athal7) | Development team home-base, promoting service discoverability, resource dependencies, and tech radar |
| [Taxfix](https://taxfix.de/) | [Sami Ur Rehman](https://github.com/samiurrehman92) | Developer's portal with software catalog at it's core. Hosts API Specs, Tech Docs, Tech Radar and some custom plugins. |
| [Busuu](https://busuu.com/) | [Adam Tester](https://github.com/adamtester) | Developer portal with service catalog, API docs, Event docs, service templating, and cost insights. |
| [Loadsmart](https://loadsmart.com/) | [Loadsmart](https://github.com/loadsmart) | Improve services visibility and operations for service owners and developers. |
| [Monzo](https://monzo.com/) | [@WillSewell](https://github.com/WillSewell), [@joechrisellis](https://github.com/joechrisellis) | Developer portal showing metadata and docs for over 2000 microservices. We have built a number of plugins such as a UI for our system to measure [software excellence](https://monzo.com/blog/2021/09/15/how-we-measure-software-excellence), and a UI to show deployment and config change events. |
| [Vaimo](https://www.vaimo.com) | [@vaimo-magnus](https://github.com/vaimo-magnus) | Developer Portal for our developers at Vaimo, currently docs and self-service towards our internal PaaS based on k8s. Plans to extend the catalog into Projects, Environments etc |
| [Wayfair](https://www.wayfair.com) | [@fransan](https://github.com/fransan), [@errskipower](https://github.com/errskipower), [@hrrs](https://github.com/hrrs) | Developer portal for service catalog, technical documentation, and APIs. |
| [CircleHD](https://www.circlehd.com) | [@circlehddev](https://github.com/circlehddev) | Developer Portal for internal dev team across the globe |
| [CastDesk](https://castdesk.com) | [@circlehddev](https://github.com/circlehddev) | Developer Portal for internal dev team across the globe |
| [Santagostino](https://santagostino.it) | [@santagostino](https://github.com/santagostino) | Developer portal, gateway to our infrastructure, documentation, service catalog and internal tooling. |
| [Peak](https://peak.ai) | [Luke Beamish](https://github.com/lukebeamish-peak) | Developer portal for all internal engineers to access documentation and tooling. |
| [Gelato](https://gelato.com/) | [Dmitry Makarenko](https://github.com/dmitry-makarenko-gelato) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal and third-party systems🚀. |
| [GoCardless](https://gocardless.com/) | [James Turley](https://github.com/tragiclifestories) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal systems. |
| [Box](https://www.box.com) | [@kielosz](https://github.com/kielosz), [@jluk-box](https://github.com/jluk-box), [@ptychu](https://github.com/ptychu), [@alexrybch](https://github.com/alexrybch), [@szubster](https://github.com/szubster) | Developer portal for service catalog, integration with internal systems, new service onboarding. |
| [Bazaarvoice](https://www.bazaarvoice.com) | [@niallmccullagh](https://github.com/niallmccullagh) | Developer portal for service catalog and scaffolds, publishing Github docs and API documentation, visualising our internal tech radar and our product engineering org structure. |
| [Krateo PlatformOps](https://www.krateo.io) | [@projectkerberus](https://github.com/projectkerberus) | A multi-cloud control plane to create, manage and deploy any kind of resource easily and centrally via a Developer Portal that centralizes via a self-service catalog the templating and ownership of services, the available documentation, the overview of the components that compose an entire domain and all the data of the service lifecycle. |
| [Adevinta](https://www.adevinta.com) | [Ray Sinnema](https://github.com/RemonSinnema) | Showcase shared services to our internal customers. |
| [Splunk](https://www.splunk.com) | [@tonytamsf](https://github.com/tonytamsf) | Developer portal as a centralized place to find people, services, documentation, escalation policies and give bravos. This portal is also being used as a centralized search engine for engineering specific documentation. |
| [SoundCloud](https://www.soundcloud.com) | [Julio Zynger](https://github.com/julioz) | Developer portal as a [humane registry](https://martinfowler.com/bliki/HumaneRegistry.html) for the organization: catalog of people, services, documentation, feature toggles, escalation policies, etc. |
| [Volvofinans Bank](https://www.volvofinans.se) | [Johan Hammar](https://github.com/johanhammar) | Developer portal enabling engineers to manage and explore software and documentation. |
| [Palo Alto Networks](https://www.paloaltonetworks.com) | [Jeremy Guarini](https://github.com/jeremyguarini), [Brian Lomeland](https://github.com/bbbmmmlll), [Palo Alto Networks](https://github.com/PaloAltoNetworks) | Developer portal, service catalog, documentation and tooling |
| [Signal Iduna Group](https://www.signal-iduna.de/) | [Jonas Thomsen](https://github.com/JoThomsen) | Developer Portal, documentation, monitoring, service catalog for our insurance ecosystem |
| [Tradeshift](https://www.tradeshift.com/) | [Soren Mathiasen](https://github.com/sorenmat) | Developer Portal: documentation, monitoring, service templates, service catalog for our micro services |
| [Unity](https://unity.com) | [Ted Cordery](https://github.com/TeddyBallGame) | A centralized service catalog with documentation for our service engineers. |
| [PicPay](https://www.picpay.com) | [Luis Baroni](https://github.com/lcsbaroni), [Renata Poluceno](https://github.com/renatapoluceno), [PicPay](https://github.com/picpay) | Developer portal for building services throught templates, service catalog with ownership of services, documentation and metrics providing autonomy and visibility for all. |
| [Epic Games](https://www.epicgames.com) | [Brian Jung](https://github.com/brian-at-epic), [Jeff Goldian](https://github.com/jeffgoldian-Epic) | Developer Portal: Service Catalog, Documentation, Software Templates and more making our internal teams' lives easier! |
| [Globo](https://globo.com) | [Carlos Gusmão](https://github.com/caeugusmao), [Guilherme Vierno](https://github.com/vierno), [Denis Aoki](https://github.com/dnsaoki2), [Maycon Dionisio](https://github.com/MayconDionisio), | Reduce the friction of accessing the information engineers need about Globo's digital services through a coherent and centralized experience. |
| [QBE](https://www.qbe.com/) | [Daniel Steel](https://github.com/danielsteelqbe), [Pete Jespers](https://github.com/petejespersqbe) | Developer portal allowing our global teams to explore and create applications, documentation and cloud infrastructure easily and quickly 🚀 |
| [GoTo](https://www.goto.com) | [Lorenzo Orsatti](https://github.com/lorsatti) | Improve onboarding experience of new developers. Discover faster and painlessly developer documentation, API definitions and team information. Provide useful dev metrics in a central place. Provide easy-to-use templates for new services. |
| [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates<br/> Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc |
| [Mosaico](https://www.mosaico.com.br/) | [Wédney Yuri](https://github.com/wedneyyuri),[@tino.milton](https://github.com/miltonjacomini) | A centralized service catalog of our documentation for our service engineers. |
| [Mox Bank](https://www.mox.com/) | [Nick Laqua](https://github.com/nick-laqua-dragon) | "Single pane of glass" developer portal for providing a best-in-class developer experience to our product teams and making Mox the best tech environment in Hongkong 🥰🚀 |
| [Keyloop](https://www.keyloop.com/) | [Andre Wanlin](https://github.com/awanlin) | Future-motive Developer Portal to help our teams create technology to make everything about buying and owning a car better. 🚗 |
| [Simply Business](https://sbtech.simplybusiness.co.uk/) | [@addersuk](https://github.com/addersuk), [@LightningStairs](https://github.com/LightningStairs), [@punitcse](https://github.com/punitcse), [@moltenice](https://github.com/moltenice) | Central developer portal to access everything a developer needs such as docs, internal service catalog, and the ability to quickly create a new service from a template. Internally developed Backstage plugins allow us to customise the experience to how we work. |
| [Overwolf](https://www.overwolf.com) | [@tomwolfgang](https://github.com/tomwolfgang) | Dev portal - software catalog, tech-docs, scaffolding |
| [Hotmart](https://www.hotmart.com) | [@fabioviana-hotmart](https://github.com/fabioviana-hotmart) | The main Developers Portal to centralize docs, applications and technical metrics. |
| [EF Education First](https://www.ef.com) | [Daan Boerlage](https://github.com/runebaas), [Rafał Nowosielski](https://github.com/rnowosielski) | Our developer portal - primarily used for cataloging and scaffolding with the ambition to expand with more feature adoptions over time |
| [Power Home Remodeling](https://www.techatpower.com) | [Ben Langfeld](https://github.com/benlangfeld) | Developer portal to our internal services, build on open-source software (including Kubernetes) in our own datacenters. Our Portal allows our team members to navigate inherant complexity and standardise. |
| [Livspace](https://www.livspace.com) | [Praveen Kumar](https://github.com/praveen-livspace) | Developer portal, service catalog, tech docs, API docs and plugins |
| [Just Eat Takeaway](https://www.justeattakeaway.com) | [Kim Wilson](https://github.com/kwilson541) | Our developer portal which centralises applications, reduces cognitive load and provides teams insights. |
| [Hopin](https://hopin.com) | [Vladimir Glafirov](https://github.com/vglafirov), [Chloe Lee](https://github.com/msfuko) | Developer portal to streamline the development practices. Integrated with service catalog, software templates, application monitoring, tech docs and plugins. |
| [HBO Max](https://hbomax.com) | [@mdb](https://github.com/mdb), [@nesta219](https://github.com/nesta219), [@nmische](https://github.com/nmische), [@hbomark](https://github.com/hbomark) | Developer portal hosting service catalog and API documentation, as well as cloud infrastructure details, operational visibility tools, and a custom plugin for browsing notable platform change events, such as deployments and configuration updates. |
| [RCHLO](https://www.riachuelo.com.br) & [MIDWAY](https://www.midway.com.br) | [@marcosborges](https://github.com/marcosborges), [@defaultbr](https://github.com/defaultbr) | Self-Service Platform |
| [HP Inc](https://www.hp.com) | [Damon Kaswell](https://github.com/dekoding) | DevEx engagement hub (dev portal: docs, standards, Q&A) and extensive assets catalog (APIs, services, code, data, etc.) for the pan-HP internal developer community. |
| [VMware](https://www.vmware.com) | [@mpriamo](https://github.com/mpriamo), [@krisapplegate](https://github.com/krisapplegate) | Part of [Tanzu Application Platform](https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/index.html) offering; internal developer portal |
| [Ualá](https://www.uala.com.ar/) | [Santiago Bernal](https://github.com/sabernal) | Initial work being done to centralize documentation for all our microservices and APIs, as well as scaffolding new services and tracking code quality |
| [IKEA IT AB](https://www.ingka.com) | [@bjornramberg](https://github.com/bjornramberg), [@supriyachitale](https://github.com/supriyachitale) | Supporting engineers at scale with self serve access and connecting the dots of our engineering platform and services, enabling product teams to move faster and go further, and unleashing innovation, reuse and co-creation across the organisation. |
| [Invitae](https://www.invitae.com/en) | [@ryan-hanchett](https://github.com/ryan-hanchett), [@gmandler42](https://github.com/gmandler42) | Centralized Developer Experience portal, putting all of our tooling behind a single pane of glass and creating a living service catalog. |
| [Fortum](https://www.fortum.com/) | [@brunoamaroalmeida](https://github.com/brunoamaroalmeida), [@dhaval-vithalani](https://github.com/dhaval-vithalani), [@sunilkumarmohanty](https://github.com/sunilkumarmohanty) | A central portal containing information about our applications, services, processes and other software assets to be used by Fortum software engineering community. |
| [Procore](https://www.procore.com/jobs/engineering) | [@shayon](https://github.com/Shayon), [@jamesdabbs-procore](https://github.com/jamesdabbs-procore) | Developer portal - centralized software catalog and templates to enable self serve and reduce cognitive load. |
+2 -68
View File
@@ -1,69 +1,3 @@
# Code of Conduct
# Community Code of Conduct
This code of conduct outlines our expectations for participants within the **Spotify FOSS** community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community.
Our open source community strives to:
- **Be friendly and patient.**
- **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
- **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
- **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. Its important to remember that a community where people feel uncomfortable or threatened is not a productive one.
- **Be careful in the words that we choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable.
- **Try to understand why we disagree**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that were different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesnt mean that theyre wrong. Dont forget that it is human to err and blaming each other doesnt get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
## Definitions
Harassment includes, but is not limited to:
- Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, race, age, regional discrimination, political or religious affiliation
- Unwelcome comments regarding a persons lifestyle choices and practices, including those related to food, health, parenting, drugs, and employment
- Deliberate misgendering. This includes deadnaming or persistently using a pronoun that does not correctly reflect a person's gender identity. You must address people by the name they give you when not addressing them by their username or handle
- Physical contact and simulated physical contact (e.g., textual descriptions like “_hug_” or “_backrub_”) without consent or after a request to stop
- Threats of violence, both physical and psychological
- Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm
- Deliberate intimidation
- Stalking or following
- Harassing photography or recording, including logging online activity for harassment purposes
- Sustained disruption of discussion
- Unwelcome sexual attention, including gratuitous or off-topic sexual images or behaviour
- Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others
- Continued one-on-one communication after requests to cease
- Deliberate “outing” of any aspect of a persons identity without their consent except as necessary to protect others from intentional abuse
- Publication of non-harassing private communication
Our open source community prioritizes marginalized peoples safety over privileged peoples comfort. We will not act on complaints regarding:
- Reverse -isms, including reverse racism, reverse sexism, and cisphobia
- Reasonable communication of boundaries, such as “leave me alone,” “go away,” or “Im not discussing this with you”
- Refusal to explain or debate social justice concepts
- Communicating in a tone you dont find congenial
- Criticizing racist, sexist, cissexist, or otherwise oppressive behavior or assumptions
### Diversity Statement
We encourage everyone to participate and are committed to building a community for all. Although we will fail at times, we seek to treat everyone both as fairly and equally as possible. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong.
Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected
characteristics above, including participants with disabilities.
### Reporting Issues
If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via **fossboard@spotify.com**. All reports will be handled with discretion. In your report please include:
- Your contact information.
- Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please
include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link.
- Any additional information that may be helpful.
After filing a report, a representative will contact you personally, review the incident, follow up with any additional questions, and make a decision as to how to respond. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. If the complaint originates from a member of the response team, it will be handled by a different member of the response team. We will respect confidentiality requests for the purpose of protecting victims of abuse.
### Attribution & Acknowledgements
We all stand on the shoulders of giants across many open source communities. We'd like to thank the communities and projects that established code of conducts and diversity statements as our inspiration:
- [Django](https://www.djangoproject.com/conduct/reporting/)
- [Python](https://www.python.org/community/diversity/)
- [Ubuntu](http://www.ubuntu.com/about/about-ubuntu/conduct)
- [Contributor Covenant](http://contributor-covenant.org/)
- [Geek Feminism](http://geekfeminism.org/about/code-of-conduct/)
- [Citizen Code of Conduct](http://citizencodeofconduct.org/)
Backstage follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
+19
View File
@@ -36,6 +36,25 @@ To become a maintainer you need to demonstrate the following:
If a maintainer is no longer interested or cannot perform the maintainer duties listed above, they should volunteer to be moved to emeritus status. In extreme cases this can also occur by a vote of the sponsors and maintainers per the voting process below.
# End User Sponsors
## Role of a Backstage End User Sponsor
- Provide support for Backstage by removing blockers, securing funding, providing advocacy, feedback, and ensuring project continuity and long term success.
- Assist Backstage maintainers in prioritizing upcoming roadmap items and planned work.
- Provide neutral mediation for any disputes that arise as part of the project.
## Backstage End User Sponsor Membership
The End User Sponsors group comprises at most 5 people. To be eligible for membership in the group, you or the company where you work you must:
- Be responsible for and end user of a production Backstage deployment of non-trivial size
- Be active contributors to the open source project
- Be willing and able to attend regularly-scheduled End User Sponsor meetings
- Abide by [Backstages Code of Conduct](./CODE_OF_CONDUCT.md).
Candidates for membership will be nominated by current Sponsor members or by Backstage maintainers. If there are more nominations than Sponsor seats remaining, existing sponsors shall vote on the candidates, and the candidates with the most votes will become Sponsors. Any ties will be broken by current Backstage sponsors.
# Reviewers
The project also contains a team called [@backstage/reviewers](https://github.com/orgs/backstage/teams/reviewers). This is the team of people who are the fallback in [`CODEOWNERS`](./.github/CODEOWNERS). This team will typically contain the maintainers, and a small number of additional people who are permitted to approve and merge pull requests. The purpose of this group is to offload some of the review work from the maintainers, simplifying and speeding up the review process for contributors.
+2 -1
View File
@@ -24,7 +24,8 @@ app:
backend:
# Used for enabling authentication, secret is shared by all backend plugins
# See backend-to-backend-auth.md in the docs for information on the format
# See https://backstage.io/docs/tutorials/backend-to-backend-auth for
# information on the format
# auth:
# keys:
# - secret: ${BACKEND_SECRET}
@@ -15,7 +15,10 @@ import cookieParser from 'cookie-parser';
import { Request, Response, NextFunction } from 'express';
import { JWT } from 'jose';
import { URL } from 'url';
import { IdentityClient } from '@backstage/plugin-auth-backend';
import {
IdentityClient,
getBearerTokenFromAuthorizationHeader,
} from '@backstage/plugin-auth-node';
// ...
@@ -44,7 +47,7 @@ async function main() {
// ...
const discovery = SingleHostDiscovery.fromConfig(config);
const identity = new IdentityClient({
const identity = IdentityClient.create({
discovery,
issuer: await discovery.getExternalBaseUrl('auth'),
});
@@ -58,7 +61,7 @@ async function main() {
) => {
try {
const token =
IdentityClient.getBearerToken(req.headers.authorization) ||
getBearerTokenFromAuthorizationHeader(req.headers.authorization) ||
req.cookies['token'];
req.user = await identity.authenticate(token);
if (!req.headers.authorization) {
@@ -80,7 +83,7 @@ async function main() {
const apiRouter = Router();
apiRouter.use(cookieParser());
// The auth route must be publically available as it is used during login
// The auth route must be publicly available as it is used during login
apiRouter.use('/auth', await auth(authEnv));
// Add a simple endpoint to be used when setting a token cookie
apiRouter.use('/cookie', authMiddleware, (_req, res) => {
+3
View File
@@ -0,0 +1,3 @@
# Scripts
Here you will find a variety of script contributions.
@@ -0,0 +1,22 @@
<#
.DESCRIPTION
Cleanes up orphaned entities for the provided Backstage URL, defaults to the local backend
#>
param(
[string]$backstageUrl = "http://localhost:7007"
)
$orphanApiUrl = "$backstageUrl/api/catalog/entities?filter=metadata.annotations.backstage.io/orphan=true"
$orphanDeleteApiUrl = "$backstageUrl/api/catalog/entities/by-uid"
$orphans = Invoke-RestMethod -Method Get -Uri $orphanApiUrl
Write-Host ""
Write-Host "Found $($orphans.length) orphaned entities"
Write-Host ""
foreach($orphan in $orphans){
Write-Host "Deleting orphan $($orphan.metadata.name) of kind $($orphan.kind)"
Invoke-RestMethod -Method Delete -Uri "$orphanDeleteApiUrl/$($orphan.metadata.uid)"
}
+21
View File
@@ -0,0 +1,21 @@
# Orphan Clean Up
## Overview
The Orphan Clean Up script is a basic PowerShell script to delete orphaned entities in the catalog. This script also assumes that you do not have authentication setup for your Backstage API endpoints.
_Warning:_ There is a risk of entities being orphaned (and being deleted by this script) in case of the location having problems and returning a 404 status code. This might lead to accidental deletion of entities until the processing loop has recreated the entity.
## Requirements
This script is PowerShell based so therefore needs to be ran in a PowerShell session. If you are not able to use PowerShell the script should give you a clear idea as to how to create it with another scripting language like Bash.
## Usage
Here's how to use the script:
1. Download the script
2. Now start a PowerShell session
3. Next navigate to the location you downloaded the script
4. Then run this command replacing `https:\\backstage.my-company.com` with the URL of your Backstage instance: `.\OrphanCleanUp.ps1 https:\\backstage.my-company.com`
5. The script will output the number of orphaned entities it finds and then the name for each one it deletes
+34 -14
View File
@@ -56,18 +56,15 @@ allows a single auth backend to serve multiple environments, such as running a
local frontend against a deployed backend. The provider configuration matching
the local `auth.environment` setting will be selected.
### Adding the provider to the sign-in page
## Using an authentication provider for sign-in
After configuring an authentication provider, the `app` frontend package needs a
small update to show this provider as a login option. The `SignInPage` component
handles this, and takes either a `provider` or `providers` (array) prop of
`SignInProviderConfig` definitions.
If you want to use an authentication provider for sign-in, as opposed to just accessing external resources, you'll need to configure that in your app as well. This is done by providing a custom `SignInPage` component to the app, which will require the user to sign in before they can access the app. Note that this does not block access to the app, which you can read more about [here](./using-auth.md).
These reference the `ApiRef` exported by the provider. Again, an example using
GitHub that can be adapted to any of the built-in providers:
If you want to, you can use the `SignInPage` component that is provided by `@backstage/core-components`, which takes either a `provider` or `providers` (array) prop of `SignInProviderConfig` definitions. These reference the `ApiRef` exported for the provider.
Again, the following example for GitHub shows the additions needed to `packages/app/src/App.tsx`, and can be adapted to any of the built-in providers:
```diff
# packages/app/src/App.tsx
+ import { githubAuthApiRef } from '@backstage/core-plugin-api';
+ import { SignInProviderConfig, SignInPage } from '@backstage/core-components';
@@ -78,8 +75,8 @@ GitHub that can be adapted to any of the built-in providers:
+ apiRef: githubAuthApiRef,
+};
+
const app = createApp({
apis,
const app = createApp({
apis,
+ components: {
+ SignInPage: props => (
+ <SignInPage
@@ -89,15 +86,15 @@ const app = createApp({
+ />
+ ),
+ },
bindRoutes({ bind }) {
bindRoutes({ bind }) {
```
To also allow unauthenticated guest access, use the `providers` prop for
`SignInPage`:
```diff
const app = createApp({
apis,
const app = createApp({
apis,
+ components: {
+ SignInPage: props => (
+ <SignInPage
@@ -106,7 +103,7 @@ const app = createApp({
+ />
+ ),
+ },
bindRoutes({ bind }) {
bindRoutes({ bind }) {
```
## Adding a custom authentication provider
@@ -119,3 +116,26 @@ Backstage uses [Passport](http://www.passportjs.org/) under the hood, which has
a wide library of authentication strategies for different providers. See
[Add authentication provider](add-auth-provider.md) for details on adding a new
Passport-supported authentication method.
## Custom ScmAuthApi Implementation
If you are using any custom authentication providers, like for example one for GitHub Enterprise, then you are likely to need a custom implementation of the [`ScmAuthApi`](https://backstage.io/docs/reference/integration-react.scmauthapi). It is an API used to authenticate towards different SCM systems in a generic way, based on what resource is being accessed, and is used for example by the Scaffolder (Software Templates) and Catalog Import plugins.
To set up a custom `ScmAuthApi` implementation, you'll need to add an API factory entry to `packages/app/src/apis.ts`. The following example shows an implementation that supports both public GitHub via `githubAuthApi` as well as a GitHub Enterprise installation hosted at `ghe.example.com` via `gheAuthApi`:
```ts
createApiFactory({
api: scmAuthApiRef,
deps: {
gheAuthApi: gheAuthApiRef,
githubAuthApi: githubAuthApiRef,
},
factory: ({ githubAuthApi, gheAuthApi }) =>
ScmAuth.merge(
ScmAuth.forGithub(githubAuthApi),
ScmAuth.forGithub(gheAuthApi, {
host: 'ghe.example.com',
}),
),
});
```
+33 -4
View File
@@ -18,11 +18,10 @@ First, install the
$ heroku login
```
Heroku runs a container registry on `registry.heroku.com`. To push Backstage
Docker images, log in to the container registry also:
If you have not yet created a project through the Heroku interface, you can create it through the CLI.
```shell
$ heroku container:login
$ heroku create <your-app>
```
You _might_ also need to set your Heroku app's stack to `container`:
@@ -31,13 +30,43 @@ You _might_ also need to set your Heroku app's stack to `container`:
$ heroku stack:set container -a <your-app>
```
Configuring your `app-config.yaml`:
```yaml
app:
# Should be the same as backend.baseUrl when using the `app-backend` plugin
baseUrl: https://<your-app>.herokuapp.com
backend:
baseUrl: https://<your-app>.herokuapp.com
listen:
port:
$env: PORT
# The $PORT environment variable is a feature of Heroku
# https://devcenter.heroku.com/articles/dynos#web-dynos
```
> Make sure your file is being copied into your container in the `Dockerfile`.
Before building the Docker image, run the [backstage host build commands](https://backstage.io/docs/deployment/docker#host-build). They must be run whenever you are going to publish a new image.
Heroku runs a container registry on `registry.heroku.com`. To push Backstage
Docker images, log in to the container registry also:
```shell
$ heroku container:login
```
## Push and deploy a Docker image
Now we can push a Backstage [Docker image](docker.md) to Heroku's container
registry and release it to the `web` worker:
```bash
$ heroku container:push web -a <your-app>
$ docker image build . -f packages/backend/Dockerfile --tag registry.heroku.com/<your-app>/web
$ docker push registry.heroku.com/<your-app>/web
$ heroku container:release web -a <your-app>
```
+2 -4
View File
@@ -114,15 +114,13 @@ const routes = (
In `Root.tsx`, add the `SidebarSearchModal` component:
```bash
import { SidebarSearchModal, SearchContextProvider } from '@backstage/plugin-search';
import { SidebarSearchModal } from '@backstage/plugin-search';
export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
<SidebarLogo />
<SearchContextProvider>
<SidebarSearchModal />
</SearchContextProvider>
<SidebarSearchModal />
<SidebarDivider />
...
```
+227 -2
View File
@@ -1,7 +1,232 @@
---
id: software-catalog-api
title: API
description: Documentation on Software Catalog API
description: The Software Catalog API
---
## TODO
The software catalog backend has a JSON based REST API, which can be leveraged
by external systems. This page describes its shape and features.
## Overview
The API surface consists of a few distinct groups of functionality. Each has a
dedicated section below.
> **Note:** This page only describes some of the most commonly used parts of the
> API, and is a work in progress.
All of the URL paths in this article are assumed to be on top of some base URL
pointing at your catalog installation. For example, if the path given in a
section below is `/entities`, and the catalog is located at
`http://localhost:7007/api/catalog` during local development, the full URL would
be `http://localhost:7007/api/catalog/entities`. The actual URL may vary from
one organization to the other, especially in production, but is commonly your
`backend.baseUrl` in your app config, plus `/api/catalog` at the end.
Some or all of the endpoints may accept or require an `Authorization` header
with a `Bearer` token, which should then be the Backstage token returned by the
[`identity API`](https://backstage.io/docs/reference/core-plugin-api.identityapiref).
## Entities
These are the endpoints that deal with reading of entities directly. What it
exposes are final entities - i.e. the output of all processing and the stitching
process, not the raw originally ingested entity data. See [The Life of an
Entity](life-of-an-entity.md) for more details about this process and
distinction.
### `GET /entities`
Lists entities. Supports the following query parameters, described in sections
below:
- [`filter`](#filtering), for selecting only a subset of all entities
- [`fields`](#field-selection), for selecting only parts of the full data
structure of each entity
- [`offset`, `limit`, and `after`](#pagination) for pagination
The return type is JSON, as an array of [`Entity`](descriptor-format.md).
#### Filtering
You can pass in one or more filter sets that get matched against each entity.
Each filter set is a number of conditions that all have to match for the
condition to be true (conditions effectively have an AND between them). At least
one filter set has to be true for the entity to be part of the result set
(filter sets effectively have an OR between them).
Example:
```text
/entities?filter=kind=user,metadata.namespace=default&filter=kind=group,spec.type
Return entities that match
Filter set 1:
Condition 1: kind = user
AND
Condition 2: metadata.namespace = default
OR
Filter set 2:
Condition 1: kind = group
AND
Condition 2: spec.type exists
```
Each condition is either on the form `<key>`, or on the form `<key>=<value>`.
The first form asserts on the existence of a certain key (with any value), and
the second asserts that the key exists and has a certain value. All checks are
always case _insensitive_.
In all cases, the key is a simplified JSON path in a given piece of entity data.
Each part of the path is a key of an object, and the traversal also descends
through arrays. There are two special forms:
- Array items that are simple value types (such as strings) match on a key-value
pair where the key is the item as a string, and the value is the string `true`
- Relations can be matched on a `relations.<type>=<targetRef>` form
Let's look at a simplified example to illustrate the concept:
```json
{
"a": {
"b": ["c", { "d": 1 }],
"e": 7
}
}
```
This would match any one of the following conditions:
- `a`
- `a.b`
- `a.b.c`
- `a.b.c=true`
- `a.b.d`
- `a.b.d=1`
- `a.e`
- `a.e=7`
Some more real world usable examples:
- Return all orphaned entities:
`/entities?filter=metadata.annotations.backstage.io/orphan=true`
- Return all users and groups:
`/entities?filter=kind=user&filter=kind=group`
- Return all service components:
`/entities?filter=kind=component,spec.type=service`
- Return all entities with the `java` tag:
`/entities?filter=metadata.tags.java`
- Return all users who are members of the `ops` group (note that the full
[reference](references.md) of the group is used):
`/entities?filter=kind=user,relations.memberof=group:default/ops`
#### Field selection
By default the full entities are returned, but you can pass in a `fields` query
parameter which selects what parts of the entity data to retain. This makes the
response smaller and faster to transfer, and may allow the catalog to perform
more efficient queries.
The query parameter value is a comma separated list of simplified JSON paths
like above. Each path corresponds to the key of either a value, or of a subtree
root that you want to keep in the output. The rest is pruned away. For example,
specifying `?fields=metadata.name,metadata.annotations,spec` retains only the
`name` and `annotations` fields of the `metadata` of each entity (it'll be an
object with at most two keys), keeps the entire `spec` unchanged, and cuts out
all other roots such as `relations`.
Some more real world usable examples:
- Return only enough data to form the full ref of each entity:
`/entities?fields=kind,metadata.namespace,metadata.name`
#### Pagination
You may pass the `offset` and `limit` query parameters to do classical
pagination through the set of entities. There is also an `after` query parameter
to return the next page of results after the previous one when performing cursor
based pagination.
Each paginated response that has a next page of data, will have a `Link`,
`rel="next"` header pointing to the query path to the next page.
Example: Getting the first page:
```text
GET /entities?limit=2
HTTP/1.1 200 OK
link: </entities?limit=2&after=eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ%3D%3D>; rel="next"
[{"metadata":{...
```
Getting the next page, since we detect the presence of the `Link` header:
```text
GET /entities?limit=2&after=eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ%3D%3D
HTTP/1.1 200 OK
link: </entities?limit=2&after=eyJsaW1pdCI6Miwib2Zmc2V0Ijo0fQ%3D%3D>; rel="next"
[{"metadata":{...
```
### `GET /entities/by-uid/<uid>`
Gets an entity by its `metadata.uid` field value.
The return type is JSON, as a single [`Entity`](descriptor-format.md), or a 404
error if there was no entity with that UID.
### `DELETE /entities/by-uid/<uid>`
Deletes an entity by its `metadata.uid` field value.
> **Note:** This method of deletion is appropriate for orphaned entities, but
> not for removal of "live" entities that are actively being updated by a
> location. Please read below.
The most common user flow is that you register a location (see below), and then
the catalog keeps itself up to date with that location and the subtree of things
that may spawn from it. This means that the catalog is a live-updating view of
an actual authoritative data source. If there's something keeping the entity
"alive" in the catalog, it will just reappear shortly after deletion with the
method described in this section. To properly remove entities, you typically
want to instead unregister the location that causes the entity to appear.
However if you have an orphaned entity, for example after removing the reference
to its file from a `Location` entity, or if a processor has stopped producing
your entity, then this deletion method is appropriate.
The return type is always an empty 204 response, whether an entity with this UID
existed or not.
### `GET /entities/by-name/<kind>/<namespace>/<name>`
Gets an entity by its `kind`, `metadata.namespace`, and `metadata.name` field
value. These are special in that they form the entity's unique
[reference](references.md) triplet.
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.
## Locations
TODO
## Other
TODO
@@ -1121,6 +1121,17 @@ This field is optional.
| [`Component`](#kind-component) | Same as this entity, typically `default` | [`dependsOn`, and reverse `dependencyOf`](well-known-relations.md#dependson-and-dependencyof) |
| [`Resource`](#kind-resource) | Same as this entity, typically `default` | [`dependsOn`, and reverse `dependencyOf`](well-known-relations.md#dependson-and-dependencyof) |
### `spec.dependencyOf` [optional]
An array of [entity references](references.md#string-references) to the
components and resources that the resource is a dependency of, e.g. `artist-lookup`.
This field is optional.
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
| --------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------- |
| [`Component`](#kind-component) | Same as this entity, typically `default` | [`dependencyOf`, and reverse `dependsOn`](well-known-relations.md#dependson-and-dependencyof) |
| [`Resource`](#kind-resource) | Same as this entity, typically `default` | [`dependencyOf`, and reverse `dependsOn`](well-known-relations.md#dependson-and-dependencyof) |
## Kind: System
Describes the following entity kind:
@@ -48,9 +48,9 @@ The details of these processes are described below.
## Ingestion
Each catalog deployment has a number of entity providers installed. They are
Each catalog deployment has a number of _entity providers_ installed. They are
responsible for fetching data from external authoritative sources in any way
that they see fit, to translate those into entity objects, and to notify the
that they see fit, translating those into entity objects, and notifying the
database when those entities are added or removed. These are the _unprocessed
entities_ that will be subject to later processing (see below), and they form
the very basis of existence for entities. If there were no entity providers, no
@@ -108,7 +108,7 @@ the processing loop should next try to process it. When the entity first
appears, this timestamp is set to "now" - asking for it to be picked up as soon
as possible.
Each catalog deployment has a number of processors installed. They are
Each catalog deployment has a number of _processors_ installed. They are
responsible for receiving unprocessed entities that the catalog decided are due
for processing, and then running that data through a number of processing
stages, mutating the entity and emitting auxiliary data about it. When all of
@@ -185,7 +185,28 @@ happen during ingestion or processing.
## Errors
> TODO: Describe how errors are exposed through entities
Errors during the ingestion and processing of entities can happen in a variety
of ways, and they may happen at a far later point in time than when they were
registered. For example, a registered file may get deleted in the remote system,
or the user may accidentally change the file contents in such a way that they
cannot be parsed successfully, etc.
There are two main ways that these errors are surfaced.
First, the catalog backend will produce detailed logs that should contain
sufficient information for a reader to find the causes for errors. Since these
logs are typically not easily found by end users, this can mainly be a useful
tool for Backstage operators who want to debug problems either with statically
registered entities that are under their control, or to help end users find
problems.
Second, for most classes of errors, the entity itself will contain a status
field that describes the problem. The contents of this field is shown at the top
of your entity page in Backstage, if you have placed the corresponding error
callout component (`EntityProcessingErrorsPanel`) there.
We are still working to improve the surfacing and observability around
processing loop errors.
## Orphaning
@@ -206,17 +227,22 @@ either, it becomes _orphaned_. The end result is as follows:
- The catalog page in Backstage for the child entity detects the new annotation
and informs users about the orphan status.
Orphaning can occur in several different scenarios. One common cause is that the
end user edited a corresponding catalog catalog-info YAML file removing the
entity's entry. In the case of a `Location` parent entity, orphaning can happen
if removing the target line pointing to the file containing the child entity.
Another common cause is large batch processors such as the ones that crawl
through remote systems looking for entities, no longer finding something that it
used to find before. Maybe the data was moved, or deleted, in the remote system.
So for example when a person leaves the company an LDAP org discovery processor
might leave an orphaned `User` entity behind. Note that this only applies to
processors - ingestion that happens using entity providers work differently,
described below.
Orphaning can occur in several different scenarios.
- If a catalog-info YAML file is moved from one place to another in the version
control system without updating the registration in the catalog, it will
effectively become orphaned "by" that registered location
- If the user edits a corresponding parent catalog-info YAML file removing the
entity's entry - for example in the case of a `Location` parent entity,
orphaning can happen if editing or removing the `target`/`targets` lines
pointing to the file containing the child entity.
- Another common cause is large batch processors such as the ones that crawl
through remote systems looking for entities, no longer finding something that
it used to find before. Maybe the data was moved, or deleted, in the remote
system. So for example when a person leaves the company an LDAP org discovery
processor might leave an orphaned `User` entity behind. Note that this only
applies to processors - ingestion that happens using entity providers work
differently, described below.
> Note that removing a file, or accidentally corrupting a file so that it cannot
> be read successfully, does _not_ lead to orphaning. Hard errors, including the
@@ -239,8 +265,78 @@ provided out of the box.
## Implicit Deletion
> TODO: Describe the process of entity providers eagerly deleting entities
Entity providers - not processors - are subject to _eager_ deletion of entities,
which may trigger the implicit deletion of more than just the entity you thought
you were deleting. This concept is explained here.
Recall that all entity providers manage a private "bucket" of entities, as
described in the [External integrations](external-integrations.md) article. They
can perform some operations on those entities, including additions, updates, and
deletions. Entity additions/updates are subject to the regular processing loops,
which means that bucket entities may end up forming roots of an entire graph of
entities that are emitted by those processors as they recursively work they way
through the bucket contents and its descendants.
When a provider issues a deletion of an entity in its bucket, that entity as
well as _the entire tree of entities processed out of it_, if any, are
considered for immediate deletion. Note "considered" - they are deleted if and
only if they would otherwise have become orphaned (no other parent entities
emitting them). Since the graph of entities is not strictly a tree, multiple
roots may actually end up indirectly referencing a node farther down in the
graph. If that's the case, that node won't go away until all such roots go away.
URLs to yaml files that you register using either the Create button or add to
your app-config, are both handled by entity providers. That means that this
implicit deletion mechanism comes into play in some everyday circumstances.
Let's illustrate.
Imagine that you have a monorepo, with a single `Location` entity in a
catalog-info file at the root, and that entity points to three other
catalog-info files in the repo with a `Component` entity in each one.
```text
/
feature_one/
catalog-info.yaml <- kind: Component
feature_two/
catalog-info.yaml <- kind: Component
feature_three/
catalog-info.yaml <- kind: Component
catalog-info.yaml <- kind: Location
```
If you register the root `Location` entity, the actual effect is that _five_
entities appear in the catalog. First, one that is named `generated-`-something,
which corresponds to the registered URL itself. That's the one that the provider
has put in its "bucket". Then, as processing loops chug along, the `Location`
entity you pointed to appears as a child of that, and then the three `Component`
entities appear in turn as children of the `Location`.
As an end user of the Backstage interface, you may now want to delete one of the
three `Component` entities. You do that by visiting the three-dots menu in the
top right of an entity view. The popup dialog that appears will inform you that
actually this entity belongs to a certain root, and that you may want to remove
that root instead (which corresponds to unregistering the originally registered
URL). If you choose to do so, _all_ of the aforementioned five entities will
actually be deleted in the same operation.
If you did not want to perform this aggressive pruning, you might have instead
chosen to remove one of the `target` rows of your `Location` catalog-info file,
and then deleted the catalog-info file that contained the `Component` you wanted
to get rid of. Now the catalog would be left with an orphaned component, and you
would instead be able to use the explicit deletion (see below) to delete that
single component.
## Explicit Deletion
> TODO: Describe direct deletion via the catalog API
The catalog and its REST API also permits direct deletion of individual
entities. This makes sense to do on orphaned entities; entities that aren't
being actively kept up to date by any parent entities. The popup interface under
the three-dots menu option of entity views does offer this option, and the
orphaned status can be seen in an info box at the top of the entity's overview
page.
However, if you were to try to do an explicit depletion on an entity that's
being kept actively updated by a parent entity, it would just reappear again
shortly thereafter when the processing loops reconsider the parent entity that's
still in there.
@@ -34,6 +34,20 @@ The migration path is pretty simple, and we've removed some of the pain points
from writing the `handlebars` templates too. Let's go through what's new and how
to upgrade.
## Add the Processor to the `plugin-catalog-backend`
An important change is to add the required processor to your `packages/backend/src/plugins/catalog.ts`
```diff
+import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend';
...
const builder = await CatalogBuilder.create(env);
+ builder.addProcessor(new ScaffolderEntitiesProcessor());
const { processingEngine, router } = await builder.build();
```
## `backstage.io/v1beta2` -> `scaffolder.backstage.io/v1beta3`
The most important change is that you'll need to switch over the `apiVersion` in
@@ -287,6 +287,79 @@ The `RepoUrlPicker` is a custom field that we provide part of the
`plugin-scaffolder`. You can provide your own custom fields by
[writing your own Custom Field Extensions](./writing-custom-field-extensions.md)
##### Using the Users `oauth` token
There's a little bit of extra magic that you get out of the box when using the
`RepoUrlPicker` as a field input. You can provide some additional options under
`ui:options` to allow the `RepoUrlPicker` to grab an `oauth` token for the user
for the required `repository`.
This is great for when you are wanting to create a new repository, or wanting to
perform operations on top of an existing repository.
A sample template that takes advantage of this is like so:
```yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: v1beta3-demo
title: Test Action template
description: scaffolder v1beta3 template demo
spec:
owner: backstage/techdocs-core
type: service
parameters:
...
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
# Here's the option you can pass to the RepoUrlPicker
requestUserCredentials:
secretsKey: USER_OAUTH_TOKEN
additionalScopes:
github:
- workflow:write
allowedHosts:
- github.com
...
steps:
...
- id: publish
name: Publish
action: publish:github
input:
allowedHosts: ['github.com']
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}
# here's where the secret can be used
token: ${{ secrets.USER_OAUTH_TOKEN }}
...
```
You will see from above that there is an additional `requestUserCredentials`
object that is passed to the `RepoUrlPicker`. This object defines what the
returned `secret` should be stored as when accessing using
`${{ secrets.secretName }}`, in this case it is `USER_OAUTH_TOKEN`. And then you
will see that there is an additional `input` field into the `publish:github`
action called `token`, in which you can use the `secret` like so:
`token: ${{ secrets.USER_OAUTH_TOKEN }}`.
There's also the ability to pass additional scopes when requesting the `oauth`
token from the user, which you can do on a per-provider basis, in case your
template can be published to multiple providers.
#### The Owner Picker
When the scaffolder needs to add new components to the catalog, it needs to have
@@ -114,7 +114,7 @@ updated documentation next time you run Backstage!
## Writing and previewing your documentation
Using the [techdocs-cli](https://github.com/backstage/techdocs-cli) you can
Using the [techdocs-cli](https://github.com/backstage/backstage/tree/master/packages/techdocs-cli) you can
preview your docs inside a local Backstage instance and get live reload on
changes. This is useful when you want to preview your documentation while
writing.
@@ -41,7 +41,10 @@ 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.
-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`.
## More information on dependency mismatches
+42 -2
View File
@@ -444,8 +444,9 @@ working directory to the package that the test is in.
Where small customizations are needed, such as setting coverage thresholds or
support for specific transforms, it is possible to override the Jest
configuration through the `"jest"` field in `package.json`. These overrides will
be loaded in from all `package.json` files in the directory ancestry, meaning
configuration through the `"jest"` field in `package.json`. For a full list of
options, see the [Jest documentation](https://jestjs.io/docs/en/configuration).
These overrides will be loaded in from all `package.json` files in the directory ancestry, meaning
that you can place common configuration in the `package.json` at the root of a
monorepo. If multiple overrides are found, they will be merged together with
configuration further down in the directory tree taking precedence.
@@ -464,6 +465,45 @@ The overrides in a single `package.json` may for example look like this:
},
```
If you want to configure editor integration for tests we recommend executing the bundled configuration directly with Jest rather than running through the Yarn test script. For example, with the Jest extension for VS Code the configuration would look something like this:
```jsonc
{
"jest.jestCommandLine": "node_modules/.bin/jest --config node_modules/@backstage/cli/config/jest.js",
// In a large repo like the Backstage main repo you likely want to disable
// watch mode and the initial test run too, leaving just manual and perhaps
// on-save test runs in place.
"jest.autoRun": {
"watch": false,
"onSave": "test-src-file"
}
}
```
If you also want to enable source maps when debugging tests, you can do so by setting the `ENABLE_SOURCE_MAPS` environment variable. For example, a complete launch configuration for VS Code debugging may look like this:
```json
{
"type": "node",
"name": "vscode-jest-tests",
"request": "launch",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"program": "${workspaceFolder}/node_modules/.bin/jest",
"cwd": "${workspaceFolder}",
"env": {
"ENABLE_SOURCE_MAPS": "true"
},
"args": [
"--config",
"node_modules/@backstage/cli/config/jest.js",
"--runInBand",
"--watchAll=false"
]
}
```
## Publishing
Package publishing is an optional part of the Backstage build system and not
+1 -16
View File
@@ -440,22 +440,7 @@ a yarn workspaces monorepo by automatically creating one grouped configuration
that includes all packages that have `backstage-cli test` in their package
`test` script.
If needed, the configuration can be extended using a `"jest"` field in
`package.json`, both within the target package and the monorepo root, with
configuration in the target package taking precedence. Refer to the
[Jest configuration documentation](https://jestjs.io/docs/en/configuration) for
a full list of configuration options.
In addition to the Jest configuration there's an optional `transformModules`
option, which is an array of module names to include in transformations.
Normally modules inside `node_modules` are not transformed, but there are cases
were published packages are not transpiled far enough to be usable by Jest, in
which case you need to enable transform of them.
Another way to override the Jest configuration is to place a `jest.config.js` or
`jest.config.ts` file in the package root. As opposed to the `package.json` way
of overriding config, this completely removes the base config, and so you need
to set it up from scratch.
For more information about configuration overrides and editor support, see the [Jest Configuration section](./cli-build-system.md#jest-configuration) in the build system documentation.
```text
Usage: backstage-cli test [options]
+57
View File
@@ -141,6 +141,63 @@ By convention, such packages should be named
`@backstage/analytics-module-[name]`, and any configuration should be keyed
under `app.analytics.[name]`.
### Handling User Identity
If the analytics platform you are integrating with has a first-class concept of
user identity, you can (optionally) choose to support this by the following this
convention:
- Allow your implementation to be instantiated with the `identityApi` as one of
its options in a `fromConfig` static method.
- Use the `userEntityRef` resolved by `identityApi`'s `getBackstageIdentity()`
method as the basis for the user ID you send to your analytics platform.
For example:
```typescript
import {
AnalyticsApi,
analyticsApiRef,
AnyApiFactory,
configApiRef,
createApiFactory,
identityApiRef,
IdentityApi,
} from '@backstage/core-plugin-api';
// Implementation that optionally initializes with a userId.
class AcmeAnalytics implements AnalyticsApi {
private constructor(accountId: number, identityApi?: IdentityApi) {
if (identityApi) {
identityApi.getBackstageIdentity().then(identity => {
AcmeAnalytics.init(accountId, {
userId: identity.userEntityRef,
});
});
} else {
AcmeAnalytics.init(accountId);
}
}
static fromConfig(config, options) {
const accountId = config.getString('app.analytics.acme.id');
return new AcmeAnalytics(accountId, options.identityApi);
}
}
// Your implementation should be instantiated like this:
export const apis: AnyApiFactory[] = [
createApiFactory({
api: analyticsApiRef,
deps: { configApi: configApiRef, identityApi: identityApiRef },
factory: ({ configApi, identityApi }) =>
AcmeAnalytics.fromConfig(configApi, {
identityApi,
}),
}),
];
```
## Capturing Events
To instrument an event in a component, start by retrieving an analytics tracker
@@ -107,7 +107,7 @@ const systemPage = (
</Grid>
</EntityLayout.Route>
<EntityLayout.Route path="/diagram" title="Diagram">
<EntitySystemDiagramCard />
<EntityCatalogGraphCard variant="gridItem" height={400} />
</EntityLayout.Route>
{/* Adding a new tab to the system view */}
+29 -30
View File
@@ -19,61 +19,60 @@ PR is merged. This is typically done every Thursday around noon CET.
maintainers.**
For this example we will be using the `@backstage/plugin-foo` package as an
example and assume that it is currently version `1.5.0` in the master branch.
example and assume that it is currently version `6.5.0` in the master branch.
In the event of a severe bug being introduced in version `1.5.0` of the
`@backstage/plugin-foo` released in the `2048-01-01` release, the following
process is used to release an emergency fix as `1.5.1`:
In the event of a severe bug being introduced in version `6.5.0` of the
`@backstage/plugin-foo` released in the `v1.18.0` Backstage release, the following
process is used to release an emergency fix as version `6.5.1` in the patch release `v1.18.1`:
- [ ] Identify the release or releases that need to be patched. We should always
patch the most recent main-line release if needed, which in this example
would be `2048-01-01`. The fix may also need backporting to older major
patch the most recent major or minor main-line release if needed, which in this example
would be `v1.18.0`. The fix may also need backporting to older major
versions, in which case we will want to patch the main-line release just
before the one that bumped the package to each new major version.
- [ ] Repeat the following steps for each release that needs to be patched:
- [ ] Make sure a patch branch exists for the release that is being patched.
If a patch already exists, reuse the existing branch. The branch **must
always** be named exactly `release-<release>-patch`.
always** be named exactly `patch/<release>`.
```bash
git checkout release-2048-01-01
git checkout -b release-2048-01-01-patch
git push --set-upstream origin release-2048-01-01-patch
git checkout v1.18.0
git checkout -b patch/v1.18.0
git push --set-upstream origin patch/v1.18.0
```
- [ ] With the `release-2048-01-01-patch` branch as a base, create a new
- [ ] With the `patch/v1.18.0` branch as a base, create a new
branch for your fix. This branch can be named anything, but the
following naming pattern may be suitable:
```bash
git checkout -b ${USER}/release-2048-01-01-emergency-fix
git checkout -b ${USER}/plugin-foo-v1.18.0-fix
```
- [ ] Create a single commit that applies fixes and creates a new patch
changeset for the affected package.
- [ ] Run `yarn release` in the root of the repo in order to convert your
changeset into package version bumps and changelog entries. Commit these
changes as a second `"Generated release"` commit.
- [ ] Create PR towards the base branch (`release-2048-01-01-patch`)
containing the two commits.
- [ ] Review/Merge the PR into `release-2048-01-01-patch`. This will
automatically trigger a release.
- [ ] Create a single commit that applies fix, nothing else.
- [ ] Create a changeset for the affected package(s), then run `yarn release` in the root
of the repo in order to convert your changeset into package version bumps and changelog entries.
Commit these changes as a second `"Generated release"` commit.
- [ ] Create PR towards the base branch (`patch/v1.18.0`) containing the two commits.
- [ ] Review/Merge the PR into `patch/v1.18.0`. This will automatically trigger a release.
- [ ] Once fixes have been created for each release, the fix should be applied
to the master branch as well. Create a PR that contains the following:
- [ ] Look up the new version of our package in the patch PR as well as the new release
version, these can be found in the package `package.json` and the root `package.json`, and
will in this case be `6.5.1` and `v1.18.1`. You will need these versions later.
- [ ] Make sure you have the latest versions of the patch branch fetched, after merging the PR: `git fetch`.
- [ ] Once fixes have been created for each release, the fix should be applied to the
master branch as well. Create a PR that contains the following:
- [ ] The fix.
- [ ] A changeset with the message "Apply fix from the x.y.z patch release",
in this case `1.5.1`. You can find the version in your patch PR for the
most recent release.
- [ ] An entry in `.changeset/patched.json` that sets the current release to
that same version:
- [ ] The fix, which you can likely cherry-pick from your patch branch: `git cherry-pick origin/patch/v1.18.0^`
- [ ] An updated `CHANGELOG.md` of all patched patches from the tip of the patch branch, which you can get using `git checkout origin/patch/v1.18.0 -- plugins/foo/CHANGELOG.md`.
- [ ] A changeset with the message "Applied the fix from version `6.5.1` of this package, which is part of the `v1.18.1` release of Backstage.",
- [ ] An entry in `.changeset/patched.json` that sets the current release version to `6.5.1`:
```json
{
"currentReleaseVersion": {
"@backstage/plugin-foo": "1.5.1"
"@backstage/plugin-foo": "6.5.1"
}
}
```
+1
View File
@@ -5,6 +5,7 @@ const React = require('react');
const redirects = {
'bind-routes':
'/docs/plugins/composability#binding-external-routes-in-the-app',
'scm-auth': '/docs/auth/#custom-scmauthapi-implementation',
};
const fallback = '/docs';
+2 -2
View File
@@ -49,7 +49,7 @@
"**/@roadiehq/**/@backstage/plugin-catalog": "*",
"**/@roadiehq/**/@backstage/catalog-model": "*"
},
"version": "0.65.0",
"version": "0.67.0",
"dependencies": {
"@manypkg/get-packages": "^1.1.3",
"@microsoft/api-documenter": "^7.15.0",
@@ -68,7 +68,7 @@
"concurrently": "^7.0.0",
"eslint-plugin-notice": "^0.9.10",
"fs-extra": "9.1.0",
"husky": "^6.0.0",
"husky": "^7.0.4",
"lerna": "^4.0.0",
"lint-staged": "^12.2.0",
"minimist": "^1.2.5",
+37
View File
@@ -1,5 +1,42 @@
# @backstage/app-defaults
## 0.1.7
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.8
## 0.1.7-next.0
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.8-next.0
## 0.1.6
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.7
- @backstage/core-app-api@0.5.2
## 0.1.6-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.7-next.1
- @backstage/core-app-api@0.5.2-next.0
## 0.1.6-next.0
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.7-next.0
## 0.1.5
### Patch Changes
+5 -5
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/app-defaults",
"description": "Provides the default wiring of a Backstage App",
"version": "0.1.5",
"version": "0.1.7",
"private": false,
"publishConfig": {
"access": "public",
@@ -29,8 +29,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/core-components": "^0.8.6",
"@backstage/core-app-api": "^0.5.1",
"@backstage/core-components": "^0.8.8",
"@backstage/core-app-api": "^0.5.2",
"@backstage/core-plugin-api": "^0.6.0",
"@backstage/plugin-permission-react": "^0.3.0",
"@backstage/theme": "^0.2.14",
@@ -42,8 +42,8 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.13.0",
"@backstage/test-utils": "^0.2.3",
"@backstage/cli": "^0.13.2",
"@backstage/test-utils": "^0.2.4",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@types/jest": "^26.0.7",
+205
View File
@@ -1,5 +1,210 @@
# example-app
## 0.2.64
### Patch Changes
- Updated dependencies
- @backstage/cli@0.13.2
- @backstage/plugin-todo@0.2.0
- @backstage/plugin-newrelic-dashboard@0.1.6
- @backstage/core-components@0.8.8
- @backstage/plugin-scaffolder@0.12.2
- @backstage/plugin-search@0.6.2
- @backstage/plugin-catalog-react@0.6.14
- @backstage/plugin-catalog@0.7.12
- @backstage/plugin-catalog-graph@0.2.10
- @backstage/plugin-catalog-import@0.8.1
- @backstage/plugin-home@0.4.14
- @backstage/app-defaults@0.1.7
- @backstage/integration-react@0.1.21
- @backstage/plugin-airbrake@0.1.3
- @backstage/plugin-apache-airflow@0.1.6
- @backstage/plugin-api-docs@0.7.2
- @backstage/plugin-azure-devops@0.1.14
- @backstage/plugin-badges@0.2.22
- @backstage/plugin-circleci@0.2.37
- @backstage/plugin-cloudbuild@0.2.35
- @backstage/plugin-code-coverage@0.1.25
- @backstage/plugin-cost-insights@0.11.20
- @backstage/plugin-explore@0.3.29
- @backstage/plugin-gcp-projects@0.3.17
- @backstage/plugin-github-actions@0.4.35
- @backstage/plugin-gocd@0.1.4
- @backstage/plugin-graphiql@0.2.30
- @backstage/plugin-jenkins@0.5.20
- @backstage/plugin-kafka@0.2.28
- @backstage/plugin-kubernetes@0.5.7
- @backstage/plugin-lighthouse@0.2.37
- @backstage/plugin-newrelic@0.3.16
- @backstage/plugin-pagerduty@0.3.25
- @backstage/plugin-rollbar@0.3.26
- @backstage/plugin-sentry@0.3.36
- @backstage/plugin-shortcuts@0.1.22
- @backstage/plugin-tech-insights@0.1.8
- @backstage/plugin-tech-radar@0.5.5
- @backstage/plugin-techdocs@0.13.3
- @backstage/plugin-user-settings@0.3.19
## 0.2.64-next.0
### Patch Changes
- Updated dependencies
- @backstage/cli@0.13.2-next.0
- @backstage/plugin-todo@0.2.0-next.0
- @backstage/plugin-newrelic-dashboard@0.1.6-next.0
- @backstage/core-components@0.8.8-next.0
- @backstage/plugin-scaffolder@0.12.2-next.0
- @backstage/plugin-search@0.6.2-next.0
- @backstage/plugin-catalog-react@0.6.14-next.0
- @backstage/plugin-catalog-graph@0.2.10-next.0
- @backstage/plugin-catalog-import@0.8.1-next.0
- @backstage/plugin-home@0.4.14-next.0
- @backstage/app-defaults@0.1.7-next.0
- @backstage/integration-react@0.1.21-next.0
- @backstage/plugin-airbrake@0.1.3-next.0
- @backstage/plugin-apache-airflow@0.1.6-next.0
- @backstage/plugin-api-docs@0.7.2-next.0
- @backstage/plugin-azure-devops@0.1.14-next.0
- @backstage/plugin-badges@0.2.22-next.0
- @backstage/plugin-catalog@0.7.12-next.0
- @backstage/plugin-circleci@0.2.37-next.0
- @backstage/plugin-cloudbuild@0.2.35-next.0
- @backstage/plugin-code-coverage@0.1.25-next.0
- @backstage/plugin-cost-insights@0.11.20-next.0
- @backstage/plugin-explore@0.3.29-next.0
- @backstage/plugin-gcp-projects@0.3.17-next.0
- @backstage/plugin-github-actions@0.4.35-next.0
- @backstage/plugin-gocd@0.1.4-next.0
- @backstage/plugin-graphiql@0.2.30-next.0
- @backstage/plugin-jenkins@0.5.20-next.0
- @backstage/plugin-kafka@0.2.28-next.0
- @backstage/plugin-kubernetes@0.5.7-next.0
- @backstage/plugin-lighthouse@0.2.37-next.0
- @backstage/plugin-newrelic@0.3.16-next.0
- @backstage/plugin-org@0.4.2-next.0
- @backstage/plugin-pagerduty@0.3.25-next.0
- @backstage/plugin-rollbar@0.3.26-next.0
- @backstage/plugin-sentry@0.3.36-next.0
- @backstage/plugin-shortcuts@0.1.22-next.0
- @backstage/plugin-tech-insights@0.1.8-next.0
- @backstage/plugin-tech-radar@0.5.5-next.0
- @backstage/plugin-techdocs@0.13.3-next.0
- @backstage/plugin-user-settings@0.3.19-next.0
## 0.2.63
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.7
- @backstage/plugin-catalog-react@0.6.13
- @backstage/plugin-code-coverage@0.1.24
- @backstage/plugin-catalog-common@0.1.2
- @backstage/cli@0.13.1
- @backstage/plugin-scaffolder@0.12.1
- @backstage/integration-react@0.1.20
- @backstage/plugin-org@0.4.1
- @backstage/plugin-pagerduty@0.3.24
- @backstage/plugin-catalog-import@0.8.0
- @backstage/core-app-api@0.5.2
- @backstage/plugin-techdocs@0.13.2
- @backstage/app-defaults@0.1.6
- @backstage/plugin-airbrake@0.1.2
- @backstage/plugin-apache-airflow@0.1.5
- @backstage/plugin-api-docs@0.7.1
- @backstage/plugin-azure-devops@0.1.13
- @backstage/plugin-badges@0.2.21
- @backstage/plugin-catalog@0.7.11
- @backstage/plugin-catalog-graph@0.2.9
- @backstage/plugin-circleci@0.2.36
- @backstage/plugin-cloudbuild@0.2.34
- @backstage/plugin-cost-insights@0.11.19
- @backstage/plugin-explore@0.3.28
- @backstage/plugin-gcp-projects@0.3.16
- @backstage/plugin-github-actions@0.4.34
- @backstage/plugin-gocd@0.1.3
- @backstage/plugin-graphiql@0.2.29
- @backstage/plugin-home@0.4.13
- @backstage/plugin-jenkins@0.5.19
- @backstage/plugin-kafka@0.2.27
- @backstage/plugin-kubernetes@0.5.6
- @backstage/plugin-lighthouse@0.2.36
- @backstage/plugin-newrelic@0.3.15
- @backstage/plugin-newrelic-dashboard@0.1.5
- @backstage/plugin-rollbar@0.3.25
- @backstage/plugin-search@0.6.1
- @backstage/plugin-sentry@0.3.35
- @backstage/plugin-shortcuts@0.1.21
- @backstage/plugin-tech-insights@0.1.7
- @backstage/plugin-tech-radar@0.5.4
- @backstage/plugin-todo@0.1.21
- @backstage/plugin-user-settings@0.3.18
## 0.2.63-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.7-next.1
- @backstage/plugin-catalog-react@0.6.13-next.1
- @backstage/plugin-code-coverage@0.1.24-next.1
- @backstage/plugin-catalog-common@0.1.2-next.0
- @backstage/cli@0.13.1-next.1
- @backstage/plugin-scaffolder@0.12.1-next.1
- @backstage/core-app-api@0.5.2-next.0
- @backstage/plugin-techdocs@0.13.2-next.1
- @backstage/plugin-catalog@0.7.11-next.1
- @backstage/app-defaults@0.1.6-next.1
## 0.2.63-next.0
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.8.7-next.0
- @backstage/plugin-org@0.4.1-next.0
- @backstage/plugin-pagerduty@0.3.24-next.0
- @backstage/plugin-catalog-import@0.8.0-next.0
- @backstage/plugin-techdocs@0.13.2-next.0
- @backstage/plugin-scaffolder@0.12.1-next.0
- @backstage/cli@0.13.1-next.0
- @backstage/app-defaults@0.1.6-next.0
- @backstage/integration-react@0.1.20-next.0
- @backstage/plugin-airbrake@0.1.2-next.0
- @backstage/plugin-apache-airflow@0.1.5-next.0
- @backstage/plugin-api-docs@0.7.1-next.0
- @backstage/plugin-azure-devops@0.1.13-next.0
- @backstage/plugin-badges@0.2.21-next.0
- @backstage/plugin-catalog@0.7.11-next.0
- @backstage/plugin-catalog-graph@0.2.9-next.0
- @backstage/plugin-catalog-react@0.6.13-next.0
- @backstage/plugin-circleci@0.2.36-next.0
- @backstage/plugin-cloudbuild@0.2.34-next.0
- @backstage/plugin-code-coverage@0.1.24-next.0
- @backstage/plugin-cost-insights@0.11.19-next.0
- @backstage/plugin-explore@0.3.28-next.0
- @backstage/plugin-gcp-projects@0.3.16-next.0
- @backstage/plugin-github-actions@0.4.34-next.0
- @backstage/plugin-gocd@0.1.3-next.0
- @backstage/plugin-graphiql@0.2.29-next.0
- @backstage/plugin-home@0.4.13-next.0
- @backstage/plugin-jenkins@0.5.19-next.0
- @backstage/plugin-kafka@0.2.27-next.0
- @backstage/plugin-kubernetes@0.5.6-next.0
- @backstage/plugin-lighthouse@0.2.36-next.0
- @backstage/plugin-newrelic@0.3.15-next.0
- @backstage/plugin-newrelic-dashboard@0.1.5-next.0
- @backstage/plugin-rollbar@0.3.25-next.0
- @backstage/plugin-search@0.6.1-next.0
- @backstage/plugin-sentry@0.3.35-next.0
- @backstage/plugin-shortcuts@0.1.21-next.0
- @backstage/plugin-tech-insights@0.1.7-next.0
- @backstage/plugin-tech-radar@0.5.4-next.0
- @backstage/plugin-todo@0.1.21-next.0
- @backstage/plugin-user-settings@0.3.18-next.0
## 0.2.62
### Patch Changes
+46 -44
View File
@@ -1,54 +1,56 @@
{
"name": "example-app",
"version": "0.2.62",
"version": "0.2.64",
"private": true,
"bundled": true,
"dependencies": {
"@backstage/app-defaults": "^0.1.5",
"@backstage/app-defaults": "^0.1.7",
"@backstage/catalog-model": "^0.9.10",
"@backstage/cli": "^0.13.0",
"@backstage/core-app-api": "^0.5.1",
"@backstage/core-components": "^0.8.6",
"@backstage/cli": "^0.13.2",
"@backstage/core-app-api": "^0.5.2",
"@backstage/core-components": "^0.8.8",
"@backstage/core-plugin-api": "^0.6.0",
"@backstage/integration-react": "^0.1.19",
"@backstage/plugin-airbrake": "^0.1.1",
"@backstage/plugin-api-docs": "^0.7.0",
"@backstage/plugin-azure-devops": "^0.1.12",
"@backstage/plugin-apache-airflow": "^0.1.4",
"@backstage/plugin-badges": "^0.2.20",
"@backstage/plugin-catalog": "^0.7.10",
"@backstage/plugin-catalog-graph": "^0.2.8",
"@backstage/plugin-catalog-import": "^0.7.10",
"@backstage/plugin-catalog-react": "^0.6.12",
"@backstage/plugin-circleci": "^0.2.35",
"@backstage/plugin-cloudbuild": "^0.2.33",
"@backstage/plugin-code-coverage": "^0.1.23",
"@backstage/plugin-cost-insights": "^0.11.18",
"@backstage/plugin-explore": "^0.3.27",
"@backstage/plugin-gcp-projects": "^0.3.15",
"@backstage/plugin-github-actions": "^0.4.33",
"@backstage/plugin-gocd": "^0.1.2",
"@backstage/plugin-graphiql": "^0.2.28",
"@backstage/plugin-home": "^0.4.12",
"@backstage/plugin-jenkins": "^0.5.18",
"@backstage/plugin-kafka": "^0.2.26",
"@backstage/plugin-kubernetes": "^0.5.5",
"@backstage/plugin-lighthouse": "^0.2.35",
"@backstage/plugin-newrelic": "^0.3.14",
"@backstage/plugin-newrelic-dashboard": "^0.1.4",
"@backstage/plugin-org": "^0.4.0",
"@backstage/plugin-pagerduty": "0.3.23",
"@backstage/plugin-rollbar": "^0.3.24",
"@backstage/plugin-scaffolder": "^0.12.0",
"@backstage/plugin-search": "^0.6.0",
"@backstage/plugin-sentry": "^0.3.34",
"@backstage/plugin-shortcuts": "^0.1.20",
"@backstage/plugin-tech-radar": "^0.5.3",
"@backstage/plugin-techdocs": "^0.13.1",
"@backstage/plugin-todo": "^0.1.20",
"@backstage/plugin-user-settings": "^0.3.17",
"@backstage/integration-react": "^0.1.21",
"@backstage/plugin-airbrake": "^0.1.3",
"@backstage/plugin-api-docs": "^0.7.2",
"@backstage/plugin-azure-devops": "^0.1.14",
"@backstage/plugin-apache-airflow": "^0.1.6",
"@backstage/plugin-badges": "^0.2.22",
"@backstage/plugin-catalog": "^0.7.12",
"@backstage/plugin-catalog-common": "^0.1.2",
"@backstage/plugin-catalog-graph": "^0.2.10",
"@backstage/plugin-catalog-import": "^0.8.1",
"@backstage/plugin-catalog-react": "^0.6.14",
"@backstage/plugin-circleci": "^0.2.37",
"@backstage/plugin-cloudbuild": "^0.2.35",
"@backstage/plugin-code-coverage": "^0.1.25",
"@backstage/plugin-cost-insights": "^0.11.20",
"@backstage/plugin-explore": "^0.3.29",
"@backstage/plugin-gcp-projects": "^0.3.17",
"@backstage/plugin-github-actions": "^0.4.35",
"@backstage/plugin-gocd": "^0.1.4",
"@backstage/plugin-graphiql": "^0.2.30",
"@backstage/plugin-home": "^0.4.14",
"@backstage/plugin-jenkins": "^0.5.20",
"@backstage/plugin-kafka": "^0.2.28",
"@backstage/plugin-kubernetes": "^0.5.7",
"@backstage/plugin-lighthouse": "^0.2.37",
"@backstage/plugin-newrelic": "^0.3.16",
"@backstage/plugin-newrelic-dashboard": "^0.1.6",
"@backstage/plugin-org": "^0.4.2-next.0",
"@backstage/plugin-pagerduty": "0.3.25",
"@backstage/plugin-permission-react": "^0.3.0",
"@backstage/plugin-rollbar": "^0.3.26",
"@backstage/plugin-scaffolder": "^0.12.2",
"@backstage/plugin-search": "^0.6.2",
"@backstage/plugin-sentry": "^0.3.36",
"@backstage/plugin-shortcuts": "^0.1.22",
"@backstage/plugin-tech-radar": "^0.5.5",
"@backstage/plugin-techdocs": "^0.13.3",
"@backstage/plugin-todo": "^0.2.0",
"@backstage/plugin-user-settings": "^0.3.19",
"@backstage/search-common": "^0.2.2",
"@backstage/plugin-tech-insights": "^0.1.6",
"@backstage/plugin-tech-insights": "^0.1.8",
"@backstage/theme": "^0.2.14",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
@@ -70,7 +72,7 @@
},
"devDependencies": {
"@backstage/plugin-permission-react": "^0.3.0",
"@backstage/test-utils": "^0.2.3",
"@backstage/test-utils": "^0.2.4",
"@rjsf/core": "^3.2.1",
"@testing-library/cypress": "^8.0.2",
"@testing-library/jest-dom": "^5.10.1",
+7 -1
View File
@@ -86,6 +86,8 @@ import * as plugins from './plugins';
import { techDocsPage } from './components/techdocs/TechDocsPage';
import { ApacheAirflowPage } from '@backstage/plugin-apache-airflow';
import { PermissionedRoute } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
const app = createApp({
apis,
@@ -140,7 +142,11 @@ const routes = (
>
{entityPage}
</Route>
<Route path="/catalog-import" element={<CatalogImportPage />} />
<PermissionedRoute
path="/catalog-import"
permission={catalogEntityCreatePermission}
element={<CatalogImportPage />}
/>
<Route
path="/catalog-graph"
element={
+2 -7
View File
@@ -34,10 +34,7 @@ import {
Settings as SidebarSettings,
UserSettingsSignInAvatar,
} from '@backstage/plugin-user-settings';
import {
SidebarSearchModal,
SearchContextProvider,
} from '@backstage/plugin-search';
import { SidebarSearchModal } from '@backstage/plugin-search';
import { Shortcuts } from '@backstage/plugin-shortcuts';
import {
Sidebar,
@@ -89,9 +86,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
<Sidebar>
<SidebarLogo />
<SidebarGroup label="Search" icon={<SearchIcon />} to="/search">
<SearchContextProvider>
<SidebarSearchModal />
</SearchContextProvider>
<SidebarSearchModal />
</SidebarGroup>
<SidebarDivider />
<SidebarGroup label="Menu" icon={<MenuIcon />}>
+47
View File
@@ -1,5 +1,52 @@
# @backstage/backend-common
## 0.10.7
### Patch Changes
- 2441d1cf59: chore(deps): bump `knex` from 0.95.6 to 1.0.2
This also replaces `sqlite3` with `@vscode/sqlite3` 5.0.7
- 599f3dfa83: chore(deps-dev): bump `@types/concat-stream` from 1.6.1 to 2.0.0
- c3868458d8: Removed unnecessary `get-port` dependency
- 04398e946e: Bump `selfsigned` to 2.0.0
## 0.10.7-next.0
### Patch Changes
- 2441d1cf59: chore(deps): bump `knex` from 0.95.6 to 1.0.2
This also replaces `sqlite3` with `@vscode/sqlite3` 5.0.7
- 599f3dfa83: chore(deps-dev): bump `@types/concat-stream` from 1.6.1 to 2.0.0
- c3868458d8: Removed unnecessary `get-port` dependency
## 0.10.6
### Patch Changes
- 50d039577a: Added a `Context` type for the backend, that can propagate an abort signal, a
deadline, and contextual values through the call stack. The main entrypoint is
the `Contexts` utility class that provides a root context creator and commonly
used decorators.
These are marked as `@alpha` for now, and are therefore only accessible via
`@backstage/backend-common/alpha`.
## 0.10.6-next.0
### Patch Changes
- 50d039577a: Added a `Context` type for the backend, that can propagate an abort signal, a
deadline, and contextual values through the call stack. The main entrypoint is
the `Contexts` utility class that provides a root context creator and commonly
used decorators.
These are marked as `@alpha` for now, and are therefore only accessible via
`@backstage/backend-common/alpha`.
## 0.10.5
### Patch Changes
+26 -1
View File
@@ -6,6 +6,7 @@
/// <reference types="node" />
/// <reference types="webpack-env" />
import { AbortController as AbortController_2 } from 'node-abort-controller';
import { AbortSignal as AbortSignal_2 } from 'node-abort-controller';
import { AwsS3Integration } from '@backstage/integration';
import { AzureIntegration } from '@backstage/integration';
@@ -13,6 +14,7 @@ import { BitbucketIntegration } from '@backstage/integration';
import { Config } from '@backstage/config';
import cors from 'cors';
import Docker from 'dockerode';
import { Duration } from 'luxon';
import { ErrorRequestHandler } from 'express';
import express from 'express';
import { GithubCredentialsProvider } from '@backstage/integration';
@@ -145,6 +147,29 @@ export interface ContainerRunner {
runContainer(opts: RunContainerOptions): Promise<void>;
}
// @alpha
export interface Context {
readonly abortSignal: AbortSignal_2;
readonly deadline: Date | undefined;
value<T = unknown>(key: string): T | undefined;
}
// @alpha
export class Contexts {
static root(): Context;
static withAbort(
parentCtx: Context,
source: AbortController_2 | AbortSignal_2,
): Context;
static withTimeoutDuration(parentCtx: Context, timeout: Duration): Context;
static withTimeoutMillis(parentCtx: Context, timeout: number): Context;
static withValue(
parentCtx: Context,
key: string,
value: unknown | ((previous: unknown | undefined) => unknown),
): Context;
}
// @public @deprecated
export const createDatabase: typeof createDatabaseClient;
@@ -152,7 +177,7 @@ export const createDatabase: typeof createDatabaseClient;
export function createDatabaseClient(
dbConfig: Config,
overrides?: Partial<Knex.Config>,
): Knex<any, unknown[]>;
): Knex<any, Record<string, any>[]>;
// @public
export function createRootLogger(
+14 -11
View File
@@ -1,14 +1,15 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.10.5",
"version": "0.10.7",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
"types": "dist/index.d.ts",
"alphaTypes": "dist/index.alpha.d.ts"
},
"homepage": "https://backstage.io",
"repository": {
@@ -21,7 +22,7 @@
],
"license": "Apache-2.0",
"scripts": {
"build": "backstage-cli build --outputs cjs,types",
"build": "backstage-cli build --experimental-type-build --outputs cjs,types",
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"prepack": "backstage-cli prepack",
@@ -41,6 +42,7 @@
"@types/cors": "^2.8.6",
"@types/dockerode": "^3.3.0",
"@types/express": "^4.17.6",
"@types/luxon": "^2.0.4",
"archiver": "^5.0.2",
"aws-sdk": "^2.840.0",
"compression": "^1.7.4",
@@ -56,16 +58,17 @@
"jose": "^1.27.1",
"keyv": "^4.0.3",
"keyv-memcache": "^1.2.5",
"knex": "^0.95.1",
"knex": "^1.0.2",
"lodash": "^4.17.21",
"logform": "^2.3.2",
"luxon": "^2.0.2",
"minimatch": "^3.0.4",
"minimist": "^1.2.5",
"morgan": "^1.10.0",
"node-abort-controller": "^3.0.1",
"node-fetch": "^2.6.1",
"node-fetch": "^2.6.7",
"raw-body": "^2.4.1",
"selfsigned": "^1.10.7",
"selfsigned": "^2.0.0",
"stoppable": "^1.1.0",
"tar": "^6.1.2",
"unzipper": "^0.10.11",
@@ -81,11 +84,11 @@
}
},
"devDependencies": {
"@backstage/cli": "^0.13.0",
"@backstage/test-utils": "^0.2.3",
"@backstage/cli": "^0.13.2",
"@backstage/test-utils": "^0.2.4",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
"@types/concat-stream": "^1.6.0",
"@types/concat-stream": "^2.0.0",
"@types/fs-extra": "^9.0.3",
"@types/http-errors": "^1.6.3",
"@types/minimist": "^1.2.0",
@@ -98,7 +101,6 @@
"@types/unzipper": "^0.10.3",
"@types/webpack-env": "^1.15.2",
"aws-sdk-mock": "^5.2.1",
"get-port": "^5.1.1",
"http-errors": "^2.0.0",
"jest": "^26.0.1",
"mock-fs": "^5.1.0",
@@ -109,7 +111,8 @@
},
"files": [
"dist",
"config.d.ts"
"config.d.ts",
"alpha"
],
"configSchema": "config.d.ts"
}
@@ -0,0 +1,345 @@
/*
* Copyright 2021 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.
*/
import { AbortController } from 'node-abort-controller';
import { AbortContext } from './AbortContext';
import { RootContext } from './RootContext';
describe('AbortContext', () => {
afterEach(() => {
jest.useRealTimers();
});
describe('forTimeoutMillis', () => {
it('can abort on a timeout', async () => {
jest.useFakeTimers();
const timeout = 200;
const deadline = Date.now() + timeout;
const root = new RootContext();
const child = AbortContext.forTimeoutMillis(root, timeout);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(child.abortSignal.aborted).toBe(false);
expect(Math.abs(+child.deadline! - deadline)).toBeLessThan(50);
expect(childListener).toBeCalledTimes(0);
jest.advanceTimersByTime(timeout + 1);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(1);
});
it('results in minimum deadline when parent triggers sooner', async () => {
jest.useFakeTimers();
const parentTimeout = 200;
const childTimeout = 300;
const parentDeadline = Date.now() + parentTimeout;
const childDeadline = parentDeadline; // clamped
const root = new RootContext();
const parent = AbortContext.forTimeoutMillis(root, parentTimeout);
const parentListener = jest.fn();
parent.abortSignal.addEventListener('abort', parentListener);
const child = AbortContext.forTimeoutMillis(parent, childTimeout);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(false);
expect(Math.abs(+parent.deadline! - parentDeadline)).toBeLessThan(50);
expect(Math.abs(+child.deadline! - childDeadline)).toBeLessThan(50);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(0);
jest.advanceTimersByTime(parentTimeout + 1);
expect(parent.abortSignal.aborted).toBe(true);
expect(child.abortSignal.aborted).toBe(true);
expect(parentListener).toBeCalledTimes(1);
expect(childListener).toBeCalledTimes(1);
});
it('results in minimum deadline when child triggers sooner', async () => {
jest.useFakeTimers();
const parentTimeout = 300;
const childTimeout = 200;
const parentDeadline = Date.now() + parentTimeout;
const childDeadline = Date.now() + childTimeout;
const root = new RootContext();
const parent = AbortContext.forTimeoutMillis(root, parentTimeout);
const parentListener = jest.fn();
parent.abortSignal.addEventListener('abort', parentListener);
const child = AbortContext.forTimeoutMillis(parent, childTimeout);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(false);
expect(Math.abs(+parent.deadline! - parentDeadline)).toBeLessThan(50);
expect(Math.abs(+child.deadline! - childDeadline)).toBeLessThan(50);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(0);
jest.advanceTimersByTime(childTimeout + 1);
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(true);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(1);
jest.advanceTimersByTime(parentTimeout - childTimeout + 1);
expect(parent.abortSignal.aborted).toBe(true);
expect(child.abortSignal.aborted).toBe(true);
expect(parentListener).toBeCalledTimes(1);
expect(childListener).toBeCalledTimes(1);
});
it('child carries over parent signal state if parent was already aborted and had no deadline', async () => {
jest.useFakeTimers();
const childTimeout = 200;
const childDeadline = Date.now() + childTimeout;
const root = new RootContext();
const parentController = new AbortController();
const parent = AbortContext.forSignal(root, parentController.signal);
parentController.abort();
const child = AbortContext.forTimeoutMillis(parent, childTimeout);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(0);
expect(Math.abs(+child.deadline! - childDeadline)).toBeLessThan(50);
jest.advanceTimersByTime(childTimeout + 1);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(0); // still
});
it('child carries over parent signal state if parent was already aborted and had a deadline', async () => {
jest.useFakeTimers();
const first = new RootContext();
const secondController = new AbortController();
const second = AbortContext.forSignal(first, secondController.signal);
secondController.abort();
const third = AbortContext.forTimeoutMillis(second, 200);
const fourth = AbortContext.forTimeoutMillis(third, 300);
expect(third.abortSignal.aborted).toBe(true);
expect(fourth.abortSignal.aborted).toBe(true);
expect(Math.abs(+fourth.deadline! - Date.now() - 200)).toBeLessThan(50);
});
});
describe('forController', () => {
it('signals child when parent is aborted', () => {
const root = new RootContext();
const parentController = new AbortController();
const parent = AbortContext.forController(root, parentController);
const parentListener = jest.fn();
parent.abortSignal.addEventListener('abort', parentListener);
const childController = new AbortController();
const child = AbortContext.forController(parent, childController);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(false);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(0);
parentController.abort();
expect(parent.abortSignal.aborted).toBe(true);
expect(child.abortSignal.aborted).toBe(true);
expect(parentListener).toBeCalledTimes(1);
expect(childListener).toBeCalledTimes(1);
});
it('does not signal parent when child is aborted', async () => {
const root = new RootContext();
const parentController = new AbortController();
const parent = AbortContext.forController(root, parentController);
const parentListener = jest.fn();
parent.abortSignal.addEventListener('abort', parentListener);
const childController = new AbortController();
const child = AbortContext.forController(parent, childController);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(false);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(0);
childController.abort();
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(true);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(1);
});
it('child carries over parent signal state if parent was already aborted', async () => {
const root = new RootContext();
const parentController = new AbortController();
const parent = AbortContext.forController(root, parentController);
parentController.abort();
const childController = new AbortController();
const child = AbortContext.forController(parent, childController);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(parent.abortSignal.aborted).toBe(true);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(0);
childController.abort();
expect(parent.abortSignal.aborted).toBe(true);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(0);
});
it('child carries over given signal state if it was already aborted', async () => {
const root = new RootContext();
const childController = new AbortController();
childController.abort();
const child = AbortContext.forController(root, childController);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(0);
});
});
describe('forSignal', () => {
it('signals child when parent is aborted', async () => {
const root = new RootContext();
const parentController = new AbortController();
const parent = AbortContext.forSignal(root, parentController.signal);
const parentListener = jest.fn();
parent.abortSignal.addEventListener('abort', parentListener);
const childController = new AbortController();
const child = AbortContext.forSignal(parent, childController.signal);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(false);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(0);
parentController.abort();
expect(parent.abortSignal.aborted).toBe(true);
expect(child.abortSignal.aborted).toBe(true);
expect(parentListener).toBeCalledTimes(1);
expect(childListener).toBeCalledTimes(1);
});
it('does not signal parent when child is aborted', async () => {
const root = new RootContext();
const parentController = new AbortController();
const parent = AbortContext.forSignal(root, parentController.signal);
const parentListener = jest.fn();
parent.abortSignal.addEventListener('abort', parentListener);
const childController = new AbortController();
const child = AbortContext.forSignal(parent, childController.signal);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(false);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(0);
childController.abort();
expect(parent.abortSignal.aborted).toBe(false);
expect(child.abortSignal.aborted).toBe(true);
expect(parentListener).toBeCalledTimes(0);
expect(childListener).toBeCalledTimes(1);
});
it('child carries over parent signal state if parent was already aborted', async () => {
const root = new RootContext();
const parentController = new AbortController();
const parent = AbortContext.forSignal(root, parentController.signal);
parentController.abort();
const childController = new AbortController();
const child = AbortContext.forSignal(parent, childController.signal);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(parent.abortSignal.aborted).toBe(true);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(0);
childController.abort();
expect(parent.abortSignal.aborted).toBe(true);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(0);
});
it('child carries over given signal state if it was already aborted', async () => {
const root = new RootContext();
const childController = new AbortController();
childController.abort();
const child = AbortContext.forSignal(root, childController.signal);
const childListener = jest.fn();
child.abortSignal.addEventListener('abort', childListener);
expect(child.abortSignal.aborted).toBe(true);
expect(childListener).toBeCalledTimes(0);
});
});
});
@@ -0,0 +1,133 @@
/*
* Copyright 2021 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.
*/
import { AbortController, AbortSignal } from 'node-abort-controller';
import { Context } from './types';
/**
* A context that implements various abort related functionality.
*/
export class AbortContext implements Context {
/**
* Abort either when the parent aborts, or after the given timeout has
* expired.
*
* @param ctx - The parent context
* @param timeout - A timeout value, in milliseconds
* @returns A new context
*/
static forTimeoutMillis(ctx: Context, timeout: number): Context {
const desiredDeadline = new Date(Date.now() + timeout);
const actualDeadline =
ctx.deadline && ctx.deadline < desiredDeadline
? ctx.deadline
: desiredDeadline;
if (ctx.abortSignal.aborted) {
if (ctx.deadline && desiredDeadline === actualDeadline) {
return ctx;
}
return new AbortContext(ctx, ctx.abortSignal, actualDeadline);
}
const controller = new AbortController();
const timeoutHandle = setTimeout(abort, timeout);
ctx.abortSignal.addEventListener('abort', abort);
function abort() {
ctx.abortSignal.removeEventListener('abort', abort);
clearTimeout(timeoutHandle!);
controller.abort();
}
return new AbortContext(ctx, controller.signal, actualDeadline);
}
/**
* Abort either when the parent aborts, or when the given controller is
* triggered.
*
* @remarks
*
* If you have access to the controller, this function is more efficient than
* {@link AbortContext#forSignal}.
*
* @param ctx - The parent context
* @param controller - An abort controller
* @returns A new context
*/
static forController(ctx: Context, controller: AbortController): Context {
// Already aborted context / signal are fine to reuse as-is
if (ctx.abortSignal.aborted) {
return ctx;
} else if (controller.signal.aborted) {
return new AbortContext(ctx, controller.signal, ctx.deadline);
}
function abort() {
ctx.abortSignal.removeEventListener('abort', abort);
controller.abort();
}
ctx.abortSignal.addEventListener('abort', abort);
return new AbortContext(ctx, controller.signal, ctx.deadline);
}
/**
* Abort either when the parent aborts, or when the given signal is triggered.
*
* @remarks
*
* If you have access to the controller and not just the signal,
* {@link AbortContext#forController} is slightly more efficient to use.
*
* @param ctx - The parent context
* @param signal - An abort signal
* @returns A new context
*/
static forSignal(ctx: Context, signal: AbortSignal): Context {
// Already aborted context / signal are fine to reuse as-is
if (ctx.abortSignal.aborted) {
return ctx;
} else if (signal.aborted) {
return new AbortContext(ctx, signal, ctx.deadline);
}
const controller = new AbortController();
function abort() {
ctx.abortSignal.removeEventListener('abort', abort);
signal.removeEventListener('abort', abort);
controller.abort();
}
ctx.abortSignal.addEventListener('abort', abort);
signal.addEventListener('abort', abort);
return new AbortContext(ctx, controller.signal, ctx.deadline);
}
private constructor(
private readonly parent: Context,
readonly abortSignal: AbortSignal,
readonly deadline: Date | undefined,
) {}
value<T = unknown>(key: string): T | undefined {
return this.parent.value(key);
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2021 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.
*/
import { Duration } from 'luxon';
import { AbortController } from 'node-abort-controller';
import { Contexts } from './Contexts';
describe('Contexts', () => {
afterEach(() => {
jest.useRealTimers();
});
describe('root', () => {
it('can create a root', () => {
const ctx = Contexts.root();
expect(ctx.abortSignal).toBeDefined();
expect(ctx.deadline).toBeUndefined();
});
});
describe('setAbort', () => {
it('works for controllers', () => {
const controller = new AbortController();
const parent = Contexts.root();
const child = Contexts.withAbort(parent, controller);
expect(child.abortSignal.aborted).toBe(false);
controller.abort();
expect(child.abortSignal.aborted).toBe(true);
});
it('works for signals', () => {
const controller = new AbortController();
const parent = Contexts.root();
const child = Contexts.withAbort(parent, controller.signal);
expect(child.abortSignal.aborted).toBe(false);
controller.abort();
expect(child.abortSignal.aborted).toBe(true);
});
});
describe('setTimeoutDuration', () => {
it('works', () => {
jest.useFakeTimers();
const parent = Contexts.root();
const child = Contexts.withTimeoutDuration(
parent,
Duration.fromMillis(200),
);
expect(child.abortSignal.aborted).toBe(false);
jest.advanceTimersByTime(100);
expect(child.abortSignal.aborted).toBe(false);
jest.advanceTimersByTime(101);
expect(child.abortSignal.aborted).toBe(true);
});
});
describe('setTimeoutMillis', () => {
it('works', () => {
jest.useFakeTimers();
const parent = Contexts.root();
const child = Contexts.withTimeoutMillis(parent, 200);
expect(child.abortSignal.aborted).toBe(false);
jest.advanceTimersByTime(100);
expect(child.abortSignal.aborted).toBe(false);
jest.advanceTimersByTime(101);
expect(child.abortSignal.aborted).toBe(true);
});
});
describe('setValue', () => {
it('works', () => {
const parent = Contexts.root();
const child = Contexts.withValue(parent, 'k', 'v');
expect(child.value('k')).toBe('v');
});
});
});
@@ -0,0 +1,114 @@
/*
* Copyright 2021 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.
*/
import { Duration } from 'luxon';
import { AbortController, AbortSignal } from 'node-abort-controller';
import { AbortContext } from './AbortContext';
import { RootContext } from './RootContext';
import { Context } from './types';
import { ValueContext } from './ValueContext';
/**
* Common context decorators.
*
* @alpha
*/
export class Contexts {
/**
* Creates a root context.
*
* @remarks
*
* This should normally only be called near the root of an application. The
* created context is meant to be passed down into deeper levels, which may or
* may not make derived contexts out of it.
*/
static root(): Context {
return new RootContext();
}
/**
* Creates a derived context, which signals to abort operations either when
* any parent context signals, or when the given source is aborted.
*
* @remarks
*
* If the parent context was already aborted, then it is returned as-is.
*
* If the given source was already aborted, then a new already-aborted context
* is returned.
*
* @param parentCtx - A parent context that shall be used as a base
* @param source - An abort controller or signal that you intend to perhaps
* trigger at some later point in time.
* @returns A new {@link Context}
*/
static withAbort(
parentCtx: Context,
source: AbortController | AbortSignal,
): Context {
return 'aborted' in source
? AbortContext.forSignal(parentCtx, source)
: AbortContext.forController(parentCtx, source);
}
/**
* Creates a derived context, which signals to abort operations either when
* any parent context signals, or when the given amount of time has passed.
* This may affect the deadline.
*
* @param parentCtx - A parent context that shall be used as a base
* @param timeout - The duration of time, after which the derived context will
* signal to abort.
* @returns A new {@link Context}
*/
static withTimeoutDuration(parentCtx: Context, timeout: Duration): Context {
return AbortContext.forTimeoutMillis(parentCtx, timeout.as('milliseconds'));
}
/**
* Creates a derived context, which signals to abort operations either when
* any parent context signals, or when the given amount of time has passed.
* This may affect the deadline.
*
* @param parentCtx - A parent context that shall be used as a base
* @param timeout - The number of milliseconds, after which the derived
* context will signal to abort.
* @returns A new {@link Context}
*/
static withTimeoutMillis(parentCtx: Context, timeout: number): Context {
return AbortContext.forTimeoutMillis(parentCtx, timeout);
}
/**
* Creates a derived context, which has a specific key-value pair set as well
* as all key-value pairs that were set in the original context.
*
* @param parentCtx - A parent context that shall be used as a base
* @param key - The key of the value to set
* @param value - The value, or a function that accepts the previous value (or
* undefined if not set yet) and computes the new value
* @returns A new {@link Context}
*/
static withValue(
parentCtx: Context,
key: string,
value: unknown | ((previous: unknown | undefined) => unknown),
): Context {
const v = typeof value === 'function' ? value(parentCtx.value(key)) : value;
return ValueContext.forConstantValue(parentCtx, key, v);
}
}

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