Backstage Software Templates

Tags: backstage
Published: 2021-04-13 21:37:28

Originally published on [mccricardo.com](https://mccricardo.com/backstage-software-templates/).

If our goal is to make our lives and the lives of those that work with us easier and happier, Backstage Software Templates can give us a hand. This tool can help us create Components inside Backstage that will load code skeletons, fill in some variables and publish that template somewhere.

## Let's get this party started

If you've been following along, in [Backstage intro](https://mccricardo.com/backstage-intro/) we set up our Backstage installation locally and, conveniently, bootstrapped a lot of components, including Software Templates. Let's right to it.

We'll start by selecting **Create Component**.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x00i1piod7bg5u6lrr00.png)

We'll then select **Golang Microservice**.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/isz3bpayqedtwju6k4mh.png)

We'll be displayed a form requesting some necessary information. We'll fill it in and click **Next Step**.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ssu746ddknsx1c04pa66.png)

A new form will be displayed that will allow us to set up VCS integration.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fxmwqj1bkyiutnz55dly.png)

At last, we will be shown a review and we can proceed with **Create**.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mdzxminl5sucpf9ymzt9.png)

And Backstage will do its magic.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/amqmcqxsav9602i4rbkv.png)

A new component will be created.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ho9he7eqkr5c5sdzydmm.png)

As well as a new repo with a lot of code.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4383kiunrf6fjgvzlcfh.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e2cdyvrbifbpdcqcfzud.png)

Let's take a moment to take a look around and let that sink in.

## What just happened?

Based on a template, Backstage was able to create a new repo, full of code and integrations. The setup we did in [Backstage intro](https://mccricardo.com/backstage-intro/) brought all of that free of charge. Taking a look at `app.config.yaml` we can see:

```yaml
catalog:
  rules:
    - allow: [Component, System, API, Group, User, Template, Location]
  locations:
    - type: url
      target: https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml
      rules:
        - allow: [Template]
```

This points to the following template:

```yaml
apiVersion: backstage.io/v1alpha1
kind: Template
metadata:
  name: golang-starter
  title: Golang Microservice
  description: Create a Golang repo with this template built by members of the Go community
  tags:
    - experimental
    - go
spec:
  owner: web@example.com
  templater: cookiecutter
  type: service
  path: "."
  schema:
    required:
      - component_id
      - project_short_description
      - docker_image
      - docker_build_image
      - docker_build_image_version
      - use_logrus_logging
      - use_viper_config
      - use_ci
      - use_cobra_cmd
    properties:
      component_id:
        title: Name
        type: string
        description: Unique name of the component
      project_short_description:
        title: Description
        type: string
        description: Description of the component
      docker_image:
        title: Docker Image
        type: string
        description: The docker base image to use when running the service
        default: alpine-base-image:latest
      docker_build_image:
        title: Docker Build Image
        type: string
        description: The docker base image to use when building the service
        default: golang
      docker_build_image_version:
        title: Docker Build Image Version
        description: The image version to use when building the service
        type: string
        enum:
          - alpine
        default: alpine
      use_logrus_logging:
        title: Enable Logrus Logging (https://github.com/sirupsen/logrus)
        type: string
        enum:
          - "y"
          - "n"
        default: "y"
      use_viper_config:
        title: Enable Viper Config (https://github.com/spf13/viper)
        type: string
        enum:
          - "y"
          - "n"
        default: "y"
      use_cobra_cmd:
        title: Enable Cobra CLI Tools (https://github.com/spf13/cobra)
        type: string
        enum:
          - "y"
          - "n"
        default: "y"
      use_ci:
        title: Add CI
        description: Add a CI config to the repo, Gitub Actions, Circle or Travis are the only supported right now
        type: string
        enum:
          - github
          - travis
          - circle
          - none
        default: github
```

Now something has to interpret this and do some magic. This is where `packages/backend/src/plugins/scaffolder.ts` comes into play:

```js
import { SingleHostDiscovery } from '@backstage/backend-common';
import { CatalogClient } from '@backstage/catalog-client';
import {
  CookieCutter,
  CreateReactAppTemplater,
  createRouter,
  Preparers,
  Publishers,
  Templaters
} from '@backstage/plugin-scaffolder-backend';
import Docker from 'dockerode';
import { Router } from 'express';
import type { PluginEnvironment } from '../types';

export default async function createPlugin({
  logger,
  config,
  database,
  reader,
}: PluginEnvironment): Promise<Router> {
  const cookiecutterTemplater = new CookieCutter();
  const craTemplater = new CreateReactAppTemplater();
  const templaters = new Templaters();

  templaters.register('cookiecutter', cookiecutterTemplater);
  templaters.register('cra', craTemplater);

  const preparers = await Preparers.fromConfig(config, { logger });
  const publishers = await Publishers.fromConfig(config, { logger });

  const dockerClient = new Docker();

  const discovery = SingleHostDiscovery.fromConfig(config);
  const catalogClient = new CatalogClient({ discoveryApi: discovery });

  return await createRouter({
    preparers,
    templaters,
    publishers,
    logger,
    config,
    dockerClient,
    database,
    catalogClient,
    reader
  });
}
```

`@backstage/plugin-scaffolder-backend` through `CookieCutter` *"knows"* how to bootstrap Golang projects based on [cookiecutter-golang](https://github.com/lacion/cookiecutter-golang). And that's how all the magic happens.

Eventually, we will need to [add our own templates](https://backstage.io/docs/features/software-templates/adding-templates) and we will need help [writing them](https://backstage.io/docs/features/software-templates/writing-templates). And if the [builtin actions](https://backstage.io/docs/features/software-templates/builtin-actions) are not enough this might include writing [custom actions](https://backstage.io/docs/features/software-templates/writing-custom-actions).

Backstage Software Templates takes a big leap into providing standardization and help teams become more productive faster.