Skip to content

Configurar o SonarCloud para um projeto usando Mocha e Istambul

Gabriel Tiveron edited this page Nov 18, 2021 · 1 revision

Como configurar o SonarCloud para um projeto JavaScript utilizando Mocha e Istambul

Histórico de Revisão

Data Versão Descrição Revisor
18/11/2021 1.0 Versão Inicial Gabriel Marques Tiveron

O que será usado

  • Github Actions
  • Node
  • SonarCloud
  • Mocha
  • Istambul
  • Python

Passo 1 - Adicionar modo de execução de testes

Para que haja um funcionamento adequado das funções é necessário que a execução dos testes seja feita através do seguinte comando

nyc --reporter=cobertura --reporter=text mocha **caminho_para_arquivos_teste** --recursive --reporter mocha-junit-reporter

Dessa forma, serão gerados dois arquivos após a execução dos testes, um do Mocha, onde será extraída a cobertura dos testes e outro do Istambul, onde será extraída as metricas de tempo de execução dos testes e sucesso. Esse comando pode ser adicionado no package.json do projeto.

Passo 2 - Adicionar Secret no repositório

Para que se possa retornar o arquivo de métricas para o repositório, é necessário que sejam definidos secrets no mesmo. Para isso, basta seguir os seguintes passos:

  1. Na página principal do repositório acesse Settings

Settings

  1. Acesse a aba Secrets

Secrets

  1. Crie secrets com o e-mail e o username do GitHub que tenha acesso ao repositório.

CI_credentials

Obs: Os nomes dos secrets devem estar exatamente como na imagem, ou devem ser alterados quando utilizados no passo 4.

Passo 3 - Parser de métricas Mocha / Istambul

import xmltodict, json
import requests
import sys
import re
from datetime import datetime

TODAY = datetime.now()

METRICS_SONAR = [
    # lista de métricas do SonarCloud
]

BASE_URL = 'https://sonarcloud.io/api/measures/component_tree?component='

def read_xml(path):
    with open(path) as xml_file:
        data = xmltodict.parse(xml_file.read())
        return json.loads(json.dumps(data))

def testing(df, coverage):
    for suite in coverage['coverage']['packages']['package']:
        _class = suite['classes']['class']
        try:
            df[_class['@filename']]['coverage'] = float(_class['@line-rate']) * 100
        except:
            pass

def get_test_obj(path_time, path_coverage):
    time = read_xml(path_time)
    coverage = read_xml(path_coverage)

    df = {}
    for suite in time['testsuites']['testsuite']:

        name = suite['@name']
        tests = suite['@tests']
        time = suite['@time']
        try:
            success_density = (int(tests) - int(suite['@failures'])) / int(tests)
        except:
            success_density = 0
        if name == 'Root Suite':
            continue

        name = name.split('->')[0].replace(" ", "")

        if name not in df:

            df[name] = { 'test_execution_time': float(time), 'tests': int(tests), 'test_success_density': success_density }

        else:

            df[name]['test_execution_time'] += float(time)
            df[name]['tests'] += int(tests)

    testing(df, coverage)

    return df

if __name__ == '__main__':
    
    REPO = sys.argv[1] # REPO name Ex.: fga-eps-mds_2021-1-PUMA-UserService

    # Get metrics from Sonar Cloud
    response = requests.get(f'{BASE_URL}{REPO}&metricKeys={",".join(METRICS_SONAR)}&ps=500')

    path_time = # caminho para o arquivo test-results.xml
    path_coverage = # caminho para o arquivo cobertura-coverage.xml

    df = get_test_obj(path_time, path_coverage)

    file_path = f'./{REPO}-{TODAY.strftime("%m-%d-%Y-%H-%M")}.json'
    j = json.loads(response.text)

    for component in j['components']:
        path = component['path']
        if path in df.keys():
            for key in df[path].keys():
                component['measures'].append({ 'metric': key, 'value': df[path][key] })

    with open(file_path, 'w') as fp:
        fp.write(json.dumps(j))
        fp.close()

Passo 4 - Configurar workflow no GitHub Actions

Crie um arquivo chamado .github/workflows/<nome_do_arquivo>.yml com o seguinte conteúdo:

name: <<nome do workflow>>

on: 
  push:
    branches:
    - <<branch alvo do workflow>>

jobs:

  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: testexec
      id: tests
      run: |
          << executar a rotina de testes do repositório >>
    - name: collect
      id: metrics
      run: |
        pip3 install xmltodict
        python3 test_coverage.py fga-eps-mds_${{ github.event.repository.name }}

        << Nesse ponto haverá um arquivo JSON com as metricas de testes juntamente com as 
           métricas do SonarCloud, basta então enviálas para onde desejar >>

Obs: Um exemplo dessa rotina pode se conferida neste link.

Para cada projeto há sua individualidade, para a execução dos testes ou para onde enviar o json gerado do sonar.

Clone this wiki locally