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 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.
We’ll then select Golang Microservice.
We’ll be displayed a form requesting some necessary information. We’ll fill it in and click Next Step.
A new form will be displayed that will allow us to set up VCS integration.
At last, we will be shown a review and we can proceed with Create.
And Backstage will do its magic.
A new component will be created.
As well as a new repo with a lot of code.
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 brought all of that free of charge. Taking a look at app.config.yaml
we can see:
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:
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:
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. And that’s how all the magic happens.
Eventually, we will need to add our own templates and we will need help writing them. And if the builtin actions are not enough this might include writing custom actions.
Backstage Software Templates takes a big leap into providing standardization and help teams become more productive faster.