github.com/xgoffin/jenkins-library@v1.154.0/vars/piperPipelineStageInit.groovy (about)

     1  import com.sap.piper.ConfigurationHelper
     2  import com.sap.piper.GenerateStageDocumentation
     3  import com.sap.piper.JenkinsUtils
     4  import com.sap.piper.StageNameProvider
     5  import com.sap.piper.Utils
     6  import com.sap.piper.k8s.ContainerMap
     7  import groovy.transform.Field
     8  
     9  import static com.sap.piper.Prerequisites.checkScript
    10  
    11  @Field String STEP_NAME = getClass().getName()
    12  @Field String TECHNICAL_STAGE_NAME = 'init'
    13  
    14  @Field Set GENERAL_CONFIG_KEYS = [
    15      /**
    16       * Defines the build tool used.
    17       * @possibleValues `docker`, `kaniko`, `maven`, `mta, ``npm`
    18       */
    19      'buildTool',
    20      /**
    21       * Defines the library resource containing the container map.
    22       */
    23      'containerMapResource',
    24      /**
    25       * Enable automatic inference of build tool (maven, npm, mta) based on existing project files.
    26       * If this is set to true, it is not required to provide the `buildTool` parameter in the `general` section of the pipeline configuration.
    27       */
    28      'inferBuildTool',
    29      /**
    30       * Enables automatic inference from the build descriptor in case projectName is not configured.
    31       */
    32      'inferProjectName',
    33      /**
    34       * Defines the library resource containing the legacy configuration definition.
    35       */
    36      'legacyConfigSettings',
    37      /**
    38       * Defines the main branch for your pipeline. **Typically this is the `master` branch, which does not need to be set explicitly.** Only change this in exceptional cases
    39       */
    40      'productiveBranch',
    41      /**
    42       * Name of the project, e.g. used for the name of lockable resources.
    43       */
    44      'projectName',
    45      /**
    46       * Specify to execute artifact versioning in a kubernetes pod.
    47       * @possibleValues `true`, `false`
    48       */
    49      'runArtifactVersioningOnPod',
    50      /**
    51       *  Defines the library resource containing stage/step initialization settings. Those define conditions when certain steps/stages will be activated. **Caution: changing the default will break the standard behavior of the pipeline - thus only relevant when including `Init` stage into custom pipelines!**
    52       */
    53      'stageConfigResource',
    54      /**
    55       * Defines the library resource containing the stash settings to be performed before and after each stage. **Caution: changing the default will break the standard behavior of the pipeline - thus only relevant when including `Init` stage into custom pipelines!**
    56       */
    57      'stashSettings',
    58      /**
    59      * Works as the stashSettings parameter, but allows the use of a stash settings file that is not available as a library resource.
    60      */
    61      'customStashSettings',
    62      /**
    63       * Whether verbose output should be produced.
    64       * @possibleValues `true`, `false`
    65       */
    66      'verbose'
    67  ]
    68  @Field STAGE_STEP_KEYS = [
    69      /**
    70       * Sets the build version.
    71       * @possibleValues `true`, `false`
    72       */
    73      'artifactPrepareVersion'
    74  ]
    75  @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus(STAGE_STEP_KEYS)
    76  @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([
    77      /**
    78       * Enables the use of technical stage names.
    79       */
    80      'useTechnicalStageNames',
    81      /**
    82       * Provides a clone from the specified repository.
    83       * This map contains attributes, such as, `branches`, `extensions`, `userRemoteConfigs` etc.
    84       * Example: `[$class: 'GitSCM', branches: [[name: <branch_to_be_cloned>]], userRemoteConfigs: [[credentialsId: <credential_to_access_repository>, url: <repository_url>]]]`.
    85       */
    86      'checkoutMap',
    87      /**
    88       * The map returned from a Jenkins git checkout. Used to set the git information in the
    89       * common pipeline environment.
    90       */
    91      'scmInfo',
    92      /**
    93       * Optional skip of checkout if checkout was done before this step already.
    94       * @possibleValues `true`, `false`
    95       */
    96      'skipCheckout',
    97      /**
    98      * Mandatory if you skip the checkout. Then you need to unstash your workspace to get the e.g. configuration.
    99      */
   100      'stashContent',
   101      /**
   102       * Optional path to the pipeline configuration file defining project specific settings.
   103       */
   104      'configFile',
   105      /**
   106       * Optional list of file names which will be extracted from library resources and which serve as source for
   107       * default values for the pipeline configuration. These are merged with and override built-in defaults, with
   108       * a parameter supplied by the last resource file taking precedence over the same parameter supplied in an
   109       * earlier resource file or built-in default.
   110       */
   111      'customDefaults',
   112      /**
   113       * Optional list of file paths or URLs which must point to YAML content. These work exactly like
   114       * `customDefaults`, but from local or remote files instead of library resources. They are merged with and
   115       * take precedence over `customDefaults`.
   116       */
   117      'customDefaultsFromFiles'
   118  ])
   119  
   120  /**
   121   * This stage initializes the pipeline run and prepares further execution.
   122   *
   123   * It will check out your repository and perform some steps to initialize your pipeline run.
   124   */
   125  @GenerateStageDocumentation(defaultStageName = 'Init')
   126  void call(Map parameters = [:]) {
   127  
   128      def script = checkScript(this, parameters) ?: this
   129      def utils = parameters.juStabUtils ?: new Utils()
   130  
   131      if (parameters.useTechnicalStageNames) {
   132          StageNameProvider.instance.useTechnicalStageNames = true
   133      }
   134  
   135      def stageName = StageNameProvider.instance.getStageName(script, parameters, this)
   136  
   137      piperStageWrapper (script: script, stageName: stageName, stashContent: [], ordinal: 1, telemetryDisabled: true) {
   138          def skipCheckout = parameters.skipCheckout
   139          if (skipCheckout != null && !(skipCheckout instanceof Boolean)) {
   140              error "[${STEP_NAME}] Parameter skipCheckout has to be of type boolean. Instead got '${skipCheckout.class.getName()}'"
   141          }
   142          def scmInfo = parameters.scmInfo
   143          if (skipCheckout && !scmInfo) {
   144              error "[${STEP_NAME}] Need am scmInfo map retrieved from a checkout. " +
   145                  "If you want to skip the checkout the scm info needs to be provided by you with parameter scmInfo, " +
   146                  "for example as follows:\n" +
   147                  "  def scmInfo = checkout scm\n" +
   148                  "  piperPipelineStageInit script:this, skipCheckout: true, scmInfo: scmInfo"
   149          }
   150          if (!skipCheckout) {
   151              scmInfo = checkout(parameters.checkoutMap ?: scm)
   152          }
   153          else {
   154              def stashContent = parameters.stashContent
   155              if(stashContent == null || stashContent.size() == 0) {
   156                  error "[${STEP_NAME}] needs stashes if you skip checkout"
   157              }
   158              utils.unstashAll(stashContent)
   159          }
   160  
   161          setupCommonPipelineEnvironment(script: script, customDefaults: parameters.customDefaults, scmInfo: scmInfo,
   162              configFile: parameters.configFile, customDefaultsFromFiles: parameters.customDefaultsFromFiles)
   163  
   164          Map config = ConfigurationHelper.newInstance(this)
   165              .loadStepDefaults()
   166              .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
   167              .mixinStageConfig(script.commonPipelineEnvironment, stageName, STEP_CONFIG_KEYS)
   168              .mixin(parameters, PARAMETER_KEYS)
   169              .addIfEmpty('stageConfigResource', 'com.sap.piper/pipeline/stageDefaults.yml')
   170              .addIfEmpty('stashSettings', 'com.sap.piper/pipeline/stashSettings.yml')
   171              .addIfEmpty('buildTool', script.commonPipelineEnvironment.buildTool)
   172              .withMandatoryProperty('buildTool')
   173              .use()
   174  
   175          if (config.legacyConfigSettings) {
   176              Map legacyConfigSettings = readYaml(text: libraryResource(config.legacyConfigSettings))
   177              checkForLegacyConfiguration(script: script, legacyConfigSettings: legacyConfigSettings)
   178          }
   179  
   180          String buildTool = config.buildTool
   181          String buildToolDesc = inferBuildToolDesc(script, config.buildTool)
   182  
   183          checkBuildTool(buildTool, buildToolDesc)
   184  
   185          script.commonPipelineEnvironment.projectName = config.projectName
   186  
   187          if (!script.commonPipelineEnvironment.projectName && config.inferProjectName) {
   188              script.commonPipelineEnvironment.projectName = inferProjectName(script, buildTool, buildToolDesc)
   189          }
   190  
   191          if (Boolean.valueOf(env.ON_K8S) && config.containerMapResource) {
   192              ContainerMap.instance.initFromResource(script, config.containerMapResource, buildTool)
   193          }
   194  
   195          initStashConfiguration(script, config.stashSettings, config.customStashSettings, config.verbose ?: false)
   196  
   197          if (config.verbose) {
   198              echo "piper-lib-os  configuration: ${script.commonPipelineEnvironment.configuration}"
   199          }
   200  
   201          // telemetry reporting
   202          utils.pushToSWA([step: STEP_NAME], config)
   203  
   204          piperInitRunStageConfiguration script: script, stageConfigResource: config.stageConfigResource
   205  
   206          // CHANGE_ID is set only for pull requests
   207          if (env.CHANGE_ID) {
   208              List prActions = []
   209  
   210              //get trigger action from comment like /piper action
   211              def jenkinsUtils = new JenkinsUtils()
   212              def commentTriggerAction = jenkinsUtils.getIssueCommentTriggerAction()
   213  
   214              if (commentTriggerAction != null) prActions.add(commentTriggerAction)
   215  
   216              try {
   217                  prActions.addAll(pullRequest.getLabels().asList())
   218              } catch (ex) {
   219                  echo "[${STEP_NAME}] GitHub labels could not be retrieved from Pull Request, please make sure that credentials are maintained on multi-branch job."
   220              }
   221  
   222              setPullRequestStageStepActivation(script, config, prActions)
   223          }
   224  
   225          if (env.BRANCH_NAME == config.productiveBranch) {
   226              if (parameters.script.commonPipelineEnvironment.configuration.runStep?.get('Init')?.slackSendNotification) {
   227                  slackSendNotification script: script, message: "STARTED: Job <${env.BUILD_URL}|${URLDecoder.decode(env.JOB_NAME, java.nio.charset.StandardCharsets.UTF_8.name())} ${env.BUILD_DISPLAY_NAME}>", color: 'WARNING'
   228              }
   229  
   230              config.artifactPrepareVersion = true
   231          }
   232  
   233          if (config.artifactPrepareVersion) {
   234              Map prepareVersionParams = [script: script]
   235              if (config.inferBuildTool) {
   236                  prepareVersionParams.buildTool = buildTool
   237              }
   238              if(buildToolDesc) {
   239                  prepareVersionParams.filePath = buildToolDesc
   240              }
   241              if (env.ON_K8S && !config.runArtifactVersioningOnPod) {
   242                  // We force dockerImage: "" for the K8S case to avoid the execution of artifactPrepareVersion in a K8S Pod.
   243                  // Since artifactPrepareVersion may need the ".git" folder in order to push a tag, it would need to be part of the stashing.
   244                  // There are however problems with tar-ing this folder, which results in a failure to copy the stash back -- without a failure of the pipeline.
   245                  // This then also has the effect that any changes made to the build descriptors by the step (updated version) are not visible in the relevant stashes.
   246                  // In addition, a mvn executable is available on the Jenkins instance which can be used directly instead of executing the command in a container.
   247                  prepareVersionParams.dockerImage = ""
   248              }
   249              artifactPrepareVersion prepareVersionParams
   250          }
   251          pipelineStashFilesBeforeBuild script: script
   252      }
   253  }
   254  
   255  // Infer build tool descriptor (maven, npm, mta)
   256  private static String inferBuildToolDesc(script, buildTool) {
   257  
   258      String buildToolDesc = null
   259  
   260      switch (buildTool) {
   261          case 'maven':
   262              Map configBuild = script.commonPipelineEnvironment.getStepConfiguration('mavenBuild', 'Build')
   263              buildToolDesc = configBuild.pomPath? configBuild.pomPath : 'pom.xml'
   264              break
   265          case 'npm': // no parameter for the descriptor path
   266              buildToolDesc = 'package.json'
   267              break
   268          case 'mta':
   269              Map configBuild = script.commonPipelineEnvironment.getStepConfiguration('mtaBuild', 'Build')
   270              buildToolDesc = configBuild.source? configBuild.source + '/mta.yaml' : 'mta.yaml'
   271              break
   272          default:
   273              break;
   274      }
   275  
   276      return buildToolDesc
   277  }
   278  
   279  private String inferProjectName(Script script, String buildTool, String buildToolDesc) {
   280      switch (buildTool) {
   281          case 'maven':
   282              def pom = script.readMavenPom file: buildToolDesc
   283              return "${pom.groupId}-${pom.artifactId}"
   284          case 'npm':
   285              Map packageJson = script.readJSON file: buildToolDesc
   286              return packageJson.name
   287          case 'mta':
   288              Map mta = script.readYaml file: buildToolDesc
   289              return mta.ID
   290      }
   291  
   292      script.error "Cannot infer projectName. Project buildTool was none of the expected ones 'mta', 'maven', or 'npm'."
   293  }
   294  
   295  private checkBuildTool(String buildTool, String buildDescriptorPattern) {
   296      if (buildDescriptorPattern && !findFiles(glob: buildDescriptorPattern)) {
   297          error "[${STEP_NAME}] buildTool configuration '${buildTool}' does not fit to your project (buildDescriptorPattern: '${buildDescriptorPattern}'), please set buildTool as general setting in your .pipeline/config.yml correctly, see also https://sap.github.io/jenkins-library/configuration/"
   298      }
   299  }
   300  
   301  private void initStashConfiguration (script, stashSettings, customStashSettings, verbose) {
   302      Map stashConfiguration = null
   303      if (customStashSettings){
   304          stashConfiguration = readYaml(file: customStashSettings)
   305      }else{
   306          stashConfiguration = readYaml(text: libraryResource(stashSettings))
   307      }
   308      if (verbose) echo "Stash config: ${stashConfiguration}"
   309      script.commonPipelineEnvironment.configuration.stageStashes = stashConfiguration
   310  }
   311  
   312  private void setPullRequestStageStepActivation(script, config, List actions) {
   313  
   314      if (script.commonPipelineEnvironment.configuration.runStep == null)
   315          script.commonPipelineEnvironment.configuration.runStep = [:]
   316      if (script.commonPipelineEnvironment.configuration.runStep[config.pullRequestStageName] == null)
   317          script.commonPipelineEnvironment.configuration.runStep[config.pullRequestStageName] = [:]
   318  
   319      actions.each {action ->
   320          if (action.startsWith(config.labelPrefix))
   321              action = action.minus(config.labelPrefix)
   322  
   323          def stepName = config.stepMappings[action]
   324          if (stepName) {
   325              script.commonPipelineEnvironment.configuration.runStep."${config.pullRequestStageName}"."${stepName}" = true
   326          }
   327      }
   328  }