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:
Johan Haals
2021-02-26 21:40:29 +01:00
parent 43ff002754
commit 296bba9910
4 changed files with 0 additions and 438 deletions
@@ -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)