Jenkinsfile 20 KB

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