Merge branch 'backstage:master' into master

This commit is contained in:
Waldir Montoya
2023-02-08 10:00:29 -05:00
committed by GitHub
537 changed files with 10172 additions and 928 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-app-api': minor
---
**BREAKING**: Renamed `RootHttpRouterConfigureOptions` to `RootHttpRouterConfigureContext`, and removed the unused type `ServiceOrExtensionPoint`.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-playlist-backend': patch
'@backstage/plugin-catalog-backend': patch
---
Minor improvements to the descriptions provided with permission rules schemas
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': patch
---
Removed the unused `TypesToServiceRef` type
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-scaffolder': patch
---
scaffolder/next: Implementing a simple `OngoingTask` page
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
---
Removing extra imports for `run` script as `TestBackend` auto loads the default factories
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-test-utils': patch
---
Updated the `mockServices.rootLogger` options to accept a single level option instead.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': patch
---
Updated to work with the new `type: 'pem'` with `createHttpServer` from `@backstage/backend-app-api`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-vault': patch
---
Surface additional context and details to the Backstage UI when the Vault plugin encounters non-successful HTTP responses from the Vault API.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-test-utils': patch
'@backstage/backend-app-api': patch
---
Updates to match new `BackendFeature` type.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-scaffolder': patch
'@backstage/plugin-scaffolder-react': patch
---
bump `@rjsf` `v5` dependencies to 5.1.0
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-techdocs-backend': patch
'@backstage/plugin-techdocs-node': patch
'@techdocs/cli': patch
---
Added support for using a default `mkdocs.yml` configuration file when none is provided
+68 -1
View File
@@ -195,82 +195,149 @@
"@backstage/plugin-vault": "0.1.8",
"@backstage/plugin-vault-backend": "0.2.6",
"@backstage/plugin-xcmetrics": "0.2.34",
"@backstage/plugin-scaffolder-node": "0.0.0"
"@backstage/plugin-scaffolder-node": "0.0.0",
"@backstage/backend-dev-utils": "0.0.0",
"@backstage/eslint-plugin": "0.0.0",
"@backstage/plugin-entity-validation": "0.0.0",
"@backstage/plugin-graphql-voyager": "0.0.0",
"@backstage/plugin-lighthouse-backend": "0.0.0",
"@backstage/plugin-lighthouse-common": "0.0.0"
},
"changesets": [
"afraid-foxes-provide",
"afraid-planets-crash",
"brave-cougars-burn",
"breezy-ears-rule",
"bright-eagles-love",
"bright-plums-cough",
"bright-teachers-compete",
"brown-islands-own",
"calm-avocados-exercise",
"chatty-owls-care",
"chilled-sheep-collect",
"clean-queens-judge",
"cold-cycles-switch",
"cool-spoons-bathe",
"create-app-1674561612",
"cuddly-boxes-agree",
"cyan-deers-walk",
"dry-donkeys-cheer",
"dull-fishes-suffer",
"dull-gorillas-sing",
"eight-falcons-explode",
"eight-hotels-sparkle",
"eight-vans-drum",
"eleven-shoes-crash",
"few-moons-accept",
"flat-cups-itch",
"four-candles-add",
"four-rivers-enjoy",
"four-tables-fix",
"friendly-chefs-rule",
"friendly-scissors-shop",
"gold-bulldogs-talk",
"gold-lemons-eat",
"gold-masks-sleep",
"great-goats-talk",
"green-adults-retire",
"green-guests-flow",
"grumpy-bottles-stare",
"grumpy-fireants-drop",
"happy-cows-moo",
"hip-chairs-double",
"hip-onions-tan",
"hip-pugs-teach",
"hip-tables-prove",
"hot-lions-cover",
"hot-wasps-cover",
"hungry-news-fix",
"itchy-chairs-punch",
"itchy-goats-melt",
"khaki-toes-care",
"late-rice-crash",
"lazy-badgers-rule",
"lazy-badgers-try",
"lemon-tables-train",
"little-jars-lay",
"long-chefs-burn",
"lovely-ladybugs-taste",
"many-nails-joke",
"many-pans-unite",
"mean-squids-kneel",
"modern-cats-worry",
"nasty-beans-accept",
"neat-schools-raise",
"neat-zebras-run",
"nervous-apricots-whisper",
"nervous-mangos-rhyme",
"nervous-phones-shout",
"new-pumpkins-sleep",
"nine-glasses-invent",
"nine-guests-compete",
"nine-ravens-kiss",
"ninety-hats-serve",
"old-knives-wonder",
"old-ways-know",
"perfect-cheetahs-serve",
"pink-falcons-serve",
"poor-moons-confess",
"popular-dancers-join",
"pretty-ladybugs-taste",
"proud-glasses-live",
"purple-feet-smile",
"quick-ladybugs-reply",
"quick-mice-change",
"rare-berries-give",
"rare-melons-battle",
"red-kiwis-compare",
"renovate-0b349f9",
"renovate-0c3644c",
"renovate-53e8b07",
"rich-snakes-rest",
"rotten-mayflies-love",
"selfish-frogs-punch",
"serious-pigs-watch",
"sharp-lobsters-build",
"shiny-years-tap",
"short-apes-relate",
"shy-buses-mix",
"shy-steaks-invite",
"silent-peas-fly",
"silly-buckets-joke",
"silly-socks-lie",
"silly-turkeys-hang",
"silver-wolves-breathe",
"slow-carrots-sniff",
"slow-moles-sin",
"smart-dingos-raise",
"soft-actors-worry",
"soft-boxes-buy",
"soft-snails-notice",
"spotty-coats-clean",
"stale-dots-smile",
"stale-experts-punch",
"stupid-ladybugs-brake",
"swift-fishes-smash",
"tall-falcons-teach",
"tall-tables-hide",
"tall-years-relate",
"tasty-jobs-help",
"thick-clocks-pump",
"thick-tables-travel",
"thin-donkeys-attack",
"thin-scissors-press",
"tough-jeans-camp",
"twenty-islands-wonder",
"twenty-parents-relate",
"two-melons-lie",
"violet-tips-rhyme",
"weak-radios-sing",
"wicked-beers-walk",
"wild-donkeys-rescue",
"witty-moose-itch",
"yellow-roses-tell",
"young-beans-float",
"young-points-drop",
"young-singers-learn"
]
}
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-test-utils': patch
'@backstage/backend-defaults': patch
---
Use the new `*ServiceFactory` exports from `@backstage/backend-app-api`
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-test-utils': patch
'@backstage/backend-app-api': patch
---
Updated usage of `ServiceFactory`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': minor
---
**BREAKING**: Switched out `LogMeta` type for `JsonObject`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-app-api': minor
---
**BREAKING** Renaming `*Factory` exports to `*ServiceFactory` instead. For example `configFactory` now is exported as `configServiceFactory`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-react': minor
---
refactor `createAsyncValidators` to be recursive to ensure validators are called in nested schemas.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-app-api': patch
---
Moved the options of the `config` and `rootHttpRouter` services out to the factories themselves, where they belong
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-entity-validation': minor
---
First implementation for the entity validation UI. For more information refer to its `README.md`.
+35
View File
@@ -0,0 +1,35 @@
---
'@backstage/plugin-techdocs-module-addons-contrib': patch
'@backstage/plugin-techdocs': patch
---
Create a TechDocs `<LightBox/>` addon that allows users to open images in a light-box on documentation pages, they can navigate between images if there are several on one page.
Here's an example on how to use it in a Backstage app:
```diff
import {
DefaultTechDocsHome,
TechDocsIndexPage,
TechDocsReaderPage,
} from '@backstage/plugin-techdocs';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react/alpha';
+import { LightBox } from '@backstage/plugin-techdocs-module-addons-contrib';
const AppRoutes = () => {
<FlatRoutes>
// other plugin routes
<Route path="/docs" element={<TechDocsIndexPage />}>
<DefaultTechDocsHome />
</Route>
<Route
path="/docs/:namespace/:kind/:name/*"
element={<TechDocsReaderPage />}
>
<TechDocsAddons>
+ <LightBox />
</TechDocsAddons>
</Route>
</FlatRoutes>;
};
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-app-api': minor
---
**BREAKING** `HttpServerCertificateOptions` when specified with a `key` and `cert` should also have the `type: 'pem'` instead of `type: 'plain'`
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-cost-insights': patch
---
Fix bug in EntityCostsCard if cost aggregation array is empty. Allow title override on the Cost Insights Page
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-test-utils': patch
'@backstage/backend-app-api': patch
---
Updated usages of `LogMeta`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': minor
---
Switch `ServiceFactory` to be an opaque type, keeping only the `service` field as public API, but also adding a type parameter for the service scope.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': minor
---
Switched `BackendFeature` to be an opaque type.
+2 -2
View File
@@ -18,12 +18,12 @@ jobs:
if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request )
steps:
- name: PR sync
uses: backstage/actions/pr-sync@v0.6.0
uses: backstage/actions/pr-sync@v0.6.1
with:
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
installation-id: ${{ secrets.BACKSTAGE_GOALIE_INSTALLATION_ID }}
project-id: PVT_kwDOBFKqdc02LQ
excluded-users: ${{ secrets.OOO_USERS }}
auto-assign: false
owning-teams: '@backstage/techdocs-core'
@@ -61,7 +61,7 @@ class DefaultFooService implements FooService {
}
}
export const fooFactory = createServiceFactory({
export const fooServiceFactory = createServiceFactory({
service: fooServiceRef,
deps: { bar: barServiceRef },
factory({ bar }) {
@@ -75,7 +75,7 @@ To create a service factory we need to provide a reference to the `service` for
If you need the creation of the service instance to be asynchronous, you can make the `factory` function async. For example:
```ts
export const fooFactory = createServiceFactory({
export const fooServiceFactory = createServiceFactory({
service: fooServiceRef,
deps: {},
async factory() {
@@ -94,18 +94,18 @@ To install a service factory in a backend instance, we pass it in through the `s
```ts
const backend = createBackend({
services: [fooFactory()],
services: [fooServiceFactory()],
});
```
Note that we call `fooFactory` to create the service factory instance. This is because `createServiceFactory` always returns a factory function that creates the actual service factory. This is done to always allow for options to be added to the service factory in the future, without breaking existing code. To add options to your service factory, you wrap the object passed to `createServiceFactory` in a callback that accepts the desired options. For example:
Note that we call `fooServiceFactory` to create the service factory instance. This is because `createServiceFactory` always returns a factory function that creates the actual service factory. This is done to always allow for options to be added to the service factory in the future, without breaking existing code. To add options to your service factory, you wrap the object passed to `createServiceFactory` in a callback that accepts the desired options. For example:
```ts
export interface FooFactoryOptions {
mode: 'eager' | 'lazy';
}
export const fooFactory = createServiceFactory(
export const fooServiceFactory = createServiceFactory(
(options?: FooFactoryOptions) => ({
service: fooServiceRef,
deps: { bar: barServiceRef },
@@ -120,7 +120,7 @@ This lets us use the options to customize the factory implementation in any way
```ts
const backend = createBackend({
services: [fooFactory({ mode: 'eager' })],
services: [fooServiceFactory({ mode: 'eager' })],
});
```
@@ -164,7 +164,7 @@ Plugin scoped services have access to a plugin metadata service, which is a spec
The plugin metadata service is the base for all plugin specific customizations for services. For example, the default implementation of the plugin scoped logger service uses the plugin metadata service to attach the plugin ID as a field in all log messages:
```ts
export const loggerFactory = createServiceFactory({
export const loggerServiceFactory = createServiceFactory({
service: coreServices.logger,
deps: {
rootLogger: coreServices.rootLogger,
@@ -183,7 +183,7 @@ Some services may benefit from having a context that is shared across all instan
The root context is defined as part of the service factory by passing the `createRootContext` option:
```ts
export const fooFactory = createServiceFactory({
export const fooServiceFactory = createServiceFactory({
service: fooServiceRef,
deps: { rootLogger: coreServices.rootLogger, bar: barServiceRef },
createRootContext({ rootLogger }) {
@@ -66,12 +66,12 @@ export const catalogProcessingExtensionPoint = createExtensionPoint<CatalogProce
### Services
| Description | Pattern | Examples |
| ----------- | ------------------- | -------------------------------------------------- |
| Interface | `<Name>Service` | `LoggerService`, `DatabaseService` |
| Reference | `<name>ServiceRef` | `loggerServiceRef`, `databaseServiceRef` |
| ID | `<pluginId>.<name>` | `'core.rootHttpRouter'`, `'catalog.catalogClient'` |
| Factory | `<name>Factory` | `loggerFactory`, `databaseFactory` |
| Description | Pattern | Examples |
| ----------- | ---------------------- | -------------------------------------------------- |
| Interface | `<Name>Service` | `LoggerService`, `DatabaseService` |
| Reference | `<name>ServiceRef` | `loggerServiceRef`, `databaseServiceRef` |
| ID | `<pluginId>.<name>` | `'core.rootHttpRouter'`, `'catalog.catalogClient'` |
| Factory | `<name>ServiceFactory` | `loggerServiceFactory`, `databaseServiceFactory` |
Example:
@@ -85,7 +85,7 @@ export const catalogClientServiceRef = createServiceRef<CatalogClientService>({
...
})
export const catalogClientFactory = createServiceFactory({
export const catalogClientServiceFactory = createServiceFactory({
service: catalogClientServiceRef,
...
})
@@ -61,11 +61,11 @@ All of these services can be replaced with your own implementations if you need
For example, let's say we want to customize the core configuration service to enable remote configuration loading. That would look something like this:
```ts
import { configFactory } from '@backstage/backend-app-api';
import { configServiceFactory } from '@backstage/backend-app-api';
const backend = createBackend({
services: [
configFactory({
configServiceFactory({
remote: { reloadIntervalSeconds: 60 },
}),
],
@@ -160,11 +160,11 @@ A shared environment is defined using `createSharedEnvironment`. In this example
```ts
// packages/backend-env/src/index.ts
import { createSharedEnvironment } from '@backstage/backend-plugin-api';
import { customDiscoveryFactory } from './customDiscoveryFactory';
import { customDiscoveryServiceFactory } from './customDiscoveryServiceFactory';
export const env = createSharedEnvironment({
services: [
customDiscoveryFactory(), // custom DiscoveryService implementation
customDiscoveryServiceFactory(), // custom DiscoveryService implementation
],
});
```
@@ -59,11 +59,11 @@ There's additional configuration that you can optionally pass to setup the `http
You can configure these additional options by adding an override for the core service when calling `createBackend` like follows:
```ts
import { httpRouterFactory } from '@backstage/backend-app-api';
import { httpRouterServiceFactory } from '@backstage/backend-app-api';
const backend = createBackend({
services: [
httpRouterFactory({
httpRouterServiceFactory({
getPath: (pluginId: string) => `/plugins/${pluginId}`,
}),
],
@@ -116,11 +116,11 @@ There's additional options that you can pass to configure the root HTTP Router s
You can configure the root HTTP Router service by passing the options to the `createBackend` function.
```ts
import { rootHttpRouterFactory } from '@backstage/backend-app-api';
import { rootHttpRouterServiceFactory } from '@backstage/backend-app-api';
const backend = createBackend({
services: [
rootHttpRouterFactory({
rootHttpRouterServiceFactory({
configure: ({ app, middleware, routes, config, logger, lifecycle }) => {
// the built in middleware is provided through an option in the configure function
app.use(middleware.helmet());
@@ -183,11 +183,11 @@ There's additional configuration that you can optionally pass to setup the `conf
You can configure these additional options by adding an override for the core service when calling `createBackend` like follows:
```ts
import { configFactory } from '@backstage/backend-app-api';
import { configServiceFactory } from '@backstage/backend-app-api';
const backend = createBackend({
services: [
configFactory({
configServiceFactory({
argv: [
'--config',
'/backstage/app-config.development.yaml',
@@ -438,11 +438,11 @@ There's additional configuration that you can optionally pass to setup the `iden
You can configure these additional options by adding an override for the core service when calling `createBackend` like follows:
```ts
import { identityFactory } from '@backstage/backend-app-api';
import { identityServiceFactory } from '@backstage/backend-app-api';
const backend = createBackend({
services: [
identityFactory({
identityServiceFactory({
issuer: 'backstage',
algorithms: ['ES256', 'RS256'],
}),
+1
View File
@@ -125,6 +125,7 @@ discover available Addons, we've compiled a list of them here:
| [`<ExpandableNavigation />`](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.expandablenavigation) | `@backstage/plugin-techdocs-module-addons-contrib` | Allows TechDocs users to expand or collapse the entire TechDocs main navigation, and keeps the user's preferred state between documentation sites. |
| [`<ReportIssue />`](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.reportissue) | `@backstage/plugin-techdocs-module-addons-contrib` | Allows TechDocs users to select a portion of text on a TechDocs page and open an issue against the repository that contains the documentation, populating the issue description with the selected text according to a configurable template. |
| [`<TextSize />`](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.textsize) | `@backstage/plugin-techdocs-module-addons-contrib` | This TechDocs addon allows users to customize text size on documentation pages, they can select how much they want to increase or decrease the font size via slider or buttons. The default value for font size is 100% and this setting is kept in the browser's local storage whenever it is changed. |
| [`<LightBox />`](https://backstage.io/docs/reference/plugin-techdocs-module-addons-contrib.lightbox) | `@backstage/plugin-techdocs-module-addons-contrib` | This TechDocs addon allows users to open images in a light-box on documentation pages, they can navigate between images if there are several on one page. The image size of the light-box image is the same as the image size on the document page. |
Got an Addon to contribute? Feel free to add a row above!
+2 -2
View File
@@ -262,12 +262,12 @@ You will have to install the `mkdocs` and `mkdocs-techdocs-core` package from
pip, as well as `graphviz` and `plantuml` from your OS package manager (e.g.
apt).
You can do so by including the following lines in the last step of your
You can do so by including the following lines right above `USER node` of your
`Dockerfile`:
```Dockerfile
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip3 install mkdocs-techdocs-core==1.0.1
RUN pip3 install mkdocs-techdocs-core==1.1.7
```
Please be aware that the version requirement could change, you need to check our
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -8361,11 +8361,11 @@ __metadata:
linkType: hard
"prettier@npm:^2.6.2":
version: 2.8.2
resolution: "prettier@npm:2.8.2"
version: 2.8.4
resolution: "prettier@npm:2.8.4"
bin:
prettier: bin-prettier.js
checksum: 740c56c2128d587d656ea1dde9bc9c3503dfc94db4f3ac387259215eeb2e216680bdad9d18a0c9feecc6b42cfa188d6fa777df4c36c1d00cedd4199074fbfbd2
checksum: c173064bf3df57b6d93d19aa98753b9b9dd7657212e33b41ada8e2e9f9884066bb9ca0b4005b89b3ab137efffdf8fbe0b462785aba20364798ff4303aadda57e
languageName: node
linkType: hard
+3 -3
View File
@@ -7369,11 +7369,11 @@ __metadata:
linkType: hard
"prettier@npm:^2.6.2":
version: 2.8.2
resolution: "prettier@npm:2.8.2"
version: 2.8.4
resolution: "prettier@npm:2.8.4"
bin:
prettier: bin-prettier.js
checksum: 740c56c2128d587d656ea1dde9bc9c3503dfc94db4f3ac387259215eeb2e216680bdad9d18a0c9feecc6b42cfa188d6fa777df4c36c1d00cedd4199074fbfbd2
checksum: c173064bf3df57b6d93d19aa98753b9b9dd7657212e33b41ada8e2e9f9884066bb9ca0b4005b89b3ab137efffdf8fbe0b462785aba20364798ff4303aadda57e
languageName: node
linkType: hard
+1 -1
View File
@@ -47,7 +47,7 @@
"@types/react": "^17",
"@types/react-dom": "^17"
},
"version": "1.11.0-next.1",
"version": "1.11.0-next.2",
"dependencies": {
"@backstage/errors": "workspace:^",
"@manypkg/get-packages": "^1.1.3"
+11
View File
@@ -1,5 +1,16 @@
# @backstage/app-defaults
## 1.1.1-next.1
### Patch Changes
- Updated dependencies
- @backstage/core-components@0.12.4-next.1
- @backstage/core-app-api@1.4.1-next.0
- @backstage/core-plugin-api@1.3.0
- @backstage/theme@0.2.16
- @backstage/plugin-permission-react@0.4.9
## 1.1.1-next.0
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/app-defaults",
"description": "Provides the default wiring of a Backstage App",
"version": "1.1.1-next.0",
"version": "1.1.1-next.1",
"publishConfig": {
"access": "public",
"main": "dist/index.esm.js",
+64
View File
@@ -1,5 +1,69 @@
# example-app
## 0.2.80-next.2
### Patch Changes
- Updated dependencies
- @backstage/plugin-scaffolder-react@1.1.0-next.2
- @backstage/plugin-scaffolder@1.11.0-next.2
- @backstage/cli@0.22.2-next.1
- @backstage/plugin-api-docs@0.9.0-next.2
- @backstage/plugin-tech-radar@0.6.1-next.1
- @backstage/catalog-model@1.2.0-next.1
- @backstage/plugin-techdocs@1.5.0-next.2
- @backstage/plugin-explore@0.4.0-next.2
- @backstage/plugin-search-react@1.5.0-next.1
- @backstage/plugin-sentry@0.5.0-next.2
- @backstage/plugin-circleci@0.3.15-next.2
- @backstage/core-components@0.12.4-next.1
- @backstage/plugin-azure-sites@0.1.4-next.2
- @backstage/plugin-search@1.1.0-next.2
- @backstage/plugin-lighthouse@0.4.0-next.2
- @backstage/app-defaults@1.1.1-next.1
- @backstage/config@1.0.6
- @backstage/core-app-api@1.4.1-next.0
- @backstage/core-plugin-api@1.3.0
- @backstage/integration-react@1.1.10-next.1
- @backstage/theme@0.2.16
- @backstage/plugin-airbrake@0.3.15-next.2
- @backstage/plugin-apache-airflow@0.2.8-next.1
- @backstage/plugin-azure-devops@0.2.6-next.2
- @backstage/plugin-badges@0.2.39-next.2
- @backstage/plugin-catalog-common@1.0.11-next.1
- @backstage/plugin-catalog-graph@0.2.27-next.2
- @backstage/plugin-catalog-import@0.9.5-next.2
- @backstage/plugin-catalog-react@1.3.0-next.2
- @backstage/plugin-cloudbuild@0.3.15-next.2
- @backstage/plugin-code-coverage@0.2.8-next.2
- @backstage/plugin-cost-insights@0.12.4-next.2
- @backstage/plugin-dynatrace@2.0.0-next.2
- @backstage/plugin-gcalendar@0.3.11-next.1
- @backstage/plugin-gcp-projects@0.3.34-next.1
- @backstage/plugin-github-actions@0.5.15-next.2
- @backstage/plugin-gocd@0.1.21-next.2
- @backstage/plugin-graphiql@0.2.47-next.1
- @backstage/plugin-home@0.4.31-next.2
- @backstage/plugin-jenkins@0.7.14-next.2
- @backstage/plugin-kafka@0.3.15-next.2
- @backstage/plugin-kubernetes@0.7.8-next.2
- @backstage/plugin-newrelic@0.3.33-next.1
- @backstage/plugin-newrelic-dashboard@0.2.8-next.2
- @backstage/plugin-org@0.6.5-next.2
- @backstage/plugin-pagerduty@0.5.8-next.2
- @backstage/plugin-permission-react@0.4.9
- @backstage/plugin-playlist@0.1.6-next.2
- @backstage/plugin-rollbar@0.4.15-next.2
- @backstage/plugin-search-common@1.2.1
- @backstage/plugin-shortcuts@0.3.7-next.1
- @backstage/plugin-stack-overflow@0.1.11-next.2
- @backstage/plugin-tech-insights@0.3.7-next.2
- @backstage/plugin-techdocs-module-addons-contrib@1.0.10-next.2
- @backstage/plugin-techdocs-react@1.1.3-next.2
- @backstage/plugin-todo@0.2.17-next.2
- @backstage/plugin-user-settings@0.6.3-next.2
- @internal/plugin-catalog-customized@0.0.7-next.2
## 0.2.80-next.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-app",
"version": "0.2.80-next.1",
"version": "0.2.80-next.2",
"private": true,
"backstage": {
"role": "frontend"
+2
View File
@@ -78,6 +78,7 @@ import {
ExpandableNavigation,
ReportIssue,
TextSize,
LightBox,
} from '@backstage/plugin-techdocs-module-addons-contrib';
import {
SettingsLayout,
@@ -203,6 +204,7 @@ const routes = (
<ExpandableNavigation />
<ReportIssue />
<TextSize />
<LightBox />
</TechDocsAddons>
</Route>
<Route
@@ -154,6 +154,7 @@ import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import {
TextSize,
ReportIssue,
LightBox,
} from '@backstage/plugin-techdocs-module-addons-contrib';
import { EntityCostInsightsContent } from '@backstage/plugin-cost-insights';
@@ -205,6 +206,7 @@ const techdocsContent = (
<TechDocsAddons>
<TextSize />
<ReportIssue />
<LightBox />
</TechDocsAddons>
</EntityTechdocsContent>
);
@@ -68,7 +68,7 @@ export const LowerCaseValuePickerFieldExtension = scaffolderPlugin.provide(
const MockDelayComponent = (
props: NextFieldExtensionComponentProps<{ test?: string }>,
) => {
const { onChange, formData, rawErrors } = props;
const { onChange, formData, rawErrors = [] } = props;
return (
<TextField
label="test"
+28
View File
@@ -1,5 +1,33 @@
# @backstage/backend-app-api
## 0.4.0-next.2
### Minor Changes
- 01a075ec1d: **BREAKING**: Renamed `RootHttpRouterConfigureOptions` to `RootHttpRouterConfigureContext`, and removed the unused type `ServiceOrExtensionPoint`.
- 4ae71b7f2e: **BREAKING** Renaming `*Factory` exports to `*ServiceFactory` instead. For example `configFactory` now is exported as `configServiceFactory`.
- d31d8e00b3: **BREAKING** `HttpServerCertificateOptions` when specified with a `key` and `cert` should also have the `type: 'pem'` instead of `type: 'plain'`
### Patch Changes
- e716946103: Updated usage of the lifecycle service.
- f60cca9da1: Updated database factory to pass service deps required for restoring database state during development.
- 610d65e143: Updates to match new `BackendFeature` type.
- ab22515647: The shutdown signal handlers are now installed as part of the backend instance rather than the lifecycle service, and explicitly cause the process to exit.
- b729f9f31f: Moved the options of the `config` and `rootHttpRouter` services out to the factories themselves, where they belong
- 71a5ec0f06: Updated usages of `LogMeta`.
- Updated dependencies
- @backstage/backend-plugin-api@0.4.0-next.2
- @backstage/backend-common@0.18.2-next.2
- @backstage/backend-tasks@0.4.3-next.2
- @backstage/plugin-auth-node@0.2.11-next.2
- @backstage/plugin-permission-node@0.7.5-next.2
- @backstage/cli-common@0.1.11
- @backstage/config@1.0.6
- @backstage/config-loader@1.1.8
- @backstage/errors@1.1.4
- @backstage/types@1.0.2
## 0.3.2-next.1
### Patch Changes
+71 -44
View File
@@ -11,17 +11,16 @@ import { ConfigService } from '@backstage/backend-plugin-api';
import { CorsOptions } from 'cors';
import { ErrorRequestHandler } from 'express';
import { Express as Express_2 } from 'express';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
import { Format } from 'logform';
import { Handler } from 'express';
import { HelmetOptions } from 'helmet';
import * as http from 'http';
import { HttpRouterService } from '@backstage/backend-plugin-api';
import { IdentityService } from '@backstage/backend-plugin-api';
import { JsonObject } from '@backstage/types';
import { LifecycleService } from '@backstage/backend-plugin-api';
import { LoadConfigOptionsRemote } from '@backstage/config-loader';
import { LoggerService } from '@backstage/backend-plugin-api';
import { LogMeta } from '@backstage/backend-plugin-api';
import { PermissionsService } from '@backstage/backend-plugin-api';
import { PluginCacheManager } from '@backstage/backend-common';
import { PluginDatabaseManager } from '@backstage/backend-common';
@@ -34,7 +33,6 @@ import { RootLoggerService } from '@backstage/backend-plugin-api';
import { SchedulerService } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceFactoryOrFunction } from '@backstage/backend-plugin-api';
import { ServiceRef } from '@backstage/backend-plugin-api';
import { TokenManagerService } from '@backstage/backend-plugin-api';
import { transport } from 'winston';
import { UrlReader } from '@backstage/backend-common';
@@ -50,10 +48,10 @@ export interface Backend {
}
// @public (undocumented)
export const cacheFactory: () => ServiceFactory<PluginCacheManager>;
// @public (undocumented)
export const configFactory: () => ServiceFactory<ConfigService>;
export const cacheServiceFactory: () => ServiceFactory<
PluginCacheManager,
'plugin'
>;
// @public (undocumented)
export interface ConfigFactoryOptions {
@@ -61,6 +59,11 @@ export interface ConfigFactoryOptions {
remote?: LoadConfigOptionsRemote;
}
// @public (undocumented)
export const configServiceFactory: (
options?: ConfigFactoryOptions | undefined,
) => ServiceFactory<ConfigService, 'root'>;
// @public (undocumented)
export function createConfigSecretEnumerator(options: {
logger: LoggerService;
@@ -88,7 +91,10 @@ export interface CreateSpecializedBackendOptions {
}
// @public (undocumented)
export const databaseFactory: () => ServiceFactory<PluginDatabaseManager>;
export const databaseServiceFactory: () => ServiceFactory<
PluginDatabaseManager,
'plugin'
>;
// @public
export class DefaultRootHttpRouter implements RootHttpRouterService {
@@ -106,7 +112,10 @@ export interface DefaultRootHttpRouterOptions {
}
// @public (undocumented)
export const discoveryFactory: () => ServiceFactory<PluginEndpointDiscovery>;
export const discoveryServiceFactory: () => ServiceFactory<
PluginEndpointDiscovery,
'plugin'
>;
// @public
export interface ExtendedHttpServer extends http.Server {
@@ -118,20 +127,20 @@ export interface ExtendedHttpServer extends http.Server {
stop(): Promise<void>;
}
// @public (undocumented)
export const httpRouterFactory: (
options?: HttpRouterFactoryOptions | undefined,
) => ServiceFactory<HttpRouterService>;
// @public (undocumented)
export interface HttpRouterFactoryOptions {
getPath?(pluginId: string): string;
}
// @public (undocumented)
export const httpRouterServiceFactory: (
options?: HttpRouterFactoryOptions | undefined,
) => ServiceFactory<HttpRouterService, 'plugin'>;
// @public
export type HttpServerCertificateOptions =
| {
type: 'plain';
type: 'pem';
key: string;
cert: string;
}
@@ -151,19 +160,22 @@ export type HttpServerOptions = {
};
};
// @public (undocumented)
export const identityFactory: (
options?: IdentityFactoryOptions | undefined,
) => ServiceFactory<IdentityService>;
// @public
export type IdentityFactoryOptions = {
issuer?: string;
algorithms?: string[];
};
// @public (undocumented)
export const identityServiceFactory: (
options?: IdentityFactoryOptions | undefined,
) => ServiceFactory<IdentityService, 'plugin'>;
// @public
export const lifecycleFactory: () => ServiceFactory<LifecycleService>;
export const lifecycleServiceFactory: () => ServiceFactory<
LifecycleService,
'plugin'
>;
// @public
export function loadBackendConfig(options: {
@@ -174,7 +186,10 @@ export function loadBackendConfig(options: {
}>;
// @public (undocumented)
export const loggerFactory: () => ServiceFactory<LoggerService>;
export const loggerServiceFactory: () => ServiceFactory<
LoggerService,
'plugin'
>;
// @public
export class MiddlewareFactory {
@@ -202,7 +217,10 @@ export interface MiddlewareFactoryOptions {
}
// @public (undocumented)
export const permissionsFactory: () => ServiceFactory<PermissionsService>;
export const permissionsServiceFactory: () => ServiceFactory<
PermissionsService,
'plugin'
>;
// @public
export function readCorsOptions(config?: Config): CorsOptions;
@@ -214,7 +232,7 @@ export function readHelmetOptions(config?: Config): HelmetOptions;
export function readHttpServerOptions(config?: Config): HttpServerOptions;
// @public (undocumented)
export interface RootHttpRouterConfigureOptions {
export interface RootHttpRouterConfigureContext {
// (undocumented)
app: Express_2;
// (undocumented)
@@ -229,55 +247,64 @@ export interface RootHttpRouterConfigureOptions {
routes: RequestHandler;
}
// @public (undocumented)
export const rootHttpRouterFactory: () => ServiceFactory<RootHttpRouterService>;
// @public (undocumented)
export type RootHttpRouterFactoryOptions = {
indexPath?: string | false;
configure?(options: RootHttpRouterConfigureOptions): void;
configure?(context: RootHttpRouterConfigureContext): void;
};
// @public (undocumented)
export const rootHttpRouterServiceFactory: (
options?: RootHttpRouterFactoryOptions | undefined,
) => ServiceFactory<RootHttpRouterService, 'root'>;
// @public
export const rootLifecycleFactory: () => ServiceFactory<RootLifecycleService>;
export const rootLifecycleServiceFactory: () => ServiceFactory<
RootLifecycleService,
'root'
>;
// @public (undocumented)
export const rootLoggerFactory: () => ServiceFactory<RootLoggerService>;
export const rootLoggerServiceFactory: () => ServiceFactory<
RootLoggerService,
'root'
>;
// @public (undocumented)
export const schedulerFactory: () => ServiceFactory<SchedulerService>;
export const schedulerServiceFactory: () => ServiceFactory<
SchedulerService,
'plugin'
>;
// @public (undocumented)
export type ServiceOrExtensionPoint<T = unknown> =
| ExtensionPoint<T>
| ServiceRef<T>;
export const tokenManagerServiceFactory: () => ServiceFactory<
TokenManagerService,
'plugin'
>;
// @public (undocumented)
export const tokenManagerFactory: () => ServiceFactory<TokenManagerService>;
// @public (undocumented)
export const urlReaderFactory: () => ServiceFactory<UrlReader>;
export const urlReaderServiceFactory: () => ServiceFactory<UrlReader, 'plugin'>;
// @public
export class WinstonLogger implements RootLoggerService {
// (undocumented)
addRedactions(redactions: Iterable<string>): void;
// (undocumented)
child(meta: LogMeta): LoggerService;
child(meta: JsonObject): LoggerService;
static colorFormat(): Format;
static create(options: WinstonLoggerOptions): WinstonLogger;
// (undocumented)
debug(message: string, meta?: LogMeta): void;
debug(message: string, meta?: JsonObject): void;
// (undocumented)
error(message: string, meta?: LogMeta): void;
error(message: string, meta?: JsonObject): void;
// (undocumented)
info(message: string, meta?: LogMeta): void;
info(message: string, meta?: JsonObject): void;
static redacter(): {
format: Format;
add: (redactions: Iterable<string>) => void;
};
// (undocumented)
warn(message: string, meta?: LogMeta): void;
warn(message: string, meta?: JsonObject): void;
}
// @public (undocumented)
@@ -287,7 +314,7 @@ export interface WinstonLoggerOptions {
// (undocumented)
level: string;
// (undocumented)
meta?: LogMeta;
meta?: JsonObject;
// (undocumented)
transports: transport[];
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-app-api",
"description": "Core API used by Backstage backend apps",
"version": "0.3.2-next.1",
"version": "0.4.0-next.2",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -53,7 +53,7 @@ describe('readHttpServerOptions', () => {
{
listen: { host: '', port: 7007 },
https: {
certificate: { type: 'plain', cert: 'my-cert', key: 'my-key' },
certificate: { type: 'pem', cert: 'my-cert', key: 'my-key' },
},
},
],
+1 -1
View File
@@ -93,7 +93,7 @@ function readHttpsOptions(config?: Config): HttpServerOptions['https'] {
return {
certificate: {
type: 'plain',
type: 'pem',
cert: cc.getString('certificate.cert'),
key: cc.getString('certificate.key'),
},
+1 -1
View File
@@ -51,7 +51,7 @@ export type HttpServerOptions = {
*/
export type HttpServerCertificateOptions =
| {
type: 'plain';
type: 'pem';
key: string;
cert: string;
}
@@ -16,9 +16,9 @@
import {
LoggerService,
LogMeta,
RootLoggerService,
} from '@backstage/backend-plugin-api';
import { JsonObject } from '@backstage/types';
import { Format, TransformableInfo } from 'logform';
import {
Logger,
@@ -33,7 +33,7 @@ import { escapeRegExp } from '../lib/escapeRegExp';
* @public
*/
export interface WinstonLoggerOptions {
meta?: LogMeta;
meta?: JsonObject;
level: string;
format: Format;
transports: Transport[];
@@ -150,23 +150,23 @@ export class WinstonLogger implements RootLoggerService {
this.#addRedactions = addRedactions;
}
error(message: string, meta?: LogMeta): void {
error(message: string, meta?: JsonObject): void {
this.#winston.error(message, meta);
}
warn(message: string, meta?: LogMeta): void {
warn(message: string, meta?: JsonObject): void {
this.#winston.warn(message, meta);
}
info(message: string, meta?: LogMeta): void {
info(message: string, meta?: JsonObject): void {
this.#winston.info(message, meta);
}
debug(message: string, meta?: LogMeta): void {
debug(message: string, meta?: JsonObject): void {
this.#winston.debug(message, meta);
}
child(meta: LogMeta): LoggerService {
child(meta: JsonObject): LoggerService {
return new WinstonLogger(this.#winston.child(meta));
}
@@ -21,7 +21,7 @@ import {
} from '@backstage/backend-plugin-api';
/** @public */
export const cacheFactory = createServiceFactory({
export const cacheServiceFactory = createServiceFactory({
service: coreServices.cache,
deps: {
config: coreServices.config,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { cacheFactory } from './cacheFactory';
export { cacheServiceFactory } from './cacheServiceFactory';
@@ -35,13 +35,14 @@ export interface ConfigFactoryOptions {
}
/** @public */
export const configFactory = createServiceFactory({
service: coreServices.config,
deps: {},
async factory({}, options?: ConfigFactoryOptions) {
const { argv = process.argv, remote } = options ?? {};
const { config } = await loadBackendConfig({ argv, remote });
return config;
},
});
export const configServiceFactory = createServiceFactory(
(options?: ConfigFactoryOptions) => ({
service: coreServices.config,
deps: {},
async factory({}) {
const { argv = process.argv, remote } = options ?? {};
const { config } = await loadBackendConfig({ argv, remote });
return config;
},
}),
);
@@ -14,5 +14,5 @@
* limitations under the License.
*/
export { configFactory } from './configFactory';
export type { ConfigFactoryOptions } from './configFactory';
export { configServiceFactory } from './configServiceFactory';
export type { ConfigFactoryOptions } from './configServiceFactory';
@@ -22,7 +22,7 @@ import {
import { ConfigReader } from '@backstage/config';
/** @public */
export const databaseFactory = createServiceFactory({
export const databaseServiceFactory = createServiceFactory({
service: coreServices.database,
deps: {
config: coreServices.config,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { databaseFactory } from './databaseFactory';
export { databaseServiceFactory } from './databaseServiceFactory';
@@ -21,7 +21,7 @@ import {
} from '@backstage/backend-plugin-api';
/** @public */
export const discoveryFactory = createServiceFactory({
export const discoveryServiceFactory = createServiceFactory({
service: coreServices.discovery,
deps: {
config: coreServices.config,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { discoveryFactory } from './discoveryFactory';
export { discoveryServiceFactory } from './discoveryServiceFactory';
@@ -14,19 +14,12 @@
* limitations under the License.
*/
import {
HttpRouterService,
ServiceFactory,
} from '@backstage/backend-plugin-api';
import { httpRouterFactory } from './httpRouterFactory';
import { httpRouterServiceFactory } from './httpRouterServiceFactory';
describe('httpRouterFactory', () => {
it('should register plugin paths', async () => {
const rootHttpRouter = { use: jest.fn() };
const factory = httpRouterFactory() as Exclude<
ServiceFactory<HttpRouterService>,
{ scope: 'root' }
>;
const factory = httpRouterServiceFactory() as any;
const handler1 = () => {};
const router1 = await factory.factory(
@@ -55,9 +48,9 @@ describe('httpRouterFactory', () => {
it('should use custom path generator', async () => {
const rootHttpRouter = { use: jest.fn() };
const factory = httpRouterFactory({
const factory = httpRouterServiceFactory({
getPath: id => `/some/${id}/path`,
}) as Exclude<ServiceFactory<HttpRouterService>, { scope: 'root' }>;
}) as any;
const handler1 = () => {};
const router1 = await factory.factory(
@@ -31,7 +31,7 @@ export interface HttpRouterFactoryOptions {
}
/** @public */
export const httpRouterFactory = createServiceFactory(
export const httpRouterServiceFactory = createServiceFactory(
(options?: HttpRouterFactoryOptions) => ({
service: coreServices.httpRouter,
deps: {
@@ -14,5 +14,5 @@
* limitations under the License.
*/
export { httpRouterFactory } from './httpRouterFactory';
export type { HttpRouterFactoryOptions } from './httpRouterFactory';
export { httpRouterServiceFactory } from './httpRouterServiceFactory';
export type { HttpRouterFactoryOptions } from './httpRouterServiceFactory';
@@ -34,7 +34,7 @@ export type IdentityFactoryOptions = {
};
/** @public */
export const identityFactory = createServiceFactory(
export const identityServiceFactory = createServiceFactory(
(options?: IdentityFactoryOptions) => ({
service: coreServices.identity,
deps: {
@@ -14,5 +14,5 @@
* limitations under the License.
*/
export { identityFactory } from './identityFactory';
export type { IdentityFactoryOptions } from './identityFactory';
export { identityServiceFactory } from './identityServiceFactory';
export type { IdentityFactoryOptions } from './identityServiceFactory';
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { lifecycleFactory } from './lifecycleFactory';
export { lifecycleServiceFactory } from './lifecycleServiceFactory';
@@ -24,7 +24,7 @@ import {
* Allows plugins to register shutdown hooks that are run when the process is about to exit.
* @public
*/
export const lifecycleFactory = createServiceFactory({
export const lifecycleServiceFactory = createServiceFactory({
service: coreServices.lifecycle,
deps: {
logger: coreServices.logger,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { loggerFactory } from './loggerFactory';
export { loggerServiceFactory } from './loggerServiceFactory';
@@ -20,7 +20,7 @@ import {
} from '@backstage/backend-plugin-api';
/** @public */
export const loggerFactory = createServiceFactory({
export const loggerServiceFactory = createServiceFactory({
service: coreServices.logger,
deps: {
rootLogger: coreServices.rootLogger,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { permissionsFactory } from './permissionsFactory';
export { permissionsServiceFactory } from './permissionsServiceFactory';
@@ -21,7 +21,7 @@ import {
import { ServerPermissionClient } from '@backstage/plugin-permission-node';
/** @public */
export const permissionsFactory = createServiceFactory({
export const permissionsServiceFactory = createServiceFactory({
service: coreServices.permissions,
deps: {
config: coreServices.config,
@@ -15,10 +15,10 @@
*/
export {
rootHttpRouterFactory,
rootHttpRouterServiceFactory,
type RootHttpRouterFactoryOptions,
type RootHttpRouterConfigureOptions,
} from './rootHttpRouterFactory';
type RootHttpRouterConfigureContext,
} from './rootHttpRouterServiceFactory';
export {
DefaultRootHttpRouter,
type DefaultRootHttpRouterOptions,
@@ -32,7 +32,7 @@ import { DefaultRootHttpRouter } from './DefaultRootHttpRouter';
/**
* @public
*/
export interface RootHttpRouterConfigureOptions {
export interface RootHttpRouterConfigureContext {
app: Express;
middleware: MiddlewareFactory;
routes: RequestHandler;
@@ -51,14 +51,11 @@ export type RootHttpRouterFactoryOptions = {
*/
indexPath?: string | false;
configure?(options: RootHttpRouterConfigureOptions): void;
configure?(context: RootHttpRouterConfigureContext): void;
};
function defaultConfigure({
app,
routes,
middleware,
}: RootHttpRouterConfigureOptions) {
function defaultConfigure(context: RootHttpRouterConfigureContext) {
const { app, routes, middleware } = context;
app.use(middleware.helmet());
app.use(middleware.cors());
app.use(middleware.compression());
@@ -69,45 +66,42 @@ function defaultConfigure({
}
/** @public */
export const rootHttpRouterFactory = createServiceFactory({
service: coreServices.rootHttpRouter,
deps: {
config: coreServices.config,
rootLogger: coreServices.rootLogger,
lifecycle: coreServices.rootLifecycle,
},
async factory(
{ config, rootLogger, lifecycle },
{
indexPath,
configure = defaultConfigure,
}: RootHttpRouterFactoryOptions = {},
) {
const logger = rootLogger.child({ service: 'rootHttpRouter' });
const app = express();
export const rootHttpRouterServiceFactory = createServiceFactory(
(options?: RootHttpRouterFactoryOptions) => ({
service: coreServices.rootHttpRouter,
deps: {
config: coreServices.config,
rootLogger: coreServices.rootLogger,
lifecycle: coreServices.rootLifecycle,
},
async factory({ config, rootLogger, lifecycle }) {
const { indexPath, configure = defaultConfigure } = options ?? {};
const logger = rootLogger.child({ service: 'rootHttpRouter' });
const app = express();
const router = DefaultRootHttpRouter.create({ indexPath });
const middleware = MiddlewareFactory.create({ config, logger });
const router = DefaultRootHttpRouter.create({ indexPath });
const middleware = MiddlewareFactory.create({ config, logger });
configure({
app,
routes: router.handler(),
middleware,
config,
logger,
lifecycle,
});
configure({
app,
routes: router.handler(),
middleware,
config,
logger,
lifecycle,
});
const server = await createHttpServer(
app,
readHttpServerOptions(config.getOptionalConfig('backend')),
{ logger },
);
const server = await createHttpServer(
app,
readHttpServerOptions(config.getOptionalConfig('backend')),
{ logger },
);
lifecycle.addShutdownHook(() => server.stop());
lifecycle.addShutdownHook(() => server.stop());
await server.start();
await server.start();
return router;
},
});
return router;
},
}),
);
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { rootLifecycleFactory } from './rootLifecycleFactory';
export { rootLifecycleServiceFactory } from './rootLifecycleServiceFactory';
@@ -15,7 +15,7 @@
*/
import { getVoidLogger } from '@backstage/backend-common';
import { BackendLifecycleImpl } from './rootLifecycleFactory';
import { BackendLifecycleImpl } from './rootLifecycleServiceFactory';
describe('lifecycleService', () => {
it('should execute registered shutdown hook', async () => {
@@ -65,7 +65,7 @@ export class BackendLifecycleImpl implements RootLifecycleService {
*
* @public
*/
export const rootLifecycleFactory = createServiceFactory({
export const rootLifecycleServiceFactory = createServiceFactory({
service: coreServices.rootLifecycle,
deps: {
logger: coreServices.rootLogger,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { rootLoggerFactory } from './rootLoggerFactory';
export { rootLoggerServiceFactory } from './rootLoggerServiceFactory';
@@ -23,7 +23,7 @@ import { transports, format } from 'winston';
import { createConfigSecretEnumerator } from '../../../config';
/** @public */
export const rootLoggerFactory = createServiceFactory({
export const rootLoggerServiceFactory = createServiceFactory({
service: coreServices.rootLogger,
deps: {
config: coreServices.config,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { schedulerFactory } from './schedulerFactory';
export { schedulerServiceFactory } from './schedulerServiceFactory';
@@ -19,13 +19,13 @@ import {
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { startTestBackend } from '@backstage/backend-test-utils';
import { schedulerFactory } from './schedulerFactory';
import { schedulerServiceFactory } from './schedulerServiceFactory';
describe('schedulerFactory', () => {
it('creates sidecar database features', async () => {
expect.assertions(3);
const subject = schedulerFactory();
const subject = schedulerServiceFactory();
const plugin = createBackendPlugin({
pluginId: 'example',
@@ -22,7 +22,7 @@ import {
import { TaskScheduler } from '@backstage/backend-tasks';
/** @public */
export const schedulerFactory = createServiceFactory({
export const schedulerServiceFactory = createServiceFactory({
service: coreServices.scheduler,
deps: {
plugin: coreServices.pluginMetadata,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { tokenManagerFactory } from './tokenManagerFactory';
export { tokenManagerServiceFactory } from './tokenManagerServiceFactory';
@@ -14,22 +14,15 @@
* limitations under the License.
*/
import {
LoggerService,
ServiceFactory,
TokenManagerService,
} from '@backstage/backend-plugin-api';
import { LoggerService } from '@backstage/backend-plugin-api';
import { ConfigReader } from '@backstage/config';
import { tokenManagerFactory } from './tokenManagerFactory';
import { tokenManagerServiceFactory } from './tokenManagerServiceFactory';
describe('tokenManagerFactory', () => {
it('should create managers that can share tokens in development', async () => {
(process.env as { NODE_ENV?: string }).NODE_ENV = 'development';
const factory = tokenManagerFactory() as Exclude<
ServiceFactory<TokenManagerService>,
{ scope: 'root' }
>;
const factory = tokenManagerServiceFactory() as any;
const deps = {
config: new ConfigReader({}),
logger: { warn() {} } as unknown as LoggerService,
@@ -21,7 +21,7 @@ import {
import { ServerTokenManager } from '@backstage/backend-common';
/** @public */
export const tokenManagerFactory = createServiceFactory({
export const tokenManagerServiceFactory = createServiceFactory({
service: coreServices.tokenManager,
deps: {
config: coreServices.config,
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { urlReaderFactory } from './urlReaderFactory';
export { urlReaderServiceFactory } from './urlReaderServiceFactory';
@@ -21,7 +21,7 @@ import {
} from '@backstage/backend-plugin-api';
/** @public */
export const urlReaderFactory = createServiceFactory({
export const urlReaderServiceFactory = createServiceFactory({
service: coreServices.urlReader,
deps: {
config: coreServices.config,
@@ -20,16 +20,19 @@ import {
coreServices,
ServiceRef,
} from '@backstage/backend-plugin-api';
import { BackendLifecycleImpl } from '../services/implementations/rootLifecycle/rootLifecycleFactory';
import { BackendLifecycleImpl } from '../services/implementations/rootLifecycle/rootLifecycleServiceFactory';
import {
BackendRegisterInit,
EnumerableServiceHolder,
ServiceOrExtensionPoint,
} from './types';
// Direct internal import to avoid duplication
// eslint-disable-next-line @backstage/no-forbidden-package-imports
import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring/types';
export class BackendInitializer {
#startPromise?: Promise<void>;
#features = new Map<BackendFeature, unknown>();
#features = new Array<InternalBackendFeature>();
#registerInits = new Array<BackendRegisterInit>();
#extensionPoints = new Map<ExtensionPoint<unknown>, unknown>();
#serviceHolder: EnumerableServiceHolder;
@@ -74,11 +77,22 @@ export class BackendInitializer {
return Object.fromEntries(result);
}
add<TOptions>(feature: BackendFeature, options?: TOptions) {
add(feature: BackendFeature) {
if (this.#startPromise) {
throw new Error('feature can not be added after the backend has started');
}
this.#features.set(feature, options);
if (feature.$$type !== '@backstage/BackendFeature') {
throw new Error(
`Failed to add feature, invalid type '${feature.$$type}'`,
);
}
const internalFeature = feature as InternalBackendFeature;
if (internalFeature.version !== 'v1') {
throw new Error(
`Failed to add feature, invalid version '${internalFeature.version}'`,
);
}
this.#features.push(internalFeature);
}
async start(): Promise<void> {
@@ -117,50 +131,39 @@ export class BackendInitializer {
}
// Initialize all features
for (const [feature] of this.#features) {
const provides = new Set<ExtensionPoint<unknown>>();
for (const feature of this.#features) {
for (const r of feature.getRegistrations()) {
const provides = new Set<ExtensionPoint<unknown>>();
let registerInit: BackendRegisterInit | undefined = undefined;
if (r.type === 'plugin') {
for (const [extRef, extImpl] of r.extensionPoints) {
if (this.#extensionPoints.has(extRef)) {
throw new Error(
`ExtensionPoint with ID '${extRef.id}' is already registered`,
);
}
this.#extensionPoints.set(extRef, extImpl);
provides.add(extRef);
}
}
feature.register({
registerExtensionPoint: (extensionPointRef, impl) => {
if (registerInit) {
throw new Error('registerExtensionPoint called after registerInit');
}
if (this.#extensionPoints.has(extensionPointRef)) {
throw new Error(`API ${extensionPointRef.id} already registered`);
}
this.#extensionPoints.set(extensionPointRef, impl);
provides.add(extensionPointRef);
},
registerInit: registerOptions => {
if (registerInit) {
throw new Error('registerInit must only be called once');
}
registerInit = {
id: feature.id,
provides,
consumes: new Set(Object.values(registerOptions.deps)),
deps: registerOptions.deps,
init: registerOptions.init as BackendRegisterInit['init'],
};
},
});
if (!registerInit) {
throw new Error(
`registerInit was not called by register in ${feature.id}`,
);
this.#registerInits.push({
id: r.type === 'plugin' ? r.pluginId : `${r.pluginId}.${r.moduleId}`,
provides,
consumes: new Set(Object.values(r.init.deps)),
init: r.init,
});
}
this.#registerInits.push(registerInit);
}
const orderedRegisterResults = this.#resolveInitOrder(this.#registerInits);
for (const registerInit of orderedRegisterResults) {
const deps = await this.#getInitDeps(registerInit.deps, registerInit.id);
await registerInit.init(deps);
const deps = await this.#getInitDeps(
registerInit.init.deps,
registerInit.id,
);
await registerInit.init.func(deps);
}
}
@@ -18,36 +18,66 @@ import {
ServiceFactory,
ServiceRef,
coreServices,
createServiceFactory,
} from '@backstage/backend-plugin-api';
import { stringifyError } from '@backstage/errors';
import { EnumerableServiceHolder } from './types';
// Direct internal import to avoid duplication
// eslint-disable-next-line @backstage/no-forbidden-package-imports
import { InternalServiceFactory } from '@backstage/backend-plugin-api/src/services/system/types';
/**
* Keep in sync with `@backstage/backend-plugin-api/src/services/system/types.ts`
* @internal
*/
export type InternalServiceRef<T> = ServiceRef<T> & {
export type InternalServiceRef = ServiceRef<unknown> & {
__defaultFactory?: (
service: ServiceRef<T>,
) => Promise<ServiceFactory<T> | (() => ServiceFactory<T>)>;
service: ServiceRef<unknown>,
) => Promise<ServiceFactory | (() => ServiceFactory)>;
};
function toInternalServiceFactory<TService, TScope extends 'plugin' | 'root'>(
factory: ServiceFactory<TService, TScope>,
): InternalServiceFactory<TService, TScope> {
const f = factory as InternalServiceFactory<TService, TScope>;
if (f.$$type !== '@backstage/ServiceFactory') {
throw new Error(`Invalid service factory, bad type '${f.$$type}'`);
}
if (f.version !== 'v1') {
throw new Error(`Invalid service factory, bad version '${f.version}'`);
}
return f;
}
const pluginMetadataServiceFactory = createServiceFactory(
(options: { pluginId: string }) => ({
service: coreServices.pluginMetadata,
deps: {},
factory: async () => ({ getId: () => options.pluginId }),
}),
);
export class ServiceRegistry implements EnumerableServiceHolder {
readonly #providedFactories: Map<string, ServiceFactory>;
readonly #loadedDefaultFactories: Map<Function, Promise<ServiceFactory>>;
readonly #providedFactories: Map<string, InternalServiceFactory>;
readonly #loadedDefaultFactories: Map<
Function,
Promise<InternalServiceFactory>
>;
readonly #implementations: Map<
ServiceFactory,
InternalServiceFactory,
{
context: Promise<unknown>;
byPlugin: Map<string, Promise<unknown>>;
}
>;
readonly #rootServiceImplementations = new Map<
ServiceFactory,
InternalServiceFactory,
Promise<unknown>
>();
constructor(factories: Array<ServiceFactory<unknown>>) {
this.#providedFactories = new Map(factories.map(f => [f.service.id, f]));
constructor(factories: Array<ServiceFactory>) {
this.#providedFactories = new Map(
factories.map(sf => [sf.service.id, toInternalServiceFactory(sf)]),
);
this.#loadedDefaultFactories = new Map();
this.#implementations = new Map();
}
@@ -55,23 +85,19 @@ export class ServiceRegistry implements EnumerableServiceHolder {
#resolveFactory(
ref: ServiceRef<unknown>,
pluginId: string,
): Promise<ServiceFactory> | undefined {
): Promise<InternalServiceFactory> | undefined {
// Special case handling of the plugin metadata service, generating a custom factory for it each time
if (ref.id === coreServices.pluginMetadata.id) {
return Promise.resolve<
ServiceFactory<typeof coreServices.pluginMetadata.T>
>({
scope: 'plugin',
service: coreServices.pluginMetadata,
deps: {},
factory: async () => ({ getId: () => pluginId }),
});
return Promise.resolve(
toInternalServiceFactory(pluginMetadataServiceFactory({ pluginId })),
);
}
let resolvedFactory: Promise<ServiceFactory> | ServiceFactory | undefined =
this.#providedFactories.get(ref.id);
const { __defaultFactory: defaultFactory } =
ref as InternalServiceRef<unknown>;
let resolvedFactory:
| Promise<InternalServiceFactory>
| InternalServiceFactory
| undefined = this.#providedFactories.get(ref.id);
const { __defaultFactory: defaultFactory } = ref as InternalServiceRef;
if (!resolvedFactory && !defaultFactory) {
return undefined;
}
@@ -82,8 +108,8 @@ export class ServiceRegistry implements EnumerableServiceHolder {
loadedFactory = Promise.resolve()
.then(() => defaultFactory!(ref))
.then(f =>
typeof f === 'function' ? f() : f,
) as Promise<ServiceFactory>;
toInternalServiceFactory(typeof f === 'function' ? f() : f),
);
this.#loadedDefaultFactories.set(defaultFactory!, loadedFactory);
}
resolvedFactory = loadedFactory.catch(error => {
@@ -100,7 +126,7 @@ export class ServiceRegistry implements EnumerableServiceHolder {
return Promise.resolve(resolvedFactory);
}
#checkForMissingDeps(factory: ServiceFactory, pluginId: string) {
#checkForMissingDeps(factory: InternalServiceFactory, pluginId: string) {
const missingDeps = Object.values(factory.deps).filter(ref => {
if (ref.id === coreServices.pluginMetadata.id) {
return false;
@@ -109,7 +135,7 @@ export class ServiceRegistry implements EnumerableServiceHolder {
return false;
}
return !(ref as InternalServiceRef<unknown>).__defaultFactory;
return !(ref as InternalServiceRef).__defaultFactory;
});
if (missingDeps.length) {
@@ -126,7 +152,7 @@ export class ServiceRegistry implements EnumerableServiceHolder {
get<T>(ref: ServiceRef<T>, pluginId: string): Promise<T> | undefined {
return this.#resolveFactory(ref, pluginId)?.then(factory => {
if (factory.scope === 'root') {
if (factory.service.scope === 'root') {
let existing = this.#rootServiceImplementations.get(factory);
if (!existing) {
this.#checkForMissingDeps(factory, pluginId);
@@ -143,7 +169,7 @@ export class ServiceRegistry implements EnumerableServiceHolder {
}
existing = Promise.all(rootDeps).then(entries =>
factory.factory(Object.fromEntries(entries)),
factory.factory(Object.fromEntries(entries), undefined),
);
this.#rootServiceImplementations.set(factory, existing);
}
+1 -5
View File
@@ -14,9 +14,5 @@
* limitations under the License.
*/
export type {
Backend,
CreateSpecializedBackendOptions,
ServiceOrExtensionPoint,
} from './types';
export type { Backend, CreateSpecializedBackendOptions } from './types';
export { createSpecializedBackend } from './createSpecializedBackend';
+4 -2
View File
@@ -34,8 +34,10 @@ export interface BackendRegisterInit {
id: string;
consumes: Set<ServiceOrExtensionPoint>;
provides: Set<ServiceOrExtensionPoint>;
deps: { [name: string]: ServiceOrExtensionPoint };
init: (deps: { [name: string]: unknown }) => Promise<void>;
init: {
deps: { [name: string]: ServiceOrExtensionPoint };
func: (deps: { [name: string]: unknown }) => Promise<void>;
};
}
/**
+19
View File
@@ -1,5 +1,24 @@
# @backstage/backend-common
## 0.18.2-next.2
### Patch Changes
- e716946103: Updated usage of the lifecycle service.
- d31d8e00b3: Updated to work with the new `type: 'pem'` with `createHttpServer` from `@backstage/backend-app-api`
- 0ff03319be: Updated usage of `createBackendPlugin`.
- f60cca9da1: The `DatabaseManager.forPlugin` method now accepts additional service dependencies. There is no need to update existing code to pass these dependencies.
- Updated dependencies
- @backstage/backend-app-api@0.4.0-next.2
- @backstage/backend-plugin-api@0.4.0-next.2
- @backstage/backend-dev-utils@0.1.0-next.0
- @backstage/cli-common@0.1.11
- @backstage/config@1.0.6
- @backstage/config-loader@1.1.8
- @backstage/errors@1.1.4
- @backstage/integration@1.4.2
- @backstage/types@1.0.2
## 0.18.2-next.1
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-common",
"description": "Common functionality library for Backstage backends",
"version": "0.18.2-next.1",
"version": "0.18.2-next.2",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
@@ -15,6 +15,7 @@
*/
import { LoggerService } from '@backstage/backend-plugin-api';
import { JsonObject } from '@backstage/types';
import { Logger as WinstonLogger, createLogger } from 'winston';
import Transport, { TransportStreamOptions } from 'winston-transport';
@@ -31,7 +32,7 @@ class BackstageLoggerTransport extends Transport {
callback();
return;
}
const { level, message, ...meta } = info as { [name: string]: unknown };
const { level, message, ...meta } = info as JsonObject;
switch (level) {
case 'error':
this.backstageLogger.error(String(message), meta);
@@ -102,7 +102,7 @@ export class ServiceBuilderImpl implements ServiceBuilder {
this.serverOptions.https = {
certificate: {
...settings.certificate,
type: 'plain',
type: 'pem',
},
};
}
+9
View File
@@ -1,5 +1,14 @@
# @backstage/backend-defaults
## 0.1.7-next.2
### Patch Changes
- e412d33025: Use the new `*ServiceFactory` exports from `@backstage/backend-app-api`
- Updated dependencies
- @backstage/backend-app-api@0.4.0-next.2
- @backstage/backend-plugin-api@0.4.0-next.2
## 0.1.7-next.1
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/backend-defaults",
"description": "Backend defaults used by Backstage backend apps",
"version": "0.1.7-next.1",
"version": "0.1.7-next.2",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
+30 -30
View File
@@ -16,22 +16,22 @@
import {
Backend,
cacheFactory,
configFactory,
cacheServiceFactory,
configServiceFactory,
createSpecializedBackend,
databaseFactory,
discoveryFactory,
httpRouterFactory,
rootHttpRouterFactory,
lifecycleFactory,
rootLifecycleFactory,
loggerFactory,
permissionsFactory,
rootLoggerFactory,
schedulerFactory,
tokenManagerFactory,
urlReaderFactory,
identityFactory,
databaseServiceFactory,
discoveryServiceFactory,
httpRouterServiceFactory,
rootHttpRouterServiceFactory,
lifecycleServiceFactory,
rootLifecycleServiceFactory,
loggerServiceFactory,
permissionsServiceFactory,
rootLoggerServiceFactory,
schedulerServiceFactory,
tokenManagerServiceFactory,
urlReaderServiceFactory,
identityServiceFactory,
} from '@backstage/backend-app-api';
import {
ServiceFactory,
@@ -44,21 +44,21 @@ import {
import type { InternalSharedBackendEnvironment } from '@backstage/backend-plugin-api/src/wiring/createSharedEnvironment';
export const defaultServiceFactories = [
cacheFactory(),
configFactory(),
databaseFactory(),
discoveryFactory(),
httpRouterFactory(),
identityFactory(),
lifecycleFactory(),
loggerFactory(),
permissionsFactory(),
rootHttpRouterFactory(),
rootLifecycleFactory(),
rootLoggerFactory(),
schedulerFactory(),
tokenManagerFactory(),
urlReaderFactory(),
cacheServiceFactory(),
configServiceFactory(),
databaseServiceFactory(),
discoveryServiceFactory(),
httpRouterServiceFactory(),
identityServiceFactory(),
lifecycleServiceFactory(),
loggerServiceFactory(),
permissionsServiceFactory(),
rootHttpRouterServiceFactory(),
rootLifecycleServiceFactory(),
rootLoggerServiceFactory(),
schedulerServiceFactory(),
tokenManagerServiceFactory(),
urlReaderServiceFactory(),
];
/**
+7
View File
@@ -0,0 +1,7 @@
# @backstage/backend-dev-utils
## 0.1.0-next.0
### Minor Changes
- 9d9cdea117: Introduced a new package for backend development utilities. Similar to how `@backstage/dev-utils` is used in the frontend.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/backend-dev-utils",
"version": "0.0.0",
"version": "0.1.0-next.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
+10
View File
@@ -1,5 +1,15 @@
# example-backend-next
## 0.0.8-next.2
### Patch Changes
- Updated dependencies
- @backstage/plugin-catalog-backend@1.7.2-next.2
- @backstage/plugin-scaffolder-backend@1.11.0-next.2
- @backstage/plugin-app-backend@0.3.42-next.2
- @backstage/backend-defaults@0.1.7-next.2
## 0.0.8-next.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "example-backend-next",
"version": "0.0.8-next.1",
"version": "0.0.8-next.2",
"main": "dist/index.cjs.js",
"types": "src/index.ts",
"license": "Apache-2.0",
+20
View File
@@ -1,5 +1,25 @@
# @backstage/backend-plugin-api
## 0.4.0-next.2
### Minor Changes
- e716946103: **BREAKING**: Split out the hook for both lifecycle services so that the first parameter of `addShutdownHook` is the hook function, and the second is the options.
- 0ff03319be: **BREAKING**: The plugin ID option passed to `createBackendPlugin` is now `pluginId`, rather than just `id`. This is to make it match `createBackendModule` more closely.
- 71a5ec0f06: **BREAKING**: Switched out `LogMeta` type for `JsonObject`.
- 610d65e143: Switched `BackendFeature` to be an opaque type.
### Patch Changes
- 9c9456fd33: Removed the unused `TypesToServiceRef` type
- 181c03edb5: Aligned opaque type markers to all use a `$type` property with namespacing.
- Updated dependencies
- @backstage/backend-tasks@0.4.3-next.2
- @backstage/plugin-auth-node@0.2.11-next.2
- @backstage/config@1.0.6
- @backstage/types@1.0.2
- @backstage/plugin-permission-common@0.7.3
## 0.3.2-next.1
### Patch Changes

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