Github Actions é um serviço relativamente novo e, ainda que em estágio beta, possui boa estabilidade. Ele permite que criemos workflows com jobs a serem executados a partir dos eventos disparados no Github. Então, por exemplo, sempre que um novo pull request é criado ou que um push é feito no Github, são exemplos de eventos que podem disparar a execução de workflows. Esse serviço favorece muito a implementação de integração e entrega contínua sem que haja a necessidade de sairmos do Github para serviços externos como Travis, CircleCI etc.
No caso específico do PHP podemos criar um workflow para que a cada novo push em determinado branch dispare a execução de um job para rodar os testes unitários do projeto, executar o PHPStan (analisador estático) e até mesmo executar o PHP Insights para avaliar a qualidade do código. Enfim, é possível executar qualquer ferramenta que faça sentido pro contexto do projeto.
Mas, há de ressaltar, o Github Actions é muito mais que isso. Possui uma infinidade de eventos que podem ser trabalhados. Nesse artigo focaremos na integração contínua de uma aplicação PHP tradicional, no sentido de rodar testes unitários, executar o PHPStan e o PHP Insights a cada novo push ou pull request a fim de garantir que o código esteja dentro dos parâmetros exigidos pela equipe antes dele ser incorporado. Mas o Github Actions pode ser usado para qualquer projeto de qualquer linguagem.
Curso Git e GitHub - Controle de versão
Conhecer o cursoNo que se baseia o Github Actions?
O Github Actions se baseia em Workflows que são fluxos de trabalho, por exemplo: Build, Teste e Publicação poderiam ser três tipos de workflows. Cada Workflow deve possuir um ou mais jobs. O Job refere-se à execução de uma tarefa, por exemplo, poderíamos em um workflow termos um job para dar build nos assets e outros job para executar os testes. É no workflow que configuramos quais eventos e ambientes (ubuntu, macOS etc) os nossos jobs serão executados. Em resumo, temos um workflow que possui N jobs e um job possui N steps (ações). Veremos isso na prática daqui a pouquinho, o que tornará mais fácil de visualizar a dinâmica da coisa toda.
O Github Actions é pago ou grátis?
É grátis para repositórios públicos e pago para repositórios privados com cobrança por minuto de execução. Na página do Github Actions você consegue visualizar melhor os detalhes de cobrança. Lembrando que enquanto estiver em fase beta o serviço estará grátis tanto para repositórios públicos quanto para privados.
O que eu preciso fazer para começar a usar?
Como o serviço ainda está em beta é preciso que você se inscreva para utilizá-lo. Basta que você esteja logado na sua conta do Github e então clicar no botão “Sign up for the beta”:
Depois é só confirmar:
O projeto de teste
Criei um projeto de uma classe e um método só, para que foquemos no assunto central do artigo, que se trata da criação de um Workflow de teste e validação do código do nosso projeto.
O nosso Workflow executará as seguintes ferramentas:
- PHPUnit
- PHPStan
- PHP Insights
Recomendo que você leia o artigo Ferramentas essenciais para um projeto PHP para conhecer um pouco mais sobre elas.
O projeto completo com o Workflow criado e ativo você pode visualizar em:
https://github.com/KennedyTedesco/github-actions-php
Antes de entrarmos na parte que toca a configuração do Workflow, primeiro quero mostrar o funcionamento visual dele lá no Github.
No projeto tem uma aba chamada Actions, clique nela:
Ela lista os Workflows configurados para o projeto. No nosso caso o workflow se chama “App Workflow”. Do lado direito temos a relação dos eventos que dispararam a execução dele. Ele foi disparado três vezes no evento de “push”, ou seja, quando subimos pro Github alterações.
No primeiro evento (de baixo pra cima) o workflow foi executado com sucesso, sem nenhum erro. Os testes passaram, o PHPStan não reportou nenhum erro e as métricas do PHP Insights estavam todas boas.
Já no segundo teste houve uma falha. Ah, o resultado da execução dos workflows também aparece na listagem dos commits:
https://github.com/KennedyTedesco/github-actions-php/commits/master
Observe os ícones de sucesso e erro.
Voltando na tela anterior, clique em um evento em que a execução do workflow teve sucesso, por exemplo, esse aqui:
É nessa tela que vemos os Jobs e suas Steps (passos onde ações são executadas). No caso, o Job “Tests” (à esquerda) executou todas as Steps (ações) da tela escura à direita. As ações que configuramos foram no sentido de definir o ambiente PHP em que a execução ocorrerá, instalação das dependências do Composer no projeto e execução das ferramentas de análise e teste.
O evento que causou falha na execução do workflow se deu por causa desse commit:
https://github.com/KennedyTedesco/github-actions-php/commit/9f6fb1142a5e2b98a2ecedd904eaa10301c1eb0e
Explicitamente fiz um teste falhar ao fazer ele comparar 4 === 8
.
Quando subi essa alteração para o Github, um evento de push
foi disparado fazendo executar o workflow, que então falhou:
Curso Git - Fundamentos
Conhecer o cursoDefinindo o Workflow no projeto
Agora que já vimos como funciona lá na interface do Github a parte visual da execução do workflow, veremos como de fato podemos criar-lo dentro do nosso projeto.
Primeiro de tudo, devemos criar uma pasta chamada .github
dentro do projeto. E, dentro dessa pasta, devemos criar uma pasta chamada workflows
.
- github-actions-php
- - .github
- - - workflows
- - - - main.yaml
É dentro da pasta workflows
que criamos os arquivos de definição dos nossos workflows. São arquivos yaml
. Criamos apenas um workflow, portanto teremos apenas um arquivo yaml nessa pasta e demos o nome dele de main.yaml
:
name: App Workflow
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
name: Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- name: Setting up PHP
uses: ./.github/actions/php
- name: Installing Composer
run: ./.github/scripts/run-composer.sh
- name: Running PHPStan
run: ./.github/scripts/run-phpstan.sh
- name: PHP Insights
run: ./.github/scripts/run-phpinsights.sh
- name: Running PHPUnit
run: ./.github/scripts/run-phpunit.sh
Esse é o nosso workflow completo. Em name
definimos o nome dele.
Em on
especificamos em quais eventos de quais branches esse workflow será executado. No caso, estamos dizendo que ele será executado sempre que um push
ou um pull request
for feito para o branch master
.
Em jobs
é onde definimos os jobs. No caso, temos apenas um job chamado build
, veja que na estrutura do yaml eu dei o nome de build
mas ao definir o nome dele lá pro Github eu o chamei de “Tests”:
build:
name: Tests
Isso não importa muito, você vai definir o nome que achar mais conveniente e lógico para o que você estiver executando. Eu poderia tranquilamente tê-lo chamado de:
tests:
name: Tests
Sem problema algum.
A diretiva runs-on
do job especifica em qual ambiente a execução acontecerá. O ideal é você escolher o mesmo ambiente que você roda em produção.
Em steps
é onde executamos as ações do job. Um job pode executar N ações. A action Checkout é padrão, é ela quem clona o projeto no ambiente de execução. Veja que ela possui um endereço do Github:
steps:
- name: Checkout
uses: actions/checkout@master
Ela é mantida pelo Github e pode ser visualizada aqui: https://github.com/actions/checkout
Ou seja, podemos executar actions que estejam em repositórios arbitrários. Existe todo um ecossistema de actions que podem ser reutilizadas. Existe até mesmo um Marketplace de Actions no próprio Github:
https://github.com/marketplace?type=actions
Também tem uma lista de centenas de actions mantidas pela comunidade:
https://github.com/sdras/awesome-actions
Voltando ao nosso workflow, a segunda action:
- name: Setting up PHP
uses: ./.github/actions/php
Ela especifica que se trata de um Dockerfile contido em ./.github/actions/php
que instalará a versão 7.3 do PHP que será usada para rodar os testes e validações:
https://github.com/KennedyTedesco/github-actions-php/tree/master/.github/actions/php
FROM php:7.3-cli-alpine
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
Ou seja, podemos criar actions baseadas em Dockerfiles.
A terceira action:
https://github.com/KennedyTedesco/github-actions-php/blob/master/.github/scripts/run-composer.sh
- name: Installing Composer
run: ./.github/scripts/run-composer.sh
Veja que ao invés de uses
ela especifica run
, pois estamos definindo qual comando ou arquivo ela deverá executar ao invés de qual action ela deverá usar.
Essa action é responsável pela instalação das dependências do composer no projeto. Nesse ponto já teremos o PHP configurado. Eu gosto de trabalhar com arquivos shell script para definir as tarefas que serão executadas. O conteúdo do arquivo run-composer.sh
é:
#!/bin/sh
cp .env.ci .env
composer install --no-ansi --no-interaction --no-suggest --prefer-dist
Ela copia o arquivo .env.ci
para .env
na raiz do projeto e depois instala as dependências. O arquivo env.ci
não tem nenhuma utilidade para o nosso projeto, eu deixei ele criado apenas para mostrar o que você pode fazer quando estiver criando um workflow para uma aplicação Symfony ou Laravel que use variáveis de ambiente. Nesse sentido, você pode ter variáveis de ambiente específicas para a execução do workflow.
Ao invés de executar o arquivo run-composer.sh
poderíamos ter executado esses comandos diretamente no yaml
do workflow, por exemplo:
- name: Installing Composer
run: |
cp .env.ci .env
composer install --no-ansi --no-interaction --no-suggest --prefer-dist
Mas eu prefiro definir arquivos shell script.
As últimas três ações rodam o PHPStan, PHP Insights e PHPUnit, respectivamente. Também são simples arquivos shell script. E com isso fechamos a configuração do nosso workflow.
Testando localmente as suas actions
Você pode usar a ferramenta act para localmente testar as suas actions. Incrível, não?
Concluindo
Eu encorajo que você leia a documentação e veja todos os recursos e opções disponíveis. Por exemplo, na página Workflow syntax for GitHub Actions tem muita informação valiosa sobre as outras sintaxes e opções.
E, não menos importante, quando você for criar um workflow para sua aplicação de maior porte, você certamente precisará lidar com a integração de variáveis de ambiente entre os jobs e actions, para isso, sugiro que você leia Virtual environments for GitHub Actions.
Como não dá pra masterizar o assunto em um artigo, tentei focar no essencial, no principal para uma aplicação PHP tradicional. Mas essas mesmas ideias podem ser agregadas para que você crie sua integração contínua para Laravel, Symfony ou outro framework qualquer. Sem contar que além do workflow de teste, você poderia ter um workflow para uma tarefa de corrigir o estilo do seu código e criar um pull request disso de forma automatizada, por exemplo. Como também poderia ter workflows para entrega/deploy contínuos. As possibilidades são muitas.
Até a próxima!