Análisis de solicitudes de fusión en GitLab usando PVS-Studio para C #

image1.png


¿Te encanta GitLab y no te gustan los errores? ¿Quiere mejorar la calidad de su código fuente? Entonces has venido al lugar correcto. Hoy le diremos cómo configurar el analizador PVS-Studio C # para verificar las solicitudes de combinación. Todo el humor de unicornio y una lectura agradable.



PVS-Studio es una herramienta para detectar 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. Puede analizar código para plataformas ARM de 32 bits, 64 bits e integradas.



Por cierto, hemos lanzado PVS-Studio 7.08, en el que hemos hecho muchas cosas interesantes . Por ejemplo:



  • Analizador de C # para Linux y macOS;
  • complemento para Rider;
  • nuevo modo para comprobar la lista de archivos.


Modo de verificación de lista de archivos



Anteriormente, para verificar ciertos archivos, era necesario pasar un .xml con una lista de archivos al analizador. Pero como no es muy conveniente, agregamos la capacidad de transferir .txt, lo que hace la vida muy fácil.



Para verificar archivos específicos, debe especificar la marca --sourceFiles ( -f ) y pasar .txt con una lista de archivos. Se parece a esto:



pvs-studio-dotnet -t path/to/solution.sln -f fileList.txt -o project.json


Si está interesado en configurar la verificación de confirmaciones o solicitudes de extracción, también puede hacerlo usando este modo. La diferencia estará en obtener una lista de archivos para analizar y dependerá de los sistemas que esté utilizando.



Principio de verificación de solicitud de fusión



El punto principal de la verificación es asegurar que los problemas detectados por el analizador no terminen en la rama maestra durante la fusión . Además, no queremos analizar todo el proyecto cada vez. Además, al fusionar ramas, tenemos una lista de archivos modificados. Por lo tanto, sugiero agregar un cheque para la solicitud de fusión.



Así es como se ve una solicitud de fusión antes de implementar un analizador estático:



image2.png


Es decir, todos los errores que estaban en la rama de cambios irán a la rama maestra. Como no nos gustaría esto, agregamos análisis, y ahora el diagrama se ve así:



image3.png


Analizamos los cambios2 y, si no hay errores, aceptamos la solicitud de fusión, en caso contrario la rechazamos.



Por cierto, si está interesado en analizar confirmaciones y solicitudes de extracción para C / C ++, puede leerlo aquí .



Gitlab



GitLab es una herramienta de ciclo de vida de DevOps basada en la web de código abierto que proporciona un sistema de gestión de repositorio de código para Git con su propia wiki, rastreador de errores, canalización de CI / CD y más.



Antes de comenzar a implementar el análisis de las solicitudes de fusión, debe registrarse y cargar su proyecto. Si no sabe cómo hacer esto, le sugiero un artículo de mi colega.



Nota... El método de configuración del entorno que se describe a continuación es uno de los posibles. El objetivo es mostrar los pasos para configurar el entorno necesario para el análisis y ejecutar el analizador. Quizás, en tu caso, sería más óptimo separar las etapas de preparación del entorno (agregar repositorios, instalar el analizador) y análisis: por ejemplo, preparar imágenes de Docker con el entorno necesario y usarlas, o algún otro método.



Para comprender mejor lo que va a suceder ahora, sugiero echar un vistazo al siguiente diagrama:



image4.png


El analizador requiere .NET Core SDK 3 para funcionar, por lo que antes de instalar el analizador, debe agregar los repositorios de Microsoft, desde los cuales se instalarán las dependencias necesarias para el analizador. La adición de repositorios de Microsoft para varias distribuciones de Linux se describe en el documento correspondiente .



Para instalar PVS-Studio a través del administrador de paquetes, también necesitará agregar repositorios de PVS-Studio. La adición de repositorios para diferentes distribuciones se describe con más detalle en la sección correspondiente de la documentación .



El analizador requiere una clave de licencia para funcionar. Puede obtener una licencia de prueba en la página de descarga del analizador .



Nota... Tenga en cuenta que el modo de funcionamiento descrito (análisis de solicitudes de fusión) requiere una licencia Enterprise. Por tanto, si quieres probar este modo de funcionamiento, no olvides indicar en el campo "Mensaje" que necesitas la licencia Enterprise.



Si se produce una solicitud de fusión, necesitamos analizar solo la lista de archivos modificados; de lo contrario, analizamos todos los archivos. Después del análisis, necesitamos convertir los registros al formato que necesitamos.



Ahora, teniendo ante tus ojos el algoritmo de trabajo, puedes proceder a escribir un guión. Para hacer esto, necesita modificar el archivo .gitlab-ci.yml o, si no es así, crearlo. Para crearlo, debe hacer clic en el nombre de su proyecto -> Configurar CI / CD .



image5.png


Ahora estamos listos para escribir el guión. Primero escribamos el código que instalará el analizador e ingresemos la licencia:



before_script:
  - apt-get update && apt-get -y install wget gnupg 

  - apt-get -y install git
  - wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
  - dpkg -i packages-microsoft-prod.deb
  - apt-get update
  - apt-get install apt-transport-https
  - apt-get update
  
  - 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-dotnet

  - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY
  - dotnet restore "$CI_PROJECT_DIR"/Test/Test.sln


Dado que la instalación y activación deben ocurrir antes que todos los demás scripts, usamos una etiqueta especial before_script . Explicaré un poco este fragmento.



Preparación para instalar el analizador:



  - wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
  - dpkg -i packages-microsoft-prod.deb
  - apt-get update
  - apt-get install apt-transport-https
  - apt-get update


Agregar repositorios y analizadores de PVS-Studio:



  - 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-dotnet


Activación de licencia:



  - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY


$ PVS_NAME : nombre de usuario.



$ PVS_KEY : clave de producto.



Restaurando las dependencias del proyecto, donde $ CI_PROJECT_DIR es la ruta completa al directorio del proyecto:



  - dotnet restore "$CI_PROJECT_DIR"/Path/To/Solution.sln


Para un análisis correcto, el proyecto debe compilarse correctamente y sus dependencias deben restaurarse (por ejemplo, se deben cargar los paquetes NuGet necesarios).



Puede establecer variables de entorno que contengan información de licencia haciendo clic en Configuración y luego en CI / CD .



image6.png


En la ventana que se abre, busque el elemento Variables , a la derecha, haga clic en el botón Expandir y agregue variables. El resultado debería verse así:



image7.png


Ahora puede continuar con el análisis. Primero, agreguemos un script para un análisis completo. Pasamos la ruta a la solución al indicador -t , y en el indicador -o escribimos la ruta al archivo en el que se escribirán los resultados del análisis. También estamos interesados ​​en el código de retorno. En este caso, nos interesa que la operación finalice cuando el código de retorno contiene información de que se emitieron advertencias durante el análisis. Este es el aspecto de este fragmento:



job:
  script:
  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -o 
PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi


Los códigos de retorno funcionan como una máscara de bits. Por ejemplo, si, como resultado del análisis, se emitieron advertencias, entonces el código de retorno será 8. Si la licencia expira dentro de un mes, el código de retorno será 4. Si se encontraron errores durante el análisis y la licencia expira dentro de un mes, en el código return, se escribirán ambos valores: sume los números y obtenga el código de retorno final - 8 + 4 = 12. Por lo tanto, al verificar los bits correspondientes, se puede obtener información sobre varios estados durante el análisis. Los códigos de retorno se describen con más detalle en la sección "códigos de retorno de pvs-studio-dotnet (Linux / macOS)" del documento " Comprobación de proyectos de Visual Studio / MSBuild / .NET Core desde la línea de comandos con PVS-Studio ".



En este caso, estamos interesados ​​en todos los códigos de retorno,donde aparece 8.



  - exit_code=$((($exit_code & 8)/8))


Obtendremos 1 cuando el código de retorno contenga el bit del número que nos interesa, de lo contrario obtendremos 0.



Es hora de agregar el análisis de la solicitud de fusión. Antes de hacer esto, preparemos un lugar para el guión. Solo necesitamos que se ejecute cuando se produce una solicitud de fusión. Se parece a esto:



merge:
  script:
  only:
  - merge_requests


Pasemos al guión en sí. Me encontré con el hecho de que la máquina virtual no sabe nada sobre origen / maestro . Por eso, la ayudamos un poco:



  - git fetch origin


Ahora obtengamos la diferencia entre las ramas y guardemos el resultado en un archivo txt :



  - git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt


Donde $ CI_COMMIT_SHA es el hash de la última confirmación.



A continuación, ejecutamos el análisis de la lista de archivos usando el indicador -f . Le transferimos el archivo .txt anterior recibido. Bueno, por analogía con el análisis completo, miramos los códigos de retorno:



  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f 
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi


El script completo para verificar la solicitud de fusión se verá así:



merge:
  script:
  - git fetch origin
  - git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt
  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f 
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
  only:
  - merge_requests


Solo queda agregar la conversión del registro después de que se hayan ejecutado todos los scripts. Usamos la etiqueta after_script y la utilidad plog-converter :



after_script:
  - plog-converter -t html -o eLog ./PVS-Studio.json


La utilidad plog-converter es un proyecto de código abierto que se utiliza para convertir el informe de errores del analizador en varias formas, como HTML. Se ofrece una descripción más detallada de la utilidad en la subsección "Utilidad de conversión de Plog" de la sección correspondiente de la documentación .



Por cierto, si desea trabajar convenientemente con informes .json localmente desde el IDE, le sugiero nuestro complemento para IDE Rider. Su uso se describe con más detalle en el documento correspondiente .



Para mayor comodidad, aquí está el .gitlab-ci.yml completo :



image: debian

before_script:
  - apt-get update && apt-get -y install wget gnupg 

  - apt-get -y install git
  - wget https://packages.microsoft.com/config/debian/10/
packages-microsoft-prod.deb -O packages-microsoft-prod.deb
  - dpkg -i packages-microsoft-prod.deb
  - apt-get update
  - apt-get install apt-transport-https
  - apt-get update
  
  - 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-dotnet

  - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY
  - dotnet restore "$CI_PROJECT_DIR"/Test/Test.sln

merge:
  script:
  - git fetch origin
  - git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt
  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f 
pvs-fl.txt -o PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
  only:
  - merge_requests

job:
  script:
  - exit_code=0
  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -o 
PVS-Studio.json || exit_code=$?
  - exit_code=$((($exit_code & 8)/8))
  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi
  
after_script:
  - plog-converter -t html -o eLog ./PVS-Studio.json


Una vez que se haya agregado todo al archivo, haga clic en Confirmar cambios . Para ver que todo está correcto, vaya a CI / CD -> Pipelines -> Running . Se abrirá una ventana de máquina virtual, al final de la cual debería ser la siguiente:



image8.png


Vimos que Job tuvo éxito: éxito, todo está bien. Ahora puede probar lo que ha hecho.



Ejemplos de trabajo



Para un ejemplo de trabajo, creemos un proyecto simple (en maestro ) en el que habrá varios archivos. Después de eso, en otra rama, cambiaremos solo un archivo e intentaremos realizar una solicitud de fusión.



Considere dos casos: cuando el archivo modificado contiene un error y cuando no. Primero, un ejemplo con un error.



Digamos que hay un archivo Program.cs en la rama maestra , que no contiene errores, y en otra rama, el desarrollador ha agregado código erróneo y quiere realizar una solicitud de fusión. El tipo de error que cometió no es tan importante, lo principal es que existe. Por ejemplo, olvidé el operador de lanzamiento (sí, están tan mal ):



void MyAwesomeMethod(String name)
{
  if (name == null)
    new ArgumentNullException(....);
  // do something
  ....
}


Veamos el resultado de analizar un ejemplo con error. Además, para asegurarme de que solo se analizó un archivo, agregué la marca -r a la línea de inicio pvs-studio-dotnet:



image9.png


Vemos que el analizador encontró un error y no permitió la fusión de ramas.



Comprobando el ejemplo sin error. Arreglando el código:



void MyAwesomeMethod(String name)
{
  if (name == null)
    throw new ArgumentNullException(....);
  // do something
  ....
}


Resultados del análisis de la solicitud de fusión:



image10.png


Como podemos ver, no se encontraron errores y la ejecución de la tarea fue exitosa, lo cual queríamos verificar.



Conclusión



Filtrar el código incorrecto antes de fusionar ramas es muy conveniente y agradable. Por lo tanto, si está utilizando CI / CD, intente construir un analizador estático para realizar pruebas. Además, esto se hace de forma bastante sencilla.



Gracias por su atención.





Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace de traducción: Nikolay Mironov. Análisis de solicitudes de fusión en GitLab usando PVS-Studio para C # .



All Articles