Delete old scaffolder docs
Co-authored-by: Ben Lambert <ben@blam.sh> Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
@@ -1,101 +0,0 @@
|
||||
---
|
||||
id: extending-preparer
|
||||
title: Create your own Preparer
|
||||
description: Documentation on Creating your own Preparer
|
||||
---
|
||||
|
||||
Preparers are responsible for reading the location of the definition of a
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template) and
|
||||
making a temporary folder with the contents of the selected skeleton.
|
||||
|
||||
Currently, we provide two different providers that can parse two different
|
||||
location protocols:
|
||||
|
||||
- `file://`
|
||||
- `github://`
|
||||
|
||||
These two are added to the `PreparersBuilder` and then passed into the
|
||||
`createRouter` function of the `@backstage/plugin-scaffolder-backend`.
|
||||
|
||||
A full example backend can be found in
|
||||
[`scaffolder.ts`](https://github.com/backstage/backstage/blob/d91c10f654475a60829fa33a5c81018e517a319a/packages/backend/src/plugins/scaffolder.ts),
|
||||
but it looks something like the following
|
||||
|
||||
```ts
|
||||
import {
|
||||
createRouter,
|
||||
FilePreparer,
|
||||
GithubPreparer,
|
||||
Preparers,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
import type { PluginEnvironment } from '../types';
|
||||
|
||||
export default async function createPlugin({ logger }: PluginEnvironment) {
|
||||
const preparers = new Preparers();
|
||||
|
||||
const filePreparer = new FilePreparer();
|
||||
const githubPreparer = new GithubPreparer();
|
||||
|
||||
preparers.register('file', filePreparer);
|
||||
preparers.register('github', githubPreparer);
|
||||
|
||||
return await createRouter({
|
||||
preparers,
|
||||
templaters,
|
||||
logger,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
As you can see in the above code, a `PreparerBuilder` is created, and then two
|
||||
of the `preparers` are registered with the different protocols that they accept.
|
||||
|
||||
The `protocol` is set on the
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template)
|
||||
when added to the service catalog. You can see more about this `PreparerKey`
|
||||
here in [Register your own template](../adding-templates.md)
|
||||
|
||||
**note:** Currently the catalog supports loading definitions from GitHub + Local
|
||||
Files, which translate into the two `PreparerKeys`: `file` and `github`. To load
|
||||
from other places, not only will there need to be another preparer, but the
|
||||
support to load the location will also need to be added to the Catalog.
|
||||
|
||||
### Creating your own Preparer to add to the `PreparerBuilder`
|
||||
|
||||
All preparers need to implement the `PreparerBase` type.
|
||||
|
||||
That type looks like the following:
|
||||
|
||||
```ts
|
||||
export type PreparerBase = {
|
||||
prepare(
|
||||
template: TemplateEntityV1alpha1,
|
||||
opts: { logger: Logger },
|
||||
): Promise<string>;
|
||||
};
|
||||
```
|
||||
|
||||
The `prepare` function will be given the
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template)
|
||||
along with the source of where the `template.yaml` was loaded from under the
|
||||
`metedata.annotations.managed-by-location` property.
|
||||
|
||||
Now it's up to you to implement a function which can go and fetch the skeleton
|
||||
and put the contents into a temporary directory and return that directory path.
|
||||
|
||||
Some good examples exist here:
|
||||
|
||||
- https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts
|
||||
- https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts
|
||||
|
||||
### Registering your own Preparer
|
||||
|
||||
You can register the preparer that you have created with the `PreparerBuilder`
|
||||
by using the `PreparerKey` from the Catalog, for example like this:
|
||||
|
||||
```ts
|
||||
const preparers = new Preparers();
|
||||
preparers.register('gcs', new GoogleCloudStoragePreparer());
|
||||
```
|
||||
|
||||
And then pass this into the `createRouter` function.
|
||||
@@ -1,96 +0,0 @@
|
||||
---
|
||||
id: extending-publisher
|
||||
title: Create your own Publisher
|
||||
description: Documentation on Creating your own Publisher
|
||||
---
|
||||
|
||||
Publishers are responsible for pushing and storing the templated skeleton after
|
||||
the values have been templated by the `Templater`. See
|
||||
[Create your own templater](./create-your-own-templater.md) for more info.
|
||||
|
||||
They receive a directory or location where the templater has successfully run
|
||||
and is now ready to store somewhere. They also are given some other options
|
||||
which are sent from the frontend, such as the `storePath` which is a string of
|
||||
where the frontend thinks we should save this templated folder.
|
||||
|
||||
Currently we provide the following `publishers`:
|
||||
|
||||
- `github`
|
||||
|
||||
This publisher is passed through to the `createRouter` function of the
|
||||
`@backstage/plugin-scaffolder-backend`. Currently, only one publisher is
|
||||
supported, but PR's are always welcome.
|
||||
|
||||
An full example backend can be found
|
||||
[here](https://github.com/backstage/backstage/blob/d91c10f654475a60829fa33a5c81018e517a319a/packages/backend/src/plugins/scaffolder.ts),
|
||||
but it looks something like the following
|
||||
|
||||
```ts
|
||||
import {
|
||||
createRouter,
|
||||
GithubPublisher,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
import type { PluginEnvironment } from '../types';
|
||||
|
||||
export default async function createPlugin({ logger }: PluginEnvironment) {
|
||||
const githubClient = new Octokit({ auth: process.env.GITHUB_TOKEN });
|
||||
const publisher = new GithubPublisher({ client: githubClient });
|
||||
|
||||
return await createRouter({
|
||||
publisher,
|
||||
logger,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The publisher will always be called with the location from the selected
|
||||
`Preparer`.
|
||||
|
||||
### Create your own Publisher and register it with the Scaffolder
|
||||
|
||||
All `publishers` need to implement the `PublisherBase` type.
|
||||
|
||||
That type looks like the following:
|
||||
|
||||
```ts
|
||||
export type PublisherBase = {
|
||||
publish(opts: {
|
||||
entity: TemplateEntityV1alpha1;
|
||||
values: TemplaterValues;
|
||||
directory: string;
|
||||
}): Promise<{ remoteUrl: string }>;
|
||||
};
|
||||
```
|
||||
|
||||
The `publisher` function will be called with an `options` object which contains
|
||||
the following:
|
||||
|
||||
- `entity` - the
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template)
|
||||
which is currently being scaffolded
|
||||
- `values` - a json object which will resemble the `spec.schema` from the
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template)
|
||||
which is defined here under spec.schema`. More info can be found here
|
||||
[Register your own template](../adding-templates.md#adding-form-values-in-the-scaffolder-wizard)
|
||||
- `directory` - a string containing the returned path from the `templater`. See
|
||||
more information here in
|
||||
[Create your own templater](./create-your-own-templater.md)
|
||||
|
||||
Now it's up to you to implement the `publish` function and return
|
||||
`{ remoteUrl: string }` which can be used to identify the finished product.
|
||||
|
||||
Some good examples exist here:
|
||||
|
||||
- https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts
|
||||
|
||||
### Registering your own Publisher
|
||||
|
||||
Currently, we only support one `publisher` (PR's welcome), but you can register
|
||||
any single `publisher` with the `createRouter`.
|
||||
|
||||
```ts
|
||||
return await createRouter({
|
||||
publisher: new MyGitlabPublisher(),
|
||||
});
|
||||
```
|
||||
@@ -1,151 +0,0 @@
|
||||
---
|
||||
id: extending-templater
|
||||
title: Creating your own Templater
|
||||
description: Documentation on Creating your own Templater
|
||||
---
|
||||
|
||||
Templaters are responsible for taking the directory path for the skeleton
|
||||
returned by the preparers, and then executing the templating command on top of
|
||||
the file and returning the completed template path. This may or may not be the
|
||||
same directory as the input directory.
|
||||
|
||||
They also receive additional values from the frontend, which can be used to
|
||||
interpolate into the skeleton files.
|
||||
|
||||
Currently we provide the following templaters:
|
||||
|
||||
- `cookiecutter`
|
||||
|
||||
This templater is added to the `TemplaterBuilder` and then passed into the
|
||||
`createRouter` function of the `@backstage/plugin-scaffolder-backend`
|
||||
|
||||
An full example backend can be found
|
||||
[here](https://github.com/backstage/backstage/blob/d91c10f654475a60829fa33a5c81018e517a319a/packages/backend/src/plugins/scaffolder.ts),
|
||||
but it looks something like the following
|
||||
|
||||
```ts
|
||||
import {
|
||||
CookieCutter,
|
||||
createRouter,
|
||||
Templaters,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
import type { PluginEnvironment } from '../types';
|
||||
|
||||
export default async function createPlugin({ logger }: PluginEnvironment) {
|
||||
const templaters = new Templaters();
|
||||
const cookiecutterTemplater = new CookieCutter();
|
||||
templaters.register('cookiecutter', cookiecutterTemplater);
|
||||
|
||||
return await createRouter({
|
||||
templaters,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
As you can see in the above code a `TemplaterBuilder` is created and the default
|
||||
`cookiecutter` `templater` is registered under the key `cookicutter`.
|
||||
|
||||
This `TemplaterKey` is used to select the correct templater from the
|
||||
`spec.templater` in the
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template).
|
||||
|
||||
If you wish to add a new templater, you'll need to register it with the
|
||||
`TemplaterBuilder`.
|
||||
|
||||
### Creating your own Templater to add to the `TemplaterBuilder`
|
||||
|
||||
All templaters need to implement the `TemplaterBase` type.
|
||||
|
||||
That type looks like the following:
|
||||
|
||||
```ts
|
||||
export type TemplaterRunOptions = {
|
||||
directory: string;
|
||||
values: TemplaterValues;
|
||||
logStream?: Writable;
|
||||
dockerClient: Docker;
|
||||
};
|
||||
|
||||
export type TemplaterBase = {
|
||||
run(opts: TemplaterRunOptions): Promise<TemplaterRunResult>;
|
||||
};
|
||||
```
|
||||
|
||||
The `run` function will be given a `TemplaterRunOptions` object which is as
|
||||
follows:
|
||||
|
||||
- `directory`- the skeleton directory returned from the `Preparer`, more info at
|
||||
[Create your own preparer](./create-your-own-preparer.md).
|
||||
- `values` - a json object which will resemble the `spec.schema` from the
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template)
|
||||
which is defined here under spec.schema`. More info can be found here
|
||||
[Register your own template](../adding-templates.md#adding-form-values-in-the-scaffolder-wizard)
|
||||
- `logStream` - a stream that you can write to for displaying in the frontend.
|
||||
- `dockerClient` - a [dockerode](https://github.com/apocas/dockerode) client to
|
||||
be able to run docker containers.
|
||||
|
||||
_note_ Currently the templaters that we provide are basically Docker action
|
||||
containers that are run on top of the skeleton folder. This keeps dependencies
|
||||
to a minimum for running Backstage scaffolder, but you don't _have_ to use
|
||||
Docker. You can `pip install cookiecutter` to run it locally in your backend.
|
||||
You could create your own templater that spins up an EC2 instance and downloads
|
||||
the folder and does everything using an AMI if you want. It's entirely up to
|
||||
you!
|
||||
|
||||
Now it's up to you to implement the `run` function, and then return a
|
||||
`TemplaterRunResult` which is `{ resultDir: string }`.
|
||||
|
||||
Some good examples exist here:
|
||||
|
||||
- https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/src/scaffolder/stages/templater/cookiecutter.ts
|
||||
|
||||
### Registering your own Templater
|
||||
|
||||
If you try to process a
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template)
|
||||
with a new `spec.templater` value, you'll need to register that with the
|
||||
`TemplaterBuilder`.
|
||||
|
||||
For example let's say you have the following
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template):
|
||||
|
||||
```yaml
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Template
|
||||
metadata:
|
||||
name: react-ssr-template
|
||||
title: React SSR Template
|
||||
description:
|
||||
Next.js application skeleton for creating isomorphic web applications.
|
||||
tags:
|
||||
- recommended
|
||||
- react
|
||||
spec:
|
||||
owner: web@example.com
|
||||
templater: handlebars
|
||||
type: website
|
||||
path: '.'
|
||||
schema:
|
||||
required:
|
||||
- component_id
|
||||
- description
|
||||
properties:
|
||||
component_id:
|
||||
title: Name
|
||||
type: string
|
||||
description: Unique name of the component
|
||||
description:
|
||||
title: Description
|
||||
type: string
|
||||
description: Description of the component
|
||||
```
|
||||
|
||||
You see that the `spec.templater` is set as `handlebars`, so you'll need to
|
||||
register this with the `TemplaterBuilder` like so:
|
||||
|
||||
```ts
|
||||
const templaters = new Templaters();
|
||||
templaters.register('handlebars', new HandlebarsTemplater());
|
||||
```
|
||||
|
||||
And then pass this into the `createRouter` function.
|
||||
@@ -1,90 +0,0 @@
|
||||
---
|
||||
id: extending-index
|
||||
title: Extending the Scaffolder
|
||||
---
|
||||
|
||||
Welcome. Take a seat. You're at the Scaffolder Documentation.
|
||||
|
||||
So, you want to create stuff inside your company from some prebaked templates?
|
||||
You're at the right place.
|
||||
|
||||
This guide is going to take you through how the Scaffolder in Backstage works.
|
||||
We'll dive into some jargon and run through what's going on in the backend to be
|
||||
able to create these templates. There's also more guides that you might find
|
||||
useful at the bottom of this document. At its core, there are 3 simple stages.
|
||||
|
||||
1. Pick a skeleton
|
||||
2. Template some variables into the skeleton
|
||||
3. Send the templated skeleton somewhere
|
||||
|
||||
These three steps are translated to the following stages under the hood in the
|
||||
scaffolder that you will need to know:
|
||||
|
||||
1. Prepare
|
||||
2. Template
|
||||
3. Publish
|
||||
|
||||
Each of these steps can be configured for your own use case, but we provide some
|
||||
sensible defaults, too.
|
||||
|
||||
Let's dive a little deeper into these phases.
|
||||
|
||||
### Glossary and Jargon
|
||||
|
||||
**Preparer** - The preparer is responsible for fetching the skeleton code and
|
||||
placing it into a directory and then will return that directory. It is
|
||||
registered with the `Preparers` with a particular type, which is then used in
|
||||
the router to pick the correct `Preparer` to run for the `Template` entity.
|
||||
|
||||
**Templater** - The templater is responsible for actually running the chosen
|
||||
templater on top of the previously returned temporary directory from the
|
||||
**Preparer**. We advise making these Docker containers as it can keep all
|
||||
dependencies--for example Cookiecutter--self contained and not a dependency on
|
||||
the host machine.
|
||||
|
||||
**Publisher** - The publisher is responsible for taking the finished directory,
|
||||
and publishing it to a remote registry. This could be a Git repository or
|
||||
something similar. Right now, the scaffolder only supports one publishing method
|
||||
for the entire lifecycle, but it could be configured from the frontend and
|
||||
passed through to the scaffolder backend.
|
||||
|
||||
### How it works
|
||||
|
||||
Most of the heavy lifting is done in the
|
||||
[router.ts](https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/src/service/router.ts#L93)
|
||||
file in the `scaffolder-backend` plugin.
|
||||
|
||||
There are two routes defined in the router: `POST /v1/jobs` and
|
||||
`GET /v1/job/:jobId`
|
||||
|
||||
To create a scaffolding job, a JSON object containing the
|
||||
[Template Entity](../../software-catalog/descriptor-format.md#kind-template) +
|
||||
additional templating values must be posted as the post body.
|
||||
|
||||
```js
|
||||
{
|
||||
"template": {
|
||||
"apiVersion": "backstage/v1alpha1",
|
||||
"kind": "Template",
|
||||
// more stuff here
|
||||
},
|
||||
"values": {
|
||||
"component_id": "test",
|
||||
"description": "somethingelse"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The values should represent something that is valid with the `schema` part of
|
||||
the [Template Entity](../../software-catalog/descriptor-format.md#kind-template)
|
||||
|
||||
Once that has been posted, a job will be setup with different stages, and the
|
||||
job processor will complete each stage before moving onto the next stage, whilst
|
||||
collecting logs and mutating the running job.
|
||||
|
||||
Here's some further reading that you might find useful:
|
||||
|
||||
- [Adding your own Template](../adding-templates.md)
|
||||
- [Creating your own Templater](./create-your-own-templater.md)
|
||||
- [Creating your own Publisher](./create-your-own-publisher.md)
|
||||
- [Creating your own Preparer](./create-your-own-preparer.md)
|
||||
Reference in New Issue
Block a user