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 DefaultValueCache(Map defaultValues){
|
||||
private List customDefaults = []
|
||||
|
||||
private DefaultValueCache(Map defaultValues, List customDefaults){
|
||||
this.defaultValues = defaultValues
|
||||
if(customDefaults) {
|
||||
this.customDefaults.addAll(customDefaults)
|
||||
}
|
||||
}
|
||||
|
||||
static getInstance(){
|
||||
return instance
|
||||
}
|
||||
|
||||
static createInstance(Map defaultValues){
|
||||
instance = new DefaultValueCache(defaultValues)
|
||||
static createInstance(Map defaultValues, List customDefaults = []){
|
||||
instance = new DefaultValueCache(defaultValues, customDefaults)
|
||||
}
|
||||
|
||||
Map getDefaultValues(){
|
||||
@ -28,6 +33,12 @@ class DefaultValueCache implements Serializable {
|
||||
instance = null
|
||||
}
|
||||
|
||||
List getCustomDefaults() {
|
||||
def result = []
|
||||
result.addAll(customDefaults)
|
||||
return result
|
||||
}
|
||||
|
||||
static void prepare(Script steps, Map parameters = [:]) {
|
||||
if(parameters == null) parameters = [:]
|
||||
if(!DefaultValueCache.getInstance() || parameters.customDefaults) {
|
||||
@ -46,7 +57,7 @@ class DefaultValueCache implements Serializable {
|
||||
MapUtils.pruneNulls(defaultValues),
|
||||
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.contains
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder
|
||||
import static org.hamcrest.Matchers.containsString
|
||||
import static org.hamcrest.Matchers.equalTo
|
||||
import static org.hamcrest.Matchers.is
|
||||
@ -63,8 +64,8 @@ class XsDeployTest extends BasePiperTest {
|
||||
@Before
|
||||
public void init() {
|
||||
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 --stepMetadata.*', '{"mode": "BG_DEPLOY", "action": "NONE", "apiUrl": "https://example.org/xs", "org": "myOrg", "space": "mySpace"}')
|
||||
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, '.*getConfig.*--contextConfig.*', '{"dockerImage": "xs", "credentialsId":"myCreds"}')
|
||||
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
|
||||
}
|
||||
|
||||
@ -88,7 +89,7 @@ class XsDeployTest extends BasePiperTest {
|
||||
thrown.expect(IllegalArgumentException)
|
||||
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(
|
||||
script: nullScript,
|
||||
@ -114,7 +115,6 @@ class XsDeployTest extends BasePiperTest {
|
||||
piperGoUtils: goUtils
|
||||
)
|
||||
|
||||
|
||||
// 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"}'))
|
||||
}
|
||||
@ -148,7 +148,10 @@ class XsDeployTest extends BasePiperTest {
|
||||
|
||||
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.dockerPullImage, equalTo(false))
|
||||
@ -158,7 +161,8 @@ class XsDeployTest extends BasePiperTest {
|
||||
new CommandLineMatcher()
|
||||
.hasProlog('./piper version'),
|
||||
new CommandLineMatcher()
|
||||
.hasProlog('./piper getConfig --contextConfig --stepMetadata \'metadata/xsDeploy.yaml\''),
|
||||
.hasProlog('./piper getConfig')
|
||||
.hasArgument('--contextConfig'),
|
||||
new CommandLineMatcher()
|
||||
.hasProlog('./piper getConfig --stepMetadata \'metadata/xsDeploy.yaml\''),
|
||||
new CommandLineMatcher()
|
||||
@ -176,7 +180,7 @@ class XsDeployTest extends BasePiperTest {
|
||||
|
||||
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(
|
||||
script: nullScript,
|
||||
@ -202,7 +206,7 @@ class XsDeployTest extends BasePiperTest {
|
||||
containsString('No operationId provided'),
|
||||
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())
|
||||
|
||||
@ -212,4 +216,61 @@ class XsDeployTest extends BasePiperTest {
|
||||
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.ConfigurationMerger
|
||||
import com.sap.piper.DefaultValueCache
|
||||
import com.sap.piper.analytics.InfluxData
|
||||
|
||||
class commonPipelineEnvironment implements Serializable {
|
||||
@ -143,4 +144,8 @@ class commonPipelineEnvironment implements Serializable {
|
||||
config = ConfigurationMerger.merge(configuration.get('stages')?.get(stageName) ?: [:], null, config)
|
||||
return config
|
||||
}
|
||||
List getCustomDefaults() {
|
||||
DefaultValueCache.getInstance().getCustomDefaults()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import static com.sap.piper.Prerequisites.checkScript
|
||||
|
||||
import com.sap.piper.DefaultValueCache
|
||||
import com.sap.piper.JenkinsUtils
|
||||
import com.sap.piper.PiperGoUtils
|
||||
|
||||
@ -10,6 +11,7 @@ import com.sap.piper.Utils
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String METADATA_FILE = 'metadata/xsDeploy.yaml'
|
||||
@Field String PIPER_DEFAULTS = 'default_pipeline_environment.yml'
|
||||
@Field String STEP_NAME = getClass().getName()
|
||||
|
||||
|
||||
@ -76,8 +78,16 @@ void call(Map parameters = [:]) {
|
||||
step: STEP_NAME,
|
||||
], 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([
|
||||
"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?
|
||||
// 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?
|
||||
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) {
|
||||
echo "[INFO] Context-Config: ${contextConfig}"
|
||||
@ -155,3 +165,11 @@ void call(Map parameters = [:]) {
|
||||
String getLockIdentifier(Map config) {
|
||||
"$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