En nuestro trabajo, utilizamos activamente la plataforma SonarQube para mantener la calidad del código a un alto nivel. Al integrar uno de los proyectos escritos en VueJs+Typescript, surgieron problemas. Por eso, me gustaría contarles más sobre cómo pudieron resolverse.

En este artículo se hablará, como mencioné antes, sobre la plataforma SonarQube. Un poco de teoría: ¿qué es esto en realidad, para aquellos que la escuchan por primera vez?
SonarQube (anteriormente Sonar) — es una plataforma de código abierto para el análisis continuo y la medición de la calidad del código.
Soporta el análisis de código y la búsqueda de errores según las reglas de los estándares de programación MISRA C, MISRA C++, MITRE/CWE y CERT Secure Coding Standards. También puede identificar errores de las listas de OWASP Top 10 y CWE/SANS Top 25 errores de programación.
A pesar de que la plataforma utiliza diversas herramientas listas, SonarQube consolida los resultados en un solo panel de información, llevando un historial de ejecuciones y permitiendo así ver la tendencia general del cambio en la calidad del software durante el desarrollo.
Se puede obtener más información en
Soporta una gran cantidad de lenguajes de programación. Según la información del enlace anterior, son más de 25 lenguajes. Para el soporte de un lenguaje específico, es necesario instalar el plugin correspondiente. La versión community incluye el plugin para trabajar con Javascript (incluido typesсript), aunque en la wiki se indica lo contrario. Por Javascript se encarga el plugin SonarJS, para Typescript SonarTS correspondientemente.
Para enviar información sobre la cobertura se utiliza el cliente oficial sonarqube-scanner, que, utilizando la configuración del config-archivo, envía estos datos al servidor SonarQube para su posterior consolidación y agregación.
Para Javascript hay . Así que, comenzamos la implementación paso a paso SonarQube en Vue-proyecto que utiliza Typescript.
Para desplegar el servidor SonarQube utilizaremos docker-compose.
sonar.yaml:
version: '1'
services:
simplesample-sonar:
image: sonarqube:lts
ports:
- 9001:9000
- 9092:9092
network_mode: bridgeInicio:
docker-compose -f sonar.yml upDespués de esto SonarQube estará disponible en la dirección – .

Por ahora no hay proyectos en él y eso es cierto. Vamos a corregir esta situación. Tomé como base el proyecto de ejemplo oficial para VueJS+TS+Jest. Lo clonaremos a nosotros:
git clone https://github.com/vuejs/vue-test-utils-typescript-example.gitPrimero necesitamos instalar el cliente SonarQube, que se llama sonar-scanner, para npm hay un wrapper:
yarn add sonarqube-scannerY de inmediato agregaremos el comando en scripts para trabajar con él.
package.json:
{
…
scripts: {
...
"sonar": "sonar-scanner"
...
},
…
}A continuación, para que funcione el escáner, es necesario establecer la configuración del proyecto en un archivo especial. Comencemos con lo básico.
sonar-project.properties:
sonar.host.url=http://localhost:9001
sonar.projectKey=test-project-vuejs-ts
sonar.projectName=Aplicación de Prueba (VueJS+TS)
sonar.sources=src
# sonar.tests=
sonar.test.inclusions=src/**/*tests*/**
sonar.sourceEncoding=UTF-8- sonar.host.url – dirección Sonarde;
- sonar.projectKey – identificador único del proyecto en el servidor Sonarde;
- sonar.projectName – su nombre, que puede ser cambiado en cualquier momento, ya que la identificación del proyecto se realiza por projectKey;
- sonar.sources – carpeta con los archivos fuente, normalmente es src, pero puede ser cualquier otra. Esta carpeta se define en relación a la carpeta raíz, que es la carpeta desde donde se ejecuta el escáner;
- sonar.tests – parámetro que va en conjunto con el anterior. Esta es la carpeta donde se encuentran las pruebas. En este proyecto, no hay tal carpeta, y la prueba está al lado del componente que se prueba en la carpeta ‘test‘, por lo que por ahora la ignoraremos y utilizaremos el siguiente parámetro;
- sonar.test.inclusions – ruta para las pruebas utilizando una máscara, puede haber varios elementos separados por comas;
- sonar.sourceEncoding – codificación para los archivos fuente.
Para la primera ejecución del escáner, todo está listo, excepto por la acción principal previa: iniciar el motor de pruebas, para que genere información sobre la cobertura, la cual será utilizada posteriormente por el escáner.
Pero para esto es necesario configurar el motor de pruebas para que genere dicha información. En este proyecto, el motor de pruebas es Jest. Y sus configuraciones se encuentran en la sección correspondiente del archivo package.json.
Agreguemos estas configuraciones:
"collectCoverage": true,
"collectCoverageFrom": [
"src/**/*",
"!src/main.ts",
"!src/App.vue",
"!src/**/*.d.*",
"!src/**/*__tests__*"
],Es decir, establecemos el propio flag de necesidad de cálculo de cobertura y la fuente (junto con las excepciones) sobre la cual se formará.
Ahora ejecutemos la prueba:
yarn testVeremos lo siguiente:

La razón es que en el componente no hay código como tal. Vamos a corregir esto.
HelloWorld.vue:
...
methods: {
calc(n) {
return n + 1;
}
},
mounted() {
this.msg1 = this.msg + this.calc(1);
},
...Esto será suficiente para calcular la cobertura.
Tras reiniciar la prueba, nos aseguraremos de esto:

En la pantalla deberíamos ver información sobre la cobertura, y en la carpeta del proyecto debería crearse una carpeta coverage con información sobre la cobertura de pruebas en un formato universal LCOV (extensión LTP GCOV).
Gcov — una herramienta de código abierto para investigar la cobertura del código. Gcov genera el número exacto de ejecuciones para cada operador en el programa y permite agregar anotaciones al código fuente. Gcov se incluye como herramienta estándar en el paquete GCC.
Lcov — una interfaz gráfica para gcov. Reúne archivos gcov de varios archivos fuente y crea un conjunto de páginas HTML con el código y la información de cobertura. También se generan páginas para facilitar la navegación. Lcov soporta la cobertura de líneas, funciones y bifurcaciones.
Después de ejecutar las pruebas, la información sobre la cobertura estará en coverage/lcov.info.
Necesitamos indicar Sonarde dónde obtenerla. Por lo tanto, agregaremos las siguientes líneas en su archivo de configuración. Sin embargo, hay un punto: los proyectos pueden ser multilingües, es decir, en la carpeta src hay fuentes para varios lenguajes de programación y la pertenencia a uno u otro, y a su vez, el uso de un determinado complemento se determina por su extensión. Y la información sobre la cobertura puede almacenarse en diferentes lugares para diferentes lenguajes de programación, por lo que para cada PLN hay su propia sección de configuración. Nuestro proyecto utiliza Typescript, por lo tanto, necesitamos una sección de configuración específicamente para él:
sonar-project.properties:
sonar.typescript.coveragePlugin=lcov
sonar.typescript.lcov.reportPaths=coverage/lcov.infoTodo está listo para la primera ejecución del escáner. Quiero señalar que el proyecto en Sonarse crea automáticamente en la primera ejecución del escáner para este proyecto. En las siguientes ocasiones, la información ya se acumulará para ver la dinámica de cambio de los parámetros del proyecto a lo largo del tiempo.
Así que usaremos el comando creado anteriormente en package.json:
yarn run sonar Nota: también se puede usar el parámetro -X para un registro más detallado.
Si la ejecución del escáner fue la primera vez, primero se descargará el binario del propio escáner. Después de eso, se iniciará y comenzará a escanear el servidor Sonaren busca de complementos instalados, calculando así los PLN admitidos. También se cargan otros diversos parámetros para su funcionamiento: quality profiles, active rules, metrics repository, server rules.


Nota: no nos detendremos en ellos en el marco de este artículo, pero siempre se puede consultar las fuentes oficiales.
A continuación, comienza el análisis de la carpeta src sobre la disponibilidad de archivos fuente para todos los lenguajes de programación soportados (si no se especifica explícitamente alguno en particular), seguido de su indexación.

A continuación, hay otros análisis diversos, en los cuales no nos detendremos en este artículo (por ejemplo, como: linting, detección de duplicación de código, etc.).
Al final del trabajo del escáner, se agrega toda la información recopilada, se archiva y se envía al servidor.
Después de esto, ya podemos ver qué se ha logrado en la interfaz web:

Como podemos ver, algo se ha logrado, e incluso muestra cierta cobertura, pero no coincide con nuestro Jestinforme.
Vamos a desglosar esto. Veamos el proyecto con más detalle, hagamos clic en el valor de cobertura y "profundicemos" en el informe detallado por archivos:

Aquí vemos, además del archivo principal que estamos investigando HelloWorld.vue, también está presente el archivo main.ts, que arruina toda la imagen de cobertura. Pero, ¿cómo es eso? Lo excluimos del cálculo de cobertura. Sí, es correcto, pero fue a nivel Jest, pero el escáner lo indexó, por lo que se incluyó en sus cálculos.
Vamos a corregir esto:
sonar-project.properties:
...
sonar.exclusions=src/main.ts
...Quisiera hacer una aclaración: además de las carpetas que se especifican en este parámetro, también se agregan todas las carpetas mencionadas en el parámetro sonar.test.inclusions.
Después de ejecutar el escáner, ya vemos la información correcta:


Desglosemos el siguiente punto – Perfiles de calidad. Mencioné anteriormente que la soporte Sonarde varios lenguajes de programación simultáneamente. Justo esto es lo que estamos observando. Pero sabemos que nuestro proyecto está escrito en TS, por lo que no tiene sentido molestar al escáner con manipulaciones y verificaciones innecesarias. Definamos el lenguaje para el análisis mediante la adición de un parámetro más al archivo de configuración Sonar:
sonar-project.properties:
...
sonar.language=ts
...Ejecutamos el escáner de nuevo y observamos el resultado:

La cobertura ha desaparecido por completo.
Si miramos en el registro del escáner, podemos ver la siguiente línea:
![]()
Es decir, los archivos de nuestro proyecto simplemente no fueron indexados.
La situación es la siguiente: oficialmente el soporte de VueJs existe en el plugin SonarJS, que se encarga de Javascript.

Pero este soporte no está en el plugin SonarTS para TS, sobre lo que se ha abierto un ticket oficial en el rastreador de errores. Sonar:
Aquí algunas respuestas de un representante de los desarrolladores de SonarQube confirmando este hecho.


Pero si todo funcionaba, usted objetará. Sí, así es, intentemos "hackear" un poco. Si hay soporte para archivos.
.vue -files-archivos Sonarentonces intentemos decirle que las considere como Typescript.
Agreguemos el parámetro:
sonar-project.properties:
...
sonar.typescript.file.suffixes=.ts,.tsx,.vue
...Iniciemos el escáner:

Y, voilà, todo ha vuelto a la normalidad, y con un solo perfil solo para Typescript. Es decir, se resolvió el problema de compatibilidad VueJs+TS para SonarQube.
Intentemos ir más allá y mejorar un poco la información sobre la cobertura.
¿Qué hemos hecho hasta ahora:
- agregamos al proyecto Sonar-el escáner;
- configuramos Jest para generar información sobre la cobertura;
- configuramos Sonar-el escáner;
- resolvimos el problema de compatibilidad -files-archivos + Typescript.
Además de la cobertura de pruebas, hay otros criterios interesantes y útiles de calidad de código, como la duplicación de código y la cantidad de líneas (que participa en el cálculo de los coeficientes relacionados con la complejidad del código) del proyecto.
En la implementación actual del plugin para trabajar con TS (SonarTS) no funcionará CPD (Detector de Copia y Pega) y el conteo de líneas de código -files-archivos.
Para crear una situación sintética de duplicación de código, simplemente duplicaremos el archivo del componente con otro nombre, también agregaremos en el código main.ts una función vacía y la duplicaremos con otro nombre. Para verificar la duplicación como en -files, así como en .ts -archivos.
main.ts:
...
function name(params:string): void {
console.log(params);
}
...Para esto, es necesario comentar temporalmente la línea de configuración:
sonar-project.properties:
...
sonar.exclusions=src/main.ts
...Reiniciemos el escáner junto con las pruebas:
yarn test && yarn run sonarNuestro porcentaje de cobertura seguramente disminuirá, pero ahora eso no nos interesa.
En términos de duplicación de líneas de código veremos:

Para la verificación, usaremos CPD-la utilidad – jscpd:
npx jscpd src
Para las líneas de código:

Esto puede resolverse en futuras versiones de los plugins SonarJS(TS). Quiero señalar que poco a poco están fusionando estos dos plugins en uno SonarJS, lo cual, creo, es correcto.
Ahora me gustaría considerar una opción para mejorar la información sobre la cobertura.
Hasta ahora vemos la cobertura de pruebas en términos porcentuales, en todo el proyecto y por archivos en particular. Pero hay una posibilidad de ampliar este indicador con información sobre la cantidad de pruebas unitarias-en el proyecto, así como en términos de archivos.
Hay una biblioteca que puede Jest-convertir el informe en formato para Sonar:
datos de prueba genéricos — .
Instalemos esta biblioteca en nuestro proyecto:
yarn add jest-sonar-reporterY lo agregaremos a la configuración Jest:
package.json:
…
"testResultsProcessor": "jest-sonar-reporter"
…Ahora ejecutemos la prueba:
yarn testDespués de lo cual se creará un archivo en la raíz del proyecto test-report.xml.
Lo usaremos en la configuración Sonar:
sonar-project.properties:
…
sonar.testExecutionReportPaths=test-report.xml
…Y reiniciaremos el escáner:
yarn run sonarVeamos qué ha cambiado en la interfaz Sonar:

Y nada ha cambiado. El hecho es que Sonar no considera los archivos descritos en el informe de Jest como archivos de pruebas unitarias-de pruebas. Para corregir esta situación, utilizaremos un parámetro de configuración Sonar sonar.tests, en el que indicaremos explícitamente las carpetas con pruebas (por ahora tenemos una):
sonar-project.properties:
…
sonar.tests=src/components/__tests__
…Reiniciemos el escáner:
yarn run sonarVeamos qué ha cambiado en la interfaz:

Ahora hemos visto la cantidad de nuestras de pruebas unitarias-pruebas y, al hacer clic en su interior, podemos ver la distribución de este número por archivos del proyecto:

Conclusión
Así que examinamos la herramienta para análisis continuo SonarQube. Integramos exitosamente el proyecto escrito en VueJs+TS. Solucionamos algunos problemas de compatibilidad. Mejoramos la informatividad de la métrica sobre la cobertura de pruebas. En este artículo solo revisamos uno de los criterios de calidad del código (probablemente uno de los principales), pero SonarQube también soporta otros criterios de calidad, incluyendo pruebas de seguridad. Pero no todas estas funcionalidades están completamente disponibles en la versión comunitaria.Una de las características interesantes y útiles son las integraciones SonarQube con varios sistemas de control de versiones de código, como GitLab y BitBucket. Para evitar un merge pull(merge) requesten la rama principal del repositorio en caso de degradación de la cobertura. Pero esa es otra historia para un artículo completamente diferente.
PD: Todo lo descrito en el artículo en forma de código está disponible en .
Solo los usuarios registrados pueden participar en la encuesta. , por favor.
¿Utiliza usted la plataforma SonarQube:
26,3%Sí5
15,8%No3
15,8%He oído hablar de esta plataforma y quiero usarla3
10,5%He oído hablar de esta plataforma y no quiero usarla2
0,0%Estoy usando otra plataforma0
31,6%Nunca he oído hablar de ella6
Votaron 19 usuarios. 3 usuarios se abstuvieron.
Fuente: habr.com
