Merge branch 'master' into improvemsgraphperf
Signed-off-by: Alex Crome <afscrome@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-common': patch
|
||||
---
|
||||
|
||||
New K8s catalog entity annotations added that will replace now deprecated k8s annotations in the catalog-model package. K8s annotation imports should now be made from plugin-kubernetes-common.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
The process of adding or modifying fields in the software-catalog search index has been simplified. For more details, see [how to customize fields in the Software Catalog index](https://backstage.io/docs/features/search/how-to-guides#how-to-customize-fields-in-the-software-catalog-index).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
---
|
||||
|
||||
Adding new Cluster detail fields to catalogClusterLocator. Replace deprecated imports with k8s annotations from plugin-kubernetes-common.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
Bumped create-app version.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Show module name causing error during build
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': minor
|
||||
---
|
||||
|
||||
- **Deprecation** - Deprecated the following exports, please import them directly from `@backstage/plugin-scaffolder-react` instead
|
||||
|
||||
```
|
||||
createScaffolderLayout
|
||||
ScaffolderLayouts
|
||||
LayoutOptions
|
||||
LayoutTemplate
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Upgrade `@rjsf` version 5 dependencies to `beta.18`
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-cookiecutter': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-sentry': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-yeoman': patch
|
||||
'@backstage/plugin-scaffolder-backend-module-rails': patch
|
||||
---
|
||||
|
||||
Internal refactor to use the new `@backstage/plugin-scaffolder-node` package for some functionality
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-node': minor
|
||||
---
|
||||
|
||||
New package that takes over some of the types and functionality from `@backstage/plugin-scaffolder-backend` that are shared with other modules
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-aws': patch
|
||||
---
|
||||
|
||||
Added support for `externalId` when assuming role in `AwsS3EntityProvider`
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': patch
|
||||
---
|
||||
|
||||
**Deprecations**: The following are deprecated and should instead be imported from the new package `@backstage/plugin-scaffolder-node`:
|
||||
|
||||
- `ActionContext`
|
||||
- `createTemplateAction`
|
||||
- `TaskSecrets`
|
||||
- `TemplateAction`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs': patch
|
||||
---
|
||||
|
||||
Improve view: remove footer overlay on large screen
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-msgraph': patch
|
||||
---
|
||||
|
||||
Extract default transformers to their own file
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
---
|
||||
|
||||
Condenses kubernetes ui plugin to fit more onscreen and increase visibility
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-incremental-ingestion': minor
|
||||
---
|
||||
|
||||
Return EventSubscriber from addIncrementalEntityProvider to hook up to EventsBackend
|
||||
+35
-2
@@ -194,7 +194,40 @@
|
||||
"@backstage/plugin-user-settings-backend": "0.1.4",
|
||||
"@backstage/plugin-vault": "0.1.8",
|
||||
"@backstage/plugin-vault-backend": "0.2.6",
|
||||
"@backstage/plugin-xcmetrics": "0.2.34"
|
||||
"@backstage/plugin-xcmetrics": "0.2.34",
|
||||
"@backstage/plugin-scaffolder-node": "0.0.0"
|
||||
},
|
||||
"changesets": []
|
||||
"changesets": [
|
||||
"bright-eagles-love",
|
||||
"brown-islands-own",
|
||||
"calm-avocados-exercise",
|
||||
"cold-cycles-switch",
|
||||
"create-app-1674561612",
|
||||
"cyan-deers-walk",
|
||||
"eight-falcons-explode",
|
||||
"flat-cups-itch",
|
||||
"friendly-scissors-shop",
|
||||
"gold-lemons-eat",
|
||||
"gold-masks-sleep",
|
||||
"itchy-goats-melt",
|
||||
"khaki-toes-care",
|
||||
"lazy-badgers-rule",
|
||||
"lazy-badgers-try",
|
||||
"lemon-tables-train",
|
||||
"lovely-ladybugs-taste",
|
||||
"nervous-apricots-whisper",
|
||||
"nervous-mangos-rhyme",
|
||||
"perfect-cheetahs-serve",
|
||||
"pink-falcons-serve",
|
||||
"quick-ladybugs-reply",
|
||||
"rare-melons-battle",
|
||||
"rotten-mayflies-love",
|
||||
"shiny-years-tap",
|
||||
"silly-turkeys-hang",
|
||||
"spotty-coats-clean",
|
||||
"stale-dots-smile",
|
||||
"swift-fishes-smash",
|
||||
"twenty-parents-relate",
|
||||
"young-singers-learn"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
'@backstage/plugin-kubernetes-backend': patch
|
||||
'@backstage/plugin-kubernetes-common': patch
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
---
|
||||
|
||||
Updated dependency `@kubernetes/client-node` to `0.18.1`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-user-settings': patch
|
||||
---
|
||||
|
||||
Added a message to advise a page reload when toggling feature flags
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-github-issues': patch
|
||||
---
|
||||
|
||||
Updated README.md examples to use correct components and fixed some syntax errors.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
'@backstage/plugin-scaffolder-react': patch
|
||||
---
|
||||
|
||||
Add `ScaffolderLayouts` to `NextScaffolderPage`
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Renamed the export `scaffolderCatalogModule` to `catalogModuleTemplateKind` in order to follow the new recommended naming patterns of backend system items. This is technically a breaking change but in an alpha export, so take care to change your imports if you have already migrated to the new backend system.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/catalog-model': patch
|
||||
---
|
||||
|
||||
Add deprecation tag to kubernetes constants in catalog, constants are now defined in plugin-kubernetes-common
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-app-api': patch
|
||||
---
|
||||
|
||||
`HttpRouterFactoryOptions.getPath` is now optional as a default value is always provided in the factory.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-splunk-on-call': patch
|
||||
---
|
||||
|
||||
Refactor plugin Card component to not rerender contents unnecessarily.
|
||||
@@ -70,6 +70,7 @@ cron
|
||||
cronjobs
|
||||
crontab
|
||||
css
|
||||
daemonsets
|
||||
Datadog
|
||||
dataflow
|
||||
dayjs
|
||||
@@ -177,6 +178,7 @@ learnings
|
||||
Leasot
|
||||
lerna
|
||||
Lerna
|
||||
limitranges
|
||||
LocalStack
|
||||
lockdown
|
||||
lockfile
|
||||
|
||||
@@ -3,12 +3,15 @@ id: backends
|
||||
title: Backend Instances
|
||||
sidebar_label: Backend
|
||||
# prettier-ignore
|
||||
description: Service APIs for backend plugins
|
||||
description: Backend instances
|
||||
---
|
||||
|
||||
The new Backstage backend system is being built to help make it simpler to install backend plugins and to keep projects up to date. It also changes the foundation to one that makes it a lot easier to evolve plugins and the system itself with minimal disruption or cause for breaking changes. You can read more about the reasoning in the [original RFC](https://github.com/backstage/backstage/issues/11611).
|
||||
## The Backend Instance
|
||||
|
||||
One of the goals of the new system was to reduce the code needed for setting up a Backstage backend and installing plugins. This is an example of how you create, add features, and start up your backend in the new system:
|
||||
This is the main entry point for creating a backend. It does not have any functionality in and of itself, but is simply responsible for wiring things together.
|
||||
It is up to you to decide how many different backends you want to deploy. You can have all features in a single one, or split things out into multiple smaller deployments.
|
||||
|
||||
Below is a simple example of a backend that installs only the catalog plugin and starts it up.
|
||||
|
||||
```ts
|
||||
import { createBackend } from '@backstage/backend-defaults';
|
||||
@@ -24,4 +27,12 @@ backend.add(catalogPlugin());
|
||||
await backend.start();
|
||||
```
|
||||
|
||||
One notable change that helped achieve this much slimmer backend setup is the introduction of a system for dependency injection, which is very similar to the one in the Backstage frontend.
|
||||
`createBackend` is responsible for creating your backend instance, and wiring up all the services that you have provided. It deals with creating default implementations of all the [core services](../core-services/01-index.md) that are used by the plugins, and also provides a way to override the default implementations with your own. You can read more about creating services and overriding them in the [building backends docs](../building-backends/01-index.md).
|
||||
|
||||
The backend instance has the ability to add features to the backend which are done using the `.add` method. Features are either plugins or modules, and you can read more about them in the [building plugins and modules docs](../building-plugins-and-modules/01-index.md). By default, a backend instance has no default features, and the services are responsible for wiring everything together.
|
||||
|
||||
At a high level, when you call `createBackend`, it will create a new backend instance, which has a registry of all the services that are currently registered, and by adding features to the backend instance and calling the `.start()` method it will ensure that all the dependencies are wired up correctly and the `registerInit` methods are called in the correct order.
|
||||
|
||||
Underneath the hood, `createBackend` calls `createSpecializedBackend` from `@backstage/backend-app-api` which is responsible for actually creating the backend instance, but with no services or no features. You can think of `createBackend` more of a 'batteries included' approach, and `createSpecializedBackend` a little more low level.
|
||||
|
||||
As mentioned previously there's also the ability to create multiple of these backends in your project so that you can split apart your backend and deploy different backends that can scale independently of each other. For instance you might choose to deploy a backend with only the catalog plugin enabled, and one with just the scaffolder plugin enabled. We've provided some tools to be able to share services and defaults across your backend system, and you can find out more about that in the [shared environments docs](../building-backends/01-index.md#shared-environments).
|
||||
|
||||
@@ -6,29 +6,26 @@ sidebar_label: Plugins
|
||||
description: Backend plugins
|
||||
---
|
||||
|
||||
## Creating Plugins
|
||||
Plugins provide the actual base features of a Backstage backend. Each plugin operates completely independently of all other plugins and they only communicate with each other through network calls. This means that there is a strong degree of isolation between plugins, and that each plugin can be considered a separate microservice. While a default Backstage project has all plugins installed within a single backend, it is also possible to split this setup into multiple backends, with each backend housing one or more plugins.
|
||||
|
||||
Plugins are created using the `createBackendPlugin` function. All plugins must have an ID and a register method. Plugins may also accept an options object, which can be either optional or required. The options are passed to the second parameter of the register method, and the options type is inferred and forwarded to the returned plugin factory function.
|
||||
## Defining a Plugin
|
||||
|
||||
Plugins are created using the `createBackendPlugin` function, and should typically be exported from a plugin package. All plugins must have an ID and a `register` method, where the ID matches the plugin ID in the package name, without the `-backend` suffix. See also the [dedicated section](./07-naming-patterns.md) about proper naming patterns.
|
||||
|
||||
```ts
|
||||
// plugins/example-backend/src/plugin.ts
|
||||
import {
|
||||
configServiceRef,
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
// export type ExamplePluginOptions = { exampleOption: boolean };
|
||||
export const examplePlugin = createBackendPlugin({
|
||||
// unique id for the plugin
|
||||
id: 'example',
|
||||
// It's possible to provide options to the plugin
|
||||
// register(env, options: ExamplePluginOptions) {
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
// logger is provided by the backend based on the dependency on loggerServiceRef above.
|
||||
async init({ logger }) {
|
||||
logger.info('Hello from example plugin');
|
||||
},
|
||||
@@ -37,32 +34,60 @@ export const examplePlugin = createBackendPlugin({
|
||||
});
|
||||
```
|
||||
|
||||
The plugin can then be installed in the backend using the returned plugin factory function:
|
||||
The `env` object passed to the `register` callback contains different methods that declare the external surface of the plugin. The `env.registerInit` method is used to register an initialization function that is run when the backend starts up. The `deps` argument is used to declare service dependencies, and the `init` callback is passed an object with the resolved dependencies. In this case, we declare a dependency on the logger service, which is one of the core services available to all Backstage backend plugins. For a full list of core services as well as documentation for each services, see the [core services section](../core-services/01-index.md). Plugins can of course also depend on services exported by other libraries.
|
||||
|
||||
The `createBackendPlugin` return value is exported as `examplePlugin`, which is a factory function used to create the actual plugin instance. For example, to install the plugin in your backend instance, you would do the following:
|
||||
|
||||
```ts
|
||||
backend.add(examplePlugin());
|
||||
```
|
||||
|
||||
If we wanted our plugin to accept options as well, we'd accept the options as the second parameter of the register method:
|
||||
The reason for why our plugin instance has been wrapped up in a factory function is so that you can always chose to add options to your plugin in the future, without breaking existing usage. To add options you wrap the object passed to `createBackendPlugin` in a callback that accepts the desired options. For example:
|
||||
|
||||
```ts
|
||||
export const examplePlugin = createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env, options?: { silent?: boolean }) {
|
||||
env.registerInit({
|
||||
deps: { logger: coreServices.logger },
|
||||
async init({ logger }) {
|
||||
if (!options?.silent) {
|
||||
logger.info('Hello from example plugin');
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
export interface ExamplePluginOptions {
|
||||
skipHello: boolean;
|
||||
}
|
||||
|
||||
export const examplePlugin = createBackendPlugin(
|
||||
(options?: ExamplePluginOptions) => ({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
async init({ logger }) {
|
||||
if (!options?.skipHello) {
|
||||
logger.info('Hello from example plugin');
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
Passing the option to the plugin during installation looks like this:
|
||||
Now your plugin accepts an optional options object, which can be used to configure each plugin instance. To supply options to the plugin, you pass them to the plugin factory method:
|
||||
|
||||
```ts
|
||||
backend.add(examplePlugin({ silent: true }));
|
||||
backend.add(examplePlugin({ skipHello: true }));
|
||||
```
|
||||
|
||||
It is also possible to make the options required, simply remove the `?` from the parameter declaration. This will be reflected in the returned factory function, which will now require the options parameter.
|
||||
|
||||
Options are a simple way to allow for more lightweight customization of a plugin, but they do not allow for more complex extensions that require access to services. For that, you need to create and register extension points for your plugin, which are covered in the [next section](./05-extension-points.md).
|
||||
|
||||
## Rules of Plugins
|
||||
|
||||
The following rules apply to the production setup of Backstage plugins in the broader Backstage plugin ecosystem. Any plugin that is maintained under the `@backstage` package namespace should follow these rules, and it is recommended that all widely distributed plugins follow these rules as well.
|
||||
|
||||
An exception to these rules are made for development or test setups, where shortcuts can be take in order to streamline development and keep things simple.
|
||||
|
||||
### Scalable
|
||||
|
||||
Plugins must always be designed to be horizontally scalable. This means that you should not keep any state in memory, or make sure that replicating this state across multiple instances is not an issue. Plugins should either be stateless, or store their state in an external service, such as a database.
|
||||
|
||||
### Isolated
|
||||
|
||||
Plugins must never communicate with each other directly through code, they may only communicate over the network. Plugins that wish to expose an external interface for other plugins and modules to use are recommended to do so though a [node-library](../../local-dev/cli-build-system.md#package-roles) package. The library should export an API client service to make calls to your plugin, or similar construct.
|
||||
|
||||
@@ -21,14 +21,16 @@ When you create a new project with `@backstage/create-app`, you'll get a backend
|
||||
import { createBackend } from '@backstage/backend-defaults';
|
||||
import { appPlugin } from '@backstage/plugin-app-backend';
|
||||
import { catalogPlugin } from '@backstage/plugin-catalog-backend';
|
||||
import { scaffolderCatalogModule } from '@backstage/plugin-scaffolder-backend';
|
||||
import { scaffolderPlugin } from '@backstage/plugin-scaffolder-backend';
|
||||
import {
|
||||
scaffolderPlugin,
|
||||
catalogModuleTemplateKind,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(appPlugin());
|
||||
backend.add(catalogPlugin());
|
||||
backend.add(scaffolderCatalogModule());
|
||||
backend.add(catalogModuleTemplateKind());
|
||||
backend.add(scaffolderPlugin());
|
||||
|
||||
backend.start();
|
||||
@@ -129,7 +131,7 @@ const backend = createBackend();
|
||||
|
||||
backend.add(appPlugin());
|
||||
backend.add(catalogPlugin());
|
||||
backend.add(scaffolderCatalogModule());
|
||||
backend.add(catalogModuleTemplateKind());
|
||||
backend.start();
|
||||
```
|
||||
|
||||
|
||||
@@ -240,11 +240,11 @@ A basic installation of the catalog plugin looks as follows.
|
||||
```diff
|
||||
// packages/backend/src/index.ts
|
||||
+import { catalogPlugin } from '@backstage/plugin-catalog-backend';
|
||||
+import { scaffolderCatalogModule } from '@backstage/plugin-scaffolder-backend';
|
||||
+import { catalogModuleTemplateKind } from '@backstage/plugin-scaffolder-backend';
|
||||
|
||||
const backend = createBackend();
|
||||
+backend.add(catalogPlugin());
|
||||
+backend.add(scaffolderCatalogModule());
|
||||
+backend.add(catalogModuleTemplateKind());
|
||||
```
|
||||
|
||||
Note that this also installs a module from the scaffolder, namely the one which
|
||||
@@ -265,9 +265,9 @@ depends on the appropriate extension point and interacts with it.
|
||||
+import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
|
||||
+import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
|
||||
+const catalogExtensionsModule = createBackendModule({
|
||||
+ pluginId: 'catalog', // name of the plugin that the module is targeting
|
||||
+ moduleId: 'extensions', // you can choose this one freely
|
||||
+const catalogModuleCustomExtensions = createBackendModule({
|
||||
+ pluginId: 'catalog', // name of the plugin that the module is targeting
|
||||
+ moduleId: 'customExtensions',
|
||||
+ register(env) {
|
||||
+ env.registerInit({
|
||||
+ deps: {
|
||||
@@ -286,8 +286,8 @@ depends on the appropriate extension point and interacts with it.
|
||||
|
||||
const backend = createBackend();
|
||||
backend.add(catalogPlugin());
|
||||
backend.add(scaffolderCatalogModule());
|
||||
+backend.add(catalogExtensionsModule());
|
||||
backend.add(catalogModuleTemplateKind());
|
||||
+backend.add(catalogModuleCustomExtensions());
|
||||
```
|
||||
|
||||
This also requires that you have a dependency on the corresponding node package,
|
||||
@@ -330,9 +330,9 @@ depends on the appropriate extension point and interacts with it.
|
||||
+import { eventsExtensionPoint } from '@backstage/plugin-events-node';
|
||||
+import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
|
||||
+const eventsExtensionsModule = createBackendModule({
|
||||
+ pluginId: 'events', // name of the plugin that the module is targeting
|
||||
+ moduleId: 'extensions', // you can choose this one freely
|
||||
+const eventsModuleCustomExtensions = createBackendModule({
|
||||
+ pluginId: 'events', // name of the plugin that the module is targeting
|
||||
+ moduleId: 'customExtensions',
|
||||
+ register(env) {
|
||||
+ env.registerInit({
|
||||
+ deps: {
|
||||
@@ -350,7 +350,7 @@ depends on the appropriate extension point and interacts with it.
|
||||
|
||||
const backend = createBackend();
|
||||
backend.add(eventsPlugin());
|
||||
+backend.add(eventsExtensionsModule());
|
||||
+backend.add(eventsModuleCustomExtensions());
|
||||
```
|
||||
|
||||
This also requires that you have a dependency on the corresponding node package,
|
||||
@@ -390,13 +390,12 @@ depends on the appropriate extension point and interacts with it.
|
||||
|
||||
```diff
|
||||
// packages/backend/src/index.ts
|
||||
// TODO: This might be moved to @backstage/plugin-scaffolder-node
|
||||
+import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-backend/alpha';
|
||||
+import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node';
|
||||
+import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
|
||||
+const scaffolderExtensionsModule = createBackendModule({
|
||||
+ pluginId: 'scaffolder', // name of the plugin that the module is targeting
|
||||
+ moduleId: 'extensions', // you can choose this one freely
|
||||
+const scaffolderModuleCustomExtensions = createBackendModule({
|
||||
+ pluginId: 'scaffolder', // name of the plugin that the module is targeting
|
||||
+ moduleId: 'customExtensions',
|
||||
+ register(env) {
|
||||
+ env.registerInit({
|
||||
+ deps: {
|
||||
@@ -414,7 +413,7 @@ depends on the appropriate extension point and interacts with it.
|
||||
|
||||
const backend = createBackend();
|
||||
backend.add(scaffolderPlugin());
|
||||
+backend.add(scaffolderExtensionsModule());
|
||||
+backend.add(scaffolderModuleCustomExtensions());
|
||||
```
|
||||
|
||||
This also requires that you have a dependency on the corresponding node package,
|
||||
|
||||
@@ -9,4 +9,237 @@ description: Building backend plugins and modules using the new backend system
|
||||
> NOTE: If you have an existing backend and/or backend plugins that are not yet
|
||||
> using the new backend system, see [migrating](./08-migrating.md).
|
||||
|
||||
# Overview
|
||||
## Overview
|
||||
|
||||
Backend [plugins](../architecture/04-plugins.md) and
|
||||
[modules](../architecture/06-modules.md), sometimes collectively referred to as
|
||||
backend _features_, are the building blocks that adopters add to their
|
||||
[backends](../architecture/02-backends.md).
|
||||
|
||||
## Plugins
|
||||
|
||||
A basic backend plugin might look as follows:
|
||||
|
||||
```ts
|
||||
import {
|
||||
createBackendPlugin,
|
||||
coreServices,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { createExampleRouter } from './router';
|
||||
|
||||
export const examplePlugin = createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
// Declare dependencies to services that you want to consume
|
||||
logger: coreServices.logger,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
},
|
||||
async init({
|
||||
// Requested service instances get injected as per above
|
||||
logger,
|
||||
httpRouter,
|
||||
}) {
|
||||
// Perform your initialization and access the services as needed
|
||||
const example = createExampleRouter(logger);
|
||||
logger.info('Hello from example plugin');
|
||||
httpRouter.use(example);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
When you depend on `plugin` scoped services, you'll receive an instance of them
|
||||
that's specific to your plugin. In the example above, the logger might tag
|
||||
messages with your plugin ID, and the HTTP router might prefix API routes with
|
||||
your plugin ID, depending on the implementation used.
|
||||
|
||||
See [the article on naming patterns](../architecture/07-naming-patterns.md) for
|
||||
details on how to best choose names/IDs for plugins and related backend system
|
||||
items.
|
||||
|
||||
## Modules
|
||||
|
||||
Backend modules are used to extend [plugins](../architecture/04-plugins.md) with
|
||||
additional features or change existing behavior. They must always be installed
|
||||
in the same backend instance as the plugin that they extend, and may only extend
|
||||
a single plugin. Modules interact with their target plugin using the [extension
|
||||
points](./05-extension-points.md) registered by the plugin, while also being
|
||||
able to depend on the [services](../architecture/03-services.md) of that plugin.
|
||||
That last point is worth reiterating: injected `plugin` scoped services will be
|
||||
the exact
|
||||
same ones as the target plugin will receive later, i.e. they will be scoped
|
||||
using the target `pluginId` of the module.
|
||||
|
||||
A module depends on the extension points exported by the target plugin's library
|
||||
package, for example `@backstage/plugin-catalog-node`, and does not directly
|
||||
declare a dependency on the plugin package itself. This is to avoid a direct
|
||||
dependency and potentially cause duplicate installations of the plugin package,
|
||||
while duplicate installations of library packages should always be supported.
|
||||
|
||||
The following is an example of how to create a module that adds a new processor
|
||||
using the `catalogProcessingExtensionPoint`:
|
||||
|
||||
```ts
|
||||
import { createBackendModule } from '@backstage/backend-plugin-api';
|
||||
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';
|
||||
import { MyCustomProcessor } from './MyCustomProcessor';
|
||||
|
||||
export const catalogModuleExampleCustomProcessor = createBackendModule({
|
||||
moduleId: 'exampleCustomProcessor',
|
||||
pluginId: 'catalog',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
catalog: catalogProcessingExtensionPoint,
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
async init({ catalog }) {
|
||||
catalog.addProcessor(new MyCustomProcessor(logger));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
See [the article on naming patterns](../architecture/07-naming-patterns.md) for
|
||||
details on how to best choose names/IDs for modules and related backend system
|
||||
items.
|
||||
|
||||
Notice that we're placing the extension point we want to interact with in the
|
||||
`deps` option, while also depending on the logger service at the same time. When
|
||||
initializing modules we can depend on both extension points and services
|
||||
interchangeably. You can also depend on multiple extension points at once, in
|
||||
case the implementation of the module requires it.
|
||||
|
||||
It is typically best to keep modules slim and to each only add a single new
|
||||
feature. It is often the case that it is better to create two separate modules
|
||||
rather than one that provides both features. The one limitation here is that
|
||||
modules can not interact with each other and need to be self contained.
|
||||
|
||||
### HTTP Handlers
|
||||
|
||||
Since modules have access to the same services as the plugin they extend, they
|
||||
are also able to register their own HTTP handlers. For more information about
|
||||
the HTTP service, see [core services](../core-services/01-index.md). When
|
||||
registering HTTP handlers, it is important to try to avoid any future conflict
|
||||
with the plugin itself, or other modules. A recommended naming pattern is to
|
||||
register the handlers under the `/modules/<module-id>` path, where `<module-id>`
|
||||
is the kebab-case ID of the module, for example
|
||||
`/modules/example-custom-processor/v1/validators`. In a standard backend setup
|
||||
the full path would then be
|
||||
`<backendUrl>/api/catalog/modules/example-custom-processor/v1/validators`.
|
||||
|
||||
### Database Access
|
||||
|
||||
The same applies for modules that perform their own migrations and interact with
|
||||
the database. They will run on the same logical database instance as the target
|
||||
plugin, so care must be taken to choose table names that do not risk colliding
|
||||
with those of the plugin. A recommended naming pattern is `<package
|
||||
name>__<table name>`, for example the `@backstage/backend-tasks` package creates
|
||||
tables named `backstage_backend_tasks__<table>`. If you use the default [`Knex`
|
||||
migration facilities](https://knexjs.org/guide/migrations.html), you will also
|
||||
want to make sure that it uses similarly prefixed migration state tables for its
|
||||
internal bookkeeping needs, so they do not collide with the main ones used by
|
||||
the plugin itself. You can do this as follows:
|
||||
|
||||
```ts
|
||||
await knex.migrate.latest({
|
||||
directory: migrationsDir,
|
||||
tableName: 'backstage_backend_tasks__knex_migrations',
|
||||
});
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
There are several ways of configuring and customizing plugins and modules.
|
||||
|
||||
### Extension Points
|
||||
|
||||
Whenever you want to allow modules to configure your plugin dynamically, for
|
||||
example in the way that the catalog backend lets catalog modules inject
|
||||
additional entity providers, you can use the extension points mechanism. This is
|
||||
described in detail with code examples in [the extension points architecture
|
||||
article](../architecture/05-extension-points.md).
|
||||
|
||||
### Configuration
|
||||
|
||||
Your plugin or module can leverage the app configuration to configure its own
|
||||
internal behavior. You do this by adding a dependency on `coreServices.config`
|
||||
and reading from that. This pattern is a good fit especially for customization
|
||||
that needs to be different across environments.
|
||||
|
||||
```ts
|
||||
import { coreServices } from '@backstage/backend-plugin-api';
|
||||
|
||||
export const examplePlugin = createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: { config: coreServices.config },
|
||||
async init({ config }) {
|
||||
// Here you can read from the current config as you see fit, e.g.:
|
||||
const value = config.getOptionalString('example.value');
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Before adding custom configuration options, make sure to read [the configuration
|
||||
docs](../../conf/index.md), in particular the section on [defining configuration
|
||||
for your own plugins](../../conf/defining.md) which explains how to establish a
|
||||
configuration schema for your specific plugin.
|
||||
|
||||
### Options
|
||||
|
||||
You'll have noted that the return values from `createBackendPlugin` and
|
||||
`createBackendModule` are actually factory functions. These can be made to
|
||||
accept options that shall be passed in at initialization time.
|
||||
|
||||
This pattern can be a good fit for fairly simple, static configuration values.
|
||||
|
||||
```ts
|
||||
export interface ExampleOptions {
|
||||
silent?: boolean;
|
||||
}
|
||||
|
||||
export const examplePlugin = createBackendPlugin(
|
||||
(options?: ExampleOptions) => ({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
// Omitted dependencies but they remain the same as above
|
||||
},
|
||||
async init(
|
||||
{
|
||||
/* ... */
|
||||
},
|
||||
) {
|
||||
// Here you can access the given options and act accordingly, e.g.:
|
||||
if (!options?.silent) {
|
||||
// ...
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
The return type from `createBackendPlugin` and `createBackendModule` will mimic
|
||||
this, resulting in a factory function that accepts an optional options object.
|
||||
You can also make it required to pass in options, by removing the optionality
|
||||
(the question mark on the options) above.
|
||||
|
||||
```ts
|
||||
backend.add(examplePlugin({ silent: true }));
|
||||
```
|
||||
|
||||
Use this pattern sparingly. There is a big convenience benefit in allowing
|
||||
people to easily install backend plugins without having to always pass in a
|
||||
large number of options, and these options cannot easily be made dynamic based
|
||||
on the environment etc.
|
||||
|
||||
@@ -6,21 +6,161 @@ sidebar_label: Testing
|
||||
description: Learn how to test your backend plugins and modules
|
||||
---
|
||||
|
||||
Utilities for testing backend plugins and modules are available in `@backstage/backend-test-utils`.
|
||||
`startTestBackend` returns a server which can be used together with `supertest` to test the plugins.
|
||||
Utilities for testing backend plugins and modules are available in
|
||||
`@backstage/backend-test-utils`. This section describes those facilities.
|
||||
|
||||
## Testing Backend Plugins and Modules
|
||||
|
||||
To facilitate testing of backend plugins and modules, the
|
||||
`@backstage/backend-test-utils` package provides a `startTestBackend` function
|
||||
which starts up an entire backend harness, complete with a number of mock
|
||||
services. You can then provide overrides for services whose behavior you need to
|
||||
adjust for the test run. The function also accepts a number of _features_ (a
|
||||
collective term for backend [plugins](../architecture/04-plugins.md) and
|
||||
[modules](../architecture/06-modules.md)), that are the subjects of the test.
|
||||
|
||||
The function returns an HTTP server instance which can be used together with
|
||||
e.g. `supertest` to easily test the actual REST service surfaces of plugins who
|
||||
register routes with [the HTTP router service
|
||||
API](../core-services/01-index.md).
|
||||
|
||||
```ts
|
||||
import { startTestBackend } from '@backstage/backend-test-utils';
|
||||
import { mockServices, startTestBackend } from '@backstage/backend-test-utils';
|
||||
import request from 'supertest';
|
||||
import { myPlugin } from './plugin.ts';
|
||||
|
||||
describe('myPlugin', () => {
|
||||
it('can serve values from config', async () => {
|
||||
const fakeConfig = { myPlugin: { value: 7 } };
|
||||
|
||||
describe('My plugin tests', () => {
|
||||
it('should return 200', async () => {
|
||||
const { server } = await startTestBackend({
|
||||
features: [myPlugin()],
|
||||
services: [mockServices.config.factory({ data: fakeConfig })],
|
||||
});
|
||||
|
||||
const response = await request(server).get('/api/example/hello');
|
||||
const response = await request(server).get('/api/example/get-value');
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.body).toEqual({ value: 7 });
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
This example shows how to access the mock service factories and
|
||||
pass options to them, which will override the default mock services.
|
||||
|
||||
The returned server also has a `port()` method which returns the dynamically
|
||||
bound listening port. You can use this to perform lower level network
|
||||
interactions with the running test service.
|
||||
|
||||
## Testing Remote Service Interactions
|
||||
|
||||
If your backend plugin or service interacts with external services using HTTP
|
||||
calls, we recommend leveraging the `msw` package to intercept actual outgoing
|
||||
requests and return mock responses. This lets you stub out remote services
|
||||
rather than the local clients, leading to more thorough and robust tests. You
|
||||
can read more about how it works [in their documentation](https://mswjs.io/).
|
||||
|
||||
The `@backstage/backend-test-utils` package exports a `setupRequestMockHandlers`
|
||||
function which ensures that the correct `jest` lifecycle hooks are invoked to
|
||||
set up and tear down your `msw` instance, and enables the option that completely
|
||||
rejects requests that don't match one of your mock rules. This ensures that your
|
||||
tests cannot accidentally leak traffic into production from tests.
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import { setupRequestMockHandlers } from '@backstage/backend-test-utils';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
|
||||
describe('read from remote', () => {
|
||||
const worker = setupServer();
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
it('should auth and read successfully', async () => {
|
||||
expect.assertions(1);
|
||||
|
||||
worker.use(
|
||||
rest.get('https://remote-server.com/api/v3/foo', (req, res, ctx) => {
|
||||
expect(req.headers.get('authorization')).toBe('Bearer fake');
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.body(JSON.stringify({ value: 7 })),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
// exercise your plugin or service as usual, with real clients
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Testing Database Interactions
|
||||
|
||||
The `@backstage/backend-test-utils` package includes facilities for testing your
|
||||
plugins' interactions with databases, including spinning up `testcontainers`
|
||||
powered Docker images with real database engines to connect to.
|
||||
|
||||
The base setup for such a test could look as follows:
|
||||
|
||||
```ts
|
||||
// MyDatabaseClass.test.ts
|
||||
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
|
||||
import { MyDatabaseClass, type FooTableRow } from './MyDatabaseClass';
|
||||
|
||||
describe('MyDatabaseClass', () => {
|
||||
// Change this to the set of constants that you actually actively intend to
|
||||
// support. This create call must be made inside a describe block. Make sure
|
||||
// to create only one TestDatabases instance per file, since spinning up
|
||||
// "physical" databases to test against is much costlier than creating the
|
||||
// "logical" databases within them that the individual tests use.
|
||||
const databases = TestDatabases.create({
|
||||
ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3'],
|
||||
});
|
||||
|
||||
// Just an example of how to conveniently bundle up the setup code
|
||||
async function createSubject(databaseId: TestDatabaseId) {
|
||||
const knex = await databases.init(databaseId);
|
||||
const subject = new MyDatabaseClass({ database: knex });
|
||||
await subject.runMigrations();
|
||||
return { knex, subject };
|
||||
}
|
||||
|
||||
describe('foo', () => {
|
||||
// Easily run the exact same test onto all supported databases
|
||||
it.each(databases.eachSupportedId())(
|
||||
'should run foo on %p',
|
||||
async databaseId => {
|
||||
const { knex, subject } = await createSubject(databaseId);
|
||||
// raw knex is available for underlying manipulation
|
||||
await knex<FooTableRow>('foo').insert({ value: 2 });
|
||||
// drive your system under test as usual
|
||||
await expect(subject.foos()).resolves.toEqual([{ value: 2 }]);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
If you want to pass the test database instance into backend plugins or services,
|
||||
you can supply it in the form of a mock instance of `coreServices.database` to
|
||||
your test database.
|
||||
|
||||
```ts
|
||||
const { knex, subject } = await createSubject(databaseId);
|
||||
const { server } = await startTestBackend({
|
||||
features: [myPlugin()],
|
||||
services: [[coreServices.database, { getClient: async () => knex }]],
|
||||
});
|
||||
```
|
||||
|
||||
When running locally, the tests only run against SQLite for the sake of speed.
|
||||
When the `CI` environment variable is set, all given database engines are used.
|
||||
|
||||
If you do not want or are unable to use docker based database engines, e.g. if
|
||||
your CI environment is able to supply databases natively, the `TestDatabases`
|
||||
support custom connection strings through the use of environment variables that
|
||||
it'll take into account when present.
|
||||
|
||||
- `BACKSTAGE_TEST_DATABASE_POSTGRES13_CONNECTION_STRING`
|
||||
- `BACKSTAGE_TEST_DATABASE_POSTGRES9_CONNECTION_STRING`
|
||||
- `BACKSTAGE_TEST_DATABASE_MYSQL8_CONNECTION_STRING`
|
||||
|
||||
@@ -18,6 +18,8 @@ import { coreServices } from '@backstage/backend-plugin-api';
|
||||
|
||||
One of the most common services is the HTTP router service which is used to expose HTTP endpoints for other plugins to consume.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to register a HTTP router for the `example` plugin.
|
||||
This single route will be available at the `/api/example/hello` path.
|
||||
|
||||
@@ -46,9 +48,33 @@ createBackendPlugin({
|
||||
});
|
||||
```
|
||||
|
||||
## Logging and Configuration Service
|
||||
### Configuring the service
|
||||
|
||||
It is common for plugins to need access to configuration values and log messages.
|
||||
There's additional configuration that you can optionally pass to setup the `httpRouter` core service.
|
||||
|
||||
- `getPath` - Can be used to generate a path for each plugin. Currently defaults to `/api/${pluginId}`
|
||||
|
||||
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';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
httpRouterFactory({
|
||||
getPath: (pluginId: string) => `/plugins/${pluginId}`,
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Root HTTP Router
|
||||
|
||||
The root HTTP router is a service that allows you to register routes on the root of the backend service. This is useful for things like health checks, or other routes that you want to expose on the root of the backend service. It is used as the base router that backs the `httpRouter` service. Most likely you won't need to use this service directly, but rather use the `httpRouter` service.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get the root HTTP router service in your `example` backend plugin to register a health check route.
|
||||
|
||||
```ts
|
||||
import {
|
||||
@@ -62,13 +88,585 @@ createBackendPlugin({
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
log: coreServices.logger,
|
||||
config: coreServices.config,
|
||||
rootHttpRouter: coreServices.rootHttpRouter,
|
||||
},
|
||||
async init({ config, log }) {
|
||||
log.warn('Brace yourself for more log output');
|
||||
const url = config.getString('backend.baseUrl');
|
||||
log.info(`Backend URL is running on ${url}`);
|
||||
async init({ rootHttpRouter }) {
|
||||
const router = Router();
|
||||
router.get('/health', (request, response) => {
|
||||
response.send('OK');
|
||||
});
|
||||
|
||||
rootHttpRouter.use(router);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Configuring the service
|
||||
|
||||
There's additional options that you can pass to configure the root HTTP Router service. These options are passed when you call `createBackend`.
|
||||
|
||||
- `indexPath` - optional path to forward all unmatched requests to. Defaults to `/api/app` which is the `app-backend` plugin responsible for serving the frontend application through the backend.
|
||||
|
||||
- `configure` - this is an optional function that you can use to configure the `express` instance. This is useful if you want to add your own middleware to the root router, such as logging, or other things that you want to do before the request is handled by the backend. It's also useful to override the order in which middleware is applied.
|
||||
|
||||
You can configure the root HTTP Router service by passing the options to the `createBackend` function.
|
||||
|
||||
```ts
|
||||
import { rootHttpRouterFactory } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
rootHttpRouterFactory({
|
||||
configure: ({ app, middleware, routes, config, logger, lifecycle }) => {
|
||||
// the built in middleware is provided through an option in the configure function
|
||||
app.use(middleware.helmet());
|
||||
app.use(middleware.cors());
|
||||
app.use(middleware.compression());
|
||||
|
||||
// you can add you your own middleware in here
|
||||
app.use(custom.logging());
|
||||
|
||||
// here the routes that are registered by other plugins
|
||||
app.use(routes);
|
||||
|
||||
// some other middleware that comes after the other routes
|
||||
app.use(middleware.notFound());
|
||||
app.use(middleware.error());
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
This service allows you to read configuration values out of your `app-config` YAML files.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how you can use the default config service to be able to get a config value, and then log it to the console.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
log: coreServices.logger,
|
||||
config: coreServices.config,
|
||||
},
|
||||
async init({ log, config }) {
|
||||
const baseUrl = config.getString('backend.baseUrl');
|
||||
log.warn(`The backend is running at ${baseUrl}`);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Configuring the service
|
||||
|
||||
There's additional configuration that you can optionally pass to setup the `config` core service.
|
||||
|
||||
- `argv` - Override the arguments that are passed to the config loader, instead of using `process.argv`
|
||||
- `remote` - Configure remote configuration loading
|
||||
|
||||
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';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
configFactory({
|
||||
argv: [
|
||||
'--config',
|
||||
'/backstage/app-config.development.yaml',
|
||||
'--config',
|
||||
'/backstage/app-config.yaml',
|
||||
],
|
||||
remote: { reloadIntervalSeconds: 60 },
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
This service allows plugins to output logging information. There are actually two logger services: a root logger, and a plugin logger which is bound to individual plugins, so that you will get nice messages with the plugin ID referenced in the log lines.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get the logger in your `example` backend plugin and create a warning message that will be printed nicely to the console.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
log: coreServices.logger,
|
||||
},
|
||||
async init({ log }) {
|
||||
log.warn("Here's a nice log line that's a warning!");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Root Logger
|
||||
|
||||
The root logger is the logger that is used by other root services. It's where the implementation lies for creating child loggers around the backstage ecosystem including child loggers for plugins with the correct metadata and annotations.
|
||||
|
||||
If you want to override the implementation for logging across all of the backend, this is the service that you should override.
|
||||
|
||||
### Configuring the service
|
||||
|
||||
The following example is how you can override the root logger service to add additional metadata to all log lines.
|
||||
|
||||
```ts
|
||||
import { coreServices } from '@backstage/backend-plugin-api';
|
||||
import { WinstonLogger } from '@backstage/backend-app-api';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
createServiceFactory({
|
||||
service: coreServices.rootLogger,
|
||||
deps: {
|
||||
config: coreServices.config,
|
||||
},
|
||||
async factory({ config }) {
|
||||
const logger = WinstonLogger.create({
|
||||
meta: {
|
||||
service: 'backstage',
|
||||
// here's some additional information that is not part of the
|
||||
// original implementation
|
||||
podName: 'myk8spod',
|
||||
},
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
format:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? format.json()
|
||||
: WinstonLogger.colorFormat(),
|
||||
transports: [new transports.Console()],
|
||||
});
|
||||
|
||||
return logger;
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Cache
|
||||
|
||||
This service lets your plugin interact with a cache. It is bound to your plugin too, so that you will only set and get values in your plugin's private namespace.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get a cache client in your `example` backend plugin and setting and getting values from the cache.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
cache: coreServices.cache,
|
||||
},
|
||||
async init({ cache }) {
|
||||
const { key, value } = { key: 'test:key', value: 'bob' };
|
||||
await cache.set(key, value, { ttl: 1000 });
|
||||
|
||||
// .. some other stuff.
|
||||
|
||||
await cache.get(key); // 'bob'
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Database
|
||||
|
||||
This service lets your plugins get a `knex` client hooked up to a database which is configured in your `app-config` YAML files, for your persistence needs.
|
||||
|
||||
If there's no config provided in `backend.database` then you will automatically get a simple in-memory SQLite 3 database for your plugin whose contents will be lost when the service restarts.
|
||||
|
||||
This service is scoped per plugin too, so that table names do not conflict across plugins.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get access to the database service in your `example` backend plugin and getting a client for interacting with the database. It also runs some migrations from a certain directory for your plugin.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { resolvePackagePath } from '@backstage/backend-common';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
database: coreServices.database,
|
||||
},
|
||||
async init({ database }) {
|
||||
const client = await database.getClient();
|
||||
const migrationsDir = resolvePackagePath(
|
||||
'@internal/my-plugin',
|
||||
'migrations',
|
||||
);
|
||||
if (!database.migrations?.skip) {
|
||||
await client.migrate.latest({
|
||||
directory: migrationsDir,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Discovery
|
||||
|
||||
When building plugins, you might find that you will need to look up another plugin's base URL to be able to communicate with it. This could be for example an HTTP route or some `ws` protocol URL. For this we have a discovery service which can provide both internal and external base URLs for a given a plugin ID.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get the discovery service in your `example` backend plugin and making a request to both the internal and external base URLs for the `derp` plugin.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { fetch } from 'node-fetch';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
discovery: coreServices.discovery,
|
||||
},
|
||||
async init({ discovery }) {
|
||||
const url = await discoverty.getBaseUrl('derp'); // can also use discovery.getBaseUrl to retrieve external URL
|
||||
const response = await fetch(`${url}/hello`);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Identity
|
||||
|
||||
When working with backend plugins, you might find that you will need to interact with the `auth-backend` plugin to both authenticate backstage tokens, and to deconstruct them to get the user's entity ref and/or ownership claims out of them.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get the identity service in your `example` backend plugin and retrieve the user's entity ref and ownership claims for the incoming request.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { Router } from 'express';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
identity: coreServices.identity,
|
||||
http: coreServices.httpRouter,
|
||||
},
|
||||
async init({ http, identity }) {
|
||||
const router = Router();
|
||||
router.get('/test-me', (request, response) => {
|
||||
// use the identity service to pull out the header from the request and get the user
|
||||
const {
|
||||
identity: { userEntityRef, ownershipEntityRefs },
|
||||
} = await identity.getIdentity({
|
||||
request,
|
||||
});
|
||||
|
||||
// send the decoded and validated things back to the user
|
||||
response.json({
|
||||
userEntityRef,
|
||||
ownershipEntityRefs,
|
||||
});
|
||||
});
|
||||
|
||||
http.use(router);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Configuring the service
|
||||
|
||||
There's additional configuration that you can optionally pass to setup the `identity` core service.
|
||||
|
||||
- `issuer` - Set an optional issuer for validation of the JWT token
|
||||
- `algorithms` - `alg` header for validation of the JWT token, defaults to `ES256`. More info on supported algorithms can be found in the [`jose` library documentation](https://github.com/panva/jose)
|
||||
|
||||
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';
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
identityFactory({
|
||||
issuer: 'backstage',
|
||||
algorithms: ['ES256', 'RS256'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Lifecycle
|
||||
|
||||
This service allows your plugins to register hooks for cleaning up resources as the service is shutting down (e.g. when a pod is being torn down, or when pressing `Ctrl+C` during local development). Other core services also leverage this same mechanism internally to stop themselves cleanly.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get the lifecycle service in your `example` backend plugin to clean up a long running interval when the service is shutting down.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
lifecycle: coreServices.lifecycle,
|
||||
logger: coreServices.logger,
|
||||
},
|
||||
async init({ lifecycle, logger }) {
|
||||
// some example work that we want to stop when shutting down
|
||||
const interval = setInterval(async () => {
|
||||
await fetch('http://google.com/keepalive').then(r => r.json());
|
||||
// do some other stuff.
|
||||
}, 1000);
|
||||
|
||||
lifecycle.addShutdownHook({
|
||||
fn: () => clearInterval(interval),
|
||||
logger,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Root Lifecycle
|
||||
|
||||
This service is the same as the lifecycle service, but should only be used by the root services. This is also where the implementation for the actual lifecycle hooks are collected and executed, so if you want to override the implementation of how those are processed, you should override this service.
|
||||
|
||||
### Configure the service
|
||||
|
||||
The following example shows how to override the default implementation of the lifecycle service with something that listens on different process events to the original.
|
||||
|
||||
```ts
|
||||
class MyCustomLifecycleService implements RootLifecycleService {
|
||||
constructor(private readonly logger: LoggerService) {
|
||||
['SIGKILL', 'SIGTERM'].map(signal =>
|
||||
process.on(signal, () => this.shutdown()),
|
||||
);
|
||||
}
|
||||
|
||||
#isCalled = false;
|
||||
#shutdownTasks: Array<LifecycleServiceShutdownHook> = [];
|
||||
|
||||
addShutdownHook(options: LifecycleServiceShutdownHook): void {
|
||||
this.#shutdownTasks.push(options);
|
||||
}
|
||||
|
||||
async shutdown(): Promise<void> {
|
||||
if (this.#isCalled) {
|
||||
return;
|
||||
}
|
||||
this.#isCalled = true;
|
||||
|
||||
this.logger.info(`Running ${this.#shutdownTasks.length} shutdown tasks...`);
|
||||
await Promise.all(
|
||||
this.#shutdownTasks.map(async hook => {
|
||||
const { logger = this.logger } = hook;
|
||||
try {
|
||||
await hook.fn();
|
||||
logger.info(`Shutdown hook succeeded`);
|
||||
} catch (error) {
|
||||
logger.error(`Shutdown hook failed, ${error}`);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const backend = createBackend({
|
||||
services: [
|
||||
createServiceFactory({
|
||||
service: coreServices.rootLifecycle,
|
||||
deps: {
|
||||
logger: coreServices.rootLogger,
|
||||
},
|
||||
async factory({ logger }) {
|
||||
return new MyCustomLifecycleService(logger);
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Permissions
|
||||
|
||||
This service allows your plugins to ask [the permissions framework](https://backstage.io/docs/permissions/overview) for authorization of user actions.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get the permissions service in your `example` backend to check to see if the user is allowed to perform a certain action with a custom permission rule.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { Router } from 'express';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
permissions: coreServices.permissions,
|
||||
http: coreServices.httpRouter,
|
||||
},
|
||||
async init({ permissions, http }) {
|
||||
const router = Router();
|
||||
router.get('/test-me', (request, response) => {
|
||||
// use the identity service to pull out the token from request headers
|
||||
const { token } = await identity.getIdentity({
|
||||
request,
|
||||
});
|
||||
|
||||
// ask the permissions framework what the decision is for the permission
|
||||
const permissionResponse = await permissions.authorize(
|
||||
[
|
||||
{
|
||||
permission: myCustomPermission,
|
||||
},
|
||||
],
|
||||
{ token },
|
||||
);
|
||||
});
|
||||
|
||||
http.use(router);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Scheduler
|
||||
|
||||
When writing plugins, you sometimes want to have things running on a schedule, or something similar to cron jobs that are distributed through instances that your backend plugin is running on. We supply a task scheduler for this purpose that is scoped per plugin so that you can create these tasks and orchestrate their execution.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get the scheduler service in your `example` backend to issue a scheduled task that runs across your instances at a given interval.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { fetch } from 'node-fetch';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
scheduler: coreServices.scheduler,
|
||||
},
|
||||
async init({ scheduler }) {
|
||||
await scheduler.scheduleTask({
|
||||
frequency: { minutes: 10 },
|
||||
timeout: { seconds: 30 },
|
||||
id: 'ping-google',
|
||||
fn: async () => {
|
||||
await fetch('http://google.com/ping');
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## URL Readers
|
||||
|
||||
Plugins will require communication with certain integrations that users have configured. Popular integrations are things like Version Control Systems (VSC), such as GitHub, BitBucket GitLab etc. These integrations are configured in the `integrations` section of the `app-config.yaml` file.
|
||||
|
||||
These URL readers are basically wrappers with authentication for files and folders that could be stored in these VCS repositories.
|
||||
|
||||
### Using the service
|
||||
|
||||
The following example shows how to get the URL Reader service in your `example` backend plugin to read a file and a directory from a GitHub repository.
|
||||
|
||||
```ts
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import os from 'os';
|
||||
|
||||
createBackendPlugin({
|
||||
id: 'example',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
urlReader: coreServices.urlReader,
|
||||
},
|
||||
async init({ urlReader }) {
|
||||
const buffer = await urlReader
|
||||
.read('https://github.com/backstage/backstage/blob/master/README.md')
|
||||
.then(r => r.buffer());
|
||||
|
||||
const tmpDir = os.tmpdir();
|
||||
const directory = await urlReader
|
||||
.readTree(
|
||||
'https://github.com/backstage/backstage/tree/master/packages/backend',
|
||||
)
|
||||
.then(tree => tree.dir({ targetDir: tmpDir }));
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -402,6 +402,41 @@ view the Kubernetes API docs for your Kubernetes version (e.g.
|
||||
[API Groups for v1.22](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#-strong-api-groups-strong-)
|
||||
)
|
||||
|
||||
### `objectTypes` (optional)
|
||||
|
||||
Overrides for the Kubernetes object types fetched from the cluster. The default object types are:
|
||||
|
||||
- pods
|
||||
- services
|
||||
- configmaps
|
||||
- limitranges
|
||||
- deployments
|
||||
- replicasets
|
||||
- horizontalpodautoscalers
|
||||
- jobs
|
||||
- cronjobs
|
||||
- ingresses
|
||||
- statefulsets
|
||||
- daemonsets
|
||||
|
||||
You may use this config to override the default object types if you only want a subset of
|
||||
the default ones. However, it's currently not supported to fetch object types other
|
||||
than the ones specified in the default types.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
kubernetes:
|
||||
objectTypes:
|
||||
- configmaps
|
||||
- deployments
|
||||
- limitranges
|
||||
- pods
|
||||
- services
|
||||
- statefulsets
|
||||
```
|
||||
|
||||
### Role Based Access Control
|
||||
|
||||
The current RBAC permissions required are read-only cluster wide, the below
|
||||
@@ -441,6 +476,13 @@ rules:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- metrics.k8s.io
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
```
|
||||
|
||||
## Surfacing your Kubernetes components as part of an entity
|
||||
|
||||
@@ -114,6 +114,42 @@ of the `SearchType` component.
|
||||
|
||||
> Check out the documentation around [integrating search into plugins](../../plugins/integrating-search-into-plugins.md#create-a-collator) for how to create your own collator.
|
||||
|
||||
## How to customize fields in the Software Catalog index
|
||||
|
||||
Sometimes you will might want to have ability to control
|
||||
which data passes to search index in catalog collator, or to customize data for specific kind.
|
||||
You can easily do that by passing `entityTransformer` callback to `DefaultCatalogCollatorFactory`.
|
||||
You can either just simply amend default behaviour, or even to write completely new document
|
||||
(which should follow some required basic structure though).
|
||||
|
||||
> `authorization` and `location` cannot be modified via a `entityTransformer`, `location` can be modified only through `locationTemplate`.
|
||||
|
||||
```diff
|
||||
// packages/backend/src/plugins/search.ts
|
||||
|
||||
const entityTransformer: CatalogCollatorEntityTransformer = (entity: Entity) => {
|
||||
if (entity.kind === 'SomeKind') {
|
||||
return {
|
||||
// customize here output for 'SomeKind' kind
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
// and customize default output
|
||||
...defaultCatalogCollatorEntityTransformer(entity),
|
||||
text: 'my super cool text',
|
||||
};
|
||||
};
|
||||
|
||||
indexBuilder.addCollator({
|
||||
collator: DefaultCatalogCollatorFactory.fromConfig(env.config, {
|
||||
discovery: env.discovery,
|
||||
tokenManager: env.tokenManager,
|
||||
+ entityTransformer,
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
## How to limit what can be searched in the Software Catalog
|
||||
|
||||
The Software Catalog includes a wealth of information about the components,
|
||||
|
||||
@@ -12,56 +12,63 @@ infrastructure needs - CI/CD, monitoring, auditing, and more.
|
||||
|
||||
The following steps assume that you have
|
||||
[created a Backstage app](./create-an-app.md) and want to add an existing plugin
|
||||
to it. We are using the
|
||||
to it.
|
||||
|
||||
We are using the
|
||||
[CircleCI](https://github.com/backstage/backstage/blob/master/plugins/circleci/README.md)
|
||||
plugin in this example.
|
||||
plugin in this example, which is designed to show CI/CD pipeline information attached
|
||||
to an entity in the software catalog.
|
||||
|
||||
1. Add the plugin's npm package to the repo:
|
||||
|
||||
```bash
|
||||
yarn workspace app add @backstage/plugin-circleci
|
||||
```
|
||||
```bash
|
||||
yarn workspace app add @backstage/plugin-circleci
|
||||
```
|
||||
|
||||
Note the plugin is added to the `app` package, rather than the root
|
||||
package.json. Backstage Apps are set up as monorepos with
|
||||
[yarn workspaces](https://classic.yarnpkg.com/en/docs/workspaces/). Since
|
||||
CircleCI is a frontend UI plugin, it goes in `app` rather than `backend`.
|
||||
Note the plugin is added to the `app` package, rather than the root
|
||||
`package.json`. Backstage Apps are set up as monorepos with
|
||||
[Yarn workspaces](https://classic.yarnpkg.com/en/docs/workspaces/). Since
|
||||
CircleCI is a frontend UI plugin, it goes in `app` rather than `backend`.
|
||||
|
||||
2. Add the `EntityCircleCIContent` extension to the entity pages in the app:
|
||||
|
||||
```diff
|
||||
// packages/app/src/components/catalog/EntityPage.tsx
|
||||
+import {
|
||||
+ EntityCircleCIContent,
|
||||
+ isCircleCIAvailable,
|
||||
+} from '@backstage/plugin-circleci';
|
||||
```diff
|
||||
// packages/app/src/components/catalog/EntityPage.tsx
|
||||
+import {
|
||||
+ EntityCircleCIContent,
|
||||
+ isCircleCIAvailable,
|
||||
+} from '@backstage/plugin-circleci';
|
||||
|
||||
...
|
||||
const cicdContent = (
|
||||
<EntitySwitch>
|
||||
...
|
||||
+ <EntitySwitch.Case if={isCircleCIAvailable}>
|
||||
+ <EntityCircleCIContent />
|
||||
+ </EntitySwitch.Case>;
|
||||
</EntitySwitch>
|
||||
);
|
||||
```
|
||||
...
|
||||
const cicdContent = (
|
||||
<EntitySwitch>
|
||||
...
|
||||
+ <EntitySwitch.Case if={isCircleCIAvailable}>
|
||||
+ <EntityCircleCIContent />
|
||||
+ </EntitySwitch.Case>;
|
||||
</EntitySwitch>
|
||||
);
|
||||
```
|
||||
|
||||
This is just one example, but each Backstage instance may integrate content or
|
||||
cards to suit their needs on different pages, tabs, etc. Note that stand-alone
|
||||
plugins that are not "attached" to the Software Catalog would be added outside
|
||||
the `EntityPage`.
|
||||
This is just one example, but each Backstage instance may integrate content or
|
||||
cards to suit their needs on different pages, tabs, etc. In addition, while some
|
||||
plugins such as this example are designed to annotate or support specific software
|
||||
catalog entities, others may be intended to be used in a stand-alone fashion and
|
||||
would be added outside the `EntityPage`, such as being added to the main navigation.
|
||||
|
||||
4. [Optional] Add proxy config:
|
||||
3. _[Optional]_ Add a proxy config:
|
||||
|
||||
```yaml
|
||||
// app-config.yaml
|
||||
proxy:
|
||||
'/circleci/api':
|
||||
target: https://circleci.com/api/v1.1
|
||||
headers:
|
||||
Circle-Token: ${CIRCLECI_AUTH_TOKEN}
|
||||
```
|
||||
Plugins that collect data off of external services may require the use of a proxy service.
|
||||
This plugin accesses the CircleCI REST API, and thus requires a proxy definition.
|
||||
|
||||
```yaml
|
||||
// app-config.yaml
|
||||
proxy:
|
||||
'/circleci/api':
|
||||
target: https://circleci.com/api/v1.1
|
||||
headers:
|
||||
Circle-Token: ${CIRCLECI_AUTH_TOKEN}
|
||||
```
|
||||
|
||||
### Adding a plugin page to the Sidebar
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ You can also serve the plugin in isolation by running `yarn start` in the plugin
|
||||
directory. Or by using the yarn workspace command, for example:
|
||||
|
||||
```bash
|
||||
yarn workspace @backstage/my-plugin start # Also supports --check
|
||||
yarn workspace @backstage/plugin-my-plugin start # Also supports --check
|
||||
```
|
||||
|
||||
This method of serving the plugin provides quicker iteration speed and a faster
|
||||
|
||||
@@ -56,7 +56,7 @@ The users selection is saved in the users browsers local storage. Once toggled i
|
||||
The easiest way to control content based on the state of a feature flag is to use the [FeatureFlagged](https://backstage.io/docs/reference/core-app-api.featureflagged) component.
|
||||
|
||||
```ts
|
||||
import { FeatureFlagged } from '@backstage/core-app-api'
|
||||
import { FeatureFlagged } from '@backstage/core-app-api';
|
||||
|
||||
...
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10093,9 +10093,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"ua-parser-js@npm:^0.7.30":
|
||||
version: 0.7.32
|
||||
resolution: "ua-parser-js@npm:0.7.32"
|
||||
checksum: 6b6b035dd78a0ab3369f166ab6f26225d823d83630788806d634f16259297a8f4ae6fe0be4e48f4353ac10dffded3971d7745c55d1432fdfc78a893ba58ef044
|
||||
version: 0.7.33
|
||||
resolution: "ua-parser-js@npm:0.7.33"
|
||||
checksum: 1510e9ec26fcaf0d8c6ae8f1078a8230e8816f083e1b5f453ea19d06b8ef2b8a596601c92148fd41899e8b3e5f83fa69c42332bd5729b931a721040339831696
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ author: Spotify
|
||||
authorUrl: https://github.com/spotify
|
||||
category: Core Feature
|
||||
description: A composable and extensible search platform built to fit your organization’s needs and find information quickly.
|
||||
documentation: https://backstage.io/docs/features/software-catalog/software-catalog-overview
|
||||
documentation: https://backstage.io/docs/features/search/search-overview
|
||||
iconUrl: img/backstage-search-platform.svg
|
||||
npmPackageName: '@backstage/plugin-search'
|
||||
order: 5
|
||||
|
||||
@@ -1244,12 +1244,24 @@ h3.collapsible span.arrow {
|
||||
transform: translateY(-50%) translateX(500px);
|
||||
}
|
||||
|
||||
@media only screen and (max-height: 675px) {
|
||||
.Sidebar__Container {
|
||||
top: 65%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
.Sidebar__Container {
|
||||
transform: translateY(-50%) translateX(300px);
|
||||
}
|
||||
}
|
||||
|
||||
.Sidebar__Container--open {
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.Sidebar__Button {
|
||||
transform: rotate(-90deg) translateY(48px);
|
||||
transform: rotate(-90deg) translateY(49px);
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
background-color: rgb(92, 214, 200);
|
||||
@@ -1263,18 +1275,34 @@ h3.collapsible span.arrow {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
.Sidebar__Button {
|
||||
width: 175px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.Sidebar__Button:hover {
|
||||
transform: rotate(-90deg) translateY(48px) scale(1.01);
|
||||
transform: rotate(-90deg) translateY(49px) scale(1.01);
|
||||
}
|
||||
|
||||
#Sidebar__HubSpotContainer {
|
||||
width: 500px;
|
||||
background-color: white;
|
||||
border-radius: 8px 0 0 8px;
|
||||
padding: 16px;
|
||||
padding-bottom: 0px;
|
||||
z-index: 10001;
|
||||
min-height: 260px;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
#Sidebar__HubSpotContainer {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
#Sidebar__HubSpotContainer form {
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
padding: 25px 25px 0px 25px;
|
||||
}
|
||||
|
||||
#Sidebar__HubSpotContainer .hs-button {
|
||||
@@ -1284,6 +1312,7 @@ h3.collapsible span.arrow {
|
||||
color: rgb(0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#Sidebar__HubSpotContainer.submitted-message {
|
||||
min-height: 260px;
|
||||
display: flex;
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@
|
||||
"@types/react": "^17",
|
||||
"@types/react-dom": "^17"
|
||||
},
|
||||
"version": "1.10.0",
|
||||
"version": "1.11.0-next.0",
|
||||
"dependencies": {
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@manypkg/get-packages": "^1.1.3"
|
||||
|
||||
@@ -1,5 +1,60 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.80-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-azure-devops@0.2.6-next.0
|
||||
- @backstage/plugin-scaffolder-react@1.1.0-next.0
|
||||
- @backstage/plugin-scaffolder@1.11.0-next.0
|
||||
- @backstage/plugin-api-docs@0.8.15-next.0
|
||||
- @backstage/plugin-techdocs@1.4.4-next.0
|
||||
- @backstage/plugin-catalog-react@1.3.0-next.0
|
||||
- @backstage/plugin-user-settings@0.6.3-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/plugin-kubernetes@0.7.8-next.0
|
||||
- @backstage/plugin-airbrake@0.3.15-next.0
|
||||
- @backstage/plugin-azure-sites@0.1.4-next.0
|
||||
- @backstage/plugin-badges@0.2.39-next.0
|
||||
- @internal/plugin-catalog-customized@0.0.7-next.0
|
||||
- @backstage/plugin-catalog-graph@0.2.27-next.0
|
||||
- @backstage/plugin-catalog-import@0.9.5-next.0
|
||||
- @backstage/plugin-circleci@0.3.15-next.0
|
||||
- @backstage/plugin-cloudbuild@0.3.15-next.0
|
||||
- @backstage/plugin-code-coverage@0.2.8-next.0
|
||||
- @backstage/plugin-cost-insights@0.12.4-next.0
|
||||
- @backstage/plugin-dynatrace@2.0.0-next.0
|
||||
- @backstage/plugin-explore@0.3.46-next.0
|
||||
- @backstage/plugin-github-actions@0.5.15-next.0
|
||||
- @backstage/plugin-gocd@0.1.21-next.0
|
||||
- @backstage/plugin-home@0.4.31-next.0
|
||||
- @backstage/plugin-jenkins@0.7.14-next.0
|
||||
- @backstage/plugin-kafka@0.3.15-next.0
|
||||
- @backstage/plugin-lighthouse@0.3.15-next.0
|
||||
- @backstage/plugin-newrelic-dashboard@0.2.8-next.0
|
||||
- @backstage/plugin-org@0.6.5-next.0
|
||||
- @backstage/plugin-pagerduty@0.5.8-next.0
|
||||
- @backstage/plugin-playlist@0.1.6-next.0
|
||||
- @backstage/plugin-rollbar@0.4.15-next.0
|
||||
- @backstage/plugin-search@1.0.8-next.0
|
||||
- @backstage/plugin-sentry@0.4.8-next.0
|
||||
- @backstage/plugin-tech-insights@0.3.7-next.0
|
||||
- @backstage/plugin-todo@0.2.17-next.0
|
||||
- @backstage/plugin-catalog-common@1.0.11-next.0
|
||||
- @backstage/plugin-techdocs-react@1.1.3-next.0
|
||||
- @backstage/cli@0.22.1
|
||||
- @backstage/plugin-techdocs-module-addons-contrib@1.0.10-next.0
|
||||
- @backstage/integration-react@1.1.9
|
||||
- @backstage/plugin-apache-airflow@0.2.7
|
||||
- @backstage/plugin-gcalendar@0.3.10
|
||||
- @backstage/plugin-gcp-projects@0.3.33
|
||||
- @backstage/plugin-graphiql@0.2.46
|
||||
- @backstage/plugin-newrelic@0.3.32
|
||||
- @backstage/plugin-shortcuts@0.3.6
|
||||
- @backstage/plugin-stack-overflow@0.1.11-next.0
|
||||
- @backstage/plugin-tech-radar@0.6.0
|
||||
|
||||
## 0.2.79
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.2.79",
|
||||
"version": "0.2.80-next.0",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
|
||||
@@ -244,6 +244,9 @@ const routes = (
|
||||
<ScaffolderFieldExtensions>
|
||||
<DelayingComponentFieldExtension />
|
||||
</ScaffolderFieldExtensions>
|
||||
<ScaffolderLayouts>
|
||||
<TwoColumnLayout />
|
||||
</ScaffolderLayouts>
|
||||
</Route>
|
||||
<Route path="/explore" element={<ExplorePage />} />
|
||||
<Route
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# @backstage/backend-app-api
|
||||
|
||||
## 0.3.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a18da2f8b5: Fixed an issue were the log redaction didn't properly escape RegExp characters.
|
||||
- ed8b5967d7: `HttpRouterFactoryOptions.getPath` is now optional as a default value is always provided in the factory.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
- @backstage/backend-tasks@0.4.3-next.0
|
||||
- @backstage/plugin-auth-node@0.2.11-next.0
|
||||
- @backstage/plugin-permission-node@0.7.5-next.0
|
||||
- @backstage/backend-plugin-api@0.3.2-next.0
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -125,7 +125,7 @@ export const httpRouterFactory: (
|
||||
|
||||
// @public (undocumented)
|
||||
export interface HttpRouterFactoryOptions {
|
||||
getPath(pluginId: string): string;
|
||||
getPath?(pluginId: string): string;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-app-api",
|
||||
"description": "Core API used by Backstage backend apps",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.2-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ export interface HttpRouterFactoryOptions {
|
||||
/**
|
||||
* A callback used to generate the path for each plugin, defaults to `/api/{pluginId}`.
|
||||
*/
|
||||
getPath(pluginId: string): string;
|
||||
getPath?(pluginId: string): string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/backend-common
|
||||
|
||||
## 0.18.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.3.2-next.0
|
||||
- @backstage/backend-plugin-api@0.3.2-next.0
|
||||
|
||||
## 0.18.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-common",
|
||||
"description": "Common functionality library for Backstage backends",
|
||||
"version": "0.18.0",
|
||||
"version": "0.18.2-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
@@ -45,7 +45,7 @@
|
||||
"@google-cloud/storage": "^6.0.0",
|
||||
"@keyv/memcache": "^1.3.5",
|
||||
"@keyv/redis": "^2.5.3",
|
||||
"@kubernetes/client-node": "0.18.0",
|
||||
"@kubernetes/client-node": "0.18.1",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@octokit/rest": "^19.0.3",
|
||||
"@types/cors": "^2.8.6",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/backend-defaults
|
||||
|
||||
## 0.1.7-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.3.2-next.0
|
||||
- @backstage/backend-plugin-api@0.3.2-next.0
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-defaults",
|
||||
"description": "Backend defaults used by Backstage backend apps",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.7-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# example-backend-next
|
||||
|
||||
## 0.0.8-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-scaffolder-backend@1.11.0-next.0
|
||||
- @backstage/backend-defaults@0.1.7-next.0
|
||||
- @backstage/plugin-app-backend@0.3.42-next.0
|
||||
- @backstage/plugin-catalog-backend@1.7.2-next.0
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend-next",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.8-next.0",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
|
||||
import { catalogPlugin } from '@backstage/plugin-catalog-backend';
|
||||
import { scaffolderCatalogModule } from '@backstage/plugin-scaffolder-backend';
|
||||
import { catalogModuleTemplateKind } from '@backstage/plugin-scaffolder-backend';
|
||||
import { createBackend } from '@backstage/backend-defaults';
|
||||
import { appPlugin } from '@backstage/plugin-app-backend';
|
||||
|
||||
const backend = createBackend();
|
||||
|
||||
backend.add(catalogPlugin());
|
||||
backend.add(scaffolderCatalogModule());
|
||||
backend.add(catalogModuleTemplateKind());
|
||||
backend.add(appPlugin({ appPackageName: 'example-app' }));
|
||||
backend.start();
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/backend-plugin-api
|
||||
|
||||
## 0.3.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-tasks@0.4.3-next.0
|
||||
- @backstage/plugin-auth-node@0.2.11-next.0
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-plugin-api",
|
||||
"description": "Core API used by Backstage backend plugins",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.2-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @backstage/backend-tasks
|
||||
|
||||
## 0.4.3-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-tasks",
|
||||
"description": "Common distributed task management library for Backstage backends",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.3-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @backstage/backend-test-utils
|
||||
|
||||
## 0.1.34-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d0901c9ba4: All mock service factories and mock service implementations are now available via the new experimental `mockServices` export.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-app-api@0.3.2-next.0
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
- @backstage/plugin-auth-node@0.2.11-next.0
|
||||
- @backstage/cli@0.22.1
|
||||
- @backstage/backend-plugin-api@0.3.2-next.0
|
||||
|
||||
## 0.1.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/backend-test-utils",
|
||||
"description": "Test helpers library for Backstage backends",
|
||||
"version": "0.1.32",
|
||||
"version": "0.1.34-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,5 +1,49 @@
|
||||
# example-backend
|
||||
|
||||
## 0.2.80-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-kubernetes-backend@0.9.3-next.0
|
||||
- @backstage/plugin-scaffolder-backend-module-rails@0.4.10-next.0
|
||||
- @backstage/plugin-tech-insights-backend-module-jsonfc@0.1.26-next.0
|
||||
- @backstage/plugin-scaffolder-backend@1.11.0-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- example-app@0.2.80-next.0
|
||||
- @backstage/plugin-techdocs-backend@1.5.3-next.0
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
- @backstage/plugin-app-backend@0.3.42-next.0
|
||||
- @backstage/catalog-client@1.3.1-next.0
|
||||
- @backstage/plugin-adr-backend@0.2.7-next.0
|
||||
- @backstage/plugin-auth-backend@0.17.5-next.0
|
||||
- @backstage/plugin-badges-backend@0.1.36-next.0
|
||||
- @backstage/plugin-catalog-backend@1.7.2-next.0
|
||||
- @backstage/plugin-catalog-node@1.3.3-next.0
|
||||
- @backstage/plugin-code-coverage-backend@0.2.8-next.0
|
||||
- @backstage/plugin-jenkins-backend@0.1.32-next.0
|
||||
- @backstage/plugin-kafka-backend@0.2.35-next.0
|
||||
- @backstage/plugin-playlist-backend@0.2.5-next.0
|
||||
- @backstage/plugin-tech-insights-backend@0.5.8-next.0
|
||||
- @backstage/plugin-todo-backend@0.1.39-next.0
|
||||
- @backstage/backend-tasks@0.4.3-next.0
|
||||
- @backstage/plugin-auth-node@0.2.11-next.0
|
||||
- @backstage/plugin-events-backend@0.2.3-next.0
|
||||
- @backstage/plugin-permission-node@0.7.5-next.0
|
||||
- @backstage/plugin-rollbar-backend@0.1.39-next.0
|
||||
- @backstage/plugin-search-backend-module-pg@0.5.3-next.0
|
||||
- @backstage/plugin-azure-devops-backend@0.3.21-next.0
|
||||
- @backstage/plugin-azure-sites-backend@0.1.4-next.0
|
||||
- @backstage/plugin-explore-backend@0.0.4-next.0
|
||||
- @backstage/plugin-graphql-backend@0.1.32-next.0
|
||||
- @backstage/plugin-permission-backend@0.5.17-next.0
|
||||
- @backstage/plugin-proxy-backend@0.2.36-next.0
|
||||
- @backstage/plugin-search-backend@1.2.3-next.0
|
||||
- @backstage/plugin-search-backend-module-elasticsearch@1.1.3-next.0
|
||||
- @backstage/plugin-search-backend-node@1.1.3-next.0
|
||||
- @backstage/plugin-tech-insights-node@0.3.10-next.0
|
||||
- @backstage/plugin-events-node@0.2.3-next.0
|
||||
|
||||
## 0.2.79
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "example-backend",
|
||||
"version": "0.2.79",
|
||||
"version": "0.2.80-next.0",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @backstage/catalog-client
|
||||
|
||||
## 1.3.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
|
||||
## 1.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/catalog-client",
|
||||
"description": "An isomorphic client for the catalog backend",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.1-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/catalog-model
|
||||
|
||||
## 1.1.6-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2518ef5b8a: Add deprecation tag to kubernetes constants in catalog, constants are now defined in plugin-kubernetes-common
|
||||
|
||||
## 1.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -14,14 +14,14 @@ export interface AlphaEntity extends Entity {
|
||||
// @public
|
||||
export const ANNOTATION_EDIT_URL = 'backstage.io/edit-url';
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export const ANNOTATION_KUBERNETES_API_SERVER = 'kubernetes.io/api-server';
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export const ANNOTATION_KUBERNETES_API_SERVER_CA =
|
||||
'kubernetes.io/api-server-certificate-authority';
|
||||
|
||||
// @public
|
||||
// @public @deprecated
|
||||
export const ANNOTATION_KUBERNETES_AUTH_PROVIDER =
|
||||
'kubernetes.io/auth-provider';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/catalog-model",
|
||||
"description": "Types and validators that help describe the model of a Backstage Catalog",
|
||||
"version": "1.1.5",
|
||||
"version": "1.1.6-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -38,6 +38,7 @@ export const ANNOTATION_EDIT_URL = 'backstage.io/edit-url';
|
||||
/**
|
||||
* Annotation for specifying the API server of a Kubernetes cluster
|
||||
*
|
||||
* @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead
|
||||
* @public
|
||||
*/
|
||||
export const ANNOTATION_KUBERNETES_API_SERVER = 'kubernetes.io/api-server';
|
||||
@@ -45,6 +46,7 @@ export const ANNOTATION_KUBERNETES_API_SERVER = 'kubernetes.io/api-server';
|
||||
/**
|
||||
* Annotation for specifying the Certificate Authority of an API server for a Kubernetes cluster
|
||||
*
|
||||
* @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead
|
||||
* @public
|
||||
*/
|
||||
export const ANNOTATION_KUBERNETES_API_SERVER_CA =
|
||||
@@ -53,6 +55,7 @@ export const ANNOTATION_KUBERNETES_API_SERVER_CA =
|
||||
/**
|
||||
* Annotation for specifying the auth provider for a Kubernetes cluster
|
||||
*
|
||||
* @deprecated Import this constant from `@backstage/plugin-kubernetes-common` instead
|
||||
* @public
|
||||
*/
|
||||
export const ANNOTATION_KUBERNETES_AUTH_PROVIDER =
|
||||
|
||||
@@ -15,14 +15,7 @@
|
||||
*/
|
||||
|
||||
export * from './conditions';
|
||||
export {
|
||||
DEFAULT_NAMESPACE,
|
||||
ANNOTATION_EDIT_URL,
|
||||
ANNOTATION_VIEW_URL,
|
||||
ANNOTATION_KUBERNETES_API_SERVER,
|
||||
ANNOTATION_KUBERNETES_API_SERVER_CA,
|
||||
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
|
||||
} from './constants';
|
||||
export * from './constants';
|
||||
export type {
|
||||
AlphaEntity,
|
||||
Entity,
|
||||
|
||||
@@ -32,6 +32,10 @@ import chalk from 'chalk';
|
||||
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
|
||||
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
|
||||
|
||||
function applyContextToError(error: string, moduleName: string): string {
|
||||
return `Failed to compile '${moduleName}':\n ${error}`;
|
||||
}
|
||||
|
||||
export async function buildBundle(options: BuildOptions) {
|
||||
const { statsJsonEnabled, schema: configSchema } = options;
|
||||
|
||||
@@ -63,10 +67,7 @@ export async function buildBundle(options: BuildOptions) {
|
||||
);
|
||||
}
|
||||
|
||||
const { stats } = await build(config, isCi).catch(error => {
|
||||
console.log(chalk.red('Failed to compile.\n'));
|
||||
throw new Error(`Failed to compile.\n${error.message || error}`);
|
||||
});
|
||||
const { stats } = await build(config, isCi);
|
||||
|
||||
if (!stats) {
|
||||
throw new Error('No stats returned');
|
||||
@@ -114,7 +115,7 @@ async function build(config: webpack.Configuration, isCi: boolean) {
|
||||
);
|
||||
|
||||
if (!stats) {
|
||||
throw new Error('No stats provided');
|
||||
throw new Error('Failed to compile: No stats provided');
|
||||
}
|
||||
|
||||
const serializedStats = stats.toJson({
|
||||
@@ -122,29 +123,33 @@ async function build(config: webpack.Configuration, isCi: boolean) {
|
||||
warnings: true,
|
||||
errors: true,
|
||||
});
|
||||
// NOTE(freben): The code below that extracts the message part of the errors,
|
||||
// is due to react-dev-utils not yet being compatible with webpack 5. This
|
||||
// may be possible to remove (just passing the serialized stats object
|
||||
// directly into the format function) after a new release of react-dev-utils
|
||||
// has been made available.
|
||||
// See https://github.com/facebook/create-react-app/issues/9880
|
||||
const { errors, warnings } = formatWebpackMessages({
|
||||
errors: serializedStats.errors?.map(e => (e.message ? e.message : e)),
|
||||
warnings: serializedStats.warnings?.map(e => (e.message ? e.message : e)),
|
||||
errors: serializedStats.errors,
|
||||
warnings: serializedStats.warnings,
|
||||
});
|
||||
|
||||
if (errors.length) {
|
||||
// Only keep the first error. Others are often indicative
|
||||
// of the same problem, but confuse the reader with noise.
|
||||
throw new Error(errors[0]);
|
||||
const errorWithContext = applyContextToError(
|
||||
errors[0],
|
||||
serializedStats.errors?.[0]?.moduleName ?? '',
|
||||
);
|
||||
throw new Error(errorWithContext);
|
||||
}
|
||||
if (isCi && warnings.length) {
|
||||
const warningsWithContext = warnings.map((warning, i) => {
|
||||
return applyContextToError(
|
||||
warning,
|
||||
serializedStats.warnings?.[i]?.moduleName ?? '',
|
||||
);
|
||||
});
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'\nTreating warnings as errors because process.env.CI = true.\n',
|
||||
),
|
||||
);
|
||||
throw new Error(warnings.join('\n\n'));
|
||||
throw new Error(warningsWithContext.join('\n\n'));
|
||||
}
|
||||
|
||||
return { stats };
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @backstage/create-app
|
||||
|
||||
## 0.4.37-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Bumped create-app version.
|
||||
|
||||
## 0.4.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/create-app",
|
||||
"description": "A CLI that helps you create your own Backstage app",
|
||||
"version": "0.4.36",
|
||||
"version": "0.4.37-next.0",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/dev-utils
|
||||
|
||||
## 1.0.12-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.3.0-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/integration-react@1.1.9
|
||||
|
||||
## 1.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/dev-utils",
|
||||
"description": "Utilities for developing Backstage plugins.",
|
||||
"version": "1.0.11",
|
||||
"version": "1.0.12-next.0",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# techdocs-cli-embedded-app
|
||||
|
||||
## 0.2.79-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-techdocs@1.4.4-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/plugin-catalog@1.7.3-next.0
|
||||
- @backstage/plugin-techdocs-react@1.1.3-next.0
|
||||
- @backstage/cli@0.22.1
|
||||
- @backstage/integration-react@1.1.9
|
||||
|
||||
## 0.2.78
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "techdocs-cli-embedded-app",
|
||||
"version": "0.2.78",
|
||||
"version": "0.2.79-next.0",
|
||||
"private": true,
|
||||
"backstage": {
|
||||
"role": "frontend"
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @techdocs/cli
|
||||
|
||||
## 1.3.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6e0b6a0d50: Fixed publish command missing awsBucketRootPath option.
|
||||
Fixed publish command having the gcsBucketRootPath option misconfigured, previously returning a boolean vs a string.
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-techdocs-node@1.4.6-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
|
||||
## 1.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@techdocs/cli",
|
||||
"description": "Utility CLI for managing TechDocs sites in Backstage.",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.2-next.0",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/plugin-adr-backend
|
||||
|
||||
## 0.2.7-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
- @backstage/catalog-client@1.3.1-next.0
|
||||
- @backstage/plugin-adr-common@0.2.6-next.0
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-adr-backend",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.7-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @backstage/plugin-adr-common
|
||||
|
||||
## 0.2.6-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-adr-common",
|
||||
"description": "Common functionalities for the adr plugin",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.6-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# @backstage/plugin-adr
|
||||
|
||||
## 0.3.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 496cf6aff0: Render the common `<MissingAnnotationEmptyState />` component when the `backstage.io/adr-location` annotation is missing from the component
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.3.0-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/plugin-adr-common@0.2.6-next.0
|
||||
- @backstage/integration-react@1.1.9
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-adr",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @backstage/plugin-airbrake-backend
|
||||
|
||||
## 0.2.15-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
|
||||
## 0.2.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-airbrake-backend",
|
||||
"version": "0.2.13",
|
||||
"version": "0.2.15-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @backstage/plugin-airbrake
|
||||
|
||||
## 0.3.15-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.3.0-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/dev-utils@1.0.12-next.0
|
||||
|
||||
## 0.3.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-airbrake",
|
||||
"version": "0.3.14",
|
||||
"version": "0.3.15-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/plugin-allure
|
||||
|
||||
## 0.1.31-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.3.0-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
|
||||
## 0.1.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-allure",
|
||||
"description": "A Backstage plugin that integrates with Allure",
|
||||
"version": "0.1.30",
|
||||
"version": "0.1.31-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/plugin-api-docs
|
||||
|
||||
## 0.8.15-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 60996f8aba: Updating the readme with better `csp` instructions
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.3.0-next.0
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/plugin-catalog@1.7.3-next.0
|
||||
|
||||
## 0.8.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-api-docs",
|
||||
"description": "A Backstage plugin that helps represent API entities in the frontend",
|
||||
"version": "0.8.14",
|
||||
"version": "0.8.15-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @backstage/plugin-app-backend
|
||||
|
||||
## 0.3.42-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
- @backstage/backend-plugin-api@0.3.2-next.0
|
||||
|
||||
## 0.3.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-app-backend",
|
||||
"description": "A Backstage backend plugin that serves the Backstage frontend app",
|
||||
"version": "0.3.40",
|
||||
"version": "0.3.42-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @backstage/plugin-auth-backend
|
||||
|
||||
## 0.17.5-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.1.6-next.0
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
- @backstage/catalog-client@1.3.1-next.0
|
||||
- @backstage/plugin-auth-node@0.2.11-next.0
|
||||
|
||||
## 0.17.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@backstage/plugin-auth-backend",
|
||||
"description": "A Backstage backend plugin that handles authentication",
|
||||
"version": "0.17.3",
|
||||
"version": "0.17.5-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @backstage/plugin-auth-node
|
||||
|
||||
## 0.2.11-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.18.2-next.0
|
||||
|
||||
## 0.2.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@backstage/plugin-auth-node",
|
||||
"version": "0.2.9",
|
||||
"version": "0.2.11-next.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user