Padronização (Idéia)
Antes de começar gostaria de enfatizar que nada disso é necessário, é somente um idéia, mas serve para aprender também.
Templates geram coisas e o ideal é gerar algo com um certo padrão que fique fácil de encontrar e relacionar as coisas dentro do backstage.
Para facilitar a procura de templates vamos organizá-los por tags. Podemos definir que um template precisa assumir uma das tags abaixo:
code
: Se for um template que irá gerar um esqueleto de código para desenvolvimento.infra
: Se for um template que irá gerar algum código infra as a code para criar um recurso.general
: O que não se encaixa em nenhum deles.
Podemos começar a observar um padrão já aqui.
- Cada template tem um docs com um index.md dentro explicando o que aquele template faz.
- Cada template é um repositório e tem o seu catalog-info.yaml que definirá o template e será obrigatório ter as tags acima propostas.
- Cada template definará o owner, sendo que este precisa ser um grupo já existente.
- Cada template tem uma pasta
template
com o conteúdo do que será modificado para gerar uma saída do esqueleto de código.
Para padronizar isso, resolvi criar esse gerador de template.
A idéia é criar um template que gera novos templates já com um certo padrão. Faça uma leitura desse repositório rapidamente para entender a proposta.
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: template-generator
title: Template to create template
description: Generator using basic organizational rules
annotations:
backstage.io/techdocs-ref: dir:. # Dentro do diretório teremos uma documentação para esse template
backstage.io/time-saved: PT4H
tags:
- general
spec:
owner: team-idp
type: ground
lifecycle: production
parameters:
- title: General Inputs
required:
- name
- owner
- principalTag
properties:
name:
# aqui teremos o nome do template que somente pode usar letras minusculas e -
title: Template Name
type: string
pattern: "^[a-z-]+$"
description: Template Name
ui:autofocus: true
ui:help: 'Only lowercase and dashes'
# o owner precisa existir no sistema e precisa ser do type team. Não vamos deixar um user ser o dono de nada no sistema, somente times.
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
spec.type: team
# A escola da tag principal que mensionamos acima.
principalTag:
title: General Tag
type: string
description: Principal Tag
default: general
enum:
- code
- infra
- general
ui:help: 'Used do Group'
# Uma lista de outras tagss que pode ser adicionada além da tag principal. Somente letras minusculas.
otherTags:
description: List of other tags (only lowercase letters and hyphen allowed)
type: array
items:
type: string
pattern: "^[a-z]+$"
ui:field: MultiTagInputField
uniqueItems: true
errorMessage:
properties:
name: 'Only lowercase and dashes can be used'
# Aqui eu simplesmente limitei que seja tudo na minha própria conta.
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
description: The prefix backstage-template- will be added automatically
type: string
ui:field: RepoUrlPicker
ui:help: |
SAME NAME GIVEN TO THE TEMPLATE
ui:options:
allowedHosts:
- github.com
- gitlab.com
allowedOrganizations:
- davidpuziol
allowedOwners:
- davidpuziol
# Uma entrada de documentação caso queira, mas não é necessário, isso pode ser feito depois no repositório que irá ser gerado.
- title: Documentation
properties:
description:
title: Write some description to be added to documentation
type: string
ui:widget: textarea
ui:options:
rows: 10
ui:placeholder: |
Do not forget write documentation!
steps:
- id: fetch-base
name: Fetch Base
action: fetch:template # Essa action é para popular o template com os nossos valores de entradas
input:
url: ./template
values:
name: ${{parameters.name}}
owner: ${{parameters.owner}}
principalTag: ${{parameters.principalTag}}
otherTags: ${{parameters.otherTags}}
description: ${{parameters.description}}
- id: publish
name: Publish
action: publish:github # publicar no repositório que escolhemos, mas vamos adicionar um prefixo backstage-template- ao nome do repositório escolhido.
input:
allowedHosts: ['github.com']
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl.split("repo=")[0] }}repo=backstage-template-${{ parameters.repoUrl.split("repo=")[1] }}
repoVisibility: private
- id: register
name: Register
action: catalog:register # Avisar ao backstage sobre esse repositório
input:
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
output:
links:
- title: Repository
url: ${{ steps['publish'].output.remoteUrl }} # mostrar a url de saida do repositório.
Tudo que vamos popular estará na pasta ./templates que neste caso é praticamente o mesmo código do template gerador, mas com algumas diferenças. Isso irá forçar que todo template tenha a estrutura abaixo.
A pasta ./template tem o seguinte:
❯ tree template
template
├── catalog-info.yaml # O próximo template, baseado no template pai.
├── docs # pasta de documentação
│ └── index.md # A documentação
└── template # plasta do template que ele irá gerar
└── main # primeiro arquivo avisando que é aqui que precisa colocar o conteúdo das coisas.
2 directories, 3 files
Dentro dessa pasta template o usuário precisa criar o seu component, recurso ou qualquer outra coisa. É aqui que tudo irá começar de fato. Poderíamos copiar arquivos para essa pasta baseado em alguma outra entrada que o tivesse no template principal.
Por exemplo, poderíamos já perguntar se é um component, um serviço, um recurso, etc. Dependento desta entrada vamos já adicionar um catalog-info.yaml ali com esse recurso pronto.
As vezes centralizar, como estamos fazendo para evitar muitos repositórios de estudo, pode ser uma estratégia caso a organização permita que somente um grupo finito de pessoas criem os templates.