A partir de la versión 7.04, el analizador PVS-Studio para lenguajes C y C ++ en Linux y macOS tiene una capacidad de prueba para verificar la lista de archivos especificados. Usando el nuevo modo, puede configurar el analizador para verificar las confirmaciones y las solicitudes de extracción. Este artículo le mostrará cómo configurar la comprobación de la lista de archivos modificados de un proyecto GitHub en sistemas de CI (integración continua) tan populares como Travis CI, Buddy y AppVeyor.
Modo de comprobación de la lista de archivos
PVS-Studio es una herramienta para detectar errores y vulnerabilidades potenciales 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 PVS-Studio versión 7.04 para Linux y macOS, apareció el modo de verificar la lista de archivos fuente. Esto funciona para proyectos cuyo sistema de compilación permite
generar el archivo
compile_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 utilizando la utilidad
Bear .
Además, el modo de verificación de la lista de archivos se puede usar junto con el registro de seguimiento de strace de los inicios del compilador (seguimiento de pvs-studio-analyzer). Para hacer esto, primero deberá realizar un ensamblaje completo 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 probados.
Sin embargo, esta opción tiene un inconveniente significativo: deberá realizar un seguimiento completo del ensamblaje de todo el proyecto en cada inicio, lo que en sí mismo contradice la idea de verificar rápidamente la confirmación. O, si el resultado del seguimiento en sí mismo se almacena en caché, los inicios posteriores del analizador pueden no estar completos si la estructura de dependencia de los archivos de origen cambia después del seguimiento (por ejemplo, se agrega un nuevo #include a uno de los archivos de origen).
Por lo tanto, no recomendamos utilizar el modo de verificación de la lista de archivos con el registro de seguimiento para verificar las confirmaciones o las solicitudes de extracción. Si puede hacer un ensamblaje incremental al verificar una confirmación, considere usar el modo de
análisis incremental .
La lista de archivos fuente para análisis se guarda en un archivo de texto y se transfiere al analizador utilizando el parámetro
-S :
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt
En este archivo, se indican las rutas relativas o absolutas a los archivos, y cada nuevo archivo debe estar en una nueva línea. Está permitido especificar no solo los nombres de los archivos para el análisis, sino también varios textos. El analizador verá que este no es un archivo e ignorará la línea. Esto puede ser ú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 pueden ser archivos de una solicitud de confirmación o extracción.
Ahora, usando este modo, puede verificar rápidamente el nuevo código antes de que entre en la rama de desarrollo principal. Para que el sistema de verificación responda a las advertencias del analizador, se ha agregado el
indicador --indicate-warnings a la
utilidad plog-converter :
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 la solicitud de enlace previo, confirmación o extracción y mostrar el informe del analizador generado en la pantalla, compartir o enviar por correo.
Nota La primera vez que ejecute el análisis de la lista de archivos, se analizará todo el proyecto, porque el analizador necesita generar un archivo de dependencias de los archivos fuente del proyecto a partir de 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 sobre el uso del modo de análisis incremental es que solo necesita almacenar en caché este archivo, no los archivos de objetos.Principios generales del análisis de solicitud de extracción
El análisis de todo el proyecto lleva mucho tiempo, por lo que tiene sentido verificar solo una parte del mismo. El problema es que necesita separar los archivos nuevos del resto de los archivos del proyecto.
Considere un ejemplo de un árbol de confirmación con dos ramas:
Imaginemos que commit
A1 contiene una cantidad bastante grande de código que ya ha sido probado. Un poco antes, creamos una rama desde el commit
A1 y cambiamos algunos archivos.
Por supuesto, notó que después de
A1 hubo dos commits más, pero también fueron fusiones de otras ramas, porque no nos comprometemos en
master . Y ahora ha llegado el momento en que la
revisión está lista. Por lo tanto,
apareció una solicitud de extracción para la fusión de
B3 y
A3 .
Por supuesto, uno podría verificar todo el resultado de su fusión, pero esto sería demasiado largo e injustificado, ya que solo se modificaron algunos archivos. Por lo tanto, es más eficiente analizar solo los cambios.
Para hacer esto, obtenemos la diferencia entre las ramas, estando en la CABEZA de la rama de la que queremos fusionarnos en master:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
$ MERGE_BASE lo consideraremos con más detalle más adelante. El hecho es que no todos los servicios de CI proporcionan la información necesaria sobre la base para la fusión, por lo que cada vez que tiene que encontrar nuevas formas de obtener estos datos. Esto se detallará 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 se han cambiado. Ahora tenemos que dar el
archivo .pvs-pr.list (redirigimos el resultado al anterior) 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) en un formato que sea fácil de leer:
plog-converter -t errorfile PVS-Studio.log --cerr -w
Este comando enumerará los errores en
stderr (secuencia de salida de mensaje de error estándar).
Solo ahora necesitamos no solo mostrar errores, sino también informar a nuestro servicio para el montaje y la prueba de problemas. Para hacer esto, se agregó la bandera
-W (
--indicate-warnings ) al convertidor. Si hay al menos una advertencia del analizador, el código de retorno de la utilidad
plog-converter cambiará a 2, lo 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 . Por conveniencia, le aconsejo que coloque todo en un script bash separado con funciones que se
invocarán desde el archivo
.travis.yml (
bash script_name.sh function_name ).
Agregaremos el código necesario al script
bash , para obtener más funcionalidad. En la sección de
instalación , escriba lo siguiente:
install: - bash .travis.sh travis_install
Si tenía alguna instrucción, puede transferirla al script eliminando guiones.
Abra el archivo
.travis.sh y agregue la instalación del analizador a la 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 }
Ahora agregue el análisis ejecutado a la sección de
script :
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 haya notado las variables de entorno especificadas
$ TRAVIS_PULL_REQUEST y
$ TRAVIS_BRANCH . Travis CI los anuncia por su cuenta:
- $ TRAVIS_PULL_REQUEST almacena el número de solicitud de extracción o falso si es una rama regular;
- $ TRAVIS_REPO_SLUG almacena el nombre del repositorio del proyecto.
El algoritmo de esta función:
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 automáticamente las sucursales durante el análisis de solicitud de extracción:
Por lo tanto, analizamos
A4 , no
B3-> A3 . Debido a esta característica, necesitamos calcular la diferencia con
A3 , que es precisamente la parte superior de la rama desde el
origen .
Quedaba un detalle importante: el almacenamiento en caché de las dependencias de los archivos de encabezado en las unidades de traducción compiladas (* .c, * .cc, * .cpp, etc.). El analizador calcula estas dependencias en el primer inicio en el modo de verificar la lista de archivos y luego la guarda en el directorio .PVS-Studio. Travis CI le permite almacenar en caché las 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 varios datos recopilados después del análisis, lo que acelerará significativamente los lanzamientos posteriores de análisis de listas de archivos o análisis incrementales. Si esto no se hace, el analizador analizará todos los archivos cada vez.
Amigo
Al igual que Travis CI,
Buddy ofrece la capacidad de crear y probar automáticamente proyectos que están almacenados en GitHub. A diferencia de Travis CI, está configurado en la interfaz web (el soporte de bash está 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:
Indicamos el compilador que se utilizó para construir el proyecto. Preste atención al contenedor acoplable que se instala en esta acción. Por ejemplo, hay un contenedor especial para GCC:
Ahora instale PVS-Studio y las utilidades necesarias:
Agregue 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 vaya a la pestaña Ejecutar (primer ícono) y agregue el siguiente código al campo apropiado del editor:
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 lee la sección sobre Travs-CI, este código ya le es familiar, sin embargo, ahora ha aparecido una nueva etapa:
El hecho es que ahora estamos analizando no el resultado de la fusión, sino el HEAD de la rama desde la que se realiza la solicitud de extracción:
Por lo tanto, estamos en la confirmación condicional
B3 y necesitamos obtener la diferencia con
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, use la API de GitHub:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}
Utilizamos las siguientes variables que Buddy proporciona:
- $ BUDDY_EXECUTION_PULL_REQEUST_NO - extraer el número de solicitud ;
- $ BUDDY_REPO_SLUG : combinación de nombre de usuario y repositorio (por ejemplo max / test).
Ahora guarde los cambios con el botón a continuación y habilite el análisis de solicitud de extracción:
A diferencia de Travis CI, no necesitamos especificar
.pvs-studio para el almacenamiento en caché, ya que Buddy almacena automáticamente en caché todos los archivos para lanzamientos posteriores. Por lo tanto, lo último que queda es guardar el inicio de sesión y la contraseña para PVS-Studio en Buddy. Después de guardar los cambios, volveremos a Pipeline. Necesitamos continuar con la configuración de las variables y agregar el inicio de sesión y la clave para PVS-Studio:
Después de eso, la aparición de una nueva solicitud de extracción o confirmación activará una verificación. Si la confirmación contiene errores, Buddy lo indicará en la página de solicitud de extracción.
Transportador
La configuración de AppVeyor es similar a la de Buddy, ya que todo sucede en la interfaz web y no es necesario agregar un archivo * .yml al repositorio del proyecto.
Vaya a la pestaña Configuración en la descripción general del proyecto:
Desplácese hacia abajo en esta página y active el almacenamiento en caché para crear solicitudes de extracción:
Ahora vaya a la pestaña Entorno, donde especificamos la imagen para el ensamblaje y las variables de entorno necesarias:
Si lee las secciones anteriores, está familiarizado con estas dos variables:
PVS_KEY y
PVS_USERNAME . De lo contrario, le recuerdo que son necesarios para verificar la licencia del analizador PVS-Studio. En el futuro, los volveremos a encontrar en los scripts de Bash.
En la misma página a continuación indicamos la carpeta para el almacenamiento en caché:
Si no lo hacemos, 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 de directorio correcto.
Ahora es el momento de verificar el guión. Abra la pestaña Pruebas y seleccione Script:
Inserte 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
Presta 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 la variable que debería almacenar este valor predeterminado parece extraño a primera vista, sin embargo, explicaré todo ahora.
Mientras configuraba el analizador en AppVeyor, me encontré con un comportamiento de analizador extremadamente extraño. Por un lado, todo funcionó correctamente, pero el análisis no comenzó. Pasé mucho tiempo para notar 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 está mintiendo un poco. Por esta razón, actualicé manualmente su valor antes de comenzar el análisis.
Y luego todo, como antes:
Ahora considere 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 cuales 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 del proyecto.
Conclusión
Por supuesto, no consideramos todos los servicios posibles de integración continua, sin embargo, todos ellos tienen características de trabajo muy similares entre sí. Con la excepción del almacenamiento en caché, cada servicio hace 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 perfectamente; 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 brinde la oportunidad de sobrescribir el fragmento almacenado en caché. Por lo tanto, si desea configurar el análisis de solicitudes de extracción en el servicio de integración continua, que no se discutió anteriormente, primero asegúrese de que no tendrá problemas con el almacenamiento en caché.
Gracias por su atencion Si algo no funciona, no dude en escribirnos en
apoyo . Le solicitaremos ayuda.

Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace a la traducción: Maxim Zvyagintsev.
Análisis de confirmaciones y solicitudes de extracción en Travis CI, Buddy y AppVeyor utilizando PVS-Studio .