diff --git a/.gitignore b/.gitignore index 2e4da7e..3bb6fce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,10 @@ .idea/ .gradle/ build/ +bin/ +lib/ *.iml +.classpath +.project +.settings/ diff --git a/README.md b/README.md index d67fd24..0c3b1d1 100644 --- a/README.md +++ b/README.md @@ -21,19 +21,20 @@ 1. Для шага подготовки требуется любой агент с меткой `agent`. 1. Для запуска шага анализа SonarQube требуется агент с меткой `sonar`. -1. Для запуска шага валидации EDT требуется агент с меткой `edt` (для собственно валидации) и агент с меткой `oscript` (для трансформации результатов с помощью библиотеки [stebi](https://github.com/Stepa86/stebi)). +1. Для запуска шагов, работающих с EDT (валидация, трансформация формата исходников) требуется агент с меткой `edt` и агент с меткой `oscript` (для трансформации результатов с помощью библиотеки [stebi](https://github.com/Stepa86/stebi)). 1. Для запуска шагов, работающих с 1С (подготовка, синтаксический контроль и т.д.) требуется агент с меткой, совпадающей со значением в поле `v8version` файла конфигурации. -1. В качестве ИБ используется файловая база, создаваемая в `./build/ib` на основании конфигурации из хранилища без пользователей. При необходимости вы можете создать пользователей на фазе инициализации ИБ. -1. Stage "Дымовые тесты" пока пустой. -1. Запуск `vrunner` на текущий момент происходит из локального каталога `oscript_modules`. Предполагается наличие в корне репозитория файла `packagedef`, в котором бы была указана зависимость от `vanessa-runner` +1. В качестве ИБ используется файловая база, создаваемая в каталоге `./build/ib`. При необходимости вы можете создать пользователей на фазе инициализации ИБ. +1. Шаг "Дымовые тесты" пока пустой. ## Возможности -1. Все шаги можно запустить на базе docker-образов из форка репозитория onec-docker. См. [памятку по слоям и последовательности сборки](https://github.com/firstBitSemenovskaya/onec-docker/blob/feature/first-bit/Layers.md) -1. Подготовка информационной базы по версии из хранилища конфигурации. +1. Все шаги можно запустить на базе docker-образов из форка репозитория onec-docker. См. [памятку по слоям и последовательности сборки](https://github.com/firstBitSemenovskaya/onec-docker/blob/feature/first-bit/Layers.md). +1. Поддержка как формата выгрузки из Конфигуратора, так и формата EDT. +1. Подготовка информационной базы по версии из хранилища конфигурации, из исходных файлов конфигурации, комбинированный режим (основная ветка - из хранилища, остальные - из исходников). 1. Запуск ИБ в режиме выполнения обработчиков обновления БСП. 1. Дополнительные шаги инициализации данных в ИБ. -1. Трансформация кода из формата конфигуратора в формат EDT (только если включен шаг `edtValidate`). +1. Трансформация кода из формата конфигуратора в формат EDT. +1. Трансформация кода из формата EDT в формат конфигуратора. 1. Запуск BDD сценариев с сохранением результатов в формате Allure. 1. Запуск синтаксического контроля средствами конфигуратора и сохранение результатов в виде отчета jUnit. 1. Запуск валидации проекта средствами EDT и конвертация отчета в формате generic issues. @@ -99,22 +100,41 @@ pipeline1C() В библиотеке применяется принцип "соглашения по конфигурации" (convention over configuration): конфигурационный файл содержит ряд настроек "по умолчанию". При соблюдении определенных правил структуры репозитория можно сократить -количество переопределений конфигурационного файла до минимума. +количество переопределений конфигурационного файла до минимума. Ниже представлены имеющиеся соглашения и способы их переопределения. * Общее: - * Исходники конфигурации ожидаются в каталоге `src/cf`. - * TODO: Имена "секретов" (jenkins credentials) по умолчанию высчитываются как `GROUP_REPO_KEY`, где `GROUP` и `REPO` - это группа проектов и имя проектов (например, `firstBitSemenovskaya` и `jenkins-lib`), а `KEY` - ключ секрета: - * `STORAGE_PATH` - путь к хранилищу конфигурации; - * `STORAGE_USER` - параметры авторизации в хранилище вида "username with password". - * Все "шаги" по умолчанию выключены. + * В качестве маски версии платформы используется строка "8.3" (`v8version`). + * Исходники конфигурации ожидаются в каталоге `src/cf` (`srcDir`). + * Формат исходников - выгрузка из Конфигуратора (`sourceFormat`). + * Ветка по умолчанию (для комбинированного режима загрузки конфигурации) - "main" (`defaultBranch`). + * Имена "секретов" (jenkins credentials, `secrets`) по умолчанию высчитываются из пути к git-репозиторию (без учета домена, с заменой `/` на `_`) с прибавлением ключа секрета. Например, для репозитория https://github.com/firstBitSemenovskaya/jenkins-lib секрет с адресом хранилища будет выглядеть как `firstBitSemenovskaya_jenkins-lib_STORAGE_PATH`. Ключи секретов: + * `STORAGE_PATH` - путь к хранилищу конфигурации (для `secrets` -> `storagePath`); + * `STORAGE_USER` - параметры авторизации в хранилище вида "username with password" (для `secrets` -> `storage`). + * Все "шаги" по умолчанию выключены (`stages`). + * Если в корне репозитория существует файл `packagedef`, то в шагах, работающих с информационной базой, будет выполнена попытка установки локальных зависимостей средствами `opm`. + * Если после установки локальных зависимостей в каталоге `oscript_modules/bin` сушествует файл `vrunner`, то для выполнения команд работы с информационной базой будет использоваться он, а не глобально установленный `vrunner` из `PATH`. * Результаты в формате `allure` ожидаются в каталоге `build/out/allure` или его подкаталогах. * Инициализация: - * Если включен шаг `initSteps`, то будет выполняться запуск ИБ с целью запуска обработчиков обновления из БСП. (`initInfobase` -> `runMigration`) + * Информационная база инициализируется только в том случае, если в сборочной линии включены шаги, работающие с базой (например, `bdd` или `syntaxCheck`). + * Информационная база инициализируется конфигурацией из хранилища конфигурации (`initInfobase` -> `initMethod`). + * Если выбран метод инициализации ИБ из хранилища конфигурации и в каталоге исходников есть файл `VERSION` (артефакт от работы утилиты `gitsync`), то из хранилища будет загружена версия конфигурации с номером из файла `VERSION`. +* Первичный запуск информационной базы: + * Если информационная база нужна для запуска в режиме "Предприятие" (например, для шагов `bdd` или `smoke`), то будет запущен шаг "Миграция ИБ". + * После загрузки конфигурации в ИБ будет выполняться запуск ИБ с целью запуска обработчиков обновления из БСП (`initInfobase` -> `runMigration`). * Если в настройках шага инициализации не заполнен массив дополнительных шагов миграции (`initInfobase` -> `additionalInitializationSteps`), но в каталоге `tools` присутствуют файлы с именами, удовлетворяющими шаблону `vrunner.init*.json`, то автоматически выполняется запуск `vrunner vanessa` с передачей найденных файлов в качестве значения настроек (параметр `--settings`) в порядке лексиграфической сортировки имен файлов. * BDD: * Если в конфигурационном файле проекта не заполнена настройка `bdd` -> `vrunnerSteps`, то автоматически выполняется запуск `vrunner vanessa --settings tools/vrunner.json`. * Синтаксический контроль: - * Если в репозитории существует файл `tools/vrunner.json`, то синтаксический контроль конфигурации с помощью конфигуратора будет выполняться с передачей файла в параметры запуска `vrunner syntax-check --settings tools/vrunner.json`. - * TODO: Значение параметра `--mode` из конфигурационного файла vrunner имеют приоритет над `syntaxCheck` -> `checkModes`. Значение из `jobConfiguration.json` передается только в том случае, если параметр отсутствует в конфигурационном файле `vrunner`. + * Если в репозитории существует файл `tools/vrunner.json`, то синтаксический контроль конфигурации с помощью конфигуратора будет выполняться с передачей файла в параметры запуска `vrunner syntax-check --settings tools/vrunner.json` (`syntaxCheck` -> `vrunnerSettings`). + * Применяется группировка ошибок по метаданным (`syntaxCheck` -> `groupErrorsByMetadata`). + * Выгрузка результатов в формат `jUnit` осуществляется в файл `./build/out/jUnit/syntax.xml` (`syntaxCheck` -> `pathToJUnitReport`). + * Если в репозитории существует файл `./tools/syntax-check-exception-file.txt`, то команде запука синтаксического контроля конфигурации данный файл будет передаваться как файл с исключениями сообщений об ошибках (параметр `--exception-file`) (`syntaxCheck` -> `exceptionFile`). + * Конфигурационный файл по умолчанию уже содержит ряд "режимов проверки" для синтаксического контроля конфигурации (`syntaxCheck` -> `checkModes`). * Трансформация результатов валидации EDT: - * По умолчанию из результатов анализа исключаются замечания, сработавшие на модулях с включенным запретом редактирования (желтый куб с замком) \ No newline at end of file + * По умолчанию из результатов анализа исключаются замечания, сработавшие на модулях с включенным запретом редактирования (желтый куб с замком) (параметры `resultsTransform` -> `removeSupport` и `resultsTransform` -> `supportLevel`). +* Анализ SonarQube: + * Предполагается наличие единственной настройки `SonarQube installation` (`sonarqube` -> `sonarQubeInstallation`). + * Используется `sonar-scanner` из переменной окружения `PATH` (`sonarqube` -> `useSonarScannerFromPath`). + * Если использование `sonar-scanner` из переменной окружения `PATH` выключено, предполагается наличие настроенного глобального инструмента `SonarQube Scanner` с идентификатором инструмента `sonar-scanner` (`sonarqube` -> `sonarScannerToolName`). + * Версия из корня конфигурации передается утилите `sonar-scanner` как значение параметра `sonar.projectVersion=$configurationVersion`. + * Если выполнялась валидация EDT, результаты валидации в формате `generic issues` передаются утилите `sonar-scanner` как значение параметра `sonar.externalIssuesReportPaths`. diff --git a/resources/globalConfiguration.json b/resources/globalConfiguration.json index e2e2ca1..8f79812 100644 --- a/resources/globalConfiguration.json +++ b/resources/globalConfiguration.json @@ -1,6 +1,9 @@ { "$schema": "schema.json", + "v8version": "8.3", "srcDir": "src/cf", + "sourceFormat": "designer", + "defaultBranch": "main", "secrets": { "storagePath": "UNKNOWN_ID", "storage": "UNKNOWN_ID" @@ -14,6 +17,7 @@ "smoke": false }, "initInfobase": { + "initMethod": "fromStorage", "runMigration": true, "additionalInitializationSteps": [] }, @@ -30,6 +34,7 @@ "syntaxCheck": { "groupErrorsByMetadata": true, "pathToJUnitReport": "./build/out/jUnit/syntax.xml", + "exceptionFile": "./tools/syntax-check-exception-file.txt", "checkModes": [ "-ThinClient", "-WebClient", diff --git a/resources/schema.json b/resources/schema.json index 7a61217..cbd7157 100644 --- a/resources/schema.json +++ b/resources/schema.json @@ -8,7 +8,16 @@ }, "srcDir" : { "type" : "string", - "description" : "Путь к корневому каталогу с исходниками конфигурации" + "description" : "Путь к корневому каталогу с исходниками конфигурации, в случае хранения исходников в формате EDT, необходимо указать путь к проекту" + }, + "sourceFormat" : { + "type" : "string", + "description" : "Формат исходников конфигурации", + "enum" : [ "edt", "designer" ] + }, + "defaultBranch" : { + "type" : "string", + "description" : "Имя ветки по умолчанию" }, "secrets" : { "type" : "object", @@ -61,6 +70,11 @@ "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" : "Запустить миграцию ИБ" @@ -127,6 +141,10 @@ "type" : "string" } }, + "exceptionFile" : { + "type" : "string", + "description" : "Путь к файлу с указанием пропускаемых ошибок.\n Формат файла: в каждой строке файла указан текст пропускаемого исключения или его часть\n Кодировка: UTF-8\n " + }, "vrunnerSettings" : { "type" : "string", "description" : "Путь к конфигурационному файлу vanessa-runner.\n По умолчанию содержит значение \"./tools/vrunner.json\".\n " diff --git a/src/ru/pulsar/jenkins/library/IStepExecutor.groovy b/src/ru/pulsar/jenkins/library/IStepExecutor.groovy index 8c11196..243763b 100644 --- a/src/ru/pulsar/jenkins/library/IStepExecutor.groovy +++ b/src/ru/pulsar/jenkins/library/IStepExecutor.groovy @@ -19,6 +19,8 @@ interface IStepExecutor { String readFile(String file, String encoding) + boolean fileExists(String file) + void echo(message) int cmd(String script, boolean returnStatus) @@ -27,12 +29,24 @@ interface IStepExecutor { void tool(String toolName) + def withCredentials(List bindings, Closure body) + + def string(String credentialsId, String variable) + + def usernamePassword(String credentialsId, String usernameVariable, String passwordVariable) + void withSonarQubeEnv(String installationName, Closure body) EnvironmentAction env() + def dir(String path, Closure body) + void createDir(String path) + void deleteDir() + + void deleteDir(String path) + def withEnv(List strings, Closure body) def archiveArtifacts(String path) diff --git a/src/ru/pulsar/jenkins/library/StepExecutor.groovy b/src/ru/pulsar/jenkins/library/StepExecutor.groovy index 573673b..c5b6368 100644 --- a/src/ru/pulsar/jenkins/library/StepExecutor.groovy +++ b/src/ru/pulsar/jenkins/library/StepExecutor.groovy @@ -37,6 +37,11 @@ class StepExecutor implements IStepExecutor { steps.readFile encoding: encoding, file: file } + @Override + boolean fileExists(String file) { + steps.fileExists file + } + @Override FileWrapper[] findFiles(String glob, String excludes = '') { steps.findFiles glob: glob, excludes: excludes @@ -64,6 +69,23 @@ class StepExecutor implements IStepExecutor { } } + @Override + def withCredentials(List bindings, Closure body) { + steps.withCredentials(bindings) { + body() + } + } + + @Override + def string(String credentialsId, String variable) { + return steps.string(credentialsId: credentialsId, variable: variable) + } + + @Override + def usernamePassword(String credentialsId, String usernameVariable, String passwordVariable) { + return steps.usernamePassword(credentialsId: credentialsId, usernameVariable: usernameVariable, passwordVariable: passwordVariable) + } + @Override EnvironmentAction env() { return steps.env @@ -74,6 +96,25 @@ class StepExecutor implements IStepExecutor { steps.createDir(path) } + @Override + def dir(String path, Closure body) { + steps.dir(path) { + body() + } + } + + @Override + void deleteDir() { + steps.deleteDir() + } + + @Override + void deleteDir(String path) { + steps.dir(path) { + steps.deleteDir() + } + } + @Override def withEnv(List strings, Closure body) { steps.withEnv(strings) { diff --git a/src/ru/pulsar/jenkins/library/configuration/ConfigurationReader.groovy b/src/ru/pulsar/jenkins/library/configuration/ConfigurationReader.groovy index 7b44dc1..09776bd 100644 --- a/src/ru/pulsar/jenkins/library/configuration/ConfigurationReader.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/ConfigurationReader.groovy @@ -3,16 +3,31 @@ package ru.pulsar.jenkins.library.configuration import com.cloudbees.groovy.cps.NonCPS import com.fasterxml.jackson.databind.MapperFeature import com.fasterxml.jackson.databind.ObjectMapper -import org.apache.commons.beanutils.BeanUtils +import org.apache.commons.beanutils.BeanUtilsBean +import org.apache.commons.beanutils.ConvertUtilsBean import ru.pulsar.jenkins.library.IStepExecutor import ru.pulsar.jenkins.library.ioc.ContextRegistry class ConfigurationReader implements Serializable { private static ObjectMapper mapper + private static BeanUtilsBean beanUtilsBean; + static { mapper = new ObjectMapper() mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); + + beanUtilsBean = new BeanUtilsBean(new ConvertUtilsBean() { + @Override + @NonCPS + Object convert(String value, Class clazz) { + if (clazz.isEnum()) { + return Enum.valueOf(clazz, value); + } else { + return super.convert(value, clazz); + } + } + }); } private static final String DEFAULT_CONFIGURATION_RESOURCE = 'globalConfiguration.json' @@ -57,13 +72,13 @@ class ConfigurationReader implements Serializable { @NonCPS private static void mergeObjects(T baseObject, T objectToMerge, Set nonMergeableSettings) { - BeanUtils.describe(objectToMerge).entrySet().stream() + beanUtilsBean.describe(objectToMerge).entrySet().stream() .filter({ e -> e.getValue() != null }) .filter({ e -> e.getKey() != "class" }) .filter({ e -> e.getKey() != "metaClass" }) .filter({ e -> !nonMergeableSettings.contains(e.getKey()) }) .forEach { e -> - BeanUtils.setProperty(baseObject, e.getKey(), e.getValue()); + beanUtilsBean.setProperty(baseObject, e.getKey(), e.getValue()); } nonMergeableSettings.forEach({ key -> diff --git a/src/ru/pulsar/jenkins/library/configuration/InitInfobaseMethod.groovy b/src/ru/pulsar/jenkins/library/configuration/InitInfobaseMethod.groovy new file mode 100644 index 0000000..c13be07 --- /dev/null +++ b/src/ru/pulsar/jenkins/library/configuration/InitInfobaseMethod.groovy @@ -0,0 +1,16 @@ +package ru.pulsar.jenkins.library.configuration + +import com.fasterxml.jackson.annotation.JsonProperty + +enum InitInfobaseMethod { + + @JsonProperty("fromStorage") + FROM_STORAGE, + + @JsonProperty("fromSource") + FROM_SOURCE, + + @JsonProperty("defaultBranchFromStorage") + DEFAULT_BRANCH_FROM_STORAGE + +} diff --git a/src/ru/pulsar/jenkins/library/configuration/InitInfobaseOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/InitInfobaseOptions.groovy index 6350339..d36a3bf 100644 --- a/src/ru/pulsar/jenkins/library/configuration/InitInfobaseOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/InitInfobaseOptions.groovy @@ -7,6 +7,15 @@ import com.fasterxml.jackson.annotation.JsonPropertyDescription @JsonIgnoreProperties(ignoreUnknown = true) class InitInfobaseOptions implements Serializable { + @JsonPropertyDescription(""" + Способ инициализации информационной базы. + Поддерживается три варианта: + * fromStorage - инициализация информационной базы из хранилища конфигурации; + * fromSource - инициализация информационной базы из исходников конфигурации; + * defaultBranchFromStorage - инициализация основной ветки из хранилища конфигурации, остальных - из исходников конфигурации. + По умолчанию содержит значение "fromStorage".""") + InitInfobaseMethod initMethod = InitInfobaseMethod.FROM_STORAGE; + @JsonPropertyDescription("Запустить миграцию ИБ") boolean runMigration = true @@ -20,7 +29,8 @@ class InitInfobaseOptions implements Serializable { @NonCPS String toString() { return "InitInfobaseOptions{" + - "runMigration=" + runMigration + + "initMethod=" + initMethod + + ", runMigration=" + runMigration + ", additionalInitializationSteps=" + additionalInitializationSteps + '}'; } diff --git a/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy b/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy index c404c9d..f623035 100644 --- a/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/JobConfiguration.groovy @@ -1,22 +1,31 @@ package ru.pulsar.jenkins.library.configuration import com.cloudbees.groovy.cps.NonCPS +import com.fasterxml.jackson.annotation.JsonEnumDefaultValue import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonPropertyDescription +import ru.pulsar.jenkins.library.IStepExecutor +import ru.pulsar.jenkins.library.ioc.ContextRegistry @JsonIgnoreProperties(ignoreUnknown = true) class JobConfiguration implements Serializable { @JsonPropertyDescription("Версия платформы 1С:Предприятие в формате 8.3.хх.хххх.") String v8version - @JsonPropertyDescription("Путь к корневому каталогу с исходниками конфигурации") + @JsonPropertyDescription("Путь к корневому каталогу с исходниками конфигурации, в случае хранения исходников в формате EDT, необходимо указать путь к проекту") String srcDir + @JsonPropertyDescription("Формат исходников конфигурации") + SourceFormat sourceFormat; + @JsonProperty("stages") @JsonPropertyDescription("Включение этапов сборок") StageFlags stageFlags; + @JsonPropertyDescription("Имя ветки по умолчанию. Значение по умолчанию - main.") + String defaultBranch + @JsonPropertyDescription("Идентификаторы сохраненных секретов") Secrets secrets; @@ -50,6 +59,8 @@ class JobConfiguration implements Serializable { return "JobConfiguration{" + "v8version='" + v8version + '\'' + ", srcDir='" + srcDir + '\'' + + ", sourceFormat=" + sourceFormat + + ", defaultBranch=" + defaultBranch + ", stageFlags=" + stageFlags + ", secrets=" + secrets + ", initInfobaseOptions=" + initInfobaseOptions + @@ -60,4 +71,15 @@ class JobConfiguration implements Serializable { ", logosConfig=" + logosConfig + '}'; } + + boolean infobaseFromFiles(){ + IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() + def env = steps.env(); + String branchName = env.BRANCH_NAME; + def initMethod = initInfobaseOptions.initMethod + + return sourceFormat == SourceFormat.EDT || + (initMethod == InitInfobaseMethod.FROM_SOURCE) || + (initMethod == InitInfobaseMethod.DEFAULT_BRANCH_FROM_STORAGE && branchName != defaultBranch) + } } \ No newline at end of file diff --git a/src/ru/pulsar/jenkins/library/configuration/Secrets.groovy b/src/ru/pulsar/jenkins/library/configuration/Secrets.groovy index 0ee17f0..51941df 100644 --- a/src/ru/pulsar/jenkins/library/configuration/Secrets.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/Secrets.groovy @@ -7,6 +7,8 @@ import com.fasterxml.jackson.annotation.JsonPropertyDescription @JsonIgnoreProperties(ignoreUnknown = true) class Secrets implements Serializable { + public static final String UNKNOWN_ID = "UNKNOWN_ID" + @JsonPropertyDescription("Путь к хранилищу конфигурации") String storagePath diff --git a/src/ru/pulsar/jenkins/library/configuration/SourceFormat.groovy b/src/ru/pulsar/jenkins/library/configuration/SourceFormat.groovy new file mode 100644 index 0000000..5f11f95 --- /dev/null +++ b/src/ru/pulsar/jenkins/library/configuration/SourceFormat.groovy @@ -0,0 +1,12 @@ +package ru.pulsar.jenkins.library.configuration + +import com.fasterxml.jackson.annotation.JsonProperty + +enum SourceFormat { + @JsonProperty("edt") + EDT, + + @JsonProperty("designer") + DESIGNER + +} \ No newline at end of file diff --git a/src/ru/pulsar/jenkins/library/configuration/SyntaxCheckOptions.groovy b/src/ru/pulsar/jenkins/library/configuration/SyntaxCheckOptions.groovy index 6edbf9b..ded2357 100644 --- a/src/ru/pulsar/jenkins/library/configuration/SyntaxCheckOptions.groovy +++ b/src/ru/pulsar/jenkins/library/configuration/SyntaxCheckOptions.groovy @@ -20,6 +20,12 @@ class SyntaxCheckOptions implements Serializable { @JsonPropertyDescription("Режимы проверки конфигурации") String[] checkModes + @JsonPropertyDescription("""Путь к файлу с указанием пропускаемых ошибок. + Формат файла: в каждой строке файла указан текст пропускаемого исключения или его часть + Кодировка: UTF-8 + """) + String exceptionFile = "./tools/syntax-check-exception-file.txt" + @JsonPropertyDescription("""Путь к конфигурационному файлу vanessa-runner. По умолчанию содержит значение "./tools/vrunner.json". """) diff --git a/src/ru/pulsar/jenkins/library/steps/Bdd.groovy b/src/ru/pulsar/jenkins/library/steps/Bdd.groovy index ebb8629..454b4c4 100644 --- a/src/ru/pulsar/jenkins/library/steps/Bdd.groovy +++ b/src/ru/pulsar/jenkins/library/steps/Bdd.groovy @@ -4,6 +4,7 @@ import ru.pulsar.jenkins.library.IStepExecutor import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.Logger +import ru.pulsar.jenkins.library.utils.VRunner class Bdd implements Serializable { @@ -29,16 +30,11 @@ class Bdd implements Serializable { steps.createDir('build/out') - // TODO: удалить после выхода VAS 1.0.35 - steps.httpRequest( - 'https://cloud.svc.pulsar.ru/index.php/s/WKwmqpFXSjfYjAH/download', - 'oscript_modules/vanessa-automation-single/vanessa-automation-single.epf' - ) - steps.catchError { config.bddOptions.vrunnerSteps.each { Logger.println("Шаг запуска сценариев командой ${it}") - steps.cmd("oscript_modules/bin/vrunner ${it} --ibconnection \"/F./build/ib\"") + String vrunnerPath = VRunner.getVRunnerPath(); + VRunner.exec("$vrunnerPath ${it} --ibconnection \"/F./build/ib\"") } } } diff --git a/src/ru/pulsar/jenkins/library/steps/EdtTransform.groovy b/src/ru/pulsar/jenkins/library/steps/DesignerToEdtFormatTransformation.groovy similarity index 90% rename from src/ru/pulsar/jenkins/library/steps/EdtTransform.groovy rename to src/ru/pulsar/jenkins/library/steps/DesignerToEdtFormatTransformation.groovy index 68e53e6..bfee6f0 100644 --- a/src/ru/pulsar/jenkins/library/steps/EdtTransform.groovy +++ b/src/ru/pulsar/jenkins/library/steps/DesignerToEdtFormatTransformation.groovy @@ -6,7 +6,7 @@ import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.Logger -class EdtTransform implements Serializable { +class DesignerToEdtFormatTransformation implements Serializable { public static final String PROJECT_NAME = 'temp' public static final String WORKSPACE = 'build/edt-workspace' @@ -15,7 +15,7 @@ class EdtTransform implements Serializable { private final JobConfiguration config; - EdtTransform(JobConfiguration config) { + DesignerToEdtFormatTransformation(JobConfiguration config) { this.config = config } @@ -34,7 +34,7 @@ class EdtTransform implements Serializable { def workspaceDir = "$env.WORKSPACE/$WORKSPACE" def configurationRoot = new File(env.WORKSPACE, config.srcDir).getAbsolutePath() - steps.createDir(workspaceDir) + steps.deleteDir(workspaceDir) Logger.println("Конвертация исходников из формата конфигуратора в формат EDT") diff --git a/src/ru/pulsar/jenkins/library/steps/EdtToDesignerFormatTransformation.groovy b/src/ru/pulsar/jenkins/library/steps/EdtToDesignerFormatTransformation.groovy new file mode 100644 index 0000000..a925b64 --- /dev/null +++ b/src/ru/pulsar/jenkins/library/steps/EdtToDesignerFormatTransformation.groovy @@ -0,0 +1,57 @@ +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.SourceFormat +import ru.pulsar.jenkins.library.ioc.ContextRegistry +import ru.pulsar.jenkins.library.utils.Constants +import ru.pulsar.jenkins.library.utils.Logger + +class EdtToDesignerFormatTransformation implements Serializable { + + public static final String WORKSPACE = 'build/edt-workspace' + public static final String CONFIGURATION_DIR = 'build/cfg' + public static final String CONFIGURATION_ZIP = 'build/cfg.zip' + public static final String CONFIGURATION_ZIP_STASH = 'cfg-zip' + + private final JobConfiguration config; + + EdtToDesignerFormatTransformation(JobConfiguration config) { + this.config = config + } + + def run() { + IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() + + Logger.printLocation() + + if (config.sourceFormat != SourceFormat.EDT) { + Logger.println("SRC is not in EDT format. No transform is needed.") + return + } + + def env = steps.env(); + + def srcDir = config.srcDir + def projectDir = new File("$env.WORKSPACE/$srcDir").getCanonicalPath() + def workspaceDir = "$env.WORKSPACE/$WORKSPACE" + def configurationRoot = "$env.WORKSPACE/$CONFIGURATION_DIR" + + steps.deleteDir(workspaceDir) + steps.deleteDir(configurationRoot) + + Logger.println("Конвертация исходников из формата EDT в формат Конфигуратора") + + def ringCommand = "ring edt workspace export --workspace-location '$workspaceDir' --project '$projectDir' --configuration-files '$configurationRoot'" + + def ringOpts =[Constants.DEFAULT_RING_OPTS] + steps.withEnv(ringOpts) { + steps.cmd(ringCommand) + } + + steps.zip(CONFIGURATION_DIR, CONFIGURATION_ZIP) + steps.stash(CONFIGURATION_ZIP_STASH, CONFIGURATION_ZIP) + } + +} diff --git a/src/ru/pulsar/jenkins/library/steps/EdtValidate.groovy b/src/ru/pulsar/jenkins/library/steps/EdtValidate.groovy index febc0fc..4f30a22 100644 --- a/src/ru/pulsar/jenkins/library/steps/EdtValidate.groovy +++ b/src/ru/pulsar/jenkins/library/steps/EdtValidate.groovy @@ -2,6 +2,7 @@ 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.SourceFormat import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.Logger @@ -26,26 +27,34 @@ class EdtValidate implements Serializable { return } - steps.unstash(EdtTransform.WORKSPACE_ZIP_STASH) - steps.unzip(EdtTransform.WORKSPACE, EdtTransform.WORKSPACE_ZIP) - def env = steps.env(); - def resultFile = "$env.WORKSPACE/$RESULT_FILE" - def workspaceLocation = "$env.WORKSPACE/$EdtTransform.WORKSPACE" + String workspaceLocation = "$env.WORKSPACE/$DesignerToEdtFormatTransformation.WORKSPACE" + String projectList; - steps.createDir(new File(resultFile).getParent()) + 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" + } else { + String projectDir = new File("$env.WORKSPACE/$config.srcDir").getCanonicalPath() + projectList = "--project-list '$projectDir'" + } + + def resultFile = "$env.WORKSPACE/$RESULT_FILE" Logger.println("Выполнение валидации EDT") - def ringCommand = "ring edt workspace validate --workspace-location '$workspaceLocation' --file '$resultFile' --project-name-list $EdtTransform.PROJECT_NAME" + def ringCommand = "ring edt workspace validate --workspace-location '$workspaceLocation' --file '$resultFile' $projectList" def ringOpts = ['RING_OPTS=-Dfile.encoding=UTF-8 -Dosgi.nl=ru -Duser.language=ru'] steps.withEnv(ringOpts) { steps.catchError { steps.cmd(ringCommand) } } - steps.archiveArtifacts("$EdtTransform.WORKSPACE/.metadata/.log") + + steps.archiveArtifacts("$DesignerToEdtFormatTransformation.WORKSPACE/.metadata/.log") steps.archiveArtifacts(RESULT_FILE) steps.stash(RESULT_STASH, RESULT_FILE) } diff --git a/src/ru/pulsar/jenkins/library/steps/InitFromFiles.groovy b/src/ru/pulsar/jenkins/library/steps/InitFromFiles.groovy new file mode 100644 index 0000000..a8ce35d --- /dev/null +++ b/src/ru/pulsar/jenkins/library/steps/InitFromFiles.groovy @@ -0,0 +1,49 @@ +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.SourceFormat +import ru.pulsar.jenkins.library.ioc.ContextRegistry +import ru.pulsar.jenkins.library.utils.Logger +import ru.pulsar.jenkins.library.utils.VRunner + +class InitFromFiles implements Serializable { + + private final JobConfiguration config; + + InitFromFiles(JobConfiguration config) { + this.config = config + } + + def run() { + IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() + + Logger.printLocation() + + if (!config.infobaseFromFiles()) { + Logger.println("init infoBase from files is disabled") + return + } + + steps.installLocalDependencies(); + + Logger.println("Распаковка файлов") + + String srcDir; + + if (config.sourceFormat == SourceFormat.EDT) { + def env = steps.env(); + srcDir = "$env.WORKSPACE/$EdtToDesignerFormatTransformation.CONFIGURATION_DIR" + + steps.unstash(EdtToDesignerFormatTransformation.CONFIGURATION_ZIP_STASH) + steps.unzip(srcDir, EdtToDesignerFormatTransformation.CONFIGURATION_ZIP) + } else { + srcDir = config.srcDir; + } + + Logger.println("Выполнение загрузки конфигурации из файлов") + String vrunnerPath = VRunner.getVRunnerPath(); + def initCommand = "$vrunnerPath init-dev --src $srcDir --ibconnection \"/F./build/ib\"" + VRunner.exec(initCommand) + } +} diff --git a/src/ru/pulsar/jenkins/library/steps/InitFromStorage.groovy b/src/ru/pulsar/jenkins/library/steps/InitFromStorage.groovy new file mode 100644 index 0000000..6ed2b39 --- /dev/null +++ b/src/ru/pulsar/jenkins/library/steps/InitFromStorage.groovy @@ -0,0 +1,74 @@ +package ru.pulsar.jenkins.library.steps + +import com.cloudbees.groovy.cps.NonCPS +import org.jenkinsci.plugins.workflow.support.actions.EnvironmentAction +import ru.pulsar.jenkins.library.IStepExecutor +import ru.pulsar.jenkins.library.configuration.JobConfiguration +import ru.pulsar.jenkins.library.configuration.Secrets +import ru.pulsar.jenkins.library.ioc.ContextRegistry +import ru.pulsar.jenkins.library.utils.Logger +import ru.pulsar.jenkins.library.utils.VRunner +import ru.pulsar.jenkins.library.utils.VersionParser + +import static ru.pulsar.jenkins.library.configuration.Secrets.UNKNOWN_ID + +class InitFromStorage implements Serializable { + + final static REPO_SLUG_REGEXP = ~/(?m)^(?:[^:\/?#\n]+:)?(?:\/+[^\/?#\n]*)?\/?([^?\n]*)/ + + private final JobConfiguration config + + InitFromStorage(JobConfiguration config) { + this.config = config + } + + def run() { + IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() + + Logger.printLocation() + + if (config.infobaseFromFiles()) { + Logger.println("init infoBase from storage is disabled") + return + } + + steps.installLocalDependencies() + + String storageVersion = VersionParser.storage() + String storageVersionParameter = storageVersion == "" ? "" : "--storage-ver $storageVersion" + + EnvironmentAction env = steps.env(); + String repoSlug = computeRepoSlug(env.GIT_URL) + + Secrets secrets = config.secrets + + String storageCredentials = secrets.storage == UNKNOWN_ID ? repoSlug + "_STORAGE_USER" : secrets.storage + String storagePath = secrets.storagePath == UNKNOWN_ID ? repoSlug + "_STORAGE_PATH" : secrets.storagePath + + steps.withCredentials([ + steps.usernamePassword( + storageCredentials, + 'RUNNER_STORAGE_USER', + 'RUNNER_STORAGE_PWD' + ), + steps.string( + storagePath, + 'RUNNER_STORAGE_NAME' + ) + ]) { + String vrunnerPath = VRunner.getVRunnerPath() + VRunner.exec "$vrunnerPath init-dev --storage $storageVersionParameter --ibconnection \"/F./build/ib\"" + } + } + + @NonCPS + private static String computeRepoSlug(String text) { + def matcher = text =~ REPO_SLUG_REGEXP + String repoSlug = matcher != null && matcher.getCount() == 1 ? matcher[0][1] : "" + if (repoSlug.endsWith(".git")) { + repoSlug = repoSlug[0..-5] + } + repoSlug = repoSlug.replace('/', '_') + return repoSlug + } +} diff --git a/src/ru/pulsar/jenkins/library/steps/InitInfobase.groovy b/src/ru/pulsar/jenkins/library/steps/InitInfobase.groovy index eaef74b..f85c9ea 100644 --- a/src/ru/pulsar/jenkins/library/steps/InitInfobase.groovy +++ b/src/ru/pulsar/jenkins/library/steps/InitInfobase.groovy @@ -5,6 +5,7 @@ import ru.pulsar.jenkins.library.IStepExecutor import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.Logger +import ru.pulsar.jenkins.library.utils.VRunner class InitInfobase implements Serializable { @@ -26,21 +27,17 @@ class InitInfobase implements Serializable { return } - // TODO: удалить после выхода VAS 1.0.35 - steps.httpRequest( - 'https://cloud.svc.pulsar.ru/index.php/s/WKwmqpFXSjfYjAH/download', - 'oscript_modules/vanessa-automation-single/vanessa-automation-single.epf' - ) - List logosConfig = ["LOGOS_CONFIG=$config.logosConfig"] steps.withEnv(logosConfig) { + String vrunnerPath = VRunner.getVRunnerPath(); + if (config.initInfobaseOptions.runMigration) { Logger.println("Запуск миграции ИБ") // Запуск миграции steps.catchError { - steps.cmd('oscript_modules/bin/vrunner run --command "ЗапуститьОбновлениеИнформационнойБазы;ЗавершитьРаботуСистемы;" --execute \\$runnerRoot/epf/ЗакрытьПредприятие.epf --ibconnection "/F./build/ib"') + VRunner.exec(vrunnerPath + ' run --command "ЗапуститьОбновлениеИнформационнойБазы;ЗавершитьРаботуСистемы;" --execute \\$runnerRoot/epf/ЗакрытьПредприятие.epf --ibconnection "/F./build/ib"') } } else { Logger.println("Шаг миграции ИБ выключен") @@ -52,12 +49,12 @@ class InitInfobase implements Serializable { files = files.sort new OrderBy( { it.name }) files.each { Logger.println("Первичная инициализация файлом ${it.path}") - steps.cmd("oscript_modules/bin/vrunner vanessa --settings ${it.path} --ibconnection \"/F./build/ib\"") + VRunner.exec("$vrunnerPath vanessa --settings ${it.path} --ibconnection \"/F./build/ib\"") } } else { config.initInfobaseOptions.additionalInitializationSteps.each { Logger.println("Первичная инициализация командой ${it}") - steps.cmd("oscript_modules/bin/vrunner ${it} --ibconnection \"/F./build/ib\"") + VRunner.exec("$vrunnerPath ${it} --ibconnection \"/F./build/ib\"") } } } diff --git a/src/ru/pulsar/jenkins/library/steps/ResultsTransformer.groovy b/src/ru/pulsar/jenkins/library/steps/ResultsTransformer.groovy index 890466b..22c261a 100644 --- a/src/ru/pulsar/jenkins/library/steps/ResultsTransformer.groovy +++ b/src/ru/pulsar/jenkins/library/steps/ResultsTransformer.groovy @@ -2,9 +2,12 @@ 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.SourceFormat import ru.pulsar.jenkins.library.ioc.ContextRegistry 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' @@ -35,11 +38,12 @@ class ResultsTransformer implements Serializable { def edtValidateFile = "$env.WORKSPACE/$EdtValidate.RESULT_FILE" def genericIssueFile = "$env.WORKSPACE/$RESULT_FILE" - steps.cmd("stebi convert $edtValidateFile $genericIssueFile $config.srcDir") + String srcDir = config.sourceFormat == SourceFormat.DESIGNER ? config.srcDir : Paths.get(config.srcDir, "src") + steps.cmd("stebi convert $edtValidateFile $genericIssueFile $srcDir") if (config.resultsTransformOptions.removeSupport) { def supportLevel = config.resultsTransformOptions.supportLevel - steps.cmd("stebi transform --remove_support $supportLevel --src $config.srcDir $genericIssueFile") + steps.cmd("stebi transform --remove_support $supportLevel --src $srcDir $genericIssueFile") } steps.archiveArtifacts(RESULT_FILE) diff --git a/src/ru/pulsar/jenkins/library/steps/SonarScanner.groovy b/src/ru/pulsar/jenkins/library/steps/SonarScanner.groovy index a75f6ec..bac8532 100644 --- a/src/ru/pulsar/jenkins/library/steps/SonarScanner.groovy +++ b/src/ru/pulsar/jenkins/library/steps/SonarScanner.groovy @@ -2,6 +2,7 @@ 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.SourceFormat import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.Logger import ru.pulsar.jenkins.library.utils.VersionParser @@ -13,7 +14,11 @@ class SonarScanner implements Serializable { SonarScanner(JobConfiguration config) { this.config = config - this.rootFile = "$config.srcDir/Configuration.xml" + if (config.sourceFormat == SourceFormat.EDT){ + this.rootFile = "$config.srcDir/src/Configuration/Configuration.mdo" + } else { + this.rootFile = "$config.srcDir/Configuration.xml" + } } def run() { @@ -39,7 +44,13 @@ class SonarScanner implements Serializable { String sonarCommand = "$sonarScannerBinary -Dsonar.branch.name=$env.BRANCH_NAME" - String configurationVersion = VersionParser.configuration(rootFile) + String configurationVersion + if (config.sourceFormat == SourceFormat.EDT) { + configurationVersion = VersionParser.edt(rootFile) + } else { + configurationVersion = VersionParser.configuration(rootFile) + } + if (configurationVersion) { sonarCommand += " -Dsonar.projectVersion=$configurationVersion" } diff --git a/src/ru/pulsar/jenkins/library/utils/Constants.groovy b/src/ru/pulsar/jenkins/library/utils/Constants.groovy new file mode 100644 index 0000000..82dc25f --- /dev/null +++ b/src/ru/pulsar/jenkins/library/utils/Constants.groovy @@ -0,0 +1,6 @@ +package ru.pulsar.jenkins.library.utils + +final class Constants { + public static final String DEFAULT_RING_OPTS = "RING_OPTS=-Dfile.encoding=UTF-8 -Dosgi.nl=ru -Duser.language=ru" +} + diff --git a/src/ru/pulsar/jenkins/library/utils/VRunner.groovy b/src/ru/pulsar/jenkins/library/utils/VRunner.groovy new file mode 100644 index 0000000..d9b48ab --- /dev/null +++ b/src/ru/pulsar/jenkins/library/utils/VRunner.groovy @@ -0,0 +1,30 @@ +package ru.pulsar.jenkins.library.utils + +import ru.pulsar.jenkins.library.IStepExecutor +import ru.pulsar.jenkins.library.ioc.ContextRegistry + +class VRunner { + + static final String DEFAULT_VRUNNER_OPTS = "RUNNER_NOCACHEUSE=1" + + static String getVRunnerPath() { + + IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() + + String vrunnerBinary = steps.isUnix() ? "vrunner" : "vrunner.bat"; + String vrunnerPath = "oscript_modules/bin/$vrunnerBinary"; + if (!steps.fileExists(vrunnerPath)) { + vrunnerPath = vrunnerBinary; + } + + return vrunnerPath; + } + + static int exec(String command, boolean returnStatus = false) { + IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() + + steps.withEnv([DEFAULT_VRUNNER_OPTS]) { + return steps.cmd(command, returnStatus) + } as int + } +} diff --git a/src/ru/pulsar/jenkins/library/utils/VersionParser.groovy b/src/ru/pulsar/jenkins/library/utils/VersionParser.groovy index 092e97f..7183967 100644 --- a/src/ru/pulsar/jenkins/library/utils/VersionParser.groovy +++ b/src/ru/pulsar/jenkins/library/utils/VersionParser.groovy @@ -10,18 +10,26 @@ class VersionParser implements Serializable { final static VERSION_REGEXP = ~/(?i)(.*)<\/version>/ static String configuration(rootFile = 'src/cf/Configuration.xml') { + return extractVersionFromFile(rootFile, VERSION_REGEXP) + } - IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() - - def configurationText = steps.readFile(rootFile, 'UTF-8'); - return version(configurationText, VERSION_REGEXP) + static String edt(rootFile = 'src/Configuration/Configuration.mdo') { + return extractVersionFromFile(rootFile, VERSION_REGEXP) } static String storage(versionFile = 'src/cf/VERSION') { + return extractVersionFromFile(versionFile, VERSION_REGEXP) + } + + private static String extractVersionFromFile(String filePath, Pattern regexp) { IStepExecutor steps = ContextRegistry.getContext().getStepExecutor() - def storageVersionText = steps.readFile(versionFile, 'UTF-8') - return version(storageVersionText, VERSION_REGEXP) + if (!steps.fileExists(filePath)) { + return "" + } + + def configurationText = steps.readFile(filePath, 'UTF-8'); + return version(configurationText, regexp) } @NonCPS diff --git a/test/integration/groovy/jobConfigurationTest.groovy b/test/integration/groovy/jobConfigurationTest.groovy index bffef3f..e3ded0b 100644 --- a/test/integration/groovy/jobConfigurationTest.groovy +++ b/test/integration/groovy/jobConfigurationTest.groovy @@ -73,5 +73,6 @@ class jobConfigurationTest { def run = rule.buildAndAssertSuccess(workflowJob) rule.assertLogContains("v8version='8.3.12.1500'", run) rule.assertLogContains("sonarScannerToolName='sonar-scanner'", run) + rule.assertLogContains("initMethod=FROM_SOURCE", run) } } \ No newline at end of file diff --git a/test/integration/resources/jobConfiguration.json b/test/integration/resources/jobConfiguration.json index b776078..e027b9f 100644 --- a/test/integration/resources/jobConfiguration.json +++ b/test/integration/resources/jobConfiguration.json @@ -1,3 +1,6 @@ { - "v8version": "8.3.12.1500" + "v8version": "8.3.12.1500", + "initInfobase": { + "initMethod": "fromSource" + } } \ No newline at end of file diff --git a/test/unit/groovy/ru/pulsar/jenkins/library/utils/TestUtils.java b/test/unit/groovy/ru/pulsar/jenkins/library/utils/TestUtils.java index 2531ae6..6d2e88b 100644 --- a/test/unit/groovy/ru/pulsar/jenkins/library/utils/TestUtils.java +++ b/test/unit/groovy/ru/pulsar/jenkins/library/utils/TestUtils.java @@ -34,6 +34,11 @@ public class TestUtils { return FileUtils.readFileToString(new File(file), encoding); }); + when(steps.fileExists(anyString())).thenAnswer(invocation -> { + String file = invocation.getArgument(0); + return new File(file).exists(); + }); + return steps; } diff --git a/vars/edtTransform.groovy b/vars/designerToEdtFormatTransformation.groovy similarity index 61% rename from vars/edtTransform.groovy rename to vars/designerToEdtFormatTransformation.groovy index de901e5..4b00f3c 100644 --- a/vars/edtTransform.groovy +++ b/vars/designerToEdtFormatTransformation.groovy @@ -1,10 +1,10 @@ import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.ioc.ContextRegistry -import ru.pulsar.jenkins.library.steps.EdtTransform +import ru.pulsar.jenkins.library.steps.DesignerToEdtFormatTransformation def call(JobConfiguration config) { ContextRegistry.registerDefaultContext(this) - def edtTransform = new EdtTransform(config) + def edtTransform = new DesignerToEdtFormatTransformation(config) edtTransform.run() } diff --git a/vars/edtToDesignerFormatTransformation.groovy b/vars/edtToDesignerFormatTransformation.groovy new file mode 100644 index 0000000..1ef1db5 --- /dev/null +++ b/vars/edtToDesignerFormatTransformation.groovy @@ -0,0 +1,10 @@ +import ru.pulsar.jenkins.library.configuration.JobConfiguration +import ru.pulsar.jenkins.library.ioc.ContextRegistry +import ru.pulsar.jenkins.library.steps.EdtToDesignerFormatTransformation + +def call(JobConfiguration config) { + ContextRegistry.registerDefaultContext(this) + + def edtBackTransform = new EdtToDesignerFormatTransformation(config) + edtBackTransform.run() +} diff --git a/vars/initFromFiles.groovy b/vars/initFromFiles.groovy new file mode 100644 index 0000000..ea0779b --- /dev/null +++ b/vars/initFromFiles.groovy @@ -0,0 +1,10 @@ +import ru.pulsar.jenkins.library.configuration.JobConfiguration +import ru.pulsar.jenkins.library.ioc.ContextRegistry +import ru.pulsar.jenkins.library.steps.InitFromFiles + +def call(JobConfiguration config) { + ContextRegistry.registerDefaultContext(this) + + def initFromFiles = new InitFromFiles(config) + initFromFiles.run() +} \ No newline at end of file diff --git a/vars/initFromStorage.groovy b/vars/initFromStorage.groovy index 3937c0c..3349381 100644 --- a/vars/initFromStorage.groovy +++ b/vars/initFromStorage.groovy @@ -1,22 +1,10 @@ import ru.pulsar.jenkins.library.configuration.JobConfiguration -import ru.pulsar.jenkins.library.utils.VersionParser +import ru.pulsar.jenkins.library.ioc.ContextRegistry +import ru.pulsar.jenkins.library.steps.InitFromStorage -def call(JobConfiguration jobConfiguration) { +def call(JobConfiguration config) { + ContextRegistry.registerDefaultContext(this) - def storageVersion = VersionParser.storage() - def storageVersionParameter = storageVersion == "" ? "" : "--storage-ver $storageVersion" - - withCredentials([ - usernamePassword( - credentialsId: jobConfiguration.secrets.storage, - passwordVariable: 'STORAGE_PSW', - usernameVariable: 'STORAGE_USR' - ), - string( - credentialsId: jobConfiguration.secrets.storagePath, - variable: 'STORAGE_PATH' - ) - ]) { - cmd "oscript_modules/bin/vrunner init-dev --storage --storage-name $STORAGE_PATH --storage-user $STORAGE_USR --storage-pwd $STORAGE_PSW $storageVersionParameter --ibconnection \"/F./build/ib\"" - } + def initFromStorage = new InitFromStorage(config) + initFromStorage.run() } \ No newline at end of file diff --git a/vars/installLocalDependencies.groovy b/vars/installLocalDependencies.groovy index 86c9580..02c13b4 100644 --- a/vars/installLocalDependencies.groovy +++ b/vars/installLocalDependencies.groovy @@ -1,3 +1,10 @@ +import ru.pulsar.jenkins.library.utils.Logger + def call() { + if (!fileExists("packagedef")) { + return + } + + Logger.println("Установка локальных зависимостей OneScript") cmd("opm install -l") } \ No newline at end of file diff --git a/vars/pipeline1C.groovy b/vars/pipeline1C.groovy index 8da44df..7f5222d 100644 --- a/vars/pipeline1C.groovy +++ b/vars/pipeline1C.groovy @@ -1,6 +1,7 @@ /* groovylint-disable NestedBlockDepth */ import groovy.transform.Field import ru.pulsar.jenkins.library.configuration.JobConfiguration +import ru.pulsar.jenkins.library.configuration.SourceFormat import java.util.concurrent.TimeUnit @@ -49,16 +50,33 @@ void call() { } stages { + stage('Трансформация из формата EDT') { + agent { + label 'edt' + } + when { + beforeAgent true + expression { config.stageFlags.needInfobase() && config.sourceFormat == SourceFormat.EDT } + } + steps { + edtToDesignerFormatTransformation config + } + } + stage('Создание ИБ') { steps { - printLocation() - - installLocalDependencies() - createDir('build/out') - // Создание базы загрузкой конфигурации из хранилища - initFromStorage config + script { + if (config.infobaseFromFiles()){ + // Создание базы загрузкой из файлов + initFromFiles config + } + else{ + // Создание базы загрузкой конфигурации из хранилища + initFromStorage config + } + } } } @@ -91,10 +109,10 @@ void call() { } when { beforeAgent true - expression { config.stageFlags.edtValidate } + expression { config.sourceFormat == SourceFormat.DESIGNER && config.stageFlags.edtValidate} } steps { - edtTransform config + designerToEdtFormatTransformation config } } } @@ -103,15 +121,28 @@ void call() { stage('Проверка качества') { parallel { stage('EDT контроль') { - agent { - label 'edt' - } when { beforeAgent true expression { config.stageFlags.edtValidate } } - steps { - edtValidate config + stages { + stage('Валидация EDT') { + agent { + label 'edt' + } + steps { + edtValidate config + } + } + + stage('Трансформация результатов') { + agent { + label 'oscript' + } + steps { + transform config + } + } } } @@ -158,19 +189,6 @@ void call() { } } - stage('Трансформация результатов') { - agent { - label 'oscript' - } - when { - beforeAgent true - expression { config.stageFlags.edtValidate } - } - steps { - transform config - } - } - stage('SonarQube') { agent { label 'sonar' diff --git a/vars/syntaxCheck.groovy b/vars/syntaxCheck.groovy index 048cb6f..636b837 100644 --- a/vars/syntaxCheck.groovy +++ b/vars/syntaxCheck.groovy @@ -2,6 +2,7 @@ import hudson.FilePath import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.utils.FileUtils +import ru.pulsar.jenkins.library.utils.VRunner def call(JobConfiguration config) { @@ -27,7 +28,8 @@ def call(JobConfiguration config) { String outPath = pathToJUnitReport.getParent() createDir(outPath) - String command = 'oscript_modules/bin/vrunner syntax-check --ibconnection "/F./build/ib"' + String vrunnerPath = VRunner.getVRunnerPath(); + String command = "$vrunnerPath syntax-check --ibconnection \"/F./build/ib\"" // Временно убрал передачу параметра. // См. https://github.com/vanessa-opensource/vanessa-runner/issues/361 @@ -49,8 +51,12 @@ def call(JobConfiguration config) { command += " --mode $checkModes" } + if (!options.exceptionFile.empty && fileExists(options.exceptionFile)) { + command += " --exception-file $options.exceptionFile" + } + // Запуск синтакс-проверки - cmd(command, true) + VRunner.exec(command, true) junit allowEmptyResults: true, testResults: FileUtils.getLocalPath(pathToJUnitReport)