1
0
mirror of https://github.com/firstBitMarksistskaya/jenkins-lib.git synced 2025-08-25 20:09:25 +02:00

Merge pull request #150 from firstBitMarksistskaya/develop

This commit is contained in:
Nikita Fedkin
2025-01-24 09:27:48 +01:00
committed by GitHub
23 changed files with 392 additions and 104 deletions

View File

@@ -46,12 +46,12 @@
1. Запуск юнит-тестов с помощью фреймворка YAXUnit с сохранением результатов в формате jUnit и Allure. 1. Запуск юнит-тестов с помощью фреймворка YAXUnit с сохранением результатов в формате jUnit и Allure.
1. Запуск синтаксического контроля средствами конфигуратора и сохранение результатов в виде отчета jUnit. 1. Запуск синтаксического контроля средствами конфигуратора и сохранение результатов в виде отчета jUnit.
1. Валидация проекта средствами EDT и трансформация отчета EDT в формат BSL LS с помощью `edt-ripper` или Generic Issue с помощью `stebi`. 1. Валидация проекта средствами EDT и трансформация отчета EDT в формат BSL LS с помощью `edt-ripper` или Generic Issue с помощью `stebi`.
1. Запуск статического анализа для SonarQube. 1. Запуск статического анализа для SonarQube.
1. Публикация результатов junit и Allure в интерфейс Jenkins. 1. Публикация результатов junit и Allure в интерфейс Jenkins.
1. Рассылка результатов сборки на почту и в Telegram. 1. Рассылка результатов сборки на почту и в Telegram.
1. Конфигурирование логгера запускаемых oscript-приложений. 1. Конфигурирование логгера запускаемых oscript-приложений.
1. Замер покрытия при выполнении тестов. 1. Замер покрытия при выполнении тестов.
1. Возможность сохранить информационную базу в виде артефакта сборки после выполнения шагов инициализации и\или после выполнения сценарных тестов.
## Подключение ## Подключение
@@ -168,6 +168,7 @@ pipeline1C()
* Если разработка ведется с использованием подсистемы [БСП "Обновление версии ИБ"](https://its.1c.ru/db/bsp315doc#content:4:1:issogl1_обновление_версии_иб), то в значение параметра `sonar.projectVersion=$configurationVersion` утилиты `sonar-scanner` можно передавать версию из созданного общего модуля. Для этого необходимо заполнить параметр (`sonarqube` -> `infoBaseUpdateModuleName`). Если параметр не заполнен, версия передается из корня конфигурации. * Если разработка ведется с использованием подсистемы [БСП "Обновление версии ИБ"](https://its.1c.ru/db/bsp315doc#content:4:1:issogl1_обновление_версии_иб), то в значение параметра `sonar.projectVersion=$configurationVersion` утилиты `sonar-scanner` можно передавать версию из созданного общего модуля. Для этого необходимо заполнить параметр (`sonarqube` -> `infoBaseUpdateModuleName`). Если параметр не заполнен, версия передается из корня конфигурации.
* По умолчанию шаг анализа не дожидается окончания фонового задания на сервере SonarQube и не анализирует результат прохождения Порога качества (`sonarqube` -> `waitForQualityGate`). * По умолчанию шаг анализа не дожидается окончания фонового задания на сервере SonarQube и не анализирует результат прохождения Порога качества (`sonarqube` -> `waitForQualityGate`).
* Если выполнялась валидация EDT, результаты валидации передаются утилите `sonar-scanner` как значение параметра `sonar.externalIssuesReportPaths` при использовании `stebi` или как значение параметра `sonar.bsl.languageserver.reportPaths` при использовании `edt-ripper`. * Если выполнялась валидация EDT, результаты валидации передаются утилите `sonar-scanner` как значение параметра `sonar.externalIssuesReportPaths` при использовании `stebi` или как значение параметра `sonar.bsl.languageserver.reportPaths` при использовании `edt-ripper`.
* Информационная база по умолчанию не сохраняется в виде артефакта сборки.
* Рассылка уведомлений: * Рассылка уведомлений:
* Электронная почта: * Электронная почта:
* Для отправки используется плагин [`email-ext`](https://plugins.jenkins.io/email-ext). Шаблоны сообщений конфигурируются в настройках плагина. * Для отправки используется плагин [`email-ext`](https://plugins.jenkins.io/email-ext). Шаблоны сообщений конфигурируются в настройках плагина.
@@ -259,8 +260,8 @@ pipeline1C()
* [Coverage41C](https://github.com/1c-syntax/Coverage41C), его необходимо установить на агент отдельно * [Coverage41C](https://github.com/1c-syntax/Coverage41C), его необходимо установить на агент отдельно
* EDT нужной версии или отдельные jar-файлы из его каталога установки, подробнее см. в [Coverage41C/README.md](https://github.com/1c-syntax/Coverage41C) * EDT нужной версии или отдельные jar-файлы из его каталога установки, подробнее см. в [Coverage41C/README.md](https://github.com/1c-syntax/Coverage41C)
* Если на агенте Coverage41C не включен в PATH, необходимо указать полный путь к нему в параметре `coverage41CPath` * Если на агенте Coverage41C не включен в PATH, необходимо указать полный путь к нему в параметре `coverage41CPath`
* Сбор замеров покрытия активируется для каждого стейджа отдельно с помощью установки параметра `"coverage": true` * Сбор замеров покрытия активируется для каждого этапа отдельно с помощью установки параметра `"coverage": true`
* поддерживаются `bdd` и `yaxunit`, для использования замеров на стейже `smoke` ожидается исправление vanessa-add в этом [PR](https://github.com/vanessa-opensource/add/pull/1153) * поддерживаются `bdd` и `yaxunit`, для использования замеров на этапе `smoke` ожидается исправление vanessa-add в этом [PR](https://github.com/vanessa-opensource/add/pull/1153)
* Чтобы замеры в `bdd`, `yaxunit`, `smoke` могли выполняться параллельно **на одном агенте**, необходимо указывать для них разные порты отладки в параметре `dbgsPort`. * Чтобы замеры в `bdd`, `yaxunit`, `smoke` могли выполняться параллельно **на одном агенте**, необходимо указывать для них разные порты отладки в параметре `dbgsPort`.
* Не забудьте настроить подключение клиентов тестирования к серверу отладки. * Не забудьте настроить подключение клиентов тестирования к серверу отладки.
@@ -312,3 +313,12 @@ jobConfiguration.json
* При изменении портов отладки в jobConfiguration.json не забывайте менять порты в настройках соответствующих шагов (и наоборот) * При изменении портов отладки в jobConfiguration.json не забывайте менять порты в настройках соответствующих шагов (и наоборот)
* Настоятельно рекомендуется использовать не "постоянные" агенты Jenkins, а контейнеры docker. При выполнении билдов в контейнерах можно использовать исключительно стандартный порт 1550. * Настоятельно рекомендуется использовать не "постоянные" агенты Jenkins, а контейнеры docker. При выполнении билдов в контейнерах можно использовать исключительно стандартный порт 1550.
## Сохранение ИБ в виде артефакта сборки
Параметры `initInfobase` -> `archiveInfobase` и `bdd` -> `archiveInfobase` отвечают за сохранение информационной базы в виде артефакта сборки после выполнения соответствующих этапов.
Можно управлять тем, при каких статусах сборки ИБ будет сохранена, см. `onAlways`, `onFailure`, `onUnstable`, `onSuccess`.
Имя файла формируется следующим образом:
* для шага `initInfoBase`: '1Cv8.1CD.zip'
* для шага `bdd`: '1Cv8.1CD.bdd.zip'

View File

@@ -36,7 +36,7 @@ val junitVersion = "5.11.0"
val spockVersion = "1.3-groovy-2.4" val spockVersion = "1.3-groovy-2.4"
val groovyVersion = "2.4.21" val groovyVersion = "2.4.21"
val slf4jVersion = "2.0.16" val slf4jVersion = "2.0.16"
val jsonschemaVersion = "4.36.0" val jsonschemaVersion = "4.37.0"
dependencies { dependencies {
implementation("org.codehaus.groovy", "groovy-all", groovyVersion) implementation("org.codehaus.groovy", "groovy-all", groovyVersion)

View File

@@ -45,12 +45,24 @@
"additionalInitializationSteps": [], "additionalInitializationSteps": [],
"templateDBPath": "", "templateDBPath": "",
"vrunnerSettings": "./tools/vrunner.json", "vrunnerSettings": "./tools/vrunner.json",
"archiveInfobase": {
"onAlways": false,
"onFailure": false,
"onUnstable": false,
"onSuccess": false
},
"extensions": [] "extensions": []
}, },
"bdd": { "bdd": {
"vrunnerSteps": [ "vrunnerSteps": [
"vanessa --settings ./tools/vrunner.json" "vanessa --settings ./tools/vrunner.json"
], ],
"archiveInfobase": {
"onAlways": false,
"onFailure": false,
"onUnstable": false,
"onSuccess": false
},
"coverage": false, "coverage": false,
"dbgsPort": 1550 "dbgsPort": 1550
}, },
@@ -64,7 +76,6 @@
}, },
"syntaxCheck": { "syntaxCheck": {
"groupErrorsByMetadata": true, "groupErrorsByMetadata": true,
"pathToJUnitReport": "./build/out/jUnit/syntax.xml",
"exceptionFile": "./tools/syntax-check-exception-file.txt", "exceptionFile": "./tools/syntax-check-exception-file.txt",
"checkModes": [ "checkModes": [
"-ThinClient", "-ThinClient",
@@ -79,7 +90,9 @@
"-CheckUseSynchronousCalls", "-CheckUseSynchronousCalls",
"-DistributiveModules" "-DistributiveModules"
], ],
"vrunnerSettings": "./tools/vrunner.json" "vrunnerSettings": "./tools/vrunner.json",
"publishToAllureReport": false,
"publishToJUnitReport": true
}, },
"smoke": { "smoke": {
"vrunnerSettings": "./tools/vrunner.json", "vrunnerSettings": "./tools/vrunner.json",

View File

@@ -1,6 +1,27 @@
{ {
"$schema" : "http://json-schema.org/draft-07/schema#", "$schema" : "http://json-schema.org/draft-07/schema#",
"definitions" : { "definitions" : {
"ArchiveInfobaseOptions" : {
"type" : "object",
"properties" : {
"onAlways" : {
"type" : "boolean",
"description" : "Сохранять всегда"
},
"onFailure" : {
"type" : "boolean",
"description" : "Сохранять при падении сборки"
},
"onSuccess" : {
"type" : "boolean",
"description" : "Сохранять при успешной сборке"
},
"onUnstable" : {
"type" : "boolean",
"description" : "Сохранять при нестабильной сборке"
}
}
},
"EmailExtConfiguration" : { "EmailExtConfiguration" : {
"type" : "object", "type" : "object",
"properties" : { "properties" : {
@@ -28,15 +49,22 @@
"bdd" : { "bdd" : {
"type" : "object", "type" : "object",
"properties" : { "properties" : {
"archiveInfobase" : {
"allOf" : [ {
"$ref" : "#/definitions/ArchiveInfobaseOptions"
}, {
"description" : "Настройки сохранения базы после выполнения всех шагов\n "
} ]
},
"coverage" : { "coverage" : {
"type" : "boolean", "type" : "boolean",
"description" : "Выполнять замер покрытия", "description" : "Выполнять замер покрытия",
"default" : "false" "default" : false
}, },
"dbgsPort" : { "dbgsPort" : {
"type" : "integer", "type" : "integer",
"description" : "Порт, на котором будет запущен сервер отладки для замера покрытия", "description" : "Порт, на котором будет запущен сервер отладки для замера покрытия",
"default" : "1550" "default" : 1550
}, },
"vrunnerSteps" : { "vrunnerSteps" : {
"description" : "Шаги, запускаемые через vrunner.\n В каждой строке передается отдельная команда \n vrunner и ее аргументы (например, \"vanessa --settings ./tools/vrunner.json\").\n По умолчанию содержит одну команду \"vanessa --settings ./tools/vrunner.json\".\n ", "description" : "Шаги, запускаемые через vrunner.\n В каждой строке передается отдельная команда \n vrunner и ее аргументы (например, \"vanessa --settings ./tools/vrunner.json\").\n По умолчанию содержит одну команду \"vanessa --settings ./tools/vrunner.json\".\n ",
@@ -80,6 +108,13 @@
"type" : "string" "type" : "string"
} }
}, },
"archiveInfobase" : {
"allOf" : [ {
"$ref" : "#/definitions/ArchiveInfobaseOptions"
}, {
"description" : "Настройки сохранения базы после выполнения всех шагов\n "
} ]
},
"extensions" : { "extensions" : {
"description" : "Массив расширений для загрузки в конфигурацию.", "description" : "Массив расширений для загрузки в конфигурацию.",
"type" : "array", "type" : "array",
@@ -250,12 +285,12 @@
"coverage" : { "coverage" : {
"type" : "boolean", "type" : "boolean",
"description" : "Выполнять замер покрытия", "description" : "Выполнять замер покрытия",
"default" : "false" "default" : false
}, },
"dbgsPort" : { "dbgsPort" : {
"type" : "integer", "type" : "integer",
"description" : "Порт, на котором будет запущен сервер отладки для замера покрытия", "description" : "Порт, на котором будет запущен сервер отладки для замера покрытия",
"default" : "1550" "default" : 1550
}, },
"publishToAllureReport" : { "publishToAllureReport" : {
"type" : "boolean", "type" : "boolean",
@@ -378,9 +413,15 @@
"type" : "boolean", "type" : "boolean",
"description" : "Группировать выявленные ошибки по объектам метаданных.\n По умолчанию включено.\n " "description" : "Группировать выявленные ошибки по объектам метаданных.\n По умолчанию включено.\n "
}, },
"pathToJUnitReport" : { "publishToAllureReport" : {
"type" : "string", "type" : "boolean",
"description" : "Путь к файлу отчета jUnit\n По умолчанию содержит значение \"./build/out/jUnit/syntax.xml\"\n " "description" : "Выполнять публикацию результатов в отчет Allure.\n По умолчанию выключено.\n ",
"default" : false
},
"publishToJUnitReport" : {
"type" : "boolean",
"description" : "Выполнять публикацию результатов в отчет JUnit.\n По умолчанию включено.\n ",
"default" : true
}, },
"vrunnerSettings" : { "vrunnerSettings" : {
"type" : "string", "type" : "string",
@@ -469,12 +510,12 @@
"coverage" : { "coverage" : {
"type" : "boolean", "type" : "boolean",
"description" : "Выполнять замер покрытия", "description" : "Выполнять замер покрытия",
"default" : "false" "default" : false
}, },
"dbgsPort" : { "dbgsPort" : {
"type" : "integer", "type" : "integer",
"description" : "Порт, на котором будет запущен сервер отладки для замера покрытия", "description" : "Порт, на котором будет запущен сервер отладки для замера покрытия",
"default" : "1550" "default" : 1550
}, },
"publishToAllureReport" : { "publishToAllureReport" : {
"type" : "boolean", "type" : "boolean",

View File

@@ -33,6 +33,7 @@ public class JobConfigurationSchemaGenerator {
writer.write(jsonSchema.toPrettyString()); writer.write(jsonSchema.toPrettyString());
System.out.println(jsonSchema.toPrettyString()); System.out.println(jsonSchema.toPrettyString());
} catch (IOException e) { } catch (IOException e) {
//noinspection CallToPrintStackTrace
e.printStackTrace(); e.printStackTrace();
} }
} }

View File

@@ -10,6 +10,7 @@ import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper
import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.configuration.JobConfiguration
import ru.pulsar.jenkins.library.configuration.StepCoverageOptions import ru.pulsar.jenkins.library.configuration.StepCoverageOptions
import ru.pulsar.jenkins.library.steps.Coverable import ru.pulsar.jenkins.library.steps.Coverable
import sp.sd.fileoperations.FileOperation
interface IStepExecutor { interface IStepExecutor {
@@ -34,6 +35,10 @@ interface IStepExecutor {
boolean fileExists(String file) boolean fileExists(String file)
void fileOperations(List<FileOperation> fileOperations)
void fileDeleteOperation(String includes)
void echo(message) void echo(message)
def cmd(String script, boolean returnStatus, boolean returnStdout) def cmd(String script, boolean returnStatus, boolean returnStdout)
@@ -89,6 +94,8 @@ interface IStepExecutor {
@SuppressWarnings('unused') @SuppressWarnings('unused')
def zip(String dir, String zipFile, String glob) def zip(String dir, String zipFile, String glob)
def zip(String dir, String zipFile, String glob, boolean archive)
def unzip(String dir, String zipFile) def unzip(String dir, String zipFile)
@SuppressWarnings('unused') @SuppressWarnings('unused')
@@ -120,4 +127,5 @@ interface IStepExecutor {
def brokenTestsSuspects() def brokenTestsSuspects()
RunWrapper currentBuild() RunWrapper currentBuild()
} }

View File

@@ -11,6 +11,7 @@ import ru.pulsar.jenkins.library.configuration.JobConfiguration
import ru.pulsar.jenkins.library.configuration.StepCoverageOptions import ru.pulsar.jenkins.library.configuration.StepCoverageOptions
import ru.pulsar.jenkins.library.steps.Coverable import ru.pulsar.jenkins.library.steps.Coverable
import ru.yandex.qatools.allure.jenkins.config.ResultsConfig import ru.yandex.qatools.allure.jenkins.config.ResultsConfig
import sp.sd.fileoperations.FileOperation
class StepExecutor implements IStepExecutor { class StepExecutor implements IStepExecutor {
@@ -55,6 +56,16 @@ class StepExecutor implements IStepExecutor {
steps.fileExists file steps.fileExists file
} }
@Override
void fileOperations(List<FileOperation> fileOperations) {
steps.fileOperations fileOperations
}
@Override
void fileDeleteOperation(String includes) {
steps.fileDeleteOperation includes: includes, excludes: '', useDefaultExcludes: true
}
@Override @Override
FileWrapper[] findFiles(String glob, String excludes = '') { FileWrapper[] findFiles(String glob, String excludes = '') {
steps.findFiles glob: glob, excludes: excludes steps.findFiles glob: glob, excludes: excludes
@@ -196,6 +207,11 @@ class StepExecutor implements IStepExecutor {
steps.zip dir: dir, zipFile: zipFile, glob: glob, overwrite: true steps.zip dir: dir, zipFile: zipFile, glob: glob, overwrite: true
} }
@Override
def zip(String dir, String zipFile, String glob = '', boolean archive) {
steps.zip dir: dir, zipFile: zipFile, glob: glob, overwrite: true, archive: archive
}
@Override @Override
def unzip(String dir, String zipFile, quiet = true) { def unzip(String dir, String zipFile, quiet = true) {
steps.unzip dir: dir, zipFile: zipFile, quiet: quiet steps.unzip dir: dir, zipFile: zipFile, quiet: quiet

View File

@@ -0,0 +1,31 @@
package ru.pulsar.jenkins.library.configuration
import com.cloudbees.groovy.cps.NonCPS
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonPropertyDescription
@JsonIgnoreProperties(ignoreUnknown = true)
class ArchiveInfobaseOptions implements Serializable {
@JsonPropertyDescription("Сохранять всегда")
Boolean onAlways = false
@JsonPropertyDescription("Сохранять при успешной сборке")
Boolean onSuccess = false
@JsonPropertyDescription("Сохранять при падении сборки")
Boolean onFailure = false
@JsonPropertyDescription("Сохранять при нестабильной сборке")
Boolean onUnstable = false
@Override
@NonCPS
String toString() {
return "ArchiveInfobaseOptions{" +
"onAlways=" + onAlways +
", onSuccess=" + onSuccess +
", onFailure=" + onFailure +
", onUnstable=" + onUnstable +
'}';
}
}

View File

@@ -16,11 +16,16 @@ class BddOptions extends StepCoverageOptions implements Serializable {
'vanessa --settings ./tools/vrunner.json' 'vanessa --settings ./tools/vrunner.json'
] ]
@JsonPropertyDescription("""Настройки сохранения базы после выполнения всех шагов
""")
ArchiveInfobaseOptions archiveInfobase
@Override @Override
@NonCPS @NonCPS
String toString() { String toString() {
return "BddOptions{" + return "BddOptions{" +
"vrunnerSteps=" + vrunnerSteps + "vrunnerSteps=" + vrunnerSteps +
"archiveInfobase=" + archiveInfobase +
"coverage=" + coverage + "coverage=" + coverage +
"dbgsPort=" + dbgsPort + "dbgsPort=" + dbgsPort +
'}' '}'

View File

@@ -69,6 +69,7 @@ class ConfigurationReader implements Serializable {
"yaxunitOptions", "yaxunitOptions",
"syntaxCheckOptions", "syntaxCheckOptions",
"resultsTransformOptions", "resultsTransformOptions",
"archiveInfobase",
"notificationsOptions", "notificationsOptions",
"emailNotificationOptions", "emailNotificationOptions",
"alwaysEmailOptions", "alwaysEmailOptions",

View File

@@ -40,6 +40,10 @@ class InitInfoBaseOptions implements Serializable {
""") """)
String templateDBPath String templateDBPath
@JsonPropertyDescription("""Настройки сохранения базы после выполнения всех шагов
""")
ArchiveInfobaseOptions archiveInfobase
@JsonPropertyDescription("Массив расширений для загрузки в конфигурацию.") @JsonPropertyDescription("Массив расширений для загрузки в конфигурацию.")
Extension[] extensions Extension[] extensions
@@ -80,6 +84,7 @@ class InitInfoBaseOptions implements Serializable {
", vrunnerSettings=" + vrunnerSettings + ", vrunnerSettings=" + vrunnerSettings +
", templateDBPath=" + templateDBPath + ", templateDBPath=" + templateDBPath +
", additionalInitializationSteps=" + additionalInitializationSteps + ", additionalInitializationSteps=" + additionalInitializationSteps +
", archiveInfobase=" + archiveInfobase +
", extensions=" + extensions + ", extensions=" + extensions +
'}' '}'
} }

View File

@@ -2,16 +2,13 @@ package ru.pulsar.jenkins.library.configuration
import com.cloudbees.groovy.cps.NonCPS import com.cloudbees.groovy.cps.NonCPS
import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonPropertyDescription import com.fasterxml.jackson.annotation.JsonPropertyDescription
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
class SyntaxCheckOptions implements Serializable { class SyntaxCheckOptions implements Serializable {
@JsonPropertyDescription("""Путь к файлу отчета jUnit
По умолчанию содержит значение "./build/out/jUnit/syntax.xml"
""")
String pathToJUnitReport = "./build/out/jUnit/syntax.xml"
@JsonPropertyDescription("""Группировать выявленные ошибки по объектам метаданных. @JsonPropertyDescription("""Группировать выявленные ошибки по объектам метаданных.
По умолчанию включено. По умолчанию включено.
""") """)
@@ -31,14 +28,27 @@ class SyntaxCheckOptions implements Serializable {
""") """)
String vrunnerSettings = "./tools/vrunner.json" String vrunnerSettings = "./tools/vrunner.json"
@JsonPropertyDescription("""Выполнять публикацию результатов в отчет Allure.
По умолчанию выключено.
""")
@JsonProperty(defaultValue = "false")
boolean publishToAllureReport = false
@JsonPropertyDescription("""Выполнять публикацию результатов в отчет JUnit.
По умолчанию включено.
""")
@JsonProperty(defaultValue = "true")
boolean publishToJUnitReport = true
@Override @Override
@NonCPS @NonCPS
String toString() { String toString() {
return "SyntaxCheckOptions{" + return "SyntaxCheckOptions{" +
"pathToJUnitReport='" + pathToJUnitReport + '\'' +
", groupErrorsByMetadata=" + groupErrorsByMetadata + ", groupErrorsByMetadata=" + groupErrorsByMetadata +
", checkModes=" + checkModes + ", checkModes=" + checkModes +
", vrunnerSettings=" + vrunnerSettings + ", vrunnerSettings=" + vrunnerSettings +
'}'; ", publishToAllureReport=" + publishToAllureReport +
", publishToJUnitReport=" + publishToJUnitReport +
'}'
} }
} }

View File

@@ -17,7 +17,7 @@ class LoadExtensions implements Serializable {
private Extension[] extensionsFiltered private Extension[] extensionsFiltered
LoadExtensions(JobConfiguration config, String stageName = "") { LoadExtensions(JobConfiguration config, String stageName) {
this.config = config this.config = config
this.stageName = stageName this.stageName = stageName
} }
@@ -33,13 +33,19 @@ class LoadExtensions implements Serializable {
def extensions = this.config.initInfoBaseOptions.extensions def extensions = this.config.initInfoBaseOptions.extensions
if (this.stageName) { // NB: расширения, подключаемые на этапе initInfoBase, остаются подключенными на всех остальных этапах
this.extensionsFiltered = extensions.findAll { extension -> if (this.stageName == "initInfoBase") {
extension.stages.contains(this.stageName) // подключаются все расширения, у которых явно указано подключение на текущем этапе
} // и те расширения, в которых этапы подключения не указаны вообще
} this.extensionsFiltered = extensions.findAll({ extension ->
else { extension.stages.contains(this.stageName) || extension.stages.length == 0
this.extensionsFiltered = extensions.findAll { extension -> extension.stages.length == 0 || extension.stages.contains("initInfoBase") } })
} else {
// на остальных этапах подключаются расширения, которые не были подключены на этапе initInfoBase
// и у которых явно указано подключение на текущем этапе
this.extensionsFiltered = extensions.findAll({ extension ->
!extension.stages.contains("initInfoBase") && extension.stages.contains(this.stageName)
})
} }
def env = steps.env() def env = steps.env()

View File

@@ -39,6 +39,9 @@ class PublishAllure implements Serializable {
if (config.stageFlags.smoke && config.smokeTestOptions.publishToAllureReport) { if (config.stageFlags.smoke && config.smokeTestOptions.publishToAllureReport) {
safeUnstash(SmokeTest.ALLURE_STASH) safeUnstash(SmokeTest.ALLURE_STASH)
} }
if (config.stageFlags.syntaxCheck && config.syntaxCheckOptions.publishToAllureReport) {
safeUnstash(SyntaxCheck.ALLURE_STASH)
}
def env = steps.env() def env = steps.env()

View File

@@ -0,0 +1,96 @@
package ru.pulsar.jenkins.library.steps
import hudson.FilePath
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.FileUtils
import ru.pulsar.jenkins.library.utils.Logger
import ru.pulsar.jenkins.library.utils.VRunner
class SyntaxCheck {
public static final String ALLURE_STASH = 'syntax-check-allure'
private final JobConfiguration config
SyntaxCheck(JobConfiguration config) {
this.config = config
}
def run() {
IStepExecutor steps = ContextRegistry.getContext().getStepExecutor()
Logger.printLocation()
if (!config.stageFlags.syntaxCheck) {
Logger.println("Syntax-check step is disabled")
return
}
def env = steps.env()
def options = config.syntaxCheckOptions
List<String> logosConfig = ["LOGOS_CONFIG=$config.logosConfig"]
steps.withEnv(logosConfig) {
steps.installLocalDependencies()
String junitReport = "build/out/jUnit/syntax-check/syntax-check.xml"
FilePath pathToJUnitReport = FileUtils.getFilePath("$env.WORKSPACE/$junitReport")
String junitReportDir = FileUtils.getLocalPath(pathToJUnitReport.getParent())
String allureReport = "build/out/allure/syntax-check/allure.xml"
FilePath pathToAllureReport = FileUtils.getFilePath("$env.WORKSPACE/$allureReport")
String allureReportDir = FileUtils.getLocalPath(pathToAllureReport.getParent())
String vrunnerPath = VRunner.getVRunnerPath()
String command = "$vrunnerPath syntax-check --ibconnection \"/F./build/ib\""
// Временно убрал передачу параметра.
// См. https://github.com/vanessa-opensource/vanessa-runner/issues/361
// command += " --workspace $env.WORKSPACE"
if (options.groupErrorsByMetadata) {
command += ' --groupbymetadata'
}
if (options.publishToJUnitReport) {
steps.createDir(junitReportDir)
command += " --junitpath $pathToJUnitReport"
}
if (options.publishToAllureReport) {
steps.createDir(allureReportDir)
command += " --allure-results2 $allureReportDir"
}
FilePath vrunnerSettings = FileUtils.getFilePath("$env.WORKSPACE/$options.vrunnerSettings")
if (vrunnerSettings.exists()) {
command += " --settings $vrunnerSettings"
}
if (!options.exceptionFile.empty && steps.fileExists(options.exceptionFile)) {
command += " --exception-file $options.exceptionFile"
}
if (options.checkModes.length > 0) {
def checkModes = options.checkModes.join(" ")
command += " --mode $checkModes"
}
// Запуск синтакс-проверки
VRunner.exec(command, true)
if (options.publishToAllureReport) {
steps.stash(ALLURE_STASH, "$allureReportDir/**", true)
steps.archiveArtifacts("$allureReportDir/**")
}
if (options.publishToJUnitReport) {
steps.junit("$junitReportDir/*.xml", true)
steps.archiveArtifacts("$junitReportDir/**")
}
}
}
}

View File

@@ -82,7 +82,7 @@ class Yaxunit implements Serializable, Coverable {
} }
if (options.publishToAllureReport) { if (options.publishToAllureReport) {
String allureReport = "./build/out/allure/yaxunit/junit.xml" String allureReport = "./build/out/allure/yaxunit/allure.xml"
FilePath pathToAllureReport = FileUtils.getFilePath("$env.WORKSPACE/$allureReport") FilePath pathToAllureReport = FileUtils.getFilePath("$env.WORKSPACE/$allureReport")
String allureReportDir = FileUtils.getLocalPath(pathToAllureReport.getParent()) String allureReportDir = FileUtils.getLocalPath(pathToAllureReport.getParent())

View File

@@ -0,0 +1,68 @@
package ru.pulsar.jenkins.library.steps
import hudson.model.Result
import ru.pulsar.jenkins.library.IStepExecutor
import ru.pulsar.jenkins.library.configuration.ArchiveInfobaseOptions
import ru.pulsar.jenkins.library.configuration.JobConfiguration
import ru.pulsar.jenkins.library.ioc.ContextRegistry
import ru.pulsar.jenkins.library.utils.Logger
class ZipInfobase implements Serializable {
private final JobConfiguration config
private final String stage
ZipInfobase(JobConfiguration config, String stage) {
this.config = config
this.stage = stage
}
def run() {
IStepExecutor steps = ContextRegistry.getContext().getStepExecutor()
Logger.printLocation()
def currentBuild = steps.currentBuild()
def currentResult = Result.fromString(currentBuild.getCurrentResult())
def archiveInfobaseOptions = getArchiveInfobaseOptionsForStage(config, stage)
def archiveName
if (stage == 'initInfoBase') {
archiveName = "1Cv8.1CD.zip"
} else {
archiveName = "1Cv8.1CD.${stage}.zip"
}
// опция отвечает только за то, будет ли файл сохранен в виде артефакта
def archiveInfobase = false
if (archiveInfobaseOptions.onAlways
|| (archiveInfobaseOptions.onFailure && (currentResult == Result.FAILURE || currentResult == Result.ABORTED))
|| (archiveInfobaseOptions.onUnstable && currentResult == Result.UNSTABLE)
|| (archiveInfobaseOptions.onSuccess && currentResult == Result.SUCCESS)) {
archiveInfobase = true
}
if (steps.fileExists(archiveName)) {
steps.fileOperations([steps.fileDeleteOperation(archiveName)])
}
steps.zip('build/ib', archiveName, '1Cv8.1CD', archiveInfobase)
steps.stash(archiveName, archiveName, false)
}
private static ArchiveInfobaseOptions getArchiveInfobaseOptionsForStage(JobConfiguration config, String stageName) {
def defaultOptions = new ArchiveInfobaseOptions()
if (!stageName) {
return defaultOptions
}
try {
return config."${stageName}Options".archiveInfobase
} catch(MissingPropertyException | NullPointerException e) {
Logger.println("Ошибка при получении настроек архивации для этапа ${stageName}: ${e.message}")
Logger.println(e.toString())
return defaultOptions
}
}
}

View File

@@ -2,7 +2,6 @@ package ru.pulsar.jenkins.library.configuration;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import ru.pulsar.jenkins.library.configuration.sonarqube.GenericIssueFormat; import ru.pulsar.jenkins.library.configuration.sonarqube.GenericIssueFormat;
import ru.pulsar.jenkins.library.utils.TestUtils; import ru.pulsar.jenkins.library.utils.TestUtils;
@@ -66,6 +65,7 @@ class ConfigurationReaderTest {
assertThat(jobConfiguration.getYaxunitOptions().getDbgsPort()).isEqualTo(1550); assertThat(jobConfiguration.getYaxunitOptions().getDbgsPort()).isEqualTo(1550);
assertThat(jobConfiguration.getInitInfoBaseOptions().getRunMigration()).isFalse(); assertThat(jobConfiguration.getInitInfoBaseOptions().getRunMigration()).isFalse();
assertThat(jobConfiguration.getInitInfoBaseOptions().getArchiveInfobase().getOnAlways()).isTrue();
assertThat(jobConfiguration.getInitInfoBaseOptions().getAdditionalInitializationSteps()).contains("vanessa --settings ./tools/vrunner.first.json"); assertThat(jobConfiguration.getInitInfoBaseOptions().getAdditionalInitializationSteps()).contains("vanessa --settings ./tools/vrunner.first.json");
assertThat(jobConfiguration.getBddOptions().getVrunnerSteps()).contains("vanessa --settings ./tools/vrunner.json"); assertThat(jobConfiguration.getBddOptions().getVrunnerSteps()).contains("vanessa --settings ./tools/vrunner.json");

View File

@@ -35,7 +35,7 @@ class LoadExtensionsTest {
.thenReturn(new FilePath(new File("/"))); .thenReturn(new FilePath(new File("/")));
// given // given
// файл содержит 4 расширения для разных стейджей // файл содержит 4 расширения для разных этапов
String config = IOUtils.resourceToString( String config = IOUtils.resourceToString(
"jobConfiguration.json", "jobConfiguration.json",
StandardCharsets.UTF_8, StandardCharsets.UTF_8,
@@ -44,11 +44,11 @@ class LoadExtensionsTest {
JobConfiguration jobConfiguration = ConfigurationReader.create(config); JobConfiguration jobConfiguration = ConfigurationReader.create(config);
// when // when
LoadExtensions loadExtensions = new LoadExtensions(jobConfiguration); LoadExtensions loadExtensionsInit = new LoadExtensions(jobConfiguration, "initInfoBase");
loadExtensions.run(); loadExtensionsInit.run();
// then // then
InitInfoBaseOptions.Extension[] extensions = loadExtensions.getExtensionsFiltered(); InitInfoBaseOptions.Extension[] extensions = loadExtensionsInit.getExtensionsFiltered();
assertThat(extensions.length).isEqualTo(2); assertThat(extensions.length).isEqualTo(2);
assertThat(extensions[0].getName()).isEqualTo("mods"); assertThat(extensions[0].getName()).isEqualTo("mods");
assertThat(extensions[1].getName()).isEqualTo("mods2"); assertThat(extensions[1].getName()).isEqualTo("mods2");

View File

@@ -48,7 +48,10 @@
"initInfoBase" "initInfoBase"
] ]
} }
] ],
"archiveInfobase": {
"onAlways": true
}
}, },
"sonarqube": { "sonarqube": {
"sonarQubeInstallation": "qa", "sonarQubeInstallation": "qa",

View File

@@ -144,7 +144,7 @@ void call() {
timeout(time: config.timeoutOptions.zipInfoBase, unit: TimeUnit.MINUTES) { timeout(time: config.timeoutOptions.zipInfoBase, unit: TimeUnit.MINUTES) {
printLocation() printLocation()
zipInfobase() zipInfobase config, 'initInfoBase'
} }
} }
} }
@@ -237,6 +237,16 @@ void call() {
} }
} }
} }
stage('Архивация ИБ') {
steps {
timeout(time: config.timeoutOptions.zipInfoBase, unit: TimeUnit.MINUTES) {
printLocation()
zipInfobase config, 'bdd'
}
}
}
} }
} }
@@ -248,12 +258,22 @@ void call() {
beforeAgent true beforeAgent true
expression { config.stageFlags.syntaxCheck } expression { config.stageFlags.syntaxCheck }
} }
stages {
stage('Распаковка ИБ') {
steps {
unzipInfobase()
}
}
stage('Выполнение синтаксического контроля') {
steps { steps {
timeout(time: config.timeoutOptions.syntaxCheck, unit: TimeUnit.MINUTES) { timeout(time: config.timeoutOptions.syntaxCheck, unit: TimeUnit.MINUTES) {
syntaxCheck config syntaxCheck config
} }
} }
} }
}
}
stage('Дымовые тесты') { stage('Дымовые тесты') {
agent { agent {

View File

@@ -1,64 +1,12 @@
import hudson.FilePath
import ru.pulsar.jenkins.library.configuration.JobConfiguration import ru.pulsar.jenkins.library.configuration.JobConfiguration
import ru.pulsar.jenkins.library.ioc.ContextRegistry import ru.pulsar.jenkins.library.ioc.ContextRegistry
import ru.pulsar.jenkins.library.utils.FileUtils import ru.pulsar.jenkins.library.steps.SyntaxCheck
import ru.pulsar.jenkins.library.utils.VRunner
def call(JobConfiguration config) { def call(JobConfiguration config) {
ContextRegistry.registerDefaultContext(this) ContextRegistry.registerDefaultContext(this)
// TODO: Вынести в отдельный класс по аналогии с SonarScanner def syntaxCheck = new SyntaxCheck(config)
syntaxCheck.run()
printLocation()
if (!config.stageFlags.syntaxCheck) {
echo("Syntax-check step is disabled")
return
}
def options = config.syntaxCheckOptions
installLocalDependencies()
unzipInfobase()
FilePath pathToJUnitReport = FileUtils.getFilePath("$env.WORKSPACE/$options.pathToJUnitReport")
String outPath = pathToJUnitReport.getParent()
createDir(outPath)
String vrunnerPath = VRunner.getVRunnerPath();
String command = "$vrunnerPath syntax-check --ibconnection \"/F./build/ib\""
// Временно убрал передачу параметра.
// См. https://github.com/vanessa-opensource/vanessa-runner/issues/361
// command += " --workspace $env.WORKSPACE"
if (options.groupErrorsByMetadata) {
command += ' --groupbymetadata'
}
command += " --junitpath $pathToJUnitReport";
FilePath vrunnerSettings = FileUtils.getFilePath("$env.WORKSPACE/$options.vrunnerSettings")
if (vrunnerSettings.exists()) {
command += " --settings $vrunnerSettings";
}
if (!options.exceptionFile.empty && fileExists(options.exceptionFile)) {
command += " --exception-file $options.exceptionFile"
}
if (options.checkModes.length > 0) {
def checkModes = options.checkModes.join(" ")
command += " --mode $checkModes"
}
// Запуск синтакс-проверки
VRunner.exec(command, true)
junit allowEmptyResults: true, testResults: FileUtils.getLocalPath(pathToJUnitReport)
archiveArtifacts FileUtils.getLocalPath(pathToJUnitReport)
} }

View File

@@ -1,7 +1,10 @@
def call() { import ru.pulsar.jenkins.library.configuration.JobConfiguration
if (fileExists('1Cv8.1CD.zip')) { import ru.pulsar.jenkins.library.ioc.ContextRegistry
fileOperations([fileDeleteOperation(includes: '1Cv8.1CD.zip')]) import ru.pulsar.jenkins.library.steps.ZipInfobase
}
zip dir: 'build/ib', glob: '1Cv8.1CD', zipFile: '1Cv8.1CD.zip' def call(JobConfiguration config, String stageName) {
stash name: "1Cv8.1CD.zip", includes: "1Cv8.1CD.zip", allowEmpty: false ContextRegistry.registerDefaultContext(this)
def zipInfobase = new ZipInfobase(config, stageName)
zipInfobase.run()
} }