Skip to content

Commit

Permalink
Update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ScottGuymer committed Sep 5, 2024
1 parent da4ba9a commit 1f14078
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 58 deletions.
59 changes: 45 additions & 14 deletions docs/appendix/part-2-code.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Part 2 - Action Code

Below is the code for the
Below is the code for the action that we will be creating in this exercise. This
action will download a random cat image from the Cat API and save it to the
workspace.

```typescript
// Imports
import { createTemplateAction } from "@backstage/plugin-scaffolder-node";
import fs from "fs";
import { Readable } from "stream";
import { ReadableStream } from "stream/web";
Expand All @@ -18,21 +20,50 @@ export interface CatResult {
height: number;
}

// handler function
ctx.logger.info(
`Running example template with parameters: ${ctx.input.myParameter}`
);
/**
* Creates an `acme:example` Scaffolder action.
*
* @remarks
*
* See {@link https://example.com} for more information.
*
* @public
*/
export function createAcmeExampleAction() {
// For more information on how to define custom actions, see
// https://backstage.io/docs/features/software-templates/writing-custom-actions
return createTemplateAction<{
myParameter: string;
}>({
id: "catscanner:randomcat",
description: "Downloads a random cat image into the workspace",
schema: {
input: {
type: "object",
required: [],
properties: {},
},
},
async handler(ctx) {
ctx.logger.info(
`Running example template with parameters: ${ctx.input.myParameter}`
);

const catResult = await fetch("https://api.thecatapi.com/v1/images/search");
const catResult = await fetch(
"https://api.thecatapi.com/v1/images/search"
);

const catData: Record<string, CatResult> = await catResult.json();
const catData: Record<string, CatResult> = await catResult.json();

const stream = fs.createWriteStream(
path.join(ctx.workspacePath, "catimage.jpeg")
);
const { body } = await fetch(catData[0].url);
const stream = fs.createWriteStream(
path.join(ctx.workspacePath, "catimage.jpeg")
);
const { body } = await fetch(catData[0].url);

await finished(Readable.fromWeb(body as ReadableStream).pipe(stream));
await finished(Readable.fromWeb(body as ReadableStream).pipe(stream));

ctx.logger.info("Cat image downloaded");
ctx.logger.info("Cat image downloaded");
},
});
}
```
9 changes: 9 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ Once you have a running installation we can move to the first exercise!
and 7007. The codespace is mapping the ports to your local ports. Ensure
you have no other processes running on those ports.

??? Note Node 20

If you are running node 20 you will need to set the `NODE_OPTIONS=--no-node-snapshot`
environment variable to prevent the node process from crashing.

You can do this in a few ways, such as running
`NODE_OPTIONS=--no-node-snapshot yarn dev` each time you start the app, or
by adding it to the `dev` script in the `package.json`.

## Authentication

For this workshop we will need to authenticate with GitHub in order to create
Expand Down
20 changes: 8 additions & 12 deletions docs/part-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,7 @@ which will automatically register the actions and make them available to us. We
need to add the following in `packages/backend/src/index.ts`

```typescript
import gitHubActions from "@backstage/plugin-scaffolder-backend-module-github";
...
backend.add(gitHubActions());
backend.add(import("@backstage/plugin-scaffolder-backend-module-github"));
```

Now, we can then use the actions we just installed in our template and create a
Expand All @@ -116,19 +112,19 @@ a new repo using the `publish:github` action. Add the following to your

!!! tip "Refreshing Template Changes"

The changes may not be immediately visible. You can the refresh the template by
going to the catalog, changing the "kind" filter to "Template", clicking on your
template and then clicking the refresh button in the about card.
The changes may not be immediately visible. You can the refresh the template
by going to the catalog, changing the "kind" filter to "Template", clicking
on your template and then clicking the refresh button in the about card.

Now, go to your template, enter the repo details and it should create a new repo
in GitHub for you.

??? Warning "Authentication"

Authentication is needed to enable your backstage to log into GitHub and create your repo.
If you are having issues go back to the Authentication section in Getting Started and ensure
you have a valid token. You will not be able to create new repos in philips-internal as by
default it tries to create public repos.
Authentication is needed to enable your backstage to log into GitHub and
create your repo. If you are having issues go back to the Authentication
section in Getting Started and ensure you have a valid token. You will only
be able to make repos in an org that you have access to create public repos.

The above package installed a lot more actions than just the `publish:github`,
[you can browse the rest of the available templates here](http://localhost:3000/create/actions).
38 changes: 25 additions & 13 deletions docs/part-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ Congratulations, you have created a new scaffolder plugin!

You can see what other plugin types there are by running `yarn new`.

## Register your plugin
## Install your plugin

The plugin won't do much on its own, we need to register it in the backend so
The plugin won't do much on its own, we need to install it in the backend so
that it gets loaded correctly.

Firstly, add your package as a reference to the
Expand Down Expand Up @@ -112,22 +112,34 @@ and you should see `acme:example` in the list. (we will change this later!)
## Write your action

Now we need to write our action. This is the code that will be executed when the
action is run as part of a template.
action is run as part of a template. We are going to use `example.ts` in our
plugin as a starting point.

First, update the definition of the action, changing the ID and description and
removing the required inputs and properties definitions. We don't need them
(yet). Your definition should something look like this:
(yet). Your call to `createTemplateAction` should something look like this:

```typescript
id: 'catscanner:randomcat',
description: 'Downloads a random cat image into the workspace',
schema: {
input: {
type: 'object',
required: [],
properties: {},
return createTemplateAction<{
myParameter: string;
}>({
id: "catscanner:randomcat",
description: "Downloads a random cat image into the workspace",
schema: {
input: {
type: "object",
required: [],
properties: {},
},
},
},
async handler(ctx) {
ctx.logger.info(
`Running example template with parameters: ${ctx.input.myParameter}`
);

await new Promise((resolve) => setTimeout(resolve, 1000));
},
});
```

Now need to implement the action code in the `handler` function in
Expand All @@ -143,7 +155,7 @@ log using `ctx.logger.info`.

!!! tip "Unit Testing"

You should write unit tests for your action using the
You can and should write unit tests for your action using the
[instructions in the backstage docs](https://backstage.io/docs/features/software-templates/writing-tests-for-actions).

## Use it in a template
Expand Down
54 changes: 35 additions & 19 deletions docs/part-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ We will create a new folder in `plugins/catscanner-react/src/components` to hold
all of the files related to the extension. lets call this `RandomCatPix`.

```bash
cd backstage/
mkdir -p plugins/catscanner-react/src/components/RandomCatPix
```

Expand All @@ -80,9 +81,20 @@ component and the validation. These files are:
- extensions.ts - contains the registration of the extension
- index.ts - exports the extension to be used in the frontend

Create the file `RandomCatPixExtension.tsx` with the following contents. This is
the skeleton of our actual UI component and we will come back and extend this
with our implementation later.
We can create all these files by running the following commands:

```bash
# go to the root of the react plugin
cd backstage/plugins/catscanner-react
touch src/components/RandomCatPix/RandomCatPixExtension.tsx \
src/components/RandomCatPix/validation.ts \
src/components/RandomCatPix/schema.ts \
src/components/RandomCatPix/extensions.ts \
src/components/RandomCatPix/index.ts
```

`RandomCatPixExtension.tsx` - This is the skeleton of our react UI component and
we will come back and extend this with our implementation later.

??? example "RandomCatPixExtension.tsx"

Expand Down Expand Up @@ -113,9 +125,9 @@ with our implementation later.
};
```

Create the file `validation.ts` with the following contents. This is the
validation of the output of the component. Inside this function, you can check
the value of the field and return an error if it is not valid.
`validation.ts` - This is the validation of the output of the component. Inside
this function, you can check the value of the field and return an error if it is
not valid.

??? example "validation.ts"

Expand All @@ -133,9 +145,9 @@ the value of the field and return an error if it is not valid.
) => {};
```

Create the file `schema.ts` with the following contents. The schema is optional,
it allows backstage to know how to render this component, what inputs it takes.
This enables the previewing of the component in the Custom Field Explorer.
`schema.ts` - The schema is optional, it allows backstage to know how to render
this component, what inputs it takes. This enables the previewing of the
component in the Custom Field Explorer.

??? example "schema.ts"

Expand All @@ -152,13 +164,11 @@ This enables the previewing of the component in the Custom Field Explorer.
};
```

Now we need to create an `extensions.ts` file that will create the Field
Extension registration. This brings together the ID, React component and
`extensions.ts` - this will create the Field Extension registration that will be
recognized by backstage. This brings together the ID, React component and
validation into a single component that we will make available to the
scaffolder.

Create the `extensions.ts` file with the following contents.

??? example "extensions.ts"

```typescript
Expand All @@ -179,8 +189,8 @@ Create the `extensions.ts` file with the following contents.
);
```

Now we need to export the component from the plugin by modifying the following
files
Now we need to export the component from the plugin by modifying the `index.ts`
in the `RandomCatPix` folder and in the components folder.

```typescript
// plugins/catscanner-react/src/components/RandomCatPix/index.ts
Expand All @@ -206,9 +216,10 @@ UI code that we will use to get a random cat image and display it for the user.
You will want to look at the `useEffect` and `useState` react hooks to allow you
to trigger the request to the API and store the result.

You must also call the `onChange` function passed as a property to pass any
output value along to the template. So you should call this each time change the
rendered cat image.
You must also call the `onChange` function passed as a props to notify backstage
of the output value you want to use in the template. This does not have to be
what you render directly in the UI, for example you can pass an ID but render a
friendly name. So you should call this each time change the rendered cat image.

!!! tip

Expand All @@ -219,6 +230,9 @@ rendered cat image.
You do this in `packages/app/src/App.tsx`. You need to provide the
`customFieldExtensions` as children to the `ScaffolderPage`.

In `App.tsx` you should find a section that looks like this, where the
scaffolder route is setup.

```tsx
const routes = (
<FlatRoutes>
Expand All @@ -229,7 +243,9 @@ const routes = (
);
```

Should be changed to look something like this
Currently it is empty as we do not have any custom UI components, only the built
in ones. We need to change the setup to take in our new custom field extension
so that the scaffolder is aware of it.

```tsx
import { ScaffolderFieldExtensions } from "@backstage/plugin-scaffolder-react";
Expand Down

0 comments on commit 1f14078

Please sign in to comment.