Jenkinsfile 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. @Library("cmsis")
  2. import com.arm.dsg.cmsis.jenkins.ArtifactoryHelper
  3. DOCKERINFO = [
  4. 'staging': [
  5. 'registryUrl': 'mcu--docker-staging.eu-west-1.artifactory.aws.arm.com',
  6. 'registryCredentialsId': 'artifactory',
  7. 'k8sPullSecret': 'artifactory-mcu-docker-staging',
  8. 'namespace': 'mcu--docker-staging',
  9. 'image': 'cmsis/linux',
  10. 'label': "${JENKINS_ENV}-${JOB_BASE_NAME}-${BUILD_NUMBER}"
  11. ],
  12. 'production': [
  13. 'registryUrl': 'mcu--docker.eu-west-1.artifactory.aws.arm.com',
  14. 'registryCredentialsId': 'artifactory',
  15. 'namespace': 'mcu--docker',
  16. 'k8sPullSecret': 'artifactory-mcu-docker',
  17. 'image': 'cmsis/linux',
  18. 'label': 'latest'
  19. ]
  20. ]
  21. HADOLINT_VERSION = '2.6.0-alpine'
  22. dockerinfo = DOCKERINFO['production']
  23. isPrecommit = (JOB_BASE_NAME == 'pre_commit')
  24. isPostcommit = (JOB_BASE_NAME == 'post_commit')
  25. isNightly = (JOB_BASE_NAME == 'nightly')
  26. isRelease = (JOB_BASE_NAME == 'release')
  27. patternGlobal = [
  28. '^Jenkinsfile'
  29. ]
  30. patternDocker = [
  31. '^docker/.*'
  32. ]
  33. patternCoreM = [
  34. '^CMSIS/Core/Include/.*',
  35. '^Device/ARM/ARMCM.*'
  36. ]
  37. patternCoreA = [
  38. '^CMSIS/Core_A/Include/.*',
  39. '^Device/ARM/ARMCA.*'
  40. ]
  41. patternCoreValidation = [
  42. '^CMSIS/CoreValidation/.*'
  43. ]
  44. CONFIGURATIONS = [
  45. 'pre_commit': [
  46. 'mdevices': ['CM0', 'CM3', 'CM4FP', 'CM7DP', 'CM23', 'CM33NS', 'CM35PS',
  47. 'CM55NS', 'CM85S'],
  48. 'adevices': ['CA7', 'CA9'],
  49. 'devices' : [],
  50. 'configs' : [
  51. 'AC5': ['low', 'tiny'],
  52. 'AC6': ['low', 'tiny'],
  53. 'AC6LTM': ['low', 'tiny'],
  54. 'GCC': ['low', 'tiny']
  55. ]
  56. ],
  57. 'post_commit': [
  58. 'devices' : ['CM0', 'CM0plus', 'CM3', 'CM4', 'CM4FP', 'CM7', 'CM7SP', 'CM7DP',
  59. 'CM23', 'CM23S', 'CM23NS', 'CM33', 'CM33S', 'CM33NS',
  60. 'CM35P', 'CM35PS', 'CM35PNS', 'CM55', 'CM55S', 'CM55NS',
  61. 'CM85S', 'CM85NS',
  62. 'CA5', 'CA7', 'CA9'],
  63. 'configs' : [
  64. 'AC5': ['low', 'tiny'],
  65. 'AC6': ['low', 'tiny'],
  66. 'AC6LTM': ['low', 'tiny'],
  67. 'GCC': ['low', 'tiny']
  68. ]
  69. ],
  70. 'nightly': [
  71. 'devices' : ['CM0', 'CM0plus', 'CM3', 'CM4', 'CM4FP', 'CM7', 'CM7SP', 'CM7DP',
  72. 'CM23', 'CM23S', 'CM23NS', 'CM33', 'CM33S', 'CM33NS',
  73. 'CM35P', 'CM35PS', 'CM35PNS', 'CM55', 'CM55S', 'CM55NS',
  74. 'CM85S', 'CM85NS',
  75. 'CA5', 'CA7', 'CA9'],
  76. 'configs' : [
  77. 'AC5': ['low', 'mid', 'high', 'size', 'tiny'],
  78. 'AC6': ['low', 'mid', 'high', 'size', 'tiny'],
  79. 'AC6LTM': ['low', 'mid', 'high', 'size', 'tiny'],
  80. 'GCC': ['low', 'mid', 'high', 'size', 'tiny']
  81. ]
  82. ],
  83. 'release': []
  84. ]
  85. CONFIGURATION = CONFIGURATIONS[JOB_BASE_NAME]
  86. // ---- PIPELINE CODE ----
  87. def getChangeset() {
  88. def fileset = sh encoding: 'UTF-8', label: '', returnStdout: true, script: 'git diff --name-only HEAD~1..HEAD'
  89. return fileset.split('\n')
  90. }
  91. def fileSetMatches(fileset, patternset) {
  92. return patternset.any { p ->
  93. fileset.any{ f -> f ==~ p }
  94. }
  95. }
  96. FORCE_BUILD = false
  97. DOCKER_BUILD = isPrecommit || isPostcommit || isNightly
  98. CORE_VALIDATION = isPrecommit || isPostcommit || isNightly
  99. COMMIT = null
  100. VERSION = null
  101. artifactory = new ArtifactoryHelper(this)
  102. pipeline {
  103. agent { label 'master' }
  104. options {
  105. timestamps()
  106. timeout(time: 1, unit: 'HOURS')
  107. ansiColor('xterm')
  108. skipDefaultCheckout()
  109. }
  110. environment {
  111. CI_ACCOUNT = credentials('grasci')
  112. ARTIFACTORY = credentials('artifactory')
  113. USER = "${CI_ACCOUNT_USR}"
  114. PASS = "${CI_ACCOUNT_PSW}"
  115. ARTIFACTORY_API_KEY = "${ARTIFACTORY_PSW}"
  116. }
  117. stages {
  118. stage('Checkout') {
  119. steps {
  120. script {
  121. COMMIT = checkoutScmWithRetry(3)
  122. echo "COMMIT: ${COMMIT}"
  123. VERSION = (sh(returnStdout: true, script: 'git describe --tags --always')).trim()
  124. echo "VERSION: '${VERSION}'"
  125. }
  126. stash name: 'dockerfile', includes: 'docker/**'
  127. }
  128. }
  129. stage('Analyse') {
  130. when {
  131. expression { return isPrecommit || isPostcommit }
  132. beforeOptions true
  133. }
  134. steps {
  135. script {
  136. def fileset = changeset
  137. def hasGlobal = fileSetMatches(fileset, patternGlobal)
  138. def hasDocker = fileSetMatches(fileset, patternDocker)
  139. def hasCoreM = fileSetMatches(fileset, patternCoreM)
  140. def hasCoreA = fileSetMatches(fileset, patternCoreA)
  141. def hasCoreValidation = fileSetMatches(fileset, patternCoreValidation)
  142. echo """Change analysis:
  143. - hasGlobal = ${hasGlobal}
  144. - hasDocker = ${hasDocker}
  145. - hasCoreM = ${hasCoreM}
  146. - hasCoreA = ${hasCoreA}
  147. - hasCoreValidation = ${hasCoreValidation}
  148. """
  149. if (isPrecommit) {
  150. if (hasGlobal || hasDocker || hasCoreM || hasCoreValidation) {
  151. CONFIGURATION['devices'] += CONFIGURATION['mdevices']
  152. }
  153. if (hasGlobal || hasDocker || hasCoreA || hasCoreValidation) {
  154. CONFIGURATION['devices'] += CONFIGURATION['adevices']
  155. }
  156. }
  157. DOCKER_BUILD &= hasDocker
  158. CORE_VALIDATION &= hasGlobal || hasDocker || hasCoreM || hasCoreA || hasCoreValidation
  159. echo """Stage schedule:
  160. - DOCKER_BUILD = ${DOCKER_BUILD}
  161. - CORE_VALIDATION = ${CORE_VALIDATION}
  162. """
  163. }
  164. }
  165. }
  166. stage('Docker Lint') {
  167. when {
  168. expression { return DOCKER_BUILD }
  169. beforeOptions true
  170. }
  171. agent {
  172. kubernetes {
  173. defaultContainer 'hadolint'
  174. slaveConnectTimeout 600
  175. yaml """\
  176. apiVersion: v1
  177. kind: Pod
  178. securityContext:
  179. runAsUser: 1000
  180. runAsGroup: 1000
  181. spec:
  182. imagePullSecrets:
  183. - name: artifactory-mcu-docker
  184. securityContext:
  185. runAsUser: 1000
  186. runAsGroup: 1000
  187. containers:
  188. - name: hadolint
  189. image: mcu--docker.eu-west-1.artifactory.aws.arm.com/hadolint/hadolint:${HADOLINT_VERSION}
  190. alwaysPullImage: true
  191. imagePullPolicy: Always
  192. command:
  193. - sleep
  194. args:
  195. - infinity
  196. resources:
  197. requests:
  198. cpu: 900m
  199. memory: 3Gi
  200. """.stripIndent()
  201. }
  202. }
  203. steps {
  204. unstash 'dockerfile'
  205. sh 'hadolint --format json docker/dockerfile* | tee hadolint.log'
  206. recordIssues tools: [hadoLint(id: 'hadolint', pattern: 'hadolint.log')],
  207. qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]],
  208. referenceJobName: 'nightly', ignoreQualityGate: true
  209. }
  210. }
  211. stage('Docker Build') {
  212. when {
  213. expression { return (isPrecommit || isPostcommit) && DOCKER_BUILD }
  214. beforeOptions true
  215. }
  216. agent {
  217. kubernetes {
  218. defaultContainer 'docker-dind'
  219. slaveConnectTimeout 600
  220. yaml """\
  221. apiVersion: v1
  222. kind: Pod
  223. spec:
  224. imagePullSecrets:
  225. - name: artifactory-mcu-docker
  226. containers:
  227. - name: docker-dind
  228. image: docker:dind
  229. securityContext:
  230. privileged: true
  231. volumeMounts:
  232. - name: dind-storage
  233. mountPath: /var/lib/docker
  234. volumes:
  235. - name: dind-storage
  236. emptyDir: {}
  237. """.stripIndent()
  238. }
  239. }
  240. steps {
  241. sh('apk add bash curl git')
  242. script {
  243. unstash 'dockerfile'
  244. dir('docker') {
  245. dockerinfo = DOCKERINFO['staging']
  246. withCredentials([sshUserPrivateKey(credentialsId: 'grasci_with_pk',
  247. keyFileVariable: 'grasciPk',
  248. passphraseVariable: '',
  249. usernameVariable: 'grasciUsername')]) {
  250. sh("GIT_SSH_COMMAND='ssh -i $grasciPk -o StrictHostKeyChecking=no' ./getDependencies.sh")
  251. }
  252. docker.withRegistry("https://${dockerinfo['registryUrl']}", dockerinfo['registryCredentialsId']) {
  253. def image = docker.build("${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']}", "--build-arg DOCKER_REGISTRY=${dockerinfo['registryUrl']} .")
  254. image.push()
  255. }
  256. }
  257. }
  258. }
  259. }
  260. stage('Pack') {
  261. agent {
  262. kubernetes {
  263. defaultContainer 'cmsis'
  264. slaveConnectTimeout 600
  265. yaml """\
  266. apiVersion: v1
  267. kind: Pod
  268. spec:
  269. imagePullSecrets:
  270. - name: ${dockerinfo['k8sPullSecret']}
  271. securityContext:
  272. runAsUser: 1000
  273. runAsGroup: 1000
  274. containers:
  275. - name: cmsis
  276. image: ${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']}
  277. alwaysPullImage: true
  278. imagePullPolicy: Always
  279. command:
  280. - sleep
  281. args:
  282. - infinity
  283. resources:
  284. requests:
  285. cpu: 900m
  286. memory: 3Gi
  287. """.stripIndent()
  288. }
  289. }
  290. steps {
  291. checkoutScmWithRetry(3)
  292. sh('./CMSIS/Utilities/fetch_devtools.sh')
  293. sh('./CMSIS/RTOS/RTX/LIB/fetch_libs.sh')
  294. sh('./CMSIS/RTOS2/RTX/Library/fetch_libs.sh')
  295. tee('doxygen.log') {
  296. sh('./CMSIS/DoxyGen/gen_doc.sh')
  297. }
  298. sh('./CMSIS/Utilities/gen_pack.sh')
  299. archiveArtifacts artifacts: 'output/ARM.CMSIS.*.pack', allowEmptyArchive: true
  300. stash name: 'pack', includes: 'output/ARM.CMSIS.*.pack'
  301. recordIssues tools: [doxygen(id: 'DOXYGEN', name: 'Doxygen', pattern: 'doxygen.log')],
  302. qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]],
  303. referenceJobName: 'nightly', ignoreQualityGate: true
  304. }
  305. }
  306. stage('CoreValidation') {
  307. when {
  308. expression { return CORE_VALIDATION }
  309. beforeOptions true
  310. }
  311. matrix {
  312. axes {
  313. axis {
  314. name 'DEVICE'
  315. values 'CM0', 'CM0plus', 'CM3', 'CM4', 'CM4FP', 'CM7', 'CM7SP', 'CM7DP',
  316. 'CM23', 'CM23S', 'CM23NS', 'CM33', 'CM33S', 'CM33NS',
  317. 'CM35P', 'CM35PS', 'CM35PNS', 'CM55', 'CM55S', 'CM55NS',
  318. 'CA5', 'CA5neon', 'CA7', 'CA7neon', 'CA9', 'CA9neon'
  319. }
  320. }
  321. stages {
  322. stage('Test') {
  323. when {
  324. expression { return DEVICE in CONFIGURATION['devices'] }
  325. beforeOptions true
  326. }
  327. agent {
  328. kubernetes {
  329. defaultContainer 'cmsis'
  330. slaveConnectTimeout 600
  331. yaml """\
  332. apiVersion: v1
  333. kind: Pod
  334. spec:
  335. imagePullSecrets:
  336. - name: ${dockerinfo['k8sPullSecret']}
  337. securityContext:
  338. runAsUser: 1000
  339. runAsGroup: 1000
  340. containers:
  341. - name: cmsis
  342. image: ${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']}
  343. alwaysPullImage: true
  344. imagePullPolicy: Always
  345. command:
  346. - sleep
  347. args:
  348. - infinity
  349. resources:
  350. requests:
  351. cpu: 900m
  352. memory: 3Gi
  353. """.stripIndent()
  354. }
  355. }
  356. steps {
  357. checkoutScmWithRetry(3)
  358. dir('CMSIS/CoreValidation/Project') {
  359. script {
  360. CONFIGURATION['configs'].each { COMPILER, OPTS ->
  361. tee("CV_${COMPILER}_${DEVICE}.log") {
  362. sh "python3 build.py -d ${DEVICE} -c ${COMPILER} -o ${OPTS.join(' -o ')} build run"
  363. }
  364. }
  365. }
  366. archiveArtifacts artifacts: 'CoreValidation_*.zip', allowEmptyArchive: true
  367. stash name: "CV_${DEVICE}", includes: '*.log, *.junit'
  368. }
  369. }
  370. }
  371. }
  372. }
  373. }
  374. stage('Results') {
  375. when {
  376. expression { return CORE_VALIDATION }
  377. beforeOptions true
  378. }
  379. steps {
  380. dir('results') {
  381. deleteDir()
  382. script {
  383. CONFIGURATION['devices'].each { unstash "CV_${it}" }
  384. }
  385. recordIssues tools: [armCc(id: 'AC5', name: 'Arm Compiler 5', pattern: 'CV_AC5_*.log'),
  386. clang(id: 'AC6', name: 'Arm Compiler 6', pattern: 'CV_AC6_*.log'),
  387. clang(id: 'AC6LTM', name: 'Arm Compiler 6 LTM', pattern: 'CV_AC6LTM_*.log'),
  388. gcc(id: 'GCC', name: 'GNU Compiler', pattern: 'CV_GCC_*.log')],
  389. qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]],
  390. referenceJobName: 'nightly', ignoreQualityGate: true
  391. xunit([
  392. JUnit(pattern: 'corevalidation_*.junit', failIfNotNew: false, skipNoTestFiles: true)
  393. ])
  394. }
  395. }
  396. }
  397. stage('Docker Promote') {
  398. when {
  399. expression { return isPostcommit && DOCKER_BUILD }
  400. beforeOptions true
  401. }
  402. agent {
  403. kubernetes {
  404. defaultContainer 'docker-dind'
  405. slaveConnectTimeout 600
  406. yaml """\
  407. apiVersion: v1
  408. kind: Pod
  409. spec:
  410. imagePullSecrets:
  411. - name: artifactory-mcu-docker
  412. containers:
  413. - name: docker-dind
  414. image: docker:dind
  415. securityContext:
  416. privileged: true
  417. volumeMounts:
  418. - name: dind-storage
  419. mountPath: /var/lib/docker
  420. volumes:
  421. - name: dind-storage
  422. emptyDir: {}
  423. """.stripIndent()
  424. }
  425. }
  426. steps {
  427. script {
  428. String postCommitTag = "${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']}"
  429. String prodCommitTag = "${DOCKERINFO['production']['registryUrl']}/${DOCKERINFO['production']['image']}:${DOCKERINFO['production']['label']}"
  430. // Pull & retag Docker Staging Container to Production
  431. docker.withRegistry("https://${dockerinfo['registryUrl']}", dockerinfo['registryCredentialsId']) {
  432. def image = docker.image("$postCommitTag")
  433. image.pull()
  434. sh "docker tag $postCommitTag $prodCommitTag"
  435. }
  436. // Push to Docker Production
  437. docker.withRegistry("https://${DOCKERINFO['production']['registryUrl']}", DOCKERINFO['production']['registryCredentialsId']) {
  438. def image = docker.image("$prodCommitTag")
  439. image.push()
  440. }
  441. }
  442. }
  443. }
  444. stage('Release Promote') {
  445. when {
  446. expression { return isRelease }
  447. beforeOptions true
  448. }
  449. steps {
  450. unstash name: 'pack'
  451. dir('output') {
  452. script {
  453. artifactory.upload pattern: 'ARM.CMSIS.*.pack',
  454. target: "mcu.promoted/CMSIS_5/${VERSION}/",
  455. props: "GIT_COMMIT=${COMMIT['GIT_COMMIT']}"
  456. }
  457. withCredentials([string(credentialsId: 'grasci_github', variable: 'ghtoken')]) {
  458. sh """
  459. curl -XPOST \
  460. -H "Authorization:token ${ghtoken}" \
  461. -H "Content-Type:application/octet-stream" \
  462. --data-binary @ARM.CMSIS.${VERSION}.pack \
  463. https://uploads.github.com/repos/ARM-software/CMSIS_5/releases/${VERSION}/assets?name=ARM.CMSIS.${VERSION}.pack
  464. """
  465. }
  466. }
  467. }
  468. }
  469. }
  470. }