A partir de la versión 7.04, el analizador PVS-Studio para los lenguajes C y C ++ en Linux y macOS proporciona la función de prueba de 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 cubre la configuración de la verificación de ciertos archivos modificados de un proyecto GitHub en sistemas populares de CI (integración continua), como Travis CI, Buddy y AppVeyor.
Modo de verificar la lista de archivos
PVS-Studio es una herramienta diseñada para detectar errores y vulnerabilidades potenciales en el código fuente de los 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 ahora existe el modo de verificar la lista de archivos. Funciona para proyectos, cuyo sistema de compilación permite generar el archivo
compile_commands.json . Es necesario para que el analizador obtenga información sobre la compilación de ciertos archivos. 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 .
Este modo de verificar la lista de archivos también se puede usar con el registro de seguimiento de ejecución del compilador generado por strace (pvs-studio-analyzer trace). Para hacerlo, primero debe completar una compilación completa del proyecto y rastrearla para que el analizador recopile información completa sobre los parámetros de compilación de todos los archivos verificados.
Sin embargo, esta opción tiene un inconveniente importante: tendrá que realizar un seguimiento de compilación completo de todo el proyecto con cada ejecución, lo que va en contra de la idea de una comprobación de confirmación rápida. O si almacena en caché el resultado del seguimiento en sí, las ejecuciones posteriores del analizador podrían estar incompletas en caso de que después de rastrear la estructura de los cambios de dependencias de los archivos de origen (por ejemplo, se agregue un nuevo #include en uno de los archivos de origen).
Por lo tanto, no recomendamos usar el modo de verificar la lista de archivos con un registro de seguimiento para verificar las confirmaciones o las solicitudes de extracción. Si puede realizar una compilación incremental al verificar una confirmación, considere usar el modo de
análisis incremental .
La lista de archivos fuente para el análisis se guarda en el archivo de texto y se pasa al analizador utilizando el parámetro
-S :
pvs-studio-analyzer analyze ... -f build/compile_commands.json -S check-list.txt
Este archivo contiene rutas relativas y absolutas a los archivos donde cada nuevo archivo entra en una nueva línea. Puede especificar ambos nombres de archivo para el análisis y texto diferente. En cuanto al texto, el analizador notará que no es un nombre de archivo e ignorará la línea. Puede ser útil para comentar si los archivos se especifican manualmente. Sin embargo, a menudo la lista de archivos se generará durante el análisis de CI, por ejemplo, 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. El
indicador --indicate-warnings se agregó en la utilidad
plog-converter para que el sistema de verificación respondiera a la presencia de advertencias del analizador.
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. Puede bloquear la solicitud de enlace de confirmación previa, confirmación o extracción y mostrar el informe del analizador generado, compartirlo o enviarlo por correo.
Nota Durante el primer análisis de la lista de archivos, se verificará todo el proyecto, ya que el analizador debe generar el archivo con dependencias de los archivos fuente del proyecto a partir de los archivos de encabezado. Esta es una peculiaridad del análisis de archivos C y C ++. En el futuro, este archivo de dependencia se puede almacenar en caché y el analizador lo actualizará automáticamente. La ventaja de verificar las confirmaciones utilizando el modo de verificar la lista de archivos sobre el modo de análisis incremental es el hecho de que debe almacenar en caché solo este archivo, no los archivos de objeto.Principios generales del análisis de solicitud de extracción
El análisis completo del proyecto lleva bastante tiempo, por lo que tiene sentido verificar solo una parte. El problema es que necesita separar los archivos nuevos del resto de los archivos del proyecto.
Veamos el ejemplo de un árbol de confirmación de dos ramas:
Imagine que la confirmación
A1 contiene una cantidad bastante grande de código que ya se ha verificado. Anteriormente, creamos una rama desde la confirmación
A1 y cambiamos algunos archivos.
Por supuesto, habrás notado que después de
A1 se llevaron a cabo otras dos confirmaciones, y otras dos ramas se fusionaron, ya que no nos comprometemos en
master . Aquí llega el momento en que la
revisión está lista. Es por eso que recibimos una solicitud de extracción para la fusión de
B3 y
A3 .
Podríamos verificar el resultado de su fusión, pero sería demasiado largo e irrazonable, ya que solo se han modificado algunos archivos. Por lo tanto, es más eficiente analizar solo los modificados.
Para hacerlo, recibiremos la diferencia entre las ramas, estando en la CABEZA de la rama, de la que queremos fusionarnos en el maestro:
git diff --name-only HEAD origin/$MERGE_BASE > .pvs-pr.list
Consideraremos
$ MERGE_BASE en detalle más adelante. El hecho es que no todos los servicios de CI proporcionan la información necesaria sobre la base de fusión, por lo que cada vez tenemos que pensar en nuevas formas de obtener estos datos. Esto se considerará en los detalles a continuación para cada uno de los servicios web descritos.
Entonces obtuvimos una diferencia entre las ramas, que es la lista de nombres de archivos modificados. Ahora necesitamos alimentar este archivo
.pvs-pr.list al analizador. Hemos redirigido la salida a ella anteriormente.
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 usar:
plog-converter -t errorfile PVS-Studio.log --cerr -w
Este comando generará la lista de errores en
stderr (flujo de error estándar).
El problema es que no solo necesitamos generar los errores, sino también informar a nuestro servicio de compilación y prueba sobre los problemas. Para hacer esto, se agregó el indicador
-W (
--indicate-warnings ) en el 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 posibles errores en los archivos de solicitud de extracción.
Travis ci
La configuración se realiza en forma de archivo
.travis.yml . Por conveniencia, le aconsejo que aísle todos los comandos relacionados con PVS-Studio en un script bash separado con funciones que se
invocarán desde el archivo
.travis.yml (
bash script_name.sh function_name ).
Al expandir el script, obtendrá más funcionalidad. En la sección de
instalación escriba lo siguiente:
install: - bash .travis.sh travis_install
Si tenía algunas instrucciones, puede moverlas en el script, eliminando los guiones.
Abra el archivo
.travis.sh y agregue la instalación del analizador en 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 agreguemos el analizador ejecutado en 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 }
Debe ejecutar este código después de compilar el proyecto, por ejemplo, si tuvo una compilación en CMake:
travis_script() { CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}" cmake $CMAKE_ARGS CMakeLists.txt make -j8 }
Obtendrás lo siguiente:
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 }
Lo más probable es que ya haya notado las variables de entorno
$ TRAVIS_PULL_REQUEST y
$ TRAVIS_BRANCH . Travis CI los declara a sí mismo:
- $ 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.
Aquí está el algoritmo operativo de esta función:
Travis CI responde a los códigos de retorno, por lo que la presencia de advertencias informará que el servicio marcará el compromiso 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 ramas al analizar una solicitud de extracción:
Por eso analizamos
A4 , no
B3-> A3 . Debido a esta peculiaridad, necesitamos evaluar la diferencia con
A3 , que es la cabeza de la rama desde el
origen .
Queda un detalle importante: el almacenamiento en caché de las dependencias de los archivos de encabezado de las unidades de traducción compiladas (* .c, * .cc, * .cpp y otras). El analizador evalúa estas dependencias durante la primera ejecución en el modo de verificar la lista de archivos y luego los almacena en el directorio .PVS-Studio. Travis CI permite el almacenamiento en caché de repositorios, por lo que
guardaremos datos en el
directorio .PVS-Studio / :
cache: directories: - .PVS-Studio/
Este código debe agregarse en el archivo
.travis.yml : este directorio almacena varios datos, recopilados después del análisis. Estos datos aceleran significativamente las ejecuciones posteriores de análisis de listas de archivos o análisis incremental. Si no lo hace, el analizador analizará todos los archivos cada vez.
Amigo
Al igual que Travis CI,
Buddy le permite crear y probar proyectos automáticamente desde 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.
Primero, necesitamos agregar un nuevo paso a la tubería:
Especifiquemos el compilador utilizado para construir el proyecto. Preste atención al contenedor acoplable, instalado durante este paso. Por ejemplo, hay un contenedor especial para GCC:
Ahora instalemos 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
Pasemos a la pestaña Ejecutar (primer icono) y agreguemos el siguiente código al campo del editor apropiado:
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 le es familiar. Pero aquí hay un nuevo paso:
El hecho es que ahora analizamos no el resultado de la fusión, sino el HEAD de la rama con la solicitud de extracción marcada:
Así que estamos en una confirmación de
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 definir
A3 , usemos la API de GitHub:
https://api.github.com/repos/${USERNAME}/${REPO}/pulls/${PULL_REQUEST_ID}
Utilizamos las siguientes variables, que Buddy nos proporciona:
- $ BUDDY_EXECUTION_PULL_REQEUST_NO : número de una solicitud de extracción;
- $ BUDDY_REPO_SLUG : combinación de un nombre de usuario y un repositorio (por ejemplo, max / test).
Ahora guardemos los cambios, usando el botón de abajo y habilite el análisis de solicitud de extracción:
A diferencia de Travis CI, no tenemos que especificar
.pvs-studio para el almacenamiento en caché, ya que Buddy almacena automáticamente en caché todos los archivos para ejecuciones posteriores. Entonces, lo último que queda es guardar el nombre de usuario y la contraseña para PVS-Studio en Buddy. Después de guardar los cambios, volveremos a la canalización. Necesitamos pasar a configurar las variables e insertar el inicio de sesión y la clave para PVS-Studio:
Después de esto, se iniciará una verificación con cada nueva solicitud de extracción o confirmación. Si un commit contiene errores, Buddy lo señalará en la página de solicitud de extracción.
Transportador
La configuración de AppVeyor es similar a Buddy, ya que todo sucede en la interfaz web y no es necesario agregar el archivo * .yml en el repositorio del proyecto.
Vayamos a la pestaña Configuración en la revisión del proyecto:
Desplácese hacia abajo en esta página y habilite el almacenamiento en caché para la compilación de solicitud de extracción:
Ahora pasemos a la pestaña Entorno, donde especificaremos la imagen para la compilación y las variables de entorno necesarias:
Si ha leído las secciones anteriores, ya está familiarizado con estas dos variables:
PVS_KEY y
PVS_USERNAME . Si no, permítame recordarle 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 en la parte inferior, especifiquemos la carpeta de caché:
Si no lo hacemos, analizaremos todo el proyecto en lugar de un par de archivos, pero recibiremos el resultado de los archivos especificados. Por lo tanto, es importante ingresar el nombre correcto del repositorio.
Ahora ha llegado el momento de la secuencia de comandos de verificación. Abra la pestaña Pruebas y elija Script:
El siguiente código debe insertarse 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
Es una asignación bastante específica del valor de salida del comando pwd a la variable, que tiene que almacenar este valor por defecto. Al principio parece extraño, pero déjame explicarte todo.
Mientras configuraba el analizador en AppVeyor, me topé con un comportamiento muy extraño del analizador. Por un lado, todo funcionó correctamente, pero el análisis no comenzó. Nos llevó mucho tiempo notar que estábamos en el directorio / home / appveyor / projects / testcalc /, mientras que el analizador estaba seguro de que estábamos en / opt / appveyor / build-agent /. En ese momento me di cuenta de que la variable $ PWD es engañosa. Por esta razón, renove manualmente su valor antes de ejecutar el análisis.
El orden adicional de las acciones fue el mismo que anteriormente:
Ahora eche un vistazo a este 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 ramas, relacionada con la solicitud de extracción comprobada. Para hacer esto, necesitamos las siguientes variables de entorno:
- $ APPVEYOR_PULL_REQUEST_NUMBER - extraer el número de solicitud;
- $ APPVEYOR_REPO_NAME: nombre de usuario y repositorio del proyecto.
Conclusión
Bueno, no hemos considerado todos los servicios de integración continua posibles, sin embargo, todos tienen detalles operativos similares. Pero en cuanto al almacenamiento en caché, cada servicio reinventa su propia rueda, por lo que siempre es diferente.
En algunos casos (como en Travis-CI) se necesitan un par de líneas de código, y el almacenamiento en caché funciona a la perfección. En otros casos (como en AppVeyor), solo tiene que especificar el directorio en la configuración. Pero hay algunos servicios en los que necesita crear claves especiales e intentar convencer al sistema para que le brinde la oportunidad de reescribir un fragmento almacenado en caché. Por lo tanto, si desea configurar el análisis de solicitud de extracción en un servicio de integración continua, que no se consideró anteriormente, primero, asegúrese de que no tendrá problemas con el almacenamiento en caché.
Gracias por su atencion Si algo no funciona, puede escribir con seguridad a nuestro
soporte . Le daremos una pista y ayuda.