blob: ccf4a18ce4d2e91d1c8c08266d3a878fd0795661 [file] [log] [blame]
Dean Birch62c4f082020-01-17 16:13:26 +00001#!/usr/bin/env groovy
2//-------------------------------------------------------------------------------
3// Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6//
7//-------------------------------------------------------------------------------
8
Dean Birchd0f9f8c2020-03-26 11:10:33 +00009@Library('trustedfirmware') _
10import org.trustedfirmware.Gerrit
11import org.trustedfirmware.Summary
Dean Bircha6ede7e2020-03-13 14:00:33 +000012
Dean Birch62c4f082020-01-17 16:13:26 +000013def listConfigs(ci_scripts_dir, config_list, filter_group) {
14 dir(ci_scripts_dir) {
15 echo "Obtaining list of configs."
Matthew Hartfb6fd362020-03-04 21:03:59 +000016 echo "Running: python3 ./configs.py -g ${filter_group.replace(" ", " -g ")}"
Dean Birch62c4f082020-01-17 16:13:26 +000017 def build_config_list_raw = sh(script: """\
Matthew Hartfb6fd362020-03-04 21:03:59 +000018python3 ./configs.py -g ${filter_group.replace(" ", " -g ")}
Dean Birch62c4f082020-01-17 16:13:26 +000019""", returnStdout: true).trim()
20 def build_config_list = build_config_list_raw.tokenize('\n')
21 config_list.addAll(build_config_list)
22 }
23}
24
Matthew Hartfb6fd362020-03-04 21:03:59 +000025def buildConfig(ci_scripts_dir, config, filter_group, results) {
Dean Birch62c4f082020-01-17 16:13:26 +000026 def params = []
Matthew Hartfb6fd362020-03-04 21:03:59 +000027 def params_collection = [:]
Dean Birch62c4f082020-01-17 16:13:26 +000028 def build_config_params
29 dir(ci_scripts_dir) {
30 echo "Obtaining build configuration for config ${config}"
Matthew Hartfb6fd362020-03-04 21:03:59 +000031 echo "Running: python3 ./configs.py -g ${filter_group.replace(" ", " -g ")} ${config}"
Dean Birch62c4f082020-01-17 16:13:26 +000032 build_config_params = sh(script: """\
Matthew Hartfb6fd362020-03-04 21:03:59 +000033python3 ./configs.py -g ${filter_group.replace(" ", " -g ")} ${config}
Dean Birch62c4f082020-01-17 16:13:26 +000034""", returnStdout: true).trim()
35 }
36 def lines = build_config_params.tokenize('\n')
37 for (String line : lines) {
38 def key, value
39 (key, value) = line.tokenize('=')
40 params += string(name: key, value: value)
Matthew Hartfb6fd362020-03-04 21:03:59 +000041 params_collection[key] = value
Dean Birch62c4f082020-01-17 16:13:26 +000042 }
43 params += string(name: 'GERRIT_BRANCH', value: env.GERRIT_BRANCH)
Dean Birchd0f9f8c2020-03-26 11:10:33 +000044 params += string(name: 'GERRIT_HOST', value: env.GERRIT_HOST)
45 params += string(name: 'GERRIT_CHANGE_NUMBER', value: env.GERRIT_CHANGE_NUMBER)
46 params += string(name: 'GERRIT_PATCHSET_REVISION', value: env.GERRIT_PATCHSET_REVISION)
Dean Birch62c4f082020-01-17 16:13:26 +000047 params += string(name: 'GERRIT_REFSPEC', value: env.GERRIT_REFSPEC)
Karl Zhang02d30352020-08-20 13:48:52 +080048 params += string(name: 'MBEDTLS_VERSION', value: env.MBEDTLS_VERSION)
Dean Birch62c4f082020-01-17 16:13:26 +000049 params += string(name: 'CODE_REPO', value: env.CODE_REPO)
Karl Zhangf6f467e2020-07-10 16:24:45 +080050 params += string(name: 'CODE_COVERAGE_EN', value: env.CODE_COVERAGE_EN)
Dean Bircha6ede7e2020-03-13 14:00:33 +000051 return { -> results
52 def build_res = build(job: 'tf-m-build-config', parameters: params, propagate: false)
53 def build_info = [build_res, config, params_collection]
54 results['builds'][build_res.number] = build_info
55 def build_url = build_res.getAbsoluteUrl()
56 print("${build_res.number}: ${config} ${build_res.result} ${build_url}")
57 failure_states = ["FAILURE", "ABORTED", "UNSTABLE", "NOT_BUILT"]
58 if (build_res.result in failure_states) {
59 error("Build failed at ${build_url}")
60 }
61 else {
62 print("Doing LAVA stuff for ${build_url}")
63 params += string(name: 'BUILD_NUMBER', value: "${build_res.number}")
64 params += string(name: 'BUILD_URL', value: build_url)
Matthew Hartfb6fd362020-03-04 21:03:59 +000065 params += string(name: 'LAVA_URL', value: env.LAVA_URL)
Dean Birch956416f2020-08-12 10:36:16 +010066 params += string(name: 'CI_SCRIPTS_BRANCH', value: env.CI_SCRIPTS_BRANCH)
67 params += string(name: 'LAVA_CREDENTIALS', value: env.LAVA_CREDENTIALS)
Dean Bircha6ede7e2020-03-13 14:00:33 +000068 def lava_res = build(job: 'tf-m-lava-submit', parameters: params, propagate: false)
Matthew Hartfb6fd362020-03-04 21:03:59 +000069 if (lava_res.result in failure_states) {
70 error("LAVA Create and Submit failed at ${lava_res.getAbsoluteUrl()}")
71 }
72 else {
73 results['lava_jobs'] += lava_res.getDescription()
74 }
Dean Birch62c4f082020-01-17 16:13:26 +000075 }
76 }
77}
78
Matthew Hart06340d72020-06-15 16:08:20 +010079def buildDocs(results) {
Dean Birch62c4f082020-01-17 16:13:26 +000080 def params = []
81 params += string(name: 'GERRIT_BRANCH', value: env.GERRIT_BRANCH)
Dean Birchd0f9f8c2020-03-26 11:10:33 +000082 params += string(name: 'GERRIT_HOST', value: env.GERRIT_HOST)
83 params += string(name: 'GERRIT_CHANGE_NUMBER', value: env.GERRIT_CHANGE_NUMBER)
84 params += string(name: 'GERRIT_PATCHSET_REVISION', value: env.GERRIT_PATCHSET_REVISION)
Dean Birch62c4f082020-01-17 16:13:26 +000085 params += string(name: 'GERRIT_REFSPEC', value: env.GERRIT_REFSPEC)
Karl Zhang02d30352020-08-20 13:48:52 +080086 params += string(name: 'MBEDTLS_VERSION', value: env.MBEDTLS_VERSION)
Dean Birch62c4f082020-01-17 16:13:26 +000087 params += string(name: 'CODE_REPO', value: env.CODE_REPO)
Matthew Hart06340d72020-06-15 16:08:20 +010088 return { -> results
Dean Birch62c4f082020-01-17 16:13:26 +000089 def res = build(job: 'tf-m-build-docs', parameters: params, propagate:false)
90 print("${res.number}: Docs ${res.result} ${res.getAbsoluteUrl()}")
Matthew Hart06340d72020-06-15 16:08:20 +010091 results['docs'] = [res.number, res.result, params]
Dean Bircha6ede7e2020-03-13 14:00:33 +000092 if (res.result in ["FAILURE", "ABORTED", "UNSTABLE", "NOT_BUILT"]) {
Dean Birch62c4f082020-01-17 16:13:26 +000093 error("Build failed at ${res.getAbsoluteUrl()}")
94 }
95 }
96}
97
Karl Zhang0413e972020-09-18 17:59:26 +080098def emailNotification(results) {
99 script {
100 if (env.JOB_NAME.equals("tf-m-nightly") && !env.EMAIL_NOTIFICATION.equals('')) {
101 def result = "Fail."
102 if (results)
103 result = "Success."
104 emailext (
105 subject: ("Job ${env.JOB_NAME} build ${env.BUILD_NUMBER} ${result}"),
106 body: "Check console output at ${env.BUILD_URL}",
107 to: "${EMAIL_NOTIFICATION}"
108 )
109 }
110 } /* script */
111}
112
xinyu-tfmb4fc0412020-08-19 10:49:51 +0800113@NonCPS
114def generateCsvContent(results) {
115 def resultsParam = []
116 results.each { result ->
117 resultsParam.add([result.value[1], \
118 result.value[0].getResult(), \
119 result.value[2]['TARGET_PLATFORM'], \
120 result.value[2]['COMPILER'], \
121 result.value[2]['PROJ_CONFIG'], \
122 result.value[2]['CMAKE_BUILD_TYPE'], \
123 result.value[2]['BL2'], \
124 result.value[2]['PSA_API_SUITE']])
125 }
126 def configs = [] as Set
127 resultsParam.each { result ->
128 if (result[2] == 'MUSCA_B1') {
129 if (result[0].contains('_OTP_')) {
130 result[2] += '_OTP'
131 }
132 }
133 if (result[6] == 'True') {
134 result[6] = 'BL2'
135 }
136 else {
137 result[6] = 'NOBL2'
138 }
139 config = result[4]
140 if (result[7] != "''") {
141 config += ' (' + result[7] + ') '
142 }
143 configs.add(config)
144 result.add(config)
145 }
146 configs.sort()
147 def csvContent = []
148 resultsParam.each { result ->
149 def configExists = false
150 for (csvLine in csvContent) {
151 if (csvLine[0] == result[2] && \
152 csvLine[1] == result[3] && \
153 csvLine[2] == result[5] && \
154 csvLine[3] == result[6]) {
155 csvLine[4][result[8]] = result[1]
156 configExists = true
157 break
158 }
159 }
160 if (!configExists) {
161 csvContent.add([result[2], result[3], result[5], result[6], [:]])
162 csvContent.last()[4][result[8]] = result[1]
163 }
164 }
165 csvContent.sort{a,b -> a[0] <=> b[0] ?: a[1] <=> b[1] ?: a[2] <=> b[2] ?: a[3] <=> b[3]}
166 def csvTable = [['Platform', 'Compiler', 'Cmake Build Type', 'BL2']]
167 csvTable[0] += configs
168 def currentPlatform = ''
169 def currentCompiler = ''
170 def currentBuild = ''
171 csvContent.each { csvLine ->
172 // Modify CSV output format for a better layout
173 if (currentPlatform == csvLine[0]) {
174 csvTable.add([''])
175 }
176 else {
177 csvTable.add([csvLine[0]])
178 currentPlatform = csvLine[0]
179 currentCompiler = ''
180 currentBuild = ''
181 }
182 if (currentCompiler == csvLine[1]) {
183 csvTable.last().add('')
184 }
185 else {
186 csvTable.last().add(csvLine[1])
187 currentCompiler = csvLine[1]
188 currentBuild = ''
189 }
190 if (currentBuild == csvLine[2]) {
191 csvTable.last().add('')
192 }
193 else {
194 csvTable.last().add(csvLine[2])
195 currentBuild = csvLine[2]
196 }
197 csvTable.last().add(csvLine[3])
198 configs.each { config ->
199 if (csvLine[4].containsKey(config)) {
200 csvTable.last().add(csvLine[4][config])
201 }
202 else {
203 csvTable.last().add('N/A')
204 }
205 }
206 }
207 return csvTable
208}
209
210def generateBuildCsv(results) {
211 def csvContent = generateCsvContent(results)
212 node("master") {
213 writeCSV file: 'build_results.csv', records: csvContent, format: CSVFormat.EXCEL
214 archiveArtifacts 'build_results.csv'
215 }
216}
Dean Bircha6ede7e2020-03-13 14:00:33 +0000217
218def buildCsv(results) {
Dean Birchd0f9f8c2020-03-26 11:10:33 +0000219 def summary = new Summary();
Dean Bircha6ede7e2020-03-13 14:00:33 +0000220 def csvContent = summary.getBuildCsv(results)
221 node("master") {
222 writeCSV file: 'build_results.csv', records: csvContent, format: CSVFormat.EXCEL
223 archiveArtifacts 'build_results.csv'
224 }
225}
226
227def writeSummary(results) {
Dean Birchd0f9f8c2020-03-26 11:10:33 +0000228 def summary = new Summary();
Dean Bircha6ede7e2020-03-13 14:00:33 +0000229 def buildLinks = summary.getLinks(results)
230 node("master") {
231 writeFile file: "build_links.html", text: buildLinks
232 archiveArtifacts 'build_links.html'
233 }
234}
235
Matthew Hartfb6fd362020-03-04 21:03:59 +0000236def lineInString(string, match) {
237 def lines = string.split("\n")
238 def result = lines.findAll { it.contains(match) }
239 return result[0]
240}
241
242def getResult(string, match) {
243 line = lineInString(string, match)
Dean Birch1d545c02020-05-29 14:09:21 +0100244 a = line.split(match)[1].split(' ')
245 score = a[0]
246 if (a.size() > 1)
247 {
248 fail_text = a[1..-1].join(" ")
249 return [score, fail_text]
250 }
251 return [score, ""]
Matthew Hartfb6fd362020-03-04 21:03:59 +0000252}
253
254def submitJobsToList(results) {
255 def all_jobs = []
256 for (String result : results){
257 jobs_s = result.split('JOBS: ')
258 if (jobs_s.size() > 1) {
259 all_jobs += jobs_s[1]
260 }
261 }
262 return(all_jobs)
263}
264
Dean Birch62c4f082020-01-17 16:13:26 +0000265def configs = []
266def builds = [:]
Matthew Hartfb6fd362020-03-04 21:03:59 +0000267def results = [:]
Dean Birch62c4f082020-01-17 16:13:26 +0000268
Karl Zhangfec84102020-06-24 09:56:36 +0800269node("docker-amd64-bionic") {
Dean Birch62c4f082020-01-17 16:13:26 +0000270 stage("Init") {
271 cleanWs()
272 dir("tf-m-ci-scripts") {
Matthew Hartfb6fd362020-03-04 21:03:59 +0000273 git url: '$CI_SCRIPTS_REPO', branch: '$CI_SCRIPTS_BRANCH', credentialsId: 'GIT_SSH_KEY'
Dean Birch62c4f082020-01-17 16:13:26 +0000274 }
275 }
276 stage("Configs") {
277 // Populate configs
278 listConfigs('tf-m-ci-scripts', configs, env.FILTER_GROUP)
Dean Bircha6ede7e2020-03-13 14:00:33 +0000279 results['builds'] = [:]
280 results['lava_jobs'] = []
Dean Birch62c4f082020-01-17 16:13:26 +0000281 for (config in configs) {
Matthew Hartfb6fd362020-03-04 21:03:59 +0000282 builds[config] = buildConfig("tf-m-ci-scripts", config, env.FILTER_GROUP, results)
Dean Birch62c4f082020-01-17 16:13:26 +0000283 }
Matthew Hart06340d72020-06-15 16:08:20 +0100284 builds["docs"] = buildDocs(results)
Dean Birch62c4f082020-01-17 16:13:26 +0000285 }
286}
Karl Zhangfec84102020-06-24 09:56:36 +0800287
Dean Birch62c4f082020-01-17 16:13:26 +0000288stage("Builds") {
289 def verify = 1
290 try {
291 parallel(builds)
292 } catch (Exception e) {
Dean Bircha6ede7e2020-03-13 14:00:33 +0000293 print(e)
Dean Birch62c4f082020-01-17 16:13:26 +0000294 manager.buildFailure()
295 verify = -1
296 } finally {
Dean Bircha6ede7e2020-03-13 14:00:33 +0000297 print("Verifying status")
Dean Birchd0f9f8c2020-03-26 11:10:33 +0000298 g = new Gerrit()
299 g.verifyStatus(verify, 'tf-m-build', 'build')
Dean Bircha6ede7e2020-03-13 14:00:33 +0000300 print("Building CSV")
xinyu-tfmb4fc0412020-08-19 10:49:51 +0800301 generateBuildCsv(results['builds'])
Dean Bircha6ede7e2020-03-13 14:00:33 +0000302 writeSummary(results['builds'])
Dean Birch62c4f082020-01-17 16:13:26 +0000303 }
304}
Matthew Hart06340d72020-06-15 16:08:20 +0100305
Karl Zhangfec84102020-06-24 09:56:36 +0800306node("docker-amd64-bionic") {
Matthew Hart06340d72020-06-15 16:08:20 +0100307 stage("Copy Docs") {
308 step([$class: 'CopyArtifact', projectName: 'tf-m-build-docs',
309 selector: specific("${results['docs'][0]}"), target: './docs/',
310 optional: true])
311 archiveArtifacts artifacts: 'docs/**', allowEmptyArchive: true
312 }
Dean Bircha6ede7e2020-03-13 14:00:33 +0000313 stage("Tests") {
314 dir("tf-m-ci-scripts") {
Matthew Hartfb6fd362020-03-04 21:03:59 +0000315 git url: '$CI_SCRIPTS_REPO', branch: '$CI_SCRIPTS_BRANCH', credentialsId: 'GIT_SSH_KEY'
Dean Bircha6ede7e2020-03-13 14:00:33 +0000316 }
Matthew Hartfb6fd362020-03-04 21:03:59 +0000317 def all_jobs = []
318 def success = true
Dean Bircha6ede7e2020-03-13 14:00:33 +0000319 print("Wait for LAVA results here...")
Matthew Hartfb6fd362020-03-04 21:03:59 +0000320 try {
321 all_jobs = submitJobsToList(results['lava_jobs'])
322 if (all_jobs.size() > 0) {
323 dir("tf-m-ci-scripts") {
Dean Birch956416f2020-08-12 10:36:16 +0100324 withCredentials([usernamePassword(credentialsId: env.LAVA_CREDENTIALS, passwordVariable: 'LAVA_TOKEN', usernameVariable: 'LAVA_USER')]) {
Matthew Hartfb6fd362020-03-04 21:03:59 +0000325 output = sh(script: """./lava_helper/lava_wait_jobs.py --job-ids ${all_jobs.join(",")} \
326 --lava-url ${env.LAVA_URL} --lava-user ${LAVA_USER} --lava-token ${LAVA_TOKEN} \
Matthew Hart05a59b52020-05-27 17:54:51 +0100327 --artifacts-path lava_artifacts --lava-timeout 7200 \
Matthew Hartfb6fd362020-03-04 21:03:59 +0000328 """, returnStdout: true).trim()
329 archiveArtifacts artifacts: 'test_summary.*', allowEmptyArchive: true
330 print(output)
331 g = new Gerrit()
Dean Birch1d545c02020-05-29 14:09:21 +0100332 def (boot_result, boot_output) = getResult(output, 'BOOT_RESULT: ')
Matthew Hartfb6fd362020-03-04 21:03:59 +0000333 if (boot_result) {
334 g.verifyStatus(boot_result, "lava_boot", "test")
335 }
Dean Birch1d545c02020-05-29 14:09:21 +0100336 def (test_result, test_output) = getResult(output, 'TEST_RESULT: ')
Matthew Hartfb6fd362020-03-04 21:03:59 +0000337 if (test_result) {
338 g.verifyStatus(test_result, "lava_test", "test")
339 }
340 if (boot_result.toInteger() < 1 || test_result.toInteger() < 1) {
Dean Birch1d545c02020-05-29 14:09:21 +0100341 error("Marking job as failed due to failed boots: ${boot_output} or tests: ${test_output}")
Matthew Hartfb6fd362020-03-04 21:03:59 +0000342 }
343 }
344 }
345 }
346 else {
347 print("There were no LAVA jobs to test.")
348 }
349 }
350 catch (Exception e) {
351 print("ERROR: ${e}")
352 success = false
353 } finally {
354 archiveArtifacts artifacts: 'tf-m-ci-scripts/lava_artifacts/**', allowEmptyArchive: true
Karl Zhang0413e972020-09-18 17:59:26 +0800355 emailNotification(success);
Matthew Hartfb6fd362020-03-04 21:03:59 +0000356 cleanWs()
357 if (!success) {
358 error("There was an Error waiting for LAVA jobs")
359 }
Dean Bircha6ede7e2020-03-13 14:00:33 +0000360 }
361 }
Dean Bircha6ede7e2020-03-13 14:00:33 +0000362}