Merge branch 'master' of github.com:backstage/backstage into s3-backend-docs
This commit is contained in:
@@ -27,6 +27,8 @@ sign-in resolvers and set them for any of the Authentication providers inside
|
||||
`@backstage/plugin-auth-backend` plugin.
|
||||
|
||||
```ts
|
||||
import { DEFAULT_NAMESPACE, stringifyEntityRef } from '@backstage/catalog-model';
|
||||
|
||||
export default async function createPlugin({
|
||||
...
|
||||
}: PluginEnvironment): Promise<Router> {
|
||||
@@ -38,22 +40,31 @@ export default async function createPlugin({
|
||||
resolver: async ({ profile: { email } }, ctx) => {
|
||||
// Call a custom validator function that checks that the email is
|
||||
// valid and on our own company's domain, and throws an Error if it
|
||||
// isn't
|
||||
// isn't.
|
||||
// TODO: Implement this function
|
||||
validateEmail(email);
|
||||
|
||||
// List of entity references that denote the identity and
|
||||
// membership of the user
|
||||
const ent = [];
|
||||
const ent: string[] = [];
|
||||
|
||||
// Let's use the username in the email ID as the user's default
|
||||
// unique identifier inside Backstage.
|
||||
const [id] = email.split('@');
|
||||
ent.push(`User:default/${id}`)
|
||||
ent.push(stringifyEntityRef({
|
||||
kind: 'User',
|
||||
namespace: DEFAULT_NAMESPACE,
|
||||
name: id,
|
||||
}));
|
||||
|
||||
// Let's call the internal LDAP provider to get a list of groups
|
||||
// that the user belongs to, and add those to the list as well
|
||||
const ldapGroups = await getLdapGroups(email);
|
||||
ldapGroups.forEach(group => ent.push(`Group:default/${group}`))
|
||||
ldapGroups.forEach(group => ent.push(stringifyEntityRef({
|
||||
kind: 'Group',
|
||||
namespace: DEFAULT_NAMESPACE,
|
||||
name: group,
|
||||
})));
|
||||
|
||||
// Issue the token containing the entity claims
|
||||
const token = await ctx.tokenIssuer.issueToken({
|
||||
|
||||
@@ -167,7 +167,9 @@ RUN yarn install --frozen-lockfile --network-timeout 600000 && rm -rf "$(yarn ca
|
||||
COPY . .
|
||||
|
||||
RUN yarn tsc
|
||||
RUN yarn --cwd packages/backend backstage-cli backend:bundle --build-dependencies
|
||||
RUN yarn --cwd packages/backend build
|
||||
# If you have not yet migrated to package roles, use the following command instead:
|
||||
# RUN yarn --cwd packages/backend backstage-cli backend:bundle --build-dependencies
|
||||
|
||||
# Stage 3 - Build the actual backend image and install production dependencies
|
||||
FROM node:16-bullseye-slim
|
||||
|
||||
@@ -24,12 +24,12 @@ Backstage ecosystem.
|
||||
|
||||
## Project roadmap
|
||||
|
||||
| Version | Description |
|
||||
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Backstage Search Pre-Alpha ✅ | Search Frontend letting you search through the entities of the software catalog. [See Pre-Alpha Use Cases.](#backstage-search-pre-alpha) |
|
||||
| Backstage Search Alpha ✅ | Basic “out-of-the-box” in-memory indexing process of entities, and their metadata, registered to the Software Catalog. [See Alpha Use Cases](#backstage-search-alpha). |
|
||||
| [Backstage Search Beta ⌛][beta] | At least one production-ready search engine that supports the same use-cases as in the alpha. [See Beta Use Cases](#backstage-search-beta). |
|
||||
| [Backstage Search GA ⌛][ga] | A stable Search API for plugin developers to add search to their plugins, and app integrators to expose that to their users. [See GA Use Cases](#backstage-search-ga). |
|
||||
| Version | Description |
|
||||
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Backstage Search Pre-Alpha ✅ | Search Frontend letting you search through the entities of the software catalog. [See Pre-Alpha Use Cases.](#backstage-search-pre-alpha) |
|
||||
| Backstage Search Alpha ✅ | Basic “out-of-the-box” in-memory indexing process of entities, and their metadata, registered to the Software Catalog. [See Alpha Use Cases](#backstage-search-alpha). |
|
||||
| Backstage Search Beta ✅ | At least one production-ready search engine that supports the same use-cases as in the alpha. [See Beta Use Cases](#backstage-search-beta). |
|
||||
| [Backstage Search GA ⌛][ga] | A stable Search API for plugin developers to add search to their plugins, and app integrators to expose that to their users. [See GA Use Cases](#backstage-search-ga). |
|
||||
|
||||
[beta]: https://github.com/backstage/backstage/milestone/27
|
||||
[ga]: https://github.com/backstage/backstage/milestone/28
|
||||
@@ -128,7 +128,7 @@ plugins integrated to search.
|
||||
| Frontend Plugin | @backstage/plugin-search |
|
||||
| Backend Plugin | @backstage/plugin-search-backend |
|
||||
| Indexer Plugin | @backstage/plugin-search-backend-node |
|
||||
| Common Code | @backstage/search-common |
|
||||
| Common Code | @backstage/plugin-search-common |
|
||||
|
||||
## Get Involved
|
||||
|
||||
|
||||
@@ -54,13 +54,14 @@ An index is a collection of such documents of a given type.
|
||||
### Collators
|
||||
|
||||
You need to be able to search something! Collators are the way to define what
|
||||
can be searched. Specifically, they're classes which return documents conforming
|
||||
to a minimum set of fields (including a document title, location, and text), but
|
||||
which can contain any other fields as defined by the collator itself. One
|
||||
collator is responsible for defining and collecting documents of a type.
|
||||
can be searched. Specifically, they're readable object streams of documents that
|
||||
conform to a minimum set of fields (including a document title, location, and
|
||||
text), but which can contain any other fields as defined by the collator itself.
|
||||
One collator is responsible for defining and collecting documents of a type.
|
||||
|
||||
Some plugins, like the Catalog Backend, provide so-called "default" collators
|
||||
which you can use out-of-the-box to start searching across Backstage quickly.
|
||||
Some plugins, like the Catalog Backend, provide so-called "default" collator
|
||||
factories which you can use out-of-the-box to start searching across Backstage
|
||||
quickly.
|
||||
|
||||
### Decorators
|
||||
|
||||
@@ -68,9 +69,15 @@ Sometimes you want to add extra information to a set of documents in your search
|
||||
index that the collator may not be aware of. For example, the Software Catalog
|
||||
knows about software entities, but it may not know about their usage or quality.
|
||||
|
||||
Decorators are classes which can add extra fields to pre-collated documents.
|
||||
This extra metadata could then be used to bias search results or otherwise
|
||||
improve the search experience in your Backstage instance.
|
||||
Decorators are transform streams which sit between a collator (read stream) and
|
||||
an indexer (write stream) during the indexing process. It can be used to add
|
||||
extra fields to documents as they are being collated and indexed. This extra
|
||||
metadata could then be used to bias search results or otherwise improve the
|
||||
search experience in your Backstage instance.
|
||||
|
||||
In addition to adding extra metadata, decorators (like any transform stream) can
|
||||
also be used to remove metadata, filter out, or even add extra documents at
|
||||
index-time.
|
||||
|
||||
### The Scheduler
|
||||
|
||||
|
||||
@@ -48,10 +48,10 @@ const app = createApp({
|
||||
## How to index TechDocs documents
|
||||
|
||||
The TechDocs plugin has supported integrations to Search, meaning that it
|
||||
provides a default collator ready to be used.
|
||||
provides a default collator factory ready to be used.
|
||||
|
||||
The purpose of this guide is to walk you through how to register the
|
||||
[DefaultTechDocsCollator](https://github.com/backstage/backstage/blob/master/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts)
|
||||
[DefaultTechDocsCollatorFactory](https://github.com/backstage/backstage/blob/master/plugins/techdocs-backend/src/search/DefaultTechDocsCollatorFactory.ts)
|
||||
in your App, so that you can get TechDocs documents indexed.
|
||||
|
||||
If you have been through the
|
||||
@@ -60,18 +60,19 @@ you should have the `packages/backend/src/plugins/search.ts` file available. If
|
||||
so, you can go ahead and follow this guide - if not, start by going through the
|
||||
getting started guide.
|
||||
|
||||
1. Import the DefaultTechDocsCollator from `@backstage/plugin-techdocs-backend`.
|
||||
1. Import the `DefaultTechDocsCollatorFactory` from
|
||||
`@backstage/plugin-techdocs-backend`.
|
||||
|
||||
```typescript
|
||||
import { DefaultTechDocsCollator } from '@backstage/plugin-techdocs-backend';
|
||||
import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-techdocs-backend';
|
||||
```
|
||||
|
||||
2. Register the DefaultTechDocsCollator with the IndexBuilder.
|
||||
2. Register the `DefaultTechDocsCollatorFactory` with the IndexBuilder.
|
||||
|
||||
```typescript
|
||||
indexBuilder.addCollator({
|
||||
defaultRefreshIntervalSeconds: 600,
|
||||
collator: DefaultTechDocsCollator.fromConfig(config, {
|
||||
factory: DefaultTechDocsCollatorFactory.fromConfig(config, {
|
||||
discovery,
|
||||
logger,
|
||||
tokenManager,
|
||||
@@ -131,3 +132,268 @@ indexBuilder.addCollator({
|
||||
|
||||
As shown above, you can add a catalog entity filter to narrow down what catalog
|
||||
entities are indexed by the search engine.
|
||||
|
||||
## How to migrate from Search Alpha to Beta
|
||||
|
||||
For the purposes of this guide, Search Beta version is defined as:
|
||||
|
||||
- **Search Plugin**: At least `v0.7.2`
|
||||
- **Search Backend Plugin**: At least `v0.4.6`
|
||||
- **Search Backend Node**: At least `v0.5.0`
|
||||
- **Search Common**: At least `v0.3.0`
|
||||
|
||||
In the Beta version, the Search Platform's indexing process has been rewritten
|
||||
as a stream pipeline in order to improve efficiency and performance on large
|
||||
sets of documents.
|
||||
|
||||
If you've not yet extended the Search Platform with custom code, and have
|
||||
instead taken advantage of default collators, decorators, and search engines
|
||||
provided by existing plugins, the migration process is fairly straightforward:
|
||||
|
||||
1. Upgrade to at least version `0.5.0` of
|
||||
`@backstage/plugin-search-backend-node`, as well as any backend plugins whose
|
||||
collators you are using (e.g. at least version `0.23.0` of
|
||||
`@backstage/plugin-catalog-backend` and/or version `0.14.1` of
|
||||
`@backstage/plugin-techdocs-backend`), as well as any search-engine specific
|
||||
plugin you are using (e.g. at least version `0.3.0` of
|
||||
`@backstage/plugin-search-backend-module-pg` or version `0.1.0` of
|
||||
`@backstage/plugin-search-backend-module-elasticsearch`).
|
||||
2. Then, make the following changes to your
|
||||
`/packages/backend/src/plugins/search.ts` file:
|
||||
|
||||
```diff
|
||||
-import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
|
||||
-import { DefaultTechDocsCollator } from '@backstage/plugin-techdocs-backend';
|
||||
+import { DefaultCatalogCollatorFactory } from '@backstage/plugin-catalog-backend';
|
||||
+import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-techdocs-backend';
|
||||
// ...
|
||||
const indexBuilder = new IndexBuilder({ logger, searchEngine });
|
||||
indexBuilder.addCollator({
|
||||
defaultRefreshIntervalSeconds: 600,
|
||||
- collator: DefaultCatalogCollator.fromConfig(config, { discovery }),
|
||||
+ factory: DefaultCatalogCollatorFactory.fromConfig(config, { discovery }),
|
||||
});
|
||||
indexBuilder.addCollator({
|
||||
defaultRefreshIntervalSeconds: 600,
|
||||
- collator: DefaultTechDocsCollator.fromConfig(config, {
|
||||
+ factory: DefaultTechDocsCollatorFactory.fromConfig(config, {
|
||||
discovery,
|
||||
logger,
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
Any custom collators, decorators, or search engine implementations will require
|
||||
minor refactoring. Continue on for details.
|
||||
|
||||
### Rewriting alpha-style collators for beta
|
||||
|
||||
In alpha versions of the Backstage Search Platform, collators were classes that
|
||||
implemented an `execute` method which resolved an `IndexableDocument` array.
|
||||
|
||||
In beta versions, the logic encapsulated by the aforementioned `execute` method
|
||||
is contained within an [object-mode][obj-mode] `Readable` stream where each
|
||||
object pushed onto the stream is of type `IndexableDocument`. Instances of this
|
||||
stream are instantiated by a factory class conforming to the
|
||||
`DocumentCollatorFactory` interface.
|
||||
|
||||
The optimal conversion strategy will vary depending on the collator's logic, but
|
||||
the simplest conversion can follow a process like this:
|
||||
|
||||
1. Rename your collator class to something like `YourCollatorFactory` and update
|
||||
it to implement `DocumentCollatorFactory` instead of `DocumentCollator`.
|
||||
2. Update its `execute` method so that it resolves
|
||||
`AsyncGenerator<YourIndexableDocument>` instead of `YourIndexableDocument[]`.
|
||||
3. Implement `DocumentCollatorFactory`'s `getCollator` method which resolves to
|
||||
`Readable.from(this.execute())` (which is a utility for creating [readable
|
||||
streams][read-stream] from [async generators][async-gen]).
|
||||
|
||||
```ts
|
||||
import { DocumentCollatorFactory } from '@backstage/plugin-search-backend-node';
|
||||
import { Readable } from 'stream';
|
||||
export class YourCollatorFactory implements DocumentCollatorFactory {
|
||||
public readonly type: string = 'your-type';
|
||||
async *execute(): AsyncGenerator<YourIndexableDocument> {
|
||||
const widgets = await this.client.getWidgets();
|
||||
for (const widget of widgets) {
|
||||
yield {
|
||||
title: widget.name,
|
||||
location: widget.url,
|
||||
text: widget.description,
|
||||
};
|
||||
}
|
||||
}
|
||||
async getCollator() {
|
||||
return Readable.from(this.execute());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: it may be possible to simplify your collator dramatically! If your custom
|
||||
collator was previously using streams under the hood (for example, by reading
|
||||
newline delimited JSON from a local or remote file), you could just expose the
|
||||
stream directly via a simple factory class:
|
||||
|
||||
```ts
|
||||
import { DocumentCollatorFactory } from '@backstage/plugin-search-backend-node';
|
||||
import { createReadStream } from 'fs';
|
||||
import { parse } from '@jsonlines/core';
|
||||
export class YourCollatorFactory implements DocumentCollatorFactory {
|
||||
public readonly type: string = 'your-type';
|
||||
async getCollator() {
|
||||
const parseStream = parse();
|
||||
return createReadStream('./documents.ndjson').pipe(parseStream);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rewriting alpha-style decorators for beta
|
||||
|
||||
In alpha versions of the Backstage Search Platform, decorators were classes that
|
||||
implemented an `execute` method which took an `IndexableDocument` array as an
|
||||
argument, and resolved a modified array of the same type.
|
||||
|
||||
In beta versions, the logic encapsulated by the aforementioned `execute` method
|
||||
is contained within an object-mode `Transform` stream which reads objects of
|
||||
type `IndexableDocument`, and writes objects of a conforming type. Similar to
|
||||
collators, instances of this stream are instantiated by a factory class
|
||||
conforming to the `DocumentDecoratorFactory` interface.
|
||||
|
||||
Although you can choose to implement a `Transform` stream from scratch, the
|
||||
`@backstage/plugin-search-backend-node` package provides a `DecoratorBase` class
|
||||
in order to simplify the developer experience. With this base class, all that's
|
||||
needed is to transfer your old decorator class logic into the base class' three
|
||||
methods (`initialize`, `decorate`, and `finalize`), and implement the factory
|
||||
class that instantiates the stream:
|
||||
|
||||
```ts
|
||||
import { DecoratorBase } from '@backstage/plugin-search-backend-node';
|
||||
export class YourDecorator extends DecoratorBase {
|
||||
async initialize() {
|
||||
// Setup logic. Performed once before any documents are consumed.
|
||||
}
|
||||
async decorate(
|
||||
document: YourIndexableDocument,
|
||||
): Promise<YourIndexableDocument | YourIndexableDocument[] | undefined> {
|
||||
// Perform transformation logic here.
|
||||
return document;
|
||||
}
|
||||
async finalize() {
|
||||
// Teardown logic. Performed once after all documents have been consumed.
|
||||
}
|
||||
}
|
||||
export class YourDecoratorFactory implements DocumentDecoratorFactory {
|
||||
async getDecorator() {
|
||||
return new YourDecorator();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note the return type of the `decorate` method and how each can be used to
|
||||
different effect.
|
||||
|
||||
- By resolving a single `YourIndexableDocument` object, your decorator can be
|
||||
used to make simple transformations:
|
||||
|
||||
```ts
|
||||
class BooleanWidgetCoolnessDecorator extends DecoratorBase {
|
||||
async decorator(widget) {
|
||||
// Perform a simple, 1:1 transformation.
|
||||
widget.isCool = widget.isCool === 'true' ? true : false;
|
||||
return widget;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- By resolving `undefined`, your decorator can filter out documents which
|
||||
shouldn't be in the index:
|
||||
|
||||
```ts
|
||||
class OnlyCoolWidgetsDecorator extends DecoratorBase {
|
||||
async decorator(widget) {
|
||||
// Perform a simple filter operation.
|
||||
return widget.isCool ? widget : undefined;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- By resolving an array of `YourIndexableDocument` objects, you can generate
|
||||
multiple documents based on the content of one:
|
||||
|
||||
```ts
|
||||
class WidgetByVariantDecorator extends DecoratorBase {
|
||||
async decorator(widget) {
|
||||
// Generate one widget doc per widget variant.
|
||||
return widget.variants.map(variant => {
|
||||
// Each widget doc is the given widget plus a "variant" property
|
||||
// pulled from a widget.variants string array.
|
||||
return {
|
||||
...widget,
|
||||
variant,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In alpha versions, a decorator had access to every `IndexableDocument`
|
||||
simultaneously. This is no longer possible in beta versions (precisely to make
|
||||
the indexing process more efficient and performant). You will need to modify
|
||||
your decorator's logic so that it does not need access to every document at
|
||||
once.
|
||||
|
||||
### Rewriting alpha-style search engines for beta
|
||||
|
||||
Search Engines are responsible for both querying and indexing documents to an
|
||||
underlying search engine technology. While the search engine query interface
|
||||
didn't change between alpha and beta versions, the indexing half of the
|
||||
interface _did_ change.
|
||||
|
||||
In alpha versions of the Backstage Search Platform, a search engine implemented
|
||||
an `index` method which took a `type` and an `IndexableDocument` array and was
|
||||
responsible for writing these documents to the underlying search engine.
|
||||
|
||||
In beta versions, the logic encapsulated by the aforementioned `index` method is
|
||||
contained within an object-mode `Writable` stream which expects objects of type
|
||||
`IndexableDocument`. On the search engine class itself, the `index` method is
|
||||
replaced with a `getIndexer` factory method which still takes the `type`, but
|
||||
resolves an instance of the aforementioned `Writable` stream.
|
||||
|
||||
Although you can choose to implement a `Writable` stream from scratch, the
|
||||
`@backstage/plugin-search-backend-node` package provides a
|
||||
`BatchSearchEngineIndexer` class in order to simplify the developer experience.
|
||||
With this base class, which collects documents in batches of a configurable size
|
||||
on your behalf, all that's needed is to transfer your old `index` method logic
|
||||
into the base class' three methods (`initialize`, `index`, and `finalize`), and
|
||||
implement the factory method that instantiates the stream:
|
||||
|
||||
```ts
|
||||
import { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node';
|
||||
import { SearchEngine } from '@backstage/plugin-search-common';
|
||||
export class YourSearchEngineIndexer extends BatchSearchEngineIndexer {
|
||||
constructor({ type }: { type: string }) {
|
||||
// Customize the number of documents passed to the index method per batch.
|
||||
super({ batchSize: 500 });
|
||||
// An imaginary search engine indexing client.
|
||||
this.index = new SomeSearchEngineIndex({ indexName: type });
|
||||
}
|
||||
async initialize() {
|
||||
// Setup logic. Performed once before any documents are consumed.
|
||||
}
|
||||
async index(documents: IndexableDocument[]) {
|
||||
await this.index.batchOf(documents);
|
||||
}
|
||||
async finalize() {
|
||||
// Teardown logic. Performed once after all documents have been consumed.
|
||||
}
|
||||
}
|
||||
export class YourSearchEngine implements SearchEngine {
|
||||
async getIndexer(type: string) {
|
||||
return new YourSearchEngineIndexer({ type });
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[obj-mode]: https://nodejs.org/docs/latest-v14.x/api/stream.html#stream_object_mode
|
||||
[read-stream]: https://nodejs.org/docs/latest-v14.x/api/stream.html#stream_readable_streams
|
||||
[async-gen]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of#iterating_over_async_generators
|
||||
|
||||
@@ -57,7 +57,7 @@ The recommended way of instantiating the catalog backend classes is to use the
|
||||
`CatalogBuilder`, as illustrated in the
|
||||
[example backend here](https://github.com/backstage/backstage/blob/master/packages/backend/src/plugins/catalog.ts).
|
||||
We will create a new
|
||||
[`EntityProvider`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/providers/types.ts)
|
||||
[`EntityProvider`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/api/provider.ts)
|
||||
subclass that can be added to this catalog builder.
|
||||
|
||||
Let's make a simple provider that can refresh a set of entities based on a
|
||||
@@ -355,7 +355,7 @@ The recommended way of instantiating the catalog backend classes is to use the
|
||||
`CatalogBuilder`, as illustrated in the
|
||||
[example backend here](https://github.com/backstage/backstage/blob/master/packages/backend/src/plugins/catalog.ts).
|
||||
We will create a new
|
||||
[`CatalogProcessor`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/ingestion/processors/types.ts)
|
||||
[`CatalogProcessor`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/api/processor.ts)
|
||||
subclass that can be added to this catalog builder.
|
||||
|
||||
It is up to you where you put the code for this new processor class. For quick
|
||||
|
||||
@@ -222,6 +222,20 @@ definition.
|
||||
Specifying this annotation will enable GoCD related features in Backstage for
|
||||
that entity.
|
||||
|
||||
### periskop.io/service-name
|
||||
|
||||
```yaml
|
||||
# Example:
|
||||
metadata:
|
||||
annotations:
|
||||
periskop.io/service-name: pump-station
|
||||
```
|
||||
|
||||
The value of this annotation is the periskop project name for the given entity.
|
||||
|
||||
Specifying this annotation will enable [Periskop](https://periskop.io/) related features in Backstage for
|
||||
that entity if the periskop plugin is installed.
|
||||
|
||||
### sentry.io/project-slug
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -94,7 +94,7 @@ for example:
|
||||
catalog:
|
||||
locations:
|
||||
- type: url
|
||||
target: https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml
|
||||
target: https://github.com/backstage/software-templates/blob/main/scaffolder-templates/react-ssr-template/template.yaml
|
||||
rules:
|
||||
- allow: [Template]
|
||||
```
|
||||
|
||||
@@ -15,13 +15,13 @@ A list of all registered actions can be found under `/create/actions`. For local
|
||||
development you should be able to reach them at
|
||||
`http://localhost:3000/create/actions`.
|
||||
|
||||
### Migrating from `fetch:cookiecutter` to `fetch:template`
|
||||
## Migrating from `fetch:cookiecutter` to `fetch:template`
|
||||
|
||||
The `fetch:template` action is a new action with a similar API to
|
||||
`fetch:cookiecutter` but no dependency on `cookiecutter`. There are two options
|
||||
for migrating templates that use `fetch:cookiecutter` to use `fetch:template`:
|
||||
|
||||
#### Using `cookiecutterCompat` mode
|
||||
### Using `cookiecutterCompat` mode
|
||||
|
||||
The new `fetch:template` action has a `cookiecutterCompat` flag which should
|
||||
allow most templates built for `fetch:cookiecutter` to work without any changes.
|
||||
@@ -43,7 +43,7 @@ allow most templates built for `fetch:cookiecutter` to work without any changes.
|
||||
values:
|
||||
```
|
||||
|
||||
#### Manual migration
|
||||
### Manual migration
|
||||
|
||||
If you prefer, you can manually migrate your templates to avoid the need for
|
||||
enabling cookiecutter compatibility mode, which will result in slightly less
|
||||
|
||||
@@ -18,7 +18,7 @@ The next step is to add
|
||||
[add templates](http://backstage.io/docs/features/software-templates/adding-templates)
|
||||
to your Backstage app.
|
||||
|
||||
### Publishing defaults
|
||||
## Publishing defaults
|
||||
|
||||
Software templates can define _publish_ actions, such as `publish:github`, to
|
||||
create new repositories or submit pull / merge requests to existing
|
||||
@@ -45,7 +45,7 @@ add the `repoVisibility` key within a software template:
|
||||
repoVisibility: public # or 'internal' or 'private'
|
||||
```
|
||||
|
||||
### Disabling Docker in Docker situation (Optional)
|
||||
## Disabling Docker in Docker situation (Optional)
|
||||
|
||||
Software templates use the `fetch:template` action by default, which requires no
|
||||
external dependencies and offers a
|
||||
@@ -68,7 +68,7 @@ RUN apt-get update && apt-get install -y python3 python3-pip
|
||||
RUN pip3 install cookiecutter
|
||||
```
|
||||
|
||||
### Customizing the ScaffolderPage with Grouping and Filtering
|
||||
## Customizing the ScaffolderPage with Grouping and Filtering
|
||||
|
||||
Once you have more than a few software templates you may want to customize your
|
||||
`ScaffolderPage` by grouping and surfacing certain templates together. You can
|
||||
|
||||
@@ -15,7 +15,7 @@ locations like GitHub or GitLab.
|
||||
<source src="https://backstage.io/blog/assets/2020-08-05/feature.mp4" type="video/mp4" />
|
||||
</video>
|
||||
|
||||
### Getting Started
|
||||
## Getting Started
|
||||
|
||||
> Be sure to have covered
|
||||
> [Getting Started with Backstage](../../getting-started) before proceeding.
|
||||
@@ -27,7 +27,7 @@ Once there, you should see something that looks similar to this:
|
||||
|
||||

|
||||
|
||||
### Choose a template
|
||||
## Choose a template
|
||||
|
||||
When you select a template that you want to create, you'll be taken to the next
|
||||
page which may or may not look different for each template. Each template can
|
||||
@@ -44,7 +44,7 @@ provider, for instance `https://github.com/backstage/my-new-repository`, or
|
||||
|
||||

|
||||
|
||||
### Run!
|
||||
## Run!
|
||||
|
||||
Once you've entered values and confirmed, you'll then get a popup box with live
|
||||
progress of what is currently happening with the creation of your template.
|
||||
@@ -60,7 +60,7 @@ step that failed which can be helpful in debugging.
|
||||
|
||||

|
||||
|
||||
### View Component in Catalog
|
||||
## View Component in Catalog
|
||||
|
||||
When it's been created, you'll see the `View in Catalog` button, which will take
|
||||
you to the registered component in the catalog:
|
||||
|
||||
@@ -162,6 +162,24 @@ away in future versions and the `RepoUrlPicker` will return an object so
|
||||
`parameters.repoUrl` will already be a
|
||||
`{ host: string; owner: string; repo: string }` 🚀
|
||||
|
||||
## Links should be used instead of named outputs
|
||||
|
||||
Previously, it was possible to provide links to the frontend using the named output `entityRef` and `remoteUrl`.
|
||||
These should be moved to `links` under the `output` object instead.
|
||||
|
||||
```diff
|
||||
output:
|
||||
- remoteUrl: '{{ steps.publish.output.remoteUrl }}'
|
||||
- entityRef: '{{ steps.register.output.entityRef }}'
|
||||
+ links:
|
||||
+ - title: Repository
|
||||
+ url: ${{ steps.publish.output.remoteUrl }}
|
||||
+ - title: Open in catalog
|
||||
+ icon: catalog
|
||||
+ entityRef: ${{ steps.register.output.entityRef }}
|
||||
|
||||
```
|
||||
|
||||
### Summary
|
||||
|
||||
Of course, we're always available on [discord](https://discord.gg/MUpMjP2) if
|
||||
|
||||
@@ -12,7 +12,7 @@ by writing custom actions which can be used along side our
|
||||
> built-in actions too**. To ensure you can continue to include the builtin
|
||||
> actions, see below to include them during registration of your action.
|
||||
|
||||
### Writing your Custom Action
|
||||
## Writing your Custom Action
|
||||
|
||||
Your custom action can live where you choose, but simplest is to include it
|
||||
alongside your `backend` package in `packages/backend`.
|
||||
@@ -79,7 +79,7 @@ The `createTemplateAction` takes an object which specifies the following:
|
||||
function using `ctx.output`
|
||||
- `handler` - the actual code which is run part of the action, with a context
|
||||
|
||||
#### The context object
|
||||
### The context object
|
||||
|
||||
When the action `handler` is called, we provide you a `context` as the only
|
||||
argument. It looks like the following:
|
||||
@@ -98,7 +98,7 @@ argument. It looks like the following:
|
||||
- `ctx.metadata` - an object containing a `name` field, indicating the template
|
||||
name. More metadata fields may be added later.
|
||||
|
||||
### Registering Custom Actions
|
||||
## Registering Custom Actions
|
||||
|
||||
Once you have your Custom Action ready for usage with the scaffolder, you'll
|
||||
need to pass this into the `scaffolder-backend` `createRouter` function. You
|
||||
@@ -145,7 +145,7 @@ return await createRouter({
|
||||
});
|
||||
```
|
||||
|
||||
### List of custom action packages
|
||||
## List of custom action packages
|
||||
|
||||
Here is a list of Open Source custom actions that you can add to your Backstage
|
||||
scaffolder backend:
|
||||
|
||||
@@ -141,7 +141,7 @@ Once it's been passed to the `ScaffolderPage` you should now be able to use the
|
||||
Something like this:
|
||||
|
||||
```yaml
|
||||
apiVersion: backstage.io/v1beta2
|
||||
apiVersion: scaffolder.backstage.io/v1beta3
|
||||
kind: Template
|
||||
metadata:
|
||||
name: Test template
|
||||
|
||||
@@ -99,7 +99,7 @@ spec:
|
||||
|
||||
Let's dive in and pick apart what each of these sections do and what they are.
|
||||
|
||||
### `spec.parameters` - `FormStep | FormStep[]`
|
||||
## `spec.parameters` - `FormStep | FormStep[]`
|
||||
|
||||
These `parameters` are template variables which can be modified in the frontend
|
||||
as a sequence. It can either be one `Step` if you just want one big list of
|
||||
@@ -227,7 +227,7 @@ spec:
|
||||
inputType: tel
|
||||
```
|
||||
|
||||
#### Hide or mask sensitive data on Review step
|
||||
### Hide or mask sensitive data on Review step
|
||||
|
||||
Sometimes, specially in custom fields, you collect some data on Create form that
|
||||
must not be shown to the user on Review step. To hide or mask this data, you can
|
||||
@@ -254,7 +254,7 @@ use `ui:widget: password` or set some properties of `ui:backstage`:
|
||||
show: false # wont print any info about 'hidden' property on Review Step
|
||||
```
|
||||
|
||||
#### The Repository Picker
|
||||
### The Repository Picker
|
||||
|
||||
In order to make working with repository providers easier, we've built a custom
|
||||
picker that can be used by overriding the `ui:field` option in the `uiSchema`
|
||||
@@ -287,7 +287,7 @@ The `RepoUrlPicker` is a custom field that we provide part of the
|
||||
`plugin-scaffolder`. You can provide your own custom fields by
|
||||
[writing your own Custom Field Extensions](./writing-custom-field-extensions.md)
|
||||
|
||||
##### Using the Users `oauth` token
|
||||
#### Using the Users `oauth` token
|
||||
|
||||
There's a little bit of extra magic that you get out of the box when using the
|
||||
`RepoUrlPicker` as a field input. You can provide some additional options under
|
||||
@@ -360,7 +360,7 @@ There's also the ability to pass additional scopes when requesting the `oauth`
|
||||
token from the user, which you can do on a per-provider basis, in case your
|
||||
template can be published to multiple providers.
|
||||
|
||||
#### The Owner Picker
|
||||
### The Owner Picker
|
||||
|
||||
When the scaffolder needs to add new components to the catalog, it needs to have
|
||||
an owner for them. Ideally, users should be able to select an owner when they go
|
||||
@@ -380,7 +380,7 @@ owner:
|
||||
- Group
|
||||
```
|
||||
|
||||
### `spec.steps` - `Action[]`
|
||||
## `spec.steps` - `Action[]`
|
||||
|
||||
The `steps` is an array of the things that you want to happen part of this
|
||||
template. These follow the same standard format:
|
||||
@@ -400,7 +400,7 @@ By default we ship some [built in actions](./builtin-actions.md) that you can
|
||||
take a look at, or you can
|
||||
[create your own custom actions](./writing-custom-actions.md).
|
||||
|
||||
### Outputs
|
||||
## Outputs
|
||||
|
||||
Each individual step can output some variables that can be used in the
|
||||
scaffolder frontend for after the job is finished. This is useful for things
|
||||
@@ -415,7 +415,7 @@ output:
|
||||
entityRef: ${{ steps.register.output.entityRef }} # link to the entity that has been ingested to the catalog
|
||||
```
|
||||
|
||||
### The templating syntax
|
||||
## The templating syntax
|
||||
|
||||
You might have noticed variables wrapped in `${{ }}` in the examples. These are
|
||||
template strings for linking and gluing the different parts of the template
|
||||
|
||||
@@ -97,7 +97,7 @@ techdocs-cli generate
|
||||
Alias: `techdocs-cli build`
|
||||
|
||||
The generate command uses the
|
||||
[`@backstage/techdocs-common`](https://github.com/backstage/backstage/tree/master/packages/techdocs-common)
|
||||
[`@backstage/plugin-techdocs-node`](https://github.com/backstage/backstage/tree/master/plugins/techdocs-node)
|
||||
package from Backstage for consistency. A Backstage app can also generate and
|
||||
publish TechDocs sites if `techdocs.builder` is set to `'local'` in
|
||||
`app-config.yaml`. See
|
||||
@@ -130,6 +130,8 @@ Options:
|
||||
if not found.
|
||||
--etag <ETAG> A unique identifier for the prepared tree e.g. commit SHA. If provided it will be stored
|
||||
in techdocs_metadata.json.
|
||||
--omitTechdocsCoreMkdocsPlugin An option to disable automatic addition of techdocs-core plugin to the mkdocs.yaml files.
|
||||
Defaults to false, which means that the techdocs-core plugin is always added to the mkdocs file.
|
||||
-v --verbose Enable verbose output. (default: false)
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
@@ -46,6 +46,24 @@ between `techdocs-backend` and the storage)
|
||||
|
||||
[TechDocs Backend](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend)
|
||||
|
||||
## TechDocs Build Strategy
|
||||
|
||||
To accommodate more complex logic surrounding whether or not to build TechDocs, the TechDocs backend
|
||||
supports selecting a Build Strategy.
|
||||
The Build Strategy is responsible for deciding whether the documentation requested should be built locally
|
||||
by the TechDocs backend or not.
|
||||
Customization of the Build Strategy allows for more complex behaviour regarding whether the TechDocs backend
|
||||
is responsible for building TechDocs, whether an external process is responsible, or whether a combination
|
||||
of local builds and an external process is responsible, on an entity-by-entity basis.
|
||||
|
||||
The default Build Strategy results in the TechDocs backend building documentation locally if the
|
||||
`techdocs.builder` configuration option is set to `'local'`, and skipping any building otherwise.
|
||||
However any logic that satisfies the Build Strategy interface can be implemented, using the Backstage
|
||||
config as well as the entity being processed to make a decision.
|
||||
|
||||
For an example of how the Build Strategy can be used to implement a 'hybrid' build model, refer to
|
||||
the [How to implement a hybrid build strategy](./how-to-guides.md#how-to-implement-a-hybrid-build-strategy) guide.
|
||||
|
||||
## TechDocs Container
|
||||
|
||||
The TechDocs container is a Docker container available at
|
||||
|
||||
@@ -37,12 +37,22 @@ techdocs:
|
||||
|
||||
pullImage: true
|
||||
|
||||
mkdocs:
|
||||
# (Optional) techdocs.generator.omitTechdocsCoreMkdocsPlugin can be used to disable automatic addition of techdocs-core plugin to the mkdocs.yaml files.
|
||||
# Defaults to false, which means that the techdocs-core plugin is always added to the mkdocs file.
|
||||
omitTechdocsCorePlugin: false
|
||||
|
||||
# techdocs.builder can be either 'local' or 'external.
|
||||
# If builder is set to 'local' and you open a TechDocs page, techdocs-backend will try to generate the docs, publish to storage
|
||||
# and show the generated docs afterwords. This is the "Basic" setup of the TechDocs Architecture.
|
||||
# If builder is set to 'external', techdocs-backend will only fetch the docs and will NOT try to generate and publish. In this case of 'external',
|
||||
# we assume that docs are being built by an external process (e.g. in the CI/CD pipeline of the repository). This is the "Recommended" setup of
|
||||
# the architecture. Read more here https://backstage.io/docs/features/techdocs/architecture
|
||||
# Using the default build strategy, if builder is set to 'local' and you open a TechDocs page,
|
||||
# techdocs-backend will try to generate the docs, publish to storage and show the generated docs afterwords.
|
||||
# This is the "Basic" setup of the TechDocs Architecture.
|
||||
# Using the default build strategy, if builder is set to 'external' (or anything other than 'local'), techdocs-backend
|
||||
# will only fetch the docs and will NOT try to generate and publish.
|
||||
# In this case, we assume that docs are being built by an external process (e.g. in the CI/CD pipeline of the repository).
|
||||
# This is the "Recommended" setup of the architecture.
|
||||
# Note that custom build strategies may alter this behaviour.
|
||||
# Read more about the "Basic" and "Recommended" setups here https://backstage.io/docs/features/techdocs/architecture
|
||||
# Read more about build strategies here: https://backstage.io/docs/features/techdocs/concepts#techdocs-build-strategy
|
||||
|
||||
builder: 'local'
|
||||
|
||||
|
||||
@@ -79,6 +79,9 @@ plugins:
|
||||
- techdocs-core
|
||||
```
|
||||
|
||||
> Note - The plugins section above is optional. Backstage automatically adds the `techdocs-core` plugin to the
|
||||
> mkdocs file if it is missing. This functionality can be turned off with a [configuration option](./configuration.md) in Backstage.
|
||||
|
||||
Update your component's entity description by adding the following lines to its
|
||||
`catalog-info.yaml` in the root of its repository:
|
||||
|
||||
|
||||
@@ -538,3 +538,58 @@ Done! Now you have a support of the following diagrams along with mermaid:
|
||||
- `Vega`
|
||||
- `Vega-Lite`
|
||||
- `WaveDrom`
|
||||
|
||||
## How to implement a hybrid build strategy
|
||||
|
||||
One limitation of the [Recommended deployment](./architecture.md#recommended-deployment) is that
|
||||
the experience for users requires modifying their CI/CD process to publish
|
||||
their TechDocs. For some users, this may be unnecessary, and provides a barrier
|
||||
to entry for onboarding users to Backstage. However, a purely local TechDocs
|
||||
build restricts TechDocs creators to using the tooling provided in Backstage,
|
||||
as well as the plugins and features provided in the Backstage-included `mkdocs`
|
||||
installation.
|
||||
|
||||
To accommodate both of these use-cases, users can implement a custom [Build Strategy](./concepts.md#techdocs-build-strategy)
|
||||
with logic to encode which TechDocs should be built locally, and which will be
|
||||
built externally.
|
||||
|
||||
To achieve this hybrid build model:
|
||||
|
||||
1. In your Backstage instance's `app-config.yaml`, set `techdocs.builder` to
|
||||
`'local'`. This ensures that Backstage will build docs for users who want the
|
||||
'out-of-the-box' experience.
|
||||
2. Configure external storage of TechDocs as normal for a production deployment.
|
||||
This allows Backstage to publish documentation to your storage, as well as
|
||||
allowing other users to publish documentation from their CI/CD pipelines.
|
||||
3. Create a custom build strategy, that implements the `DocsBuildStrategy` interface,
|
||||
and which implements your custom logic for determining whether to build docs for
|
||||
a given entity.
|
||||
For example, to only build docs when an entity has the `company.com/techdocs-builder`
|
||||
annotation set to `'local'`:
|
||||
|
||||
```typescript
|
||||
export class AnnotationBasedBuildStrategy {
|
||||
private readonly config: Config;
|
||||
|
||||
constructor(config: Config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
async shouldBuild(_: Entity): Promise<boolean> {
|
||||
return (
|
||||
this.entity.metadata?.annotations?.['company.com/techdocs-builder'] ===
|
||||
'local'
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. Pass an instance of this Build Strategy as the `docsBuildStrategy` parameter of the
|
||||
TechDocs backend `createRouter` method.
|
||||
|
||||
Users should now be able to choose to have their documentation built and published by
|
||||
the TechDocs backend by adding the `company.com/techdocs-builder` annotation to their
|
||||
entity. If the value of this annotation is `'local'`, the TechDocs backend will build
|
||||
and publish the documentation for them. If the value of the `company.com/techdocs-builder`
|
||||
annotation is anything other than `'local'`, the user is responsible for publishing
|
||||
documentation to the appropriate location in the TechDocs external storage.
|
||||
|
||||
@@ -57,6 +57,7 @@ done like this:
|
||||
import { createApp } from '@backstage/app-defaults';
|
||||
import { ThemeProvider } from '@material-ui/core/styles';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import LightIcon from '@material-ui/icons/WbSunny';
|
||||
|
||||
const app = createApp({
|
||||
apis: ...,
|
||||
@@ -65,6 +66,7 @@ const app = createApp({
|
||||
id: 'my-theme',
|
||||
title: 'My Custom Theme',
|
||||
variant: 'light',
|
||||
icon: <LightIcon />,
|
||||
Provider: ({ children }) => (
|
||||
<ThemeProvider theme={myTheme}>
|
||||
<CssBaseline>{children}</CssBaseline>
|
||||
|
||||
@@ -133,9 +133,9 @@ familiar with. For other options, see
|
||||
Go to
|
||||
[https://github.com/settings/applications/new](https://github.com/settings/applications/new)
|
||||
to create your OAuth App. The `Homepage URL` should point to Backstage's
|
||||
frontend, in our tutorial it would be `http://127.0.0.1:3000`. The
|
||||
frontend, in our tutorial it would be `http://localhost:3000`. The
|
||||
`Authorization callback URL` will point to the auth backend, which will most
|
||||
likely be `http://127.0.0.1:7007/api/auth/github/handler/frame`.
|
||||
likely be `http://localhost:7007/api/auth/github/handler/frame`.
|
||||
|
||||
<p align='center'>
|
||||
<img src='../assets/getting-started/gh-oauth.png' alt='Screenshot of the GitHub OAuth creation page' />
|
||||
|
||||
@@ -160,8 +160,8 @@ are separated out into their own folder, see further down.
|
||||
reusable React components. Stories are within the core package, and are
|
||||
published in the [Backstage Storybook](https://backstage.io/storybook).
|
||||
|
||||
- [`techdocs-common/`](https://github.com/backstage/backstage/tree/master/packages/techdocs-common) -
|
||||
Common functionalities for TechDocs, to be shared between
|
||||
- [`techdocs-node/`](https://github.com/backstage/backstage/tree/master/plugins/techdocs-node) -
|
||||
Common node.js functionalities for TechDocs, to be shared between
|
||||
[techdocs-backend](https://github.com/backstage/backstage/tree/master/plugins/techdocs-backend)
|
||||
plugin and [techdocs-cli](https://github.com/backstage/techdocs-cli).
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ Once you've done that, you'll also need to add the segment below to `packages/ba
|
||||
```ts
|
||||
/* packages/backend/src/plugins/catalog.ts */
|
||||
|
||||
import { AwsS3DiscoveryProcessor } from '@backstage/plugin-catalog-backend';
|
||||
import { AwsS3DiscoveryProcessor } from '@backstage/plugin-catalog-backend-module-aws';
|
||||
|
||||
const builder = await CatalogBuilder.create(env);
|
||||
/** ... other processors ... */
|
||||
|
||||
@@ -80,6 +80,18 @@ The target is composed of the following parts:
|
||||
reduce the amount of API calls if you have a large workspace.
|
||||
[See here for the specification](https://developer.atlassian.com/bitbucket/api/2/reference/meta/filtering)
|
||||
for the query argument (will be passed as the `q` query parameter).
|
||||
- (Optional) The `search=true` query argument to activate the mode utilizing code search.
|
||||
- Is mutually exclusive to the `q` query argument.
|
||||
- Allows providing values at `catalogPath` for finding catalog files as allowed by the `path` filter/modifier
|
||||
[at Bitbucket Cloud's code search](https://confluence.atlassian.com/bitbucket/code-search-in-bitbucket-873876782.html#Search-Pathmodifier).
|
||||
- `catalogPath=/catalog-info.yaml`
|
||||
- `catalogPath=catalog-info.yaml` (anywhere in the repository)
|
||||
- `catalogPath=/path/catalog-info.yaml`
|
||||
- `catalogPath=path/catalog-info.yaml`
|
||||
- `catalogPath=/path/*/catalog-info.yaml`
|
||||
- `catalogPath=path/*/catalog-info.yaml`
|
||||
- Supports multiple catalog files per repository depending on the `catalogPath` value.
|
||||
- Registers `Location` entities for existing files only vs all matching repositories.
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -95,6 +107,23 @@ Examples:
|
||||
- `https://bitbucket.org/workspaces/my-workspace?catalogPath=my/nested/path/catalog.yaml`
|
||||
will find all repositories in the `my-workspace` workspace and use the catalog
|
||||
file at `my/nested/path/catalog.yaml`.
|
||||
- `https://bitbucket.org/workspaces/my-workspace?search=true&catalogPath=/catalog.yaml`
|
||||
will find all `catalog.yaml` files located in the root of repositories in the workspace `my-workspace`.
|
||||
- `https://bitbucket.org/workspaces/my-workspace?search=true&catalogPath=catalog.yaml`
|
||||
will find all `catalog.yaml` files located anywhere within repositories in the workspace `my-workspace`.
|
||||
- `https://bitbucket.org/workspaces/my-workspace?search=true&catalogPath=/my/nested/path/catalog.yaml`
|
||||
will find all `catalog.yaml` files located within the directory `/my/nested/path/` within
|
||||
repositories in the workspace `my-workspace`.
|
||||
- `https://bitbucket.org/workspaces/my-workspace?search=true&catalogPath=my/nested/path/catalog.yaml`
|
||||
will find all `catalog.yaml` files located within the directory `my/nested/path/` located anywhere within
|
||||
repositories in the workspace `my-workspace`.
|
||||
- `https://bitbucket.org/workspaces/my-workspace?search=true&catalogPath=/my/*/path/catalog.yaml`
|
||||
will find all `catalog.yaml` files located within a directory `path/` located within any (recursive) directory
|
||||
within the directory `my/` in the root of repositories in the workspace `my-workspace`
|
||||
(`/my/nested/path/catalog.yaml`, `/my/very/nested/path/catalog.yaml`, ...).
|
||||
- `https://bitbucket.org/workspaces/my-workspace/projects/apis-*/repos/service-*?search=true&catalogPath=catalog.yaml`
|
||||
will find all `catalog.yaml` files located anywhere within repositories starting with `service-`
|
||||
in projects starting with `api-` in the workspace `my-workspace`.
|
||||
|
||||
## Custom repository processing
|
||||
|
||||
|
||||
@@ -34,3 +34,19 @@ The target is composed of three parts:
|
||||
a similar variation for catalog files stored in the root directory of each
|
||||
repository. If you want to use the repository's default branch use the `*`
|
||||
wildcard, e.g.: `/blob/*/catalog-info.yaml`
|
||||
|
||||
Finally, you will have to add the processor in the catalog initialization code
|
||||
of your backend.
|
||||
|
||||
```diff
|
||||
// In packages/backend/src/plugins/catalog.ts
|
||||
+import { GitLabDiscoveryProcessor } from '@backstage/plugin-catalog-backend-module-gitlab';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
const builder = await CatalogBuilder.create(env);
|
||||
+ builder.addProcessor(
|
||||
+ GitLabDiscoveryProcessor.fromConfig(env.config, { logger: env.logger })
|
||||
+ );
|
||||
```
|
||||
|
||||
+119
-127
@@ -14,9 +14,11 @@ entities that mirror your org setup.
|
||||
|
||||
## Installation
|
||||
|
||||
1. The processor is not installed by default, therefore you have to add a
|
||||
dependency to `@backstage/plugin-catalog-backend-module-ldap` to your backend
|
||||
package.
|
||||
This guide will use the Entity Provider method. If you for some reason prefer
|
||||
the Processor method (not recommended), it is described separately below.
|
||||
|
||||
The provider is not installed by default, therefore you have to add a dependency
|
||||
to `@backstage/plugin-catalog-backend-module-ldap` to your backend package.
|
||||
|
||||
```bash
|
||||
# From your Backstage root directory
|
||||
@@ -24,63 +26,73 @@ cd packages/backend
|
||||
yarn add @backstage/plugin-catalog-backend-module-ldap
|
||||
```
|
||||
|
||||
2. The `LdapOrgReaderProcessor` is not registered by default, so you have to
|
||||
register it in the catalog plugin:
|
||||
> Note: When configuring to use a Provider instead of a Processor you do not
|
||||
> need to add a _location_ pointing to your LDAP server
|
||||
|
||||
```typescript
|
||||
// packages/backend/src/plugins/catalog.ts
|
||||
builder.addProcessor(
|
||||
LdapOrgReaderProcessor.fromConfig(env.config, {
|
||||
logger: env.logger,
|
||||
}),
|
||||
);
|
||||
Update the catalog plugin initialization in your backend to add the provider and
|
||||
schedule it:
|
||||
|
||||
```diff
|
||||
// packages/backend/src/plugins/catalog.ts
|
||||
+import { Duration } from 'luxon';
|
||||
+import { LdapOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-ldap';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
const builder = await CatalogBuilder.create(env);
|
||||
|
||||
+ // The target parameter below needs to match the ldap.providers.target
|
||||
+ // value specified in your app-config.
|
||||
+ builder.addEntityProvider(
|
||||
+ LdapOrgEntityProvider.fromConfig(env.config, {
|
||||
+ id: 'our-ldap-master',
|
||||
+ target: 'ldaps://ds.example.net',
|
||||
+ logger: env.logger,
|
||||
+ schedule: env.scheduler.createScheduledTaskRunner({
|
||||
+ frequency: Duration.fromObject({ minutes: 60 }),
|
||||
+ timeout: Duration.fromObject({ minutes: 15 }),
|
||||
+ }),
|
||||
+ }),
|
||||
+ );
|
||||
```
|
||||
|
||||
After this, you also have to add some configuration in your app-config that
|
||||
describes what you want to import for that target.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following configuration is a small example of how a setup could look for
|
||||
importing groups and users from a corporate LDAP server.
|
||||
|
||||
```yaml
|
||||
catalog:
|
||||
locations:
|
||||
- type: ldap-org
|
||||
target: ldaps://ds.example.net
|
||||
processors:
|
||||
ldapOrg:
|
||||
providers:
|
||||
- target: ldaps://ds.example.net
|
||||
bind:
|
||||
dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net
|
||||
secret: ${LDAP_SECRET}
|
||||
users:
|
||||
dn: ou=people,ou=example,dc=example,dc=net
|
||||
options:
|
||||
filter: (uid=*)
|
||||
map:
|
||||
description: l
|
||||
set:
|
||||
metadata.customField: 'hello'
|
||||
groups:
|
||||
dn: ou=access,ou=groups,ou=example,dc=example,dc=net
|
||||
options:
|
||||
filter: (&(objectClass=some-group-class)(!(groupType=email)))
|
||||
map:
|
||||
description: l
|
||||
set:
|
||||
metadata.customField: 'hello'
|
||||
ldap:
|
||||
providers:
|
||||
- target: ldaps://ds.example.net
|
||||
bind:
|
||||
dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net
|
||||
secret: ${LDAP_SECRET}
|
||||
users:
|
||||
dn: ou=people,ou=example,dc=example,dc=net
|
||||
options:
|
||||
filter: (uid=*)
|
||||
map:
|
||||
description: l
|
||||
set:
|
||||
metadata.customField: 'hello'
|
||||
groups:
|
||||
dn: ou=access,ou=groups,ou=example,dc=example,dc=net
|
||||
options:
|
||||
filter: (&(objectClass=some-group-class)(!(groupType=email)))
|
||||
map:
|
||||
description: l
|
||||
set:
|
||||
metadata.customField: 'hello'
|
||||
```
|
||||
|
||||
Locations point out the specific org(s) you want to import. The `type` of these
|
||||
locations must be `ldap-org`, and the `target` must point to the exact URL
|
||||
(starting with `ldap://` or `ldaps://`) of the targeted LDAP server. You can
|
||||
have several such location entries if you want, but typically you will have just
|
||||
one.
|
||||
|
||||
The processor itself is configured in the other block, under
|
||||
`catalog.processors.ldapOrg`. There may be many providers, each targeting a
|
||||
specific `target` which is supposed to be on the same form as the location
|
||||
`target`.
|
||||
There may be many providers, each targeting a specific `target` which is
|
||||
supposed to match the `target` of a dedicated provider instance - i.e., you will
|
||||
add one entity provider class instance per target to ingest from.
|
||||
|
||||
These config blocks have a lot of options in them, so we will describe each
|
||||
"root" key within the block separately.
|
||||
@@ -163,7 +175,7 @@ below, with their default values, but they are all optional.
|
||||
|
||||
If you leave out an optional mapping, it will still be copied using that default
|
||||
value. For example, even if you do not put in the field `displayName` in your
|
||||
config, the processor will still copy the attribute `cn` into the entity field
|
||||
config, the provider will still copy the attribute `cn` into the entity field
|
||||
`spec.profile.displayName`.
|
||||
|
||||
```yaml
|
||||
@@ -245,7 +257,7 @@ shown below, with their default values, but they are all optional.
|
||||
|
||||
If you leave out an optional mapping, it will still be copied using that default
|
||||
value. For example, even if you do not put in the field `displayName` in your
|
||||
config, the processor will still copy the attribute `cn` into the entity field
|
||||
config, the provider will still copy the attribute `cn` into the entity field
|
||||
`spec.profile.displayName`. If the target field is optional, such as the display
|
||||
name, the importer will accept missing attributes and just leave the target
|
||||
field unset. If the target field is mandatory, such as the name of the entity,
|
||||
@@ -283,94 +295,74 @@ map:
|
||||
members: member
|
||||
```
|
||||
|
||||
## Customize the Processor
|
||||
## Customize the Provider
|
||||
|
||||
In case you want to customize the ingested entities, the
|
||||
`LdapOrgReaderProcessor` allows to pass transformers for users and groups.
|
||||
In case you want to customize the ingested entities, the provider allows to pass
|
||||
transformers for users and groups. Here we will show an example of overriding
|
||||
the group transformer.
|
||||
|
||||
1. Create a transformer:
|
||||
|
||||
```ts
|
||||
export async function myGroupTransformer(
|
||||
vendor: LdapVendor,
|
||||
config: GroupConfig,
|
||||
group: SearchEntry,
|
||||
): Promise<GroupEntity | undefined> {
|
||||
// Transformations may change namespace, change entity naming pattern, fill
|
||||
// profile with more or other details...
|
||||
```ts
|
||||
export async function myGroupTransformer(
|
||||
vendor: LdapVendor,
|
||||
config: GroupConfig,
|
||||
group: SearchEntry,
|
||||
): Promise<GroupEntity | undefined> {
|
||||
// Transformations may change namespace, change entity naming pattern, fill
|
||||
// profile with more or other details...
|
||||
|
||||
// Create the group entity on your own, or wrap the default transformer
|
||||
return await defaultGroupTransformer(vendor, config, group);
|
||||
}
|
||||
```
|
||||
// Create the group entity on your own, or wrap the default transformer
|
||||
return await defaultGroupTransformer(vendor, config, group);
|
||||
}
|
||||
```
|
||||
|
||||
2. Configure the processor with the transformer:
|
||||
2. Configure the provider with the transformer:
|
||||
|
||||
```ts
|
||||
```ts
|
||||
const ldapEntityProvider = LdapOrgEntityProvider.fromConfig(env.config, {
|
||||
id: 'our-ldap-master',
|
||||
target: 'ldaps://ds.example.net',
|
||||
logger: env.logger,
|
||||
groupTransformer: myGroupTransformer,
|
||||
});
|
||||
```
|
||||
|
||||
## Using a Processor instead of a Provider
|
||||
|
||||
An alternative to using the Provider for ingesting LDAP entries is to use a
|
||||
Processor. This is the old way that's based on registering locations with the
|
||||
proper type and target, triggering the processor to run.
|
||||
|
||||
The drawback of this method is that it will leave orphaned Group/User entities
|
||||
whenever they are deleted on your LDAP server, and you cannot control the
|
||||
frequency with which they are refreshed, separately from other processors.
|
||||
|
||||
### Processor Installation
|
||||
|
||||
The `LdapOrgReaderProcessor` is not registered by default, so you have to
|
||||
register it in the catalog plugin:
|
||||
|
||||
```typescript
|
||||
// packages/backend/src/plugins/catalog.ts
|
||||
builder.addProcessor(
|
||||
LdapOrgReaderProcessor.fromConfig(config, {
|
||||
logger,
|
||||
groupTransformer: myGroupTransformer,
|
||||
LdapOrgReaderProcessor.fromConfig(env.config, {
|
||||
logger: env.logger,
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
## Using a Provider instead of a Processor
|
||||
### Driving LDAP Org Processor Ingestion with Locations
|
||||
|
||||
An alternative to using the Processor for ingesting LDAP entries is to use a
|
||||
Provider. Doing this can give you a little bit more freedom to handle the LDAP
|
||||
ingestion more independently from the rest of the catalog ingestion.
|
||||
Locations point out the specific org(s) you want to import. The `type` of these
|
||||
locations must be `ldap-org`, and the `target` must point to the exact URL
|
||||
(starting with `ldap://` or `ldaps://`) of the targeted LDAP server. You can
|
||||
have several such location entries if you want, but typically you will have just
|
||||
one.
|
||||
|
||||
This can be useful if you have a lot of Users and Groups and hitting your LDAP
|
||||
server is resource intensive but you still want your other catalog entries to be
|
||||
updated frequently.
|
||||
|
||||
> Note: When configuring to use a Provider instead of a Processor you do not
|
||||
> need to add a _location_ pointing to your LDAP server
|
||||
|
||||
```ts
|
||||
// packages/backend/src/plugins/catalog.ts
|
||||
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
import { Router } from 'express';
|
||||
import { LdapOrgEntityProvider } from '@backstage/plugin-catalog-backend-module-ldap';
|
||||
|
||||
import { Duration } from 'luxon';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
const ldapEntityProvider = LdapOrgEntityProvider.fromConfig(env.config, {
|
||||
id: 'custom-ldap',
|
||||
// target needs to match the catalog.processors.ldapOrg.providers.target specified in app-config
|
||||
target: 'ldaps://ds.example.net',
|
||||
logger: env.logger,
|
||||
});
|
||||
|
||||
const builder = await CatalogBuilder.create(env);
|
||||
builder.addEntityProvider(ldapEntityProvider);
|
||||
|
||||
// You can change the refresh interval for the other catalog entries independently, or just leave the line below out to use the default refresh interval
|
||||
builder.setRefreshIntervalSeconds(100);
|
||||
|
||||
const { processingEngine, router } = await builder.build();
|
||||
await processingEngine.start();
|
||||
|
||||
await env.scheduler.scheduleTask({
|
||||
id: 'refresh_ldap',
|
||||
// frequency sets how often you want to ingest users and groups from LDAP, in this case every 60 minutes
|
||||
frequency: Duration.fromObject({ minutes: 60 }),
|
||||
timeout: Duration.fromObject({ minutes: 15 }),
|
||||
fn: async () => {
|
||||
try {
|
||||
await ldapEntityProvider.read();
|
||||
} catch (error) {
|
||||
env.logger.error(error);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
```yaml
|
||||
catalog:
|
||||
locations:
|
||||
- type: ldap-org
|
||||
target: ldaps://ds.example.net
|
||||
```
|
||||
|
||||
@@ -72,6 +72,53 @@ or IDE that has support for formatting, linting, and type checking.
|
||||
Let's dive into a detailed look at each of these steps and how they are
|
||||
implemented in a typical Backstage app.
|
||||
|
||||
## Package Roles
|
||||
|
||||
> Package roles were introduced in March 2022. To migrate existing projects, see the [migration guide](../tutorials/package-role-migration.md).
|
||||
|
||||
The Backstage build system uses the concept of package roles in order to help keep
|
||||
configuration lean, provide utility and tooling, and enable optimizations. A package
|
||||
role is a single string that identifies what the purpose of a package is, and it's
|
||||
defined in the `package.json` of each package like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-package",
|
||||
"backstage": {
|
||||
"role": "<role>"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
These are the available roles that are currently supported by the Backstage build system:
|
||||
|
||||
| Role | Description | Example |
|
||||
| ---------------------- | -------------------------------------------- | -------------------------------------------- |
|
||||
| frontend | Bundled frontend application | `package/app` |
|
||||
| backend | Bundled backend application | `packages/backend` |
|
||||
| cli | Package used as a command-line interface | `@backstage/cli`, `@backstage/codemods` |
|
||||
| web-library | Web library for use by other packages | `@backstage/plugin-catalog-react` |
|
||||
| node-library | Node.js library for use by other packages | `@backstage/plugin-techdocs-node` |
|
||||
| common-library | Isomorphic library for use by other packages | `@backstage/plugin-permission-common` |
|
||||
| frontend-plugin | Backstage frontend plugin | `@backstage/plugin-scaffolder` |
|
||||
| frontend-plugin-module | Backstage frontend plugin module | `@backstage/plugin-analytics-module-ga` |
|
||||
| backend-plugin | Backstage backend plugin | `@backstage/plugin-auth-backend` |
|
||||
| backend-plugin-module | Backstage backend plugin module | `@backstage/plugin-search-backend-module-pg` |
|
||||
|
||||
Most of the steps that we cover below have an accompanying command that is intended to be used as a package script. The commands are all available under the `backstage-cli package` category, and many of the commands will behave differently depending on the role of the package. The commands are intended to be used like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Formatting
|
||||
|
||||
The formatting setup lives completely within each Backstage application and is
|
||||
@@ -96,9 +143,38 @@ configurations in turn build on top of the lint rules from
|
||||
|
||||
In a standard Backstage setup, each individual package has its own lint
|
||||
configuration, along with a root configuration that applies to the entire
|
||||
project. Each configuration is initially one that simply extends a base
|
||||
configuration provided by the Backstage CLI, but they can be customized to fit
|
||||
the needs of each package.
|
||||
project. The configuration in each package starts out as a standard configuration
|
||||
that is determined based on the package role, but it can be customized to fit the needs of each package.
|
||||
|
||||
A minimal `.eslintrc.js` configuration now looks like this:
|
||||
|
||||
```js
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
```
|
||||
|
||||
But you can provide custom overrides for each package using the optional second argument:
|
||||
|
||||
```js
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
ignorePatterns: ['templates/'],
|
||||
rules: {
|
||||
'jest/expect-expect': 'off',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The configuration factory also provides utilities for extending the configuration in ways that are otherwise very cumbersome to do with plain ESLint, particularly for rules like `no-restricted-syntax`. These are the extra keys that are available:
|
||||
|
||||
| Key | Description |
|
||||
| ----------------------- | ------------------------------------------------------------------ |
|
||||
| `tsRules` | Additional rules to apply to TypeScript files |
|
||||
| `testRules` | Additional rules to apply to tests files |
|
||||
| `restrictedImports` | Additional paths to add to `no-restricted-imports` |
|
||||
| `restrictedSrcImports` | Additional paths to add to `no-restricted-imports` in src files |
|
||||
| `restrictedTestImports` | Additional paths to add to `no-restricted-imports` in test files |
|
||||
| `restrictedSyntax` | Additional patterns to add to `no-restricted-syntax` |
|
||||
| `restrictedSrcSyntax` | Additional patterns to add to `no-restricted-syntax` in src files |
|
||||
| `restrictedTestSyntax` | Additional patterns to add to `no-restricted-syntax` in test files |
|
||||
|
||||
## Type Checking
|
||||
|
||||
@@ -167,11 +243,8 @@ nevertheless be useful to know how it works, since all of the published
|
||||
Backstage packages are built using this process.
|
||||
|
||||
The build is currently using [Rollup](https://rollupjs.org/) and executes in
|
||||
isolation for each individual package. There are currently three different
|
||||
commands in the Backstage CLI that invokes the build process, `plugin:build`,
|
||||
`backend:build`, and simply `build`. The two former are pre-configured commands
|
||||
for frontend and backend plugins, while the `build` command provides more
|
||||
control over the output.
|
||||
isolation for each individual package. The build is invoked using the `package build`
|
||||
command, and applies to all packages roles except the bundled ones, `frontend` and `backend`.
|
||||
|
||||
There are three different possible outputs of the build process: JavaScript in
|
||||
CommonJS module format, JavaScript in ECMAScript module format, and type
|
||||
@@ -181,12 +254,10 @@ files like stylesheets or images. For more details on what syntax and file
|
||||
formats are supported by the build process, see the [loaders section](#loaders).
|
||||
|
||||
When building CommonJS or ESM output, the build commands will always use
|
||||
`src/index.ts` as the entrypoint. All dependencies of the package will be marked
|
||||
as external, meaning that in general it is only the contents of the `src` folder
|
||||
that ends up being compiled and output to `dist`. All import statements of
|
||||
external dependencies, even within the same monorepo, will stay intact. The
|
||||
externalized dependencies are based on dependency information in `package.json`,
|
||||
which means it's important to keep it up to date.
|
||||
`src/index.ts` as the entrypoint. All non-relative modules imports are considered
|
||||
external, meaning the Rollup build will only compile the source code of the package
|
||||
itself. All import statements of external dependencies, even within the same
|
||||
monorepo, will stay intact.
|
||||
|
||||
The build of the type definitions works quite differently. The entrypoint of the
|
||||
type definition build is the relative location of the package within the
|
||||
@@ -207,11 +278,11 @@ cover each combination of these cases separately.
|
||||
|
||||
### Frontend Development
|
||||
|
||||
There are two different commands that start the frontend development bundling:
|
||||
`app:serve`, which serves an app and uses `src/index` as the entrypoint, and
|
||||
`plugin:serve`, which serves a plugin and uses `dev/index` as the entrypoint.
|
||||
These are typically invoked via the `yarn start` script, and are intended for
|
||||
local development only. When running the bundle command, a development server
|
||||
The frontend development setup is used for all packages with a frontend role, and
|
||||
is invoked using the `package start` command.
|
||||
The only difference between the different roles is that packages with the `'frontend'`
|
||||
role use `src/index` as the entrypoint, while other roles instead use `dev/index`.
|
||||
When running the start command, a development server
|
||||
will be set up that listens to the protocol, host and port set by `app.baseUrl`
|
||||
in the configuration. If needed it is also possible to override the listening
|
||||
options through the `app.listen` configuration.
|
||||
@@ -235,8 +306,8 @@ support for them instead.
|
||||
### Frontend Production
|
||||
|
||||
The frontend production bundling creates your typical web content bundle, all
|
||||
contained within a single folder, ready for static serving. It is invoked using
|
||||
the `app:build` command, and unlike the development bundling there is no way to
|
||||
contained within a single folder, ready for static serving. It is used when building
|
||||
packages with the `'frontend'` role, and unlike the development bundling there is no way to
|
||||
build a production bundle of an individual plugin. The output of the bundling
|
||||
process is written to the `dist` folder in the package.
|
||||
|
||||
@@ -255,13 +326,25 @@ correctly from linked in packages, the `ModuleScopePlugin` from
|
||||
[`react-dev-utils`](https://www.npmjs.com/package/react-dev-utils) which makes
|
||||
sure that imports don't reach outside the package, a few fallbacks for some
|
||||
Node.js modules like `'buffer'` and `'events'`, a plugin that writes the
|
||||
frontend configuration to the bundle as `process.env.APP_CONFIG` and build
|
||||
information as `process.env.BUILD_INFO`, and lastly minification handled by
|
||||
frontend configuration to the bundle as `process.env.APP_CONFIG`, and lastly minification handled by
|
||||
[esbuild](https://esbuild.github.io/) using the
|
||||
[`esbuild-loader`](https://npm.im/esbuild-loader). There are of course also a
|
||||
set of loaders configured, which you can read more about in the
|
||||
[loaders](#loaders) and [transpilation](#transpilation) sections.
|
||||
|
||||
During the build, the following constants are also set:
|
||||
|
||||
```java
|
||||
process.env.NODE_ENV = 'production';
|
||||
process.env.BUILD_INFO = {
|
||||
cliVersion: '0.4.0', // The version of the CLI package
|
||||
gitVersion: 'v0.4.0-86-ge54815618', // output of `git describe --always`
|
||||
packageVersion: '1.0.5', // The version of the app package itself
|
||||
timestamp: 1678900000000, // Date.now() when the build started
|
||||
commit: 'e548156182a973ed4b459e18533afc22c85ffff8', // output of `git rev-parse HEAD`
|
||||
};
|
||||
```
|
||||
|
||||
The output of the bundling process is split into two categories of files with
|
||||
separate caching strategies. The first is a set of generic assets with plain
|
||||
names in the root of the `dist/` folder. You will want to serve these with
|
||||
@@ -331,7 +414,7 @@ dependencies installed, and as soon as you copy over and extract the contents of
|
||||
the `bundle.tar.gz` archive on top of it, the backend will be ready to run.
|
||||
|
||||
The following is an example of a `Dockerfile` that can be used to package the
|
||||
output of `backstage-cli backend:bundle` into an image:
|
||||
output of building a package with role `'backend'` into an image:
|
||||
|
||||
```Dockerfile
|
||||
FROM node:16-bullseye-slim
|
||||
@@ -543,12 +626,45 @@ The following is an excerpt of a typical setup of an isomorphic library package:
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "backstage-cli build",
|
||||
"lint": "backstage-cli lint",
|
||||
"test": "backstage-cli test",
|
||||
"prepack": "backstage-cli prepack",
|
||||
"postpack": "backstage-cli postpack",
|
||||
"clean": "backstage-cli clean"
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test",
|
||||
"clean": "backstage-cli package clean",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack"
|
||||
},
|
||||
"files": ["dist"],
|
||||
```
|
||||
|
||||
## Experimental Type Build
|
||||
|
||||
The Backstage CLI has an experimental feature where multiple different type definition files can be generated for different release stages. The release stages are marked in the [TSDoc](https://tsdoc.org/) for each individual export, using either `@public`, `@alpha`, or `@beta`. Rather than just building a single `index.d.ts` file, the build process will instead output `index.d.ts`, `index.beta.d.ts`, and `index.alpha.d.ts`. Each of these files will have exports from more unstable release stages stripped, meaning that `index.d.ts` will omit all exports marked with `@alpha` or `@beta`, while `index.beta.d.ts` will omit all exports marked with `@alpha`.
|
||||
|
||||
This feature is aimed at projects that publish to package registries and wish to maintain different levels of API stability within each package. There is no need to use this within a single monorepo, as it has no effect due to only applying to built and published packages.
|
||||
|
||||
In order for the experimental type build to work, `@microsoft/api-extractor` must be installed in your project, as it is an optional peer dependency of the Backstage CLI. There are then three steps that need to be taken for each package where you want to enable this feature:
|
||||
|
||||
- Add the `--experimental-type-build` flag to the `"build"` script of the package.
|
||||
- Add either one or both of `"alphaTypes"` and `"betaTypes"` to the `"publishConfig"` of the package:
|
||||
```json
|
||||
"publishConfig": {
|
||||
...
|
||||
"types": "dist/index.d.ts",
|
||||
"alphaTypes": "dist/index.alpha.d.ts",
|
||||
"betaTypes": "dist/index.beta.d.ts"
|
||||
},
|
||||
```
|
||||
- Add either one or both of `"alpha"` and `"beta"` to the `"files"` of the package:
|
||||
```json
|
||||
"files": [
|
||||
"dist",
|
||||
"alpha",
|
||||
"beta"
|
||||
]
|
||||
```
|
||||
|
||||
Once this setup is complete, users of the published packages will only be able to access the stable API via the main package entry point, for example `@acme/my-plugin`. Exports marked with `@alpha` or `@beta` will only be available via the `/alpha` entry point, for example `@acme/my-plugin/alpha`, and exports marked with `@beta` will only be available via `/beta`. This does not apply within the monorepo that contains the package. There all exports still have to be imported via the main entry point.
|
||||
|
||||
Note that these different entry points are only separated during type checking. At runtime they all share the same code which contains the exports from all releases stages.
|
||||
|
||||
An example of this setup can be seen in the [`@backstage/catalog-model`](https://github.com/backstage/backstage/blob/da0675bf9f28ed1460f03635a22d3c26abd14707/packages/catalog-model/package.json#L14) package, which has enabled `alpha` type exports. With this setup, exports marked as `@alpha` are only available for import via `@backstage/catalog-model/alpha`. The `@backstage/catalog-model` package currently does not have any exports marked as `@beta`, or a `/beta` entry point.
|
||||
|
||||
+150
-433
@@ -7,251 +7,202 @@ description: Descriptions of all commands available in the CLI.
|
||||
This page lists all commands provided by the Backstage CLI, what they're for,
|
||||
and where to use them.
|
||||
|
||||
The documentation for each command begins with specifying its scope, this
|
||||
indicates where the command should be used by selecting from the following list:
|
||||
|
||||
- `app` - A frontend app package, such as `packages/app`.
|
||||
- `backend` - A backend package, such as `packages/backend`.
|
||||
- `frontend-plugin` - A frontend plugin package.
|
||||
- `backend-plugin` - A backend plugin package.
|
||||
- `root` - The monorepo root.
|
||||
- `any` - Any kind of package, but not the repo root.
|
||||
|
||||
## help
|
||||
|
||||
This command displays a help summary or detailed help screens for each command.
|
||||
Below is a cleaned up output of `yarn backstage-cli --help`.
|
||||
Below is a cleaned up output of `yarn backstage-cli --help`
|
||||
|
||||
```text
|
||||
app:build Build an app for a production release
|
||||
app:serve Serve an app for local development
|
||||
repo [command] Command that run across an entire Backstage project
|
||||
package [command] Lifecycle scripts for individual packages
|
||||
migrate [command] Migration utilities
|
||||
|
||||
backend:build Build a backend plugin
|
||||
backend:bundle Bundle the backend into a deployment archive
|
||||
backend:build-image Bundles the package into a docker image
|
||||
backend:dev Start local development server with HMR for the backend
|
||||
create Open up an interactive guide to creating new things in your app
|
||||
|
||||
plugin:build Build a plugin
|
||||
plugin:diff Diff an existing plugin with the creation template
|
||||
plugin:serve Serves the dev/ folder of a plugin
|
||||
config:docs Browse the configuration reference documentation
|
||||
config:print Print the app configuration for the current package
|
||||
config:check Validate that the given configuration loads and matches schema
|
||||
config:schema Dump the app configuration schema
|
||||
|
||||
build Build a package for publishing
|
||||
build-workspace Builds a temporary dist workspace from the provided packages
|
||||
lint Lint a package
|
||||
test Run tests, forwarding args to Jest, defaulting to watch mode
|
||||
clean Delete cache directories
|
||||
versions:bump Bump Backstage packages to the latest versions
|
||||
versions:check Check Backstage package versioning
|
||||
|
||||
create Open up an interactive guide to creating new things in your app
|
||||
create-plugin Creates a new plugin in the current repository
|
||||
remove-plugin Removes plugin in the current repository
|
||||
build-workspace Builds a temporary dist workspace from the provided packages
|
||||
create-github-app Create new GitHub App in your organization (experimental)
|
||||
|
||||
config:docs Browse the configuration reference documentation
|
||||
config:print Print the app configuration for the current package
|
||||
config:check Validate that the given configuration loads and matches schema
|
||||
config:schema Dump the app configuration schema
|
||||
|
||||
versions:bump Bump Backstage packages to the latest versions
|
||||
versions:check Check Backstage package versioning
|
||||
|
||||
prepack Prepares a package for packaging before publishing
|
||||
postpack Restores the changes made by the prepack command
|
||||
|
||||
create-github-app Create new GitHub App in your organization (experimental)
|
||||
|
||||
info Show helpful information for debugging and reporting bugs
|
||||
help [command] display help for command
|
||||
info Show helpful information for debugging and reporting bugs
|
||||
help [command] display help for command
|
||||
```
|
||||
|
||||
## app:build
|
||||
|
||||
Scope: `app`
|
||||
|
||||
Builds a bundle of static content from the app, which can then be served via any
|
||||
static web server such as `nginx`, or via the
|
||||
[`app-backend`](https://www.npmjs.com/package/@backstage/plugin-app-backend)
|
||||
plugin directly from a Backstage backend instance.
|
||||
|
||||
The command also reads and injects static configuration into the bundle. It is
|
||||
important to note that when deploying using your own static content hosting
|
||||
solution, this will be the final configuration used in the frontend unless you
|
||||
for example hook in configuration loading from the backend. When using the
|
||||
`nginx` based Dockerfile in this repo along with its included run script,
|
||||
`APP_CONFIG_` environment variables will be injected into the frontend, and when
|
||||
serving using the `app-backend` plugin, the configuration is completely injected
|
||||
from the backend and the configuration at the time of calling this command will
|
||||
not be used.
|
||||
|
||||
Note that even when injecting configuration at runtime, it is not possible to
|
||||
change the base path of the app. For example, if you at build time have
|
||||
`app.baseUrl` set to `http://dev-app.com/my-app`, you can change that to
|
||||
`https://prod-app.com/my-app`, but not to `https://prod-app.com`, as that would
|
||||
change the path.
|
||||
|
||||
During the build, the following variables are set:
|
||||
|
||||
```java
|
||||
process.env.NODE_ENV = 'production';
|
||||
process.env.BUILD_INFO = {
|
||||
cliVersion: '0.4.0', // The version of the CLI package
|
||||
gitVersion: 'v0.4.0-86-ge54815618', // output of `git describe --always`
|
||||
packageVersion: '1.0.5', // The version of the app package itself
|
||||
timestamp: 1678900000000, // Date.now() when the build started
|
||||
commit: 'e548156182a973ed4b459e18533afc22c85ffff8', // output of `git rev-parse HEAD`
|
||||
};
|
||||
```
|
||||
|
||||
Some CI environments do not properly report correct resource limits, potentially
|
||||
leading to errors such as `ENOMEM` during compilation. If you run into this
|
||||
issue you can limit the parallelization of the build process by setting the
|
||||
environment variable `BACKSTAGE_CLI_BUILD_PARALLEL`, which is forwarded to the
|
||||
[`terser-webpack-plugin`](https://github.com/webpack-contrib/terser-webpack-plugin#parallel).
|
||||
You can set it to `false` or `1` to completely disable parallelization, but
|
||||
usually a low value such as `2` is enough.
|
||||
The `package` command category, `yarn backstage-cli package --help`
|
||||
|
||||
```text
|
||||
Usage: backstage-cli app:build
|
||||
start [options] Start a package for local development
|
||||
build [options] Build a package for production deployment or publishing
|
||||
lint [options] Lint a package
|
||||
test Run tests, forwarding args to Jest, defaulting to watch mode
|
||||
clean Delete cache directories
|
||||
prepack Prepares a package for packaging before publishing
|
||||
postpack Restores the changes made by the prepack command
|
||||
```
|
||||
|
||||
The `repo` command category, `yarn backstage-cli repo --help`
|
||||
|
||||
```text
|
||||
build [options] Build packages in the project, excluding bundled app and backend packages.
|
||||
lint [options] Lint all packages in the project
|
||||
```
|
||||
|
||||
The `migrate` command category, `yarn backstage-cli migrate --help`
|
||||
|
||||
```text
|
||||
package-roles Add package role field to packages that don't have it
|
||||
package-scripts Set package scripts according to each package role
|
||||
package-lint-configs Migrates all packages to use @backstage/cli/config/eslint-factory
|
||||
```
|
||||
|
||||
## repo build
|
||||
|
||||
Builds all packages in the project, excluding bundled packages by default, i.e. ones
|
||||
with the role `'frontend'` or `'backend'`.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli repo build [options]
|
||||
|
||||
Build packages in the project, excluding bundled app and backend packages.
|
||||
|
||||
Options:
|
||||
--all Build all packages, including bundled app and backend packages.
|
||||
--since <ref> Only build packages and their dev dependents that changed since the specified ref
|
||||
```
|
||||
|
||||
## repo lint
|
||||
|
||||
Lint all packages in the project.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli repo lint [options]
|
||||
|
||||
Lint all packages in the project
|
||||
|
||||
Options:
|
||||
--format <format> Lint report output format (default: "eslint-formatter-friendly")
|
||||
--since <ref> Only lint packages that changed since the specified ref
|
||||
--fix Attempt to automatically fix violations
|
||||
```
|
||||
|
||||
## package start
|
||||
|
||||
Starts the package for local development. See the frontend and backend development parts in the build system [bundling](./cli-build-system.md#bundling) section for more details.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli package start [options]
|
||||
|
||||
Start a package for local development
|
||||
|
||||
Options:
|
||||
--stats Write bundle stats to output directory
|
||||
--lax Do not require environment variables to be set
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
--role <name> Run the command with an explicit package role
|
||||
--check Enable type checking and linting if available
|
||||
--inspect Enable debugger in Node.js environments
|
||||
--inspect-brk Enable debugger in Node.js environments, breaking before code starts
|
||||
```
|
||||
|
||||
## app:serve
|
||||
## package build
|
||||
|
||||
Scope: `app`
|
||||
|
||||
Serve an app for local development. This starts up a local development server,
|
||||
using a bundling configuration that is quite similar to that of the `app:build`
|
||||
command, but with development features such as React Hot Module Replacement,
|
||||
faster sourcemaps, no minification, etc.
|
||||
|
||||
The static configuration is injected into the frontend, but it does not support
|
||||
watching, meaning that changes in for example `app-config.yaml` are not
|
||||
reflected until the serve process is restarted.
|
||||
|
||||
During the build, the following variables are set:
|
||||
|
||||
```java
|
||||
process.env.NODE_ENV = 'development';
|
||||
process.env.BUILD_INFO = { /* See app:build */ };
|
||||
```
|
||||
|
||||
The server listening configuration is controlled through the static
|
||||
configuration. The `app.baseUrl` determines the listening host and port, as well
|
||||
as whether HTTPS is used or not. It is also possible to override the listening
|
||||
host and port if needed by setting `app.listen.host` and `app.listen.port`.
|
||||
Build an individual package based on its role. See the build system [building](./cli-build-system.md#building) and [bundling](./cli-build-system.md#bundling) sections for more details.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli app:serve [options]
|
||||
Usage: backstage-cli package build [options]
|
||||
|
||||
Build a package for production deployment or publishing
|
||||
|
||||
Options:
|
||||
--check Enable type checking and linting
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
--role <name> Run the command with an explicit package role
|
||||
--minify Minify the generated code. Does not apply to app or backend packages.
|
||||
--experimental-type-build Enable experimental type build. Does not apply to app or backend packages.
|
||||
--skip-build-dependencies Skip the automatic building of local dependencies. Applies to backend packages only.
|
||||
--stats If bundle stats are available, write them to the output directory. Applies to app packages only.
|
||||
--config <path> Config files to load instead of app-config.yaml. Applies to app packages only. (default: [])
|
||||
```
|
||||
|
||||
## backend:build
|
||||
## package lint
|
||||
|
||||
Scope: `backend-plugin`
|
||||
|
||||
This builds a backend package for publishing and use in production. The build
|
||||
output is written to `dist/`. Be sure to list any additional file that the
|
||||
package depends on at runtime in the `"files"` field inside `package.json`, a
|
||||
common example being the `migrations` directory.
|
||||
Lint a package. In addition to the default `eslint` behavior, this command will
|
||||
include TypeScript files, treat warnings as errors, and default to linting the
|
||||
entire directory if no specific files are listed. For more information, see the
|
||||
build system [linting](./cli-build-system.md#linting) section.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli backend:build [options]
|
||||
Usage: backstage-cli package lint [options]
|
||||
|
||||
Lint a package
|
||||
|
||||
Options:
|
||||
--minify Minify the generated code
|
||||
-h, --help display help for command
|
||||
--format <format> Lint report output format (default: "eslint-formatter-friendly")
|
||||
--fix Attempt to automatically fix violations
|
||||
```
|
||||
|
||||
## backend:bundle
|
||||
## package test
|
||||
|
||||
Scope: `backend`
|
||||
Run tests, forwarding all unknown options to Jest, and defaulting to watch mode.
|
||||
When executing the tests, `process.env.NODE_ENV` will be set to `"test"`.
|
||||
|
||||
Bundles the backend into a `dist/bundle.tar.gz` archive. See the
|
||||
[backend bundling](./cli-build-system.md#backend-production-bundling) build
|
||||
systems documentation for more details.
|
||||
This command uses a default Jest configuration that is included in the CLI,
|
||||
which is set up with similar goals for speed, scale, and working within a
|
||||
monorepo. The configuration sets the `src` as the root directory, enforces the
|
||||
`.test.` infix for tests, and uses `src/setupTests.ts` as the test setup
|
||||
location. The included configuration also supports test execution at the root of
|
||||
a yarn workspaces monorepo by automatically creating one grouped configuration
|
||||
that includes all packages that have `backstage-cli test` in their package
|
||||
`test` script.
|
||||
|
||||
For more information about configuration overrides and editor support, see the [Jest Configuration section](./cli-build-system.md#jest-configuration) in the build system documentation.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli backend:bundle [options]
|
||||
Usage: backstage-cli package test [options]
|
||||
|
||||
Bundle the backend into a deployment archive
|
||||
Run tests, forwarding args to Jest, defaulting to watch mode
|
||||
|
||||
Options:
|
||||
--build-dependencies Build all local package dependencies before bundling the backend
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## backend:build-image
|
||||
|
||||
Scope: `backend`
|
||||
|
||||
Builds a Docker image of the backend package, forwarding all unknown options to
|
||||
`docker image build`. For example:
|
||||
|
||||
```bash
|
||||
yarn backstage-cli backend:build-image --build --tag my-backend-image
|
||||
```
|
||||
|
||||
The image is built using the backend package along with all of its local package
|
||||
dependencies. It expects to find a `Dockerfile` at the root of the backend
|
||||
package, which will be used during the build.
|
||||
|
||||
The Dockerfile is **NOT** executed within the package or repo itself. Because
|
||||
the packages in the repo itself are configured for development instead of
|
||||
production use, the final Docker build happens in a separate temporary
|
||||
directory, to which the backend package and dependencies have been copied. Only
|
||||
files listed within the `"files"` field within each package's `package.json` are
|
||||
copied over, along with the root `package.json`, `yarn.lock`, and any
|
||||
`app-config.*.yaml` files.
|
||||
|
||||
During the build a `skeleton.tar` file is created and put at the repo root. This
|
||||
file contains the `package.json` of each included package, which together with
|
||||
the root `package.json` and `yarn.lock` can be used to run a cached
|
||||
`yarn install` before the full production builds of all the packages are copied
|
||||
over, providing a significant speedup if Docker build layer caching available.
|
||||
|
||||
This command is experimental and we hope to be able to replace it with one that
|
||||
is less integrated directly with Docker, and also supports multi-stage Docker
|
||||
builds. It is possible to replicate most of what this command does by manually
|
||||
building each package, and then use the `build-workspace` to create the
|
||||
temporary workspace, and finally copy over any additional files to the workspace
|
||||
and execute the Docker build within it.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli backend:build-image [options]
|
||||
|
||||
Options:
|
||||
--build Build packages before packing them into the image
|
||||
--backstage-cli-help display help for command
|
||||
```
|
||||
|
||||
## backend:dev
|
||||
## package clean
|
||||
|
||||
Scope: `backend`, `backend-plugin`
|
||||
|
||||
Starts a backend package in development mode, with watch mode enabled for all
|
||||
local dependencies.
|
||||
Remove cache and output directories.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli backend:dev [options]
|
||||
Usage: backstage-cli package clean [options]
|
||||
|
||||
Options:
|
||||
--check Enable type checking and linting
|
||||
--inspect Enable debugger
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
Delete cache directories
|
||||
```
|
||||
|
||||
## package prepack
|
||||
|
||||
This command should be added as `scripts.prepack` in all packages. It enables
|
||||
packaging- and publish-time overrides for fields inside `packages.json`.
|
||||
For more details, see the build system [publishing](./cli-build-system.md#publishing) section.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli package prepack [options]
|
||||
|
||||
Prepares a package for packaging before publishing
|
||||
```
|
||||
|
||||
## package postpack
|
||||
|
||||
This should be added as `scripts.postpack` in all packages. It restores
|
||||
`package.json` to what it looked like before calling the `prepack` command.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli package postpack [options]
|
||||
|
||||
Restores the changes made by the prepack command
|
||||
```
|
||||
|
||||
## create
|
||||
|
||||
Scope: `root`
|
||||
|
||||
The `create` command opens up an interactive guide for you to create new things
|
||||
in your app. If you do not pass in any options it is completely interactive, but
|
||||
it is possible to pre-select what you want to create using the `--select` flag,
|
||||
@@ -278,181 +229,16 @@ this:
|
||||
Usage: backstage-cli create [options]
|
||||
|
||||
Options:
|
||||
--select <name> Select the thing you want to be creating upfront
|
||||
--option <name>=<value> Pre-fill options for the creation process (default: [])
|
||||
--scope <scope> The scope to use for new packages
|
||||
--npm-registry <URL> The package registry to use for new packages
|
||||
--select <name> Select the thing you want to be creating upfront
|
||||
--option <name>=<value> Pre-fill options for the creation process (default: [])
|
||||
--scope <scope> The scope to use for new packages
|
||||
--npm-registry <URL> The package registry to use for new packages
|
||||
--no-private Do not mark new packages as private
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## create-plugin
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Creates a new plugin within the repository. This command is typically wrapped up
|
||||
in the root `package.json` to be executed with `yarn create-plugin`, using
|
||||
options that are appropriate for the organization that owns the app repo. A
|
||||
recommended scope for internal packages is `@internal`.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli create-plugin [options]
|
||||
|
||||
Options:
|
||||
--backend Create plugin with the backend dependencies as default
|
||||
--scope <scope> npm scope
|
||||
--npm-registry <URL> npm registry URL
|
||||
--no-private Public npm package
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## remove-plugin
|
||||
|
||||
Scope: `root`
|
||||
|
||||
A utility to remove a plugin from a repo, essentially undoing everything that
|
||||
was done by `create-plugin`.
|
||||
|
||||
This is primarily intended as a utility for manual tests and end to end testing
|
||||
scripts.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli remove-plugin [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## plugin:build
|
||||
|
||||
Scope: `frontend-plugin`
|
||||
|
||||
Build a frontend plugin for publishing to a package registry. There is no need
|
||||
to run this command during development or even in CI unless the package is being
|
||||
published. The `app:bundle` command does not use the output for this command
|
||||
when bundling local package dependencies.
|
||||
|
||||
The output is written to a `dist/` folder. It also outputs type declarations for
|
||||
the plugin, and therefore requires `yarn tsc` to have been run first. The input
|
||||
type declarations are expected to be found within `dist-types/` at the root of
|
||||
the monorepo.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli plugin:build [options]
|
||||
|
||||
Options:
|
||||
--minify Minify the generated code
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## plugin:serve
|
||||
|
||||
Scope: `frontend-plugin`
|
||||
|
||||
Serves a frontend plugin by itself for isolated development. The serve task
|
||||
itself is essentially identical to `app:serve`, but the entrypoint is instead
|
||||
set to the `dev/` folder within the plugin.
|
||||
|
||||
The `dev/` folder typically contains a small wrapper script that hooks up any
|
||||
necessary mock APIs or other things that are needed for the plugin to function.
|
||||
The `@backstage/dev-utils` package provides utilities to that end.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli plugin:serve [options]
|
||||
|
||||
Options:
|
||||
--check Enable type checking and linting
|
||||
--config <path> Config files to load instead of app-config.yaml (default: [])
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## plugin:diff
|
||||
|
||||
Scope: `frontend-plugin`
|
||||
|
||||
Compares a frontend plugin to the `create-plugin` template, making sure that it
|
||||
hasn't diverged from the template and recommending updates when it has. A good
|
||||
practice is to run this command after updating the version of the CLI in a
|
||||
project.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli plugin:diff [options]
|
||||
|
||||
Options:
|
||||
--check Fail if changes are required
|
||||
--yes Apply all changes
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## build
|
||||
|
||||
Scope: `any`
|
||||
|
||||
Build a single package for publishing, just like the `plugin:build` and
|
||||
`backend:build` commands. This command is intended for standalone packages that
|
||||
aren't plugins, and for example support building of isomorphic packages for
|
||||
usage in both the frontend and backend.
|
||||
|
||||
For frontend packages you'll want to include `esm` output, and for backend
|
||||
packages `cjs`. Whether to include `types` depends on if you need type
|
||||
declarations for the package, and also requires `yarn tsc` to have been run
|
||||
first.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli build [options]
|
||||
|
||||
Options:
|
||||
--outputs <formats> List of formats to output [types,cjs,esm]
|
||||
--minify Minify the generated code
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## lint
|
||||
|
||||
Scope: `any`
|
||||
|
||||
Lint a package. In addition to the default `eslint` behavior, this command will
|
||||
include TypeScript files, treat warnings as errors, and default to linting the
|
||||
entire directory if no specific files are listed.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli lint [options]
|
||||
|
||||
Options:
|
||||
--format <format> Lint report output format (default: "eslint-formatter-friendly")
|
||||
--fix Attempt to automatically fix violations
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## test
|
||||
|
||||
Scope: `any`
|
||||
|
||||
Run tests, forwarding all unknown options to Jest, and defaulting to watch mode.
|
||||
When executing the tests, `process.env.NODE_ENV` will be set to `"test"`.
|
||||
|
||||
This command uses a default Jest configuration that is included in the CLI,
|
||||
which is set up with similar goals for speed, scale, and working within a
|
||||
monorepo. The configuration sets the `src` as the root directory, enforces the
|
||||
`.test.` infix for tests, and uses `src/setupTests.ts` as the test setup
|
||||
location. The included configuration also supports test execution at the root of
|
||||
a yarn workspaces monorepo by automatically creating one grouped configuration
|
||||
that includes all packages that have `backstage-cli test` in their package
|
||||
`test` script.
|
||||
|
||||
For more information about configuration overrides and editor support, see the [Jest Configuration section](./cli-build-system.md#jest-configuration) in the build system documentation.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli test [options]
|
||||
|
||||
Options:
|
||||
--backstage-cli-help display help for command
|
||||
```
|
||||
|
||||
## config:docs
|
||||
|
||||
Scope: `root`
|
||||
|
||||
This commands opens up the reference documentation of your apps local
|
||||
configuration schema in the browser. This is useful to get an overview of what
|
||||
configuration values are available to use, a description of what they do and
|
||||
@@ -464,14 +250,12 @@ Usage: backstage-cli config:docs [options]
|
||||
Browse the configuration reference documentation
|
||||
|
||||
Options:
|
||||
--package <name> Only include the schema that applies to the given package
|
||||
--package <name> Only include the schema that applies to the given package
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## config:print
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Print the static configuration, defaulting to reading `app-config.yaml` in the
|
||||
repo root, using schema collected from all local packages in the repo.
|
||||
|
||||
@@ -497,8 +281,6 @@ Options:
|
||||
|
||||
## config:check
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Validate that static configuration loads and matches schema, defaulting to
|
||||
reading `app-config.yaml` in the repo root and using schema collected from all
|
||||
local packages in the repo.
|
||||
@@ -517,8 +299,6 @@ Options:
|
||||
|
||||
## config:schema
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Dump the configuration schema that was collected from all local packages in the
|
||||
repo.
|
||||
|
||||
@@ -538,8 +318,6 @@ Options:
|
||||
|
||||
## versions:bump
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Bump all `@backstage` packages to the latest versions. This checks for updates
|
||||
in the package registry, and will update entries both in `yarn.lock` and
|
||||
`package.json` files when necessary.
|
||||
@@ -554,8 +332,6 @@ Options:
|
||||
|
||||
## versions:check
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Validate `@backstage` dependencies within the repo, making sure that there are
|
||||
no duplicates of packages that might lead to breakages.
|
||||
|
||||
@@ -571,63 +347,8 @@ Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## prepack
|
||||
|
||||
Scope: `any`
|
||||
|
||||
This command should be added as `scripts.prepack` in all packages. It enables
|
||||
packaging- and publish-time overrides for fields inside `packages.json`.
|
||||
|
||||
The checked in version of all packages in a Backstage monorepo are tailored for
|
||||
local development, and as such `main` and similar fields inside `package.json`
|
||||
point to development source, i.e. `src/index.ts`. Using this when publishing
|
||||
would lead to a broken package, since `src/` is not included in the published
|
||||
package and we instead need to point to files in the `dist/` directory. This
|
||||
command allows for those fields to be rewritten when needed, and does so by
|
||||
copying all fields within `publishConfig` to the top-level of each
|
||||
`package.json`, skipping `access`, `registry`, and `tag`.
|
||||
|
||||
The need for this command may be removed in the future, as this exact method of
|
||||
overriding fields for publishing is already supported by some package managers.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli prepack [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## postpack
|
||||
|
||||
Scope: `any`
|
||||
|
||||
This should be added as `scripts.postpack` in all packages. It restores
|
||||
`package.json` to what it looked like before calling the `prepack` command.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli postpack [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## clean
|
||||
|
||||
Scope: `any`
|
||||
|
||||
Remove cache and output directories.
|
||||
|
||||
```text
|
||||
Usage: backstage-cli clean [options]
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
## build-workspace
|
||||
|
||||
Scope: `any`, `root`
|
||||
|
||||
Builds a mirror of the workspace using the packaged production version of each
|
||||
package. This essentially calls `yarn pack` in each included package and unpacks
|
||||
the resulting archive in the target `workspace-dir`.
|
||||
@@ -638,8 +359,6 @@ Usage: backstage-cli build-workspace [options] <workspace-dir>
|
||||
|
||||
## create-github-app
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Creates a GitHub App in your GitHub organization. This is an alternative to
|
||||
token-based [GitHub integration](../integrations/github/locations.md). See
|
||||
[GitHub Apps for Backstage Authentication](../plugins/github-apps.md).
|
||||
@@ -653,8 +372,6 @@ Usage: backstage-cli create-github-app <github-org>
|
||||
|
||||
## info
|
||||
|
||||
Scope: `root`
|
||||
|
||||
Outputs debug information which is useful when opening an issue. Outputs system
|
||||
information, node.js and npm versions, CLI version and type (inside backstage
|
||||
repo or a created app), all `@backstage/*` package dependency versions.
|
||||
|
||||
@@ -50,3 +50,4 @@ improve the tooling, as well as to more easily keep the system up to date.
|
||||
- **Bundle** - A collection of the deployment artifacts. The output of the
|
||||
bundling process, which brings a collection of packages into a single
|
||||
collection of deployment artifacts.
|
||||
- **Package Role** - The declared role of a package, see [package roles](./cli-build-system.md#package-roles).
|
||||
|
||||
@@ -310,7 +310,7 @@ backend:
|
||||
backend:
|
||||
cache:
|
||||
store: redis
|
||||
connection: user:pass@cache.example.com:6379
|
||||
connection: redis://user:pass@cache.example.com:6379
|
||||
```
|
||||
|
||||
Contributions supporting other cache stores are welcome!
|
||||
|
||||
@@ -67,12 +67,3 @@ process is used to release an emergency fix as version `6.5.1` in the patch rele
|
||||
- [ ] The fix, which you can likely cherry-pick from your patch branch: `git cherry-pick origin/patch/v1.18.0^`
|
||||
- [ ] An updated `CHANGELOG.md` of all patched packages from the tip of the patch branch, `git checkout origin/patch/v1.18.0 -- {packages,plugins}/*/CHANGELOG.md`.
|
||||
- [ ] A changeset with the message "Applied the fix from version `6.5.1` of this package, which is part of the `v1.18.1` release of Backstage."
|
||||
- [ ] An entry in `.changeset/patched.json` that sets the current release version to `6.5.1`:
|
||||
|
||||
```json
|
||||
{
|
||||
"currentReleaseVersion": {
|
||||
"@backstage/plugin-foo": "6.5.1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -49,29 +49,6 @@ yarn add sqlite3
|
||||
From an operational perspective, you only need to install drivers for clients
|
||||
that are actively used.
|
||||
|
||||
### Database Manager
|
||||
|
||||
Existing Backstage instances should be updated to use `DatabaseManager` from
|
||||
`@backstage/backend-common` in your `packages/backend/src/index.ts` file, the
|
||||
`SingleConnectionDatabaseManager` has been deprecated. Import the manager and
|
||||
update the references as shown below if this is not the case:
|
||||
|
||||
```diff
|
||||
import {
|
||||
- SingleConnectionDatabaseManager,
|
||||
+ DatabaseManager,
|
||||
} from '@backstage/backend-common';
|
||||
|
||||
// ...
|
||||
|
||||
function makeCreateEnv(config: Config) {
|
||||
// ...
|
||||
- const databaseManager = SingleConnectionDatabaseManager.fromConfig(config);
|
||||
+ const databaseManager = DatabaseManager.fromConfig(config);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
You should set the base database client and connection information in your
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
---
|
||||
id: package-role-migration
|
||||
title: Package Role Migration
|
||||
description: Guide for how to migrate packages to use the new role utility
|
||||
---
|
||||
|
||||
The Backstage CLI has introduced the concept of package roles, whose purpose is to
|
||||
enable more powerful tooling, optimizations, and leaner package configuration. More background and
|
||||
information about the change can be found in the [original RFC](https://github.com/backstage/backstage/issues/8729) and the [FAQ](#faq) on this page.
|
||||
|
||||
Package roles are implemented through a well-known `"backstage"."role"` field in the
|
||||
`package.json` of each package. There are a handful of roles defined so far, and it
|
||||
is not possible to use values outside the [set of predefined roles](../local-dev/cli-build-system.md#package-roles).
|
||||
|
||||
With roles in place in all packages, the Backstage CLI is able to automatically
|
||||
determine how to handle each package. For example, the different build commands
|
||||
have been replaced by a single one that instead knows how to build each role.
|
||||
The test and lint configurations are also selected automatically based on the role, and
|
||||
a new category of `repo` commands have been introduced in the CLI, which are able
|
||||
to operate across all packages simultaneously.
|
||||
|
||||
Package roles have been used in the Backstage main repository for a while, and
|
||||
we now recommend that all Backstage projects are migrated to use package roles.
|
||||
|
||||
## Migration
|
||||
|
||||
In order to make the migration as smooth as possible `@backstage/cli` provides
|
||||
a number of migration utilities. Using these in combination with some manual review
|
||||
and optional steps should be all you need to migrate to package roles in most projects.
|
||||
|
||||
Before you begin the migration, make sure you have updated to the most recent version of
|
||||
the `@backstage/cli`.
|
||||
|
||||
### TL;DR, Step 1-4:
|
||||
|
||||
This is a sorter version of all of the steps below, in case you're in a hurry.
|
||||
|
||||
Run the following commands:
|
||||
|
||||
```sh
|
||||
yarn backstage-cli migrate package-roles
|
||||
yarn backstage-cli migrate package-scripts
|
||||
yarn backstage-cli migrate package-lint-configs
|
||||
```
|
||||
|
||||
Have a look at the new commands under `yarn backstage-cli repo`, and switch to them wherever you can. They tend to be much faster compared to their `lerna` equivalents.
|
||||
|
||||
### Step 1 - Add package roles
|
||||
|
||||
The first step is to add the `"backstage"."role"` field to each package. This can of course be done manually, but the following command will attempt to automatically detect the role of each package in your project:
|
||||
|
||||
```sh
|
||||
yarn backstage-cli migrate package-roles
|
||||
```
|
||||
|
||||
The automatic detection is not perfect, so it is recommended to manually review the
|
||||
roles that were assigned to each package.
|
||||
You can use the [package role definitions](../local-dev/cli-build-system.md#package-roles) as a reference.
|
||||
|
||||
### Step 2 - Migrate package scripts
|
||||
|
||||
The migration to package roles also introduces a new `package` command category to the CLI.
|
||||
Each command under the `package` category is designed to be mapped directly to an entry in `"scripts"` in `package.json`. These commands replace the existing commands like `build`, `app:build`, `lint`, and `test`. They look something like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Every package role has a fixed set of recommended scripts. It is strongly recommended that you use these scripts, as it allows for optimizations in other parts of the CLI. You can migrate to using all of these scripts by running the following command:
|
||||
|
||||
```sh
|
||||
yarn backstage-cli migrate package-scripts
|
||||
```
|
||||
|
||||
The migration command also carries over any existing flags that were being passed in the old scripts.
|
||||
|
||||
If you in the end do not want to use this exact script setup, it is still recommended to migrate to using the `package` commands, as the top-level commands will be deprecated and removed. If you don't want to use package roles either, you can pass an explicit role to some of the package commands, for example `yarn backstage-cli package build --role web-library`.
|
||||
|
||||
### Step 3 - Migrate package ESLint configurations
|
||||
|
||||
An area that has been simplified as part of the move to package roles is the ESLint configuration. Rather than having each package select which configuration they want (and getting it wrong), they now use a shared configuration factory that utilizes the package role. You can read more about the new configuration setup in the [build system documentation](../local-dev/cli-build-system.md#linting).
|
||||
|
||||
To migrate the ESLint configuration of all packages in your project, run the following command:
|
||||
|
||||
```sh
|
||||
yarn backstage-cli migrate package-lint-configs
|
||||
```
|
||||
|
||||
This will migrate all existing `.eslintrc.js` that extend the old configuration from `@backstage/cli`, as well as carry over any additional configuration.
|
||||
|
||||
### Step 4 - Use `backstage-cli repo`
|
||||
|
||||
The Backstage CLI recently introduced a new `repo` command category, which houses commands that operate on an entire monorepo at once. These commands work particularly well once packages have been migrated to use roles, as that allows for some very effective optimizations. It is typically much faster to use these commands compared to using tools like `lerna`, as they're able to avoid the overhead of calling package scripts through `yarn` and can operate on multiple packages at once. You can read more about the `repo` command in the [CLI command documentation](../local-dev/cli-commands.md#repo-build).
|
||||
|
||||
The way to execute this step of the migration is not as well defined as the previous steps, as it depends on what your development and CI/CD setup looks like. Look for the following patterns to replace in your root `package.json` as well as CI/CD setup:
|
||||
|
||||
- Commands that lint the entire repo should be replaced with `yarn backstage-cli repo lint` along with a `--since` flag if needed. For example this:
|
||||
|
||||
```sh
|
||||
lerna run lint --since origin/master --
|
||||
```
|
||||
|
||||
would be replaced by the following:
|
||||
|
||||
```sh
|
||||
backstage-cli repo lint --since origin/master
|
||||
```
|
||||
|
||||
- In places where the entire repo is being built, use `yarn backstage-cli repo build`, which also supports the `--since` flag. The migration here is a bit more nuanced as it depends on why you are building all packages.
|
||||
- If you are building all packages to **verify** that you are able to build them, you most likely want `backstage-cli repo build --all`. The `--all` flag signals that bundled packages like `packages/app` and `packages/backend` should be built as well. Pair this up with a `--since` flag in CI to avoid needing to build all packages.
|
||||
- If you are building all packages to **publish** them, then `backstage-cli repo build` is enough, as it builds all published packages.
|
||||
- If you are building all packages to **deploy** them, you likely don't want to use the `repo` command at all, simply call `yarn build` in the packages you want to deploy instead. For example, if you are deploying the backend with a docker host build, it's enough to call `yarn build` inside `packages/backend`.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why were package roles introduced?
|
||||
|
||||
To keep configuration lean, allow for more utilities and tooling, and to enable optimizations in the build system. You can read more about the reasoning in the [original RFC](https://github.com/backstage/backstage/issues/8729).
|
||||
|
||||
### Do I have to migrate to using package roles?
|
||||
|
||||
Short answer - yes.
|
||||
|
||||
Longer answer - mostly, you can get around having to declare the role of your packages by instead explicitly declaring the role in the command invocation or configuration. For example, the `app:build` command will go away, but you can replace it with `package build --role frontend` if you don't want to declare the role in `package.json` . It is however strongly recommended to declare the package roles.
|
||||
|
||||
### I have a package where none of the existing roles apply
|
||||
|
||||
The `web-library`, `node-library` and `common-library` roles are general purpose roles that should cover most use cases. If you feel like none of those roles work for you, then please open an issue in the [Backstage repo](https://github.com/backstage/backstage) and suggest the addition of a new role.
|
||||
|
||||
### Should I include the role in published packages?
|
||||
|
||||
Yes. While there is nothing that will consume the role at the moment, it is likely that future tooling will be able to provide a better experience for users when published packages include the role.
|
||||
@@ -43,9 +43,11 @@ backend:
|
||||
+ user: ${POSTGRES_USER}
|
||||
+ password: ${POSTGRES_PASSWORD}
|
||||
+ # https://node-postgres.com/features/ssl
|
||||
+ #ssl: require # see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
|
||||
+ #ca: # if you have a CA file and want to verify it you can uncomment this section
|
||||
+ #$file: <file-path>/ca/server.crt
|
||||
+ # you can set the sslmode configuration option via the `PGSSLMODE` environment variable
|
||||
+ # see https://www.postgresql.org/docs/current/libpq-ssl.html Table 33.1. SSL Mode Descriptions (e.g. require)
|
||||
+ # ssl:
|
||||
+ # ca: # if you have a CA file and want to verify it you can uncomment this section
|
||||
+ # $file: <file-path>/ca/server.crt
|
||||
```
|
||||
|
||||
If you have an `app-config.local.yaml` for local development, a similar update
|
||||
|
||||
Reference in New Issue
Block a user