Wesley Egberto
Posted on October 2, 2021
Github Actions nos permite automatizar, customizar e executar workflows do desenvolvimento de software diretamente no repositório do projeto.
Podemos:
- rodar o build continuamente
- executar testes automatizados a cada push
- executar processo de CI completo
- executar processo de CD para diversas clouds e ambientes
O Github Actions possui uma ampla biblioteca de Actions que nos permites executar diversos tipos de ações (desde simples build da aplicação até o build da sua imagem Docker e deploy no seu cluster Kubernetes na AWS).
Os jobs do Github Actions são orientados à eventos, isso significa que você pode configurar a execução de determinado job a partir de uma determinada ação (push, PR, merge) no seu repositório.
O Github Actions possui uma camada free que nos disponibiliza um tempo de execução mensal dos jobs e um período de retenção dos logs de forma limitada, detalhes podem ser acessados aqui.
No plano Enterprise do Github, é possível adicionar processo de aprovação em ambientes no workflow a fim de limitar quem pode fazer o quê em determinados ambientes.
Componentes
Workflows
Um workflow é um procedimento declarado e automatizado que adicionamos no repositório através de um arquivo YAML.
Um workflow é composto de um ou mais jobs que podem ser agendados ou iniciados por um ou mais eventos.
Events
Um evento é uma ação específica que pode disparar um ou mais jobs dos workflows declarados no repositório.
Essa ação pode ser um push, PR ou merge efetuado no repositório.
Na documentação do Github, tem a lista de ações disponíveis que podemos utilizar para disparar um workflow.
Job
Um job é composto por um ou mais steps que executam em um mesmo runner de forma sequencial a partir de determinado evento.
Abaixo segue o diagrama mostrando a estrutura do job:
Um workflow com mais de um job pode rodá-los em paralelos ou de forma sequencial, caso seja configurado.
Actions
Action são comandos isolados que são combinados em steps para criar um job.
Uma Action é o menor nível portável de um workflow, podemos criar e reutilizar Actions através de nossos repositórios ou compartilhar com a comunidade.
Um Action sempre estará dentro de um step para poder ser executado no workflow.
Runner
Um runner é um server que tem a runner application do Github Actions instalada.
Podemos utilizar um runner hospedado pelo Github ou em nossa própria infraestrutura.
Um runner busca jobs disponíveis, roda-os e reporta o progresso, logs e resultados para o repositório no Github.
Estrutura do Workflow
O workflow é declarado em um arquivo YAML com um esquema de declaração do Github Actions para definir os eventos, jobs e seus steps.
Esse arquivo YAML fica armazenado junto à aplicação no repositório do Github e em seu próprio diretório, localizado em .github/workflows/
.
Quando ocorre um push no repositório, o Github verifica se existe a pasta de workflows e, caso exista algum arquivo YAML, é criado os workflows no repositório.
Componentes do Workflow
Abaixo seguem alguns campos que podem ser utilizados no arquivo de workflow.
-
name
: campo opcional que define o nome do workflow que será exibido no repositório. -
on
: campo que define os eventos que irão disparar o seu workflow. -
jobs
: campo que define os jobs deste workflow. O job tem os seguintes campos:-
runs-on
: define o runner do job. -
steps
: declara os steps do job. O step tem os seguintes campos: -
uses
: define qual action será utilizada neste step do job. -
with
: podemos configurar alguns atributos que são utilizadas pela action definida. -
run
: define o commando que será executado no runner.
-
Na documentação do Github podemos ver toda sintaxe disponível para construir um workflow.
Primeiro Exemplo
Abaixo segue um exemplo de workflow (arquivo .github/workflows/sample.yml
):
name: Github Exemplo
on: [push]
jobs:
check-bats-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm install -g bats
- run: bats -v
No workflow declaramos, em on: [push]
, que deverá rodar sempre que ocorrer um push em qualquer branch do repositório.
Também é possível limitar as branches que queremos utilizar no disparo do workflow, exemplo:
on:
push:
branches:
- main # executa nos pushes na main
- 'releases/**' # executa nas branches com prefixo `releases/`
Na documentação do Github podemos ver a variedade de opções de ações que podemos utilizar para disparar um workflow.
No workflow também definimos o nosso workflow a executar os seguintes passos:
-
uses: actions/checkout@v2
: efetua o git clone do nosso repositório; -
uses: actions/setup-node@v2
: utiliza um action para configurar o Nodejs v14; -
run: npm install -g bats
: executa o Npm install para instalar o bats globalmente; -
run: bats -v
: executa o bats instalado anteriomente.
Perceba que os steps do job são executados sequencialmente e os steps seguintes dependem do step anterior.
Isso mostra que o estado do nosso runner é compartilhado dentro do job, logo, podemos instalar e configurar o runner para utilizar tudo que o nosso projeto dependa para fazer build e publicação.
Alguns exemplos:
- configurar o Docker
- configurar credenciais da nossa cloud
- configurar versões das linguagens e ferramentas
Na aba Actions do repositório no Github é possível visualizar a execução desse workflow.
Exemplo de Workflow Completo
Para concretizar melhor o poder de introduzir o Github Actions no seu ciclo de vida de desenvolvimento de software.
Vamos visualizar um exemplo de uma aplicação Java onde queremos definir um CI que faça o build, teste e publicação do nosso artefato gerado.
O nosso projeto está utilizando o Maven como gerenciado de dependências e de build. Nele temos configurado os plugins necessários para executar os testes e gerar um relatório do resultado da execução e da cobertura em HTML. Também temos configurado o nosso repositório de artefatos para utilizar o Github Artifacts.
Passos executados pelo workflow:
- faça o build da aplicação
- rode os testes da aplicação
- armazene o resultado dos testes para podemos consultar posteriomente
- efetuar publicação do nosso artefado construído para o repositório
Workflow
Abaixo segue o arquivo que define nosso workflow com os comentários demonstrados suas capactidades:
name: Java Workflow Example - Build, Test and Deploy
# configuramos para rodar apenas quando houver um push na master
on:
push:
branches:
- master
jobs:
# `build` é o nome do job
build:
# nome para exibir no repositório
name: Build, Test and Deploy
# utilizamos uma instância do ubuntu como runner
runs-on: ubuntu-latest
steps:
# utilizamos a action checkout para fazer o git clone no runner
- uses: actions/checkout@v2
# utilizamos a action setup-java para configurar a versão necessária do JDK
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: 11
architecture: x64
# aqui podemos configurar um cache para cachear as dependências do projeto,
# isso vai permitir que as próximas execuções do workflow sejam mais rápidas
# visto que as dependências já estarão disponibilizadas para o runner
# nota: utilizamos um hash do arquivo POM.xml, então quando o alterarmos,
# as dependências são baixadas novamente
- name: Cache Maven packages
uses: actions/cache@v2
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
# aqui apenas definimos o commando para executar no runner
- name: Maven Test
run: mvn test
# aqui criamos a pasta para armazenar o relatório dos testes
- run: mkdir coverage-report && cp -r target/site/jacoco/* coverage-report
# aqui utilizamos um action para registrar o resultado do teste no nosso workflow,
# caso ocorra alguma falha em algum teste, ficará explicito nos logs de execução aba Actions
- name: Publish Test Report
if: ${{ always() }}
uses: scacap/action-surefire-report@v1
# aqui utilizamos um action para fazer a publicação do relatório de testes,
# esse relatório pode ser baixado nos detalhes de execução do workflow
- uses: actions/upload-artifact@v2
with:
name: Test Coverage Report
path: coverage-report
# fazemos construção e publicação do artefato construído
- name: Maven Build and Publish
run: mvn -B deploy
env:
# com estamos utilizado o Github Artifact, passamos o token do repositório para fazer upload
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# copiamos o artefato construído para uma pasta específica
- run: mkdir dist && cp target/*.jar dist
# aqui fazemos o publicação do artefato para que possa ser baixado nos detalhes de execução do workflow
- uses: actions/upload-artifact@v2
with:
name: Package
path: dist
O workflow acima é bem útil visto que tem todo nosso ciclo de desenvolvimento junto ao repositório, facilitando a visualização e entendimento de todos.
Após executar o workflow podemos ver o seu resultado, como no exemplo abaixo:
E o Github também nos disponibiliza algumas páginas que nos permite construir alguns dashboards para incluir no README do nosso repositório, facilitando a visualização do histórico e estado atual do projeto.
O projeto de exemplo utilizado aqui pode ser acessado no seus repositório no Github, nele está o projeto Java e outros workflows que utilizei em diferentes testes.
Conclusão
O Github Actions é uma ferramenta bem interessante, muito versátil e de fácil customização e utilização.
A grande vantagem que vejo é a enorme biblioteca de Actions disponbilizada pela comunidade e por fornecedores (Oracle, Microsoft, Google, Github, etc) que nos permitem fazer qualquer passo necessário.
E por estar toda definida com uma sintaxe de fácil leitura e junto ao projeto, o ciclo de desenvolvimento fica claro para todos que estão na equipe, desde o estagiário até o sênior, o que facilita o onboarding e o compartilhamento de informações no time.
Referências
Posted on October 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.