exception_message_exec = 'failed to execute the following command: '
exception_message_code_generation = 'Generated code verification failed'
-node('nordix-nsm-build-ubuntu1804') {
+node('nordix-nsm-build-ubuntu2204') {
build_number = env.BUILD_NUMBER
workspace = env.WORKSPACE
ws("${workspace}/${build_number}") {
def image_names = params.IMAGE_NAMES.split(' ')
def version = params.IMAGE_VERSION
def e2e_enabled = params.E2E_ENABLED
+ def helm_chart_upload = params.HELM_CHART_UPLOAD
+ def security_scan_enabled = params.SECURITY_SCAN_ENABLED
def git_project = params.GIT_PROJECT
def current_branch = params.CURRENT_BRANCH
def default_branch = params.DEFAULT_BRANCH
])
sh 'git show'
}
- stage('Verify') {
- Verify().call()
- }
+ Verify().call()
stage('Docker login') {
- withCredentials([usernamePassword(credentialsId: 'nordix-cicd-harbor-credentials', passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USERNAME')]) {
- sh '''#!/bin/bash -eu
+ if (env.DRY_RUN != 'true') {
+ withCredentials([usernamePassword(credentialsId: 'nordix-cicd-harbor-credentials', passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USERNAME')]) {
+ sh '''#!/bin/bash -eu
echo $HARBOR_PASSWORD | docker login --username $HARBOR_USERNAME --password-stdin $IMAGE_REGISTRY
'''
+ }
+ } else {
+ echo 'Docker login'
}
}
stage('Base Image') {
}
stage('Images') {
Images(image_names, version, build_steps, image_registry, local_version).call()
+ if (currentBuild.result == 'FAILURE') {
+ Error('Failed to build image(s)').call()
+ }
+ }
+ stage('Helm Chart') {
+ HelmChart(helm_chart_upload, version).call()
+ }
+ stage('Security Scan') {
+ if (security_scan_enabled == true) {
+ SecurityScan(current_branch, version).call()
+ } else {
+ Utils.markStageSkippedForConditional('Security Scan')
+ }
}
stage('E2E') {
- E2e(e2e_enabled).call()
+ if (e2e_enabled == true) {
+ E2e(current_branch, version).call()
+ } else {
+ Utils.markStageSkippedForConditional('E2E')
+ }
}
}
stage('Cleanup') {
}
}
-// Static analysis: Runs the GeneratedCode function and then UnitTests and Linter in parallel
+// Verify the Generated code, UnitTests and Linter
def Verify() {
return {
GeneratedCode().call() // cannot generate code and run the linter and tests at the same time
- // Linter().call()
- // UnitTests().call()
- def stages = [:]
- stages.put('Unit Tests', UnitTests())
- stages.put('Linter', Linter())
- // stages.put('Generated code verification', GeneratedCode())
- parallel(stages)
+ Linter().call()
+ UnitTests().call()
}
}
SetBuildStatus(completed, context, success)
} catch (Exception e) {
SetBuildStatus(failed, context, failure)
- Error(exception_message_exec + command).call()
+ Error("${exception_message_exec} ${command}").call()
}
}
}
SetBuildStatus(completed, context, success)
} catch (Exception e) {
SetBuildStatus(failed, context, failure)
- Error(exception_message_exec + command).call()
+ Error("${exception_message_exec} ${command}").call()
}
}
}
def GeneratedCode() {
return {
def context = 'Generated code verification'
- SetBuildStatus(in_progress, context, pending)
- stage('go mod tidy') {
- def command = 'go mod tidy'
- try {
- ExecSh(command).call()
- if (GetModifiedFiles() != '') {
- throw new Exception(exception_message_code_generation)
- }
- } catch (Exception e) {
- SetBuildStatus(failed, context, failure)
- Error(exception_message_exec + command).call()
- }
- }
- stage('go generate ./...') {
- def command = 'make generate'
+ stage('Generated code verification') {
+ def command = 'make go-generate manifests generate-controller'
try {
+ SetBuildStatus(in_progress, context, pending)
ExecSh(command).call()
if (GetModifiedFiles() != '') {
throw new Exception(exception_message_code_generation)
}
+ SetBuildStatus(completed, context, success)
} catch (Exception e) {
SetBuildStatus(failed, context, failure)
Error(exception_message_exec + command).call()
}
}
- stage('Proto') {
- // TODO: protoc version could be different
- Utils.markStageSkippedForConditional('Proto')
- // try {
- // sh 'make proto'
- // if (GetModifiedFiles() != '') {
- // throw new Exception(exception_message)
- // }
- // } catch (Exception e) {
- // SetBuildStatus(failed, context, failure)
- // sh 'git diff'
- // sh 'git status -s'
- // Error(e).call()
- // }
- }
- SetBuildStatus(completed, context, success)
}
}
SetBuildStatus(completed_message, context, success)
} catch (Exception e) {
SetBuildStatus(failed_message, context, failure)
- Error(exception_message_exec + command).call()
+ unstable "${exception_message_exec} ${command}"
+ currentBuild.result = 'FAILURE'
}
}
}
}
+// Generate and upload the helm chart
+def HelmChart(helm_chart_upload, version) {
+ return {
+ parallel(
+ 'Helm Chart': {
+ stage('Generate Helm Chart') {
+ def context = 'Generate Helm Chart'
+ def command = "make generate-helm-chart VERSION=${version}"
+ try {
+ SetBuildStatus(in_progress, context, pending)
+ ExecSh(command).call()
+ SetBuildStatus(completed, context, success)
+ } catch (Exception e) {
+ SetBuildStatus(failed, context, failure)
+ Error("${exception_message_exec} ${command}").call()
+ }
+ }
+ stage('Upload Helm Chart') {
+ if (helm_chart_upload == true) {
+ withCredentials([string(credentialsId: 'nsm-nordix-artifactory-api-key', variable: 'API_KEY')]) {
+ ExecSh("""
+ charts=\$(cd _output/helm/ && ls *.tgz)
+ for chart in \$charts
+ do
+ curl -H 'X-JFrog-Art-Api:${API_KEY}' -T _output/helm/\$chart \"https://artifactory.nordix.org/artifactory/cloud-native/meridio/\$chart\"
+ done
+ """).call()
+ }
+ } else {
+ Utils.markStageSkippedForConditional('Upload Helm Chart')
+ }
+ }
+ }
+ )
+ }
+}
+
+// Run the security scan job
+def SecurityScan(current_branch, version) {
+ return {
+ build job: 'meridio-periodic-security-scan', parameters: [
+ string(name: 'IMAGE_VERSION', value: "$version"),
+ string(name: 'CURRENT_BRANCH', value: "$current_branch"),
+ string(name: 'DRY_RUN', value: env.DRY_RUN)
+ ], wait: true
+ }
+}
+
// Run the E2e Tests
// Currently skipped
-def E2e(e2e_enabled) {
- if (e2e_enabled == 'true') {
- return {
- echo 'make e2e' // todo
- }
- } else {
- return {
- Utils.markStageSkippedForConditional('E2E')
- }
+def E2e(current_branch, version) {
+ return {
+ build job: 'meridio-e2e-test-kind', parameters: [
+ string(name: 'MERIDIO_VERSION', value: "$version"),
+ string(name: 'TAPA_VERSION', value: "$version"),
+ string(name: 'CURRENT_BRANCH', value: "$current_branch"),
+ string(name: 'DRY_RUN', value: env.DRY_RUN)
+ ], wait: true
}
}
// Execute command
def ExecSh(command) {
return {
- sh """
- . \${HOME}/.profile
- ${command}
- """
+ if (env.DRY_RUN != 'true') {
+ sh """
+ . \${HOME}/.profile
+ ${command}
+ """
+ } else {
+ echo "${command}"
+ }
}
}
// Set the commit status on Github
// https://plugins.jenkins.io/github/#plugin-content-pipeline-examples
def SetBuildStatus(String message, String context, String state) {
- step([
- $class: 'GitHubCommitStatusSetter',
- reposSource: [$class: 'ManuallyEnteredRepositorySource', url: 'https://github.com/Nordix/Meridio'],
- commitShaSource: [$class: 'ManuallyEnteredShaSource', sha: GetCommitSha()],
- contextSource: [$class: 'ManuallyEnteredCommitContextSource', context: context],
- errorHandlers: [[$class: 'ShallowAnyErrorHandler']], // Prevent GitHubCommitStatusSetter to set the job status to unstable
- statusResultSource: [ $class: 'ConditionalStatusResultSource', results: [[$class: 'AnyBuildResult', message: message, state: state]] ]
- ])
+ if (env.DRY_RUN != 'true') {
+ step([
+ $class: 'GitHubCommitStatusSetter',
+ reposSource: [$class: 'ManuallyEnteredRepositorySource', url: 'https://github.com/Nordix/Meridio'],
+ commitShaSource: [$class: 'ManuallyEnteredShaSource', sha: GetCommitSha()],
+ contextSource: [$class: 'ManuallyEnteredCommitContextSource', context: context],
+ errorHandlers: [[$class: 'ShallowAnyErrorHandler']], // Prevent GitHubCommitStatusSetter to set the job status to unstable
+ statusResultSource: [ $class: 'ConditionalStatusResultSource', results: [[$class: 'AnyBuildResult', message: message, state: state]] ]
+ ])
+ }
}
// Return the current commit sha