Jenkinsfile 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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/Utilities/fetch_devtools.sh')
  290. sh('./CMSIS/RTOS/RTX/LIB/fetch_libs.sh')
  291. sh('./CMSIS/RTOS2/RTX/Library/fetch_libs.sh')
  292. tee('doxygen.log') {
  293. sh('./CMSIS/DoxyGen/gen_doc.sh')
  294. }
  295. sh('./CMSIS/Utilities/gen_pack.sh')
  296. archiveArtifacts artifacts: 'output/ARM.CMSIS.*.pack', allowEmptyArchive: true
  297. stash name: 'pack', includes: 'output/ARM.CMSIS.*.pack'
  298. recordIssues tools: [doxygen(id: 'DOXYGEN', name: 'Doxygen', pattern: 'doxygen.log')],
  299. qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]],
  300. referenceJobName: 'nightly', ignoreQualityGate: true
  301. }
  302. }
  303. stage('CoreValidation') {
  304. when {
  305. expression { return CORE_VALIDATION }
  306. beforeOptions true
  307. }
  308. matrix {
  309. axes {
  310. axis {
  311. name 'DEVICE'
  312. values 'CM0', 'CM0plus', 'CM3', 'CM4', 'CM4FP', 'CM7', 'CM7SP', 'CM7DP',
  313. 'CM23', 'CM23S', 'CM23NS', 'CM33', 'CM33S', 'CM33NS',
  314. 'CM35P', 'CM35PS', 'CM35PNS', 'CM55', 'CM55S', 'CM55NS',
  315. 'CA5', 'CA5neon', 'CA7', 'CA7neon', 'CA9', 'CA9neon'
  316. }
  317. }
  318. stages {
  319. stage('Test') {
  320. when {
  321. expression { return DEVICE in CONFIGURATION['devices'] }
  322. beforeOptions true
  323. }
  324. agent {
  325. kubernetes {
  326. defaultContainer 'cmsis'
  327. slaveConnectTimeout 600
  328. yaml """\
  329. apiVersion: v1
  330. kind: Pod
  331. spec:
  332. imagePullSecrets:
  333. - name: ${dockerinfo['k8sPullSecret']}
  334. securityContext:
  335. runAsUser: 1000
  336. runAsGroup: 1000
  337. containers:
  338. - name: cmsis
  339. image: ${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']}
  340. alwaysPullImage: true
  341. imagePullPolicy: Always
  342. command:
  343. - sleep
  344. args:
  345. - infinity
  346. resources:
  347. requests:
  348. cpu: 2
  349. memory: 2Gi
  350. """.stripIndent()
  351. }
  352. }
  353. steps {
  354. checkoutScmWithRetry(3)
  355. dir('CMSIS/CoreValidation/Tests') {
  356. script {
  357. CONFIGURATION['configs'].each { COMPILER, OPTS ->
  358. tee("CV_${COMPILER}_${DEVICE}.log") {
  359. sh "python3 build.py -d ${DEVICE} -c ${COMPILER} -o ${OPTS.join(' -o ')} build run"
  360. }
  361. }
  362. }
  363. archiveArtifacts artifacts: 'CoreValidation_*.zip', allowEmptyArchive: true
  364. stash name: "CV_${DEVICE}", includes: '*.log, *.junit'
  365. }
  366. }
  367. }
  368. }
  369. }
  370. }
  371. stage('Results') {
  372. when {
  373. expression { return CORE_VALIDATION }
  374. beforeOptions true
  375. }
  376. steps {
  377. dir('results') {
  378. deleteDir()
  379. script {
  380. CONFIGURATION['devices'].each { unstash "CV_${it}" }
  381. }
  382. recordIssues tools: [armCc(id: 'AC5', name: 'Arm Compiler 5', pattern: 'CV_AC5_*.log'),
  383. clang(id: 'AC6', name: 'Arm Compiler 6', pattern: 'CV_AC6_*.log'),
  384. clang(id: 'AC6LTM', name: 'Arm Compiler 6 LTM', pattern: 'CV_AC6LTM_*.log'),
  385. gcc(id: 'GCC', name: 'GNU Compiler', pattern: 'CV_GCC_*.log')],
  386. qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]],
  387. referenceJobName: 'nightly', ignoreQualityGate: true
  388. xunit([
  389. JUnit(pattern: 'corevalidation_*.junit', failIfNotNew: false, skipNoTestFiles: true)
  390. ])
  391. }
  392. }
  393. }
  394. stage('Docker Promote') {
  395. when {
  396. expression { return isPostcommit && DOCKER_BUILD }
  397. beforeOptions true
  398. }
  399. agent {
  400. kubernetes {
  401. defaultContainer 'docker-dind'
  402. slaveConnectTimeout 600
  403. yaml """\
  404. apiVersion: v1
  405. kind: Pod
  406. spec:
  407. imagePullSecrets:
  408. - name: artifactory-mcu-docker
  409. containers:
  410. - name: docker-dind
  411. image: docker:dind
  412. securityContext:
  413. privileged: true
  414. volumeMounts:
  415. - name: dind-storage
  416. mountPath: /var/lib/docker
  417. volumes:
  418. - name: dind-storage
  419. emptyDir: {}
  420. """.stripIndent()
  421. }
  422. }
  423. steps {
  424. script {
  425. String postCommitTag = "${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']}"
  426. String prodCommitTag = "${DOCKERINFO['production']['registryUrl']}/${DOCKERINFO['production']['image']}:${DOCKERINFO['production']['label']}"
  427. // Pull & retag Docker Staging Container to Production
  428. docker.withRegistry("https://${dockerinfo['registryUrl']}", dockerinfo['registryCredentialsId']) {
  429. def image = docker.image("$postCommitTag")
  430. image.pull()
  431. sh "docker tag $postCommitTag $prodCommitTag"
  432. }
  433. // Push to Docker Production
  434. docker.withRegistry("https://${DOCKERINFO['production']['registryUrl']}", DOCKERINFO['production']['registryCredentialsId']) {
  435. def image = docker.image("$prodCommitTag")
  436. image.push()
  437. }
  438. }
  439. }
  440. }
  441. stage('Release Promote') {
  442. when {
  443. expression { return isRelease }
  444. beforeOptions true
  445. }
  446. steps {
  447. unstash name: 'pack'
  448. dir('output') {
  449. script {
  450. artifactory.upload pattern: 'ARM.CMSIS.*.pack',
  451. target: "mcu.promoted/CMSIS_5/${VERSION}/",
  452. props: "GIT_COMMIT=${COMMIT['GIT_COMMIT']}"
  453. }
  454. withCredentials([string(credentialsId: 'grasci_github', variable: 'ghtoken')]) {
  455. sh """
  456. curl -XPOST \
  457. -H "Authorization:token ${ghtoken}" \
  458. -H "Content-Type:application/octet-stream" \
  459. --data-binary @ARM.CMSIS.${VERSION}.pack \
  460. https://uploads.github.com/repos/ARM-software/CMSIS_5/releases/${VERSION}/assets?name=ARM.CMSIS.${VERSION}.pack
  461. """
  462. }
  463. }
  464. }
  465. }
  466. }
  467. }