Skip to main content

Configuração/Cobertura de Código com SonarCloud

Este guia tem como objetivo ajudar na configuração do SonarCloud em projetos multi-repo e monorepo, integrando-os com o GitHub Actions para rodar testes, gerar relatórios e enviá-los ao SonarCloud. Siga os passos abaixo para configurar corretamente em seu projeto.

1. Criando um Projeto no SonarCloud

  • Acesse o SonarCloud e faça login pela sua conta do GitHub que está na organização da DigitalSys
  • Clique em “+” no menu superior e selecione “Analyze new project”

  • Certifique que em “organization” esteja selecionada a organização da DigitalSys e escolha o repositório que deseja analisar
  • Se estiver configurando para um projeto monorepo, selecione a opção "Setup a <u>monorepo</u>" e escolha o repositório do seu projeto

  • Após selecionar seu projeto, clique em “Set Up”
  • Na página seguinte, escolha o critério para o que será considerado novo código para as próximas análises
  • Selecione “Previous version” para que cada nova versão do código no GitHub seja analisada
  • Por fim, crie seu projeto clicando em “Create Project”

2. Adicionando Token do SonarCloud ao GitHub

  • Após Criar o projeto, selecione “With GitHub Actions” para o método de análise

  • Na página seguinte copie o Sonar Token gerado

  • No repositório do GitHub, vá para Settings > Secrets and variables > Actions

  • No nome do Secret escreva SONAR_TOKEN e em secret cole o Token gerado pelo SonarCloud
  • Por fim, Clique em “Add secret” para criar o Secret

3. Configurando o SonarCloud no Projeto

  • Voltando para a página do SonarCloud podemos acessar as informações do projeto no menu lateral clicando no botão “Information”
  • Essa página contem as chaves de projeto e de organização

  • Essas chaves devem estar presente em um arquivo sonar-project.properties na raiz do seu projeto, da seguinte forma
sonar.projectKey=DigitalsysTecnologia_exemplo
sonar.organization=digitalsys
  • Caso o projeto analisado seja monorepo, além do arquivo de propriedades da raiz, cada módulo deve conter seu próprio sonar-project.properties, alterando entre eles o sonar.projectKey para o informado no seu repositório próprio do SonarCloud
  • No arquivo de propriedades do SonarCloud também podem ser definidas algumas configurações, as mais utilizadas são:

<colgroup><col style="width: 262px;"></col><col style="width: 356px;"></col><col style="width: 417px;"></col></colgroup> COMANDO

DESCRIÇÃO

EXEMPLO

sonar.projectKey

Identificador único do projeto no SonarCloud

sonar.projectKey=my_project_key

sonar.organization

Nome da organização no SonarCloud

sonar.organization=my_organization

sonar.sources

Diretório(s) onde o código-fonte está localizado. Pode ser múltiplo, separado por vírgulas

sonar.sources=src

sonar.tests

Diretório(s) onde os testes estão localizados. Pode ser múltiplo, separado por vírgulas

sonar.tests=tests

sonar.language

Linguagem de programação principal do projeto

sonar.language=java

sonar.exclusions

Arquivos ou diretórios a serem excluídos da análise

sonar.exclusions=**/*.xml

sonar.inclusions

Especifica quais arquivos ou diretórios incluir na análise, se for diferente dos padrões

sonar.inclusions=src/**/*.java

sonar.tests.inclusions

Especifica quais arquivos de teste incluir na análise

sonar.tests.inclusions=tests/**/*.java

sonar.test.exclusions

Arquivos ou diretórios de teste a serem excluídos da análise

sonar.test.exclusions=tests/helpers/**

sonar.coverage.exclusions

Arquivos ou diretórios a serem excluídos da análise de cobertura de código

sonar.coverage.exclusions=src/main/resources

sonar.go.coverage.reportPaths

Caminho para o arquivo do relatório de cobertura de testes para projetos em Golang

sonar.go.coverage.reportPaths=reports/*coverage*.out

sonar.python.coverage.reportPaths

Caminho para o arquivo do relatório de cobertura de testes para projetos em Python

sonar.python.coverage.reportPaths=reports/*coverage*.out

Mais comandos podem ser encontrados na Documentação do SonarCloud

Exemplo de arquivo sonar-project.properties comum

sonar.projectKey=DigitalsysTecnologia_exemplo
sonar.organization=digitalsys

sonar.qualitygate.wait=true

sonar.sources=.
sonar.python.coverage.reportPaths=reports/coverage.xml

sonar.coverage.exclusions=**/tests/**,Dockerfile

4. Configurando Workflow do GitHub Actions

  • No repositório do projeto, crie um arquivo “.github/workflows/”
  • Dentro dessa pasta, crie um arquivo YAML, por exemplo, ci.yml
  • Nesse arquivo podemos definir ações que serão executadas pelo GitHub em definidas mudanças no repositório

Primeiro, podemos definir o nome do nosso workflow e quando ele será executado

name: Main Workflow

on:
push:
branches:
- '**'
pull_request:
types: [opened, synchronize, reopened]

Com esse código definimos um workflow chamado Main Workflow que será executado sempre que houver um push em qualquer branch do projeto e sempre que um pull request for aberto, sincronizado ou reaberto

Agora podemos criar as ações que serão executadas nos momentos definidos na primeira parte do código. Em nosso caso precisamos:

  1. Gerar o relatório de cobertura de testes;
  2. Enviar para análise do SonarCloud;

Para cada ação precisamos especificar os passos do zero, então para gerar o relatório de testes precisamos iniciar o projeto como se estivéssemos o executando pela primeira vez, o exemplo abaixo apresenta os passos necessários para rodar um projeto em Python, dês de configurar a versão do Python que será utilizada até o comando para se gerar o arquivo do relatório pelo GitHub Actions

jobs:          
run-tests:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.12

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r ./requirements.txt

- name: Run tests
run: |
pytest tests --cov=./ --cov-report=xml:reports/coverage.xml

- name: Store test reports
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: ./reports/coverage.xml
retention-days: 1
if-no-files-found: error

Nesse código estamos criando um “job” chamado run-tests, nele começamos baixando uma versão compatível com o projeto do Python e baixamos suas dependências. No exemplo foi gerado a cobertura de testes pelo pytest, utilizando a flag --cov-report=xml:reports/coverage.xml, que está armazenando o arquivo de relatório em reports/coverage.xml

Por fim, utilizamos o “actions/upload-artifact” para armazenar o relatório, o tornando acessível para os próximos jobs

Agora podemos criar um novo job, com o objetivo de enviar o relatório gerado para a análise do SonarCloud

sonar-scan:
needs: run-tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Download coverage artifact
uses: actions/download-artifact@v4
with:
name: coverage-report
path: ./reports/

- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

É importante definir que esse job possui dependência no anterior (needs: run-tests), pois se não eles irão ser executados em paralelo, porém precisamos esperar o artefato da primeira ação ser gerado

Com isso, podemos baixar o relatório utilizando o “actions/download-artifact” e especificando o caminho de destino do arquivo. Nota: O caminho de destino para o relatório deve ser o mesmo especificado no sonar-project.properties

Por fim, podemos usar o módulo do actions do sonarcloud “sonarsource/sonarcloud-github-action@master” para realizar a análise e enviar o relatório automaticamente. É importante passar como variável o GITHUB_TOKEN e o SONAR_TOKEN, o Token do SonarCloud foi adicionado as secrets no passo 2., já o Token do GitHub é setado automaticamente pelo próprio GitHub nas secrets do repositório, para acessar uma secret pelo YAML de workflow do Actions basta utilizar ${{ secrets.SECRET_NAME }}

Pronto, na próxima vez que for feito um push ou um pull request as análises de código e cobertura de testes deve estar presente no repositório do projeto no SonarCloud

Exemplo completo do arquivo ci.yml, para um projeto Python

name: Main Workflow

on:
push:
branches:
- '**'
pull_request:
types: [opened, synchronize, reopened]

jobs:
run-tests:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.12

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r ./requirements.txt

- name: Run tests
run: |
pytest tests --cov=./ --cov-report=xml:reports/coverage.xml

- name: Store test reports
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: ./reports/coverage.xml
retention-days: 1
if-no-files-found: error

sonar-scan:
needs: run-tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Download coverage artifact
uses: actions/download-artifact@v4
with:
name: coverage-report
path: ./reports/

- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}