Skip to content

Commit

Permalink
Merge pull request #1 from opsta/stage-maven-unit
Browse files Browse the repository at this point in the history
Initial first version with Maven CI/CD
  • Loading branch information
winggundamth committed Jan 9, 2020
2 parents b0b3b16 + 74b4ecf commit ac0f52a
Show file tree
Hide file tree
Showing 10 changed files with 438 additions and 6 deletions.
32 changes: 26 additions & 6 deletions vars/inPod.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
// Prepare podTemplate
def call(String podType, String projectName, String k8sCloudName = projectName, Map podTemplateArgs = [:], Closure body) {
/**
* Prepare podTemplate
*
* @param podType String to map podTemplate with inPodMap
* @param projectName String of project name
* @param k8sCloudName String of Jenkins Kubernetes Cloud Name
* @param podTemplateArgs Map is the same as podTemplate
* @param body Closure to run steps within node()
*/
def call(
String podType,
String projectName,
String k8sCloudName = projectName,
Map podTemplateArgs = [:],
Closure body
) {

// Assign default containers and volumes for each type of deployment
// Please bump version if you update containers or volumes
Expand All @@ -8,13 +22,19 @@ def call(String podType, String projectName, String k8sCloudName = projectName,
version: "0.1.0",
containers: [
// Don't use alpine version. It having problem with forking JVM such as running surefire and junit testing
// https://hub.docker.com/_/openjdk?tab=tags
containerTemplate(name: 'java', image: 'openjdk:11.0.5-jdk-stretch', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'maven', image: 'maven:3.6.3-jdk-11-slim', ttyEnabled: true, command: 'cat'),
// https://hub.docker.com/_/maven?tab=tags
containerTemplate(name: 'maven', image: 'maven:3.6.3-jdk-11', ttyEnabled: true, command: 'cat'),
// https://hub.docker.com/_/docker?tab=tags
containerTemplate(name: 'docker', image: 'docker:19.03.5-dind', ttyEnabled: true, privileged: true,
command: 'dockerd --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2375 --storage-driver=overlay2'),
containerTemplate(name: 'helm', image: 'lachlanevenson/k8s-helm:v2.16.1', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'kubectl', image: 'lachlanevenson/k8s-kubectl:v1.16.3', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'robot', image: 'ppodgorsek/robot-framework:3.4.0', ttyEnabled: true, command: 'cat')
// https://hub.docker.com/r/lachlanevenson/k8s-helm/tags
containerTemplate(name: 'helm', image: 'lachlanevenson/k8s-helm:v3.0.2', ttyEnabled: true, command: 'cat'),
// https://hub.docker.com/r/lachlanevenson/k8s-kubectl/tags
containerTemplate(name: 'kubectl', image: 'lachlanevenson/k8s-kubectl:v1.16.4', ttyEnabled: true, command: 'cat'),
// https://hub.docker.com/r/ppodgorsek/robot-framework/tags
containerTemplate(name: 'robot', image: 'ppodgorsek/robot-framework:3.5.0', ttyEnabled: true, command: 'cat')
],
volumes: [
// Mount NFS as PVC for caching
Expand Down
71 changes: 71 additions & 0 deletions vars/stageBuildDocker.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Build and push Docker Image
*
* @param imgNames List of Docker Images name
* eg. ['module-1', 'module-2']
* @param imgTag String of Docker Image Tag
* eg. dev
* @param imgRepoServerUrl String of Private Docker Registry Server Url
* that you want to authen
* eg. https://registry.hub.docker.com
* @param imgRepoJenkinsCred String of Jenkins Credentials name
* @param imgNamePrefix String of Docker Image Prefix
* eg. private.registry.com/username
* @param paramArgs Map of optional variables
* [
* containerName: String Container name in podTemplate
* mavenSettingsFilePath: String Custom Maven settings file path
* eg. ./.m2/maven-mirror-settings.yml
* ]
*/
def call(
imgNames,
imgTag,
imgRepoServerUrl,
imgRepoJenkinsCred,
imgNamePrefix,
Map paramArgs = [:]
) {
// Set default optional arguments
private def defaultArgs = [
containerName: 'docker',
mavenSettingsFilePath: ''
]
// Replace default optional arguments with parametered arguments
private def args = defaultArgs << paramArgs

stage('Build and Push Docker Image') {
container(args.containerName) {

// Enable Docker Buildkit to improve build speed and enable new features
// Require Docker > 18.09
withEnv(['DOCKER_BUILDKIT=1']) {

// Authen with Private Registry
docker.withRegistry("${imgRepoServerUrl}", "${imgRepoJenkinsCred}") {

// In case of we build multiple images per git repository
imgNames.each { item ->

// Build variables
imgFullName = "${imgNamePrefix}/${item}"
if (imgNames.size() > 1) {
dockerfile = "Dockerfile.${item}"
} else {
dockerfile = "Dockerfile"
}
echo "Start building ${item} image [${imgFullName}:${imgTag}]"

// Search and replace Maven custom settings file parameter
if(!args.mavenSettingsFilePath.isEmpty()) {
sh "sed -i 's!\\(RUN .*\\)-s .* \\(.*\\)!\\1-s ${args.mavenSettingsFilePath} \\2!g' ${dockerfile}"
}

// Build and Push Docker Image
docker.build("${imgFullName}:${imgTag}", "-f ${dockerfile} --pull .").push()
}
}
}
}
}
}
11 changes: 11 additions & 0 deletions vars/stageCloneRepository.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Git Clone Repository and Checkout
*
* @return scmVars Object
*/
def call() {
stage('Clone repository') {
scmVars = checkout scm
}
return scmVars
}
48 changes: 48 additions & 0 deletions vars/stageHelmDeploy.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Run OWASP Dependency Check with Maven
*
* @param projectName String of Project Name
* @param appName String of Application Name
* @param envName String of Environment Name
* eg. dev
* @param kubeConfigJenkinsCred String of kubeconfig Jenkins Credentials name
* @param scmVars Object from checkout scm in Jenkinsfile
* @param paramArgs Map of optional variables
* [
* containerName: String Container name in podTemplate
* helmValueFile: String Helm value file path
* helmChartPath: String Helm Chart directory path
* ]
*/
def call(
projectName,
appName,
envName,
kubeConfigJenkinsCred,
scmVars,
Map paramArgs = [:]
) {

// Set default optional arguments
private def defaultArgs = [
containerName: 'helm',
helmValueFile: "k8s/helm-values/${envName}/values-${projectName}-${envName}-${appName}.yaml",
helmChartPath: 'k8s/helm'
]
// Replace default optional arguments with parametered arguments
private def args = defaultArgs << paramArgs

stage("Deploy ${appName}") {
container(args.containerName) {
withCredentials([file(credentialsId: kubeConfigJenkinsCred, variable: 'KUBECONFIG')]) {
sh """
mkdir -p ~/.kube/
cat $KUBECONFIG > ~/.kube/config
sed -i 's/COMMIT_ID: CHANGE_COMMIT_ID/COMMIT_ID: ${scmVars.GIT_COMMIT}/g' ${args.helmValueFile}
helm upgrade -i -f ${args.helmValueFile} --namespace ${projectName}-${envName} --wait \
${projectName}-${envName}-${appName} ${args.helmChartPath}
"""
}
}
}
}
37 changes: 37 additions & 0 deletions vars/stageMavenOwaspCheck.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Run OWASP Dependency Check with Maven
*
* @param paramArgs Map of optional variables
* [
* containerName: String Container name in podTemplate
* odcInstallation: String OWASP Dependency Check Installation Name in Jenkins
* owaspReportFileName: String OWASP output report file name
* owaspDataPath: String OWASP Download Data Path
* ]
*/
def call(
Map paramArgs = [:]
) {

// Set default optional arguments
private def defaultArgs = [
odcInstallation: 'dependency-check',
containerName: 'maven',
owaspReportFileName: 'dependency-check-report.xml',
owaspDataPath: '/home/jenkins/dependency-check-data'
]
// Replace default optional arguments with parametered arguments
private def args = defaultArgs << paramArgs

stage('Run OWASP Dependency Check with Maven') {
container(args.containerName) {
dependencycheck(
additionalArguments: "--out ${args.owaspReportFileName} --data ${args.owaspDataPath}",
odcInstallation: args.odcInstallation
)
dependencyCheckPublisher(
pattern: args.owaspReportFileName
)
}
}
}
45 changes: 45 additions & 0 deletions vars/stageMavenSonarqubeAnalysis.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Run SonarQube Analysis with Maven
*
* @param sonarQubeEnv String of SonarQube Environment Name in Jenkins
* @param paramArgs Map of optional variables
* [
* containerName: String Container name in podTemplate
* mavenSettingsFilePath: String Custom Maven settings file path
* eg. ./.m2/maven-mirror-settings.yml
* sonarQubeMavenPluginVersion: String SonarQube Maven Plugin Version. Pick version from here
* https://mvnrepository.com/artifact/org.sonarsource.scanner.maven/sonar-maven-plugin
* ]
*/
def call(
String sonarQubeEnv,
Map paramArgs = [:]
) {

// Set default optional arguments
private def defaultArgs = [
sonarQubeMavenPluginVersion: "3.7.0.1746",
mavenSettingsFilePath: '',
containerName: 'maven'
]
// Replace default optional arguments with parametered arguments
private def args = defaultArgs << paramArgs

stage('SonarQube Analysis with Maven') {
container(args.containerName) {
withSonarQubeEnv(sonarQubeEnv) {

// Check if need custom maven settings
mavenSettingsFilePathParameter = ''
if(!args.mavenSettingsFilePath.isEmpty()) {
mavenSettingsFilePathParameter = "-s ${args.mavenSettingsFilePath}"
}

sh """
mvn ${mavenSettingsFilePathParameter} -e \
org.sonarsource.scanner.maven:sonar-maven-plugin:${args.sonarQubeMavenPluginVersion}:sonar
"""
}
}
}
}
53 changes: 53 additions & 0 deletions vars/stageMavenUnitTests.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Run Maven Unit Tests
*
* @param paramArgs Map of optional variables
* [
* containerName: String Container name in podTemplate
* mavenSettingsFilePath: String Custom Maven settings file path
* eg. ./.m2/maven-mirror-settings.yml
* jUnitReportPath: String JUnit Output Report Path
* ]
*/
def call(
Map paramArgs = [:]
) {

// Set default optional arguments
private def defaultArgs = [
mavenSettingsFilePath: '',
containerName: 'maven',
jUnitReportPath: ''
]
// Replace default optional arguments with parametered arguments
private def args = defaultArgs << paramArgs

try {
stage('Maven Unit Tests') {
container(args.containerName) {

// Check if need custom maven settings
mavenSettingsFilePathParameter = ''
if(!args.mavenSettingsFilePath.isEmpty()) {
mavenSettingsFilePathParameter = "-s ${args.mavenSettingsFilePath}"
}

sh """
mvn -e ${mavenSettingsFilePathParameter} clean test
"""
}
}
} catch(Exception e) {
// Print error
echo e.toString()
currentBuild.result = 'FAILURE'
} finally {
if(!args.jUnitReportPath.isEmpty()) {
junit args.jUnitReportPath
}
// Stop job when failure
if(currentBuild.result == 'FAILURE') {
sh "exit 1"
}
}
}
41 changes: 41 additions & 0 deletions vars/stageRobotPublish.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Publish Robot Framework Result
*
* @param paramArgs Map of optional variables
* [
* containerName: String Container name in podTemplate
* robotOutputBasePath: String Temporary Robot Output Report Base Path
* passThreshold: Integer Percent of test to pass threshold
* unstableThreshold: Integer Percent of test threshold to make build unstable
* ]
*/
def call(
Map paramArgs = [:]
) {

// Set default optional arguments
private def defaultArgs = [
containerName: 'robot',
robotOutputBasePath: 'test/robot/reports',
passThreshold: 100,
unstableThreshold: 0
]
// Replace default optional arguments with parametered arguments
private def args = defaultArgs << paramArgs

stage("Publish Robot Framework Result") {
container(args.containerName) {
step([
$class: 'RobotPublisher',
disableArchiveOutput: true,
outputPath: args.robotOutputBasePath,
logFileName: '**/log.html',
outputFileName: '**/output.xml',
reportFileName: '**/report.html',
otherFiles: '**/*screenshot*.png',
passThreshold: args.passThreshold,
unstableThreshold: args.unstableThreshold
])
}
}
}

0 comments on commit ac0f52a

Please sign in to comment.