Integração contínua (CI) no GitHub Actions em projetos Java

Por Gaspar Barancelli Junior em 04 de abril de 2024

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.

4
5
6

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.

7
8

Armazenando os Tokens dos serviços no GitHub

3
13

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.

1
2

A nossa Action vai conter os 4 seguintes jobs:

  1. Compilar o código fonte

  2. Executar os testes

  3. 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

  4. 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.

9
10
11
12

// Compartilhe esse Post