Merge branch 'master' into scaffolder/EntityPicker-arbitrary-values

This commit is contained in:
Jason Nguyen
2021-12-21 17:50:16 -07:00
committed by GitHub
539 changed files with 9860 additions and 3498 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search': patch
---
Add Optional Props to Override Icon for SidebarSearch and SidebarSearchModal Component
-5
View File
@@ -1,5 +0,0 @@
---
'@backstage/plugin-github-actions': patch
---
Show empty state only when workflow API call has completed
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/app-defaults': patch
'@backstage/core-app-api': patch
'@backstage/core-plugin-api': patch
---
Add `FetchApi` and related `fetchApiRef` which implement fetch, with an added Backstage token header when available.
+22
View File
@@ -0,0 +1,22 @@
---
'@backstage/backend-common': patch
---
Fixed bug in backend-common to allow passing of remote option in order to enable passing remote url in --config option. The remote option should be passed along with reloadIntervalSeconds from packages/backend/src/index.ts (Updated the file as well)
These changes are needed in `packages/backend/src/index.ts` if remote URLs are desired to be passed in --config option and read and watch remote files for config.
```diff
@@ -86,7 +86,11 @@ async function main() {
const config = await loadBackendConfig({
argv: process.argv,
logger,
+ remote: {
+ reloadIntervalSeconds: 60 * 10 // Check remote config changes every 10 minutes. Change to your desired interval in seconds
+ }
});
+
const createEnv = makeCreateEnv(config);
const healthcheckEnv = useHotMemoize(module, () => createEnv('healthcheck'));
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/config-loader': patch
---
In case remote.reloadIntervalSeconds is passed, it must be a valid positive value
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-user-settings': patch
---
Fix undefined identity bug in UserSettingsProfileCard caused by using deprecated methods of the IdentityApi
+11
View File
@@ -0,0 +1,11 @@
---
'@backstage/core-plugin-api': minor
---
**BREAKING CHANGE** The `StorageApi` has received several updates that fills in gaps for some use-cases and makes it easier to avoid mistakes:
- The `StorageValueChange` type has been renamed to `StorageValueSnapshot`, the `newValue` property has been renamed to `value`, the stored value type has been narrowed to `JsonValue`, and it has received a new `presence` property that is `'unknown'`, `'absent'`, or `'present'`.
- The `get` method has been deprecated in favor of a new `snapshot` method, which returns a `StorageValueSnapshot`.
- The `observe$` method has had its contract changed. It should now emit values when the `presence` of a key changes, this may for example happen when remotely stored values are requested on page load and the presence switches from `'unknown'` to either `'absent'` or `'present'`.
The above changes have been made with deprecations in place to maintain much of the backwards compatibility for consumers of the `StorageApi`. The only breaking change is the narrowing of the stored value type, which may in some cases require the addition of an explicit type parameter to the `get` and `observe$` methods.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-config-schema': patch
'@backstage/plugin-scaffolder': patch
---
Fix a small browser console warning
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
added useOwnedEntities hook to get the list of entities of the logged-in user
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-kubernetes': minor
---
Includes `KubernetesBackendClient` in the export to allow developers to use it externally.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Added peerPluginDependencies option to experimentalInstallationRecipe for install command to install plugins it depends on.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-radar': minor
---
Add new property to enable open links in a new window/tab
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-org': patch
---
Fixed bug in OwnershipCard component where text wasn't correctly pluralized
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-rails': patch
---
Add new options to rails new (force and skipTests)
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-common': minor
---
Create catalog-common and add catalog permissions.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-bazaar': patch
'@backstage/plugin-bazaar-backend': patch
---
made the linkage between a Bazaar project to a catalog Entity optional
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-app-api': minor
---
Updated `WebStorageApi` to reflect the `StorageApi` changes in `@backstage/core-plugin-api`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/test-utils': minor
---
Updated `MockStorageApi` to reflect the `StorageApi` changes in `@backstage/core-plugin-api`.
+25
View File
@@ -0,0 +1,25 @@
---
'@backstage/plugin-catalog': patch
---
Deprecated the `CatalogClientWrapper` class.
The default implementation of `catalogApiRef` that this plugin exposes, is now powered by the new `fetchApiRef`. The default implementation of _that_ API, in turn, has the ability to inject the user's Backstage token in requests in a similar manner to what the deprecated `CatalogClientWrapper` used to do. The latter has therefore been taken out of the default catalog API implementation.
If you use a custom `fetchApiRef` implementation that does NOT issue tokens, or use a custom `catalogApiRef` implementation which does NOT use the default `fetchApiRef`, you can still for some time wrap your catalog API in this class to get back the old behavior:
```ts
// Add this to your packages/app/src/plugins.ts if you want to get back the old
// catalog client behavior:
createApiFactory({
api: catalogApiRef,
deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef },
factory: ({ discoveryApi, identityApi }) =>
new CatalogClientWrapper({
client: new CatalogClient({ discoveryApi }),
identityApi,
}),
}),
```
But do consider migrating to making use of the `fetchApiRef` as soon as convenient, since the wrapper class will be removed in a future release.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-client': patch
---
Add the ability to supply a custom `fetchApi`. In the default frontend app setup, this will use the `fetchApiRef` implementation.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/config-loader': minor
---
Removed deprecated option `env` from `LoadConfigOptions` and associated tests
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-newrelic-dashboard': patch
---
Created a New Plugin , which imports dashboard links and snapshots from New Relic
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-home': patch
---
Fix undefined identity bug in `WelcomeTitle` caused by using deprecated methods of the IdentityApi
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/test-utils': minor
---
Removed deprecated `Keyboard` class which has been superseded by `@testing-library/user-event#userEvent`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-rollbar-backend': patch
---
Bump `axios`
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/core-app-api': minor
---
- Removed deprecated definition `createApp` from `@backstage/core-app-api` which has been replaced by `@backstage/app-defaults#createApp`
- Removed deprecated type `BackstagePluginWithAnyOutput`
- Removed deprecated constructors for `GithubAuth`, `OAuth2`, and `SamlAuth` as the `create` method should be used instead
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/core-plugin-api': minor
---
- Removed deprecated option `description` from `ApiRefConfig`
- Removed descriptions from all plugin API refs
- Removed deprecated parameters `path`, `icon`, and `title` in `createRouteRef`
- Removed deprecated types `Error` and `ErrorContext` from `ErrorApi`
+30
View File
@@ -0,0 +1,30 @@
---
'@backstage/create-app': patch
---
The `index.html` template of the app has been updated to use the new `config` global provided by the Backstage CLI.
To apply this change to an existing app, make the following changes to `packages/app/public/index.html`:
```diff
- <title><%= app.title %></title>
+ <title><%= config.getString('app.title') %></title>
```
```diff
- <% if (app.googleAnalyticsTrackingId && typeof app.googleAnalyticsTrackingId === 'string') { %>
+ <% if (config.has('app.googleAnalyticsTrackingId')) { %>
<script
async
- src="https://www.googletagmanager.com/gtag/js?id=<%= app.googleAnalyticsTrackingId %>"
+ src="https://www.googletagmanager.com/gtag/js?id=<%= config.getString('app.googleAnalyticsTrackingId') %>"
></script>
```
```diff
- gtag('config', '<%= app.googleAnalyticsTrackingId %>');
+ gtag(
+ 'config',
+ '<%= config.getString("app.googleAnalyticsTrackingId") %>',
+ );
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/test-utils': minor
---
Removed deprecated `msw` definition which was replaced by calling `setupRequestMockHandlers` directly
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/config-loader': minor
---
Removed deprecated option `configPaths` as it has been superseded by `configTargets`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Added OwnedEntityPicker field which displays Owned Entities in options
+15
View File
@@ -0,0 +1,15 @@
---
'@backstage/cli': patch
---
The frontend configuration is now available as a `config` global during templating of the `index.html` file. This allows for much more flexibility as the values available during templating is not longer hardcoded to a fixed set of values.
For example, to access the app title, you would now do the following:
```html
<title><%= config.getString('app.title') %></title>
```
Along with this change, usage of the existing `app.<key>` values has been deprecated and will be removed in a future release. The general pattern for migrating existing usage is to replace `<%= app.<key> %>` with `<%= config.getString('app.<key>') %>`, although in some cases you may need to use for example `config.has('app.<key>')` or `config.getOptionalString('app.<key>')` instead.
The [`@backstage/create-app` changelog](https://github.com/backstage/backstage/blob/master/packages/create-app/CHANGELOG.md#049) also contains more details how to migrate existing usage.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-auth-backend': patch
---
Fixed the fallback identity population to correctly generate an entity reference for `userEntityRef` if no token is provided.
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/app-defaults': patch
'@backstage/core-app-api': minor
'@backstage/core-plugin-api': minor
---
- Removed deprecation configuration option `theme` from `AppTheme` of the `AppThemeApi`
- Removed reference to `theme` in the `app-defaults` default `AppTheme`
- Removed logic in `AppThemeProvider` that creates `ThemeProvider` from `appTheme.theme`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-client': patch
---
Add support for passing paging parameters to the getEntities call of the catalog client
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-search-backend': minor
---
Search result location filtering
This change introduces a filter for search results based on their location protocol. The intention is to filter out unsafe or
malicious values before they can be consumed by the frontend. By default locations must be http/https URLs (or paths).
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Do not `setState` when unmounted in `OverflowTooltip`
+5
View File
@@ -0,0 +1,5 @@
---
'embedded-techdocs-app': patch
---
The `index.html` template was updated to use the new `config` global.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs-backend': patch
---
Fixed a bug preventing cache from being enabled in TechDocs "recommended" deployment mode.
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/core-components': patch
'@backstage/plugin-scaffolder': patch
---
In @backstage/plugin-scaffolder - When user will have one option available in hostUrl or owner - autoselect and select component should be readonly.
in @backstage/core-components - Select component has extended API with few more props: native : boolean, disabled: boolean. native - if set to true - Select component will use native browser select picker (not rendered by Material UI lib ).
disabled - if set to true - action on component will not be possible.
+17
View File
@@ -0,0 +1,17 @@
---
'@backstage/core-components': patch
'@backstage/plugin-catalog': patch
'@backstage/plugin-circleci': patch
'@backstage/plugin-cloudbuild': patch
'@backstage/plugin-github-actions': patch
'@backstage/plugin-gitops-profiles': patch
'@backstage/plugin-jenkins': patch
'@backstage/plugin-lighthouse': patch
'@backstage/plugin-org': patch
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-search': patch
'@backstage/plugin-sentry': patch
'@backstage/plugin-sonarqube': patch
---
Prefer using `Link` from `@backstage/core-components` rather than material-UI.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-jenkins-backend': patch
---
feature: add crumbIssuer option to Jenkins (optional) configuration, improve the UI to show a notification after executing the action re-build
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-jenkins': patch
---
feature: add crumbIssuer option to Jenkins (optional) configuration, improve the UI to show a notification after executing the action re-build
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Add DescriptionField override to support Markdown
-14
View File
@@ -1,14 +0,0 @@
---
'@backstage/plugin-apache-airflow': minor
---
Introduces a new plugin for the Apache Airflow workflow management platform.
This implementation has been tested with the Apache Airflow v2 API,
authenticating with basic authentication through the Backstage proxy plugin.
Supported functionality includes:
- Information card of version information of the Airflow instance
- Information card of instance health for the meta-database and scheduler
- Table of DAGs with meta information and status, along with a link to view
details in the Airflow UI
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-app-api': patch
---
Schema-validate local storage cached session info on load
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-plugin-api': minor
---
Removed deprecated types `ApiRefType` and `ApiRefsToTypes`
+1
View File
@@ -42,3 +42,4 @@
/.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
+24
View File
@@ -0,0 +1,24 @@
catalog:
- plugins/catalog/**/*
- plugins/catalog-*/**/*
- packages/catalog-*/**/*
scaffolder:
- plugins/scaffolder/**/*
- plugins/scaffolder-*/**/*
search:
- plugins/search/**/*
- plugins/search-*/**/*
- packages/search-*/**/*
docs-like-code:
- plugins/techdocs/**/*
- plugins/techdocs-*/**/*
- packages/techdocs-*/**/*
documentation:
- docs/**/*
microsite:
- microsite/**/*
auth:
- plugins/auth-backend/**/*
- packages/core-app-api/src/apis/implementations/auth/**/*
- packages/core-app-api/src/lib/Auth*/**/*
- packages/core-plugin-api/src/apis/definitions/auth.ts
+9 -1
View File
@@ -12,6 +12,7 @@ Atlassian
automations
autoscaling
Autoscaling
autoselect
Avro
backrub
Bigtable
@@ -53,6 +54,7 @@ configs
const
cookiecutter
cron
cronjobs
css
Datadog
dataflow
@@ -90,10 +92,12 @@ Figma
firehydrant
FireHydrant
Firekube
Firestore
Fiverr
gitbeaker
GitHub
GitLab
Gource
Grafana
graphql
GraphQL
@@ -187,6 +191,7 @@ OAuth
octokit
oidc
Okta
Oldsberg
onboarding
Onboarding
OpenShift
@@ -194,6 +199,8 @@ orgs
pagerduty
pageview
parallelization
Patrik
Peloton
plantuml
Platformize
Podman
@@ -293,6 +300,7 @@ truthy
typeahead
ui
unbreak
Unconference
unmanaged
unregister
unregistration
@@ -304,6 +312,7 @@ utils
validator
validators
varchar
Wayfair
Weaveworks
Webpack
winston
@@ -316,4 +325,3 @@ Zalando
Zhou
zoomable
zsh
Firestore
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
name: Create Changeset PR
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Install Dependencies
run: yarn --frozen-lockfile
- name: Create Release Pull Request
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
uses: actions/checkout@v2
- name: Install Fossa
run: "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | bash"
+12
View File
@@ -0,0 +1,12 @@
name: 'Pull Request Labeler'
on:
- pull_request_target
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v3
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
sync-labels: true
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
recent activity from the author. It will be closed if no further activity occurs.
If you are the author and the PR has been closed, feel free to re-open the PR and continue the contribution!
days-before-pr-stale: 7
days-before-pr-close: 3
days-before-pr-close: 5
exempt-pr-labels: reviewer-approved,awaiting-review
stale-pr-label: stale
operations-per-run: 100
+4
View File
@@ -2,6 +2,10 @@
# [Backstage](https://backstage.io)
> 🎄 The maintainers will be taking a break over the holidays from week beginning 20th Dec. The Repository and Discord may be quieter than usual. We will be back next year, rested and restored, on Jan. 3. 🎄
> 🎅 Happy holidays and a Happy New Year to all, and especially those that have made this year special for Backstage! 🎅
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![CNCF Status](https://img.shields.io/badge/cncf%20status-sandbox-blue.svg)](https://www.cncf.io/projects)
[![Main CI Build](https://github.com/backstage/backstage/workflows/Main%20Master%20Build/badge.svg)](https://github.com/backstage/backstage/actions?query=workflow%3A%22Main+Master+Build%22)
+5
View File
@@ -74,6 +74,11 @@ proxy:
headers:
X-Api-Key: ${NEW_RELIC_REST_API_KEY}
'/newrelic/api':
target: https://api.newrelic.com
headers:
X-Api-Key: ${NEW_RELIC_USER_KEY}
'/pagerduty':
target: https://api.pagerduty.com
headers:
+122
View File
@@ -61,3 +61,125 @@ breaking change to make `theme` optional. This means that if you currently
construct the themes that you pass on to `createApp` using `AppTheme` as an
intermediate type, you will need to work around this in some way, for example by
passing the themes to `createApp` more directly.
### Generic Auth API Refs
`Released 2021-12-16 in @backstage/core-plugin-api v0.3.1`
There are four auth Utility API references in `@backstage/core-plugin-api` that
were too generic to be useful. The APIs in question are `auth0AuthApiRef`,
`oauth2ApiRef`, `oidcAuthApiRef`, and `samlAuthApiRef`. The issue with these
APIs was that they had no actual contract of what the backing auth provider was.
This made it more or less impossible to use these providers in open source
plugins in any meaningful way. We also did not want to keep these Utility API
references around just as helpers either, instead opting to remove them and let
integrators define their own APIs that are more specific to their auth provider.
This is also falls in line with a long-term goal to unify all auth providers to
not have separate frontend implementations.
If you're currently using one of these API references for either Sign-In or
access delegation within an app, there are a couple of steps you need to take to
migrate to your own custom API.
First, you'll need to define a new Utility API reference. If you're only using
the API for sign-in, you can put the definition in `packages/app/src/apis.ts`.
However, if you need to access your auth API inside plugins you you'll need to
export it from a common package. If you don't already have one we recommended
creating `@internal/apis` and from there export the API reference.
```ts
// `ProfileInfoApi & BackstageIdentityApi & SessionApi` are required for sign-in
// Include `OAuthApi & OpenIdConnectApi` only if applicable
export const acmeAuthApiRef: ApiRef<
OAuthApi &
OpenIdConnectApi &
ProfileInfoApi &
BackstageIdentityApi &
SessionApi
> = createApiRef({
id: 'internal.auth.acme',
});
```
Next you'll want to wire up the API inside `packages/app/src/apis.ts`, which
varies depending on which API you're replacing. If you for example are replacing
the `oauth2ApiRef`, the factory might look like this:
```ts
// oauth2
createApiFactory({
api: acmeAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
oauthRequestApi: oauthRequestApiRef,
configApi: configApiRef,
},
factory: ({ discoveryApi, oauthRequestApi, configApi }) =>
OAuth2.create({
discoveryApi,
oauthRequestApi,
environment: configApi.getOptionalString('auth.environment'),
}),
});
```
Provider specific factory implementations, copy the code you need into the
factory method depending on which apiRef you previously used.
```ts
// samlAuthApiRef
SamlAuth.create({
discoveryApi,
environment: configApi.getOptionalString('auth.environment'),
});
// oidcAuthApiRef
OAuth2.create({
discoveryApi,
oauthRequestApi,
provider: {
id: 'oidc',
title: 'Your Identity Provider',
icon: () => null,
},
environment: configApi.getOptionalString('auth.environment'),
});
// auth0AuthApiRef
OAuth2.create({
discoveryApi,
oauthRequestApi,
provider: {
id: 'auth0',
title: 'Auth0',
icon: () => null,
},
defaultScopes: ['openid', 'email', 'profile'],
environment: configApi.getOptionalString('auth.environment'),
});
```
Finally, for the provider to show up in your settings menu, you also need to
update the settings route in `packages/app/src/App.tsx` to pass the
`acmeAuthApiRef` to the `UserSettingsPage`. This replaces all existing provider
items, so you might want to add back any of the default ones that you are using
from the
[DefaultProviderSettings](https://github.com/backstage/backstage/blob/a3ec122170e0205fd3f9c307b98b1c5e4f55bf5f/plugins/user-settings/src/components/AuthProviders/DefaultProviderSettings.tsx#L35).
```tsx
<Route
path="/settings"
element={
<UserSettingsPage
providerSettings={
<ProviderSettingsItem
title="ACME"
description="Provides sign-in via ACME"
apiRef={acmeAuthApiRef}
icon={Star}
/>
}
/>
}
/>
```
+4 -4
View File
@@ -128,8 +128,8 @@ the core APIs. The core APIs are the ones exported by
[configApiRef](../reference/core-plugin-api.configapiref.md).
The core APIs are loaded for any app created with
[createApp](../reference/core-app-api.createapp.md) from
[@backstage/core-plugin-api](../reference/core-plugin-api.md), which means that
[createApp](../reference/app-defaults.createapp.md) from
[@backstage/core-plugin-api](../reference/app-defaults.md), which means that
there is no step that needs to be taken to include these APIs in an app.
### Plugin APIs
@@ -168,7 +168,7 @@ Lastly, the app itself is the final point where APIs can be added, and what has
the final say in what APIs will be loaded at runtime. The app may override the
factories for any of the core or plugin APIs, with the exception of the config,
app theme, and identity APIs. These are static APIs that are tied into the
[createApp](../reference/core-app-api.createapp.md) implementation, and
[createApp](../reference/app-defaults.createapp.md) implementation, and
therefore not possible to override.
Overriding APIs is useful for apps that want to switch out behavior to tailor it
@@ -313,7 +313,7 @@ The common development environment for plugins is included in
[createDevApp](../reference/dev-utils.createdevapp.md) function creates an
application with implementations for all core APIs already present. Contrary to
the method for wiring up Utility API implementations in an app created with
[createApp](../reference/core-app-api.createapp.md),
[createApp](../reference/app-defaults.createapp.md),
[createDevApp](../reference/dev-utils.createdevapp.md) uses automatic dependency
injection. This is to make it possible to replace any API implementation, and
having that be reflected in dependents of that API.
@@ -1,6 +1,7 @@
---
id: adrs-adr000
title: ADR000: [TITLE]
title: 'ADR000: [TITLE]'
# prettier-ignore
description: Architecture Decision Record (ADR) for [TITLE] [DESCRIPTION]
---
@@ -1,6 +1,7 @@
---
id: adrs-adr001
title: ADR001: Architecture Decision Record (ADR) log
title: 'ADR001: Architecture Decision Record (ADR) log'
# prettier-ignore
description: Architecture Decision Record (ADR) logs as a reference point for the team
---
@@ -1,6 +1,7 @@
---
id: adrs-adr002
title: ADR002: Default Software Catalog File Format
title: 'ADR002: Default Software Catalog File Format'
# prettier-ignore
description: Architecture Decision Record (ADR) log on Default Software Catalog File Format
---
@@ -1,6 +1,7 @@
---
id: adrs-adr003
title: ADR003: Avoid Default Exports and Prefer Named Exports
title: 'ADR003: Avoid Default Exports and Prefer Named Exports'
# prettier-ignore
description: Architecture Decision Record (ADR) log on Avoid Default Exports and Prefer Named Exports
---
@@ -1,6 +1,7 @@
---
id: adrs-adr004
title: ADR004: Module Export Structure
title: 'ADR004: Module Export Structure'
# prettier-ignore
description: Architecture Decision Record (ADR) log on Module Export Structure
---
@@ -1,6 +1,7 @@
---
id: adrs-adr005
title: ADR005: Catalog Core Entities
title: 'ADR005: Catalog Core Entities'
# prettier-ignore
description: Architecture Decision Record (ADR) log on Catalog Core Entities
---
@@ -1,6 +1,7 @@
---
id: adrs-adr006
title: ADR006: Avoid React.FC and React.SFC
title: 'ADR006: Avoid React.FC and React.SFC'
# prettier-ignore
description: Architecture Decision Record (ADR) log on Avoid React.FC and React.SFC
---
@@ -1,6 +1,7 @@
---
id: adrs-adr007
title: ADR007: Use MSW to mock http requests
title: 'ADR007: Use MSW to mock http requests'
# prettier-ignore
description: Architecture Decision Record (ADR) log on Use MSW to mock http requests
---
@@ -1,6 +1,7 @@
---
id: adrs-adr008
title: ADR008: Default Catalog File Name
title: 'ADR008: Default Catalog File Name'
# prettier-ignore
description: Architecture Decision Record (ADR) log on Default Catalog File Name
---
@@ -1,6 +1,7 @@
---
id: adrs-adr009
title: ADR009: Entity References
title: 'ADR009: Entity References'
# prettier-ignore
description: Architecture Decision Record (ADR) log on Entity References
---
@@ -1,6 +1,7 @@
---
id: adrs-adr010
title: ADR010: Use the Luxon Date Library
title: 'ADR010: Use the Luxon Date Library'
# prettier-ignore
description: Architecture Decision Record (ADR) for Luxon Date Library
---
@@ -1,6 +1,7 @@
---
id: adrs-adr011
title: ADR011: Plugin Package Structure
title: 'ADR011: Plugin Package Structure'
# prettier-ignore
description: Architecture Decision Record (ADR) for Plugin Package Structure
---
@@ -1,6 +1,7 @@
---
id: adrs-adr012
title: ADR012: Use Luxon.toLocaleString and date/time presets
title: 'ADR012: Use Luxon.toLocaleString and date/time presets'
# prettier-ignore
description: Architecture Decision Record (ADR) for using Luxon's toLocaleString method and date/time presets for displaying dates and times
---
+1
View File
@@ -2,6 +2,7 @@
id: adrs-overview
title: Architecture Decision Records (ADR)
sidebar_label: Overview
# prettier-ignore
description: Overview of Architecture Decision Records (ADR)
---
+1 -1
View File
@@ -48,6 +48,6 @@ The Microsoft provider is a structure with three configuration keys:
## Adding the provider to the Backstage frontend
To add the provider to the frontend, add the `microsoftAuthApi` reference and
To add the provider to the frontend, add the `microsoftAuthApiRef` reference and
`SignInPage` component as shown in
[Adding the provider to the sign-in page](../index.md#adding-the-provider-to-the-sign-in-page).
+4 -1
View File
@@ -67,7 +67,7 @@ production build.
## Configuration Files
It is possible to have multiple configuration files (bundled and/or remote),
It is possible to have multiple configuration files (bundled and/or remote\*),
both to support different environments, but also to define configuration that is
local to specific packages. The configuration files to load are selected using a
`--config <local-path|url>` flag, and it is possible to load any number of
@@ -77,6 +77,9 @@ root when running the backend, you would use `--config ../../my-config.yaml`,
and for config file on a config server you would use
`--config https://some.domain.io/app-config.yaml`
**Note**: In case URLs are passed, it is also needed to set the remote option in
the loadBackendConfig call.
If no `config` flags are specified, the default behavior is to load
`app-config.yaml` and, if it exists, `app-config.local.yaml` from the repo root.
In the provided project setup, `app-config.local.yaml` is `.gitignore`'d, making
@@ -264,6 +264,12 @@ following objects:
- horizontalpodautoscalers
- ingresses
The following RBAC permissions are required on the batch API group for the
following objects:
- jobs
- cronjobs
## Surfacing your Kubernetes components as part of an entity
There are two ways to surface your Kubernetes components as part of an entity.
+12
View File
@@ -90,6 +90,18 @@ within your instance. The configuration options are documented in the
The underlying functionality is using official ElasticSearch client version 7.x,
meaning that ElasticSearch version 7 is the only one confirmed to be supported.
Should you need to create your own bespoke search experiences that require more
than just a query translator (such as faceted search or Relay pagination), you
can access the configuration of the search engine in order to create new elastic
search clients. The version of the client need not be the same as one used
internally by the elastic search engine plugin. For example:
```typescript
import { Client } from '@elastic/elastic-search';
const client = searchEngine.newClient(options => new Client(options));
```
## Example configurations
### AWS
@@ -26,7 +26,7 @@ You can create your own Field Extension by using the
`API` like below:
```tsx
//packages/app/scaffolder/MyCustomExtension/MyCustomExtension.tsx
//packages/app/src/scaffolder/MyCustomExtension/MyCustomExtension.tsx
import React from 'react';
import { FieldProps, FieldValidation } from '@rjsf/core';
import FormControl from '@material-ui/core/FormControl';
@@ -68,7 +68,7 @@ export const myCustomValidation = (
```
```tsx
// packages/app/scaffolder/MyCustomExtension/extensions.ts
// packages/app/src/scaffolder/MyCustomExtension/extensions.ts
/*
This is where the magic happens and creates the custom field extension.
@@ -94,7 +94,7 @@ export const MyCustomFieldExtension = plugin.provide(
```
```tsx
// packages/app/scaffolder/MyCustomExtension/index.ts
// packages/app/src/scaffolder/MyCustomExtension/index.ts
export { MyCustomFieldExtension } from './extension';
```
@@ -102,7 +102,7 @@ export { MyCustomFieldExtension } from './extension';
Once all these files are in place, you then need to provide your custom
extension to the `scaffolder` plugin.
You do this in `packages/app/App.tsx`. You need to provide the
You do this in `packages/app/src/App.tsx`. You need to provide the
`customFieldExtensions` as children to the `ScaffolderPage`.
```tsx
@@ -118,7 +118,7 @@ const routes = (
Should look something like this instead:
```tsx
import { MyCustomFieldExtension } from './scafffolder/MyCustomExtension';
import { MyCustomFieldExtension } from './scaffolder/MyCustomExtension';
const routes = (
<FlatRoutes>
...
+6 -1
View File
@@ -1,4 +1,9 @@
# TechDocs CLI
---
id: cli
title: TechDocs CLI
# prettier-ignore
description: TechDocs CLI - a utility command line interface for managing TechDocs sites in Backstage.
---
Utility command line interface for managing TechDocs sites in
[Backstage](https://github.com/backstage/backstage).
+1 -1
View File
@@ -54,7 +54,7 @@ For example, adding the theme that we created in the previous section can be
done like this:
```ts
import { createApp } from '@backstage/core-app-api';
import { createApp } from '@backstage/app-defaults';
const app = createApp({
apis: ...,
+1 -1
View File
@@ -368,7 +368,7 @@ The following is an example of creation and usage of a parameterized route:
```tsx
// Creation of a parameterized route
const myRouteRef = createRouteRef({
title: 'My Named Route',
id: 'myroute',
params: ['name']
})
-1
View File
@@ -48,7 +48,6 @@ that implements the `OAuthApi` type, it's now working in the frontend too.
```ts
const spotifyAuthApiRef = createApiRef<OAuthApi>({
id: 'core.auth.spotify',
description: 'Provides authentication towards Spotify APIs',
});
```
@@ -99,7 +99,6 @@ export interface MyAwesomeApi {
export const myAwesomeApiRef = createApiRef<MyAwesomeApi>({
id: 'plugin.my-awesome-api.service',
description: 'Example API definition',
});
```
@@ -0,0 +1,145 @@
---
title: Backstage Wrapped 2021
author: Lee Mills, Spotify
authorURL: https://github.com/leemills83
authorImageURL: https://avatars1.githubusercontent.com/u/1236238?s=460&v=4
---
![Backstage in 2021: 75+ public adopters, 500+ contributors, almost 2,000 forks, 9,000+ contributions, 4,000+ Discord members](assets/21-12-20/backstage-wrapped-2021.png)
What a year 2021 has been for the Backstage project and community. As the year comes to a close, we can look back at some of the happenings, the successes, and welcome all the newcomers to our growing community.
In a year that has had its fair share of ups and downs, this community has been something that has brought me so much in the support you provide each other, your eagerness, passion, and willingness to share. Thank you to all of you for creating such a great community, and welcome to everyone joining us. I cant wait to meet you all and see what great things we can create together in the new year.
In 2021 weve seen the project and community grow in every dimension, reaching over 75 public adopters, over 500 contributors from around the world all bringing new ideas and perspectives. Weve had so many of you sharing and demoing your hard work in our monthly community sessions, added new plugins, built new features and really started to see Backstage have an impact for engineering teams across so many of our users.
Now lets hear from the maintainers and look at the stats!
<!--truncate-->
## The community grew…and grew
This year, Netflix, [Expedia][metrics], Wayfair, Peloton, [Box][10], [DAZN][dazn], TELUS, and Unity all officially joined the community — along with more than 50 other public [adopters][md]. Contributors grew by leaps and bounds, too.
Patrik Oldsberg ([@Rugvip][rugvip]):
> Its been awesome to see the engagement by the community grow even more in 2021, especially the way people within the community support each other. Thanks to our growing number of stable, experienced, and knowledgeable contributors its now possible to get help in places like Discord anytime, day or night.
### More adopters, more contributors
![Accelerated growth of Public Backstage Adopters, from July 2020December 2021.](assets/21-12-20/public-backstage-adopters-2021.png)
In January, Backstage had 17 public adopters. By September, [we had 50][50]. And the curve only got steeper from there.
- **75+ public adopters**
- **500+ contributors**
- **4,000+ Discord members**
- **9,000+ PRs & issues**
### A very busy repo
Along with the growth in contributors, PRs, and issues, our active, thriving community has crossed (or is just about to cross) other big milestones on GitHub, too.
- **Nearly 2,000 forks**
- **20,000+ commits**
- **14,000+ GitHub stars**
### Where in the world is the Backstage community?
Watch the visualization below to see where in the world all those contributions came from this past year.
<iframe width="780" height="440" src="https://www.youtube.com/embed/O1xtDv_XDt4" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>
### What does 9,000 contributions look like?
<iframe width="780" height="440" src="https://www.youtube.com/embed/bCqhoK7it2g" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>
Can you spot your name in the video above?
Picking up from the end of 2020, the video shows every single contribution to the Backstage source code over this past year. The visualization was built using [Gource.io][gource]:
> Software projects are displayed by Gource as an animated tree with the root directory of the project at its centre. Directories appear as branches with files as leaves. Developers can be seen working on the tree at the times they contributed to the project.
And if your name isnt in there, its never too late to get started [contributing][contributing] — so that you too can become a bright, sparkling, laser-beam-shooting spider-node thing in 2022!
## Other 2021 milestones
As the community grew, so did the product — with the addition of new features as well as important performance and stability improvements to the core.
Ben Lambert ([@benjdlambert][blam]):
> Weve had a lot of priorities this year. Our first priority was rebuilding the catalog to make it more efficient. Then, toward the later part of the year, weve been stabilizing the core with deprecations and API changes ahead of our 1.0 release of the Core Framework next year.
>
> Its been a super productive year for us all as Core Maintainers, and the product has come on leaps and bounds with the help of everyone involved in the project!
### New features
These new features were built with the community, and made with customization and extensibility in mind.
- **Kubernetes Service Monitoring ([RFC][k8s])**
- **Search Platform ([Alpha][search])**
- **Composable Homepage ([README][home])**
- **Authorization Framework ([RFC][auth])**
### Major stability updates
As we get the ball rolling for [CNCF Incubation][cncf], weve been busy updating, refining, documenting, deprecating, and stabilizing the core.
- **Software Templates ([Beta][scaffolder])**
- **TechDocs ([Beta][techdocs])**
- **API Reference ([docs][api])**
### 50+ open source plugins
We reached [50+ plugins][plugins] built by the community this year, including official plugins (**Snyk**, **FireHydrant**), highly requested plugins (**PagerDuty**, **Prometheus**), and plugins based on new ideas and functionality (**XCMetrics**, **[Tech Insights][techrfc]**) — all tailor-made for Backstage.
### In the spotlight
This year Backstage was center stage at both community-organized events and at major conferences.
- **New (and [expanded][09]) Community Sessions**
- **Backstage Users Unconference + [Open Mic][openmic]**
- **KubeCon + CloudNativeCon [Europe][europe] & [North America][na]**
- **GitHub Universe 2021 [Keynote][day2]**
Find more talks, podcasts, blog posts, and Backstage in the news [here][news].
## Goodbye, 2021. Hello, 2022!
Lastly, thanks to everyone in the global Backstage community who contributed to the open source project in 2021.
This was the first year Spotify hosted [Backstage Community Sessions][meetups], and its been a great source of inspiration, motivation, and joy getting to know all the people behind the contributions. We look forward to seeing all your faces again in 2022 — and hopefully many new ones as well.
Until then, [grab this Backstage Zoom background][zoom] to use at the next Community Session.
![Backstage Zoom Background](assets/21-12-20/Backstage-background-02-2021.png)
See you then! Happy holidays from everyone on the Backstage team at Spotify!
[metrics]: https://backstage.spotify.com/blog/measuring-backstage-proof-of-value-at-expedia/
[10]: https://backstage.spotify.com/blog/community-session/10-box-and-spotify-paid-plugins/
[dazn]: https://backstage.spotify.com/blog/adopter-spotlight/dazn/
[md]: https://github.com/backstage/backstage/blob/master/ADOPTERS.md
[rugvip]: https://github.com/Rugvip
[50]: https://backstage.io/blog/2021/09/30/50-public-adopters
[gource]: https://gource.io
[contributing]: https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md
[blam]: https://github.com/benjdlambert
[k8s]: https://github.com/backstage/backstage/issues/2857
[search]: https://backstage.io/blog/2021/06/24/announcing-backstage-search-platform
[home]: https://github.com/backstage/backstage/blob/master/plugins/home/README.md
[auth]: https://backstage.spotify.com/blog/authorization-framework-rfc/
[scaffolder]: https://backstage.io/blog/2021/07/26/software-templates-are-now-in-beta
[techdocs]: https://backstage.io/blog/2021/09/16/the-techdocs-beta-has-landed
[api]: https://backstage.io/docs/reference/
[cncf]: https://github.com/cncf/toc/pull/717
[plugins]: https://backstage.io/plugins
[techrfc]: https://github.com/backstage/backstage/issues/7576
[09]: https://backstage.spotify.com/blog/community-session/09-prometheus-homepage-templates/
[openmic]: https://backstage-openmic.com
[europe]: https://www.youtube.com/watch?v=aIURaocR5D8
[na]: https://backstage.spotify.com/blog/kubecon-na-2021/
[day2]: https://www.youtube.com/watch?v=7yQJlYvpoYs&t=269s
[news]: https://github.com/backstage/community#newsletters
[meetups]: https://github.com/backstage/community#meetups
[zoom]: https://drive.google.com/file/d/14wOPXEBZ5Qmi29ms4Sqp1m56dM0AIHbB/view?usp=sharing
Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

+5 -4
View File
@@ -55,9 +55,9 @@
},
"version": "1.0.0",
"dependencies": {
"@microsoft/api-documenter": "^7.13.68",
"@microsoft/api-extractor": "^7.18.7",
"@microsoft/api-extractor-model": "^7.13.5",
"@microsoft/api-documenter": "^7.13.77",
"@microsoft/api-extractor": "^7.19.2",
"@microsoft/api-extractor-model": "^7.15.1",
"@microsoft/tsdoc": "^0.13.2"
},
"devDependencies": {
@@ -78,11 +78,12 @@
"prettier": "^2.2.1",
"shx": "^0.3.2",
"ts-node": "^10.4.0",
"typescript": "~4.3.5",
"yarn-lock-check": "^1.0.5"
},
"prettier": "@spotify/prettier-config",
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"*.{js,jsx,ts,tsx,mjs,cjs}": [
"eslint --fix",
"prettier --write"
],
@@ -34,6 +34,8 @@ import {
OneLoginAuth,
UnhandledErrorForwarder,
AtlassianAuth,
createFetchApi,
FetchMiddlewares,
} from '@backstage/core-app-api';
import {
@@ -42,6 +44,8 @@ import {
analyticsApiRef,
errorApiRef,
discoveryApiRef,
fetchApiRef,
identityApiRef,
oauthRequestApiRef,
googleAuthApiRef,
githubAuthApiRef,
@@ -92,6 +96,27 @@ export const apis = [
deps: { errorApi: errorApiRef },
factory: ({ errorApi }) => WebStorage.create({ errorApi }),
}),
createApiFactory({
api: fetchApiRef,
deps: {
configApi: configApiRef,
identityApi: identityApiRef,
discoveryApi: discoveryApiRef,
},
factory: ({ configApi, identityApi, discoveryApi }) => {
return createFetchApi({
middleware: [
FetchMiddlewares.resolvePluginProtocol({
discoveryApi,
}),
FetchMiddlewares.injectIdentityAuth({
identityApi,
config: configApi,
}),
],
});
},
}),
createApiFactory({
api: oauthRequestApiRef,
deps: {},
@@ -73,7 +73,7 @@ const DefaultErrorBoundaryFallback = ({
};
/**
* Creates a set of default components to pass along to {@link @backstage/core-app-api#createApp}.
* Creates a set of default components to pass along to {@link @backstage/core-app-api#createSpecializedApp}.
*
* @public
*/
@@ -28,7 +28,6 @@ export const themes: AppTheme[] = [
title: 'Light Theme',
variant: 'light',
icon: <LightIcon />,
theme: lightTheme,
Provider: ({ children }) => (
<ThemeProvider theme={lightTheme}>
<CssBaseline>{children}</CssBaseline>
@@ -40,7 +39,6 @@ export const themes: AppTheme[] = [
title: 'Dark Theme',
variant: 'dark',
icon: <DarkIcon />,
theme: darkTheme,
Provider: ({ children }) => (
<ThemeProvider theme={darkTheme}>
<CssBaseline>{children}</CssBaseline>
+18
View File
@@ -1,5 +1,23 @@
# example-app
## 0.2.57
### Patch Changes
- Updated dependencies
- @backstage/plugin-github-actions@0.4.27
- @backstage/core-app-api@0.2.1
- @backstage/plugin-kubernetes@0.5.1
- @backstage/core-plugin-api@0.3.1
- @backstage/core-components@0.8.1
- @backstage/plugin-org@0.3.31
- @backstage/plugin-azure-devops@0.1.7
- @backstage/cli@0.10.2
- @backstage/catalog-model@0.9.8
- @backstage/plugin-techdocs@0.12.10
- @backstage/plugin-catalog-react@0.6.7
- @backstage/plugin-apache-airflow@0.1.0
## 0.2.56
### Patch Changes
+14 -13
View File
@@ -1,39 +1,40 @@
{
"name": "example-app",
"version": "0.2.56",
"version": "0.2.57",
"private": true,
"bundled": true,
"dependencies": {
"@backstage/app-defaults": "^0.1.2",
"@backstage/catalog-model": "^0.9.7",
"@backstage/cli": "^0.10.1",
"@backstage/core-app-api": "^0.2.0",
"@backstage/core-components": "^0.8.0",
"@backstage/core-plugin-api": "^0.3.0",
"@backstage/catalog-model": "^0.9.8",
"@backstage/cli": "^0.10.2",
"@backstage/core-app-api": "^0.2.1",
"@backstage/core-components": "^0.8.1",
"@backstage/core-plugin-api": "^0.3.1",
"@backstage/integration-react": "^0.1.15",
"@backstage/plugin-api-docs": "^0.6.18",
"@backstage/plugin-azure-devops": "^0.1.6",
"@backstage/plugin-apache-airflow": "^0.0.0",
"@backstage/plugin-azure-devops": "^0.1.7",
"@backstage/plugin-apache-airflow": "^0.1.0",
"@backstage/plugin-badges": "^0.2.16",
"@backstage/plugin-catalog": "^0.7.4",
"@backstage/plugin-catalog-graph": "^0.2.3",
"@backstage/plugin-catalog-import": "^0.7.5",
"@backstage/plugin-catalog-react": "^0.6.5",
"@backstage/plugin-catalog-react": "^0.6.7",
"@backstage/plugin-circleci": "^0.2.31",
"@backstage/plugin-cloudbuild": "^0.2.29",
"@backstage/plugin-code-coverage": "^0.1.19",
"@backstage/plugin-cost-insights": "^0.11.13",
"@backstage/plugin-explore": "^0.3.22",
"@backstage/plugin-gcp-projects": "^0.3.10",
"@backstage/plugin-github-actions": "^0.4.26",
"@backstage/plugin-github-actions": "^0.4.27",
"@backstage/plugin-graphiql": "^0.2.24",
"@backstage/plugin-home": "^0.4.7",
"@backstage/plugin-jenkins": "^0.5.14",
"@backstage/plugin-kafka": "^0.2.22",
"@backstage/plugin-kubernetes": "^0.5.0",
"@backstage/plugin-kubernetes": "^0.5.1",
"@backstage/plugin-lighthouse": "^0.2.31",
"@backstage/plugin-newrelic": "^0.3.10",
"@backstage/plugin-org": "^0.3.30",
"@backstage/plugin-newrelic-dashboard": "^0.1.0",
"@backstage/plugin-org": "^0.3.31",
"@backstage/plugin-pagerduty": "0.3.19",
"@backstage/plugin-rollbar": "^0.3.20",
"@backstage/plugin-scaffolder": "^0.11.14",
@@ -41,7 +42,7 @@
"@backstage/plugin-sentry": "^0.3.30",
"@backstage/plugin-shortcuts": "^0.1.15",
"@backstage/plugin-tech-radar": "^0.4.13",
"@backstage/plugin-techdocs": "^0.12.9",
"@backstage/plugin-techdocs": "^0.12.10",
"@backstage/plugin-todo": "^0.1.16",
"@backstage/plugin-user-settings": "^0.3.13",
"@backstage/search-common": "^0.2.0",
+13 -11
View File
@@ -47,13 +47,12 @@
min-height: 100%;
}
</style>
<title><%= app.title %></title>
<title><%= config.getString('app.title') %></title>
<% if (app.googleAnalyticsTrackingId && typeof
app.googleAnalyticsTrackingId==='string' ) { %>
<% if (config.has('app.googleAnalyticsTrackingId')) { %>
<script
async
src="https://www.googletagmanager.com/gtag/js?id=<%= app.googleAnalyticsTrackingId %>"
src="https://www.googletagmanager.com/gtag/js?id=<%= config.getString('app.googleAnalyticsTrackingId') %>"
></script>
<script>
window.dataLayer = window.dataLayer || [];
@@ -62,10 +61,12 @@
}
gtag('js', new Date());
gtag('config', '<%= app.googleAnalyticsTrackingId %>');
gtag(
'config',
'<%= config.getString("app.googleAnalyticsTrackingId") %>',
);
</script>
<% } %> <% if (app.datadogRum.clientToken && app.datadogRum.applicationId )
{ %>
<% } %> <% if (config.has('app.datadogRum')) { %>
<script>
(function (h, o, u, n, d) {
h = h[d] = h[d] || {
@@ -88,11 +89,12 @@
);
DD_RUM.onReady(function () {
DD_RUM.init({
clientToken: '<%= app.datadogRum.clientToken %>',
applicationId: '<%= app.datadogRum.applicationId %>',
site: '<%= app.datadogRum.site %>' || 'datadoghq.com',
clientToken: '<%= config.getString("app.datadogRum.clientToken") %>',
applicationId:
'<%= config.getString("app.datadogRum.applicationId") %>',
site: '<%= config.getOptionalString("app.datadogRum.site") || "datadoghq.com" %>',
service: 'backstage',
env: '<%= app.datadogRum.env %>',
env: '<%= config.getString("app.datadogRum.env") %>',
sampleRate: 100,
trackInteractions: true,
});
@@ -124,8 +124,16 @@ import {
EntityTravisCIOverviewCard,
isTravisciAvailable,
} from '@roadiehq/backstage-plugin-travis-ci';
import {
isNewRelicDashboardAvailable,
EntityNewRelicDashboardContent,
EntityNewRelicDashboardCard,
} from '@backstage/plugin-newrelic-dashboard';
import React, { ReactNode, useMemo, useState } from 'react';
const customEntityFilterKind = ['Component', 'API', 'System'];
const EntityLayoutWrapper = (props: { children?: ReactNode }) => {
const [badgesDialogOpen, setBadgesDialogOpen] = useState(false);
@@ -289,6 +297,14 @@ const overviewContent = (
</EntitySwitch.Case>
</EntitySwitch>
<EntitySwitch>
<EntitySwitch.Case if={isNewRelicDashboardAvailable}>
<Grid item md={6} xs={12}>
<EntityNewRelicDashboardCard />
</Grid>
</EntitySwitch.Case>
</EntitySwitch>
<Grid item md={4} xs={12}>
<EntityLinksCard />
</Grid>
@@ -369,6 +385,14 @@ const serviceEntityPage = (
<EntityTechdocsContent />
</EntityLayout.Route>
<EntityLayout.Route
if={isNewRelicDashboardAvailable}
path="/newrelic-dashboard"
title="New Relic Dashboard"
>
<EntityNewRelicDashboardContent />
</EntityLayout.Route>
<EntityLayout.Route path="/kubernetes" title="Kubernetes">
<EntityKubernetesContent />
</EntityLayout.Route>
@@ -427,6 +451,13 @@ const websiteEntityPage = (
<EntityLayout.Route path="/docs" title="Docs">
<EntityTechdocsContent />
</EntityLayout.Route>
<EntityLayout.Route
if={isNewRelicDashboardAvailable}
path="/newrelic-dashboard"
title="New Relic Dashboard"
>
<EntityNewRelicDashboardContent />
</EntityLayout.Route>
<EntityLayout.Route path="/kubernetes" title="Kubernetes">
<EntityKubernetesContent />
@@ -523,7 +554,10 @@ const userPage = (
<EntityUserProfileCard variant="gridItem" />
</Grid>
<Grid item xs={12} md={6}>
<EntityOwnershipCard variant="gridItem" />
<EntityOwnershipCard
variant="gridItem"
entityFilterKind={customEntityFilterKind}
/>
</Grid>
</Grid>
</EntityLayout.Route>
@@ -539,7 +573,10 @@ const groupPage = (
<EntityGroupProfileCard variant="gridItem" />
</Grid>
<Grid item xs={12} md={6}>
<EntityOwnershipCard variant="gridItem" />
<EntityOwnershipCard
variant="gridItem"
entityFilterKind={customEntityFilterKind}
/>
</Grid>
<Grid item xs={12}>
<EntityMembersListCard />
+7
View File
@@ -1,5 +1,12 @@
# @backstage/backend-common
## 0.9.14
### Patch Changes
- fe24bc9a32: Each plugin now saves to a separate sqlite database file when `connection.filename` is provided in the sqlite config.
Any existing sqlite database files will be ignored.
## 0.9.13
### Patch Changes
+2
View File
@@ -21,6 +21,7 @@ import { GitLabIntegration } from '@backstage/integration';
import { isChildPath } from '@backstage/cli-common';
import { JsonValue } from '@backstage/types';
import { Knex } from 'knex';
import { LoadConfigOptionsRemote } from '@backstage/config-loader';
import { Logger as Logger_2 } from 'winston';
import { MergeResult } from 'isomorphic-git';
import { PushResult } from 'isomorphic-git';
@@ -338,6 +339,7 @@ export function isDatabaseConflictError(e: unknown): boolean;
// @public
export function loadBackendConfig(options: {
logger: Logger_2;
remote?: LoadConfigOptionsRemote;
argv: string[];
}): Promise<Config>;
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.9.13",
"version": "0.9.14",
"main": "src/index.ts",
"types": "src/index.ts",
"private": false,
@@ -81,7 +81,7 @@
}
},
"devDependencies": {
"@backstage/cli": "^0.10.1",
"@backstage/cli": "^0.10.2",
"@backstage/test-utils": "^0.1.24",
"@types/archiver": "^5.1.0",
"@types/compression": "^1.7.0",
@@ -94,7 +94,7 @@
"@types/recursive-readdir": "^2.2.0",
"@types/stoppable": "^1.1.0",
"@types/supertest": "^2.0.8",
"@types/tar": "^4.0.3",
"@types/tar": "^6.1.1",
"@types/unzipper": "^0.10.3",
"@types/webpack-env": "^1.15.2",
"aws-sdk-mock": "^5.2.1",
+3 -1
View File
@@ -23,6 +23,7 @@ import {
loadConfig,
ConfigSchema,
ConfigTarget,
LoadConfigOptionsRemote,
} from '@backstage/config-loader';
import { AppConfig, Config, ConfigReader } from '@backstage/config';
import { JsonValue } from '@backstage/types';
@@ -178,6 +179,7 @@ let currentCancelFunc: () => void;
export async function loadBackendConfig(options: {
logger: Logger;
// process.argv or any other overrides
remote?: LoadConfigOptionsRemote;
argv: string[];
}): Promise<Config> {
const args = parseArgs(options.argv);
@@ -202,8 +204,8 @@ export async function loadBackendConfig(options: {
const config = new ObservableConfigProxy(options.logger);
const { appConfigs } = await loadConfig({
configRoot: paths.targetRoot,
configPaths: [],
configTargets: configTargets,
remote: options.remote,
watch: {
onChange(newConfigs) {
options.logger.info(
@@ -15,6 +15,7 @@
*/
import { ConfigReader } from '@backstage/config';
import { omit } from 'lodash';
import path from 'path';
import {
createDatabaseClient,
ensureDatabaseExists,
@@ -170,28 +171,6 @@ describe('DatabaseManager', () => {
);
});
it('uses top level sqlite database filename if plugin config is not present', async () => {
const testManager = DatabaseManager.fromConfig(
new ConfigReader({
backend: {
database: {
client: 'sqlite3',
connection: 'some-file-path',
},
},
}),
);
await testManager.forPlugin('pluginwithoutconfig').getClient();
const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1);
const [_, overrides] = mockCalls[0];
expect(overrides).toHaveProperty(
'connection.filename',
expect.stringContaining('some-file-path'),
);
});
it('provides an inmemory sqlite database if top level is also inmemory and plugin config is not present', async () => {
const testManager = DatabaseManager.fromConfig(
new ConfigReader({
@@ -214,6 +193,110 @@ describe('DatabaseManager', () => {
);
});
it('throws if top level sqlite filename is provided', async () => {
const testManager = DatabaseManager.fromConfig(
new ConfigReader({
backend: {
database: {
client: 'sqlite3',
connection: 'some-file-path',
},
},
}),
);
await expect(
testManager.forPlugin('pluginwithoutconfig').getClient(),
).rejects.toBeInstanceOf(Error);
});
it('creates plugin-specific sqlite files when plugin config is not present', async () => {
const testManager = DatabaseManager.fromConfig(
new ConfigReader({
backend: {
database: {
client: 'sqlite3',
connection: {
directory: 'sqlite-files',
},
},
},
}),
);
await testManager.forPlugin('pluginwithoutconfig').getClient();
const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1);
const [_, overrides] = mockCalls[0];
expect(overrides).toHaveProperty(
'connection.filename',
path.join('sqlite-files', 'pluginwithoutconfig.sqlite'),
);
});
it('uses sqlite directory from top level config and filename from plugin config', async () => {
const testManager = DatabaseManager.fromConfig(
new ConfigReader({
backend: {
database: {
client: 'sqlite3',
connection: {
directory: 'sqlite-files',
},
plugin: {
test: {
connection: {
filename: 'other.sqlite',
},
},
},
},
},
}),
);
await testManager.forPlugin('test').getClient();
const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1);
const [_, overrides] = mockCalls[0];
expect(overrides).toHaveProperty(
'connection.filename',
path.join('sqlite-files', 'other.sqlite'),
);
});
it('uses sqlite directory and filename from plugin config', async () => {
const testManager = DatabaseManager.fromConfig(
new ConfigReader({
backend: {
database: {
client: 'sqlite3',
connection: {
directory: 'sqlite-files',
},
plugin: {
test: {
connection: {
directory: 'custom-sqlite-files',
filename: 'other.sqlite',
},
},
},
},
},
}),
);
await testManager.forPlugin('test').getClient();
const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1);
const [_, overrides] = mockCalls[0];
expect(overrides).toHaveProperty(
'connection.filename',
path.join('custom-sqlite-files', 'other.sqlite'),
);
});
it('connects to a plugin database using a specific database name', async () => {
// testdbname.connection.database is set in config
await manager.forPlugin('testdbname').getClient();
@@ -282,7 +365,10 @@ describe('DatabaseManager', () => {
expect(baseConfig.get().client).toEqual('sqlite3');
// sqlite3 uses 'filename' instead of 'database'
expect(overrides).toHaveProperty('connection.filename');
expect(overrides).toHaveProperty(
'connection.filename',
'plugin_with_different_client',
);
});
it('provides database client specific base from plugin connection string when client set under plugin', async () => {
@@ -28,6 +28,7 @@ import {
normalizeConnection,
} from './connection';
import { PluginDatabaseManager } from './types';
import path from 'path';
/**
* Provides a config lookup path for a plugin's config block.
@@ -114,10 +115,18 @@ export class DatabaseManager {
const connection = this.getConnectionConfig(pluginId);
if (this.getClientType(pluginId).client === 'sqlite3') {
// sqlite database name should fallback to ':memory:' as a special case
return (
(connection as Knex.Sqlite3ConnectionConfig)?.filename ?? ':memory:'
);
const sqliteFilename: string | undefined = (
connection as Knex.Sqlite3ConnectionConfig
).filename;
if (sqliteFilename === ':memory:') {
return sqliteFilename;
}
const sqliteDirectory =
(connection as { directory?: string }).directory ?? '.';
return path.join(sqliteDirectory, sqliteFilename ?? `${pluginId}.sqlite`);
}
const databaseName = (connection as Knex.ConnectionConfig)?.database;
@@ -205,6 +214,17 @@ export class DatabaseManager {
this.config.get('connection'),
this.config.getString('client'),
);
if (
client === 'sqlite3' &&
'filename' in baseConnection &&
baseConnection.filename !== ':memory:'
) {
throw new Error(
'`connection.filename` is not supported for the base sqlite connection. Prefer `connection.directory` or provide a filename for the plugin connection instead.',
);
}
// Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The
// `database` property from the base connection is omitted unless `pluginDivisionMode`
// is set to `schema`. SQLite3's `filename` property is an exception as this is used as a

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