mirror of
https://github.com/firstBitMarksistskaya/jenkins-lib.git
synced 2024-12-11 11:19:08 +02:00
Merge branch 'develop'
This commit is contained in:
commit
0829836d61
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,5 +1,10 @@
|
||||
.idea/
|
||||
.gradle/
|
||||
build/
|
||||
bin/
|
||||
lib/
|
||||
|
||||
*.iml
|
||||
.classpath
|
||||
.project
|
||||
.settings/
|
||||
|
54
README.md
54
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:
|
||||
* По умолчанию из результатов анализа исключаются замечания, сработавшие на модулях с включенным запретом редактирования (желтый куб с замком)
|
||||
* По умолчанию из результатов анализа исключаются замечания, сработавшие на модулях с включенным запретом редактирования (желтый куб с замком) (параметры `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`.
|
||||
|
@ -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",
|
||||
|
@ -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 "
|
||||
|
@ -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<String> strings, Closure body)
|
||||
|
||||
def archiveArtifacts(String path)
|
||||
|
@ -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<String> strings, Closure body) {
|
||||
steps.withEnv(strings) {
|
||||
|
@ -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 <T extends Object> void mergeObjects(T baseObject, T objectToMerge, Set<String> 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 ->
|
||||
|
@ -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
|
||||
|
||||
}
|
@ -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 +
|
||||
'}';
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
package ru.pulsar.jenkins.library.configuration
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
|
||||
enum SourceFormat {
|
||||
@JsonProperty("edt")
|
||||
EDT,
|
||||
|
||||
@JsonProperty("designer")
|
||||
DESIGNER
|
||||
|
||||
}
|
@ -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".
|
||||
""")
|
||||
|
@ -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\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
49
src/ru/pulsar/jenkins/library/steps/InitFromFiles.groovy
Normal file
49
src/ru/pulsar/jenkins/library/steps/InitFromFiles.groovy
Normal file
@ -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)
|
||||
}
|
||||
}
|
74
src/ru/pulsar/jenkins/library/steps/InitFromStorage.groovy
Normal file
74
src/ru/pulsar/jenkins/library/steps/InitFromStorage.groovy
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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<String> 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\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
}
|
||||
|
6
src/ru/pulsar/jenkins/library/utils/Constants.groovy
Normal file
6
src/ru/pulsar/jenkins/library/utils/Constants.groovy
Normal file
@ -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"
|
||||
}
|
||||
|
30
src/ru/pulsar/jenkins/library/utils/VRunner.groovy
Normal file
30
src/ru/pulsar/jenkins/library/utils/VRunner.groovy
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -10,18 +10,26 @@ class VersionParser implements Serializable {
|
||||
final static VERSION_REGEXP = ~/(?i)<version>(.*)<\/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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
{
|
||||
"v8version": "8.3.12.1500"
|
||||
"v8version": "8.3.12.1500",
|
||||
"initInfobase": {
|
||||
"initMethod": "fromSource"
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
10
vars/edtToDesignerFormatTransformation.groovy
Normal file
10
vars/edtToDesignerFormatTransformation.groovy
Normal file
@ -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()
|
||||
}
|
10
vars/initFromFiles.groovy
Normal file
10
vars/initFromFiles.groovy
Normal file
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -1,3 +1,10 @@
|
||||
import ru.pulsar.jenkins.library.utils.Logger
|
||||
|
||||
def call() {
|
||||
if (!fileExists("packagedef")) {
|
||||
return
|
||||
}
|
||||
|
||||
Logger.println("Установка локальных зависимостей OneScript")
|
||||
cmd("opm install -l")
|
||||
}
|
@ -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'
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user