Analisar projeto Laravel 5 (PHP) com o SonarQube

Publicado em 18-07-2015 00:52 | Criado por Luís Cruz | Categoria: Integração contínua
Click here to view the English version

No artigo anterior instalámos e configurámos o SonarQube e o SonarQube Runner. Agora que temos as ferramentas instaladas, vamos analisar o projeto Laravel 5 que criámos no segundo artigo da série "Como criar um servidor de integração contínua".

Esta série de artigos sobre Integração Contínua começou com o artigo Ferramentas para servidor de integração continua (CI) e mostra como criar um servidor de integração contínua para projetos PHP.

 

 

Este artigo encontra-se dividido nas seguintes secções:

  1. Instalar PHPUnit e configurar o phpunit.xml
  2. Adicionar o ficheiro sonar-project.properties ao projeto
  3. Executar análise do projeto com o SonarQube Runner

 

1. Instalar PHPUnit e configurar o phpunit.xml

Para que o SonarQube seja capaz de interpretar a nossa aplicação, nomeadamente a cobertura de testes ao código, vamos usar o PHPUnit. O PHPUnit vem incluído por defeito com o Laravel, mas vamos ter de o instalar no servidor e alterar as definições do phpunit.xml. Para isso, segue os seguintes passos.

  1. Vamos começar por instalar o PHPUnit globalmente, através dos comandos:

    cd ~/Downloads
    wget https://phar.phpunit.de/phpunit.phar
    chmod +x phpunit.phar
    sudo mv phpunit.phar /usr/local/bin/phpunit
  2. Para que o PHPUnit consiga exportar e guardar os resultados dos testes é necessário que tenhas a extensão XDebug ativa no PHP. Para instalares a extensão deves executar o comando abaixo.

    sudo apt-get install php5-xdebug
    Todos os comandos especificados neste artigo foram executados num Linux Mint baseado em Ubunto. Caso utilizes outra distribuição é provável que apenas tenhas de alterar o apt-get para o gestor de dependências correto. No entanto, é possível que os nomes das dependências sejam diferentes.
  3. Para que o resultado dos testes seja interpretado pelo SonarQube, como já indiquei, é necessário ajustar a configuração do PHPUnit. Por defeito o Laravel já inclui o ficheiro de configuração phpunit.xml, na raiz do projeto, e é esse ficheiro que vamos alterar para o seguinte conteúdo:

    <?xml version="1.0" encoding="UTF-8"?>
    <phpunit backupGlobals="false"
        backupStaticAttributes="false"
        bootstrap="bootstrap/autoload.php"
        colors="true"
        convertErrorsToExceptions="true"
        convertNoticesToExceptions="true"
        convertWarningsToExceptions="true"
        processIsolation="false"
        stopOnFailure="false"
        syntaxCheck="false">
      <testsuites>
        <testsuite name="Application Test Suite">
          <directory>./tests/</directory>
        </testsuite>
      </testsuites>
      <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <ini name="memory_limit" value="2048M"/>
      </php>
    
      <logging>
        <log type="coverage-html" target="./ci/codeCoverage/" charset="UTF-8" yui="true" highlight="false" lowUpperBound="35" highLowerBound="70"/>
        <log type="coverage-clover" target="./ci/codeCoverage/codeCoverage.xml"/>
        <log type="metrics-xml" target="./ci/codeCoverage/metrics.xml"/>
        <log type="test-xml" target="./ci/codeCoverage/logfile.xml" logIncompleteSkipped="false"/>
      </logging>
    </phpunit>

    As configurações que alterei, em relação à verão original do ficheiro, foram:

    1. No grupo <php> incluí a propriedade <ini name="memory_limit" value="2048M"/> que permite aumentar o limite da memória do PHP quando os testes estão a ser executados. Embora esta propriedade não seja obrigatória eu recomendo que a adiciones para que o processo PHP tenha memória suficiente quando os testes são executados.
    2. Adicionei o grupo <logging> que é o que realmente interessa. Esta configuração permite registar o resultado dos testes que será lido pelo SonarRunner.

      É importante registar a informação resultante do PHPUnit para que seja possível saber qual a percentagem de cobertura de testes do teu código. Ou seja, com este output do PHPUnit o SonarQube consegue detetar qual a percentagem do teu código que está testado.

      Para efeitos desta demonstração o resultado dos testes é guardado num novo diretório, em «project_root»/ci/codeCoverage.

  4. Executa o comando phpunit na raiz do teu projeto para garantir que está tudo a funcionar corretamente. Deves ver a informação da criação do output e os diretórios serão criados automaticamente:

    Executar PHPUnit com cobertura de código

  5. Agora faz push das alterações ao ficheiro de configurações para o servidor.

    Antes de enviares as alterações, adiciona o diretório ci ao ficheiro .gitignore. Os ficheiros apenas são úteis para a análise do SonarQube e não existe qualquer necessidade de os colocares no repositório.
  6. Depois de enviares as alterações, será executada a configuração no TeamCity e, caso acedas à aplicação, deves ver qualquer coisa como:

    Execução da Configuração iniciada no TeamCity

    Aguarda que a execução termine antes de procederes ao passo seguinte.

  7. Vamos verificar que os testes são executados no servidor e que o resultado é armazenado no diretório ci. Para isso, acede ao servidor através do terminal, ao diretório que contem o código no Teamcity Agent, como apresentado de seguida. Lembra-te de substituir a {hash} pelo nome correto do diretório.

    cd /opt/TeamcityAgent/work/{hash}
    phpunit

    Se tudo correu bem, deves ver uma informação semelhante à da imagem seguinte e deverás ter o diretório ci criado.

    Executar PHPunit com Code Coverage

2. Adicionar o ficheiro sonar-project.properties ao projeto

O teu projeto ainda não é visível no SonarQube porque ainda não foi executada nenhuma análise. Para que a análise seja feita corretamente, deves adicionar um novo ficheiro, com nome sonar-project.properties à raiz do teu projeto, com o seguinte conteúdo:

# Required metadata
sonar.projectKey=testproject
sonar.projectName=testproject
sonar.projectVersion=1.0.0

# Path to the parent source code directory.
sonar.sources=app

# Language
# We've commented this out, because we want to analyse both PHP and Javascript
#sonar.language=php

# Encoding of the source code
sonar.sourceEncoding=UTF-8

# Reusing PHPUnit reports
sonar.php.coverage.reportPath=ci/codeCoverage/codeCoverage.xml
sonar.php.tests.reportPath=ci/testResults.xml

# Here, you can exclude all the directories that you don't want to analyse.
# As an example, I'm excluding the Providers directory
sonar.exclusions=app/Providers/**

# Additional parameters
#sonar.my.property=value

Este ficheiro contem a informação necessária para a análise do projeto. Segue uma breve descrição das configurações do ficheiro.

  • sonar.projectKey, sonar.projectName e sonar.projectVersion: são valores obrigatórios e permitem identificar o projeto no SonarQube (nomeadamente o projectKey).
  • sonar.sources: Indica qual o diretório que contém o código fonte da tua aplicação. No nosso caso apontamos para o diretório app porque aí estará todo o nosso código.

    Não faz sentido incluir o diretório vendor, node_components ou bower_components, uma vez que estes diretórios já contém código testado e o código não é mantido por ti, pelo que a análise a este código causaria uma perda de tempo e poderia causar análises irrealistas. Apenas interessa o código da tua aplicação e é esse que deve ser testado e analisado.

  • sonar.language: Indica qual a linguagem de programação a usar na análise. Como podes ver, temos esta propriedade comentada (com o caracter #) porque pretendemos ter uma análise a mais que uma linguagem (PHP e Javascript).
  • sonar.php.coverage.reportPath e sonar.php.tests.reportPath: Indicam quais os caminhos do output dos testes do PHPUnit. Deves definir os mesmo caminhos já definidos no ficheiro phpunit.xml, no ponto anterior.
  • sonar.exclusions: Permite definir exclusões de ficheiros ou diretórios existentes que pertencam ao diretório definido em sonar.sources. No nosso caso e especificamente para efeitos de testes excluimos o diretório Providers. Num caso real deves remover esta propriedade ou definir diretórios ou ficheiros que não devam ser usados na análise.

    Como nota, esta propriedade era útil com projetos Laravel 4, porque o diretório app continha ficheiros relativos a base de dados (database), a traduções (langs), ao armazenamento (storage) e a vistas (views), todos eles irrelevantes para a análise que pretendemos com o SonarQube.

  • sonar.my.property: Esta propriedade está comentada e serve apenas para perceberes que podes definir propriedades especificas do teu projeto, que poderão depois ser usadas no SonarQube.

Existe mais informação passível de colocar neste ficheiro de configurações e existe informação específica mediante a linguagem e o tipo de projetos. Podes ver na página do GitHub exemplos do ficheiro de configuração, bastando

  1. Selecionar a linguagem que pretendes
  2. Procurar pelo diretório que termina em sonar-runner
  3. Visualizar o conteúdo do ficheiro sonar-project.properties

Depois de adicionares o ficheiro ao projeto e o preencheres corretamente, envia as alterações para o repositório Git (git push).

3. Executar análise do projeto com o SonarQube Runner

Vamos executar o SonarQube Runner pela primeira vez, para que o projeto seja adicionado ao SonarQube. Para o efeito acede ao diretório da aplicação, no servidor, e executa o comando para efetuar a análise

cd /opt/TeamcityAgent/work/{hash}
sudo /opt/sonar-runner-2.4/bin/sonar-runner -e -X

Este comando deve terminar com a informação EXECUTION SUCCESS. Agora, quando acederes ao SonarQube, já deverás ver o teu projeto:

Projeto adicionado ao SonarQube após análise do SonarQube Runner

Se carregares no nome do projeto, és direcionado para uma página que contem os seus detalhes. No entanto, a informação apresentada ainda não é real

Análise incorreta no SonarQube devido à linguagem

Isto acontece porque a análise feita ao nosso projeto foi Java (lembra-te que comentámos a propriedade sonar.language no ponto anterior e, como tal, o SonarQube Runner não sabe a linguagem que deve usar na analise.

Temos então de indicar ao SonarQube quais as linguagens que queremos analisar. Para isso, deves aceder a Settings » System » Update Center, como apresentado na imagem abaixo

Centro de atualizações no SonarQube

Nesta página é possível instalar vários plugins e, para o nosso caso, vamos instalar três: PHP, Javascript (ambos dentro do grupo Languages) e Redmine (dentro do grupo Integration). Para instalares os plugins deves carregar sobre o nome do plugin e carregar no botão Install.

Instalar plugins no SonarQube

Depois de instalados os três plugins, reinicia o SonarQube com o comando

/opt/sonarqube-5.1.1/bin/linux-x86-64/sonar.sh restart

A análise ao projeto é feita através de Perfis de Qualidade. Estes perfis podem ser pré-configurados (como, por exemplo, o PSR-2) ou podem ser definidos por ti. Podes gerir os perfis no menu Quality Profiles.

Gerir perfis de qualidade no SonarQube

Vamos agora associar os perfis de qualidade ao nosso projeto. Para o efeito, acede ao Dashboard e clica no nome do teu projeto. Dentro do teu projeto, acede ao menu Settings » Quality Profiles. Define, nessa página, o perfil Sonar way para Javascript e PSR-2 para PHP.

Aceder aos perfis de qualidade do projeto no SonarQube Alterar perfil de qualidade para PHP e Javascript no SonarQube

Agora volta a executar manualmente a análise do projeto com o comando:

cd /opt/TeamcityAgent/work/{hash}
sudo /opt/sonar-runner-2.4/bin/sonar-runner -e -X

Neste momento já deves ver o número de linhas de código, a quantidade de problemas que tens para resolver e quais os ficheiros em que os tens de resolver. Existe uma panóplia de informação disponível e de formas de visualizar essa informação, que deixo para explorares.

Dashboard do SonarQube Visão global do projeto no SonarQube

Análise a defeitos no projeto (SonarQube) Detalhe pormenorizado de um defeito no SonarQube

Com isto consegues analisar o teu projeto e perceber a complexidade da tua aplicação. A minha recomendação é que faças um acompanhamento periódico à qualidade da tua aplicação e à Divida Técnica.

No próximo e último artigo desta série de Integração Contínua, vamos integrar o SonarQube com o TeamCity e com o Redmine.