Integração contínua (CI) no GitHub Actions em projetos Java
Produzir software de qualidade é uma tarefa difícil pois exige constante investigação e manutenção para mantê-lo funcionando corretamente durante o passar do tempo. A integração contínua é uma técnica de desenvolvimento que busca acelerar a detecção de bugs e problemas de integração, utilizando um repositório de código único para mesclar o código fonte desenvolvido por cada programador da equipe e executando o build do software a cada push.
Para facilitar a automação de todos os fluxos de trabalho de software é que surgiu o GitHub Actions, através dele podemos criar, testar e implantar nosso software sem maiores dificuldades.
O ecossistema do Java é muito rico e conta com diversas ferramentas para que um código de qualidade seja produzido, vamos utilizar algumas dessas ferramentas para nos fornecer um feedback sobre a qualidade do nosso código e até mesmo quebrando nosso build em caso de falhas em algumas etapas.
Ferramentas Utilizadas
- 
Apache Maven
 
Apache Maven é uma ferramenta de gerenciamento e compreensão de projetos de software. Com base no conceito de modelo de objeto de projeto (POM), o Maven pode gerenciar a construção, o relatório e a documentação de um projeto a partir de uma informação central.
- 
JaCoCo
 
JaCoCo é uma biblioteca de cobertura de código Java gratuita distribuída sob a Licença Pública Eclipse.
- 
SonarQube
 
O SonarQube é uma plataforma de código aberto desenvolvida pela SonarSource para inspeção contínua da qualidade do código, para executar revisões automáticas com análise estática do código para detectar bugs, odores de código e vulnerabilidades de segurança.
- 
DockerHub
 
Docker Hub é o maior repositório do mundo de imagens de contêiner com uma variedade de fontes de conteúdo, incluindo desenvolvedores de comunidades de contêineres, projetos de código aberto e fornecedores de software independentes (ISV) construindo e distribuindo seu código em contêineres. Os usuários têm acesso a repositórios públicos gratuitos para armazenamento e compartilhamento de imagens ou podem escolher um plano de assinatura para repositórios privados.
- 
JUnit
 
JUnit é uma estrutura simples para escrever testes repetíveis. É uma instância da arquitetura xUnit para estruturas de teste de unidade.
Integrações
Algumas ferramentas mencionadas acima estão hospedadas na nuvem, portanto precisaremos criar uma conta de acesso e gerar um token para que seja possível realizar a integração do GitHub com as ferramentas.
Configuração do Token de acesso ao DockerHub
O artefato gerado pela nossa aplicação será uma imagem docker e a mesma será armazenada no repositório de imagens do DockerHub.
Faça um cadastro no DockerHub e execute os passos abaixo para gerar um token de acesso.
Configuração do Token de acesso ao SonarCloud
Utilizaremos o SonarCloud para realizar analise estática dos nossos códigos fontes.
Faça um cadastro no SonarCloud e execute os passos abaixo para gerar um token de acesso.
Armazenando os Tokens dos serviços no GitHub
Configurando o Projeto Java
Vamos adicionar os seguintes plugins no Maven que são responsáveis por gerar as estatísticas de cobertura do código fonte, realizar a integração com o SonarQube e também gerar a nossa imagem Docker.
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.6</version>
    <executions>
        <execution>
            <id>prepare-agent</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.sonarsource.scanner.maven</groupId>
    <artifactId>sonar-maven-plugin</artifactId>
    <version>3.7.0.1746</version>
    <executions>
        <execution>
            <phase>verify</phase>
            <goals>
                <goal>sonar</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>2.6.0</version>
    <configuration>
        <from>
            <image>openjdk:15-jdk-slim-buster</image>
        </from>
        <to>
            <image>gasparbarancelli/blog:${project.version}</image>
            <auth>
                <username>
                    ${env.DOCKERHUB_USERNAME}
                </username>
                <password>
                    ${env.DOCKERHUB_TOKEN}
                </password>
            </auth>
        </to>
        <container>
            <jvmFlags>
                <jvmFlag>-Xms256m</jvmFlag>
                <jvmFlag>-Xmx512m</jvmFlag>
            </jvmFlags>
            <mainClass>io.github.gasparbarancelli.blog.BlogApplication</mainClass>
        </container>
    </configuration>
</plugin>
Configurando o GitHub Actions
Agora o passo mais importante, acessar o nosso repositório no GitHub e configurar uma nova Action.
A nossa Action vai conter os 4 seguintes jobs:
- 
Compilar o código fonte
 - 
Executar os testes
 - 
Gerar as estatísticas de cobertura de testes e também realizar a integração com o SonarCloud para analise estática do código fonte
 - 
Realizar o build da aplicação e criar uma imagem Docker publicando a mesma no DockerHub
 
Segue o código fonte da Action contendo os jobs mencionados acima, observe o uso das Secrets que adicionamos no GitHUb, em nenhum momento passamos os valores dos tokens.
name: Java CI with Maven
on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]
jobs:
  compile:
    runs-on: ubuntu-latest
    name: Compile
    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK 15
      uses: actions/setup-java@v1
      with:
        java-version: 15
    - name: Compile code
      run: mvn -B compile
  test:
    runs-on: ubuntu-latest
    name: Tests
    needs: compile
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 15
        uses: actions/setup-java@v1
        with:
          java-version: 15
      - name: Run unit tests
        run: mvn -B test
  analysis:
    runs-on: ubuntu-latest
    name: Analysis and Coverage
    needs: test
    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 15
        uses: actions/setup-java@v1
        with:
          java-version: 15
      - name: Integrate with sonarcloud
        run: mvn -B org.jacoco:jacoco-maven-plugin:prepare-agent verify sonar:sonar -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml -Dsonar.projectKey=gasparbarancelli_blog -Dsonar.organization=gasparbarancelli -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=${{secrets.SONARCLOUD_TOKEN}}
        env:
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
  build:
    runs-on: ubuntu-latest
    name: Build and Deliver
    needs: analysis
    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK 15
      uses: actions/setup-java@v1
      with:
        java-version: 15
    - name: Build Project, create docker image and send image to dockerhub
      env:
        DOCKERHUB_USERNAME: ${{secrets.DOCKERHUB_USERNAME}}
        DOCKERHUB_TOKEN: ${{secrets.DOCKERHUB_TOKEN}}
      run: mvn -B package jib:build -DskipTests
Resultado Final
Ao executarmos um push na Branch master o Action criado acima será executado e os seguintes resultados são esperados.