Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
No analizador PVS-Studio para linguaxes C e C++ en Linux e macOS, a partir da versión 7.04, apareceu unha opción de proba para comprobar a lista de ficheiros especificados. Usando o novo modo, pode configurar o analizador para comprobar as confirmacións e as solicitudes de extracción. Este artigo indicarache como configurar a comprobación da lista de ficheiros modificados dun proxecto de GitHub en sistemas de CI (integración continua) tan populares como Travis CI, Buddy e AppVeyor.

Modo de verificación da lista de ficheiros

PVS-Estudio é unha ferramenta para identificar erros e posibles vulnerabilidades no código fonte dos programas escritos en C, C++, C# e Java. Funciona en sistemas de 64 bits en Windows, Linux e macOS.

Na versión PVS-Studio 7.04 para Linux e macOS, apareceu un modo para comprobar a lista de ficheiros fonte. Isto funciona para proxectos cuxo sistema de compilación permite xerar un ficheiro compile_commands.json. É necesario que o analizador extraia información sobre a compilación dos ficheiros especificados. Se o teu sistema de compilación non admite a xeración do ficheiro compile_commands.json, podes tentar xerar tal ficheiro usando a utilidade Teña.

Ademais, o modo de verificación da lista de ficheiros pódese usar xunto co rexistro de rastrexo de traza dos lanzamentos do compilador (rastro pvs-studio-analyzer). Para iso, primeiro terás que realizar unha compilación completa do proxecto e rastrexalo para que o analizador recolla información completa sobre os parámetros de compilación de todos os ficheiros que se están a comprobar.

Non obstante, esta opción ten un inconveniente importante: terás que realizar un rastrexo completo de compilación de todo o proxecto cada vez que o executas, o que en si mesmo contradí a idea de verificar rapidamente un commit. Ou, se almacena en caché o propio resultado do rastrexo, as execucións posteriores do analizador poden estar incompletas se a estrutura de dependencias dos ficheiros fonte cambia despois do rastrexo (por exemplo, engádese un novo #include a un dos ficheiros fonte).

Polo tanto, non recomendamos usar o modo de verificación da lista de ficheiros co rexistro de rastrexo para comprobar as confirmacións ou as solicitudes de extracción. No caso de que poida facer unha compilación incremental ao comprobar unha confirmación, considere usar o modo análise incremental.

A lista de ficheiros fonte para a análise gárdase nun ficheiro de texto e pásase ao analizador mediante o parámetro -S:

pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt

Este ficheiro especifica camiños relativos ou absolutos aos ficheiros e cada ficheiro novo debe estar nunha nova liña. É aceptable especificar non só os nomes de ficheiros para a análise, senón tamén varios textos. O analizador verá que este non é un ficheiro e ignorará a liña. Isto pode ser útil para comentar se os ficheiros se especifican manualmente. Non obstante, moitas veces xerarase unha lista de ficheiros durante a análise en CI, por exemplo, estes poden ser ficheiros dunha solicitude de confirmación ou extracción.

Agora, usando este modo, pode comprobar rapidamente o código novo antes de que entre na rama principal de desenvolvemento. Para garantir que o sistema de dixitalización responde ás advertencias do analizador, a utilidade Plog-conversor bandeira engadida --indicar-advertencias:

plog-converter ... --indicate-warnings ... -o /path/to/report.tasks ...

Con esta marca, o conversor devolverá un código distinto de cero se hai avisos no informe do analizador. Usando o código de retorno, pode bloquear unha solicitude de conexión, confirmación ou extracción de precommit, e o informe do analizador xerado pódese mostrar, compartir ou enviar por correo electrónico.

Nota. Cando comeza a analizar unha lista de ficheiros, analizarase todo o proxecto, porque o analizador necesita xerar un ficheiro de dependencias dos ficheiros fonte do proxecto nos ficheiros de cabeceira. Esta é unha característica de análise de ficheiros C e C++. No futuro, o ficheiro de dependencia pódese almacenar na caché e o analizador actualizarase automaticamente. A vantaxe de comprobar as confirmacións cando se usa o modo de verificación da lista de ficheiros fronte ao modo de análise incremental é que só precisa almacenar na memoria caché ese ficheiro e non os ficheiros obxecto.

Principios xerais da análise de solicitudes de extracción

Analizar todo o proxecto leva moito tempo, polo que ten sentido comprobar só unha determinada parte do mesmo. O problema é que cómpre separar os novos ficheiros do resto dos ficheiros do proxecto.

Vexamos un exemplo dunha árbore de commit con dúas ramas:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio

Imaxinemos ese compromiso A1 contén unha cantidade bastante grande de código que xa foi probado. Un pouco antes fixemos unha rama dende o commit A1 e cambiou algúns ficheiros.

Ti, por suposto, notaches iso despois A1 producíronse dous compromisos máis, pero tamén foron fusións doutras ramas, porque non nos comprometemos mestre. E agora chegou o momento en que hotfix listo. Por iso apareceu un pull request para a fusión B3 и A3.

Por suposto, sería posible comprobar todo o resultado da súa fusión, pero isto levaría demasiado tempo e sería inxustificado, xa que só se modificaron algúns ficheiros. Polo tanto, é máis eficiente analizar só os modificados.

Para iso, obtemos a diferenza entre as ramas, estando na CABEZA da rama desde a que queremos fundirnos en mestre:

git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list

$MERGE_BASE verémolo en detalle máis adiante. O caso é que non todos os servizos de CI proporcionan a información necesaria sobre a base de datos para a fusión, polo que cada vez tes que buscar novas formas de obter estes datos. Isto describirase en detalle a continuación en cada un dos servizos web descritos.

Entón, obtivemos a diferenza entre as ramas, ou mellor dito, unha lista de nomes de ficheiros que se cambiaron. Agora necesitamos dar o ficheiro .pvs-pr.lista (rediriximos a saída anterior a ela) ao analizador:

pvs-studio-analyzer analyze -j8 
                            -o PVS-Studio.log 
                            -S .pvs-pr.list

Despois da análise, necesitamos converter o ficheiro de rexistro (PVS-Studio.log) nun formato fácil de ler:

plog-converter -t errorfile PVS-Studio.log --cerr -w

Este comando enumerará os erros en stderr (saída de mensaxe de erro estándar).

Só agora necesitamos non só mostrar erros, senón tamén informar ao noso servizo de montaxe e probas sobre a presenza de problemas. Para este fin, engadiuse unha bandeira ao conversor -W (--indicar-advertencias). Se hai polo menos un aviso do analizador, o código de retorno da utilidade Plog-conversor cambiará a 2, que á súa vez informará ao servizo de CI sobre a presenza de posibles erros nos ficheiros de solicitude de extracción.

Travis C.I.

A configuración realízase como un ficheiro .travis.yml. Para comodidade, recoméndoche que poña todo nun script bash separado con funcións que se chamarán desde o ficheiro .travis.yml (bash nome_script.sh nome_función).

Engadiremos o código necesario ao script en bater, deste xeito conseguiremos máis funcionalidades. En sección instalar imos escribir o seguinte:

install:
  - bash .travis.sh travis_install

Se tiveses algunha instrución, podes transferilas ao guión, eliminando os guións.

Imos abrir o ficheiro .travis.sh e engade a configuración do analizador á función travis_install():

travis_install() {
  wget -q -O - https://files.viva64.com/etc/pubkey.txt 
    | sudo apt-key add -
  sudo wget -O /etc/apt/sources.list.d/viva64.list 
    https://files.viva64.com/etc/viva64.list
  
  sudo apt-get update -qq
  sudo apt-get install -qq pvs-studio 
}

Agora imos engadir á sección escrita realizar a análise:

script:
  - bash .travis.sh travis_script

E no script bash:

travis_script() {
  pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
  
  if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
    git diff --name-only origin/HEAD > .pvs-pr.list
    pvs-studio-analyzer analyze -j8 
                                -o PVS-Studio.log 
                                -S .pvs-pr.list 
                                --disableLicenseExpirationCheck
  else
    pvs-studio-analyzer analyze -j8 
                                -o PVS-Studio.log 
                                --disableLicenseExpirationCheck
  fi
  
  plog-converter -t errorfile PVS-Studio.log --cerr -w
}

Este código debe executarse despois de construír o proxecto, por exemplo, se tivese unha compilación en CMake:

travis_script() {
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  cmake $CMAKE_ARGS CMakeLists.txt
  make -j8
}

Resultará así:

travis_script() {
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  cmake $CMAKE_ARGS CMakeLists.txt
  make -j8
  
  pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY
  
  if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
    git diff --name-only origin/HEAD > .pvs-pr.list
    pvs-studio-analyzer analyze -j8 
                                -o PVS-Studio.log 
                                -S .pvs-pr.list 
                                --disableLicenseExpirationCheck
  else
    pvs-studio-analyzer analyze -j8 
                                -o PVS-Studio.log 
                                --disableLicenseExpirationCheck
  fi
  
  plog-converter -t errorfile PVS-Studio.log --cerr -w
}

Probablemente xa notaches estas variables de ambiente $TRAVIS_PULL_REQUEST и $TRAVIS_BRANCH. Travis CI decláraos independentemente:

  • $TRAVIS_PULL_REQUEST almacena o número de solicitude de extracción ou teito, se esta é unha rama regular;
  • $TRAVIS_REPO_SLUG almacena o nome do repositorio do proxecto.

O algoritmo para esta función:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Travis CI responde aos códigos de retorno, polo que a presenza de avisos indicará ao servizo que marque a confirmación como que contén erros.

Agora vexamos máis de cerca esta liña de código:

git diff --name-only origin/HEAD > .pvs-pr.list

O feito é que Travis CI fusiona automaticamente ramas mentres analiza unha solicitude de extracción:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Por iso analizamos A4pero non B3->A3. Debido a esta característica, necesitamos calcular a diferenza con A3, que é precisamente a parte superior da rama de orixe.

Queda un detalle importante: almacenar en caché as dependencias dos ficheiros de cabeceira en unidades de tradución compiladas (*.c, *.cc, *.cpp, etc.). O analizador calcula estas dependencias cando se inicia por primeira vez no modo de verificación dunha lista de ficheiros e despois gárdaos no directorio .PVS-Studio. Travis CI permíteche almacenar cartafoles na caché, polo que gardamos os datos do directorio .PVS-Studio/:

cache:
  directories:
    - .PVS-Studio/

Este código debe engadirse ao ficheiro .travis.yml. Este directorio almacena varios datos recollidos despois da análise, o que acelerará significativamente as execucións posteriores da análise da lista de ficheiros ou da análise incremental. Se isto non se fai, entón o analizador analizará todos os ficheiros cada vez.

Camarada

Como Travis CI, Camarada ofrece a posibilidade de construír e probar automaticamente proxectos almacenados en GitHub. A diferenza de Travis CI, está configurado na interface web (o soporte de bash está dispoñible), polo que non hai necesidade de almacenar ficheiros de configuración no proxecto.

En primeiro lugar, necesitamos engadir unha nova acción á cadea de montaxe:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Imos indicar o compilador que se utilizou para construír o proxecto. Observe o contedor docker que está instalado nesta acción. Por exemplo, hai un contedor especial para GCC:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Agora imos instalar PVS-Studio e as utilidades necesarias:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Engadimos as seguintes liñas ao editor:

apt-get update && apt-get -y install wget gnupg jq

wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -
wget -O /etc/apt/sources.list.d/viva64.list 
  https://files.viva64.com/etc/viva64.list

apt-get update && apt-get -y install pvs-studio

Agora imos á pestana Executar (primeira icona) e engade o seguinte código ao campo do editor correspondente:

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY

if [ "$BUDDY_EXECUTION_PULL_REQUEST_NO" != '' ]; then
  PULL_REQUEST_ID="pulls/$BUDDY_EXECUTION_PULL_REQUEST_NO"
  MERGE_BASE=`wget -qO - 
    https://api.github.com/repos/${BUDDY_REPO_SLUG}/${PULL_REQUEST_ID} 
    | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck 
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck
fi

plog-converter -t errorfile PVS-Studio.log --cerr -w

Se le a sección sobre Travs-CI, este código xa che é familiar, pero agora hai unha nova etapa:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
O caso é que agora analizamos non o resultado da fusión, senón o HEAD da rama desde a que se fai a solicitude de extracción:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Así que estamos nun compromiso condicional B3 e temos que sacar a diferenza A3:

PULL_REQUEST_ID="pulls/$BUDDY_EXECUTION_PULL_REQUEST_NO"
  MERGE_BASE=`wget -qO - 
    https://api.github.com/repos/${BUDDY_REPO_SLUG}/${PULL_REQUEST_ID} 
    | jq -r ".base.ref"`
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list

Por determinar A3 Imos usar a API de GitHub:

https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}

Usamos as seguintes variables que ofrece Buddy:

  • $BUDDY_EXECUTION_PULL_REQEUST_NO - número de solicitude de extracción;
  • $BUDDY_REPO_SLUG — unha combinación de nome de usuario e repositorio (por exemplo max/test).

Agora imos gardar os cambios usando o botón de abaixo e habilitar a análise da solicitude de extracción:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
A diferenza de Travis CI, non necesitamos especificar .pvs-studio para almacenar na caché, xa que Buddy almacena automaticamente todos os ficheiros para os seguintes lanzamentos. Polo tanto, o último que queda é gardar o inicio de sesión e o contrasinal de PVS-Studio en Buddy. Despois de gardar os cambios, volveremos a Pipeline. Necesitamos pasar a configurar as variables e engadir un inicio de sesión e unha clave para PVS-Studio:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Despois diso, a aparición dunha nova solicitude de extracción ou confirmación activará a revisión. Se unha confirmación contén erros, Buddy indicarao na páxina de solicitude de extracción.

AppVeyor

Configurar AppVeyor é semellante a Buddy, xa que todo ocorre na interface web e non hai necesidade de engadir un ficheiro *.yml ao repositorio do proxecto.

Imos á pestana Configuración na vista xeral do proxecto:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Desprácese cara abaixo nesta páxina e active o gardado da caché para recoller solicitudes de extracción:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Agora imos á pestana Ambiente, onde especificamos a imaxe para a montaxe e as variables de ambiente necesarias:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Se liches as seccións anteriores, estás moi familiarizado con estas dúas variables − PVS_KEY и PVS_USERNAME. Se non, permíteme recordarche que son necesarios para verificar a licenza do analizador PVS-Studio. Verémolos de novo nos guións de Bash no futuro.

Na mesma páxina a continuación indicamos o cartafol para almacenar na caché:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Se non facemos isto, analizaremos todo o proxecto en lugar dun par de ficheiros, pero obteremos a saída dos ficheiros especificados. Polo tanto, é importante introducir o nome correcto do directorio.

Agora toca probar o guión. Abra a pestana Probas e seleccione Script:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Debes pegar o seguinte código neste formulario:

sudo apt-get update && sudo apt-get -y install jq

wget -q -O - https://files.viva64.com/etc/pubkey.txt 
  | sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/viva64.list 
  https://files.viva64.com/etc/viva64.list

sudo apt-get update && sudo apt-get -y install pvs-studio

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY

PWD=$(pwd -L)
if [ "$APPVEYOR_PULL_REQUEST_NUMBER" != '' ]; then
  PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
  MERGE_BASE=`wget -qO - 
    https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} 
    | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck 
                              --dump-files --dump-log pvs-dump.log 
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck
fi

plog-converter -t errorfile PVS-Studio.log --cerr -w

Prestemos atención á seguinte parte do código:

PWD=$(pwd -L)
if [ "$APPVEYOR_PULL_REQUEST_NUMBER" != '' ]; then
  PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
  MERGE_BASE=`wget -qO - 
   https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} 
   | jq -r ".base.ref"`

  git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck 
                              --dump-files --dump-log pvs-dump.log 
                              -S .pvs-pr.list
else
  pvs-studio-analyzer analyze -j8 
                              -o PVS-Studio.log 
                              --disableLicenseExpirationCheck
fi

A asignación bastante específica do valor do comando pwd a unha variable que debería almacenar este valor predeterminado parece estraña a primeira vista, porén, explicarei todo agora.

Mentres configuraba o analizador en AppVeyor, atopei un comportamento moi estraño do analizador. Por unha banda, todo funcionou correctamente, pero a análise non comezou. Pasei moito tempo vendo que estamos no directorio /home/appveyor/projects/testcalc/ e o analizador está seguro de que estamos no /opt/appveyor/build-agent/. Entón decateime de que a variable $PWD mentía un pouco. Por este motivo, actualicei manualmente o seu valor antes de comezar a análise.

E entón todo é como antes:

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio
Considere agora o seguinte fragmento:

PULL_REQUEST_ID="pulls/$APPVEYOR_PULL_REQUEST_NUMBER"
MERGE_BASE=`wget -qO - 
  https://api.github.com/repos/${APPVEYOR_REPO_NAME}/${PULL_REQUEST_ID} 
  | jq -r ".base.ref"`

Nel obtemos a diferenza entre as ramas sobre as que se declara a solicitude de extracción. Para iso necesitamos as seguintes variables de ambiente:

  • $APPVEYOR_PULL_REQUEST_NUMBER — número de solicitude de extracción;
  • $APPVEYOR_REPO_NAME - nome de usuario e repositorio do proxecto.

Conclusión

Por suposto, non consideramos todos os posibles servizos de integración continua, pero todos teñen características operativas moi similares entre si. Con excepción do caché, cada servizo fai a súa propia "bicicleta", polo que todo é sempre diferente.

Nalgún lugar, como en Travis-CI, un par de liñas de código e caché funcionan perfectamente; nalgún lugar, como en AppVeyor, só precisa especificar o cartafol na configuración; pero nalgún lugar cómpre crear claves únicas e tentar convencer ao sistema para que che dea a oportunidade de sobrescribir o fragmento almacenado na caché. Polo tanto, se queres configurar a análise das solicitudes de extracción nun servizo de integración continua que non se comentou anteriormente, primeiro asegúrate de que non terás problemas co caché.

Grazas pola súa atención. Se algo non funciona, non dubide en escribirnos a apoiar. Asesoraremos e axudaremos.

Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio

Se queres compartir este artigo cun público de fala inglesa, utiliza a ligazón de tradución: Maxim Zvyagintsev. Análise de confirmacións e solicitudes de extracción en Travis CI, Buddy e AppVeyor mediante PVS-Studio.

Fonte: www.habr.com

Engadir un comentario