Criando uma GitHub Action com Node.js

Gustavo Salvador
devmuch
Published in
5 min readAug 14, 2020
Photo by Richy Great on Unsplash

Nesse post irei demonstrar como construir uma Action com Node.js, processo que no geral é simples e lhe dá autonomia para não se limitar ao uso de Actions preexistentes que não façam exatamente o que você precise. Automatizaremos como exemplo uma ação sempre realizada ao abrirmos um pull request em alguns repositórios da DM: atribuí-lo para o usuário que o criou.

Não irei entrar em detalhes sobre a feature Actions do GitHub pois a documentação deles é bem completa, vale recorrer para entender alguns conceitos/encontrar mais exemplos.

A Action é uma aplicação que realiza uma tarefas como lint, testes, deploy a partir de um evento como o push em uma branch ou criação de uma nova tag. É possível organizar e combinar as Actions, compondo um workflow: nele está definido quais Actions/comandos serão executados, quando e como. As regras do workflow ficam definidas em um arquivo de configuração YAML, encontrado no caminho .github/workflows/ de um repositório no GitHub.

Ela pode ser desenvolvida em qualquer linguagem, desde que executável via Docker. Iremos construir a nossa Action com Node.js, que segue um processo diferente e principalmente por ser executada em menor tempo que uma Action de container Docker.

Picard já dizia. GitHub

Partindo de um repositório público clonado localmente e configurado via $ npm init, o primeiro passo é criar um arquivo action.yml de metadata da Action na raiz do projeto:

action.yml

Os primeiros campos definem como a sua Action irá aparecer no Marketplace do GitHub ao ser publicada. Em inputs estão os parâmetros, cujos valores são definidos no arquivo de um workflow que irá usar esta Action. O input token será utilizado para se comunicar com a API do GitHub via Octokit. Neste caso, iremos usar o token padrão disponibilizado pela Actions, ${{ github.token }}. Em runs, definimos qual a versão do Node.js a utilizar e qual o arquivo de entrada da aplicação. Esse é o básico para seguirmos, mas recomendo conferir a documentação do arquivo de metadata para conhecer os outros campos disponíveis.

É obrigatório que sua Action possua um README.md, então crie algo como:

README.md

O GitHub disponibiliza um toolkit para simplificar a construção das Actions. Nele se encontram diversos pacotes, dentre os quais usaremos dois:

Instale-os com $ npm i --save @actions/core @actions/github.

Crie uma pasta src/ e dentro dela, o arquivo index.js:

src/index.js

Este arquivo será o entrypoint da aplicação, lendo inputs e executando ações de acordo. O código lê o input com getInput() e executa uma função handle(), falhando a Action via setFailed() com uma mensagem em caso de erro.

Agora, crie o arquivo github.js dentro de src/. Nele, iremos definir a função handle(), que irá criar um Octokit e executar assign(). É interessante dividir as responsabilidades aqui para poder verificar o context.eventName e executar diferentes funções a partir de seu conteúdo.

Dentro dessa função, iremos utilizar a API de Pull Request para buscar os dados do PR atual. O context do Octokit possui informações sobre a execução do workflow e do evento que gerou o trigger; mais especificamente, possui o payload completo do webhook da API. Os eventos são diversos, mas há exemplos e listagem das propriedades de cada evento na documentação.

Neste cenário, só estamos interessados em PRs. Então faremos uma verificação na função handle(), lançando um erro se for outro evento. Em context conseguimos obter os valores de owner, repo e number para utilizar como parâmetros de addAssignees(), junto com actor.

O pacote do Toolkit possui a função addAssignees, que possui o mesmo efeito prático que um POST no caminho /repos/:owner/:repo/issues/:issue_number/assignees na API REST v3 do GitHub. Utilizaremos-a em assign():

src/github.js

Veja que para realizarmos assign para um usuário específico, bastaria adicionar um novo campo em inputs no arquivo action.yml representando o nome do usuário e usar esse valor em assignees. Seguindo essa ideia, poderíamos usar outras funções do Octokit como pull.createReviewComment() para criar um comentário ou issues.addLabels() para adicionar labels ao PR.

Para a Action poder ser executada, é preciso que o repositório possua todas suas dependências. Como uma alternativa a subir o node_modules/, iremos utilizar a ferramenta @zeit/ncc para compilar o código e os pacotes em um .js único. Instale com $ npm i --save-dev @zeit/ncc. Para facilitar a execução, adicione o NPM script em package.json:

package.json

E crie um .gitignore para não subir os pacotes:

.gitignore

Execute o script, suba suas alterações no GitHub e gere uma tag:

O GitHub recomenda alguns padrões de versionamento, mas um simples v1 já nos permite utilizar a Action em outro projeto. Para isso, basta adicionar um arquivo de workflow, ex. pull-request.yml em .github/workflows/ do repo com o seguinte conteúdo (lembre-se de substituir os campos em <>):

.github/workflows/pull-request.yml

Efetuando o merge deste código na branch principal, ao abrir um PR você receberá o assign automaticamente 👌.

Se acessar a página do repositório da Action, virá esse botão para gerar um release e publicar a Action no Marketplace. Se pretende compartilhar sua Action com outras pessoas, é interessante que o faça.

Esse exemplo foi inspirado na Action Auto assign PR and request review, disponível no GitHub da Delivery Much. Além de auto assign para abertura de pull requests, é possível solicitar review para uma lista de usuários e times. Fique a vontade para usá-la 😉

Espero que com esse exemplo prático você consiga ter ideias para automatizar algum processo nos projetos que você trabalhe. Há diversas possibilidades, como podemos ver na Awesome Actions e nesta Action que permite você jogue xadrez no seu repositório ♟.

Stay home!

--

--