blob: 14bd19f0d5920b55abfdd84f989af4b4123d73bc [file] [log] [blame]
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +03001package com.mirantis.mcp
2
Sergey Kolekonov74a6b6e2019-06-28 11:45:47 +04003import org.jfrog.hudson.pipeline.common.types.ArtifactoryServer
4import org.jfrog.hudson.pipeline.common.types.buildInfo.BuildInfo
Sergey Kulanov91d8def2016-11-15 13:53:17 +02005
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +03006/**
7 * Return string of mandatory build properties for binaries
8 * User can also add some custom properties.
9 *
10 * @param customProperties a Array of Strings that should be added to mandatory props
11 * in format ["prop1=value1", "prop2=value2"]
12 * */
13def getBinaryBuildProperties(ArrayList customProperties) {
14 def namespace = "com.mirantis."
15 def properties = [
Sergey Kulanovc70f1c22016-11-16 13:05:20 +020016 "buildName=${env.JOB_NAME}",
17 "buildNumber=${env.BUILD_NUMBER}",
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030018 "gerritProject=${env.GERRIT_PROJECT}",
19 "gerritChangeNumber=${env.GERRIT_CHANGE_NUMBER}",
20 "gerritPatchsetNumber=${env.GERRIT_PATCHSET_NUMBER}",
21 "gerritChangeId=${env.GERRIT_CHANGE_ID}",
22 "gerritPatchsetRevision=${env.GERRIT_PATCHSET_REVISION}"
23 ]
24
25 if (customProperties) {
26 properties.addAll(customProperties)
27 }
28
29 def common = new com.mirantis.mcp.Common()
30
31 return common.constructString(properties, namespace, ";")
32}
33
34/**
Kirill Mashchenko1d225c22018-06-19 13:52:17 +030035 * Get URL to artifact(s) by properties
36 * Returns String(s) with URL to found artifact or null if nothing
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030037 *
38 * @param artifactoryURL String, an URL to Artifactory
39 * @param properties LinkedHashMap, a Hash of properties (key-value) which
40 * which should determine artifact in Artifactory
Kirill Mashchenko1d225c22018-06-19 13:52:17 +030041 * @param onlyLastItem Boolean, return only last URL if true(by default),
42 * else return list of all found artifact URLS
Sergey Kolekonov54c44842019-06-17 19:25:52 +040043 * @param repos ArrayList, a list of repositories to search in
Kirill Mashchenko1d225c22018-06-19 13:52:17 +030044 *
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030045 */
Sergey Kolekonov54c44842019-06-17 19:25:52 +040046def uriByProperties(String artifactoryURL, LinkedHashMap properties, Boolean onlyLastItem=true, ArrayList repos=[]) {
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030047 def key, value
48 def properties_str = ''
49 for (int i = 0; i < properties.size(); i++) {
50 // avoid serialization errors
Kirill Mashchenko56c8ff32018-06-28 03:01:34 +030051 key = properties.entrySet().toArray()[i].key.trim()
52 value = properties.entrySet().toArray()[i].value.trim()
53 properties_str += /${key}=${value}&/
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030054 }
Sergey Kolekonov54c44842019-06-17 19:25:52 +040055 def repos_str = (repos) ? repos.join(',') : ''
56 def search_url
57 if (repos_str) {
58 search_url = "${artifactoryURL}/api/search/prop?${properties_str}&repos=${repos_str}"
59 } else {
60 search_url = "${artifactoryURL}/api/search/prop?${properties_str}"
61 }
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030062
Kirill Mashchenko56c8ff32018-06-28 03:01:34 +030063 def result = sh(script: /curl -X GET '${search_url}'/,
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030064 returnStdout: true).trim()
65 def content = new groovy.json.JsonSlurperClassic().parseText(result)
66 def uri = content.get("results")
67 if (uri) {
Kirill Mashchenko1d225c22018-06-19 13:52:17 +030068 if (onlyLastItem) {
69 return uri.last().get("uri")
70 } else {
71 res = []
72 uri.each {it ->
73 res.add(it.get("uri"))
74 }
75 return res
76 }
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030077 } else {
78 return null
79 }
80}
81
Kirill Mashchenko1d225c22018-06-19 13:52:17 +030082
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030083/**
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +030084 * Set properties for artifact in Artifactory repo
85 *
86 * @param artifactUrl String, an URL to artifact in Artifactory repo
87 * @param properties LinkedHashMap, a Hash of properties (key-value) which
88 * should be assigned for choosen artifact
89 * @param recursive Boolean, if artifact_url is a directory, whether to set
90 * properties recursively or not
91 */
92def setProperties(String artifactUrl, LinkedHashMap properties, Boolean recursive = false) {
93 def properties_str = 'properties='
94 def key, value
95 if (recursive) {
96 recursive = 'recursive=1'
97 } else {
98 recursive = 'recursive=0'
99 }
Alexander Evseevbd40ef92017-10-18 12:24:45 +0300100 properties_str += properties.collect({"${it.key}=${it.value}"}).join(';')
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300101 def url = "${artifactUrl}?${properties_str}&${recursive}"
102 withCredentials([
103 [$class : 'UsernamePasswordMultiBinding',
104 credentialsId : 'artifactory',
105 passwordVariable: 'ARTIFACTORY_PASSWORD',
106 usernameVariable: 'ARTIFACTORY_LOGIN']
107 ]) {
108 sh "bash -c \"curl -X PUT -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} \'${url}\'\""
109 }
110}
111
112/**
Sergey Kolekonov76c17f52019-09-09 16:55:01 +0400113 * Create an empty directory in Artifactory repo
114 *
115 * @param artifactoryURL String, an URL to Artifactory
116 * @param path String, a path to the desired directory including repository name
117 * @param dir String, desired directory name
118 */
119def createDir (String artifactoryURL, String path, String dir) {
120 def url = "${artifactoryURL}/${path}/${dir}/"
121 withCredentials([
122 [$class : 'UsernamePasswordMultiBinding',
123 credentialsId : 'artifactory',
124 passwordVariable: 'ARTIFACTORY_PASSWORD',
125 usernameVariable: 'ARTIFACTORY_LOGIN']
126 ]) {
127 sh "bash -c \"curl -X PUT -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} \'${url}\'\""
128 }
129}
130
131/**
Sergey Kolekonovce616712019-09-10 16:09:23 +0400132 * Move/copy an artifact or a folder to the specified destination
133 *
134 * @param artifactoryURL String, an URL to Artifactory
135 * @param sourcePath String, a source path to the artifact including repository name
136 * @param dstPath String, a destination path to the artifact including repository name
137 * @param copy boolean, whether to copy or move the item, default is move
138 * @param dryRun boolean, whether to perform dry run on not, default is false
139 */
140def moveItem (String artifactoryURL, String sourcePath, String dstPath, boolean copy = false, boolean dryRun = false) {
141 def url = "${artifactoryURL}/api/${copy ? 'copy' : 'move'}/${sourcePath}?to=/${dstPath}&dry=${dryRun ? '1' : '0'}"
Alexandr Lovtsov066f4882021-01-18 17:29:26 +0300142 def http = new com.mirantis.mk.Http()
143 return http.doPost(url, 'artifactory')
Sergey Kolekonovce616712019-09-10 16:09:23 +0400144}
145
146/**
147 * Recursively delete the specified artifact or a folder
148 *
149 * @param artifactoryURL String, an URL to Artifactory
150 * @param itemPath String, a source path to the item including repository name
151 */
152def deleteItem (String artifactoryURL, String itemPath) {
153 def url = "${artifactoryURL}/${itemPath}"
Alexandr Lovtsov89d24a52021-01-28 17:41:14 +0300154 def http = new com.mirantis.mk.Http()
155 return http.doDelete(url, 'artifactory')
Sergey Kolekonovce616712019-09-10 16:09:23 +0400156}
157
158/**
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300159 * Get properties for specified artifact in Artifactory
160 * Returns LinkedHashMap of properties
161 *
162 * @param artifactUrl String, an URL to artifact in Artifactory repo
163 */
164def getPropertiesForArtifact(String artifactUrl) {
165 def url = "${artifactUrl}?properties"
166 def result
167 withCredentials([
168 [$class : 'UsernamePasswordMultiBinding',
169 credentialsId : 'artifactory',
170 passwordVariable: 'ARTIFACTORY_PASSWORD',
171 usernameVariable: 'ARTIFACTORY_LOGIN']
172 ]) {
173 result = sh(script: "bash -c \"curl -X GET -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} \'${url}\'\"",
174 returnStdout: true).trim()
175 }
176 def properties = new groovy.json.JsonSlurperClassic().parseText(result)
177 return properties.get("properties")
178}
179
180/**
vnaumov5b2dccf2019-10-10 22:12:15 +0200181 * Get checksums of artifact
182 *
183 * @param artifactoryUrl String, an URL ofArtifactory repo
184 * @param repoName Artifact repository name
185 * @param artifactName Artifactory object name
186 * @param checksumType Type of checksum (default md5)
187 */
188
189def getArtifactChecksum(artifactoryUrl, repoName, artifactName, checksumType = 'md5'){
190 def url = "${artifactoryUrl}/api/storage/${repoName}/${artifactName}"
191 withCredentials([
192 [$class : 'UsernamePasswordMultiBinding',
193 credentialsId : 'artifactory',
194 passwordVariable: 'ARTIFACTORY_PASSWORD',
195 usernameVariable: 'ARTIFACTORY_LOGIN']
196 ]) {
197 def result = sh(script: "bash -c \"curl -X GET -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} \'${url}\'\"",
198 returnStdout: true).trim()
199 }
200
201 def properties = new groovy.json.JsonSlurperClassic().parseText(result)
202 return properties['checksums'][checksumType]
203}
204
205/**
Denis Egorenkoedd21dc2018-11-23 17:38:17 +0400206 * Check if image with tag exist by provided path
207 * Returns true or false
208 *
209 * @param artifactoryURL String, an URL to Artifactory
210 * @param imageRepo String, path to image to check, includes repo path and image name
211 * @param tag String, tag to check
212 * @param artifactoryCreds String, artifactory creds to use. Optional, default is 'artifactory'
213 */
214def imageExists(String artifactoryURL, String imageRepo, String tag, String artifactoryCreds = 'artifactory') {
Sergey Otpuschennikov406778f2019-10-10 14:49:40 +0400215 def url = artifactoryURL + '/v2/' + imageRepo + '/manifests/' + tag
Denis Egorenkoedd21dc2018-11-23 17:38:17 +0400216 def result
217 withCredentials([
218 [$class : 'UsernamePasswordMultiBinding',
219 credentialsId : artifactoryCreds,
220 passwordVariable: 'ARTIFACTORY_PASSWORD',
221 usernameVariable: 'ARTIFACTORY_LOGIN']
222 ]) {
223 result = sh(script: "bash -c \"curl -X GET -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} \'${url}\'\"",
224 returnStdout: true).trim()
225 }
226 def properties = new groovy.json.JsonSlurperClassic().parseText(result)
227 return properties.get("errors") ? false : true
228}
229
230/**
Denis Egorenko7c0abfe2017-02-14 15:42:02 +0400231 * Find docker images by tag
232 * Returns Array of image' hashes with names as full path in @repo
233 *
234 * Example:
235 *
236 * [ {
237 * "path" : "mirantis/ccp/ci-cd/gerrit-manage/test"
238 * },
239 * {
240 * "path" : "mirantis/ccp/ci-cd/gerrit/test"
241 * }
242 * ]
243 *
244 * @param artifactoryURL String, an URL to Artifactory
245 * @param repo String, a name of repo where should be executed search
246 * @param tag String, tag of searched image
247 */
248def getImagesByTag(String artifactoryURL, String repo, String tag) {
249 def url = "${artifactoryURL}/api/search/aql"
250 def result
251 writeFile file: "query",
252 text: """\
253 items.find(
254 {
255 \"repo\": \"${repo}\",
256 \"@docker.manifest\": { \"\$match\" : \"${tag}*\" }
257 }
258 ).
259 include(\"path\")
260 """.stripIndent()
261 withCredentials([
262 [$class: 'UsernamePasswordMultiBinding',
263 credentialsId: 'artifactory',
264 passwordVariable: 'ARTIFACTORY_PASSWORD',
265 usernameVariable: 'ARTIFACTORY_LOGIN']
266 ]) {
267 result = sh(script: "bash -c \"curl -X POST -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} -d @query \'${url}\'\"",
268 returnStdout: true).trim()
269 }
270 def images = new groovy.json.JsonSlurperClassic().parseText(result)
271 return images.get("results")
272}
273
274/**
Alexandr Lovtsova0295432021-01-28 17:20:32 +0300275 * Convert Mirantis docker image url/path to Mirantis artifactory path ready for use in API calls
276 *
277 * For example:
278 * 'docker-dev-kaas-local.docker.mirantis.net/mirantis/kaas/si-test:master' -> 'docker-dev-kaas-local/mirantis/kaas/si-test/master'
279 *
280 */
281def dockerImageToArtifactoryPath(String image) {
282 List imageParts = image.tokenize('/')
283 String repoName = imageParts[0].tokenize('.')[0]
284 String namespace = imageParts[1..-2].join('/')
285 String imageName = imageParts[-1].tokenize(':')[0]
286 String imageTag = imageParts[-1].tokenize(':')[1]
287
288 return [repoName, namespace, imageName, imageTag].join('/')
289}
290
291/**
Alexandr Lovtsov8fb5d7c2021-01-28 17:42:24 +0300292 * Copy docker image from one url to another
293 *
294 * @param srcImage String, Mirantis URL/path for docker image to copy from
295 * @param dstImage String, Mirantis URL/path for docker image to copy to
296 */
297def copyDockerImage(String srcImage, String dstImage) {
298 def artifactoryServer = Artifactory.server(env.ARTIFACTORY_SERVER ?: 'mcp-ci')
299 String srcPath = dockerImageToArtifactoryPath(srcImage)
300 String dstPath = dockerImageToArtifactoryPath(dstImage)
301
302 return moveItem(artifactoryServer.getUrl(), srcPath, dstPath, true)
303}
304
305/**
306 * Delete docker image on Mirantis's artifactory
307 *
308 * @param image String, Mirantis URL/path for docker image to delete
309 */
310def deleteDockerImage(String image) {
311 def artifactoryServer = Artifactory.server(env.ARTIFACTORY_SERVER ?: 'mcp-ci')
312
313 return deleteItem(artifactoryServer.getUrl() + '/artifactory', dockerImageToArtifactoryPath(image))
314}
315
316/**
Alexandr Lovtsovd3023d02021-05-12 15:54:44 +0300317 * Upload list of docker images to Artifactory
318 *
319 * @param server ArtifactoryServer, the instance of Artifactory server
320 * @param registry String, the name of Docker registry
321 * @param images List[Map], list of maps where each map consist of following fields:
322 * {
323 * 'repository': String '...', // (mandatory) The name of Artifactory Docker repository
324 * 'name': String '...', // (mandatory) docker image name
325 * 'tag': String '...', // (mandatory) docker image tag/version
326 * 'buildInfo': BuildInfo '...', // (optional) the instance of a build-info object which
327 * can be published, if it's not null (default),
328 * then we publish BuildInfo,
329 * 'properties': LinkedHashMap '...', // (optional) Map of artifactory properties to set for image,
330 * if not provided, then some common properties will be set
331 * }
332 *
333 */
334def uploadImagesToArtifactory(ArtifactoryServer server, String registry, List images) {
335 // Check that every provided image's specs contain mandatory fields (name, tag, repository)
336 images.each {
337 if (!(it.name && it.tag && it.repository)) {
338 error("Incorrect image upload spec: ${it}")
339 }
340 }
341
342 // TODO Switch to Artifactoy image' pushing mechanism once we will
343 // prepare automatical way for enabling artifactory build-proxy
344 //def artDocker
345 withCredentials([[
346 $class: 'UsernamePasswordMultiBinding',
347 credentialsId: env.ARTIFACTORY_CREDENTIALS_ID ?: 'artifactory',
348 passwordVariable: 'ARTIFACTORY_PASSWORD',
349 usernameVariable: 'ARTIFACTORY_LOGIN',
350 ]]) {
351 sh ("docker login -u ${ARTIFACTORY_LOGIN} -p ${ARTIFACTORY_PASSWORD} ${registry}")
352 //artDocker = Artifactory.docker("${env.ARTIFACTORY_LOGIN}", "${env.ARTIFACTORY_PASSWORD}")
353 }
354
355 images.each {
356 String image = it.name // mandatory
357 String version = it.tag // mandatory
358 String repository = it.repository // mandatory
359
360 sh ("docker push ${registry}/${image}:${version}")
361 //artDocker.push("${registry}/${image}:${version}", repository)
362 def image_url = server.getUrl() + "/api/storage/${repository}/${image}/${version}"
363
364 LinkedHashMap properties = it.get('properties')
365 if ( ! properties ) {
366 properties = [
367 'com.mirantis.buildName':"${env.JOB_NAME}",
368 'com.mirantis.buildNumber': "${env.BUILD_NUMBER}",
369 'com.mirantis.gerritProject': "${env.GERRIT_PROJECT}",
370 'com.mirantis.gerritChangeNumber': "${env.GERRIT_CHANGE_NUMBER}",
371 'com.mirantis.gerritPatchsetNumber': "${env.GERRIT_PATCHSET_NUMBER}",
372 'com.mirantis.gerritChangeId': "${env.GERRIT_CHANGE_ID}",
373 'com.mirantis.gerritPatchsetRevision': "${env.GERRIT_PATCHSET_REVISION}",
374 'com.mirantis.targetImg': "${image}",
375 'com.mirantis.targetTag': "${version}"
376 ]
377 }
378
379 setProperties(image_url, properties)
380
381 BuildInfo buildInfo = it.get('buildInfo')
382 if ( buildInfo != null ) {
383 buildInfo.env.capture = true
384 buildInfo.env.filter.addInclude("*")
385 buildInfo.env.filter.addExclude("*PASSWORD*")
386 buildInfo.env.filter.addExclude("*password*")
387 buildInfo.env.collect()
388 server.publishBuildInfo(buildInfo)
389 }
390 }
391}
392/**
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300393 * Upload docker image to Artifactory
394 *
Sergey Kulanov8cd6d222016-11-17 13:42:47 +0200395 * @param server ArtifactoryServer, the instance of Artifactory server
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300396 * @param registry String, the name of Docker registry
397 * @param image String, Docker image name
398 * @param version String, Docker image version
399 * @param repository String, The name of Artifactory Docker repository
Sergey Kulanov8cd6d222016-11-17 13:42:47 +0200400 * @param buildInfo BuildInfo, the instance of a build-info object which can be published,
401 * if defined, then we publish BuildInfo
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300402 */
Sergey Kulanov8cd6d222016-11-17 13:42:47 +0200403def uploadImageToArtifactory (ArtifactoryServer server, String registry, String image,
404 String version, String repository,
Dmitry Burmistrov6ee39522017-05-22 12:46:25 +0400405 BuildInfo buildInfo = null,
406 LinkedHashMap properties = null) {
Alexandr Lovtsovd3023d02021-05-12 15:54:44 +0300407 Map images = [
408 'repository': repository,
409 'name': image,
410 'tag': version,
411 'buildInfo': buildInfo,
412 'properties': properties,
413 ]
414 uploadImagesToArtifactory(server, registry, [images])
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300415}
416
417/**
418 * Upload binaries to Artifactory
419 *
420 * @param server ArtifactoryServer, the instance of Artifactory server
421 * @param buildInfo BuildInfo, the instance of a build-info object which can be published
422 * @param uploadSpec String, a spec which is a JSON file that specifies which files should be
423 * uploaded or downloaded and the target path
424 * @param publishInfo Boolean, whether publish a build-info object to Artifactory
425 */
Sergey Kulanov91d8def2016-11-15 13:53:17 +0200426def uploadBinariesToArtifactory (ArtifactoryServer server, BuildInfo buildInfo, String uploadSpec,
427 Boolean publishInfo = false) {
Jakub Josefbefcf6c2017-11-14 18:03:10 +0100428 server.upload(uploadSpec, buildInfo)
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300429
430 if ( publishInfo ) {
431 buildInfo.env.capture = true
432 buildInfo.env.filter.addInclude("*")
433 buildInfo.env.filter.addExclude("*PASSWORD*")
434 buildInfo.env.filter.addExclude("*password*")
435 buildInfo.env.collect()
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300436 server.publishBuildInfo(buildInfo)
437 }
438}
439
440/**
441 * Promote Docker image artifact to release repo
442 *
443 * @param artifactoryURL String, an URL to Artifactory
444 * @param artifactoryDevRepo String, the source dev repository name
445 * @param artifactoryProdRepo String, the target repository for the move or copy
446 * @param dockerRepo String, the docker repository name to promote
447 * @param artifactTag String, an image tag name to promote
448 * @param targetTag String, target tag to assign the image after promotion
449 * @param copy Boolean, an optional value to set whether to copy instead of move
450 * Default: false
451 */
452def promoteDockerArtifact(String artifactoryURL, String artifactoryDevRepo,
453 String artifactoryProdRepo, String dockerRepo,
454 String artifactTag, String targetTag, Boolean copy = false) {
455 def url = "${artifactoryURL}/api/docker/${artifactoryDevRepo}/v2/promote"
Dmitry Burmistrov5deaa7d2017-05-30 17:12:54 +0400456 String queryFile = UUID.randomUUID().toString()
Dmitry Burmistrov97beb9b2017-05-29 17:21:34 +0400457 writeFile file: queryFile,
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300458 text: """{
459 \"targetRepo\": \"${artifactoryProdRepo}\",
460 \"dockerRepository\": \"${dockerRepo}\",
461 \"tag\": \"${artifactTag}\",
462 \"targetTag\" : \"${targetTag}\",
463 \"copy\": \"${copy}\"
464 }""".stripIndent()
Dmitry Burmistrov97beb9b2017-05-29 17:21:34 +0400465 sh "cat ${queryFile}"
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300466 withCredentials([
467 [$class : 'UsernamePasswordMultiBinding',
468 credentialsId : 'artifactory',
469 passwordVariable: 'ARTIFACTORY_PASSWORD',
470 usernameVariable: 'ARTIFACTORY_LOGIN']
471 ]) {
Sergey Reshetnyakf0775fb2018-06-28 14:54:01 +0400472 sh "bash -c \"curl --fail -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} -H \"Content-Type:application/json\" -X POST -d @${queryFile} ${url}\""
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300473 }
Dmitry Burmistrov97beb9b2017-05-29 17:21:34 +0400474 sh "rm -v ${queryFile}"
Ruslan Kamaldinov90d4e672016-11-11 18:31:00 +0300475}
Denis Egorenko60f47c12019-03-11 20:54:13 +0400476
477/**
478 * Save job artifacts to Artifactory server if available.
479 * Returns link to Artifactory repo, where saved job artifacts.
480 *
481 * @param config LinkedHashMap which contains next parameters:
482 * @param artifactory String, Artifactory server id
483 * @param artifactoryRepo String, repo to save job artifacts
484 * @param buildProps ArrayList, additional props for saved artifacts. Optional, default: []
485 * @param artifactory_not_found_fail Boolean, whether to fail if provided artifactory
486 * id is not found or just print warning message. Optional, default: false
487 */
488def uploadJobArtifactsToArtifactory(LinkedHashMap config) {
489 def common = new com.mirantis.mk.Common()
490 def artifactsDescription = ''
491 def artifactoryServer
Dmitry Tyzhnenko9ade0722020-03-31 13:17:54 +0300492
493 if (!config.containsKey('deleteArtifacts')) {
494 config.deleteArtifacts = true // default behavior before add the flag
495 }
496
Denis Egorenko60f47c12019-03-11 20:54:13 +0400497 try {
498 artifactoryServer = Artifactory.server(config.get('artifactory'))
499 } catch (Exception e) {
500 if (config.get('artifactory_not_found_fail', false)) {
501 throw e
502 } else {
503 common.warningMsg(e)
504 return "Artifactory server is not found. Can't save artifacts in Artifactory."
505 }
506 }
Dmitry Tyzhnenko812673a2020-03-26 21:59:14 +0200507 def artifactDir = config.get('artifactDir') ?: 'cur_build_artifacts'
Denis Egorenko60f47c12019-03-11 20:54:13 +0400508 def user = ''
509 wrap([$class: 'BuildUser']) {
510 user = env.BUILD_USER_ID
511 }
512 dir(artifactDir) {
513 try {
Denis Egorenko5fc40f82019-03-13 18:35:51 +0400514 unarchive(mapping: ['**/*' : '.'])
Denis Egorenko60f47c12019-03-11 20:54:13 +0400515 // Mandatory and additional properties
516 def properties = getBinaryBuildProperties(config.get('buildProps', []) << "buildUser=${user}")
Dmitry Tyzhnenko812673a2020-03-26 21:59:14 +0200517 def pattern = config.get('artifactPattern') ?: '*'
Denis Egorenko60f47c12019-03-11 20:54:13 +0400518
519 // Build Artifactory spec object
520 def uploadSpec = """{
521 "files":
522 [
523 {
Dmitry Tyzhnenko812673a2020-03-26 21:59:14 +0200524 "pattern": "${pattern}",
Denis Egorenko60f47c12019-03-11 20:54:13 +0400525 "target": "${config.get('artifactoryRepo')}/",
Denis Egorenko850f56a2019-03-13 20:44:43 +0400526 "flat": false,
Denis Egorenko60f47c12019-03-11 20:54:13 +0400527 "props": "${properties}"
528 }
529 ]
530 }"""
531
532 artifactoryServer.upload(uploadSpec, newBuildInfo())
533 def linkUrl = "${artifactoryServer.getUrl()}/artifactory/${config.get('artifactoryRepo')}"
534 artifactsDescription = "Job artifacts uploaded to Artifactory: <a href=\"${linkUrl}\">${linkUrl}</a>"
535 } catch (Exception e) {
536 if (e =~ /no artifacts/) {
537 artifactsDescription = 'Build has no artifacts saved.'
538 } else {
539 throw e
540 }
541 } finally {
Dmitry Tyzhnenko9ade0722020-03-31 13:17:54 +0300542 if (config.deleteArtifacts) {
543 deleteDir()
544 }
Denis Egorenko60f47c12019-03-11 20:54:13 +0400545 }
546 }
547 return artifactsDescription
548}
Dmitry Tyzhnenko39cf09c2020-05-05 20:08:52 +0300549
550/**
551 * Save custom artifacts to Artifactory server if available.
552 * Returns link to Artifactory repo, where saved artifacts.
553 *
554 * @param config LinkedHashMap which contains next parameters:
555 * @param artifactory String, Artifactory server id
556 * @param artifactoryRepo String, repo to save job artifacts
557 * @param buildProps ArrayList, additional props for saved artifacts. Optional, default: []
558 * @param artifactory_not_found_fail Boolean, whether to fail if provided artifactory
559 * id is not found or just print warning message. Optional, default: false
560 */
561def uploadArtifactsToArtifactory(LinkedHashMap config) {
562 def common = new com.mirantis.mk.Common()
563 def artifactsDescription = ''
564 def artifactoryServer
565
566 try {
567 artifactoryServer = Artifactory.server(config.get('artifactory'))
568 } catch (Exception e) {
569 if (config.get('artifactory_not_found_fail', false)) {
570 throw e
571 } else {
572 common.warningMsg(e)
573 return "Artifactory server is not found. Can't save artifacts in Artifactory."
574 }
575 }
576 def user = ''
577 wrap([$class: 'BuildUser']) {
578 user = env.BUILD_USER_ID
579 }
580 try {
581 // Mandatory and additional properties
582 def properties = getBinaryBuildProperties(config.get('buildProps', []) << "buildUser=${user}")
583 def pattern = config.get('artifactPattern') ?: '*'
584
585 // Build Artifactory spec object
586 def uploadSpec = """{
587 "files":
588 [
589 {
590 "pattern": "${pattern}",
591 "target": "${config.get('artifactoryRepo')}/",
592 "flat": false,
593 "props": "${properties}"
594 }
595 ]
596 }"""
597
598 artifactoryServer.upload(uploadSpec, newBuildInfo())
Alexandr Lovtsov9293d992021-01-19 19:55:41 +0300599 def linkUrl = "${artifactoryServer.getUrl()}/${config.get('artifactoryRepo')}"
Dmitry Tyzhnenko39cf09c2020-05-05 20:08:52 +0300600 artifactsDescription = "Job artifacts uploaded to Artifactory: <a href=\"${linkUrl}\">${linkUrl}</a>"
601 } catch (Exception e) {
602 if (e =~ /no artifacts/) {
603 artifactsDescription = 'Build has no artifacts saved.'
604 } else {
605 throw e
606 }
607 }
608 return artifactsDescription
609}
Andrii Baraniukf9992ca2023-05-04 11:43:44 +0300610
611/**
612 * Get artifactory server object
613 *
614 * @param serverName Artifactory server name
615 */
616def getArtifactoryServer(serverName = ''){
617 if (!serverName) {
618 error ("Artifactory serverName must be specified")
619 }
620 return Artifactory.server(serverName)
621}