blob: 6f4d788c34233d2e4f1d0c2df7f38b12c40178b0 [file] [log] [blame]
Sergey Kulanov1bbd3612016-09-30 11:40:11 +03001package ci.mcp
2
3/**
4 * https://issues.jenkins-ci.org/browse/JENKINS-26481
5 * fix groovy List.collect()
Sergey Kulanov56d0d052016-10-13 15:48:56 +03006**/
7@NonCPS
8def constructString(ArrayList options, String keyOption, String separator = " ") {
9 return options.collect{ keyOption + it }.join(separator).replaceAll("\n", "")
10}
11
12/**
Sergey Kulanov1bbd3612016-09-30 11:40:11 +030013 * Build command line options, e.g:
14 * cmd_opts=["a=b", "c=d", "e=f"]
15 * key = "--build-arg "
16 * separator = " "
17 * def options = getCommandBuilder(cmd_opts, key, separator)
18 * println options
19 * > --build-arg a=b --build-arg c=d --build-arg e=f
20 *
21 * @param options List of Strings (options that should be populated)
22 * @param keyOption key that should be added before each option
23 * @param separator Separator between key+Option pairs
24 */
Sergey Kulanov1bbd3612016-09-30 11:40:11 +030025def getCommandBuilder(ArrayList options, String keyOption, String separator = " ") {
Sergey Kulanov56d0d052016-10-13 15:48:56 +030026 return constructString(options, keyOption)
27}
28
29/**
Sergey Kulanov20c8b132016-11-02 13:24:32 +020030* Add LABEL to the end of the Dockerfile
31* User can also add some custom properties
32*
33* @param dockerfilePath is the path to Dockerfile, the default is ./Dockerfile
34* @param customProperties a Array of Strings that should be added to mandatory props
35* in format ["prop1=value1", "prop2=value2"]
36**/
37def setDockerfileLabels(String dockerfilePath = "./Dockerfile", ArrayList customProperties = null){
38
39 if (!fileExists(dockerfilePath)){
40 throw new RuntimeException("Unable to add LABEL to Dockerfile, ${dockerfilePath} doesn't exists")
41 }
42 echo "Updating ${dockerfilePath}"
43
44 def namespace = "com.mirantis.image-specs."
45 def properties = [
46 "gerritProject=${env.GERRIT_PROJECT}",
47 "gerritChangeNumber=${env.GERRIT_CHANGE_NUMBER}",
48 "gerritPatchsetNumber=${env.GERRIT_PATCHSET_NUMBER}",
49 "gerritChangeId=${env.GERRIT_CHANGE_ID}",
50 "gerritPatchsetRevision=${env.GERRIT_PATCHSET_REVISION}"
51 ]
52
53 if (customProperties != null){
54 properties.addAll(customProperties)
55 }
56
57 def metadata = constructString(properties, namespace, " ")
58 sh """
59 cat <<EOF>> ${dockerfilePath}
60 # Apply additional build metadata
61 LABEL ${metadata}
62 """
63 return metadata
64}
65
66/**
Sergey Kulanov56d0d052016-10-13 15:48:56 +030067* Return string of mandatory build properties for binaries
68* User can also add some custom properties
69*
70* @param customProperties a Array of Strings that should be added to mandatory props
71* in format ["prop1=value1", "prop2=value2"]
72**/
73def getBinaryBuildProperties(ArrayList customProperties) {
74
75 def namespace = "com.mirantis."
76 def properties = [
77 "gerritProject=${env.GERRIT_PROJECT}",
78 "gerritChangeNumber=${env.GERRIT_CHANGE_NUMBER}",
79 "gerritPatchsetNumber=${env.GERRIT_PATCHSET_NUMBER}",
80 "gerritChangeId=${env.GERRIT_CHANGE_ID}",
Sergey Kulanov64bc88a2016-10-18 16:26:34 +030081 "gerritPatchsetRevision=${env.GERRIT_PATCHSET_REVISION}"
Sergey Kulanov56d0d052016-10-13 15:48:56 +030082 ]
83
84 if (customProperties){
85 properties.addAll(customProperties)
86 }
87
88 return constructString(properties, namespace, ";")
Sergey Kulanov1bbd3612016-09-30 11:40:11 +030089}
Sergey Kulanov1835afe2016-10-19 16:53:14 +030090
91/**
92 * Parse HEAD of current directory and return commit hash
93 */
94def getGitCommit() {
95 git_commit = sh (
96 script: 'git rev-parse HEAD',
97 returnStdout: true
98 ).trim()
99 return git_commit
100}
Denis Egorenkoe3552682016-10-18 13:29:29 +0300101
102/**
Sergey Kulanov4f2fbcb2016-10-28 14:25:20 +0300103 * Generate current timestamp
104 *
105 * @param format Defaults to yyyyMMddHHmmss
106 */
107def getDatetime(format="yyyyMMddHHmmss") {
108 def now = new Date();
109 return now.format(format, TimeZone.getTimeZone('UTC'));
110}
111
112/**
Denis Egorenkoe3552682016-10-18 13:29:29 +0300113* Get URL to artifact by properties
114* Returns String with URL to found artifact or null if nothing
115*
116* @param artifactoryURL String, an URL to Artifactory
117* @param properties LinkedHashMap, a Hash of properties (key-value) which
118* which should determine artifact in Artifactory
119*/
120def uriByProperties(String artifactoryURL, LinkedHashMap properties) {
121 def key, value
122 def properties_str = ''
123 for ( int i = 0; i < properties.size(); i++ ) {
124 // avoid serialization errors
125 key = properties.entrySet().toArray()[i].key
126 value = properties.entrySet().toArray()[i].value
127 properties_str += "${key}=${value}&"
128 }
129 def search_url = "${artifactoryURL}/api/search/prop?${properties_str}"
130
131 def result = sh(script: "bash -c \"curl -X GET \'${search_url}\'\"",
132 returnStdout: true).trim()
133 def content = new groovy.json.JsonSlurperClassic().parseText(result)
134 def uri = content.get("results")
135 if ( uri ) {
136 return uri.last().get("uri")
137 } else {
138 return null
139 }
140}
141
142/**
Sergey Kulanovd4e31282016-11-08 17:39:19 +0200143* Get URL to artifact by properties
144* Returns String with URL to found artifact or null if nothing
145*
146* @param artifactoryURL String, an URL to Artifactory
147* @param properties String, URI in format prop1=val1&prop2=val2&prop3val3
148* which should determine artifact in Artifactory
149*/
150def uriByProperties(String artifactoryURL, String properties) {
151
152 def search_url = "${artifactoryURL}/api/search/prop?${properties}"
153
154 def result = sh(script: "bash -c \"curl -X GET \'${search_url}\'\"",
155 returnStdout: true).trim()
156 def content = new groovy.json.JsonSlurperClassic().parseText(result)
157 def uri = content.get("results")
158 if ( uri ) {
159 return uri.last().get("uri")
160 } else {
161 return null
162 }
163}
164
165/**
Denis Egorenkoe3552682016-10-18 13:29:29 +0300166* Set properties for artifact in Artifactory repo
167*
168* @param artifactUrl String, an URL to artifact in Artifactory repo
169* @param properties LinkedHashMap, a Hash of properties (key-value) which
170* should be assigned for choosen artifact
171* @param recursive Boolean, if artifact_url is a directory, whether to set
172* properties recursively or not
173*/
174def setProperties (String artifactUrl, LinkedHashMap properties, Boolean recursive=false) {
175 def properties_str = 'properties='
176 def key,value
177 if (recursive) {
178 recursive = 'recursive=1'
179 } else {
180 recursive = 'recursive=0'
181 }
182 for ( int i = 0; i < properties.size(); i++ ) {
183 // avoid serialization errors
184 key = properties.entrySet().toArray()[i].key
185 value = properties.entrySet().toArray()[i].value
186 properties_str += "${key}=${value}|"
187 }
188 def url = "${artifactUrl}?${properties_str}&${recursive}"
189 withCredentials([
190 [$class: 'UsernamePasswordMultiBinding',
191 credentialsId: 'artifactory',
192 passwordVariable: 'ARTIFACTORY_PASSWORD',
193 usernameVariable: 'ARTIFACTORY_LOGIN']
194 ]) {
195 sh "bash -c \"curl -X PUT -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} \'${url}\'\""
196 }
197}
198
199/**
200* Get properties for specified artifact in Artifactory
201* Returns LinkedHashMap of properties
202*
203* @param artifactUrl String, an URL to artifact in Artifactory repo
204*/
205def getPropertiesForArtifact(String artifactUrl) {
206 def url = "${artifactUrl}?properties"
207 def result
208 withCredentials([
209 [$class: 'UsernamePasswordMultiBinding',
210 credentialsId: 'artifactory',
211 passwordVariable: 'ARTIFACTORY_PASSWORD',
212 usernameVariable: 'ARTIFACTORY_LOGIN']
213 ]) {
214 result = sh(script: "bash -c \"curl -X GET -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} \'${url}\'\"",
215 returnStdout: true).trim()
216 }
217 def properties = new groovy.json.JsonSlurperClassic().parseText(result)
218 return properties.get("properties")
219}
220
221/**
222* Upload docker image to Artifactory
223*
224* @param artifactoryURL String, an URL to Artifactory
225* @param registry String, the name of Docker registry
226* @param image String, Docker image name
227* @param version String, Docker image version
228* @param repository String, The name of Artifactory Docker repository
229*/
230def uploadImageToArtifactory (String artifactoryURL, String registry, String image,
231 String version, String repository) {
232 // TODO Switch to Artifactoy image' pushing mechanism once we will
233 // prepare automatical way for enabling artifactory build-proxy
234 //def artDocker
235 withCredentials([
236 [$class: 'UsernamePasswordMultiBinding',
237 credentialsId: 'artifactory',
238 passwordVariable: 'ARTIFACTORY_PASSWORD',
239 usernameVariable: 'ARTIFACTORY_LOGIN']
240 ]) {
241 sh ("docker login -u ${ARTIFACTORY_LOGIN} -p ${ARTIFACTORY_PASSWORD} ${registry}")
242 //artDocker = Artifactory.docker("${env.ARTIFACTORY_LOGIN}", "${env.ARTIFACTORY_PASSWORD}")
243 }
244
245 sh ("docker push ${registry}/${image}:${version}")
246 //artDocker.push("${registry}/${image}:${version}", "${repository}")
247 def image_url = "${artifactoryURL}/api/storage/${repository}/${image}/${version}"
248
249 def properties = ['com.mirantis.build_name':"${env.JOB_NAME}",
250 'com.mirantis.build_id': "${env.BUILD_NUMBER}",
251 'com.mirantis.changeid': "${env.GERRIT_CHANGE_ID}",
252 'com.mirantis.patchset_number': "${env.GERRIT_PATCHSET_NUMBER}",
253 'com.mirantis.target_tag': "${version}"]
254 setProperties(image_url, properties)
255}
256
257/**
258* Upload binaries to Artifactory
259*
260* @param server ArtifactoryServer, the instance of Artifactory server
261* @param buildInfo BuildInfo, the instance of a build-info object which can be published
262* @param uploadSpec String, a spec which is a JSON file that specifies which files should be
263* uploaded or downloaded and the target path
264* @param publishInfo Boolean, whether publish a build-info object to Artifactory
265*/
266def uploadBinariesToArtifactory (server, buildInfo, String uploadSpec,
267 Boolean publishInfo=false) {
268 buildInfo.append(server.upload(uploadSpec))
269
270 if ( publishInfo ) {
271 buildInfo.env.capture = true
272 buildInfo.env.filter.addInclude("*")
273 buildInfo.env.filter.addExclude("*PASSWORD*")
274 buildInfo.env.filter.addExclude("*password*")
275 buildInfo.env.collect()
276 server.publishBuildInfo(buildInfo)
277 }
278}
279
280/**
281* Promote Docker image artifact to release repo
282*
283* @param artifactoryURL String, an URL to Artifactory
284* @param artifactoryDevRepo String, the source dev repository name
285* @param artifactoryProdRepo String, the target repository for the move or copy
286* @param dockerRepo String, the docker repository name to promote
287* @param artifactTag String, an image tag name to promote
288* @param targetTag String, target tag to assign the image after promotion
289* @param copy Boolean, an optional value to set whether to copy instead of move
290* Default: false
291*/
292def promoteDockerArtifact(String artifactoryURL, String artifactoryDevRepo,
293 String artifactoryProdRepo, String dockerRepo,
294 String artifactTag, String targetTag, Boolean copy=false) {
295 def url = "${artifactoryURL}/api/docker/${artifactoryDevRepo}/v2/promote"
296 writeFile file: "query.json",
297 text: """{
298 \"targetRepo\": \"${artifactoryProdRepo}\",
299 \"dockerRepository\": \"${dockerRepo}\",
300 \"tag\": \"${artifactTag}\",
301 \"targetTag\" : \"${targetTag}\",
302 \"copy\": \"${copy}\"
303 }""".stripIndent()
304 sh "cat query.json"
305 withCredentials([
306 [$class: 'UsernamePasswordMultiBinding',
307 credentialsId: 'artifactory',
308 passwordVariable: 'ARTIFACTORY_PASSWORD',
309 usernameVariable: 'ARTIFACTORY_LOGIN']
310 ]) {
311 sh "bash -c \"curl -u ${ARTIFACTORY_LOGIN}:${ARTIFACTORY_PASSWORD} -H \"Content-Type:application/json\" -X POST -d @query.json ${url}\""
312 }
313}