| @Library("cmsis") |
| import com.arm.dsg.cmsis.jenkins.ArtifactoryHelper |
| |
| DOCKERINFO = [ |
| 'staging': [ |
| 'registryUrl': 'mcu--docker-staging.eu-west-1.artifactory.aws.arm.com', |
| 'registryCredentialsId': 'artifactory', |
| 'k8sPullSecret': 'artifactory-mcu-docker-staging', |
| 'namespace': 'mcu--docker-staging', |
| 'image': 'cmsis/linux', |
| 'label': "${JENKINS_ENV}-${JOB_BASE_NAME}-${BUILD_NUMBER}" |
| ], |
| 'production': [ |
| 'registryUrl': 'mcu--docker.eu-west-1.artifactory.aws.arm.com', |
| 'registryCredentialsId': 'artifactory', |
| 'namespace': 'mcu--docker', |
| 'k8sPullSecret': 'artifactory-mcu-docker', |
| 'image': 'cmsis/linux', |
| 'label': 'latest' |
| ] |
| ] |
| HADOLINT_VERSION = '2.6.0-alpine' |
| |
| dockerinfo = DOCKERINFO['production'] |
| |
| isPrecommit = (JOB_BASE_NAME == 'pre_commit') |
| isPostcommit = (JOB_BASE_NAME == 'post_commit') |
| isNightly = (JOB_BASE_NAME == 'nightly') |
| isRelease = (JOB_BASE_NAME == 'release') |
| |
| patternGlobal = [ |
| '^Jenkinsfile' |
| ] |
| |
| patternDocker = [ |
| '^docker/.*' |
| ] |
| |
| patternCoreM = [ |
| '^CMSIS/Core/Include/.*', |
| '^Device/ARM/ARMCM.*' |
| ] |
| |
| patternCoreA = [ |
| '^CMSIS/Core_A/Include/.*', |
| '^Device/ARM/ARMCA.*' |
| ] |
| |
| patternCoreValidation = [ |
| '^CMSIS/CoreValidation/.*' |
| ] |
| |
| CONFIGURATIONS = [ |
| 'pre_commit': [ |
| 'mdevices': ['CM0', 'CM3', 'CM4FP', 'CM7DP', 'CM23', 'CM33NS', 'CM35PS', |
| 'CM55NS', 'CM85S'], |
| 'adevices': ['CA7', 'CA9'], |
| 'devices' : [], |
| 'configs' : [ |
| 'AC5': ['low', 'tiny'], |
| 'AC6': ['low', 'tiny'], |
| 'AC6LTM': ['low', 'tiny'], |
| 'GCC': ['low', 'tiny'] |
| ] |
| ], |
| 'post_commit': [ |
| 'devices' : ['CM0', 'CM0plus', 'CM3', 'CM4', 'CM4FP', 'CM7', 'CM7SP', 'CM7DP', |
| 'CM23', 'CM23S', 'CM23NS', 'CM33', 'CM33S', 'CM33NS', |
| 'CM35P', 'CM35PS', 'CM35PNS', 'CM55', 'CM55S', 'CM55NS', |
| 'CM85S', 'CM85NS', |
| 'CA5', 'CA7', 'CA9'], |
| 'configs' : [ |
| 'AC5': ['low', 'tiny'], |
| 'AC6': ['low', 'tiny'], |
| 'AC6LTM': ['low', 'tiny'], |
| 'GCC': ['low', 'tiny'] |
| ] |
| ], |
| 'nightly': [ |
| 'devices' : ['CM0', 'CM0plus', 'CM3', 'CM4', 'CM4FP', 'CM7', 'CM7SP', 'CM7DP', |
| 'CM23', 'CM23S', 'CM23NS', 'CM33', 'CM33S', 'CM33NS', |
| 'CM35P', 'CM35PS', 'CM35PNS', 'CM55', 'CM55S', 'CM55NS', |
| 'CM85S', 'CM85NS', |
| 'CA5', 'CA7', 'CA9'], |
| 'configs' : [ |
| 'AC5': ['low', 'mid', 'high', 'size', 'tiny'], |
| 'AC6': ['low', 'mid', 'high', 'size', 'tiny'], |
| 'AC6LTM': ['low', 'mid', 'high', 'size', 'tiny'], |
| 'GCC': ['low', 'mid', 'high', 'size', 'tiny'] |
| ] |
| ], |
| 'release': [] |
| ] |
| CONFIGURATION = CONFIGURATIONS[JOB_BASE_NAME] |
| |
| // ---- PIPELINE CODE ---- |
| |
| def getChangeset() { |
| def fileset = sh encoding: 'UTF-8', label: '', returnStdout: true, script: 'git diff --name-only HEAD~1..HEAD' |
| return fileset.split('\n') |
| } |
| |
| def fileSetMatches(fileset, patternset) { |
| return patternset.any { p -> |
| fileset.any{ f -> f ==~ p } |
| } |
| } |
| |
| FORCE_BUILD = false |
| DOCKER_BUILD = isPrecommit || isPostcommit || isNightly |
| CORE_VALIDATION = isPrecommit || isPostcommit || isNightly |
| COMMIT = null |
| VERSION = null |
| |
| artifactory = new ArtifactoryHelper(this) |
| |
| pipeline { |
| agent { label 'master' } |
| options { |
| timestamps() |
| timeout(time: 1, unit: 'HOURS') |
| ansiColor('xterm') |
| skipDefaultCheckout() |
| } |
| environment { |
| CI_ACCOUNT = credentials('grasci') |
| ARTIFACTORY = credentials('artifactory') |
| USER = "${CI_ACCOUNT_USR}" |
| PASS = "${CI_ACCOUNT_PSW}" |
| ARTIFACTORY_API_KEY = "${ARTIFACTORY_PSW}" |
| } |
| stages { |
| stage('Checkout') { |
| steps { |
| script { |
| COMMIT = checkoutScmWithRetry(3) |
| echo "COMMIT: ${COMMIT}" |
| VERSION = (sh(returnStdout: true, script: 'git describe --tags --always')).trim() |
| echo "VERSION: '${VERSION}'" |
| } |
| |
| stash name: 'dockerfile', includes: 'docker/**' |
| } |
| } |
| |
| stage('Analyse') { |
| when { |
| expression { return isPrecommit || isPostcommit } |
| beforeOptions true |
| } |
| steps { |
| script { |
| def fileset = changeset |
| def hasGlobal = fileSetMatches(fileset, patternGlobal) |
| def hasDocker = fileSetMatches(fileset, patternDocker) |
| def hasCoreM = fileSetMatches(fileset, patternCoreM) |
| def hasCoreA = fileSetMatches(fileset, patternCoreA) |
| def hasCoreValidation = fileSetMatches(fileset, patternCoreValidation) |
| |
| echo """Change analysis: |
| - hasGlobal = ${hasGlobal} |
| - hasDocker = ${hasDocker} |
| - hasCoreM = ${hasCoreM} |
| - hasCoreA = ${hasCoreA} |
| - hasCoreValidation = ${hasCoreValidation} |
| """ |
| |
| if (isPrecommit) { |
| if (hasGlobal || hasDocker || hasCoreM || hasCoreValidation) { |
| CONFIGURATION['devices'] += CONFIGURATION['mdevices'] |
| } |
| if (hasGlobal || hasDocker || hasCoreA || hasCoreValidation) { |
| CONFIGURATION['devices'] += CONFIGURATION['adevices'] |
| } |
| } |
| |
| DOCKER_BUILD &= hasDocker |
| CORE_VALIDATION &= hasGlobal || hasDocker || hasCoreM || hasCoreA || hasCoreValidation |
| |
| echo """Stage schedule: |
| - DOCKER_BUILD = ${DOCKER_BUILD} |
| - CORE_VALIDATION = ${CORE_VALIDATION} |
| """ |
| } |
| } |
| } |
| |
| stage('Docker Lint') { |
| when { |
| expression { return DOCKER_BUILD } |
| beforeOptions true |
| } |
| agent { |
| kubernetes { |
| defaultContainer 'hadolint' |
| slaveConnectTimeout 600 |
| yaml """\ |
| apiVersion: v1 |
| kind: Pod |
| securityContext: |
| runAsUser: 1000 |
| runAsGroup: 1000 |
| spec: |
| imagePullSecrets: |
| - name: artifactory-mcu-docker |
| securityContext: |
| runAsUser: 1000 |
| runAsGroup: 1000 |
| containers: |
| - name: hadolint |
| image: mcu--docker.eu-west-1.artifactory.aws.arm.com/hadolint/hadolint:${HADOLINT_VERSION} |
| alwaysPullImage: true |
| imagePullPolicy: Always |
| command: |
| - sleep |
| args: |
| - infinity |
| resources: |
| requests: |
| cpu: 900m |
| memory: 3Gi |
| """.stripIndent() |
| } |
| } |
| steps { |
| unstash 'dockerfile' |
| |
| sh 'hadolint --format json docker/dockerfile* | tee hadolint.log' |
| |
| recordIssues tools: [hadoLint(id: 'hadolint', pattern: 'hadolint.log')], |
| qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]], |
| referenceJobName: 'nightly', ignoreQualityGate: true |
| } |
| } |
| |
| stage('Docker Build') { |
| when { |
| expression { return (isPrecommit || isPostcommit) && DOCKER_BUILD } |
| beforeOptions true |
| } |
| agent { |
| kubernetes { |
| defaultContainer 'docker-dind' |
| slaveConnectTimeout 600 |
| yaml """\ |
| apiVersion: v1 |
| kind: Pod |
| spec: |
| imagePullSecrets: |
| - name: artifactory-mcu-docker |
| containers: |
| - name: docker-dind |
| image: docker:dind |
| securityContext: |
| privileged: true |
| volumeMounts: |
| - name: dind-storage |
| mountPath: /var/lib/docker |
| volumes: |
| - name: dind-storage |
| emptyDir: {} |
| """.stripIndent() |
| } |
| } |
| steps { |
| sh('apk add bash curl git') |
| script { |
| unstash 'dockerfile' |
| |
| dir('docker') { |
| dockerinfo = DOCKERINFO['staging'] |
| withCredentials([sshUserPrivateKey(credentialsId: 'grasci_with_pk', |
| keyFileVariable: 'grasciPk', |
| passphraseVariable: '', |
| usernameVariable: 'grasciUsername')]) { |
| sh("GIT_SSH_COMMAND='ssh -i $grasciPk -o StrictHostKeyChecking=no' ./getDependencies.sh") |
| } |
| docker.withRegistry("https://${dockerinfo['registryUrl']}", dockerinfo['registryCredentialsId']) { |
| def image = docker.build("${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']}", "--build-arg DOCKER_REGISTRY=${dockerinfo['registryUrl']} .") |
| image.push() |
| } |
| } |
| } |
| } |
| } |
| |
| stage('Pack') { |
| agent { |
| kubernetes { |
| defaultContainer 'cmsis' |
| slaveConnectTimeout 600 |
| yaml """\ |
| apiVersion: v1 |
| kind: Pod |
| spec: |
| imagePullSecrets: |
| - name: ${dockerinfo['k8sPullSecret']} |
| securityContext: |
| runAsUser: 1000 |
| runAsGroup: 1000 |
| containers: |
| - name: cmsis |
| image: ${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']} |
| alwaysPullImage: true |
| imagePullPolicy: Always |
| command: |
| - sleep |
| args: |
| - infinity |
| resources: |
| requests: |
| cpu: 900m |
| memory: 3Gi |
| """.stripIndent() |
| } |
| } |
| steps { |
| checkoutScmWithRetry(3) |
| sh('./CMSIS/Utilities/fetch_devtools.sh') |
| sh('./CMSIS/RTOS/RTX/LIB/fetch_libs.sh') |
| sh('./CMSIS/RTOS2/RTX/Library/fetch_libs.sh') |
| |
| tee('doxygen.log') { |
| sh('./CMSIS/DoxyGen/gen_doc.sh') |
| } |
| sh('./CMSIS/Utilities/gen_pack.sh') |
| |
| archiveArtifacts artifacts: 'output/ARM.CMSIS.*.pack', allowEmptyArchive: true |
| stash name: 'pack', includes: 'output/ARM.CMSIS.*.pack' |
| |
| recordIssues tools: [doxygen(id: 'DOXYGEN', name: 'Doxygen', pattern: 'doxygen.log')], |
| qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]], |
| referenceJobName: 'nightly', ignoreQualityGate: true |
| } |
| } |
| |
| stage('CoreValidation') { |
| when { |
| expression { return CORE_VALIDATION } |
| beforeOptions true |
| } |
| matrix { |
| axes { |
| axis { |
| name 'DEVICE' |
| values 'CM0', 'CM0plus', 'CM3', 'CM4', 'CM4FP', 'CM7', 'CM7SP', 'CM7DP', |
| 'CM23', 'CM23S', 'CM23NS', 'CM33', 'CM33S', 'CM33NS', |
| 'CM35P', 'CM35PS', 'CM35PNS', 'CM55', 'CM55S', 'CM55NS', |
| 'CA5', 'CA5neon', 'CA7', 'CA7neon', 'CA9', 'CA9neon' |
| } |
| } |
| stages { |
| stage('Test') { |
| when { |
| expression { return DEVICE in CONFIGURATION['devices'] } |
| beforeOptions true |
| } |
| agent { |
| kubernetes { |
| defaultContainer 'cmsis' |
| slaveConnectTimeout 600 |
| yaml """\ |
| apiVersion: v1 |
| kind: Pod |
| spec: |
| imagePullSecrets: |
| - name: ${dockerinfo['k8sPullSecret']} |
| securityContext: |
| runAsUser: 1000 |
| runAsGroup: 1000 |
| containers: |
| - name: cmsis |
| image: ${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']} |
| alwaysPullImage: true |
| imagePullPolicy: Always |
| command: |
| - sleep |
| args: |
| - infinity |
| resources: |
| requests: |
| cpu: 900m |
| memory: 3Gi |
| """.stripIndent() |
| } |
| } |
| steps { |
| checkoutScmWithRetry(3) |
| dir('CMSIS/CoreValidation/Project') { |
| script { |
| CONFIGURATION['configs'].each { COMPILER, OPTS -> |
| tee("CV_${COMPILER}_${DEVICE}.log") { |
| sh "python3 build.py -d ${DEVICE} -c ${COMPILER} -o ${OPTS.join(' -o ')} build run" |
| } |
| } |
| } |
| |
| archiveArtifacts artifacts: 'CoreValidation_*.zip', allowEmptyArchive: true |
| stash name: "CV_${DEVICE}", includes: '*.log, *.junit' |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| stage('Results') { |
| when { |
| expression { return CORE_VALIDATION } |
| beforeOptions true |
| } |
| steps { |
| dir('results') { |
| deleteDir() |
| script { |
| CONFIGURATION['devices'].each { unstash "CV_${it}" } |
| } |
| |
| recordIssues tools: [armCc(id: 'AC5', name: 'Arm Compiler 5', pattern: 'CV_AC5_*.log'), |
| clang(id: 'AC6', name: 'Arm Compiler 6', pattern: 'CV_AC6_*.log'), |
| clang(id: 'AC6LTM', name: 'Arm Compiler 6 LTM', pattern: 'CV_AC6LTM_*.log'), |
| gcc(id: 'GCC', name: 'GNU Compiler', pattern: 'CV_GCC_*.log')], |
| qualityGates: [[threshold: 1, type: 'DELTA', unstable: true]], |
| referenceJobName: 'nightly', ignoreQualityGate: true |
| xunit([ |
| JUnit(pattern: 'corevalidation_*.junit', failIfNotNew: false, skipNoTestFiles: true) |
| ]) |
| } |
| |
| } |
| } |
| |
| stage('Docker Promote') { |
| when { |
| expression { return isPostcommit && DOCKER_BUILD } |
| beforeOptions true |
| } |
| agent { |
| kubernetes { |
| defaultContainer 'docker-dind' |
| slaveConnectTimeout 600 |
| yaml """\ |
| apiVersion: v1 |
| kind: Pod |
| spec: |
| imagePullSecrets: |
| - name: artifactory-mcu-docker |
| containers: |
| - name: docker-dind |
| image: docker:dind |
| securityContext: |
| privileged: true |
| volumeMounts: |
| - name: dind-storage |
| mountPath: /var/lib/docker |
| volumes: |
| - name: dind-storage |
| emptyDir: {} |
| """.stripIndent() |
| } |
| } |
| steps { |
| script { |
| String postCommitTag = "${dockerinfo['registryUrl']}/${dockerinfo['image']}:${dockerinfo['label']}" |
| String prodCommitTag = "${DOCKERINFO['production']['registryUrl']}/${DOCKERINFO['production']['image']}:${DOCKERINFO['production']['label']}" |
| |
| // Pull & retag Docker Staging Container to Production |
| docker.withRegistry("https://${dockerinfo['registryUrl']}", dockerinfo['registryCredentialsId']) { |
| def image = docker.image("$postCommitTag") |
| image.pull() |
| sh "docker tag $postCommitTag $prodCommitTag" |
| } |
| // Push to Docker Production |
| docker.withRegistry("https://${DOCKERINFO['production']['registryUrl']}", DOCKERINFO['production']['registryCredentialsId']) { |
| def image = docker.image("$prodCommitTag") |
| image.push() |
| } |
| } |
| } |
| } |
| |
| stage('Release Promote') { |
| when { |
| expression { return isRelease } |
| beforeOptions true |
| } |
| steps { |
| unstash name: 'pack' |
| dir('output') { |
| script { |
| artifactory.upload pattern: 'ARM.CMSIS.*.pack', |
| target: "mcu.promoted/CMSIS_5/${VERSION}/", |
| props: "GIT_COMMIT=${COMMIT['GIT_COMMIT']}" |
| } |
| withCredentials([string(credentialsId: 'grasci_github', variable: 'ghtoken')]) { |
| sh """ |
| curl -XPOST \ |
| -H "Authorization:token ${ghtoken}" \ |
| -H "Content-Type:application/octet-stream" \ |
| --data-binary @ARM.CMSIS.${VERSION}.pack \ |
| https://uploads.github.com/repos/ARM-software/CMSIS_5/releases/${VERSION}/assets?name=ARM.CMSIS.${VERSION}.pack |
| """ |
| } |
| } |
| } |
| } |
| } |
| } |