mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
Provide support for additional customer config layers.
This commit is contained in:
parent
264e783833
commit
e6b00fa601
@ -8,16 +8,21 @@ class DefaultValueCache implements Serializable {
|
|||||||
|
|
||||||
private Map defaultValues
|
private Map defaultValues
|
||||||
|
|
||||||
private DefaultValueCache(Map defaultValues){
|
private List customDefaults = []
|
||||||
|
|
||||||
|
private DefaultValueCache(Map defaultValues, List customDefaults){
|
||||||
this.defaultValues = defaultValues
|
this.defaultValues = defaultValues
|
||||||
|
if(customDefaults) {
|
||||||
|
this.customDefaults.addAll(customDefaults)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getInstance(){
|
static getInstance(){
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
static createInstance(Map defaultValues){
|
static createInstance(Map defaultValues, List customDefaults = []){
|
||||||
instance = new DefaultValueCache(defaultValues)
|
instance = new DefaultValueCache(defaultValues, customDefaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
Map getDefaultValues(){
|
Map getDefaultValues(){
|
||||||
@ -28,6 +33,12 @@ class DefaultValueCache implements Serializable {
|
|||||||
instance = null
|
instance = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List getCustomDefaults() {
|
||||||
|
def result = []
|
||||||
|
result.addAll(customDefaults)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
static void prepare(Script steps, Map parameters = [:]) {
|
static void prepare(Script steps, Map parameters = [:]) {
|
||||||
if(parameters == null) parameters = [:]
|
if(parameters == null) parameters = [:]
|
||||||
if(!DefaultValueCache.getInstance() || parameters.customDefaults) {
|
if(!DefaultValueCache.getInstance() || parameters.customDefaults) {
|
||||||
@ -46,7 +57,7 @@ class DefaultValueCache implements Serializable {
|
|||||||
MapUtils.pruneNulls(defaultValues),
|
MapUtils.pruneNulls(defaultValues),
|
||||||
MapUtils.pruneNulls(configuration))
|
MapUtils.pruneNulls(configuration))
|
||||||
}
|
}
|
||||||
DefaultValueCache.createInstance(defaultValues)
|
DefaultValueCache.createInstance(defaultValues, customDefaults)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import static org.hamcrest.Matchers.allOf
|
import static org.hamcrest.Matchers.allOf
|
||||||
import static org.hamcrest.Matchers.contains
|
import static org.hamcrest.Matchers.contains
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder
|
||||||
import static org.hamcrest.Matchers.containsString
|
import static org.hamcrest.Matchers.containsString
|
||||||
import static org.hamcrest.Matchers.equalTo
|
import static org.hamcrest.Matchers.equalTo
|
||||||
import static org.hamcrest.Matchers.is
|
import static org.hamcrest.Matchers.is
|
||||||
@ -63,8 +64,8 @@ class XsDeployTest extends BasePiperTest {
|
|||||||
@Before
|
@Before
|
||||||
public void init() {
|
public void init() {
|
||||||
helper.registerAllowedMethod('withEnv', [List, Closure], {l, c -> env = l; c()})
|
helper.registerAllowedMethod('withEnv', [List, Closure], {l, c -> env = l; c()})
|
||||||
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*getConfig --contextConfig --stepMetadata.*', '{"dockerImage": "xs", "credentialsId":"myCreds"}')
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*getConfig.*--contextConfig.*', '{"dockerImage": "xs", "credentialsId":"myCreds"}')
|
||||||
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*getConfig --stepMetadata.*', '{"mode": "BG_DEPLOY", "action": "NONE", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "BG_DEPLOY", "action": "NONE", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
||||||
nullScript.commonPipelineEnvironment.xsDeploymentId = null
|
nullScript.commonPipelineEnvironment.xsDeploymentId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ class XsDeployTest extends BasePiperTest {
|
|||||||
thrown.expect(IllegalArgumentException)
|
thrown.expect(IllegalArgumentException)
|
||||||
thrown.expectMessage('No enum constant')
|
thrown.expectMessage('No enum constant')
|
||||||
|
|
||||||
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*getConfig --stepMetadata.*', '{"mode": "DOES_NOT_EXIST", "action": "NONE", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "DOES_NOT_EXIST", "action": "NONE", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
||||||
|
|
||||||
stepRule.step.xsDeploy(
|
stepRule.step.xsDeploy(
|
||||||
script: nullScript,
|
script: nullScript,
|
||||||
@ -114,7 +115,6 @@ class XsDeployTest extends BasePiperTest {
|
|||||||
piperGoUtils: goUtils
|
piperGoUtils: goUtils
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// nota bene: script and piperGoUtils are not contained in the json below.
|
// nota bene: script and piperGoUtils are not contained in the json below.
|
||||||
assertThat(env*.toString(), contains('PIPER_parametersJSON={"apiUrl":"https://example.org/xs","org":"myOrg","space":"mySpace","credentialsId":"myCreds","deployOpts":"-t 60","mtaPath":"myApp.mta","mode":"DEPLOY","action":"NONE"}'))
|
assertThat(env*.toString(), contains('PIPER_parametersJSON={"apiUrl":"https://example.org/xs","org":"myOrg","space":"mySpace","credentialsId":"myCreds","deployOpts":"-t 60","mtaPath":"myApp.mta","mode":"DEPLOY","action":"NONE"}'))
|
||||||
}
|
}
|
||||||
@ -148,7 +148,10 @@ class XsDeployTest extends BasePiperTest {
|
|||||||
|
|
||||||
assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, is('1234'))
|
assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, is('1234'))
|
||||||
|
|
||||||
assertThat(writeFileRule.files.keySet(), contains('metadata/xsDeploy.yaml'))
|
assertThat(writeFileRule.files.keySet(), containsInAnyOrder(
|
||||||
|
'.pipeline/additionalConfigs/default_pipeline_environment.yml',
|
||||||
|
'metadata/xsDeploy.yaml',
|
||||||
|
))
|
||||||
|
|
||||||
assertThat(dockerRule.dockerParams.dockerImage, equalTo('xs'))
|
assertThat(dockerRule.dockerParams.dockerImage, equalTo('xs'))
|
||||||
assertThat(dockerRule.dockerParams.dockerPullImage, equalTo(false))
|
assertThat(dockerRule.dockerParams.dockerPullImage, equalTo(false))
|
||||||
@ -158,7 +161,8 @@ class XsDeployTest extends BasePiperTest {
|
|||||||
new CommandLineMatcher()
|
new CommandLineMatcher()
|
||||||
.hasProlog('./piper version'),
|
.hasProlog('./piper version'),
|
||||||
new CommandLineMatcher()
|
new CommandLineMatcher()
|
||||||
.hasProlog('./piper getConfig --contextConfig --stepMetadata \'metadata/xsDeploy.yaml\''),
|
.hasProlog('./piper getConfig')
|
||||||
|
.hasArgument('--contextConfig'),
|
||||||
new CommandLineMatcher()
|
new CommandLineMatcher()
|
||||||
.hasProlog('./piper getConfig --stepMetadata \'metadata/xsDeploy.yaml\''),
|
.hasProlog('./piper getConfig --stepMetadata \'metadata/xsDeploy.yaml\''),
|
||||||
new CommandLineMatcher()
|
new CommandLineMatcher()
|
||||||
@ -176,7 +180,7 @@ class XsDeployTest extends BasePiperTest {
|
|||||||
|
|
||||||
nullScript.commonPipelineEnvironment.xsDeploymentId = '1234'
|
nullScript.commonPipelineEnvironment.xsDeploymentId = '1234'
|
||||||
|
|
||||||
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*getConfig --stepMetadata.*', '{"mode": "BG_DEPLOY", "action": "RESUME", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "BG_DEPLOY", "action": "RESUME", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
||||||
|
|
||||||
stepRule.step.xsDeploy(
|
stepRule.step.xsDeploy(
|
||||||
script: nullScript,
|
script: nullScript,
|
||||||
@ -202,7 +206,7 @@ class XsDeployTest extends BasePiperTest {
|
|||||||
containsString('No operationId provided'),
|
containsString('No operationId provided'),
|
||||||
containsString('Was there a deployment before?')))
|
containsString('Was there a deployment before?')))
|
||||||
|
|
||||||
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*getConfig --stepMetadata.*', '{"mode": "BG_DEPLOY", "action": "RESUME", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'getConfig.* (?!--contextConfig)', '{"mode": "BG_DEPLOY", "action": "RESUME", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
||||||
|
|
||||||
assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, nullValue())
|
assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, nullValue())
|
||||||
|
|
||||||
@ -212,4 +216,61 @@ class XsDeployTest extends BasePiperTest {
|
|||||||
failOnError: true,
|
failOnError: true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdditionalCustomConfigLayers() {
|
||||||
|
|
||||||
|
def resources = ['a.yml': '- x: y}', 'b.yml' : '- a: b}']
|
||||||
|
|
||||||
|
helper.registerAllowedMethod('libraryResource', [String], {
|
||||||
|
|
||||||
|
r ->
|
||||||
|
|
||||||
|
def resource = resources[r]
|
||||||
|
if(resource) return resource
|
||||||
|
|
||||||
|
File res = new File(new File('resources'), r)
|
||||||
|
if (res.exists()) {
|
||||||
|
return res.getText()
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException("Resource '${r}' not found.")
|
||||||
|
})
|
||||||
|
|
||||||
|
assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, nullValue())
|
||||||
|
|
||||||
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*xsDeploy .*', '{"operationId": "1234"}')
|
||||||
|
|
||||||
|
nullScript.commonPipelineEnvironment = ['reset': {}, 'getCustomDefaults': {['a.yml', 'b.yml']}]
|
||||||
|
|
||||||
|
goUtils = new PiperGoUtils(null) {
|
||||||
|
void unstashPiperBin() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stepRule.step.xsDeploy(
|
||||||
|
script: nullScript,
|
||||||
|
piperGoUtils: goUtils
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(nullScript.commonPipelineEnvironment.xsDeploymentId, is('1234'))
|
||||||
|
|
||||||
|
assertThat(writeFileRule.files.keySet(), containsInAnyOrder(
|
||||||
|
'.pipeline/additionalConfigs/a.yml',
|
||||||
|
'.pipeline/additionalConfigs/b.yml',
|
||||||
|
'.pipeline/additionalConfigs/default_pipeline_environment.yml',
|
||||||
|
'metadata/xsDeploy.yaml',
|
||||||
|
))
|
||||||
|
|
||||||
|
assertThat(shellRule.shell,
|
||||||
|
allOf(
|
||||||
|
new CommandLineMatcher()
|
||||||
|
.hasProlog('./piper getConfig')
|
||||||
|
.hasArgument('--contextConfig')
|
||||||
|
.hasArgument('--defaultConfig "b.yml" "a.yml" "default_pipeline_environment.yml"'),
|
||||||
|
new CommandLineMatcher()
|
||||||
|
.hasProlog('./piper getConfig --stepMetadata \'metadata/xsDeploy.yaml\''),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import com.sap.piper.ConfigurationLoader
|
import com.sap.piper.ConfigurationLoader
|
||||||
import com.sap.piper.ConfigurationMerger
|
import com.sap.piper.ConfigurationMerger
|
||||||
|
import com.sap.piper.DefaultValueCache
|
||||||
import com.sap.piper.analytics.InfluxData
|
import com.sap.piper.analytics.InfluxData
|
||||||
|
|
||||||
class commonPipelineEnvironment implements Serializable {
|
class commonPipelineEnvironment implements Serializable {
|
||||||
@ -143,4 +144,8 @@ class commonPipelineEnvironment implements Serializable {
|
|||||||
config = ConfigurationMerger.merge(configuration.get('stages')?.get(stageName) ?: [:], null, config)
|
config = ConfigurationMerger.merge(configuration.get('stages')?.get(stageName) ?: [:], null, config)
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
List getCustomDefaults() {
|
||||||
|
DefaultValueCache.getInstance().getCustomDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import static com.sap.piper.Prerequisites.checkScript
|
import static com.sap.piper.Prerequisites.checkScript
|
||||||
|
|
||||||
|
import com.sap.piper.DefaultValueCache
|
||||||
import com.sap.piper.JenkinsUtils
|
import com.sap.piper.JenkinsUtils
|
||||||
import com.sap.piper.PiperGoUtils
|
import com.sap.piper.PiperGoUtils
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ import com.sap.piper.Utils
|
|||||||
import groovy.transform.Field
|
import groovy.transform.Field
|
||||||
|
|
||||||
@Field String METADATA_FILE = 'metadata/xsDeploy.yaml'
|
@Field String METADATA_FILE = 'metadata/xsDeploy.yaml'
|
||||||
|
@Field String PIPER_DEFAULTS = 'default_pipeline_environment.yml'
|
||||||
@Field String STEP_NAME = getClass().getName()
|
@Field String STEP_NAME = getClass().getName()
|
||||||
|
|
||||||
|
|
||||||
@ -76,8 +78,16 @@ void call(Map parameters = [:]) {
|
|||||||
step: STEP_NAME,
|
step: STEP_NAME,
|
||||||
], null)
|
], null)
|
||||||
|
|
||||||
writeFile(file: METADATA_FILE, text: libraryResource(METADATA_FILE))
|
|
||||||
|
|
||||||
|
List configs = [PIPER_DEFAULTS]
|
||||||
|
configs.addAll(script.commonPipelineEnvironment.getCustomDefaults())
|
||||||
|
configs = configs.reverse()
|
||||||
|
|
||||||
|
for(def customDefault : configs) {
|
||||||
|
writeFile(file: ".pipeline/additionalConfigs/${customDefault}", text: libraryResource(customDefault))
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFile(file: METADATA_FILE, text: libraryResource(METADATA_FILE))
|
||||||
|
|
||||||
withEnv([
|
withEnv([
|
||||||
"PIPER_parametersJSON=${groovy.json.JsonOutput.toJson(parameters)}",
|
"PIPER_parametersJSON=${groovy.json.JsonOutput.toJson(parameters)}",
|
||||||
@ -87,9 +97,9 @@ void call(Map parameters = [:]) {
|
|||||||
// context config gives us e.g. the docker image name. --> How does this work for customer maintained images?
|
// context config gives us e.g. the docker image name. --> How does this work for customer maintained images?
|
||||||
// There is a name provided in the metadata file. But we do not provide a docker image for that.
|
// There is a name provided in the metadata file. But we do not provide a docker image for that.
|
||||||
// The user has to build that for her/his own. How do we expect to configure this?
|
// The user has to build that for her/his own. How do we expect to configure this?
|
||||||
Map contextConfig = readJSON (text: sh(returnStdout: true, script: "./piper getConfig --contextConfig --stepMetadata '${METADATA_FILE}'"))
|
Map contextConfig = readJSON (text: sh(returnStdout: true, script: "./piper ${parameters.verbose ? '--verbose' :''} getConfig --stepMetadata '${METADATA_FILE}' --defaultConfig ${joinAndQuote(configs)} --contextConfig"))
|
||||||
|
|
||||||
Map projectConfig = readJSON (text: sh(returnStdout: true, script: "./piper ${parameters.verbose ? '--verbose' :''} getConfig --stepMetadata '${METADATA_FILE}'"))
|
Map projectConfig = readJSON (text: sh(returnStdout: true, script: "./piper ${parameters.verbose ? '--verbose' :''} getConfig --stepMetadata '${METADATA_FILE}' --defaultConfig ${joinAndQuote(configs)}"))
|
||||||
|
|
||||||
if(parameters.verbose) {
|
if(parameters.verbose) {
|
||||||
echo "[INFO] Context-Config: ${contextConfig}"
|
echo "[INFO] Context-Config: ${contextConfig}"
|
||||||
@ -155,3 +165,11 @@ void call(Map parameters = [:]) {
|
|||||||
String getLockIdentifier(Map config) {
|
String getLockIdentifier(Map config) {
|
||||||
"$STEP_NAME:${config.apiUrl}:${config.org}:${config.space}"
|
"$STEP_NAME:${config.apiUrl}:${config.org}:${config.space}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String joinAndQuote(List l) {
|
||||||
|
_l = []
|
||||||
|
for(def e : l) {
|
||||||
|
_l << '"' + e + '"'
|
||||||
|
}
|
||||||
|
_l.join(' ')
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user