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 }