1
0

Merge pull request #19 from kuzja086/FromEDTTransform

This commit is contained in:
Nikita Fedkin
2021-11-03 20:46:56 +03:00
committed by GitHub
22 changed files with 308 additions and 28 deletions

2
.gitignore vendored
View File

@@ -1,5 +1,7 @@
.idea/
.gradle/
build/
bin/
lib/
*.iml

View File

@@ -2,6 +2,8 @@
"$schema": "schema.json",
"v8version": "8.3",
"srcDir": "src/cf",
"sourceFormat": "designer",
"defaultBranch": "main",
"secrets": {
"storagePath": "UNKNOWN_ID",
"storage": "UNKNOWN_ID"
@@ -15,6 +17,7 @@
"smoke": false
},
"initInfobase": {
"initMethod": "fromStorage",
"runMigration": true,
"additionalInitializationSteps": []
},

View File

@@ -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" : "Запустить миграцию ИБ"

View File

@@ -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 ->

View File

@@ -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
}

View File

@@ -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 +
'}';
}

View File

@@ -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)
}
}

View File

@@ -0,0 +1,12 @@
package ru.pulsar.jenkins.library.configuration
import com.fasterxml.jackson.annotation.JsonProperty
enum SourceFormat {
@JsonProperty("edt")
EDT,
@JsonProperty("designer")
DESIGNER
}

View File

@@ -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
}

View File

@@ -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.createDir(workspaceDir)
steps.createDir(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)
}
}

View 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
@@ -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;
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 {
projectList = "--project-list '$config.srcDir'"
}
def resultFile = "$env.WORKSPACE/$RESULT_FILE"
steps.createDir(new File(resultFile).getParent())
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)
}

View 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\""
steps.cmd(initCommand)
}
}

View 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"
}

View 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"
}

View File

@@ -17,6 +17,14 @@ class VersionParser implements Serializable {
return version(configurationText, VERSION_REGEXP)
}
static String edt(rootFile = 'src/Configuration/Configuration.mdo') {
IStepExecutor steps = ContextRegistry.getContext().getStepExecutor()
def configurationText = steps.readFile(rootFile, 'UTF-8');
return version(configurationText, VERSION_REGEXP)
}
static String storage(versionFile = 'src/cf/VERSION') {
IStepExecutor steps = ContextRegistry.getContext().getStepExecutor()

View File

@@ -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)
}
}

View File

@@ -1,3 +1,6 @@
{
"v8version": "8.3.12.1500"
"v8version": "8.3.12.1500",
"initInfobase": {
"initMethod": "fromSource"
}
}

View File

@@ -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()
}

View 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
View 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()
}

View File

@@ -4,6 +4,10 @@ import ru.pulsar.jenkins.library.utils.VersionParser
def call(JobConfiguration jobConfiguration) {
printLocation()
installLocalDependencies();
def storageVersion = VersionParser.storage()
def storageVersionParameter = storageVersion == "" ? "" : "--storage-ver $storageVersion"

View File

@@ -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
}
}
}