Запускаем інспекцыі IntelliJ IDEA на Jenkins

IntelliJ IDEA на сёння валодае найболей прасунутым статычным аналізатарам кода Java, па сваіх магчымасцях якія пакінулі далёка ззаду такіх «ветэранаў», як Checkstyle и Spotbugs. Яе шматлікія "інспекцыі" правяраюць код у розных аспектах, ад стылю кадавання да характэрных багаў.

Аднак пакуль вынікі аналізу адлюстроўваюцца толькі ў лакальным інтэрфейсе IDE распрацоўніка, ад іх мала карысці для працэсу распрацоўкі. Статычны аналіз неабходна выконваць у якасці першага кроку канвеера зборкі, яго вынікі павінны вызначаць quality gates, а зборка павінна фелівацца, калі quality gates не пройдзеныя. Вядома, што TeamCity CI інтэграваны з IDEA. Але нават калі вы не карыстаецеся TeamCity, вы цалкам можаце паспрабаваць запускаць інспекцыі IDEA у любым іншым CI-серверы. Прапаноўваю паглядзець, як гэта можна зрабіць, выкарыстоўваючы IDEA Community Edition, Jenkins і Warnings NG plugin.

Крок 1. Запускаем аналіз у кантэйнеры і атрымліваем справаздачу

Спачатку задума запускаць IDE (дэсктопнае прыкладанне!) усярэдзіне CI-сістэмы, не мелай графічнага інтэрфейсу, можа здацца сумнеўнай і вельмі клапотнай. На шчасце, распрацоўшчыкі IDEA далі магчымасць запускаць фарматаванне кода и інспекцыі з каманднага радка. Прычым для запуску IDEA у такім рэжыме не патрабуецца графічная падсістэма і гэтыя задачы можна выконваць на серверах з тэкставай абалонкай.

Запуск інспекцый ажыццяўляецца пры дапамозе скрыпту bin/inspect.sh з установачнай дырэкторыі IDEA. У якасці параметраў патрабуюцца:

  • поўны шлях да праекту (адносныя не падтрымліваюцца),
  • шлях да .xml-файлу з наладамі інспекцый (звычайна знаходзіцца ўсярэдзіне праекту ў .idea/inspectionProfiles/Project_Default.xml),
  • поўны шлях да тэчкі, у якую будуць складзеныя .xml-файлы са справаздачамі аб выніках аналізу.

Акрамя таго, чакаецца, што

  • у IDE будзе наладжаны шлях да Java SDK, інакш аналіз працаваць не будзе. Гэтыя наладкі змяшчаюцца ў канфігурацыйным файле jdk.table.xml у тэчцы глабальнай канфігурацыі IDEA. Сама глабальная канфігурацыя IDEA па змаўчанні ляжыць у хатняй дырэкторыі карыстальніка, але гэтае месцазнаходжанне можа быць відавочна зададзена у файле idea.properties.
  • аналізаваны праект павінен быць валідным праектам IDEA, для чаго на кантроль версій давядзецца закаміціць некаторыя файлы, якія звычайна ігнаруюцца, а менавіта:
    • .idea/inspectionProfiles/Project_Default.xml - налады аналізатара, яны відавочна будуць выкарыстаныя пры запуску інспекцый у кантэйнеры,
    • .idea/modules.xml - інакш атрымаем памылку 'This project contains no modules',
    • .idea/misc.xml - інакш атрымаем памылку 'The JDK is not configured properly for this project',
    • *.iml-файлы - інакш атрымаем памылку пра не наладжаны JDK у модулі.

Хоць звычайна гэтыя файлы ўключаюць у .gitignore, яны не ўтрымоўваюць ніякай спецыфічнай для асяроддзя канкрэтнага распрацоўніка інфармацыі - у адрозненне ад, напрыклад, файла workspace.xml, дзе такая інфармацыя, як раз, утрымліваецца, і таму каміціць яго не трэба.

Сам сабою напрошваецца выйсце запакаваць JDK разам з IDEA Community Edition у кантэйнер у выглядзе, гатовым да «натручвання» на аналізаваныя праекты. Выберам прыдатны базавы кантэйнер, і вось які ў нас атрымаецца Dockerfile:

Докер-файл

FROM openkbs/ubuntu-bionic-jdk-mvn-py3

ARG INTELLIJ_VERSION="ideaIC-2019.1.1"

ARG INTELLIJ_IDE_TAR=${INTELLIJ_VERSION}.tar.gz

ENV IDEA_PROJECT_DIR="/var/project"

WORKDIR /opt

COPY jdk.table.xml /etc/idea/config/options/

RUN wget https://download-cf.jetbrains.com/idea/${INTELLIJ_IDE_TAR} && 
    tar xzf ${INTELLIJ_IDE_TAR} && 
    tar tzf ${INTELLIJ_IDE_TAR} | head -1 | sed -e 's//.*//' | xargs -I{} ln -s {} idea && 
    rm ${INTELLIJ_IDE_TAR} && 
    echo idea.config.path=/etc/idea/config >> idea/bin/idea.properties && 
    chmod -R 777 /etc/idea

CMD idea/bin/inspect.sh ${IDEA_PROJECT_DIR} ${IDEA_PROJECT_DIR}/.idea/inspectionProfiles/Project_Default.xml ${IDEA_PROJECT_DIR}/target/idea_inspections -v2

Пры дапамозе опцыі idea.config.path мы прымусілі IDEA шукаць сваю глабальную канфігурацыю ў тэчцы /etc/idea, т. К. хатняя тэчка карыстача ва ўмовах працы ў CI – рэч нявызначаная і часцяком зусім адсутная.

Так выглядае які капіюецца ў кантэйнер файл jdk.table.xml, у якім прапісаны шляхі да OpenJDK, усталяванай усярэдзіне кантэйнера (за аснову можа быць узяты аналагічны файл з вашай уласнай дырэкторыі з наладамі IDEA):

jdk.table.xml

<application>
 <component name="ProjectJdkTable">
   <jdk version="2">
     <name value="1.8" />
     <type value="JavaSDK" />
     <version value="1.8" />
     <homePath value="/usr/java" />
     <roots>
       <annotationsPath>
         <root type="composite">
           <root url="jar://$APPLICATION_HOME_DIR$/lib/jdkAnnotations.jar!/" type="simple" />
         </root>
       </annotationsPath>
       <classPath>
         <root type="composite">
           <root url="jar:///usr/java/jre/lib/charsets.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/deploy.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/access-bridge-64.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/cldrdata.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/dnsns.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/jaccess.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/jfxrt.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/localedata.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/nashorn.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/sunec.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/sunjce_provider.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/sunmscapi.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/sunpkcs11.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/ext/zipfs.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/javaws.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/jce.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/jfr.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/jfxswt.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/jsse.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/management-agent.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/plugin.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/resources.jar!/" type="simple" />
           <root url="jar:///usr/java/jre/lib/rt.jar!/" type="simple" />
         </root>
       </classPath>
     </roots>
     <additional />
   </jdk>
 </component>
</application>

Выява ў гатовым выглядзе даступны на Docker Hub.

Перад тым, як рушыць далей, праверым запуск аналізатара IDEA у кантэйнеры:

docker run --rm -v <путь/к/вашему/проекту>:/var/project inponomarev/intellij-idea-analyzer

Аналіз павінен паспяхова адпрацаваць, а ў падтэчку target/idea_inspections павінны з'явіцца шматлікія .xml-файлы са справаздачамі аналізатара.

Цяпер больш няма ніякіх сумневаў у тым, што аналізатар IDEA можа быць запушчаны ў аўтаномным рэжыме ў любым CI-акружэнні, і мы пераходзім да другога кроку.

Крок 2. Адлюстроўваем і аналізуем справаздачу

Атрымаць справаздачу ў выглядзе .xml-файлаў - паўсправы, зараз яго трэба зрабіць чалавекачытаемым. А таксама яго вынікі павінны быць скарыстаны ў quality gates - логіцы вызначэння таго, праходзіць ці не праходзіць прыманае змяненне па крытэрыях якасці.

У гэтым нам дапаможа Jenkins Warnings NG Plugin, рэліз якога быў зроблены ў студзені 2019 года. З яго з'яўленнем шматлікія асобныя плагіны для працы з вынікамі статычнага аналізу ў Jenkins (CheckStyle, FindBugs, PMD і т. п.) зараз пазначаныя як састарэлыя (obsolete).

Убудова складаецца з двух частак:

  • шматлікіх зборшчыкаў паведамленняў аналізатараў (поўны спіс уключае ў сябе ўсе вядомыя навуцы аналізатары ад AcuCobol да ZPT Lint),
  • адзінага для ўсіх іх праглядальніка справаздач.

У спісе таго, што ўмее аналізаваць Warnings NG, знаходзяцца ў тым ліку папярэджанні кампілятара Java і папярэджанні з логаў выканання Maven: хоць яны ўвесь час навідавоку, іх рэдка калі мэтанакіравана аналізуюць. Справаздачы IntelliJ IDEA таксама ўваходзяць у пералік распазнаваных фарматаў.

Т. к. убудова новы, ён першапачаткова добра ўзаемадзейнічае Jenkins Pipeline. Крок зборкі з яго ўдзелам будзе выглядаць наступным чынам (мы проста гаворым убудову, які фармат справаздачы распазнаем і якія файлы варта прасканаваць):

stage ('Static analysis'){
    sh 'rm -rf target/idea_inspections'
    docker.image('inponomarev/intellij-idea-analyzer').inside {
       sh '/opt/idea/bin/inspect.sh $WORKSPACE $WORKSPACE/.idea/inspectionProfiles/Project_Default.xml $WORKSPACE/target/idea_inspections -v2'
    }
    recordIssues(
       tools: [ideaInspection(pattern: 'target/idea_inspections/*.xml')]
    )
}

Інтэрфейс справаздачы выглядае так:

Запускаем інспекцыі IntelliJ IDEA на Jenkins

Зручна, што гэты інтэрфейс з'яўляецца ўніверсальным для ўсіх распазнаваных аналізатараў. Ён змяшчае інтэрактыўную дыяграму размеркавання знаходак па катэгорыях і графік дынамікі змены колькасці знаходак. У грыдзе ўнізе старонкі можна выконваць хуткі пошук. Адзінае, што для іспэкцый IDEA не зарабіла карэктна – магчымасць браўзіць код непасрэдна ў Jenkins (хоць для іншых справаздач, напрыклад Checkstyle, гэтая плягін умее гэта рабіць прыгожа). Падобна, гэта баг парсера справаздач IDEA, які мае быць паправіць.

Сярод магчымасцяў Warnings NG – магчымасць агрэгаваць у адной справаздачы знаходкі з розных крыніц і праграмаваць Quality Gates, у тым ліку – «храпавік» па рэферэнтнай зборцы. Некаторая дакументацыя па праграмаванні Quality Gates даступная тут - зрэшты, яна не поўная, і даводзіцца глядзець у зыходнікі. З іншага боку, для поўнага кантролю над тым, што адбываецца, «храпавік» можна рэалізаваць і самастойна (гл. мой папярэдні пост на гэтую тэму).

Заключэнне

Перад тым, як пачаць рыхтаваць дадзены матэрыял, я вырашыў пашукаць: а ці не пісаў ужо хто-небудзь на гэтую тэму на Хабры? я знайшоў толькі інтэрв'ю 2017 года с lany, дзе ён кажа:

Наколькі мне вядома, інтэграцыі з Jenkins ці maven-плагіна няма […] У прынцыпе, любы энтузіяст мог бы пасябраваць IDEA Community Edition і Jenkins, многія б ад гэтага толькі выйгралі.

Што ж: праз два гады ў нас ёсць Warnings NG Plugin, і нарэшце гэтае сяброўства ажыццявілася!

Крыніца: habr.com

Дадаць каментар