Jenkinsfile 20 KB

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