github.com/jaylevin/jenkins-library@v1.230.4/vars/setupCommonPipelineEnvironment.groovy (about)

     1  import com.cloudbees.groovy.cps.NonCPS
     2  
     3  import static com.sap.piper.Prerequisites.checkScript
     4  
     5  import com.sap.piper.GenerateDocumentation
     6  import com.sap.piper.ConfigurationHelper
     7  import com.sap.piper.Utils
     8  import com.sap.piper.analytics.InfluxData
     9  
    10  import groovy.transform.Field
    11  
    12  @Field String STEP_NAME = getClass().getName()
    13  
    14  @Field Set GENERAL_CONFIG_KEYS = [
    15      /** */
    16      'collectTelemetryData',
    17  
    18      /** Credentials (username and password) used to download custom defaults if access is secured.*/
    19      'customDefaultsCredentialsId',
    20  
    21      /** Enable automatic inference of build tool (maven, npm, mta) based on existing project files.
    22       * If this is set to true, it is not required to set the build tool by hand for those cases.
    23       */
    24      'inferBuildTool'
    25  ]
    26  
    27  @Field Set STEP_CONFIG_KEYS = []
    28  
    29  @Field Set PARAMETER_KEYS = [
    30      /** Path to the pipeline configuration file defining project specific settings.*/
    31      'configFile',
    32      /** A list of file names which will be extracted from library resources and which serve as source for
    33       * default values for the pipeline configuration. These are merged with and override built-in defaults, with
    34       * a parameter supplied by the last resource file taking precedence over the same parameter supplied in an
    35       * earlier resource file or built-in default.*/
    36      'customDefaults',
    37      /** A list of file paths or URLs which must point to YAML content. These work exactly like
    38       * `customDefaults`, but from local or remote files instead of library resources. They are merged with and
    39       * take precedence over `customDefaults`.*/
    40      'customDefaultsFromFiles',
    41      /** The map returned from a Jenkins git checkout. Used to set the git information in the
    42       * common pipeline environment */
    43      'scmInfo'
    44  ]
    45  
    46  /**
    47   * Initializes the [`commonPipelineEnvironment`](commonPipelineEnvironment.md), which is used throughout the complete pipeline.
    48   *
    49   * !!! tip
    50   *     This step needs to run at the beginning of a pipeline right after the SCM checkout.
    51   *     Then subsequent pipeline steps consume the information from `commonPipelineEnvironment`; it does not need to be passed to pipeline steps explicitly.
    52   */
    53  @GenerateDocumentation
    54  void call(Map parameters = [:]) {
    55  
    56      handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
    57  
    58          def script = checkScript(this, parameters)
    59  
    60          String configFile = parameters.get('configFile')
    61          loadConfigurationFromFile(script, configFile)
    62  
    63          // Copy custom defaults from library resources to include them in the 'pipelineConfigAndTests' stash
    64          List customDefaultsResources = Utils.appendParameterToStringList(
    65              ['default_pipeline_environment.yml'], parameters, 'customDefaults')
    66          customDefaultsResources.each {
    67              cd ->
    68                  writeFile file: ".pipeline/${cd}", text: libraryResource(cd)
    69          }
    70  
    71          List customDefaultsFiles = Utils.appendParameterToStringList(
    72              [], parameters, 'customDefaultsFromFiles')
    73  
    74          if (script.commonPipelineEnvironment.configuration.customDefaults) {
    75              if (!script.commonPipelineEnvironment.configuration.customDefaults in List) {
    76                  // Align with Go side on supported parameter type.
    77                  error "You have defined the parameter 'customDefaults' in your project configuration " +
    78                      "but it is of an unexpected type. Please make sure that it is a list of strings, i.e. " +
    79                      "customDefaults = ['...']. See https://sap.github.io/jenkins-library/configuration/ for " +
    80                      "more details."
    81              }
    82              customDefaultsFiles = Utils.appendParameterToStringList(
    83                  customDefaultsFiles, script.commonPipelineEnvironment.configuration as Map, 'customDefaults')
    84          }
    85          String customDefaultsCredentialsId = script.commonPipelineEnvironment.configuration.general?.customDefaultsCredentialsId
    86          customDefaultsFiles = copyOrDownloadCustomDefaultsIntoPipelineEnv(script, customDefaultsFiles, customDefaultsCredentialsId)
    87  
    88          prepareDefaultValues([
    89              script: script,
    90              customDefaults: parameters.customDefaults,
    91              customDefaultsFromFiles: customDefaultsFiles ])
    92  
    93          piperLoadGlobalExtensions script: script, customDefaults: parameters.customDefaults, customDefaultsFromFiles: customDefaultsFiles
    94  
    95          String stashIncludes = '.pipeline/**'
    96          if (configFile && !configFile.startsWith('.pipeline/')) {
    97              stashIncludes += ", $configFile"
    98          }
    99          stash name: 'pipelineConfigAndTests', includes: stashIncludes, allowEmpty: true
   100  
   101          Map config = ConfigurationHelper.newInstance(this)
   102              .loadStepDefaults()
   103              .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
   104              .use()
   105  
   106          inferBuildTool(script, config)
   107  
   108          (parameters.utils ?: new Utils()).pushToSWA([
   109              step: STEP_NAME,
   110              stepParamKey4: 'customDefaults',
   111              stepParam4: parameters.customDefaults?'true':'false'
   112          ], config)
   113  
   114          InfluxData.addField('step_data', 'build_url', env.BUILD_URL)
   115          InfluxData.addField('pipeline_data', 'build_url', env.BUILD_URL)
   116  
   117          def scmInfo = parameters.scmInfo
   118          if (scmInfo) {
   119              setGitUrlsOnCommonPipelineEnvironment(script, scmInfo.GIT_URL)
   120              script.commonPipelineEnvironment.setGitCommitId(scmInfo.GIT_COMMIT)
   121          }
   122      }
   123  }
   124  
   125  
   126  // Infer build tool (maven, npm, mta) based on existing build descriptor files in the project root.
   127  private static void inferBuildTool(script, config) {
   128      // For backwards compatibility, build tool inference must be enabled via inferBuildTool setting
   129      boolean inferBuildTool = config?.inferBuildTool
   130  
   131      if (inferBuildTool) {
   132          boolean isMtaProject = script.fileExists('mta.yaml')
   133          def isMavenProject = script.fileExists('pom.xml')
   134          def isNpmProject = script.fileExists('package.json')
   135  
   136          if (isMtaProject) {
   137              script.commonPipelineEnvironment.buildTool = 'mta'
   138          } else if (isMavenProject) {
   139              script.commonPipelineEnvironment.buildTool = 'maven'
   140          } else if (isNpmProject) {
   141              script.commonPipelineEnvironment.buildTool = 'npm'
   142          }
   143      }
   144  }
   145  
   146  private static loadConfigurationFromFile(script, String configFile) {
   147      if (!configFile) {
   148          String defaultYmlConfigFile = '.pipeline/config.yml'
   149          String defaultYamlConfigFile = '.pipeline/config.yaml'
   150          if (script.fileExists(defaultYmlConfigFile)) {
   151              configFile = defaultYmlConfigFile
   152          } else if (script.fileExists(defaultYamlConfigFile)) {
   153              configFile = defaultYamlConfigFile
   154          }
   155      }
   156  
   157      // A file passed to the function is not checked for existence in order to fail the pipeline.
   158      if (configFile) {
   159          script.commonPipelineEnvironment.configuration = script.readYaml(file: configFile)
   160          script.commonPipelineEnvironment.configurationFile = configFile
   161      }
   162  }
   163  
   164  private static List copyOrDownloadCustomDefaultsIntoPipelineEnv(script, List customDefaults, String credentialsId) {
   165      List fileList = []
   166      int urlCount = 0
   167      for (int i = 0; i < customDefaults.size(); i++) {
   168          // copy retrieved file to .pipeline/ to make sure they are in the pipelineConfigAndTests stash
   169          if (!(customDefaults[i] in CharSequence) || customDefaults[i] == '') {
   170              script.echo "WARNING: Ignoring invalid entry in custom defaults from files: '${customDefaults[i]}'"
   171              continue
   172          }
   173          String fileName
   174          if (customDefaults[i].startsWith('http://') || customDefaults[i].startsWith('https://')) {
   175              fileName = "custom_default_from_url_${urlCount}.yml"
   176  
   177              Map httpRequestParameters = [
   178                  url: customDefaults[i],
   179                  validResponseCodes: '100:399,404' // Allow a more specific error message for 404 case
   180              ]
   181              if (credentialsId) {
   182                  httpRequestParameters.authentication = credentialsId
   183              }
   184              def response = script.httpRequest(httpRequestParameters)
   185              if (response.status == 404) {
   186                  error "URL for remote custom defaults (${customDefaults[i]}) appears to be incorrect. " +
   187                      "Server returned HTTP status code 404. " +
   188                      "Please make sure that the path is correct and no authentication is required to retrieve the file."
   189              }
   190  
   191              script.writeFile file: ".pipeline/$fileName", text: response.content
   192              urlCount++
   193          } else if (script.fileExists(customDefaults[i])) {
   194              fileName = customDefaults[i]
   195              script.writeFile file: ".pipeline/$fileName", text: script.readFile(file: fileName)
   196          } else {
   197              script.echo "WARNING: Custom default entry not found: '${customDefaults[i]}', it will be ignored"
   198              continue
   199          }
   200          fileList.add(fileName)
   201      }
   202      return fileList
   203  }
   204  
   205  /*
   206   * Returns the parts of an url.
   207   * Valid keys for the retured map are:
   208   *   - protocol
   209   *   - auth
   210   *   - host
   211   *   - port
   212   *   - path
   213   */
   214  @NonCPS
   215  /* private */ Map parseUrl(String url) {
   216  
   217      def urlMatcher = url =~ /^((http|https|git|ssh):\/\/)?((.*)@)?([^:\/]+)(:([\d]*))?(\/?(.*))$/
   218  
   219      return [
   220          protocol: urlMatcher[0][2],
   221          auth: urlMatcher[0][4],
   222          host: urlMatcher[0][5],
   223          port: urlMatcher[0][7],
   224          path: urlMatcher[0][9],
   225      ]
   226  }
   227  
   228  private void setGitUrlsOnCommonPipelineEnvironment(script, String gitUrl) {
   229  
   230      Map url = parseUrl(gitUrl)
   231  
   232      if (url.protocol in ['http', 'https']) {
   233          script.commonPipelineEnvironment.setGitSshUrl("git@${url.host}:${url.path}")
   234          script.commonPipelineEnvironment.setGitHttpsUrl(gitUrl)
   235      } else if (url.protocol in [ null, 'ssh', 'git']) {
   236          script.commonPipelineEnvironment.setGitSshUrl(gitUrl)
   237          script.commonPipelineEnvironment.setGitHttpsUrl("https://${url.host}/${url.path}")
   238      }
   239  
   240      List gitPathParts = url.path.replaceAll('.git', '').split('/')
   241      def gitFolder = 'N/A'
   242      def gitRepo = 'N/A'
   243      switch (gitPathParts.size()) {
   244          case 0:
   245              break
   246          case 1:
   247              gitRepo = gitPathParts[0]
   248              break
   249          case 2:
   250              gitFolder = gitPathParts[0]
   251              gitRepo = gitPathParts[1]
   252              break
   253          default:
   254              gitRepo = gitPathParts[gitPathParts.size()-1]
   255              gitPathParts.remove(gitPathParts.size()-1)
   256              gitFolder = gitPathParts.join('/')
   257              break
   258      }
   259      script.commonPipelineEnvironment.setGithubOrg(gitFolder)
   260      script.commonPipelineEnvironment.setGithubRepo(gitRepo)
   261  }