diff --git a/README.md b/README.md index 3018524c..89c095ea 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,10 @@ ## Ограничения +1. Хранение исходников в корне репозитория или в каталоге первого уровня (например, в `src`) не рекомендуется. 1. Для шага подготовки требуется любой агент с меткой `agent`. 1. Для запуска шага анализа SonarQube требуется агент с меткой `sonar`. -1. Для запуска шагов, работающих с EDT (валидация, трансформация формата исходников) требуется агент с меткой `edt` (если используется несколько версий EDT необходимо к метке добавить версию, например `edt@2021.3.4:x86_64`) и агент с меткой `oscript`, на котором глобально установлена библиотека [stebi](https://github.com/Stepa86/stebi) версии 1.9.1 или новее. +1. Для запуска шагов, работающих с EDT (валидация, трансформация формата исходников) требуется агент с меткой `edt` (если используется несколько версий EDT необходимо к метке добавить версию, например `edt@2021.3.4:x86_64`) и агент с меткой `oscript`, на котором глобально установлена библиотека [stebi](https://github.com/Stepa86/stebi) версии 1.11.1 и выше или [edt-ripper](https://github.com/bia-technologies/edt_ripper). 1. Для запуска шагов, работающих с 1С (подготовка, синтаксический контроль и т.д.) требуется агент с меткой, совпадающей со значением в поле `v8version` файла конфигурации. 1. В качестве ИБ используется файловая база, создаваемая в каталоге `./build/ib`. При необходимости вы можете создать пользователей на фазе инициализации ИБ. @@ -38,7 +39,8 @@ 1. Запуск BDD сценариев с сохранением результатов в формате Allure. 1. Запуск юнит-тестов с помощью фреймворка YAXUnit с сохранением результатов в формате jUnit и Allure. 1. Запуск синтаксического контроля средствами конфигуратора и сохранение результатов в виде отчета jUnit. -1. Запуск валидации проекта средствами EDT и конвертация отчета в формате generic issues. +1. Валидация проекта средствами EDT и трансформация отчета EDT в формат BSL LS с помощью `edt-ripper` или Generic Issue с помощью `stebi`. + 1. Запуск статического анализа для SonarQube. 1. Публикация результатов junit и Allure в интерфейс Jenkins. 1. Рассылка результатов сборки на почту и в Telegram. @@ -148,7 +150,9 @@ pipeline1C() * Если в репозитории существует файл `./tools/syntax-check-exception-file.txt`, то команде запуска синтаксического контроля конфигурации данный файл будет передаваться как файл с исключениями сообщений об ошибках (параметр `--exception-file`) (`syntaxCheck` -> `exceptionFile`). * Конфигурационный файл по умолчанию уже содержит ряд "режимов проверки" для синтаксического контроля конфигурации (`syntaxCheck` -> `checkModes`). * Трансформация результатов валидации EDT: - * По умолчанию из результатов анализа исключаются замечания, сработавшие на модулях с включенным запретом редактирования (желтый куб с замком) (параметры `resultsTransform` -> `removeSupport` и `resultsTransform` -> `supportLevel`). + * Используется `stebi` (параметр `resultsTransform` -> `transformer`) + * Формат файла - `generic issues` для SonarQube 10.3+ (параметр `resultsTransform` -> `genericIssueFormat`) + * `stebi` исключает из результатов анализа замечания, сработавшие на модулях с включенным запретом редактирования (желтый куб с замком) (параметры `resultsTransform` -> `removeSupport` и `resultsTransform` -> `supportLevel`). * Анализ SonarQube: * Предполагается наличие единственной настройки `SonarQube installation` (`sonarqube` -> `sonarQubeInstallation`). * Используется `sonar-scanner` из переменной окружения `PATH` (`sonarqube` -> `useSonarScannerFromPath`). @@ -156,7 +160,7 @@ pipeline1C() * Применяется расчет аргументов командной строки для работы [`branch plugin`](https://github.com/mc1arke/sonarqube-community-branch-plugin) или коммерческих версий SonarQube (`sonarqube` -> `branchAnalysisConfiguration`). * Если разработка ведется с использованием подсистемы [БСП "Обновление версии ИБ"](https://its.1c.ru/db/bsp315doc#content:4:1:issogl1_обновление_версии_иб), то в значение параметра `sonar.projectVersion=$configurationVersion` утилиты `sonar-scanner` можно передавать версию из созданного общего модуля. Для этого необходимо заполнить параметр (`sonarqube` -> `infoBaseUpdateModuleName`). Если параметр не заполнен, версия передается из корня конфигурации. * По умолчанию шаг анализа не дожидается окончания фонового задания на сервере SonarQube и не анализирует результат прохождения Порога качества (`sonarqube` -> `waitForQualityGate`). - * Если выполнялась валидация EDT, результаты валидации в формате `generic issues` передаются утилите `sonar-scanner` как значение параметра `sonar.externalIssuesReportPaths`. + * Если выполнялась валидация EDT, результаты валидации передаются утилите `sonar-scanner` как значение параметра `sonar.externalIssuesReportPaths` при использовании `stebi` или как значение параметра `sonar.bsl.languageserver.reportPaths` при использовании `edt-ripper`. * Рассылка уведомлений: * Электронная почта: * Для отправки используется плагин [`email-ext`](https://plugins.jenkins.io/email-ext). Шаблоны сообщений конфигурируются в настройках плагина. @@ -173,9 +177,9 @@ pipeline1C() ## Настройка загрузки расширений -Если у вас есть расширения которые необходимо загрузить в базу для проведения тестов и проверок, это можно сделать на этапе подготовки базы. +Если у вас есть расширения, которые необходимо загрузить в базу для проведения тестов и проверок, это можно сделать на этапе подготовки базы. -* При загрузке из исходников расширения должны быть в том же формате(edt или конфигуратора) что и основная конфигурация. +* При загрузке из исходников расширения должны быть в том же формате (edt или конфигуратора), что и основная конфигурация. * Для загрузки расширений необходимо описать каждое из них в массиве (`initInfobase` -> `extensions`). Для загрузки расширений в информационную базу необходимо выполнить следующие шаги: @@ -233,4 +237,9 @@ pipeline1C() * Добавить расширение `YAXUnit` и дополнительные расширения с тестами можно в `jobConfiguration.json` -> `initInfobase` -> `extensions`. Они будут загружены при инициализации ИБ. * Если ваши тесты размещены в отдельных расширениях, скопируйте файл `./resources/yaxunit.json` из текущей библиотеки в свой репозиторий (`./tools/yaxunit.json`) и перечислите в нем имена ваших расширений. - * Если используется собственный файл `tools/yaxunit.json`, то значение параметра reportPath в нем должно быть равно `./build/out/yaxunit/junit.xml` + * Если используется собственный файл `tools/yaxunit.json`, то значение параметра `reportPath` в нем должно быть равно `./build/out/yaxunit/junit.xml` + +## Настройка трансформации результата валидации EDT + + * При использовании SonarQube версии <10.3 и `stebi` формат отчета должен быть `Generic_Issue` (параметр `resultsTransform` -> `genericIssueFormat`) + * Трансформацию результатов может выполнять `edt-ripper` (параметр `resultsTransform` -> `transformer`). В этом случае замечания будут загружены в SonarQube в формате BSL LS, что позволяет полноценно управлять ими в SonarQube. diff --git a/build.gradle.kts b/build.gradle.kts index a731a1da..3f5ed774 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,8 +5,8 @@ plugins { groovy jacoco id("com.mkobit.jenkins.pipelines.shared-library") version "0.10.1" - id("com.github.ben-manes.versions") version "0.28.0" - id("org.jenkins-ci.jpi") version "0.38.0" apply false + id("com.github.ben-manes.versions") version "0.51.0" + id("org.jenkins-ci.jpi") version "0.52.0-rc.1" apply false } repositories { @@ -28,27 +28,29 @@ tasks { } java { - sourceCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } -val junitVersion = "5.6.1" +val junitVersion = "5.11.0" val spockVersion = "1.3-groovy-2.4" -val groovyVersion = "2.4.19" -val slf4jVersion = "1.8.0-beta4" -var jacksonVersion = "2.9.8" +val groovyVersion = "2.4.21" +val slf4jVersion = "2.0.16" +val jsonschemaVersion = "4.36.0" dependencies { implementation("org.codehaus.groovy", "groovy-all", groovyVersion) - // jackson - implementation("com.fasterxml.jackson.module", "jackson-module-jsonSchema", jacksonVersion) + // jsonschema-generator + implementation("com.github.victools", "jsonschema-generator", jsonschemaVersion) + implementation("com.github.victools", "jsonschema-module-jackson", jsonschemaVersion) // unit-tests - testImplementation("org.junit.jupiter", "junit-jupiter-api", junitVersion) testRuntimeOnly("org.junit.jupiter", "junit-jupiter-engine", junitVersion) + testImplementation("org.junit.jupiter", "junit-jupiter-api", junitVersion) - testImplementation("org.assertj", "assertj-core", "3.15.0") - testImplementation("org.mockito", "mockito-core", "5.11.0") + testImplementation("org.assertj", "assertj-core", "3.26.3") + testImplementation("org.mockito", "mockito-core", "5.13.0") testImplementation("org.slf4j", "slf4j-api", slf4jVersion) testImplementation("org.slf4j", "slf4j-simple", slf4jVersion) @@ -74,7 +76,7 @@ tasks.test { } reports { - html.isEnabled = true + html.required.set(true) } } @@ -85,8 +87,8 @@ tasks.check { tasks.jacocoTestReport { reports { - xml.isEnabled = true - xml.destination = File("$buildDir/reports/jacoco/test/jacoco.xml") + xml.required.set(true) + xml.outputLocation.set(File("$buildDir/reports/jacoco/test/jacoco.xml")) } } @@ -101,20 +103,27 @@ sharedLibrary { coreVersion.set(jenkinsIntegration.downloadDirectory.file("core-version.txt").map { it.asFile.readText().trim() }) // TODO: retrieve downloaded plugin resource pluginDependencies { - dependency("org.jenkins-ci.plugins", "pipeline-build-step", "2.12") - dependency("org.jenkins-ci.plugins", "pipeline-utility-steps", "2.8.0") - dependency("org.jenkins-ci.plugins", "git", "4.4.4") - dependency("org.jenkins-ci.plugins", "http_request", "1.15") - dependency("org.6wind.jenkins", "lockable-resources", "2.7") - dependency("ru.yandex.qatools.allure", "allure-jenkins-plugin", "2.28.1") - val declarativePluginsVersion = "1.6.0" + dependency("org.jenkins-ci.plugins", "pipeline-build-step", "540.vb_e8849e1a_b_d8") + dependency("org.jenkins-ci.plugins", "pipeline-utility-steps", "2.17.0") + dependency("org.jenkins-ci.plugins", "git", "5.2.2") + dependency("org.jenkins-ci.plugins", "http_request", "1.19") + dependency("org.jenkins-ci.plugins", "timestamper", "1.27") + dependency("org.jenkins-ci.plugins", "credentials", "1371.vfee6b_095f0a_3") + dependency("org.jenkins-ci.plugins", "token-macro", "400.v35420b_922dcb_") + dependency("org.jenkins-ci.plugins.workflow", "workflow-step-api", "678.v3ee58b_469476") + + dependency("org.jenkins-ci.modules", "sshd", "3.329.v668e35efc720") + dependency("org.6wind.jenkins", "lockable-resources", "1255.vf48745da_35d0") + dependency("ru.yandex.qatools.allure", "allure-jenkins-plugin", "2.31.1") + dependency("io.jenkins.blueocean", "blueocean-pipeline-api-impl", "1.27.14") + dependency("sp.sd", "file-operations", "266.v9d4e1eb_235b_a_") + + val declarativePluginsVersion = "2.2214.vb_b_34b_2ea_9b_83" dependency("org.jenkinsci.plugins", "pipeline-model-api", declarativePluginsVersion) - dependency("org.jenkinsci.plugins", "pipeline-model-declarative-agent", "1.1.1") dependency("org.jenkinsci.plugins", "pipeline-model-definition", declarativePluginsVersion) dependency("org.jenkinsci.plugins", "pipeline-model-extensions", declarativePluginsVersion) - dependency("io.jenkins.blueocean", "blueocean-pipeline-api-impl", "1.25.3") - dependency("sp.sd", "file-operations", "214.v2e7dc7f25757") + dependency("org.jenkinsci.plugins", "pipeline-model-declarative-agent", "1.1.1") } } diff --git a/resources/globalConfiguration.json b/resources/globalConfiguration.json index 5e4399c5..aa1af975 100644 --- a/resources/globalConfiguration.json +++ b/resources/globalConfiguration.json @@ -92,6 +92,8 @@ "publishToJUnitReport": true }, "resultsTransform": { + "transformer": "stebi", + "genericIssueFormat": "Generic_Issue_10_3", "removeSupport": true, "supportLevel": 0 }, diff --git a/resources/schema.json b/resources/schema.json index 58561f05..a1c89a0f 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -1,284 +1,337 @@ { - "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:JobConfiguration", - "properties" : { - "v8version" : { - "type" : "string", - "description" : "Версия платформы 1С:Предприятие в формате 8.3.хх.хххх." - }, - "edtVersion" : { - "type" : "string", - "description" : "Версия модуля 1C:Enterprise Development Tools формате xxxx.x.x:x86_64" - }, - "srcDir" : { - "type" : "string", - "description" : "Путь к корневому каталогу с исходниками конфигурации, в случае хранения исходников в формате EDT, необходимо указать путь к проекту" - }, - "sourceFormat" : { - "type" : "string", - "description" : "Формат исходников конфигурации", - "enum" : [ "edt", "designer" ] - }, - "defaultBranch" : { - "type" : "string", - "description" : "Имя ветки по умолчанию. Значение по умолчанию - main." - }, - "secrets" : { + "$schema" : "http://json-schema.org/draft-07/schema#", + "definitions" : { + "EmailExtConfiguration" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:Secrets", - "description" : "Идентификаторы сохраненных секретов", "properties" : { - "storagePath" : { - "type" : "string", - "description" : "Путь к хранилищу конфигурации" - }, - "storage" : { - "type" : "string", - "description" : "Данные авторизации в хранилище конфигурации" + "attachLog" : { + "type" : "boolean" }, - "telegramChatId" : { - "type" : "string", - "description" : "Идентификатор telegram-чата для отправки уведомлений" + "directRecipients" : { + "type" : "array", + "items" : { + "type" : "string" + } }, - "telegramBotToken" : { - "type" : "string", - "description" : "Токен авторизации telegram-бота для отправки уведомлений" + "recipientProviders" : { + "type" : "array", + "items" : { + "type" : "string", + "enum" : [ "developers", "requestor", "brokenBuildSuspects", "brokenTestsSuspects" ] + } } } - }, - "stages" : { + } + }, + "type" : "object", + "properties" : { + "bdd" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:StageFlags", - "description" : "Включение этапов сборок", "properties" : { - "sonarqube" : { - "type" : "boolean", - "description" : "Анализ SonarQube включен" - }, - "syntaxCheck" : { - "type" : "boolean", - "description" : "Синтаксический контроль включен" - }, - "edtValidate" : { - "type" : "boolean", - "description" : "Валидация EDT включена" - }, - "smoke" : { - "type" : "boolean", - "description" : "Дымовые тесты включены" - }, - "yaxunit" : { - "type" : "boolean", - "description" : "Запуск YAXUnit тестов включен" - }, - "initSteps" : { - "type" : "boolean", - "description" : "Предварительные шаги инициализации включены" - }, - "bdd" : { - "type" : "boolean", - "description" : "Запуск BDD сценариев включен" - }, - "email" : { - "type" : "boolean", - "description" : "Выполнять рассылку результатов сборки на email" - }, - "telegram" : { - "type" : "boolean", - "description" : "Выполнять рассылку результатов сборки в telegram" + "vrunnerSteps" : { + "description" : "Шаги, запускаемые через vrunner.\n В каждой строке передается отдельная команда \n vrunner и ее аргументы (например, \"vanessa --settings ./tools/vrunner.json\").\n По умолчанию содержит одну команду \"vanessa --settings ./tools/vrunner.json\".\n ", + "type" : "array", + "items" : { + "type" : "string" + } } - } + }, + "description" : "Настройки шага запуска BDD сценариев" }, - "timeout" : { - "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:TimeoutOptions", - "description" : "Настройка таймаутов для шагов", - "properties" : { - "edtToDesignerFormatTransformation" : { - "type" : "integer", - "description" : "Таймаут шага трансформации исходников из формата EDT в формат Конфигуратора, в минутах.\n По умолчанию содержит значение 60.\n " - }, - "getBinaries" : { - "type" : "integer", - "description" : "Таймаут шага получения бинарников, в минутах.\n По умолчанию содержит значение 60.\n " - }, - "createInfoBase" : { - "type" : "integer", - "description" : "Таймаут шага создания информационной базы, в минутах.\n По умолчанию содержит значение 60.\n " - }, - "loadConfiguration" : { - "type" : "integer", - "description" : "Таймаут шага загрузки конфигурации в базу, в минутах.\n По умолчанию содержит значение 60.\n " - }, - "initInfoBase" : { - "type" : "integer", - "description" : "Таймаут шага инициализации информационной базы, в минутах.\n По умолчанию содержит значение 60.\n " - }, - "loadExtensions" : { - "type" : "integer", - "description" : "Таймаут шага загрузки расширений в базу, в минутах.\n По умолчанию содержит значение 60.\n " - }, - "zipInfoBase" : { - "type" : "integer", - "description" : "Таймаут шага архивирования информационной базы, в минутах.\n По умолчанию содержит значение 60.\n " - }, - "designerToEdtFormatTransformation" : { - "type" : "integer", - "description" : "Таймаут шага трансформации исходников из формата Конфигуратора в формат EDT, в минутах.\n По умолчанию содержит значение 60.\n " - }, - "edtValidate" : { - "type" : "integer", - "description" : "Таймаут шага валидации EDT, в минутах.\n По умолчанию содержит значение 240.\n " - }, - "resultTransformation" : { - "type" : "integer", - "description" : "Таймаут шага трансформации результатов EDT, в минутах.\n По умолчанию содержит значение 10.\n " - }, - "bdd" : { - "type" : "integer", - "description" : "Таймаут шага проверки сценариев поведения, в минутах.\n По умолчанию содержит значение 120.\n " - }, - "syntaxCheck" : { - "type" : "integer", - "description" : "Таймаут шага синтаксического контроля, в минутах.\n По умолчанию содержит значение 240.\n " - }, - "smoke" : { - "type" : "integer", - "description" : "Таймаут шага дымовых тестов, в минутах.\n По умолчанию содержит значение 240.\n " - }, - "yaxunit" : { - "type" : "integer", - "description" : "Таймаут шага YAXUnit тестов, в минутах.\n По умолчанию содержит значение 240.\n " - }, - "sonarqube" : { - "type" : "integer", - "description" : "Таймаут шага статического анализа SonarQube, в минутах.\n По умолчанию содержит значение 90.\n " - } - } + "defaultBranch" : { + "type" : "string", + "description" : "Имя ветки по умолчанию. Значение по умолчанию - main." + }, + "edtVersion" : { + "type" : "string", + "description" : "Версия модуля 1C:Enterprise Development Tools формате xxxx.x.x:x86_64" }, "initInfobase" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:InitInfoBaseOptions", - "description" : "Настройки шага инициализации ИБ", "properties" : { - "initMethod" : { - "type" : "string", - "description" : "\n Способ инициализации информационной базы.\n Поддерживается три варианта:\n * fromStorage - инициализация информационной базы из хранилища конфигурации;\n * fromSource - инициализация информационной базы из исходников конфигурации;\n * defaultBranchFromStorage - инициализация основной ветки из хранилища конфигурации, остальных - из исходников конфигурации.\n По умолчанию содержит значение \"fromStorage\".", - "enum" : [ "fromStorage", "fromSource", "defaultBranchFromStorage" ] - }, - "runMigration" : { - "type" : "boolean", - "description" : "Запустить миграцию ИБ" - }, "additionalInitializationSteps" : { - "type" : "array", "description" : "Дополнительные шаги, запускаемые через vrunner.\n В каждой строке передается отдельная команда \n vrunner и ее аргументы (например, \"vanessa --settings ./tools/vrunner.first.json\")\n ", + "type" : "array", "items" : { "type" : "string" } }, - "vrunnerSettings" : { - "type" : "string", - "description" : "Путь к конфигурационному файлу vanessa-runner.\n По умолчанию содержит значение \"./tools/vrunner.json\"\n Используется, если на этапе подготовки база загружается из эталона. \n " - }, - "templateDBPath" : { - "type" : "string", - "description" : "\n Путь к файлу эталонной базы данных.\n * По умолчанию не заполнен;\n * Указывается путь к файлу *.dt или *.1CD.\n " - }, "extensions" : { - "type" : "array", "description" : "Массив расширений для загрузки в конфигурацию.", + "type" : "array", "items" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:InitInfoBaseOptions:Extension", "properties" : { - "name" : { + "initMethod" : { "type" : "string", - "description" : "Имя расширения, используемое при его загрузке в конфигурацию." + "enum" : [ "fromSource", "fromFile" ], + "description" : "\n Способ инициализации расширения.\n Поддерживается два варианта:\n * fromSource - инициализация расширения из исходников;\n * fromFile - скачивание скомпилированного cfe по ссылке.\n " }, - "initMethod" : { + "name" : { "type" : "string", - "description" : "\n Способ инициализации расширения.\n Поддерживается два варианта:\n * fromSource - инициализация расширения из исходников;\n * fromFile - скачивание скомпилированного cfe по ссылке.\n ", - "enum" : [ "fromSource", "fromFile" ] + "description" : "Имя расширения, используемое при его загрузке в конфигурацию." }, "path" : { "type" : "string", "description" : "\n Путь к расширению.\n * В случае если выбран initMethod - указывается путь к исходникам расширения.\n * В случае если выбран initMethod - указывается путь к cfe-файлу\n " }, "stages" : { - "type" : "array", "description" : "\n Шаги, на которых необходимо использовать расширение\n * Если не заполнено, то расширение будет подключено при инициализации базы и останется в базе на всех последующих шагах.\n * Если заполнено, то расширение будет подключено только на соответствующих шагах.\n ", + "type" : "array", "items" : { "type" : "string" } } } } + }, + "initMethod" : { + "type" : "string", + "enum" : [ "fromStorage", "fromSource", "defaultBranchFromStorage" ], + "description" : "\n Способ инициализации информационной базы.\n Поддерживается три варианта:\n * fromStorage - инициализация информационной базы из хранилища конфигурации;\n * fromSource - инициализация информационной базы из исходников конфигурации;\n * defaultBranchFromStorage - инициализация основной ветки из хранилища конфигурации, остальных - из исходников конфигурации.\n По умолчанию содержит значение \"fromStorage\".", + "default" : "fromStorage" + }, + "runMigration" : { + "type" : "boolean", + "description" : "Запустить миграцию ИБ" + }, + "templateDBPath" : { + "type" : "string", + "description" : "\n Путь к файлу эталонной базы данных.\n * По умолчанию не заполнен;\n * Указывается путь к файлу *.dt или *.1CD.\n " + }, + "vrunnerSettings" : { + "type" : "string", + "description" : "Путь к конфигурационному файлу vanessa-runner.\n По умолчанию содержит значение \"./tools/vrunner.json\"\n Используется, если на этапе подготовки база загружается из эталона. \n " } - } + }, + "description" : "Настройки шага инициализации ИБ" }, - "bdd" : { + "logosConfig" : { + "type" : "string", + "description" : "Конфигурация библиотеки logos. Применяется перед запуском каждой стадии сборки" + }, + "notifications" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:BddOptions", - "description" : "Настройки шага запуска BDD сценариев", "properties" : { - "vrunnerSteps" : { - "type" : "array", - "description" : "Шаги, запускаемые через vrunner.\n В каждой строке передается отдельная команда \n vrunner и ее аргументы (например, \"vanessa --settings ./tools/vrunner.json\").\n По умолчанию содержит одну команду \"vanessa --settings ./tools/vrunner.json\".\n ", - "items" : { - "type" : "string" - } + "email" : { + "type" : "object", + "properties" : { + "alwaysOptions" : { + "$ref" : "#/definitions/EmailExtConfiguration" + }, + "failureOptions" : { + "$ref" : "#/definitions/EmailExtConfiguration" + }, + "onAlways" : { + "type" : "boolean", + "description" : "Отправлять всегда" + }, + "onFailure" : { + "type" : "boolean", + "description" : "Отправлять при падении сборки" + }, + "onSuccess" : { + "type" : "boolean", + "description" : "Отправлять при успешной сборке" + }, + "onUnstable" : { + "type" : "boolean", + "description" : "Отправлять при нестабильной сборке" + }, + "successOptions" : { + "$ref" : "#/definitions/EmailExtConfiguration" + }, + "unstableOptions" : { + "$ref" : "#/definitions/EmailExtConfiguration" + } + }, + "description" : "Настройки рассылки результатов сборки через email" + }, + "telegram" : { + "type" : "object", + "properties" : { + "onAlways" : { + "type" : "boolean", + "description" : "Отправлять всегда" + }, + "onFailure" : { + "type" : "boolean", + "description" : "Отправлять при падении сборки" + }, + "onSuccess" : { + "type" : "boolean", + "description" : "Отправлять при успешной сборке" + }, + "onUnstable" : { + "type" : "boolean", + "description" : "Отправлять при нестабильной сборке" + } + }, + "description" : "Настройки рассылки результатов сборки через telegram" + } + }, + "description" : "Настройки рассылки результатов сборки" + }, + "resultsTransform" : { + "type" : "object", + "properties" : { + "genericIssueFormat" : { + "type" : "string", + "enum" : [ "Generic_Issue", "Generic_Issue_10_3" ], + "description" : "Формат отчета generic issue. Только для stebi.\n Для SonarQube версии ниже 10.3 необходимо использовать Generic_Issue.\n По умолчанию Generic_Issue_10_3\n ", + "default" : "Generic_Issue_10_3" + }, + "removeSupport" : { + "type" : "boolean", + "description" : "Фильтровать замечания по уровню поддержки модуля. Только для stebi. По умолчанию включено." + }, + "supportLevel" : { + "type" : "integer", + "description" : "Настройка фильтрации замечаний по уровню поддержки. Только для stebi.\n 0 - удалить файлы на замке;\n 1 - удалить файлы на замке и на поддержке;\n 2 - удалить файлы на замке, на поддержке и снятые с поддержки.\n " + }, + "transformer" : { + "type" : "string", + "enum" : [ "stebi", "edt-ripper" ], + "description" : "Способ преобразования замечаний.\n Поддерживается stebi и edt-ripper.\n По умолчанию содержит значение \"stebi\".\n ", + "default" : "stebi" + } + }, + "description" : "Настройки трансформации результатов анализа" + }, + "secrets" : { + "type" : "object", + "properties" : { + "storage" : { + "type" : "string", + "description" : "Данные авторизации в хранилище конфигурации" + }, + "storagePath" : { + "type" : "string", + "description" : "Путь к хранилищу конфигурации" + }, + "telegramBotToken" : { + "type" : "string", + "description" : "Токен авторизации telegram-бота для отправки уведомлений" + }, + "telegramChatId" : { + "type" : "string", + "description" : "Идентификатор telegram-чата для отправки уведомлений" + } + }, + "description" : "Идентификаторы сохраненных секретов" + }, + "smoke" : { + "type" : "object", + "properties" : { + "publishToAllureReport" : { + "type" : "boolean", + "description" : "Выполнять публикацию результатов в отчет Allure.\n По умолчанию выключено.\n " + }, + "publishToJUnitReport" : { + "type" : "boolean", + "description" : "Выполнять публикацию результатов в отчет JUnit.\n По умолчанию включено.\n " + }, + "vrunnerSettings" : { + "type" : "string", + "description" : "Путь к конфигурационному файлу vanessa-runner.\n По умолчанию содержит значение \"./tools/vrunner.json\".\n " + }, + "xddConfigPath" : { + "type" : "string", + "description" : "Путь к конфигурационному файлу для xddTestRunner.\n По умолчанию содержит значение \"./tools/xUnitParams.json\".\n " } - } + }, + "description" : "Настройки дымового тестирования" }, "sonarqube" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:SonarQubeOptions", - "description" : "Настройки анализа SonarQube", "properties" : { + "branchAnalysisConfiguration" : { + "type" : "string", + "enum" : [ "auto", "fromEnv" ], + "description" : "Вариант конфигурации branch plugin.\n Поддерживаемые варианты:\n * auto - применяется автоконфигурация sonar-scanner силами branchplugin. Так же может применяться для отключения конфигурирования, если branch plugin отсутствует;\n * fromEnv - применяется ручная конфигурация sonar-scanner на основе переменных среды.\n Значение по умолчанию: fromEnv.", + "default" : "auto" + }, + "infoBaseUpdateModuleName" : { + "type" : "string", + "description" : "Имя общего модуля (например, ОбновлениеИнформационнойБазыXXX), в котором указана версия библиотеки.\n Версия должна задаваться в виде присвоения `Описание.Версия = \"ваш номер версии\";`\n " + }, "sonarQubeInstallation" : { "type" : "string", "description" : "Имя настроенного SonarQube-сервера (SonarQube installations).\nЕсли настроен только один сервер, то может быть оставлено пустым." }, - "useSonarScannerFromPath" : { - "type" : "boolean", - "description" : "Использовать sonar-scanner, доступный в PATH" - }, "sonarScannerToolName" : { "type" : "string", "description" : "Имя настроенной утилиты sonar-scanner.\nПрименяется, если useSonarScannerFromPath установлено в false." }, - "infoBaseUpdateModuleName" : { - "type" : "string", - "description" : "Имя общего модуля (например, ОбновлениеИнформационнойБазыXXX), в котором указана версия библиотеки.\n Версия должна задаваться в виде присвоения `Описание.Версия = \"ваш номер версии\";`\n " - }, - "branchAnalysisConfiguration" : { - "type" : "string", - "description" : "Вариант конфигурации branch plugin.\n Поддерживаемые варианты:\n * auto - применяется автоконфигурация sonar-scanner силами branchplugin. Так же может применяться для отключения конфигурирования, если branch plugin отсутствует;\n * fromEnv - применяется ручная конфигурация sonar-scanner на основе переменных среды.\n Значение по умолчанию: fromEnv.", - "enum" : [ "auto", "fromEnv" ] + "useSonarScannerFromPath" : { + "type" : "boolean", + "description" : "Использовать sonar-scanner, доступный в PATH" }, "waitForQualityGate" : { "type" : "boolean", "description" : "Ожидать состояние Quality Gate от SonarQube после загрузки анализа. По умолчанию `false`.\n Таймаут ожидания состояния равен таймауту шага.\n " } - } + }, + "description" : "Настройки анализа SonarQube" }, - "syntaxCheck" : { + "sourceFormat" : { + "type" : "string", + "enum" : [ "edt", "designer" ], + "description" : "Формат исходников конфигурации", + "default" : "designer" + }, + "srcDir" : { + "type" : "string", + "description" : "Путь к корневому каталогу с исходниками конфигурации, в случае хранения исходников в формате EDT, необходимо указать путь к проекту" + }, + "stages" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:SyntaxCheckOptions", - "description" : "Настройки синтаксического контроля", "properties" : { - "pathToJUnitReport" : { - "type" : "string", - "description" : "Путь к файлу отчета jUnit\n По умолчанию содержит значение \"./build/out/jUnit/syntax.xml\"\n " + "bdd" : { + "type" : "boolean", + "description" : "Запуск BDD сценариев включен" }, - "groupErrorsByMetadata" : { + "edtValidate" : { "type" : "boolean", - "description" : "Группировать выявленные ошибки по объектам метаданных.\n По умолчанию включено.\n " + "description" : "Валидация EDT включена" + }, + "email" : { + "type" : "boolean", + "description" : "Выполнять рассылку результатов сборки на email" + }, + "initSteps" : { + "type" : "boolean", + "description" : "Предварительные шаги инициализации включены" + }, + "smoke" : { + "type" : "boolean", + "description" : "Дымовые тесты включены" + }, + "sonarqube" : { + "type" : "boolean", + "description" : "Анализ SonarQube включен" + }, + "syntaxCheck" : { + "type" : "boolean", + "description" : "Синтаксический контроль включен" + }, + "telegram" : { + "type" : "boolean", + "description" : "Выполнять рассылку результатов сборки в telegram" }, + "yaxunit" : { + "type" : "boolean", + "description" : "Запуск YAXUnit тестов включен" + } + }, + "description" : "Включение этапов сборок" + }, + "syntaxCheck" : { + "type" : "object", + "properties" : { "checkModes" : { - "type" : "array", "description" : "Режимы проверки конфигурации", + "type" : "array", "items" : { "type" : "string" } @@ -287,44 +340,94 @@ "type" : "string", "description" : "Путь к файлу с указанием пропускаемых ошибок.\n Формат файла: в каждой строке файла указан текст пропускаемого исключения или его часть\n Кодировка: UTF-8\n " }, + "groupErrorsByMetadata" : { + "type" : "boolean", + "description" : "Группировать выявленные ошибки по объектам метаданных.\n По умолчанию включено.\n " + }, + "pathToJUnitReport" : { + "type" : "string", + "description" : "Путь к файлу отчета jUnit\n По умолчанию содержит значение \"./build/out/jUnit/syntax.xml\"\n " + }, "vrunnerSettings" : { "type" : "string", "description" : "Путь к конфигурационному файлу vanessa-runner.\n По умолчанию содержит значение \"./tools/vrunner.json\".\n " } - } + }, + "description" : "Настройки синтаксического контроля" }, - "smoke" : { + "timeout" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:SmokeTestOptions", - "description" : "Настройки дымового тестирования", "properties" : { - "vrunnerSettings" : { - "type" : "string", - "description" : "Путь к конфигурационному файлу vanessa-runner.\n По умолчанию содержит значение \"./tools/vrunner.json\".\n " + "bdd" : { + "type" : "integer", + "description" : "Таймаут шага проверки сценариев поведения, в минутах.\n По умолчанию содержит значение 120.\n " }, - "xddConfigPath" : { - "type" : "string", - "description" : "Путь к конфигурационному файлу для xddTestRunner.\n По умолчанию содержит значение \"./tools/xUnitParams.json\".\n " + "createInfoBase" : { + "type" : "integer", + "description" : "Таймаут шага создания информационной базы, в минутах.\n По умолчанию содержит значение 60.\n " }, - "publishToAllureReport" : { - "type" : "boolean", - "description" : "Выполнять публикацию результатов в отчет Allure.\n По умолчанию выключено.\n " + "designerToEdtFormatTransformation" : { + "type" : "integer", + "description" : "Таймаут шага трансформации исходников из формата Конфигуратора в формат EDT, в минутах.\n По умолчанию содержит значение 60.\n " }, - "publishToJUnitReport" : { - "type" : "boolean", - "description" : "Выполнять публикацию результатов в отчет JUnit.\n По умолчанию включено.\n " + "edtToDesignerFormatTransformation" : { + "type" : "integer", + "description" : "Таймаут шага трансформации исходников из формата EDT в формат Конфигуратора, в минутах.\n По умолчанию содержит значение 60.\n " + }, + "edtValidate" : { + "type" : "integer", + "description" : "Таймаут шага валидации EDT, в минутах.\n По умолчанию содержит значение 240.\n " + }, + "getBinaries" : { + "type" : "integer", + "description" : "Таймаут шага получения бинарников, в минутах.\n По умолчанию содержит значение 60.\n " + }, + "initInfoBase" : { + "type" : "integer", + "description" : "Таймаут шага инициализации информационной базы, в минутах.\n По умолчанию содержит значение 60.\n " + }, + "loadConfiguration" : { + "type" : "integer", + "description" : "Таймаут шага загрузки конфигурации в базу, в минутах.\n По умолчанию содержит значение 60.\n " + }, + "loadExtensions" : { + "type" : "integer", + "description" : "Таймаут шага загрузки расширений в базу, в минутах.\n По умолчанию содержит значение 60.\n " + }, + "resultTransformation" : { + "type" : "integer", + "description" : "Таймаут шага трансформации результатов EDT, в минутах.\n По умолчанию содержит значение 10.\n " + }, + "smoke" : { + "type" : "integer", + "description" : "Таймаут шага дымовых тестов, в минутах.\n По умолчанию содержит значение 240.\n " + }, + "sonarqube" : { + "type" : "integer", + "description" : "Таймаут шага статического анализа SonarQube, в минутах.\n По умолчанию содержит значение 90.\n " + }, + "syntaxCheck" : { + "type" : "integer", + "description" : "Таймаут шага синтаксического контроля, в минутах.\n По умолчанию содержит значение 240.\n " + }, + "yaxunit" : { + "type" : "integer", + "description" : "Таймаут шага YAXUnit тестов, в минутах.\n По умолчанию содержит значение 240.\n " + }, + "zipInfoBase" : { + "type" : "integer", + "description" : "Таймаут шага архивирования информационной базы, в минутах.\n По умолчанию содержит значение 60.\n " } - } + }, + "description" : "Настройка таймаутов для шагов" + }, + "v8version" : { + "type" : "string", + "description" : "Версия платформы 1С:Предприятие в формате 8.3.хх.хххх." }, "yaxunit" : { "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:YaxunitOptions", - "description" : "Настройки YAXUnit", "properties" : { - "vrunnerSettings" : { - "type" : "string", - "description" : "Путь к конфигурационному файлу vanessa-runner.\n По умолчанию содержит значение \"./tools/vrunner.json\".\n " - }, "configPath" : { "type" : "string", "description" : "Путь к конфигурационному файлу YAXUnit.\n По умолчанию содержит значение \"./tools/yaxunit.json\".\n " @@ -336,114 +439,13 @@ "publishToJUnitReport" : { "type" : "boolean", "description" : "Выполнять публикацию результатов в отчет JUnit.\n По умолчанию включено.\n " - } - } - }, - "resultsTransform" : { - "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:ResultsTransformOptions", - "description" : "Настройки трансформации результатов анализа", - "properties" : { - "removeSupport" : { - "type" : "boolean", - "description" : "Фильтровать замечания по уровню поддержки модуля. По умолчанию включено." - }, - "supportLevel" : { - "type" : "integer", - "description" : "Настройка фильтрации замечаний по уровню поддержки.\n 0 - удалить файлы на замке;\n 1 - удалить файлы на замке и на поддержке;\n 2 - удалить файлы на замке, на поддержке и снятые с поддержки.\n " - } - } - }, - "notifications" : { - "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:NotificationsOptions", - "description" : "Настройки рассылки результатов сборки", - "properties" : { - "email" : { - "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:notification:EmailNotificationOptions", - "description" : "Настройки рассылки результатов сборки через email", - "properties" : { - "onAlways" : { - "type" : "boolean", - "description" : "Отправлять всегда" - }, - "onSuccess" : { - "type" : "boolean", - "description" : "Отправлять при успешной сборке" - }, - "onFailure" : { - "type" : "boolean", - "description" : "Отправлять при падении сборки" - }, - "onUnstable" : { - "type" : "boolean", - "description" : "Отправлять при нестабильной сборке" - }, - "alwaysOptions" : { - "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:notification:email:EmailExtConfiguration", - "properties" : { - "attachLog" : { - "type" : "boolean" - }, - "directRecipients" : { - "type" : "array", - "items" : { - "type" : "string" - } - }, - "recipientProviders" : { - "type" : "array", - "items" : { - "type" : "string", - "enum" : [ "developers", "requestor", "brokenBuildSuspects", "brokenTestsSuspects" ] - } - } - } - }, - "successOptions" : { - "type" : "object", - "$ref" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:notification:email:EmailExtConfiguration" - }, - "failureOptions" : { - "type" : "object", - "$ref" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:notification:email:EmailExtConfiguration" - }, - "unstableOptions" : { - "type" : "object", - "$ref" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:notification:email:EmailExtConfiguration" - } - } }, - "telegram" : { - "type" : "object", - "id" : "urn:jsonschema:ru:pulsar:jenkins:library:configuration:notification:TelegramNotificationOptions", - "description" : "Настройки рассылки результатов сборки через telegram", - "properties" : { - "onAlways" : { - "type" : "boolean", - "description" : "Отправлять всегда" - }, - "onSuccess" : { - "type" : "boolean", - "description" : "Отправлять при успешной сборке" - }, - "onFailure" : { - "type" : "boolean", - "description" : "Отправлять при падении сборки" - }, - "onUnstable" : { - "type" : "boolean", - "description" : "Отправлять при нестабильной сборке" - } - } + "vrunnerSettings" : { + "type" : "string", + "description" : "Путь к конфигурационному файлу vanessa-runner.\n По умолчанию содержит значение \"./tools/vrunner.json\".\n " } - } - }, - "logosConfig" : { - "type" : "string", - "description" : "Конфигурация библиотеки logos. Применяется перед запуском каждой стадии сборки" + }, + "description" : "Настройки YAXUnit" } } } \ No newline at end of file diff --git a/src/JobConfigurationSchemaGenerator.java b/src/JobConfigurationSchemaGenerator.java index 0a542b05..c272bb58 100644 --- a/src/JobConfigurationSchemaGenerator.java +++ b/src/JobConfigurationSchemaGenerator.java @@ -1,27 +1,40 @@ -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.module.jsonSchema.JsonSchema; -import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.victools.jsonschema.generator.OptionPreset; +import com.github.victools.jsonschema.generator.SchemaGenerator; +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; +import com.github.victools.jsonschema.generator.SchemaVersion; +import com.github.victools.jsonschema.module.jackson.JacksonModule; + +import com.github.victools.jsonschema.module.jackson.JacksonOption; import ru.pulsar.jenkins.library.configuration.JobConfiguration; -import java.io.File; -import java.io.StringWriter; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; public class JobConfigurationSchemaGenerator { public static void main(String[] args) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - JsonSchemaGenerator generator = new JsonSchemaGenerator(mapper); - JsonSchema jsonSchema = generator.generateSchema(JobConfiguration.class); - StringWriter json = new StringWriter(); - mapper.configure(SerializationFeature.INDENT_OUTPUT, true); - mapper.writeValue(json, jsonSchema); + SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_7, OptionPreset.PLAIN_JSON) + .with(new JacksonModule(JacksonOption.FLATTENED_ENUMS_FROM_JSONVALUE, JacksonOption.FLATTENED_ENUMS_FROM_JSONPROPERTY)); + + configBuilder.forFields().withDefaultResolver(field -> { + JsonProperty annotation = field.getAnnotationConsideringFieldAndGetter(JsonProperty.class); + return annotation == null || annotation.defaultValue().isEmpty() ? null : annotation.defaultValue(); + }); - File jsonSchemaFile = new File("./resources/schema.json"); - mapper.writeValue(jsonSchemaFile, jsonSchema); + SchemaGenerator generator = new SchemaGenerator(configBuilder.build()); + JsonNode jsonSchema = generator.generateSchema(JobConfiguration.class); - System.out.println(json); + String outputPath = "./resources/schema.json"; + try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputPath))) { + writer.write(jsonSchema.toPrettyString()); + System.out.println(jsonSchema.toPrettyString()); + } catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/src/ru/pulsar/jenkins/library/configuration/InitInfoBaseOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/InitInfoBaseOptions.groovy index 46ba640e..32f7ca9f 100644 --- a/src/ru/pulsar/jenkins/library/configuration/InitInfoBaseOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/InitInfoBaseOptions.groovy @@ -2,6 +2,7 @@ package ru.pulsar.jenkins.library.configuration import com.cloudbees.groovy.cps.NonCPS import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonPropertyDescription @JsonIgnoreProperties(ignoreUnknown = true) @@ -14,6 +15,7 @@ class InitInfoBaseOptions implements Serializable { * fromSource - инициализация информационной базы из исходников конфигурации; * defaultBranchFromStorage - инициализация основной ветки из хранилища конфигурации, остальных - из исходников конфигурации. По умолчанию содержит значение "fromStorage".""") + @JsonProperty(defaultValue = "fromStorage") InitInfoBaseMethod initMethod = InitInfoBaseMethod.FROM_STORAGE @JsonPropertyDescription("Запустить миграцию ИБ") diff --git a/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy b/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy index 8330abe6..3175d42f 100644 --- a/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy @@ -19,57 +19,58 @@ class JobConfiguration implements Serializable { String srcDir @JsonPropertyDescription("Формат исходников конфигурации") - SourceFormat sourceFormat; + @JsonProperty(defaultValue = "designer") + SourceFormat sourceFormat @JsonProperty("stages") @JsonPropertyDescription("Включение этапов сборок") - StageFlags stageFlags; + StageFlags stageFlags @JsonProperty("timeout") @JsonPropertyDescription("Настройка таймаутов для шагов") - TimeoutOptions timeoutOptions; + TimeoutOptions timeoutOptions @JsonPropertyDescription("Имя ветки по умолчанию. Значение по умолчанию - main.") String defaultBranch @JsonPropertyDescription("Идентификаторы сохраненных секретов") - Secrets secrets; + Secrets secrets @JsonProperty("initInfobase") @JsonPropertyDescription("Настройки шага инициализации ИБ") - InitInfoBaseOptions initInfoBaseOptions; + InitInfoBaseOptions initInfoBaseOptions @JsonProperty("bdd") @JsonPropertyDescription("Настройки шага запуска BDD сценариев") - BddOptions bddOptions; + BddOptions bddOptions @JsonProperty("sonarqube") @JsonPropertyDescription("Настройки анализа SonarQube") - SonarQubeOptions sonarQubeOptions; + SonarQubeOptions sonarQubeOptions @JsonProperty("syntaxCheck") @JsonPropertyDescription("Настройки синтаксического контроля") - SyntaxCheckOptions syntaxCheckOptions; + SyntaxCheckOptions syntaxCheckOptions @JsonProperty("smoke") @JsonPropertyDescription("Настройки дымового тестирования") - SmokeTestOptions smokeTestOptions; + SmokeTestOptions smokeTestOptions @JsonProperty("yaxunit") @JsonPropertyDescription("Настройки YAXUnit") - YaxunitOptions yaxunitOptions; + YaxunitOptions yaxunitOptions @JsonProperty("resultsTransform") @JsonPropertyDescription("Настройки трансформации результатов анализа") - ResultsTransformOptions resultsTransformOptions; + ResultsTransformOptions resultsTransformOptions @JsonProperty("notifications") @JsonPropertyDescription("Настройки рассылки результатов сборки") - NotificationsOptions notificationsOptions; + NotificationsOptions notificationsOptions @JsonProperty("logosConfig") @JsonPropertyDescription("Конфигурация библиотеки logos. Применяется перед запуском каждой стадии сборки") - String logosConfig; + String logosConfig @Override @NonCPS @@ -92,13 +93,13 @@ class JobConfiguration implements Serializable { ", resultsTransformOptions=" + resultsTransformOptions + ", notificationOptions=" + notificationsOptions + ", logosConfig='" + logosConfig + '\'' + - '}'; + '}' } boolean infoBaseFromFiles() { IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() - def env = steps.env(); - String branchName = env.BRANCH_NAME; + def env = steps.env() + String branchName = env.BRANCH_NAME def initMethod = initInfoBaseOptions.initMethod return (initMethod == InitInfoBaseMethod.FROM_SOURCE) || diff --git a/src/ru/pulsar/jenkins/library/configuration/ResultsTransformOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/ResultsTransformOptions.groovy index f450d84a..1e4ba92a 100644 --- a/src/ru/pulsar/jenkins/library/configuration/ResultsTransformOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/ResultsTransformOptions.groovy @@ -3,26 +3,44 @@ package ru.pulsar.jenkins.library.configuration import com.cloudbees.groovy.cps.NonCPS import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonPropertyDescription +import com.fasterxml.jackson.annotation.JsonProperty +import ru.pulsar.jenkins.library.configuration.sonarqube.GenericIssueFormat @JsonIgnoreProperties(ignoreUnknown = true) class ResultsTransformOptions implements Serializable { - @JsonPropertyDescription("Фильтровать замечания по уровню поддержки модуля. По умолчанию включено.") + @JsonPropertyDescription("""Способ преобразования замечаний. + Поддерживается stebi и edt-ripper. + По умолчанию содержит значение "stebi". + """) + @JsonProperty(defaultValue = "stebi") + ResultsTransformerType transformer + + @JsonPropertyDescription("Фильтровать замечания по уровню поддержки модуля. Только для stebi. По умолчанию включено.") Boolean removeSupport = true - @JsonPropertyDescription("""Настройка фильтрации замечаний по уровню поддержки. + @JsonPropertyDescription("""Настройка фильтрации замечаний по уровню поддержки. Только для stebi. 0 - удалить файлы на замке; 1 - удалить файлы на замке и на поддержке; 2 - удалить файлы на замке, на поддержке и снятые с поддержки. """) Integer supportLevel + @JsonPropertyDescription("""Формат отчета generic issue. Только для stebi. + Для SonarQube версии ниже 10.3 необходимо использовать Generic_Issue. + По умолчанию Generic_Issue_10_3 + """) + @JsonProperty(defaultValue = "Generic_Issue_10_3") + GenericIssueFormat genericIssueFormat + @Override @NonCPS String toString() { return "ResultsTransformOptions{" + + "transformer=" + transformer + "removeSupport=" + removeSupport + - ", supportLevel=" + supportLevel + - '}'; + "supportLevel=" + supportLevel + + "genericIssueFormat=" + genericIssueFormat + + '}' } } diff --git a/src/ru/pulsar/jenkins/library/configuration/ResultsTransformerType.groovy b/src/ru/pulsar/jenkins/library/configuration/ResultsTransformerType.groovy new file mode 100644 index 00000000..cd997460 --- /dev/null +++ b/src/ru/pulsar/jenkins/library/configuration/ResultsTransformerType.groovy @@ -0,0 +1,12 @@ +package ru.pulsar.jenkins.library.configuration + +import com.fasterxml.jackson.annotation.JsonProperty + +enum ResultsTransformerType { + @JsonProperty("stebi") + STEBI, + + @JsonProperty("edt-ripper") + EDT_RIPPER + +} \ No newline at end of file diff --git a/src/ru/pulsar/jenkins/library/configuration/SonarQubeOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/SonarQubeOptions.groovy index efa3da76..b030a35d 100644 --- a/src/ru/pulsar/jenkins/library/configuration/SonarQubeOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/SonarQubeOptions.groovy @@ -2,6 +2,7 @@ package ru.pulsar.jenkins.library.configuration import com.cloudbees.groovy.cps.NonCPS import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonPropertyDescription @JsonIgnoreProperties(ignoreUnknown = true) @@ -10,7 +11,7 @@ class SonarQubeOptions implements Serializable { @JsonPropertyDescription( "Имя настроенного SonarQube-сервера (SonarQube installations).\nЕсли настроен только один сервер, то может быть оставлено пустым." ) - String sonarQubeInstallation; + String sonarQubeInstallation @JsonPropertyDescription("Использовать sonar-scanner, доступный в PATH") Boolean useSonarScannerFromPath @@ -30,6 +31,7 @@ class SonarQubeOptions implements Serializable { * auto - применяется автоконфигурация sonar-scanner силами branchplugin. Так же может применяться для отключения конфигурирования, если branch plugin отсутствует; * fromEnv - применяется ручная конфигурация sonar-scanner на основе переменных среды. Значение по умолчанию: fromEnv.""") + @JsonProperty(defaultValue = "auto") BranchAnalysisConfiguration branchAnalysisConfiguration @JsonPropertyDescription("""Ожидать состояние Quality Gate от SonarQube после загрузки анализа. По умолчанию `false`. @@ -47,6 +49,6 @@ class SonarQubeOptions implements Serializable { ", infoBaseUpdateModuleName='" + infoBaseUpdateModuleName + '\'' + ", branchAnalysisConfiguration='" + branchAnalysisConfiguration + '\'' + ", waitForQualityGate='" + waitForQualityGate + '\'' + - '}'; + '}' } } diff --git a/src/ru/pulsar/jenkins/library/configuration/sonarqube/GenericIssueFormat.groovy b/src/ru/pulsar/jenkins/library/configuration/sonarqube/GenericIssueFormat.groovy new file mode 100644 index 00000000..0062d0d5 --- /dev/null +++ b/src/ru/pulsar/jenkins/library/configuration/sonarqube/GenericIssueFormat.groovy @@ -0,0 +1,22 @@ +package ru.pulsar.jenkins.library.configuration.sonarqube + +import com.fasterxml.jackson.annotation.JsonProperty + +enum GenericIssueFormat { + @JsonProperty("Generic_Issue") + GENERIC_ISSUE("Generic_Issue"), + + @JsonProperty("Generic_Issue_10_3") + GENERIC_ISSUE_10_3("Generic_Issue_10_3") + + private String value + + private GenericIssueFormat(String value) { + this.value = value + } + + String getValue() { + return value + } + +} \ No newline at end of file diff --git a/src/ru/pulsar/jenkins/library/steps/DesignerToEdtFormatTransformation.groovy b/src/ru/pulsar/jenkins/library/steps/DesignerToEdtFormatTransformation.groovy index f678d0cf..320fb609 100644 --- a/src/ru/pulsar/jenkins/library/steps/DesignerToEdtFormatTransformation.groovy +++ b/src/ru/pulsar/jenkins/library/steps/DesignerToEdtFormatTransformation.groovy @@ -10,12 +10,11 @@ import ru.pulsar.jenkins.library.utils.Logger class DesignerToEdtFormatTransformation implements Serializable { - public static final String PROJECT_NAME = 'temp' public static final String WORKSPACE = 'build/edt-workspace' public static final String WORKSPACE_ZIP = 'build/edt-workspace.zip' public static final String WORKSPACE_ZIP_STASH = 'edt-workspace-zip' - private final JobConfiguration config; + private final JobConfiguration config DesignerToEdtFormatTransformation(JobConfiguration config) { this.config = config @@ -31,18 +30,19 @@ class DesignerToEdtFormatTransformation implements Serializable { return } - def env = steps.env(); + def env = steps.env() def workspaceDir = FileUtils.getFilePath("$env.WORKSPACE/$WORKSPACE") def srcDir = config.srcDir def configurationRoot = FileUtils.getFilePath("$env.WORKSPACE/$srcDir") + def projectName = configurationRoot.getName() def edtVersionForRing = EDT.ringModule(config) steps.deleteDir(workspaceDir) Logger.println("Конвертация исходников из формата конфигуратора в формат EDT") - def ringCommand = "ring $edtVersionForRing workspace import --configuration-files \"$configurationRoot\" --project-name $PROJECT_NAME --workspace-location \"$workspaceDir\"" + def ringCommand = "ring $edtVersionForRing workspace import --configuration-files \"$configurationRoot\" --project-name $projectName --workspace-location \"$workspaceDir\"" steps.ringCommand(ringCommand) diff --git a/src/ru/pulsar/jenkins/library/steps/EdtValidate.groovy b/src/ru/pulsar/jenkins/library/steps/EdtValidate.groovy index f766b9e0..70efc79f 100644 --- a/src/ru/pulsar/jenkins/library/steps/EdtValidate.groovy +++ b/src/ru/pulsar/jenkins/library/steps/EdtValidate.groovy @@ -13,7 +13,7 @@ class EdtValidate implements Serializable { public static final String RESULT_STASH = 'edt-validate' public static final String RESULT_FILE = 'build/out/edt-validate.out' - private final JobConfiguration config; + private final JobConfiguration config EdtValidate(JobConfiguration config) { this.config = config @@ -29,16 +29,21 @@ class EdtValidate implements Serializable { return } - def env = steps.env(); + def env = steps.env() String workspaceLocation = "$env.WORKSPACE/$DesignerToEdtFormatTransformation.WORKSPACE" - String projectList; + String projectList if (config.sourceFormat == SourceFormat.DESIGNER) { steps.unstash(DesignerToEdtFormatTransformation.WORKSPACE_ZIP_STASH) steps.unzip(DesignerToEdtFormatTransformation.WORKSPACE, DesignerToEdtFormatTransformation.WORKSPACE_ZIP) - projectList = "--project-name-list $DesignerToEdtFormatTransformation.PROJECT_NAME" + def srcDir = config.srcDir + def configurationRoot = FileUtils.getFilePath("$env.WORKSPACE/$srcDir") + + def projectName = configurationRoot.getName() + + projectList = "--project-name-list $projectName" } else { def srcDir = config.srcDir def projectDir = FileUtils.getFilePath("$env.WORKSPACE/$srcDir") diff --git a/src/ru/pulsar/jenkins/library/steps/ResultsTransformer.groovy b/src/ru/pulsar/jenkins/library/steps/ResultsTransformer.groovy index 6ea02f94..0eabf616 100644 --- a/src/ru/pulsar/jenkins/library/steps/ResultsTransformer.groovy +++ b/src/ru/pulsar/jenkins/library/steps/ResultsTransformer.groovy @@ -2,18 +2,20 @@ package ru.pulsar.jenkins.library.steps import ru.pulsar.jenkins.library.IStepExecutor import ru.pulsar.jenkins.library.configuration.JobConfiguration +import ru.pulsar.jenkins.library.configuration.ResultsTransformerType import ru.pulsar.jenkins.library.configuration.SourceFormat import ru.pulsar.jenkins.library.ioc.ContextRegistry +import ru.pulsar.jenkins.library.utils.FileUtils import ru.pulsar.jenkins.library.utils.Logger import java.nio.file.Paths class ResultsTransformer implements Serializable { - public static final String RESULT_STASH = 'edt-generic-issue' - public static final String RESULT_FILE = 'build/out/edt-generic-issue.json' + public static final String RESULT_STASH = 'edt-issues' + public static final String RESULT_FILE = 'build/out/edt-issues.json' - private final JobConfiguration config; + private final JobConfiguration config ResultsTransformer(JobConfiguration config) { this.config = config @@ -24,7 +26,7 @@ class ResultsTransformer implements Serializable { Logger.printLocation() - def env = steps.env(); + def env = steps.env() if (!config.stageFlags.edtValidate) { Logger.println("EDT validation is disabled. No transform is needed.") @@ -33,20 +35,46 @@ class ResultsTransformer implements Serializable { steps.unstash(EdtValidate.RESULT_STASH) - Logger.println("Конвертация результата EDT в Generic Issue") + ResultsTransformerType transformerType = config.resultsTransformOptions.transformer def edtValidateFile = "$env.WORKSPACE/$EdtValidate.RESULT_FILE" - def genericIssueFile = "$env.WORKSPACE/$RESULT_FILE" + def srcDir + if (config.sourceFormat == SourceFormat.DESIGNER) { + srcDir = FileUtils.getFilePath("$env.WORKSPACE/$config.srcDir") + } else { + def src = Paths.get(config.srcDir, "src") + srcDir = FileUtils.getFilePath("$env.WORKSPACE/$src") + } + + if (transformerType == ResultsTransformerType.STEBI) { + + Logger.println("Конвертация результата EDT в Generic Issue с помощью stebi") + + def genericIssueFile = "$env.WORKSPACE/$RESULT_FILE" + def genericIssuesFormat = config.resultsTransformOptions.genericIssueFormat.getValue() + + steps.cmd("stebi convert --Format $genericIssuesFormat -r $edtValidateFile $genericIssueFile $srcDir") + + if (config.resultsTransformOptions.removeSupport) { + def supportLevel = config.resultsTransformOptions.supportLevel + steps.cmd("stebi transform --Format $genericIssuesFormat --remove_support $supportLevel --src $srcDir $genericIssueFile") + } - String srcDir = config.sourceFormat == SourceFormat.DESIGNER ? config.srcDir : Paths.get(config.srcDir, "src") - steps.cmd("stebi convert -r $edtValidateFile $genericIssueFile $srcDir") + } else { + + Logger.println("Конвертация результата EDT в Issues с помощью edt-ripper") + + srcDir = FileUtils.getFilePath("$env.WORKSPACE/$config.srcDir") + + def projectName = srcDir.getName() + def srcDirExceptLast = srcDir.getParent() + + steps.cmd("edt-ripper parse $edtValidateFile $srcDirExceptLast $projectName $env.WORKSPACE/$RESULT_FILE") - if (config.resultsTransformOptions.removeSupport) { - def supportLevel = config.resultsTransformOptions.supportLevel - steps.cmd("stebi transform --remove_support $supportLevel --src $srcDir $genericIssueFile") } steps.archiveArtifacts(RESULT_FILE) steps.stash(RESULT_STASH, RESULT_FILE) + } } diff --git a/src/ru/pulsar/jenkins/library/steps/SonarScanner.groovy b/src/ru/pulsar/jenkins/library/steps/SonarScanner.groovy index 23b55386..5b9808b2 100644 --- a/src/ru/pulsar/jenkins/library/steps/SonarScanner.groovy +++ b/src/ru/pulsar/jenkins/library/steps/SonarScanner.groovy @@ -3,6 +3,7 @@ package ru.pulsar.jenkins.library.steps import ru.pulsar.jenkins.library.IStepExecutor import ru.pulsar.jenkins.library.configuration.BranchAnalysisConfiguration import ru.pulsar.jenkins.library.configuration.JobConfiguration +import ru.pulsar.jenkins.library.configuration.ResultsTransformerType import ru.pulsar.jenkins.library.configuration.SourceFormat import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.Logger @@ -10,7 +11,7 @@ import ru.pulsar.jenkins.library.utils.VersionParser class SonarScanner implements Serializable { - private final JobConfiguration config; + private final JobConfiguration config SonarScanner(JobConfiguration config) { this.config = config @@ -26,7 +27,7 @@ class SonarScanner implements Serializable { return } - def env = steps.env(); + def env = steps.env() def sonarScannerBinary @@ -58,8 +59,13 @@ class SonarScanner implements Serializable { } if (config.stageFlags.edtValidate) { - steps.unstash("edt-generic-issue") - sonarCommand += " -Dsonar.externalIssuesReportPaths=build/out/edt-generic-issue.json" + steps.unstash(ResultsTransformer.RESULT_STASH) + + if (config.resultsTransformOptions.transformer == ResultsTransformerType.STEBI) { + sonarCommand += " -Dsonar.externalIssuesReportPaths=" + ResultsTransformer.RESULT_FILE + } else { + sonarCommand += " -Dsonar.bsl.languageserver.reportPaths=" + ResultsTransformer.RESULT_FILE + } } if (config.sonarQubeOptions.waitForQualityGate) { diff --git a/test/integration/groovy/pipeline1cTest.groovy b/test/integration/groovy/pipeline1cTest.groovy new file mode 100644 index 00000000..5930571d --- /dev/null +++ b/test/integration/groovy/pipeline1cTest.groovy @@ -0,0 +1,33 @@ +import hudson.model.Label +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition +import org.jenkinsci.plugins.workflow.job.WorkflowJob +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.jvnet.hudson.test.JenkinsRule + +class pipeline1cTest { + + @Rule + public JenkinsRule rule = new JenkinsRule() + + @Before + void configureGlobalGitLibraries() { + RuleBootstrapper.setup(rule) + } + + @Test + void "pipeline1C should do something"() { + def pipeline = ''' + pipeline1C() + '''.stripIndent() + + rule.createSlave(Label.get("agent")) + final CpsFlowDefinition flow = new CpsFlowDefinition(pipeline, true) + final WorkflowJob workflowJob = rule.createProject(WorkflowJob, 'project') + workflowJob.definition = flow + + rule.assertLogContains('(pre-stage)', rule.buildAndAssertSuccess(workflowJob)) + } + +} diff --git a/test/unit/groovy/ru/pulsar/jenkins/library/configuration/ConfigurationReaderTest.java b/test/unit/groovy/ru/pulsar/jenkins/library/configuration/ConfigurationReaderTest.java index 89c46ad3..9200320b 100644 --- a/test/unit/groovy/ru/pulsar/jenkins/library/configuration/ConfigurationReaderTest.java +++ b/test/unit/groovy/ru/pulsar/jenkins/library/configuration/ConfigurationReaderTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import ru.pulsar.jenkins.library.configuration.sonarqube.GenericIssueFormat; import ru.pulsar.jenkins.library.utils.TestUtils; import java.io.IOException; @@ -47,8 +48,11 @@ void testCreateJobConfigurationObject() throws IOException { assertThat(jobConfiguration.getSyntaxCheckOptions().getCheckModes()).hasSize(4); - assertThat(jobConfiguration.getResultsTransformOptions().getRemoveSupport()).isFalse(); - assertThat(jobConfiguration.getResultsTransformOptions().getSupportLevel()).isZero(); + ResultsTransformOptions resultsTransformOptions = jobConfiguration.getResultsTransformOptions(); + assertThat(resultsTransformOptions.getTransformer()).isEqualTo(ResultsTransformerType.STEBI); + assertThat(resultsTransformOptions.getGenericIssueFormat()).isEqualTo(GenericIssueFormat.GENERIC_ISSUE); + assertThat(resultsTransformOptions.getRemoveSupport()).isFalse(); + assertThat(resultsTransformOptions.getSupportLevel()).isZero(); assertThat(jobConfiguration.getSmokeTestOptions().getVrunnerSettings()).contains("./tools/vrunner-smoke.json"); assertThat(jobConfiguration.getSmokeTestOptions().isPublishToAllureReport()).isFalse(); diff --git a/test/unit/resources/jobConfiguration.json b/test/unit/resources/jobConfiguration.json index 803b75ea..3b3dcbc5 100644 --- a/test/unit/resources/jobConfiguration.json +++ b/test/unit/resources/jobConfiguration.json @@ -54,6 +54,8 @@ ] }, "resultsTransform": { + "transformer": "stebi", + "genericIssueFormat": "Generic_Issue", "removeSupport": false }, "smoke": {