Análisis de confirmaciones y solicitudes de extracción en Travis CI, Buddy y AppVeyor usando PVS-Studio

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
En el analizador PVS-Studio para lenguajes C y C++ en Linux y macOS, a partir de la versión 7.04, apareció una opción de prueba para verificar la lista de archivos especificados. Con el nuevo modo, puede configurar el analizador para verificar confirmaciones y solicitudes de extracción. Este artículo le dirá cómo configurar la verificación de la lista de archivos modificados de un proyecto GitHub en sistemas CI (integración continua) tan populares como Travis CI, Buddy y AppVeyor.

Modo de verificación de lista de archivos

PVS-Estudio es una herramienta para identificar errores y posibles vulnerabilidades en el código fuente de programas escritos en C, C++, C# y Java. Funciona en sistemas de 64 bits en Windows, Linux y macOS.

En la versión PVS-Studio 7.04 para Linux y macOS, apareció un modo para verificar la lista de archivos fuente. Esto funciona para proyectos cuyo sistema de compilación le permite generar un archivo. compilar_commands.json. Es necesario para que el analizador extraiga información sobre la compilación de los archivos especificados. Si su sistema de compilación no admite la generación del archivo compile_commands.json, puede intentar generar dicho archivo usando la utilidad Tenga.

Además, el modo de verificación de la lista de archivos se puede utilizar junto con el registro de seguimiento de los inicios del compilador (seguimiento pvs-studio-analyzer). Para hacer esto, primero deberá realizar una compilación completa del proyecto y realizar un seguimiento para que el analizador recopile información completa sobre los parámetros de compilación de todos los archivos que se están verificando.

Sin embargo, esta opción tiene un inconveniente importante: deberá realizar un seguimiento de compilación completo de todo el proyecto cada vez que lo ejecute, lo que en sí mismo contradice la idea de verificar rápidamente una confirmación. O, si almacena en caché el resultado del seguimiento, las ejecuciones posteriores del analizador pueden estar incompletas si la estructura de dependencia de los archivos fuente cambia después del seguimiento (por ejemplo, se agrega un nuevo #include a uno de los archivos fuente).

Por lo tanto, no recomendamos utilizar el modo de verificación de la lista de archivos con el registro de seguimiento para verificar confirmaciones o solicitudes de extracción. En caso de que pueda realizar una compilación incremental al verificar una confirmación, considere usar el modo analisis incremental.

La lista de archivos fuente para el análisis se guarda en un archivo de texto y se pasa al analizador mediante el parámetro -S:

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

Este archivo especifica rutas relativas o absolutas a los archivos, y cada archivo nuevo debe estar en una nueva línea. Es aceptable especificar no sólo los nombres de los archivos para el análisis, sino también varios textos. El analizador verá que no se trata de un archivo e ignorará la línea. Esto puede resultar útil para comentar si los archivos se especifican manualmente. Sin embargo, a menudo se generará una lista de archivos durante el análisis en CI; por ejemplo, estos podrían ser archivos de una confirmación o solicitud de extracción.

Ahora, al usar este modo, puede verificar rápidamente el código nuevo antes de que ingrese a la rama de desarrollo principal. Para garantizar que el sistema de escaneo responda a las advertencias del analizador, la utilidad convertidor-plog bandera agregada --indicar-advertencias:

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

Con este indicador, el convertidor devolverá un código distinto de cero si hay advertencias en el informe del analizador. Con el código de retorno, puede bloquear un gancho de confirmación previa, una confirmación o una solicitud de extracción, y el informe del analizador generado se puede mostrar, compartir o enviar por correo electrónico.

Nota. Cuando comience a analizar una lista de archivos por primera vez, se analizará todo el proyecto, porque el analizador necesita generar un archivo de dependencias de los archivos fuente del proyecto en los archivos de encabezado. Esta es una característica del análisis de archivos C y C++. En el futuro, el archivo de dependencia se puede almacenar en caché y el analizador lo actualizará automáticamente. La ventaja de verificar las confirmaciones cuando se usa el modo de verificación de la lista de archivos en lugar del modo de análisis incremental es que solo necesita almacenar en caché ese archivo y no los archivos objeto.

Principios generales del análisis de solicitudes de extracción

Analizar todo el proyecto lleva mucho tiempo, por lo que tiene sentido comprobar sólo una determinada parte del mismo. El problema es que necesita separar los archivos nuevos del resto de los archivos del proyecto.

Veamos un ejemplo de un árbol de confirmación con dos ramas:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio

Imaginemos ese compromiso A1 Contiene una cantidad bastante grande de código que ya ha sido probado. Un poco antes hicimos una rama del compromiso. A1 y cambié algunos archivos.

Por supuesto, te diste cuenta de que después A1 Ocurrieron dos compromisos más, pero también fueron fusiones de otras ramas, porque no nos comprometemos a dominar. Y ahora ha llegado el momento en que revisión listo. Por eso apareció una solicitud de extracción para la fusión. B3 и A3.

Por supuesto, sería posible comprobar el resultado completo de su fusión, pero esto llevaría demasiado tiempo y sería injustificado, ya que sólo se modificaron unos pocos archivos. Por tanto, es más eficaz analizar sólo los modificados.

Para ello, obtenemos la diferencia entre las ramas, estando en el HEAD de la rama desde la que queremos fusionarnos en master:

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

$MERGE_BASE lo veremos en detalle más adelante. El hecho es que no todos los servicios de CI proporcionan la información necesaria sobre la base de datos para fusionar, por lo que cada vez hay que idear nuevas formas de obtener estos datos. Esto se describirá en detalle a continuación en cada uno de los servicios web descritos.

Entonces, obtuvimos la diferencia entre las ramas, o más bien, una lista de nombres de archivos que fueron cambiados. Ahora tenemos que darle el archivo. .pvs-pr.lista (redireccionamos el resultado anterior a él) al analizador:

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

Después del análisis, necesitamos convertir el archivo de registro (PVS-Studio.log) a un formato fácil de leer:

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

Este comando enumerará los errores en stderr (salida de mensaje de error estándar).

Sólo que ahora necesitamos no sólo mostrar los errores, sino también informar a nuestro servicio de montaje y pruebas sobre la presencia de problemas. Para ello, se añadió una bandera al convertidor. -W (--indicar-advertencias). Si hay al menos una advertencia del analizador, el código de retorno de la utilidad convertidor-plog cambiará a 2, que a su vez informará al servicio de CI sobre la presencia de posibles errores en los archivos de solicitud de extracción.

Travis CI

La configuración se realiza como un archivo. .travis.yml. Para mayor comodidad, le aconsejo que coloque todo en un script bash separado con funciones que se llamarán desde el archivo. .travis.yml (bash script_name.sh nombre_función).

Agregaremos el código necesario al script en golpear, de esta forma conseguiremos más funcionalidad. En la sección instalar escribamos lo siguiente:

install:
  - bash .travis.sh travis_install

Si tenía alguna instrucción, puede transferirla al script eliminando los guiones.

Abramos el archivo .travis.sh y agregue la configuración del analizador a la función travis_instalar():

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 
}

Ahora agreguemos a la sección. guión ejecutar análisis:

script:
  - bash .travis.sh travis_script

Y en el 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 ejecutarse después de compilar el proyecto, por ejemplo, si tenía una 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 ya hayas notado estas variables de entorno. $TRAVIS_PULL_REQUEST и $TRAVIS_BRANCH. Travis CI los declara de forma independiente:

  • $TRAVIS_PULL_REQUEST almacena el número de solicitud de extracción o false, si se trata de una sucursal regular;
  • $TRAVIS_REPO_SLUG almacena el nombre del repositorio del proyecto.

El algoritmo para esta función:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Travis CI responde a los códigos de retorno, por lo que la presencia de advertencias le indicará al servicio que marque la confirmación como que contiene errores.

Ahora echemos un vistazo más de cerca a esta línea de código:

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

El hecho es que Travis CI fusiona ramas automáticamente mientras analiza una solicitud de extracción:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Por eso analizamos A4Y no B3->A3. Debido a esta característica, necesitamos calcular la diferencia con A3, que es precisamente la parte superior de la rama de natural.

Queda un detalle importante: almacenar en caché las dependencias de los archivos de encabezado en las unidades de traducción compiladas (*.c, *.cc, *.cpp, etc.). El analizador calcula estas dependencias cuando se inicia por primera vez en el modo de verificar una lista de archivos y luego los guarda en el directorio .PVS-Studio. Travis CI permite almacenar en caché carpetas, por lo que guardaremos los datos del directorio .PVS-Studio/:

cache:
  directories:
    - .PVS-Studio/

Este código debe agregarse al archivo. .travis.yml. Este directorio almacena diversos datos recopilados después del análisis, lo que acelerará significativamente las ejecuciones posteriores de análisis de listas de archivos o análisis incrementales. Si no se hace esto, el analizador analizará todos los archivos cada vez.

Amigo

Como Travis CI, Amigo proporciona la capacidad de crear y probar automáticamente proyectos almacenados en GitHub. A diferencia de Travis CI, se configura en la interfaz web (hay soporte para bash disponible), por lo que no es necesario almacenar archivos de configuración en el proyecto.

En primer lugar, debemos agregar una nueva acción a la línea de ensamblaje:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Indiquemos el compilador que se utilizó para construir el proyecto. Observe el contenedor acoplable que se instala en esta acción. Por ejemplo, existe un contenedor especial para GCC:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Ahora instalemos PVS-Studio y las utilidades necesarias:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Agreguemos las siguientes líneas al 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

Ahora vayamos a la pestaña Ejecutar (primer icono) y agreguemos el siguiente código al campo del editor correspondiente:

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

Si lees la sección sobre Travs-CI, entonces este código ya te resulta familiar, sin embargo, ahora hay una nueva etapa:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
El caso es que ahora no analizamos el resultado de la fusión, sino el HEAD de la rama desde la que se realiza la solicitud de extracción:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Entonces estamos en un compromiso condicional. B3 y necesitamos obtener la diferencia de 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

Para determinar A3 Usemos la API de GitHub:

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

Usamos las siguientes variables que proporciona Buddy:

  • $BUDDY_EXECUTION_PULL_REQEUST_NO — número de solicitud de extracción;
  • $BUDDY_REPO_SLUG — una combinación de nombre de usuario y repositorio (por ejemplo max/test).

Ahora guardemos los cambios usando el botón a continuación y habilitemos el análisis de la solicitud de extracción:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
A diferencia de Travis CI, no necesitamos especificar .pvs-estudio para el almacenamiento en caché, ya que Buddy almacena automáticamente en caché todos los archivos para lanzamientos posteriores. Por tanto, lo último que queda es guardar el nombre de usuario y la contraseña de PVS-Studio en Buddy. Después de guardar los cambios, regresaremos a Pipeline. Necesitamos pasar a configurar variables y agregar un inicio de sesión y una clave para PVS-Studio:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Después de esto, la aparición de una nueva solicitud de extracción o confirmación activará la revisión. Si una confirmación contiene errores, Buddy lo indicará en la página de solicitud de extracción.

AppVeyor

Configurar AppVeyor es similar a Buddy, ya que todo sucede en la interfaz web y no es necesario agregar un archivo *.yml al repositorio del proyecto.

Vayamos a la pestaña Configuración en la descripción general del proyecto:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Desplácese hacia abajo en esta página y habilite el guardado de caché para recopilar solicitudes de extracción:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Ahora vayamos a la pestaña Entorno, donde especificamos la imagen para el ensamblaje y las variables de entorno necesarias:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Si ha leído las secciones anteriores, está muy familiarizado con estas dos variables: PVS_KEY и PVS_NOMBRE DE USUARIO. Si no, déjame recordarte que son necesarios para verificar la licencia del analizador PVS-Studio. Los veremos nuevamente en scripts Bash en el futuro.

En la misma página a continuación indicamos la carpeta para el almacenamiento en caché:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Si no hacemos esto, analizaremos todo el proyecto en lugar de un par de archivos, pero obtendremos el resultado de los archivos especificados. Por lo tanto, es importante ingresar el nombre del directorio correcto.

Ahora es el momento de probar el guión. Abra la pestaña Pruebas y seleccione Script:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Debe pegar el siguiente código en este 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 a la siguiente parte del 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

La asignación bastante específica del valor del comando pwd a una variable que debería almacenar este valor predeterminado parece extraña a primera vista, sin embargo, lo explicaré todo ahora.

Mientras configuraba el analizador en AppVeyor, encontré un comportamiento extremadamente extraño del analizador. Por un lado, todo funcionó correctamente, pero el análisis no se inició. Pasé mucho tiempo notando que estamos en el directorio /home/appveyor/projects/testcalc/, y el analizador está seguro de que estamos en /opt/appveyor/build-agent/. Entonces me di cuenta de que la variable $PWD mentía un poco. Por este motivo, actualicé manualmente su valor antes de iniciar el análisis.

Y luego todo es como antes:

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio
Consideremos ahora el siguiente 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"`

En él obtenemos la diferencia entre las ramas sobre las que se declara la solicitud de extracción. Para hacer esto necesitamos las siguientes variables de entorno:

  • $APPVEYOR_PULL_REQUEST_NUMBER — número de solicitud de extracción;
  • $APPVEYOR_REPO_NAME: nombre de usuario y repositorio de proyectos.

Conclusión

Por supuesto, no hemos considerado todos los posibles servicios de integración continua, sin embargo, todos tienen características operativas extremadamente similares entre sí. A excepción del almacenamiento en caché, cada servicio crea su propia “bicicleta”, por lo que todo es siempre diferente.

En algún lugar, como en Travis-CI, un par de líneas de código y almacenamiento en caché funcionan a la perfección; en algún lugar, como en AppVeyor, solo necesita especificar la carpeta en la configuración; pero en algún lugar debe crear claves únicas e intentar convencer al sistema para que le dé la oportunidad de sobrescribir el fragmento almacenado en caché. Por lo tanto, si desea configurar un análisis de solicitudes de extracción en un servicio de integración continua que no se analizó anteriormente, primero asegúrese de no tener problemas con el almacenamiento en caché.

Gracias por su atención. Si algo no funciona, no dudes en escribirnos a apoyar. Le asesoraremos y ayudaremos.

Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio

Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace de traducción: Maxim Zvyagintsev. Análisis de commits y pull request en Travis CI, Buddy y AppVeyor usando PVS-Studio.

Fuente: habr.com

Añadir un comentario