Інтеграція проекту VueJS+TS із SonarQube

У своїй роботі ми активно використовуємо платформу SonarQube для підтримки якості коду на найвищому рівні. При інтеграції одного з проектів, написаному на VueJs+Typescript, виникли проблеми. Тому хотів би розповісти докладніше про те, як удалося їх вирішити.

Інтеграція проекту VueJS+TS із SonarQube

У цій статті йтиметься, як писав вище, про платформу SonarQube. Небагато теорії — що це таке взагалі, для тих, хто чує про неї вперше:

SonarQube (колишній Сонар) — платформа з відкритим вихідним кодом для безперервного аналізу (continuous inspection) і вимірювання якості коду.
Підтримує аналіз коду та пошук помилок згідно з правилами стандартів програмування MISRA C, MISRA C++, MITRE/CWE та CERT Secure Coding Standards. А також вміє розпізнавати помилки зі списків OWASP Топ-10 та CWE/SANS Топ-25 помилок програмування.
Незважаючи на те, що платформа використовує різні готові інструменти, SonarQube зводить результати до єдиної інформаційної панелі (dashboard), ведучи історію прогонів і дозволяючи тим самим побачити загальну тенденцію зміни якості програмного забезпечення в ході розробки.

Докладніше можна дізнатися на офіційному сайті

Підтримується багато мов програмування. Судячи з інформації з посилання вище, це понад 25 мов. Для підтримки конкретної мови необхідно встановити відповідний плагін. У community-версію входить плагін для роботи з Javascript (У тому числі типи сript), хоча у wiki написано зворотне. За Javascript відповідає плагін SonarJSза Typescript SonarTS відповідно.

Для надсилання інформації про покриття використовується офіційний клієнт sonarqube-scanner, який, використовуючи налаштування з конфиг-файла, надсилає ці дані на сервер SonarQube для подальшої консолідації та агрегування.

Для Javascript є npm-обгортка. Отже, починаємо покрокове впровадження SonarQube в Vue-проект, що використовує Машинопис.

Для розгортання сервера SonarQube скористаємося докер-створити.

sonar.yaml:

version: '1'
    services:
        simplesample-sonar:
            image: sonarqube:lts
            ports:
                - 9001:9000
                - 9092:9092
            network_mode: bridge

запуск:

docker-compose -f sonar.yml up

Після цього SonarQube буде доступний за адресою – http://localhost:9001 .

Інтеграція проекту VueJS+TS із SonarQube
Поки що в ньому немає проектів, і це справедливо. Виправлятимемо цю ситуацію. За основу я взяв офіційний проект-приклад для VueJS+TS+Jest. Схиляємо його до себе:

git clone https://github.com/vuejs/vue-test-utils-typescript-example.git

Спочатку нам потрібно встановити клієнта SonarQube, який називається сонар-сканер, Для нмм є обгортка:

yarn add sonarqube-scanner

І відразу ж додамо команду до scripts до роботи з ним.

package.json:

{
 … 
   scripts: {
      ...
      "sonar": "sonar-scanner"
      ...
   },
 …
}

Далі, для роботи сканера, потрібно встановити параметри проекту в спеціальному файлі. Почнемо з базових.

sonar-project.properties:

sonar.host.url=http://localhost:9001

sonar.projectKey=test-project-vuejs-ts
sonar.projectName=Test Application (VueJS+TS)

sonar.sources=src
# sonar.tests=
sonar.test.inclusions=src/**/*tests*/**
sonar.sourceEncoding=UTF-8

  • sonar.host.url – адреса Сонар'а;
  • sonar.projectKey - Унікальний ідентифікатор проекту на сервері Сонар'а;
  • sonar.projectName – його найменування, воно може бути змінено у будь-який момент, тому що ідентифікація проекту здійснюється за projectKey;
  • sonar.sources - папка з вихідними джерелами, зазвичай це SRCале може бути будь-яким. Ця папка задається щодо рутової папки, якою є папка, звідки запущений сканер;
  • sonar.tests - Параметр, який йде в парі з попереднім. Це тека, де знаходяться тести. У даному проекті немає такої папки, а тест знаходиться поряд з компонентом, що тестується в папці 'тест', тому ми його поки що проігноруємо і скористаємося наступним параметром;
  • sonar.test.inclusions - шлях для тестів з використанням маски, може бути кілька елементів, перерахованих через кому;
  • sonar.sourceEncoding – кодування для вихідних файлів.

Для першого запуску сканера все готово, крім основної попередньої дії: запуск самого тестового движка, для формування ним інформації про покриття, яку й надалі використовуватиме сканер.

Але для цього необхідно налаштувати тестовий двигун на формування цієї інформації. У цьому проекті тестовий двигун - це є. І його налаштування знаходяться у відповідному розділі файлу package.json.

Додамо ці налаштування:

"collectCoverage": true,
"collectCoverageFrom": [
      "src/**/*",
      "!src/main.ts",
      "!src/App.vue",
      "!src/**/*.d.*",
      "!src/**/*__tests__*"
],

Тобто задаємо сам прапор необхідності обчислення покриття та джерело (разом із винятками), на основі яких воно формуватиметься.

Тепер запустимо тест:

yarn test

Побачимо таке:

Інтеграція проекту VueJS+TS із SonarQube

Причина в тому, що в самому компоненті як такого коду немає. Виправимо це.

HelloWorld.vue:

...
methods: {
    calc(n) {
      return n + 1;
    }
  },
mounted() {
  this.msg1 = this.msg + this.calc(1);
},
...

Цього достатньо для розрахунку покриття.

Після перезапуску тесту переконаємось у цьому:

Інтеграція проекту VueJS+TS із SonarQube

На екрані ми повинні побачити інформацію про покриття, а в папці проекту буде створено папку охоплення з інформацією про покриття тестами в універсальному форматі LCOV (LTP GCOV extension).

Gcov - Утиліта, що вільно розповсюджується, для дослідження покриття коду. Gcov генерує точну кількість виконань для кожного оператора у програмі та дозволяє додати анотації до вихідного коду. Gcov постачається як стандартна утиліта у складі пакету GCC.
Lcov - Графічний інтерфейс для gcov. Він збирає файли gcov для кількох файлів з вихідними джерелами та створює комплект HTML сторінок з кодом та відомостями про покриття. Також генеруються сторінки для спрощення навігації. Lcov підтримує покриття рядків, функцій, розгалужень.

Після виконання тестів інформація про покриття буде перебуває в coverage/lcov.info.
Нам треба сказати СонарЗвідки її взяти. Тому додамо наступні рядки у файл конфігурації. Але є один момент: проекти можуть бути мультимовними, тобто в папці SRC знаходяться вихідники для кількох мов програмування та приналежність до того чи іншого, і в свою чергу використання того чи іншого плагіна визначається за його розширенням. І інформація про покриття може зберігатись у різних місцях для різних мов програмування, тому для кожного ЯП є свій розділ для налаштування цього. У нас проект використовує Машинопистому нам необхідний розділ налаштувань саме для нього:

sonar-project.properties:

sonar.typescript.coveragePlugin=lcov
sonar.typescript.lcov.reportPaths=coverage/lcov.info

Все готове до першого запуску сканера. Хочу зауважити, що проект у Сонаре створюється автоматично при першому запуску сканера для даного проекту. У наступні рази інформація вже акумулюватиметься, щоб бачити динаміку зміни параметрів проекту в часі.

Отже, скористаємося командою, створеною раніше в package.json:

yarn run sonar 

Примітка: можна також скористатися параметром -X для детальнішого логування.

Якщо запуск сканера був вперше, спочатку скачається бінарник самого сканера. Після цього він запускається та починає сканувати сервер СонарТа щодо встановлених плагінів, обчислюючи тим самим підтримувані ЯП. Також завантажуються інші різні параметри його роботи: quality profiles, active rules, metrics repository, server rules.

Інтеграція проекту VueJS+TS із SonarQube

Інтеграція проекту VueJS+TS із SonarQube

Примітка: докладно на них ми зупинятися не будемо в рамках цієї статті, але завжди можна звернутися до офіційних джерел.

Далі починається аналіз папки SRC щодо наявності вихідних файлів для всіх (якщо не заданий явно якийсь конкретний) підтримуваних ЯП, з подальшою їх індексацією.

Інтеграція проекту VueJS+TS із SonarQube

Далі йдуть інші різні аналізи, на яких ми не загострюємо увагу в цій статті (наприклад, такі як: лінтинг, визначення дублювання коду тощо).

Наприкінці роботи сканера відбувається агрегування всієї зібраної інформації, архівування та відправлення її на сервер.

Після цього ми можемо вже подивитися, що вийшло у веб-інтерфейсі:

Інтеграція проекту VueJS+TS із SonarQube

Як бачимо, щось вийшло, і навіть показує якесь покриття, але воно не відповідає нашому є-Звіту.

Давайте розумітися. Подивимося на проект детальніше, клікнемо за значенням покриття, і "провалимося" до деталізованого звіту за файлами:

Інтеграція проекту VueJS+TS із SonarQube

Тут ми бачимо окрім основного, досліджуваного файлу HelloWorld.vue, присутній і файл main.tsщо псує всю картину покриття. Але як так, ми його виключали з розрахунку покриття. Так, все правильно, але це було на рівні єале сканер його проіндексував, тому він потрапив у його розрахунки.

Давайте виправимо це:

sonar-project.properties:

...
sonar.exclusions=src/main.ts
...

Хочеться зробити уточнення: окрім тих папок, які задані в даному параметрі, також додаються всі папки, перелічені у параметрі sonar.test.inclusions.

Після запуску сканера бачимо коректну інформацію:

Інтеграція проекту VueJS+TS із SonarQube

Інтеграція проекту VueJS+TS із SonarQube

Розберемо наступний момент – Якісні профілі. Я говорив вище про підтримку СонарТому кілька ЯП одночасно. Ось це ми й спостерігаємо. Але ми знаємо, що проект у нас написаний на TSТому навіщо напружувати сканер зайвими маніпуляціями та перевірками. Мова для аналізу задамо через додавання ще одного параметра файл конфігурації СонарТа:

sonar-project.properties:

...
sonar.language=ts
...

Знову запустимо сканер і подивимося результат:

Інтеграція проекту VueJS+TS із SonarQube

Покриття зникло зовсім.

Якщо подивимося в лог сканера, то можемо побачити наступний рядок:

Інтеграція проекту VueJS+TS із SonarQube

Тобто файли нашого проекту просто не були проіндексовані.

Ситуація така: офіційно підтримка VueJs є у плагіні SonarJS, який відповідає за Javascript.

Інтеграція проекту VueJS+TS із SonarQube

Але цієї підтримки немає у плагіні SonarTS для TS, про що заведено офіційний тикет у баг-трекері СонарТа:

  1. https://jira.sonarsource.com/browse/MMF-1441
  2. https://github.com/SonarSource/SonarJS/issues/1281

Ось деякі відповіді одного із представників з боку розробників SonarQube, що підтверджує цей факт.

Інтеграція проекту VueJS+TS із SonarQube

Інтеграція проекту VueJS+TS із SonarQube

Але ж у нас все працювало, заперечіть Ви. Так, так і є, давайте спробуємо трохи "похакерити".
Якщо є підтримка .vue-файлів СонарТому, то давайте спробуємо сказати йому щоб він їх розглядав як Машинопис.

Додамо параметр:

sonar-project.properties:

...
sonar.typescript.file.suffixes=.ts,.tsx,.vue
...

Запустимо сканер:

Інтеграція проекту VueJS+TS із SonarQube

І, вуаля, все повернулося на круги своя, і з одним профілем тільки для Машинопис. Тобто вдалося вирішити проблему у підтримці VueJs+TS для SonarQube.

Спробуємо піти далі і трохи покращити інформацію про покриття.

Що ж ми зробили зараз:

  • додали до проекту Сонар-Сканер;
  • налаштували є для формування інформації про покриття;
  • конфігурували Сонар-Сканер;
  • вирішили проблему підтримки .vue-файлів + Машинопис.

Крім покриття тестами є інші цікаві корисні критерії якості коду, наприклад, дублювання коду та кількість рядків (бере участь у розрахунку коефіцієнтів, пов'язаних із складністю коду) проекту.

У поточній реалізації плагіна для роботи з TS (SonarTS) не буде працювати CPD (Copy Paste Detector) та підрахунок рядків коду .vue-Файлів.

Для створення синтетичної ситуації з дублювання коду просто задублюємо файл компонента з іншим ім'ям, також додамо в код main.ts функцію-пустушку і задублюємо його з іншим ім'ям. Щоб перевірити дублювання як у .vue, Так і в .ts -Файли.

main.ts:

...
function name(params:string): void {
  console.log(params);
}
...

Для цього потрібно тимчасово закоментувати рядок конфігурації:

sonar-project.properties:

...
sonar.exclusions=src/main.ts
...

Перезапустимо сканер разом із тестуванням:

yarn test && yarn run sonar

У нас, звичайно, впаде покриття, але зараз нам це не цікаво.

У розрізі дублювання рядків коду побачимо:

Інтеграція проекту VueJS+TS із SonarQube

Для перевірки скористаємося CPD-Утилітою - jscpd:

npx jscpd src

Інтеграція проекту VueJS+TS із SonarQube

Для рядків коду:

Інтеграція проекту VueJS+TS із SonarQube

Можливо, це вирішиться у майбутніх версіях плагінів SonarJS(TS). Хочу зауважити, що вони поступово починають зливати ці два плагіни в один SonarJSщо, думаю, правильно.

Тепер хотілося розглянути варіант покращення інформації про покриття.

Поки що ми бачимо покриття тестами у відсотковому відношенні, по всьому проекту, і за файлами зокрема. Але є можливість розширити цей показник інформацією про кількість блок-тестів за проектом, а також у розрізі файлів

Є бібліотека, яка вміє є-репорт конвертувати у формат для СонарТа:
generic test data - https://docs.sonarqube.org/display/SONAR/Generic+Test+Data.

Встановимо цю бібліотеку до себе у проект:

yarn add jest-sonar-reporter

І додамо його до конфігурації є:

package.json:

…
"testResultsProcessor": "jest-sonar-reporter"
…

Тепер виконаємо тест:

yarn test

Після чого в корені проекту буде створено файл test-report.xml.

Задіємо його у конфігурації СонарТа:

sonar-project.properties:

…
sonar.testExecutionReportPaths=test-report.xml
…

І перезапустимо сканер:

yarn run sonar

Подивимося, що змінилося в інтерфейсі СонарТа:

Інтеграція проекту VueJS+TS із SonarQube

І нічого не змінилося. Справа в тому, що Sonar не розглядає файли, описані в Jest-репорті як файли блок-Тестів. Для того, щоб виправити цю ситуацію, задіємо параметр конфігурації Сонар sonar.tests, в якому явно вкажемо папки з тестами (вона у нас поки що одна):

sonar-project.properties:

…
sonar.tests=src/components/__tests__
…

Перезапустимо сканер:

yarn run sonar

Подивимося, що змінилося в інтерфейсі:

Інтеграція проекту VueJS+TS із SonarQube

Тепер ми побачили кількість наших блок-тестів і, провалившись на кліку всередину, можемо подивитися розподіл цього числа за файлами проекту:

Інтеграція проекту VueJS+TS із SonarQube

Висновок

Отже, ми розглянули інструмент безперервного аналізу SonarQube. Успішно інтегрували до нього проект, написаний на VueJs+TS. Вирішили деякі проблеми сумісності. Підвищили інформативність показника покриття тестами. У цій статті ми розглянули лише один із критеріїв якості коду (можливо, один із основних), але SonarQube підтримує інші критерії якості, включаючи тестування на безпеку. Але не всі ці можливості в повному обсязі доступні в співтовариство-Версії. Одна з цікавих та корисних можливостей – це інтеграції SonarQube з різними системами керування репозиторіями коду, наприклад, такі як GitLab та BitBucket. Щоб не допустити merge pull(merge) requestТа в основну гілку репозиторію при деградації покриття. Але це історія вже зовсім іншої статті.

PS: Все, що описано у статті у вигляді коду доступне в моєму форці.

Тільки зареєстровані користувачі можуть брати участь в опитуванні. Увійдіть, будь ласка.

Ви використовуєте платформу SonarQube:

  • 26,3%Так5

  • 15,8%Ні3

  • 15,8%Чув про дану платформу і хочу використовувати3

  • 10,5%Чув про дану платформу і не хочу використовувати2

  • 0,0%Використовую іншу платформу0

  • 31,6%Вперше чую про неї6

Проголосували 19 користувачів. Утрималися 3 користувача.

Джерело: habr.com

Додати коментар або відгук