Configurando CI/CD com Github Actions e Firebase App Distribution para projetos Android
Denis Vieira
Posted on May 12, 2020
A integração contínua (CI) e a implantação contínua (CD) são os primeiros passos para começarmos a automatizar e agilizar o nosso processo de desenvolvimento. Dessa forma, temos certeza de que nosso código é sempre verificado, testado e atende aos nossos padrões de qualidade antes de ser implantado.
Atualmente, existem várias ferramentas que podem nos ajudar a automatizar tudo isso. Um dos mais populares são Jenkins, GitLab, Travis CI, CircleCI ou Fastlane. Mas agora para nossa felicidade o queridinho do open source, o Github, entrou no jogo com o GitHub Actions.
No Github existe um marketplace que contém varios Apps e Actions disponíveis para adicionarmos grandes poderes em nossos projetos e o melhor é que são facilmente acopláveis e desacopláveis com simples configurações. Estes itens funcionam como extensões ou plugins que automatizam varias tarefas importantes para nosso projeto e também são open-source e desenvolvidos por vários desenvolvedores. Para nosso setup utilizaremos as actions, Checkout para realizar o checkout do nosso repositório, setup-java para configurar o Java JDK e Firebase App Distribution para finalmente enviarmos nossa APK para o Firebase.
Então, vamos lá.
Primeiramente, vá na aba "Actions" no repositorio do projeto android que desejamos automatizar, após iremos no link "setup a workflow yourself" para criar a nossa própria configuração através do proprio editor do Github, lembrando que após finalizar o arquivo de todos os workflows é preciso realizar o commit dele, mas se desejar você também pode fazer manualmente no seu editor de código pessoal, para isso precisamos apenas criar uma pasta na raiz do seu projeto com o nome ".github" e dentro dela criar outra pasta com nome "workflows" e nela adicionaremos todos os nossos arquivos de workflow.
Baseando na necessidade de criar um setup para aplicar um workflow baseado em no Git Feature Branch, iremos basicamente criar 2 workflows, o "Pull Requests CI" que irá iniciar quando houver um novo pull request para Master ou branch de release, verificando se os testes passam, rodando build e gerando uma APK que será armazenada no Github Artifacts para testes funcionais de uma nova feature ou bug desenvolvido e o "Master Release CI" que irá rodar quando houver alguma atualização na Master ou branch de release, fazendo as mesmas verificações mas dessa vez enviando a APK de release para o Firebase App Distribution.
Obs: Fique a vontade para utilizar qualquer nome para seus workflows, Jobs e Steps deste post, os utilizados são só sugestões baseadas na minha necessidade atual.
Vamos iniciar então criando o Pull Requests CI, primeiramente iremos configurar em que caso iremos rodar esse workflow, nesse caso em todos os pull requests criados para as branchs "master" ou "release..".
name: Pull Requests CI
on:
pull_request:
branches:
- 'master'
- 'release*'
Agora iremos configurar os Jobs que irão ser executados. Cada Job pode ter vários Steps, e é nesses Steps que iremos configurar o que precisamos para chegar a cada resultado.
Então, partindo do principio que se os testes não passarem não precisar rodar mais nada. O Primeiro Job que iremos configurar será o de testes. Neste Job basicamente precisamos de um ambiente Ubuntu e configurar o JDK 1.8 como pré-requisitos, então para esse Job temos esses dois Steps definidos pelo nome "set up JDK 1.8" e "Unit tests" e em "runs-on" definimos o ambiente "Ubuntu-latest". Tendo nosso primeiro Job Ficando dessa forma:
# Um workflow é composto de um ou mais Jobs que podem ser executados sequencialmente ou em paralelo
jobs:
# Este Workflow contém dois Jobs chamados "test" e "build-and-deploy"
test:
name: Run Unit Tests
# O tipo de runner em que o job será executado
runs-on: ubuntu-latest
# Steps representam a sequencia de tarefas usando shell runners que serão executadas como parte do Job
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Unit tests
run: bash ./gradlew test --stacktrace
Agora iremos configurar nosso Job principal o "build-and-generate-apk", nesse Job iremos configurar os Steps "set up JDK 1.8", "Install NDK", "Build Debug" e "Upload APK on Github Artifact" onde disponibilizaremos para um Q.A, P.O ou por você mesmo a APK para teste da Feature ou Bug antes de ser mergeado. Tendo nosso Job ficando dessa forma:
build-and-generate-apk:
# O tipo de runner em que o job será executado
runs-on: ubuntu-latest
# Steps representam a sequencia de tarefas usando o shell runners que serão executadas no como parte do Job
steps:
- uses: actions/checkout@v1
# Step para Configurar o JDK
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
# Step para instalar o NDK
- name: Install NDK
run: echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;20.0.5594570"
# Step para Buildar o Projeto e gerar a APK
- name: Build Debug
run: ./gradlew assembleDebug
# Step para salvar a APK como Artifacts
- name: Upload APK on Build Artifacts
uses: actions/upload-artifact@v1
with:
name: app
path: app/build/outputs/apk/debug/app-debug.apk
Pronto, agora toda vez que criamos um Pull Request, a Pipeline é iniciada com esse Workflow.
E ao final dela temos uma apk para teste gerada e disponível para realizar um teste funcional de uma feature para um testar uma nova funcionalidade.
Segue o link do arquivo final deste workflow:
Tendo pronto nosso primeiro workflow que tratará nosso primeiro processo de desenvolvimento, o Pull Request. Agora iremos configurar o "Master Release CI" que irá iniciar sempre que ocorrer uma atualização em nossa branch principal, no caso a "master" ou alguma outra branch com iniciais "release".
Então primeiramente iremos criar um novo arquivo .yml de para esse nosso novo workflow, decidi batizar de "master-release-ci.yml". Iniciando configurando o caso em que iremos iniciar esse workflow, adicionamos o código abaixo para que a pipeline só inicie apenas para os casos de quando ocorrer uma atualização nessas branchs.
name: Master Release CI
on:
push:
branches:
- 'master'
- 'release*'
Neste workflow na parte configuração dos Jobs e Steps apenas o que difere seria adicionar o Step de "upload artifact to Firebase App Distribution", onde iremos fazer o upload do artefato gerado no build para o Firebase Distribuition, e para isso precisaremos realizar algumas configurações com o Firebase, se caso você ainda não tiver configurado o Firebase em seu projeto Android siga as instruções do Link da Documentação Oficial.
Com seu aplicativo configurado, iremos entrar em nosso projeto no console do firebase e acessar a sessão de "App Distribution", lá adicionaremos nosso Android app e ele já estará disponível para enviarmos uma apk e distribuir para os testers e grupos que quisermos. Com isso você já pode fazer upload de seus apks manualmente e distribuir para grupos facilmente, também é possível fazer upload localmente de qualquer apk através do FIREBASE CLI seguindo as instruções da Documentação Oficial.
Para realizarmos este procedimento automaticamente via Github Actions e em uma pipeline confiável, precisamos gerar algumas credenciais antes. O "FIREBASE APP ID" e "FIREBASE TOKEN".
O Firebase App ID é facilmente encontrado na Aba de indo em Project Overview -> Selecionar Settings do App Android já Configurado -> E lá embaixo em "Your apps" copiamos a hash do App Id. Ex.:"1:1234567890:android:0a1b2c3d4e5f67890"
Para adquirir o Firebase Token é necessário utilizar o Firebase CLI para realizar algumas actions locais em sua máquina, se você ainda não tem configurado, veja como instalar no seguinte Link da Documentação Oficial.
Com o Firebase CLI instalado, iremos configura-lo para utilizar nossa conta do Firebase utilizando o comando:
firebase login:ci
Este comando irá abrir uma nova janela de autenticação do google no browser (caso não abra automaticamente, haverá um link que você poderá ver na linha comando), após autenticar com sua conta com sucesso, você verá a mensagem "✔ Success! Use this token to login on a CI server:" e logo abaixo verá uma hash que é o nosso "Firebase Token" e que deverá ser usado em nosso arquivo de workflow do github actions.
Como o Firebase App Id e Firebase Token são credenciais é importante que não a deixemos expostas diretamente no código, então iremos configura-lá como "Secrets" do projeto e assim deixando-os dinâmicos e realmente ofuscados.
Para configurar os "Secrets" de um projeto vá até a parte de Settings do seu repositório e haverá uma aba de "Secrets". Seguindo simplesmente vamos em "Add a new secret" e adicionamos as duas que precisamos, o FIREBASE_APP_ID e FIREBASE_TOKEN, com seus respectivos valores que adquirimos nas etapas anteriores.
Agora com as credenciais que precisamos em mãos e configuradas no projeto, vamos voltar para nosso arquivo de configuração do workflow. Nele agora iremos adicionar nosso único Job com os steps necessários para build e geração da apk, acrescentando o novo Step que servirá para enviar a Apk para o Firebase Distribuition automaticamente. Sendo assim nosso Job fica da exata maneira abaixo:
# Um workflow é composto de um ou mais Jobs que podem ser executados sequencialmente ou em paralelo
jobs:
# Este Workflow contém um único Job chamado "build-and-deploy"
build-and-deploy:
# O tipo de runner em que o job será executado
runs-on: ubuntu-latest
# Steps representam a sequencia de tarefas usando o shell runners que serão executadas no como parte do Job
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
# Step para Instalar o NDK
- name: Install NDK
run: echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;20.0.5594570"
# Step para Buildar o Projeto e gerar a APK
- name: build debug apk
run: ./gradlew assembleDebug
# Step para Enviar a APK gerada para o Firebase App Distribution
- name: upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1.2.1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: testers
file: app/build/outputs/apk/debug/app-debug.apk
Segue o link do arquivo final deste workflow:
E pronto ! Agora temos o que precisamos para realizar uma entrega integrada, continua e centralizada para todas as partes interessadas apenas seguindo um fluxo de desenvolvimento simples. Por favor comente suas dúvidas, sugestões e compartilhe sua experiência.
Segue o link de um projeto antigo open source que apliquei as configurações deste artigo.
Próximo Passo:
- Configurar para gerar apk de release com a keystore
Estes workflows ainda são muito simples, mas pretendo criar novos posts adicionando alguns outros jobs ou steps também muito importantes, como linters, sonarqube, relatórios de testes e rodar instrumented tests com Firebase Test Lab. Segue ai e fica ligado !!
Observações:
- Mesmo enviando o apk automaticamente para o Firebase Distribuition através do Actions ainda é necessário que você vá até o console do Firebase na sessão de App Distribuition e realize a distribuição para o grupo que desejar.
- Por padrão as release notes são preenchidas com a descrição do último commit, mas é possível modifica-lá antes de realizar a sua distribuição.
Referências:
Posted on May 12, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.