Freneticamente os versionadores de código estão juntando o fruto do trabalho das várias pessoas envolvidas em um projeto. Contudo, ainda que você tenha testes unitários, se a execução deles não estiver atrelada e condicionando o PR, nada impede que um código que quebre padrões e comportamentos seja adicionado a sua base de códigos. Para situações como essas existem as GitHub Actions.
Neste breve manual, vamos aprender como configurar uma GitHub Action que rode os testes de unidade e rode a análise do Sonar, enviando para o SonaCloud.io. Chamo apenas atenção que, para utilizar o SonarCloud gratuitamente, você terá que tornar público o seu repositório. Caso opte por pagar a assinatura do SonarCloud, os passos são os mesmos. Apenas o repositório que poderá ser privado. Caso você também possua uma opção on-premisse do SonarQube, poderá utilizá-la normalmente. Vamos ao conteúdo.
Configurando o SonarCloud.io
Integração com GitHub
Acesse sonarcloud.io. A tela inicial irá pedir que você se cadastre ou faça o login. Aconselho que você faça o cadastro e integre a sua conta do GitHub com o SonarCloud. Vai facilitar a sua vida. Infelizmente não tenho os prints para te mostrar aqui como fazer. Mas o processo é realmente bastante simples.
Após cadastrado você terá acesso a tela de projetos. Se não me engano, já até poderá selecionar projetos durante o processo de cadastro. Mas não faça isso por agora. Vamos seguir aqui os passos juntos.

Agora é o momento de você configurar um projeto. Diferente da versão on-premisse, onde os projetos são adicionados ao seu sonar por padrão, no SonarCloud você precisa configurá-los de antemão. É o que vamos fazer. Você pode clicar no botão “Analyze new project”, que está no centro da tela, ou no botão com o símbolo “+” que está no canto superior direito da página, ao lado da sua foto de perfil e selecionar a opção “Analyze new project”.
Na janela que se abre, você verá todos os projetos do seu GitHub. Os privados aparecem acinzentados e com um cadeado, impedindo sua seleção. Marque o projeto que deseja analisar e clique no botão “Set Up”.

Neste momento, o SonarCloud fará uma análise do conteúdo do seu projeto, tentando descobrir se ele oferece suporte. Para alguns tipos de projeto o sonar provê integração automática. Com projetos C#, contudo, é preciso que você faça uso de algum pipeline de CI. Que no nosso caso é o GitHub. Clique no botão “With GitHub Actions”.

A próxima etapa é muito importante. Para que você não exponha suas credenciais de acesso, as GitHub Actions e o SonarCloud fazem uso de um token de autenticação. O token é mostrada logo após clicar no botão. COPIE IMEDIATAMENTE o conteúdo do token. Se você o perder, terá de criar outro. Já te explico o que você vai fazer com esse token. Apenas clique no botão “Continue”.

Ao selecionar a opção “.Net”, o sonar te mostra um arquivo de exemplo de workflow. Em situações mais simples, você poderia utilizar esse arquivo. Mas como temos outros planos, apenas ignore.

E assim está completa a configuração do nosso projeto. Pelo menos o que diz respeito a integração. Você pode clicar no ícone “SonarCloud” ou ainda em “My Projects” para visualizar os projetos configurados.

Configurações de análise
Mas ainda é necessário configurar a análise. Esta etapa serve para você dizer ao sonar onde estão os arquivos com informações do code-coverage, quais projetos devem ser ignorados, quais arquivos devem ser ignorados (os gerados automaticamente, por exemplo) e afins.
Se você não acertar todas a configurações de primeira, não se preocupe. Você pode alterar e disparar manualmente novas execuções. Clique no projeto ou em “Configure Analysis”. O SonarCloud irá te redirecionar para uma página que já vimos antes. Mas diferente do que fizemos, clique no menu Administration -> General Settings.

Nesta tela, todas as configurações de análise de código estão acessíveis. Apenas vá alternando entre as abas para configurar o que for pertinente.

Ao clicar em “Language” e selecionar C#, por exemplo, você pode informar a localização dos arquivos de cobertura em vários formatos. Na aplicação de exemplo, estamos utilizando o opencover, que é gerado dentro dos projetos de testes, que estão em __tests__
. Como o nome dos arquivos tem suporte a Glob, posso digitar __tests__/**/coverage.opencover.xml
para encontrar a cobertura de código.

Você pode fazer mais configurações no SonarCloud, definindo arquivos que deve ignorar na análise, por exemplo (veja a aba Analysis Scope), mas não vou me aprofundar nesse ponto agora. Este é o momento em que mudamos do SonarCloud para o GitHub.
Configurando o repositório no GitHub
Depois de acessar o seu repositório no GitHub, clique na aba “Actions”. O GitHub já é esperto o bastante para saber qual é a linguagem do seu projeto e já sugere opções de actions para utilizar. Clique na opção “.Net Core”.

Gentilmente o GitHub irá criar um template de action que, basicamente, já compila e roda os testes do seu projeto. E do lado direito também é apresentada uma lista de snippets que podem auxiliar na criação da sua action.

Customizando a Action padrão de .Net Core
Vamos aproveitar esse arquivo para que eu te explique algumas coisas básicas:
Nesta parte do código você está definindo quando a sua action deve ser executada. Para este caso, nossa action será executado sempre que um push for feito na branch develop
ou um PR for aberto para a branch develop
. Caso você queira que a execução seja feita para todas as branches, substitua develop
por ‘**’.
on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]
Os demais pontos são autoexplicativos, mas ainda quero te chamar atenção para:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.301
Esse conjunto de código instalada a versão especificada em dotnet-version no ambiente em que estamos rodando – ubuntu-latest. Será possível utilizar a versão dotnet 5, que está em pré-release? Claro que sim! Basta que você altere a versão do SDK para:
with:
dotnet-version: 5.0.100-preview.2.20176.6
Precisa ser esse nome grande, porque é o disponível no metadata da versão (disponível em https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/5.0/releases.json). Um ponto triste é que AINDA não há versão do dotnet-sonarscanner rodando na versão net5. Contudo, já existe PR aberto para essa atualização. Aguarde um pouco antes de atualizar os projetos 😉
Adicionar análise do SonarCloud na Action de .Net Core
Eu não utilizei o arquivo que o SonarCloud sugeriu por um motivo simples: Ele usa Windows por padrão. E eu quero que os meus artefatos sejam produzidos e validados no Linux. Por isso grande parte do que vamos utilizar aqui é o mesmo que já foi fornecido pela SonarCloud, mas com as devida adaptações. Vamos lá.
O script que o SonarCloud fornece possui algumas opções de caching que são interessantes. Elas podem tornar o processo mais rápido, já que reaproveitam etapas já executadas. Por isso, vamos introduzir esse conteúdo no nosso arquivo:
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~\sonar\cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache SonarCloud scanner
id: cache-sonar-scanner
uses: actions/cache@v1
with:
path: .\.sonar\scanner
key: ${{ runner.os }}-sonar-scanner
restore-keys: ${{ runner.os }}-sonar-scanner
- name: Install SonarCloud scanner
if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
run: dotnet tool update dotnet-sonarscanner --tool-path ./.sonar/scanner
Aqui entra a parte de teste e análise, que de fato tanto importa para nós.
- name: Test and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
./.sonar/scanner/dotnet-sonarscanner begin /k:"Project-key" /o:"user" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover -l trx
./.sonar/scanner/dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
A parte importante nesse trecho de código é o ${{ secretes.SONAR_TOKEN }}
. Lembra que no começo nós guardamos essa informação que o SonarCloud gerou para nós? É hora de utilizá-la! NÃO! Você não vai colar essa chave no seu arquivo. Para funcionar o CI corretamente, o GitHub implementou uma área no repositório chamada “Secrets”, onde todos os dados sensíveis podem ser armazenados. Entre eles, o nosso Token! Para acessar, você precisa ir até o seu repositório, clicar na aba Settings, e depois acessar o menu Secrets. Clique em New Secret para criarmos uma nova Secret com o nome SONAR_TOKEN
(ou qualquer outro que você preferir).

Nem você e nem ninguém jamais terá acesso ao conteúdo dessa secret novamente. E agora voltando ao nosso arquivo, ele deverá ficar assim:
name: Validate code
on:
push:
branches: ["**"]
pull_request:
branches: [develop]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.100-preview.2.20176.6
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~\sonar\cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache SonarCloud scanner
id: cache-sonar-scanner
uses: actions/cache@v1
with:
path: .\.sonar\scanner
key: ${{ runner.os }}-sonar-scanner
restore-keys: ${{ runner.os }}-sonar-scanner
- name: Install SonarCloud scanner
if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
run: dotnet tool update dotnet-sonarscanner --tool-path ./.sonar/scanner
- name: Install project dependencies
run: dotnet restore
- name: Test and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
./.sonar/scanner/dotnet-sonarscanner begin /k:"ftathiago_esbc" /o:"ftathiago" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover -l trx
./.sonar/scanner/dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
- name: Build
run: dotnet build --configuration Release --no-restore
Particularmente eu prefiro criar dois Jobs: Um para análise e outro para o build (e quem sabe um terceiro para deploy?). Porém isso ampliaria demais o contexto e a complexidade desse artigo.
Agora, quando você abrir um pull request para a develop ou fazer qualquer push, o seu PR ficará decorado da seguinte maneira:

Mas claro, só se você tiver passado pelo code review 😉
E voltando para o SonarCloud, o que nós temos todos os detalhes da análise do nosso código:

Nada mal. Mas ainda tem algumas coisinhas para melhorar.
Espero que essas dicas sirvam pra te ajudar a manter a qualidade do código, além de tirar o medo de brincar com as Actions do GitHub!
Puts, comigo ainda não funcionou a parte da cobertura de código, ta tudo funcionando, só isso que não. To quase desistindo
Eita, o que tá acontecendo? Fala aew, quem sabe eu te ajudo?
Bom, não sei onde estou errando, mas https://sonarcloud.io/dashboard?id=DonPSantos_ApiCore conforme pode ver no link, o Sonar não ta pegando o coverage de minha API
🙁
Cara, o que pode estar acontecendo é você não ter instalado o `coverlet.msbuild` ao seu projeto de teste. Esse pacote que é o responsável por gerar os arquivos de análise de cobertura. Dê uma olhada nesse outro artigo, onde eu falo do coverlet e até como gerar esse repo localmente (https://www.blogdoft.com.br/2020/06/11/como-gerar-relatorios-de-code-coverage-para-codigo-c/)
Outro provável ponto de erro pode estar na configuração do Sonar. Tente entrar nas configurações do sonar e confirmar se o path que vc informou está correto. Um teste válido é: se vc rodar os mesmos comandos na sua máquina… deve funcionar (desde que esteja com as secrets iguais e tal). Depois volta aí e diz se funcionou 🙂
O “coverlet.msbuild” eu já tinha, estava faltando o pacote “Microsoft.NET.Test.Sdk” instalei, consegui rodar localmente, porém não pegou ainda, a config do Sonar está exatamente como no seu artigo.
Meu projeto no GitHub: https://github.com/DonPSantos/ApiCore
CONSEGUIIIIIIIIII KKKKKK
Muito obrigado!!!! peguei o caminho “chumbado” do log do GitHub e coloquei na config do Sonar e foi
Show!!! Sobre ter de baixar o SDK, eu acho estranho isso. Você utilizou os templates de teste do .net ou criou um projeto na mão?
Sobre o path chumbado… funciona, mas eu aconselho utilizar os path relativos.
Agora que vc viu que funciona, continue testando! É bem da hora, né? Ver o trem rodando é sensacional!
Estou em guerra com esse negócio,
Essas suas dicas me quebraram um galhão.
Sucesso cara.