github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/src/com/sap/piper/ConfigurationHelper.groovy (about)

     1  package com.sap.piper
     2  
     3  @API
     4  class ConfigurationHelper implements Serializable {
     5  
     6      def static SEPARATOR = '/'
     7  
     8      static ConfigurationHelper newInstance(Script step, Map config = [:]) {
     9          new ConfigurationHelper(step, config)
    10      }
    11  
    12      ConfigurationHelper loadStepDefaults(Map compatibleParameters = [:], String stageName = step.env.STAGE_NAME) {
    13          DefaultValueCache.prepare(step)
    14          this.config = ConfigurationLoader.defaultGeneralConfiguration()
    15          mixin(ConfigurationLoader.defaultGeneralConfiguration(), null, compatibleParameters)
    16          mixin(ConfigurationLoader.defaultStepConfiguration(null, name), null, compatibleParameters)
    17          mixin(ConfigurationLoader.defaultStageConfiguration(null, stageName), null, compatibleParameters)
    18          return this
    19      }
    20  
    21      private Map config
    22      private Script step
    23      private String name
    24      private Map validationResults = null
    25      private String dependingOn
    26  
    27      private ConfigurationHelper(Script step, Map config){
    28          this.config = config ?: [:]
    29          this.step = step
    30          this.name = step.STEP_NAME
    31          if(!this.name) throw new IllegalArgumentException('Step has no public name property!')
    32      }
    33  
    34      ConfigurationHelper collectValidationFailures() {
    35          validationResults = validationResults ?: [:]
    36          return this
    37      }
    38  
    39      ConfigurationHelper mixinGeneralConfig(commonPipelineEnvironment, Set filter = null, Map compatibleParameters = [:]){
    40          Map generalConfiguration = ConfigurationLoader.generalConfiguration([commonPipelineEnvironment: commonPipelineEnvironment])
    41          return mixin(generalConfiguration, filter, compatibleParameters)
    42      }
    43  
    44      ConfigurationHelper mixinStageConfig(commonPipelineEnvironment, stageName, Set filter = null, Map compatibleParameters = [:]){
    45          Map stageConfiguration = ConfigurationLoader.stageConfiguration([commonPipelineEnvironment: commonPipelineEnvironment], stageName)
    46          return mixin(stageConfiguration, filter, compatibleParameters)
    47      }
    48  
    49      ConfigurationHelper mixinStepConfig(commonPipelineEnvironment, Set filter = null, Map compatibleParameters = [:]){
    50          Map stepConfiguration = ConfigurationLoader.stepConfiguration([commonPipelineEnvironment: commonPipelineEnvironment], name)
    51          return mixin(stepConfiguration, filter, compatibleParameters)
    52      }
    53  
    54      ConfigurationHelper mixin(Map parameters, Set filter = null, Map compatibleParameters = [:]){
    55          if (parameters.size() > 0 && compatibleParameters.size() > 0) {
    56              parameters = ConfigurationMerger.merge(handleCompatibility(compatibleParameters, parameters), null, parameters)
    57          }
    58          if (filter) {
    59              filter.add('collectTelemetryData')
    60          }
    61          config = ConfigurationMerger.merge(parameters, filter, config)
    62          return this
    63      }
    64  
    65      private Map handleCompatibility(Map compatibleParameters, String paramStructure = '', Map configMap, Map newConfigMap = [:] ) {
    66          Map newConfig = [:]
    67          compatibleParameters.each {entry ->
    68              if (entry.getValue() instanceof Map) {
    69                  def internalParamStructure = (paramStructure ? paramStructure + '.' : '') + entry.getKey()
    70                  newConfig[entry.getKey()] = handleCompatibility(entry.getValue(), internalParamStructure, configMap, newConfig)
    71              } else {
    72                  def configSubMap = configMap
    73                  for(String key in paramStructure.tokenize('.')){
    74                      configSubMap = configSubMap?.get(key)
    75                  }
    76                  if (configSubMap == null || (configSubMap != null && configSubMap[entry.getKey()] == null)) {
    77                      def value = getConfigPropertyNested(configMap, entry.getValue())
    78                      if(null == value)
    79                          value = getConfigPropertyNested(newConfigMap, entry.getValue())
    80                      if (value != null) {
    81                          newConfig[entry.getKey()] = value
    82                          def paramName = (paramStructure ? paramStructure + '.' : '') + entry.getKey()
    83                          this.step.echo ("[INFO] The parameter '${entry.getValue()}' is COMPATIBLE to the parameter '${paramName}'")
    84                      }
    85                  }
    86              }
    87          }
    88          return newConfig
    89      }
    90  
    91      ConfigurationHelper mixin(String key){
    92          def parts = tokenizeKey(key)
    93          def targetMap = config
    94          if(parts.size() > 1) {
    95              key = parts.last()
    96              parts.remove(key)
    97              targetMap = getConfigPropertyNested(config, parts.join(SEPARATOR))
    98          }
    99          def dependentValue = config[dependingOn]
   100          if(targetMap[key] == null && dependentValue && config[dependentValue])
   101              targetMap[key] = config[dependentValue][key]
   102  
   103          dependingOn = null
   104          return this
   105      }
   106  
   107      ConfigurationHelper dependingOn(dependentKey){
   108          dependingOn = dependentKey
   109          return this
   110      }
   111  
   112      ConfigurationHelper addIfEmpty(key, value){
   113          if (config[key] instanceof Boolean) {
   114              return this
   115          } else if (!config[key]){
   116              config[key] = value
   117          }
   118          return this
   119      }
   120  
   121      ConfigurationHelper addIfNull(key, value){
   122          if (config[key] == null){
   123              config[key] = value
   124          }
   125          return this
   126      }
   127  
   128      Map use(){
   129          handleValidationFailures()
   130          MapUtils.traverse(config, { v -> (v instanceof GString) ? v.toString() : v })
   131          if(config.verbose) step.echo "[${name}] Configuration: ${config}"
   132          return MapUtils.deepCopy(config)
   133      }
   134  
   135      /* private */ def getConfigPropertyNested(key) {
   136          return getConfigPropertyNested(config, key)
   137      }
   138  
   139      /* private */ static getConfigPropertyNested(Map config, key) {
   140  
   141          List parts = tokenizeKey(key)
   142  
   143          if (config[parts.head()] != null) {
   144  
   145              if (config[parts.head()] in Map && !parts.tail().isEmpty()) {
   146                  return getConfigPropertyNested(config[parts.head()], parts.tail().join(SEPARATOR))
   147              }
   148  
   149              if (config[parts.head()].class == String) {
   150                  return (config[parts.head()] as String).trim()
   151              }
   152          }
   153          return config[parts.head()]
   154      }
   155  
   156      /* private */  static tokenizeKey(String key) {
   157          // reason for cast to CharSequence: String#tokenize(./.) causes a deprecation warning.
   158          List parts = (key in String) ? (key as CharSequence).tokenize(SEPARATOR) : ([key] as List)
   159          return parts
   160      }
   161  
   162      private void existsMandatoryProperty(key, errorMessage) {
   163  
   164          def paramValue = getConfigPropertyNested(config, key)
   165  
   166          if (paramValue == null) {
   167              if(! errorMessage) errorMessage = "ERROR - NO VALUE AVAILABLE FOR ${key}"
   168  
   169              def iae = new IllegalArgumentException(errorMessage)
   170              if(validationResults == null) {
   171                  throw iae
   172              }
   173              validationResults.put(key, iae)
   174          }
   175      }
   176  
   177      ConfigurationHelper withMandatoryProperty(key, errorMessage = null, condition = null){
   178          if(condition){
   179              if(condition(this.config))
   180                  existsMandatoryProperty(key, errorMessage)
   181          }else{
   182              existsMandatoryProperty(key, errorMessage)
   183          }
   184          return this
   185      }
   186  
   187      ConfigurationHelper withPropertyInValues(String key, Set values){
   188          withMandatoryProperty(key)
   189          def value = config[key] instanceof GString ? config[key].toString() : config[key]
   190          if(! (value in values) ) {
   191              throw new IllegalArgumentException("Invalid ${key} = '${value}'. Valid '${key}' values are: ${values}.")
   192          }
   193          return this
   194      }
   195  
   196      private handleValidationFailures() {
   197          if(! validationResults) return
   198          if(validationResults.size() == 1) throw validationResults.values().first()
   199          String msg = 'ERROR - NO VALUE AVAILABLE FOR: ' + validationResults.keySet().join(', ')
   200          IllegalArgumentException iae = new IllegalArgumentException(msg)
   201          validationResults.each { e -> iae.addSuppressed(e.value) }
   202          throw iae
   203      }
   204  }