diff --git a/.travis.yml b/.travis.yml
index bf129433c..c3fe9230e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,8 +4,13 @@ install:
- pip install --user mkdocs mkdocs-material
script:
- mvn test -B
-- if [[ "${TRAVIS_PULL_REQUEST}" != "false" ]]; then cd documentation && mkdocs build --clean --verbose --strict; fi;
+- if [[ "${TRAVIS_PULL_REQUEST}" != "false" ]]; then cd documentation && mkdocs build --clean --verbose --strict && cd ..; fi;
cache:
directories:
- $HOME/.m2
- $HOME/.cache/pip
+after_success:
+ - mvn -DrepoToken=$COVERALLS_REPO_TOKEN org.jacoco:jacoco-maven-plugin:report org.eluder.coveralls:coveralls-maven-plugin:report
+notifications:
+ slack:
+ secure: UYzfd4QYLtAX39r8LzV1dYp7cKMhYRRjI/xswMEkR+RgdMWxVPPH3kcsNLwkdNGSPn1b8Aidz8YLss9JolrepWjwI283dK8EUthZAOw03+PmL5X/3nOJ7aGv0sxwYqF5ypltBrerTf6jtPUTcQdtao+0O8bgnzShc6nWWE4MLXonjOm1pZLRUo81un+0bzm8C2ABIeHC6xuZCRycXP5u1mW1nDLK3900uY1rxIDTSZKEzA0IzLQhE9uROvI1r48fW8cKJQQjMMO5PPorq+0eDl2YTE8rQr9ldvuRE7A/ubsOQR0N5F8iAv1JTZXuXGt62fw6eKDQ1h94suEk7X+baV0EwlfhsHXcI1MxRFwxNSr9k1WaVFfA4TrM8XYBAcW3JGRA51ZK3q4EcjpuxpupaA7kZDtH53W7ePzH2TIp6yknln1q+yfcsP7cGv38sSKpKwOyMgAPRElkZzcoo31kw/PLzKPXYJEovRqx/0lWzczbFSscsroNaGCavC02++bUnyUXW2W+PG4gDSBFVZjtrvTPKnZ6DpHXV97x6xC/CzyhFj/Nf+ao/J9IIfocnc4vXJojwS550KIvM7xCDJwa/+29dajj2l6dQqrcOe3UT3O5UGU9I0KkGEDMfkLOD71eRy58qiYz3y953e52DvvzWQJbvfuk8ubMO+Fmn4GyRz8=
diff --git a/README.md b/README.md
index c323a3a15..044868b4c 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
[![Build Status](https://travis-ci.org/SAP/jenkins-library.svg?branch=master)](https://travis-ci.org/SAP/jenkins-library)
+[![Coverage Status](https://coveralls.io/repos/github/SAP/jenkins-library/badge.svg?branch=jacocoCodeCoverage)](https://coveralls.io/github/SAP/jenkins-library?branch=jacocoCodeCoverage)
# Description
@@ -47,7 +48,7 @@ provided pipeline library.
# Requirements
- * Java Runtime Environment 8
+ * Java Runtime Environment 8
* Installation of Jenkins v 2.60.3 or higher running on Linux. We tested with
debian-stretch.
* Jenkins Plugins installed as described in the [Required
diff --git a/documentation/docs/steps/artifactSetVersion.md b/documentation/docs/steps/artifactSetVersion.md
new file mode 100644
index 000000000..4af50bbf3
--- /dev/null
+++ b/documentation/docs/steps/artifactSetVersion.md
@@ -0,0 +1,75 @@
+# artifactSetVersion
+
+## Description
+The continuous delivery process requires that each build is done with a unique version number.
+
+The version generated using this step will contain:
+
+* Version (major.minor.patch) from descriptor file in master repository is preserved. Developers should be able to autonomously decide on increasing either part of this version number.
+* Timestamp
+* CommitId (by default the long version of the hash)
+
+After conducting automatic versioning the new version is pushed as a new tag into the source code repository (e.g. GitHub)
+
+## Prerequsites
+none
+
+## Parameters
+
+| parameter | mandatory | default | possible values |
+| ----------|-----------|---------|-----------------|
+| script | no | empty `commonPipelineEnvironment` | |
+| buildTool | no | maven | maven, docker |
+| dockerVersionSource | no | `''` | FROM, (ENV name),appVersion |
+| filePath | no | buildTool=`maven`: pom.xml
docker: Dockerfile | |
+| gitCommitId | no | `GitUtils.getGitCommitId()` | |
+| gitCredentialsId | yes | as defined in custom configuration | |
+| gitUserEMail | no | | |
+| gitUserName | no | | |
+| gitSshUrl | yes | | |
+| tagPrefix | no | 'build_' | |
+| timestamp | no | current time in format according to `timestampTemplate` | |
+| timestampTemplate | no | `%Y%m%d%H%M%S` | |
+| versioningTemplate | no | depending on `buildTool`
maven: `${version}-${timestamp}${commitId?"_"+commitId:""}` | |
+
+* `script` defines the global script environment of the Jenkinsfile run. Typically `this` is passed to this parameter. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for retrieving e.g. configuration parameters.
+* `buildTool` defines the tool which is used for building the artifact.
+* `dockerVersionSource` specifies the source to be used for the main version which is used for generating the automatic version.
+
+ * This can either be the version of the base image - as retrieved from the `FROM` statement within the Dockerfile, e.g. `FROM jenkins:2.46.2`
+ * Alternatively the name of an environment variable defined in the Docker image can be used which contains the version number, e.g. `ENV MY_VERSION 1.2.3`
+ * The third option `appVersion` applies only to the artifactType `appContainer`. Here the version of the app which is packaged into the container will be used as version for the container itself.
+
+* Using `filePath` you could define a custom path to the descriptor file.
+* `gitCommitId` defines the version prefix of the automatically generated version. By default it will take the long commitId hash. You could pass any other string (e.g. the short commitId hash) to be used. In case you don't want to have the gitCommitId added to the automatic versioning string you could set the value to an empty string: `''`.
+* `gitCredentialsId`defines the ssh git credentials to be used for writing the tag.
+* The parameters `gitUserName` and `gitUserEMail` allow to overwrite the global git settings available on your Jenkins server
+* `gitSshUrl` defines the git ssh url to the source code repository.
+* `tagPrefix` defines the prefix wich is used for the git tag which is written during the versioning run.
+* `timestamp` defines the timestamp to be used in the automatic version string. You could overwrite the default behavior by explicitly setting this string.
+
+## Step configuration
+Following parameters can also be specified as step parameters using the global configuration file:
+
+* `artifactType`
+* `buildTool`
+* `dockerVersionSource`
+* `filePath`
+* `gitCredentialsId`
+* `gitUserEMail`
+* `gitUserName`
+* `gitSshUrl`
+* `tagPrefix`
+* `timestamp`
+* `timestampTemplate`
+* `versioningTemplate`
+
+## Explanation of pipeline step
+
+Pipeline step:
+
+```groovy
+artifactSetVersion script: this, buildTool: 'maven'
+```
+
+
diff --git a/documentation/mkdocs.yml b/documentation/mkdocs.yml
index b3791bda0..ccd7d3f99 100644
--- a/documentation/mkdocs.yml
+++ b/documentation/mkdocs.yml
@@ -2,6 +2,7 @@ site_name: Jenkins 2.0 Pipelines
pages:
- Home: index.md
- 'Library steps':
+ - artifactSetVersion: steps/artifactSetVersion.md
- commonPipelineEnvironment: steps/commonPipelineEnvironment.md
- dockerExecute: steps/dockerExecute.md
- durationMeasure: steps/durationMeasure.md
diff --git a/pom.xml b/pom.xml
index b0725ab81..5dbbeb468 100644
--- a/pom.xml
+++ b/pom.xml
@@ -159,6 +159,55 @@
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.0
+
+
+
+
+
+ pre-unit-test
+ prepare-agent
+
+
+
+ post-unit-test
+ package
+ report
+
+
+
+
+
+ pre-integration-test
+ prepare-agent-integration
+
+
+
+ post-integration-test
+ report-integration
+
+
+
+
+ org.eluder.coveralls
+ coveralls-maven-plugin
+ 4.3.0
+
diff --git a/resources/default_pipeline_environment.yml b/resources/default_pipeline_environment.yml
index b4e2a7fb9..c4fe9296a 100644
--- a/resources/default_pipeline_environment.yml
+++ b/resources/default_pipeline_environment.yml
@@ -4,6 +4,15 @@ general:
#Steps Specific Configuration
steps:
+ artifactSetVersion:
+ timestampTemplate: '%Y%m%d%H%M%S'
+ tagPrefix: 'build_'
+ maven:
+ filePath: 'pom.xml'
+ versioningTemplate: '${version}-${timestamp}${commitId?"_"+commitId:""}'
+ docker:
+ filePath: 'Dockerfile'
+ versioningTemplate: '${version}-${timestamp}${commitId?"_"+commitId:""}'
mavenExecute:
dockerImage: 'maven:3.5-jdk-7'
influxWriteData:
diff --git a/src/com/sap/piper/ConfigurationMerger.groovy b/src/com/sap/piper/ConfigurationMerger.groovy
index cf1513313..0195543f9 100644
--- a/src/com/sap/piper/ConfigurationMerger.groovy
+++ b/src/com/sap/piper/ConfigurationMerger.groovy
@@ -2,37 +2,34 @@ package com.sap.piper
import com.cloudbees.groovy.cps.NonCPS
+import com.sap.piper.MapUtils
+
class ConfigurationMerger {
@NonCPS
- def static merge(Map configs, List configKeys, Map defaults=[:]) {
+ def static merge(Map configs, List configKeys, Map defaults) {
+ Map filteredConfig = configKeys?configs.subMap(configKeys):configs
Map merged = [:]
- merged.putAll(defaults)
- merged.putAll(filterByKeyAndNull(configs, configKeys))
+ merged.putAll(defaults)
+
+ for(String key : filteredConfig.keySet())
+ if(MapUtils.isMap(filteredConfig[key]))
+ merged[key] = merge(filteredConfig[key], null, defaults[key])
+ else if(filteredConfig[key] != null)
+ merged[key] = filteredConfig[key]
+ // else: keep defaults value and omit null values from config
return merged
}
@NonCPS
- def static merge(Map configs, Map configKeys, Map defaults = [:]) {
- Map merged = [:]
- merged.putAll(defaults)
- if(configs != null)
- for(String key : configKeys.keySet()){
- if(isMap(configKeys[key])){
- merged[key] = merge(configs[key], configKeys[key], defaults[key])
- }else{
- if(configs[key] != null)
- merged[key] = configs[key]
- }
- }
- return merged
- }
-
- @NonCPS
- def static merge(Map parameters, List parameterKeys, Map configurationMap, List configurationKeys, Map defaults=[:]){
- Map merged = merge(configurationMap, configurationKeys, defaults)
- merged.putAll(filterByKeyAndNull(parameters, parameterKeys))
-
+ def static merge(
+ Map parameters, List parameterKeys,
+ Map configuration, List configurationKeys,
+ Map defaults=[:]
+ ){
+ Map merged
+ merged = merge(configuration, configurationKeys, defaults)
+ merged = merge(parameters, parameterKeys, merged)
return merged
}
@@ -51,33 +48,11 @@ class ConfigurationMerger {
Map configurationMap, List configurationKeys,
Map stepDefaults=[:]
){
- Map merged = [:]
- merged.putAll(stepDefaults)
- merged.putAll(filterByKeyAndNull(configurationMap, configurationKeys))
- merged.putAll(pipelineDataMap)
- merged.putAll(filterByKeyAndNull(parameters, parameterKeys))
+ Map merged
+ merged = merge(configurationMap, configurationKeys, stepDefaults)
+ merged = merge(pipelineDataMap, null, merged)
+ merged = merge(parameters, parameterKeys, merged)
return merged
}
-
- @NonCPS
- private static filterByKeyAndNull(Map map, List keys) {
- Map filteredMap = map.findAll {
- if(it.value == null){
- return false
- }
- return true
- }
-
- if(keys == null) {
- return filteredMap
- }
-
- return filteredMap.subMap(keys)
- }
-
- @NonCPS
- def static isMap(object){
- return object in Map
- }
}
diff --git a/src/com/sap/piper/GitUtils.groovy b/src/com/sap/piper/GitUtils.groovy
new file mode 100644
index 000000000..ed4592cb1
--- /dev/null
+++ b/src/com/sap/piper/GitUtils.groovy
@@ -0,0 +1,7 @@
+package com.sap.piper
+
+import com.cloudbees.groovy.cps.NonCPS
+
+def getGitCommitId() {
+ return sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
+}
diff --git a/src/com/sap/piper/MapUtils.groovy b/src/com/sap/piper/MapUtils.groovy
new file mode 100644
index 000000000..e42b5aaff
--- /dev/null
+++ b/src/com/sap/piper/MapUtils.groovy
@@ -0,0 +1,10 @@
+package com.sap.piper
+
+import com.cloudbees.groovy.cps.NonCPS
+
+class MapUtils implements Serializable {
+ @NonCPS
+ static isMap(object){
+ return object in Map
+ }
+}
diff --git a/src/com/sap/piper/versioning/ArtifactVersioning.groovy b/src/com/sap/piper/versioning/ArtifactVersioning.groovy
new file mode 100644
index 000000000..f16cbbf54
--- /dev/null
+++ b/src/com/sap/piper/versioning/ArtifactVersioning.groovy
@@ -0,0 +1,30 @@
+package com.sap.piper.versioning
+
+abstract class ArtifactVersioning implements Serializable {
+
+ final protected script
+ final protected Map configuration
+
+ protected ArtifactVersioning(script, configuration) {
+ this.script = script
+ this.configuration = configuration
+ }
+
+ public static getArtifactVersioning(buildTool, script, configuration) {
+ switch (buildTool) {
+ case 'maven':
+ return new MavenArtifactVersioning(script, configuration)
+ case 'docker':
+ return new DockerArtifactVersioning(script, configuration)
+ default:
+ throw new IllegalArgumentException("No versioning implementation for buildTool: ${buildTool} available.")
+ }
+ }
+
+ abstract setVersion(version)
+ abstract getVersion()
+
+ protected echo(msg){
+ script.echo("[${this.getClass().getSimpleName()}] ${msg}")
+ }
+}
diff --git a/src/com/sap/piper/versioning/DockerArtifactVersioning.groovy b/src/com/sap/piper/versioning/DockerArtifactVersioning.groovy
new file mode 100644
index 000000000..65cd4eabf
--- /dev/null
+++ b/src/com/sap/piper/versioning/DockerArtifactVersioning.groovy
@@ -0,0 +1,50 @@
+package com.sap.piper.versioning
+
+class DockerArtifactVersioning extends ArtifactVersioning {
+ protected DockerArtifactVersioning(script, configuration) {
+ super(script, configuration)
+ }
+
+ @Override
+ def getVersion() {
+ if (configuration.dockerVersionSource == 'FROM')
+ return getVersionFromDockerBaseImageTag(configuration.filePath)
+ else
+ //standard assumption: version is assigned to an env variable
+ return getVersionFromDockerEnvVariable(configuration.filePath, configuration.dockerVersionSource)
+ }
+
+ @Override
+ def setVersion(version) {
+ def dockerVersionDir = (configuration.dockerVersionDir?dockerVersionDir:'')
+ script.dir(dockerVersionDir) {
+ script.writeFile file:'VERSION', text: version
+ }
+ }
+
+ def getVersionFromDockerEnvVariable(filePath, envVarName) {
+ def lines = script.readFile(filePath).split('\n')
+ def version = ''
+ for (def i = 0; i < lines.size(); i++) {
+ if (lines[i].startsWith('ENV') && lines[i].split(' ')[1] == envVarName) {
+ version = lines[i].split(' ')[2]
+ break
+ }
+ }
+ echo("Version from Docker environment variable ${envVarName}: ${version}")
+ return version.trim()
+ }
+
+ def getVersionFromDockerBaseImageTag(filePath) {
+ def lines = script.readFile(filePath).split('\n')
+ def version = null
+ for (def i = 0; i < lines.size(); i++) {
+ if (lines[i].startsWith('FROM') && lines[i].indexOf(':') > 0) {
+ version = lines[i].split(':')[1]
+ break
+ }
+ }
+ echo("Version from Docker base image tag: ${version}")
+ return version.trim()
+ }
+}
diff --git a/src/com/sap/piper/versioning/MavenArtifactVersioning.groovy b/src/com/sap/piper/versioning/MavenArtifactVersioning.groovy
new file mode 100644
index 000000000..db77b5b9d
--- /dev/null
+++ b/src/com/sap/piper/versioning/MavenArtifactVersioning.groovy
@@ -0,0 +1,18 @@
+package com.sap.piper.versioning
+
+class MavenArtifactVersioning extends ArtifactVersioning {
+ protected MavenArtifactVersioning (script, configuration) {
+ super(script, configuration)
+ }
+
+ @Override
+ def getVersion() {
+ def mavenPom = script.readMavenPom (file: configuration.filePath)
+ return mavenPom.getVersion().replaceAll(/-SNAPSHOT$/, "")
+ }
+
+ @Override
+ def setVersion(version) {
+ script.sh "mvn versions:set -DnewVersion=${version} --file ${configuration.filePath}"
+ }
+}
diff --git a/test/groovy/ArtifactSetVersionTest.groovy b/test/groovy/ArtifactSetVersionTest.groovy
new file mode 100644
index 000000000..6a11c62b6
--- /dev/null
+++ b/test/groovy/ArtifactSetVersionTest.groovy
@@ -0,0 +1,115 @@
+#!groovy
+import com.lesfurets.jenkins.unit.BasePipelineTest
+import com.sap.piper.DefaultValueCache
+import com.sap.piper.GitUtils
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+import org.junit.rules.RuleChain
+import util.JenkinsLoggingRule
+import util.JenkinsReadMavenPomRule
+import util.JenkinsShellCallRule
+import util.JenkinsWriteFileRule
+import util.Rules
+
+import static org.junit.Assert.assertEquals
+
+class ArtifactSetVersionTest extends BasePipelineTest {
+
+ Script artifactSetVersionScript
+
+ def cpe
+ def gitUtils
+ def sshAgentList = []
+
+ ExpectedException thrown = ExpectedException.none()
+ JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
+ JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
+ JenkinsWriteFileRule jwfr = new JenkinsWriteFileRule(this)
+
+ @Rule
+ public RuleChain ruleChain = Rules
+ .getCommonRules(this)
+ .around(thrown)
+ .around(jlr)
+ .around(jscr)
+ .around(new JenkinsReadMavenPomRule(this, 'test/resources/MavenArtifactVersioning'))
+ .around(jwfr)
+
+ @Before
+ void init() throws Throwable {
+
+ helper.registerAllowedMethod("sshagent", [List.class, Closure.class], { list, closure ->
+ sshAgentList = list
+ return closure()
+ })
+
+ jscr.setReturnValue('git rev-parse HEAD', 'testCommitId')
+ jscr.setReturnValue("date +'%Y%m%d%H%M%S'", '20180101010203')
+ jscr.setReturnValue('git diff --quiet HEAD', 0)
+
+ cpe = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment
+ artifactSetVersionScript = loadScript("artifactSetVersion.groovy")
+
+ gitUtils = new GitUtils()
+ prepareObjectInterceptors(gitUtils)
+ }
+
+ @Test
+ void testVersioning() {
+ artifactSetVersionScript.call(script: [commonPipelineEnvironment: cpe], juStabGitUtils: gitUtils, buildTool: 'maven', gitSshUrl: 'myGitSshUrl')
+
+ assertEquals('1.2.3-20180101010203_testCommitId', cpe.getArtifactVersion())
+ assertEquals('testCommitId', cpe.getGitCommitId())
+
+ assertEquals('mvn versions:set -DnewVersion=1.2.3-20180101010203_testCommitId --file pom.xml', jscr.shell[3])
+ assertEquals('git add .', jscr.shell[4])
+ assertEquals ("git commit -m 'update version 1.2.3-20180101010203_testCommitId'", jscr.shell[5])
+ assertEquals ("git remote set-url origin myGitSshUrl", jscr.shell[6])
+ assertEquals ("git tag build_1.2.3-20180101010203_testCommitId", jscr.shell[7])
+ assertEquals ("git push origin build_1.2.3-20180101010203_testCommitId", jscr.shell[8])
+ }
+
+ @Test
+ void testVersioningCustomGitUserAndEMail() {
+ artifactSetVersionScript.call(script: [commonPipelineEnvironment: cpe], juStabGitUtils: gitUtils, buildTool: 'maven', gitSshUrl: 'myGitSshUrl', gitUserEMail: 'test@test.com', gitUserName: 'test')
+
+ assertEquals ('git -c user.email="test@test.com" -c user.name "test" commit -m \'update version 1.2.3-20180101010203_testCommitId\'', jscr.shell[5])
+ }
+
+ @Test
+ void testVersioningWithTimestamp() {
+ artifactSetVersionScript.call(script: [commonPipelineEnvironment: cpe], juStabGitUtils: gitUtils, buildTool: 'maven', timestamp: '2018')
+ assertEquals('1.2.3-2018_testCommitId', cpe.getArtifactVersion())
+ }
+
+ @Test
+ void testVersioningNoBuildTool() {
+ thrown.expect(Exception)
+ thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR buildTool')
+ artifactSetVersionScript.call(script: [commonPipelineEnvironment: cpe], juStabGitUtils: gitUtils)
+ }
+
+ @Test
+ void testVersioningWithCustomTemplate() {
+ artifactSetVersionScript.call(script: [commonPipelineEnvironment: cpe], juStabGitUtils: gitUtils, buildTool: 'maven', versioningTemplate: '${version}-xyz')
+ assertEquals('1.2.3-xyz', cpe.getArtifactVersion())
+ }
+
+ @Test
+ void testVersioningWithTypeAppContainer() {
+ cpe.setArtifactVersion('1.2.3-xyz')
+ artifactSetVersionScript.call(script: [commonPipelineEnvironment: cpe], juStabGitUtils: gitUtils, buildTool: 'docker', artifactType: 'appContainer', dockerVersionSource: 'appVersion')
+ assertEquals('1.2.3-xyz', cpe.getArtifactVersion())
+ assertEquals('1.2.3-xyz', jwfr.files['VERSION'])
+ }
+
+ void prepareObjectInterceptors(object) {
+ object.metaClass.invokeMethod = helper.getMethodInterceptor()
+ object.metaClass.static.invokeMethod = helper.getMethodInterceptor()
+ object.metaClass.methodMissing = helper.getMethodMissingInterceptor()
+ }
+
+
+}
diff --git a/test/groovy/MTABuildTest.groovy b/test/groovy/MTABuildTest.groovy
index 100aa8969..e678aec8e 100644
--- a/test/groovy/MTABuildTest.groovy
+++ b/test/groovy/MTABuildTest.groovy
@@ -30,8 +30,7 @@ public class MTABuildTest extends BasePipelineTest {
def currentDir
- def otherDir
- def mtaBuildShEnv
+ def mtaYaml
def mtaBuildScript
def cpe
@@ -40,87 +39,57 @@ public class MTABuildTest extends BasePipelineTest {
void init() {
currentDir = tmp.newFolder().toURI().getPath()[0..-2] //omit final '/'
- otherDir = tmp.newFolder().toURI().getPath()[0..-2] //omit final '/'
+ mtaYaml = new File("$currentDir/mta.yaml")
+ mtaYaml << defaultMtaYaml()
helper.registerAllowedMethod('readYaml', [Map], {
m ->
return new Yaml().load((m.file as File).text)
})
- helper.registerAllowedMethod("dir", [String, Closure], {
- s, c ->
- currentDir = "${currentDir}/${s}"
- c()
- })
helper.registerAllowedMethod('pwd', [], { currentDir } )
- helper.registerAllowedMethod("withEnv", [List.class, Closure.class],
- { l, c ->
- mtaBuildShEnv = l
- c()
- })
- helper.registerAllowedMethod('error', [String], { s -> throw new hudson.AbortException(s) })
binding.setVariable('PATH', '/usr/bin')
- binding.setVariable('JAVA_HOME', '/opt/java')
- binding.setVariable('env', [:])
- mtaBuildScript = loadScript("mtaBuild.groovy").mtaBuild
+ mtaBuildScript = loadScript('mtaBuild.groovy').mtaBuild
cpe = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment
}
@Test
- public void straightForwardTest(){
+ void environmentPathTest() {
- binding.getVariable('env')['MTA_JAR_LOCATION'] = '/opt/mta'
+ mtaBuildScript.call(buildTarget: 'NEO')
- new File("${currentDir}/mta.yaml") << defaultMtaYaml()
-
- def mtarFilePath = mtaBuildScript.call(script: [commonPipelineEnvironment: cpe],
- buildTarget: 'NEO')
-
- assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/
-
- assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin")
-
- assert jscr.shell[1].contains(' -jar /opt/mta/mta.jar --mtar ')
-
- assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar"
-
- assert jlr.log.contains( "[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment.")
+ assert jscr.shell[1].contains('PATH=./node_modules/.bin:/usr/bin')
}
@Test
- public void mtarFilePathFromCommonPipelineEnviromentTest(){
+ void sedTest() {
- binding.getVariable('env')['MTA_JAR_LOCATION'] = '/opt/mta'
+ mtaBuildScript.call(buildTarget: 'NEO')
- new File("${currentDir}/mta.yaml") << defaultMtaYaml()
+ assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/
+ }
+
+
+ @Test
+ void mtarFilePathFromCommonPipelineEnviromentTest() {
mtaBuildScript.call(script: [commonPipelineEnvironment: cpe],
buildTarget: 'NEO')
def mtarFilePath = cpe.getMtarFilePath()
- assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/
-
- assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin")
-
- assert jscr.shell[1].contains(' -jar /opt/mta/mta.jar --mtar ')
-
- assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar"
-
- assert jlr.log.contains("[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment.")
+ assert mtarFilePath == "$currentDir/com.mycompany.northwind.mtar"
}
@Test
- public void mtaBuildWithSurroundingDirTest(){
-
- binding.getVariable('env')['MTA_JAR_LOCATION'] = '/opt/mta'
+ void mtaBuildWithSurroundingDirTest() {
def newDirName = 'newDir'
- def newDirPath = "${currentDir}/${newDirName}"
+ def newDirPath = "$currentDir/$newDirName"
def newDir = new File(newDirPath)
newDir.mkdirs()
@@ -128,109 +97,102 @@ public class MTABuildTest extends BasePipelineTest {
helper.registerAllowedMethod('pwd', [], { newDirPath } )
- def mtarFilePath = mtaBuildScript.call(script: [commonPipelineEnvironment: cpe], buildTarget: 'NEO')
+ def mtarFilePath = mtaBuildScript.call(buildTarget: 'NEO')
assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/newDir\/mta.yaml"$/
- assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin")
-
- assert jscr.shell[1].contains(' -jar /opt/mta/mta.jar --mtar ')
-
- assert mtarFilePath == "${currentDir}/${newDirName}/com.mycompany.northwind.mtar"
-
- assert jlr.log.contains("[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment.")
+ assert mtarFilePath == "$currentDir/$newDirName/com.mycompany.northwind.mtar"
}
+
@Test
- void mtaHomeNotSetTest() {
+ void mtaJarLocationNotSetTest() {
- new File("${currentDir}/mta.yaml") << defaultMtaYaml()
-
- def mtarFilePath = mtaBuildScript.call(script: [commonPipelineEnvironment: cpe], buildTarget: 'NEO')
-
- assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/
-
- assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin")
+ mtaBuildScript.call(buildTarget: 'NEO')
assert jscr.shell[1].contains(' -jar mta.jar --mtar ')
- assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar"
-
- assert jlr.log.contains( "[mtaBuild] Using MTA JAR from current working directory." )
+ assert jlr.log.contains('[mtaBuild] Using MTA JAR from current working directory.')
}
@Test
- void mtaHomeAsParameterTest() {
+ void mtaJarLocationAsParameterTest() {
- new File("${currentDir}/mta.yaml") << defaultMtaYaml()
-
- def mtarFilePath = mtaBuildScript.call(mtaJarLocation: '/mylocation/mta', buildTarget: 'NEO')
-
- assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/
-
- assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin")
+ mtaBuildScript.call(mtaJarLocation: '/mylocation/mta', buildTarget: 'NEO')
assert jscr.shell[1].contains(' -jar /mylocation/mta/mta.jar --mtar ')
- assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar"
-
- assert jlr.log.contains("[mtaBuild] MTA JAR \"/mylocation/mta/mta.jar\" retrieved from parameters.".toString())
+ assert jlr.log.contains('[mtaBuild] MTA JAR "/mylocation/mta/mta.jar" retrieved from parameters.')
}
@Test
- public void noMtaPresentTest(){
+ void noMtaPresentTest() {
+
+ mtaYaml.delete()
thrown.expect(FileNotFoundException)
- mtaBuildScript.call(script: [commonPipelineEnvironment: cpe],
- buildTarget: 'NEO')
+ mtaBuildScript.call(buildTarget: 'NEO')
}
@Test
- public void badMtaTest(){
+ void badMtaTest() {
+
thrown.expect(ParserException)
thrown.expectMessage('while parsing a block mapping')
- new File("${currentDir}/mta.yaml") << badMtaYaml()
+ mtaYaml.text = badMtaYaml()
- mtaBuildScript.call(script: [commonPipelineEnvironment: cpe],
- buildTarget: 'NEO')
+ mtaBuildScript.call(buildTarget: 'NEO')
}
@Test
- public void noIdInMtaTest(){
+ void noIdInMtaTest() {
+
thrown.expect(AbortException)
thrown.expectMessage("Property 'ID' not found in mta.yaml file at: '")
- new File("${currentDir}/mta.yaml") << noIdMtaYaml()
+ mtaYaml.text = noIdMtaYaml()
- mtaBuildScript.call(script: [commonPipelineEnvironment: cpe],
- buildTarget: 'NEO')
+ mtaBuildScript.call(buildTarget: 'NEO')
}
@Test
- public void noBuildTargetTest(){
+ void noBuildTargetTest() {
+
thrown.expect(Exception)
- thrown.expectMessage("ERROR - NO VALUE AVAILABLE FOR buildTarget")
+ thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR buildTarget')
- new File("${currentDir}/mta.yaml") << defaultMtaYaml()
-
- mtaBuildScript.call(script: [commonPipelineEnvironment: cpe])
+ mtaBuildScript.call()
}
- private defaultMtaYaml(){
+
+ @Test
+ void mtaJarLocationFromEnvironmentTest() {
+
+ binding.setVariable('env', [:])
+ binding.getVariable('env')['MTA_JAR_LOCATION'] = '/env/mta'
+
+ mtaBuildScript.call(buildTarget: 'NEO')
+
+ assert jscr.shell[1].contains('-jar /env/mta/mta.jar --mtar')
+ assert jlr.log.contains('[mtaBuild] MTA JAR "/env/mta/mta.jar" retrieved from environment.')
+ }
+
+
+ private defaultMtaYaml() {
return '''
_schema-version: "2.0.0"
ID: "com.mycompany.northwind"
version: 1.0.0
-
+
parameters:
hcp-deployer-version: "1.0.0"
-
+
modules:
- name: "fiorinorthwind"
type: html5
@@ -243,15 +205,15 @@ public class MTABuildTest extends BasePipelineTest {
'''
}
- private badMtaYaml(){
+ private badMtaYaml() {
return '''
_schema-version: "2.0.0
ID: "com.mycompany.northwind"
version: 1.0.0
-
+
parameters:
hcp-deployer-version: "1.0.0"
-
+
modules:
- name: "fiorinorthwind"
type: html5
@@ -264,14 +226,14 @@ public class MTABuildTest extends BasePipelineTest {
'''
}
- private noIdMtaYaml(){
+ private noIdMtaYaml() {
return '''
_schema-version: "2.0.0"
version: 1.0.0
-
+
parameters:
hcp-deployer-version: "1.0.0"
-
+
modules:
- name: "fiorinorthwind"
type: html5
diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy
index bb9dccd25..a86341031 100644
--- a/test/groovy/NeoDeploymentTest.groovy
+++ b/test/groovy/NeoDeploymentTest.groovy
@@ -47,7 +47,6 @@ class NeoDeploymentTest extends BasePipelineTest {
archiveName = "archive.mtar"
helper.registerAllowedMethod('dockerExecute', [Map, Closure], null)
- helper.registerAllowedMethod('error', [String], { s -> throw new AbortException(s) })
helper.registerAllowedMethod('fileExists', [String], { s -> return new File(workspacePath, s).exists() })
helper.registerAllowedMethod('usernamePassword', [Map], { m -> return m })
helper.registerAllowedMethod('withCredentials', [List, Closure], { l, c ->
diff --git a/test/groovy/com/sap/piper/ConfigurationMergerTest.groovy b/test/groovy/com/sap/piper/ConfigurationMergerTest.groovy
index 9529f5e04..125b18712 100644
--- a/test/groovy/com/sap/piper/ConfigurationMergerTest.groovy
+++ b/test/groovy/com/sap/piper/ConfigurationMergerTest.groovy
@@ -44,12 +44,14 @@ class ConfigurationMergerTest {
void testMergeDeepStructure(){
Map defaults = [fruits: [apples: 1, oranges: 10, bananaaas: 0]]
Map configuration = [fruits: [bananaaas: 50, cucumbers: 1000]]
- Map configurationKeys = [fruits: [apples: null, oranges: null, bananaaas: null]]
- Map parameters = [fruits: [apples: 18]]
- Map parameterKeys = [fruits: [apples: null, oranges: null, bananaaas: null]]
- Map merged = ConfigurationMerger.mergeDeepStructure(parameters, parameterKeys, configuration, configurationKeys, defaults)
+ List configurationKeys = ['fruits']
+ Map parameters = [fruits: [apples: 18], veggie: []]
+ List parameterKeys = ['fruits']
+ Map merged = ConfigurationMerger.merge(parameters, parameterKeys, configuration, configurationKeys, defaults)
Assert.assertEquals(50, merged.fruits.bananaaas)
Assert.assertEquals(18, merged.fruits.apples)
- Assert.assertEquals(null, merged.fruits.cucumbers)
+ Assert.assertEquals(10, merged.fruits.oranges)
+ Assert.assertEquals(1000, merged.fruits.cucumbers)
+ Assert.assertEquals(null, merged.veggie)
}
}
diff --git a/test/groovy/com/sap/piper/GitUtilsTest.groovy b/test/groovy/com/sap/piper/GitUtilsTest.groovy
new file mode 100644
index 000000000..8ffff2d24
--- /dev/null
+++ b/test/groovy/com/sap/piper/GitUtilsTest.groovy
@@ -0,0 +1,47 @@
+package com.sap.piper
+
+import com.lesfurets.jenkins.unit.BasePipelineTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+import org.junit.rules.RuleChain
+import util.JenkinsReadMavenPomRule
+import util.JenkinsShellCallRule
+import util.Rules
+import util.SharedLibraryCreator
+
+import static org.junit.Assert.assertEquals
+
+class GitUtilsTest extends BasePipelineTest {
+
+ JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
+ ExpectedException thrown = ExpectedException.none()
+
+ @Rule
+ public RuleChain ruleChain = Rules.getCommonRules(this).around(jscr).around(thrown)
+
+ GitUtils gitUtils
+
+ @Before
+ void init() throws Exception {
+ gitUtils = new GitUtils()
+ prepareObjectInterceptors(gitUtils)
+
+ jscr.setReturnValue('git rev-parse HEAD', 'testCommitId')
+ }
+
+ void prepareObjectInterceptors(object) {
+ object.metaClass.invokeMethod = helper.getMethodInterceptor()
+ object.metaClass.static.invokeMethod = helper.getMethodInterceptor()
+ object.metaClass.methodMissing = helper.getMethodMissingInterceptor()
+ }
+
+ @Test
+ void testGetGitCommitId() {
+
+ assertEquals('testCommitId', gitUtils.getGitCommitId())
+
+ }
+
+}
diff --git a/test/groovy/com/sap/piper/MapUtilsTest.groovy b/test/groovy/com/sap/piper/MapUtilsTest.groovy
new file mode 100644
index 000000000..0cc7f9e67
--- /dev/null
+++ b/test/groovy/com/sap/piper/MapUtilsTest.groovy
@@ -0,0 +1,13 @@
+package com.sap.piper
+
+import org.junit.Assert
+import org.junit.Test
+
+class MapUtilsTest {
+
+ @Test
+ void testIsMap(){
+ Assert.assertTrue('Map is not recognized as Map', MapUtils.isMap([:]))
+ Assert.assertTrue('String is recognized as Map', !MapUtils.isMap('I am not a Map'))
+ }
+}
diff --git a/test/groovy/com/sap/piper/versioning/ArtifactVersioningTest.groovy b/test/groovy/com/sap/piper/versioning/ArtifactVersioningTest.groovy
new file mode 100644
index 000000000..6bc8b1923
--- /dev/null
+++ b/test/groovy/com/sap/piper/versioning/ArtifactVersioningTest.groovy
@@ -0,0 +1,28 @@
+package com.sap.piper.versioning
+
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+
+import static org.junit.Assert.assertTrue
+import static org.junit.Assert.assertEquals
+
+class ArtifactVersioningTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none()
+
+ @Test
+ void testInstatiateFactoryMethod() {
+ def versionObj = ArtifactVersioning.getArtifactVersioning( 'maven', this, [:])
+ assertTrue(versionObj instanceof MavenArtifactVersioning)
+ }
+
+ @Test
+ void testInstatiateFactoryMethodWithInvalidToolId() {
+ thrown.expect(IllegalArgumentException)
+ thrown.expectMessage('No versioning implementation for buildTool: invalid available.')
+ ArtifactVersioning.getArtifactVersioning('invalid', this, [:])
+ }
+}
diff --git a/test/groovy/com/sap/piper/versioning/DockerArtifactVersioningTest.groovy b/test/groovy/com/sap/piper/versioning/DockerArtifactVersioningTest.groovy
new file mode 100644
index 000000000..8af044237
--- /dev/null
+++ b/test/groovy/com/sap/piper/versioning/DockerArtifactVersioningTest.groovy
@@ -0,0 +1,71 @@
+package com.sap.piper.versioning
+
+import com.lesfurets.jenkins.unit.BasePipelineTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+import org.junit.rules.RuleChain
+import util.JenkinsLoggingRule
+import util.JenkinsReadFileRule
+import util.JenkinsReadMavenPomRule
+import util.JenkinsShellCallRule
+import util.JenkinsWriteFileRule
+import util.Rules
+
+import static org.junit.Assert.assertEquals
+import static org.junit.Assert.assertTrue
+
+class DockerArtifactVersioningTest extends BasePipelineTest{
+
+ DockerArtifactVersioning av
+
+ String passedDir
+
+ JenkinsReadFileRule jrfr = new JenkinsReadFileRule(this, 'test/resources/DockerArtifactVersioning')
+ JenkinsWriteFileRule jwfr = new JenkinsWriteFileRule(this)
+ JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
+ ExpectedException thrown = ExpectedException.none()
+
+ @Rule
+ public RuleChain ruleChain = Rules
+ .getCommonRules(this)
+ .around(jrfr)
+ .around(jwfr)
+ .around(jlr)
+ .around(thrown)
+
+ @Before
+ public void init() {
+
+ helper.registerAllowedMethod("dir", [String.class, Closure.class], { s, closure ->
+ passedDir = s
+ return closure()
+ })
+
+ prepareObjectInterceptors(this)
+ }
+
+ @Test
+ void testVersioningFrom() {
+ av = new DockerArtifactVersioning(this, [filePath: 'Dockerfile', dockerVersionSource: 'FROM'])
+ assertEquals('1.2.3', av.getVersion())
+ av.setVersion('1.2.3-20180101')
+ assertEquals('1.2.3-20180101', jwfr.files['VERSION'])
+ assertTrue(jlr.log.contains('[DockerArtifactVersioning] Version from Docker base image tag: 1.2.3'))
+ }
+
+ @Test
+ void testVersioningEnv() {
+ av = new DockerArtifactVersioning(this, [filePath: 'Dockerfile', dockerVersionSource: 'TEST'])
+ assertEquals('2.3.4', av.getVersion())
+ assertTrue(jlr.log.contains('[DockerArtifactVersioning] Version from Docker environment variable TEST: 2.3.4'))
+ }
+
+
+ void prepareObjectInterceptors(object) {
+ object.metaClass.invokeMethod = helper.getMethodInterceptor()
+ object.metaClass.static.invokeMethod = helper.getMethodInterceptor()
+ object.metaClass.methodMissing = helper.getMethodMissingInterceptor()
+ }
+}
diff --git a/test/groovy/com/sap/piper/versioning/MavenArtifactVersioningTest.groovy b/test/groovy/com/sap/piper/versioning/MavenArtifactVersioningTest.groovy
new file mode 100644
index 000000000..69901ec57
--- /dev/null
+++ b/test/groovy/com/sap/piper/versioning/MavenArtifactVersioningTest.groovy
@@ -0,0 +1,54 @@
+package com.sap.piper.versioning
+
+import com.lesfurets.jenkins.unit.BasePipelineTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+import org.junit.rules.RuleChain
+import util.JenkinsReadMavenPomRule
+import util.JenkinsShellCallRule
+import util.Rules
+
+import static org.junit.Assert.assertEquals
+import static org.junit.Assert.assertTrue
+
+class MavenArtifactVersioningTest extends BasePipelineTest{
+
+ MavenArtifactVersioning av
+
+ JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
+ ExpectedException thrown = ExpectedException.none()
+
+ @Rule
+ public RuleChain ruleChain = Rules.getCommonRules(this).around(jscr).around(thrown).around(new JenkinsReadMavenPomRule(this, 'test/resources/MavenArtifactVersioning'))
+
+ @Before
+ public void init() {
+ prepareObjectInterceptors(this)
+ }
+
+ @Test
+ void testVersioning() {
+ av = new MavenArtifactVersioning(this, [filePath: 'pom.xml'])
+ assertEquals('1.2.3', av.getVersion())
+ av.setVersion('1.2.3-20180101')
+ assertEquals('mvn versions:set -DnewVersion=1.2.3-20180101 --file pom.xml', jscr.shell[0])
+ }
+
+
+ @Test
+ void testVersioningCustomFilePathSnapshot() {
+ av = new MavenArtifactVersioning(this, [filePath: 'snapshot/pom.xml'])
+ assertEquals('1.2.3', av.getVersion())
+ av.setVersion('1.2.3-20180101')
+ assertEquals('mvn versions:set -DnewVersion=1.2.3-20180101 --file snapshot/pom.xml', jscr.shell[0])
+ }
+
+
+ void prepareObjectInterceptors(object) {
+ object.metaClass.invokeMethod = helper.getMethodInterceptor()
+ object.metaClass.static.invokeMethod = helper.getMethodInterceptor()
+ object.metaClass.methodMissing = helper.getMethodMissingInterceptor()
+ }
+}
diff --git a/test/groovy/util/JenkinsErrorRule.groovy b/test/groovy/util/JenkinsErrorRule.groovy
new file mode 100644
index 000000000..52809fc67
--- /dev/null
+++ b/test/groovy/util/JenkinsErrorRule.groovy
@@ -0,0 +1,35 @@
+package util
+
+import com.lesfurets.jenkins.unit.BasePipelineTest
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+class JenkinsErrorRule implements TestRule {
+
+ final BasePipelineTest testInstance
+
+
+ JenkinsErrorRule(BasePipelineTest testInstance) {
+ this.testInstance = testInstance
+ }
+
+ @Override
+ Statement apply(Statement base, Description description) {
+ return statement(base)
+ }
+
+ private Statement statement(final Statement base) {
+ return new Statement() {
+ @Override
+ void evaluate() throws Throwable {
+
+ testInstance.helper.registerAllowedMethod('error', [String], {
+ s -> throw new hudson.AbortException(s)
+ })
+
+ base.evaluate()
+ }
+ }
+ }
+}
diff --git a/test/groovy/util/JenkinsReadFileRule.groovy b/test/groovy/util/JenkinsReadFileRule.groovy
new file mode 100644
index 000000000..d1e16d657
--- /dev/null
+++ b/test/groovy/util/JenkinsReadFileRule.groovy
@@ -0,0 +1,41 @@
+package util
+
+import com.lesfurets.jenkins.unit.BasePipelineTest
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+class JenkinsReadFileRule implements TestRule {
+
+ final BasePipelineTest testInstance
+ final String testRoot
+
+ JenkinsReadFileRule(BasePipelineTest testInstance, String testRoot) {
+ this.testInstance = testInstance
+ this.testRoot = testRoot
+ }
+
+ @Override
+ Statement apply(Statement base, Description description) {
+ return statement(base)
+ }
+
+ private Statement statement(final Statement base) {
+ return new Statement() {
+ @Override
+ void evaluate() throws Throwable {
+
+ testInstance.helper.registerAllowedMethod( 'readFile', [String.class], {s -> return (loadFile("${testRoot}/${s}")).getText('UTF-8')} )
+
+ testInstance.helper.registerAllowedMethod( 'readFile', [Map.class], {m -> return (loadFile("${testRoot}/${m.file}")).getText(m.encoding?m.encoding:'UTF-8')} )
+
+ base.evaluate()
+ }
+ }
+ }
+
+ File loadFile(String path){
+ return new File(path)
+ }
+
+}
diff --git a/test/groovy/util/JenkinsReadMavenPomRule.groovy b/test/groovy/util/JenkinsReadMavenPomRule.groovy
new file mode 100644
index 000000000..4c6d7f3a0
--- /dev/null
+++ b/test/groovy/util/JenkinsReadMavenPomRule.groovy
@@ -0,0 +1,66 @@
+package util
+
+import com.lesfurets.jenkins.unit.BasePipelineTest
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+class JenkinsReadMavenPomRule implements TestRule {
+
+ final BasePipelineTest testInstance
+ final String testRoot
+
+ JenkinsReadMavenPomRule(BasePipelineTest testInstance, String testRoot) {
+ this.testInstance = testInstance
+ this.testRoot = testRoot
+ }
+
+ @Override
+ Statement apply(Statement base, Description description) {
+ return statement(base)
+ }
+
+ private Statement statement(final Statement base) {
+ return new Statement() {
+ @Override
+ void evaluate() throws Throwable {
+
+ testInstance.helper.registerAllowedMethod('readMavenPom', [Map.class], {m -> return loadPom("${testRoot}/${m.file}")})
+
+ base.evaluate()
+ }
+ }
+ }
+
+ MockPom loadPom( String path ){
+ return new MockPom( path )
+ }
+
+ class MockPom {
+ def pom
+ MockPom(String path){
+ def f = new File( path )
+ if ( f.exists() ){
+ this.pom = new XmlSlurper().parse(f)
+ }
+ else {
+ throw new FileNotFoundException( 'Failed to find file: ' + path )
+ }
+ }
+ String getVersion(){
+ return pom.version
+ }
+ String getGroupId(){
+ return pom.groupId
+ }
+ String getArtifactId(){
+ return pom.artifactId
+ }
+ String getPackaging(){
+ return pom.packaging
+ }
+ String getName(){
+ return pom.name
+ }
+ }
+}
diff --git a/test/groovy/util/JenkinsShellCallRule.groovy b/test/groovy/util/JenkinsShellCallRule.groovy
index ce17ce7d6..0541f87ef 100644
--- a/test/groovy/util/JenkinsShellCallRule.groovy
+++ b/test/groovy/util/JenkinsShellCallRule.groovy
@@ -11,10 +11,16 @@ class JenkinsShellCallRule implements TestRule {
List shell = []
+ def returnValues = [:]
+
JenkinsShellCallRule(BasePipelineTest testInstance) {
this.testInstance = testInstance
}
+ def setReturnValue(script, value) {
+ returnValues[script] = value
+ }
+
@Override
Statement apply(Statement base, Description description) {
return statement(base)
@@ -26,10 +32,17 @@ class JenkinsShellCallRule implements TestRule {
void evaluate() throws Throwable {
testInstance.helper.registerAllowedMethod("sh", [String.class], {
- command ->
+ command ->
shell.add(command.replaceAll(/\s+/," ").trim())
})
+ testInstance.helper.registerAllowedMethod("sh", [Map.class], {
+ m ->
+ shell.add(m.script.replaceAll(/\s+/," ").trim())
+ if (m.returnStdout || m.returnStatus)
+ return returnValues[m.script]
+ })
+
base.evaluate()
}
}
diff --git a/test/groovy/util/JenkinsWriteFileRule.groovy b/test/groovy/util/JenkinsWriteFileRule.groovy
new file mode 100644
index 000000000..6a59dcf32
--- /dev/null
+++ b/test/groovy/util/JenkinsWriteFileRule.groovy
@@ -0,0 +1,34 @@
+package util
+
+import com.lesfurets.jenkins.unit.BasePipelineTest
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+class JenkinsWriteFileRule implements TestRule {
+
+ final BasePipelineTest testInstance
+
+ Map files = [:]
+
+ JenkinsWriteFileRule(BasePipelineTest testInstance) {
+ this.testInstance = testInstance
+ }
+
+ @Override
+ Statement apply(Statement base, Description description) {
+ return statement(base)
+ }
+
+ private Statement statement(final Statement base) {
+ return new Statement() {
+ @Override
+ void evaluate() throws Throwable {
+
+ testInstance.helper.registerAllowedMethod( 'writeFile', [Map.class], {m -> files[m.file] = m.text.toString()})
+
+ base.evaluate()
+ }
+ }
+ }
+}
diff --git a/test/groovy/util/Rules.groovy b/test/groovy/util/Rules.groovy
index d009d2576..e9c5791de 100644
--- a/test/groovy/util/Rules.groovy
+++ b/test/groovy/util/Rules.groovy
@@ -1,8 +1,8 @@
-package util;
+package util
-import org.junit.rules.RuleChain;
+import org.junit.rules.RuleChain
-import com.lesfurets.jenkins.unit.BasePipelineTest;
+import com.lesfurets.jenkins.unit.BasePipelineTest
import com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration
public class Rules {
@@ -15,5 +15,6 @@ public class Rules {
return RuleChain.outerRule(new JenkinsSetupRule(testCase, libConfig))
.around(new JenkinsReadYamlRule(testCase))
.around(new JenkinsResetDefaultCacheRule())
+ .around(new JenkinsErrorRule(testCase))
}
}
diff --git a/test/resources/DockerArtifactVersioning/Dockerfile b/test/resources/DockerArtifactVersioning/Dockerfile
new file mode 100644
index 000000000..0ddb8e2bb
--- /dev/null
+++ b/test/resources/DockerArtifactVersioning/Dockerfile
@@ -0,0 +1,5 @@
+FROM rootImage:1.2.3
+
+USER root
+
+ENV TEST 2.3.4
diff --git a/test/resources/MavenArtifactVersioning/pom.xml b/test/resources/MavenArtifactVersioning/pom.xml
new file mode 100644
index 000000000..3f9487ae1
--- /dev/null
+++ b/test/resources/MavenArtifactVersioning/pom.xml
@@ -0,0 +1,8 @@
+
+ 4.0.0
+ com.sap.piper
+ library-test
+ war
+ 1.2.3
+ library-test
+
diff --git a/test/resources/MavenArtifactVersioning/snapshot/pom.xml b/test/resources/MavenArtifactVersioning/snapshot/pom.xml
new file mode 100644
index 000000000..241042583
--- /dev/null
+++ b/test/resources/MavenArtifactVersioning/snapshot/pom.xml
@@ -0,0 +1,8 @@
+
+ 4.0.0
+ com.sap.piper
+ library-test
+ war
+ 1.2.3-SNAPSHOT
+ library-test
+
diff --git a/vars/artifactSetVersion.groovy b/vars/artifactSetVersion.groovy
new file mode 100644
index 000000000..8b75014d8
--- /dev/null
+++ b/vars/artifactSetVersion.groovy
@@ -0,0 +1,138 @@
+import com.sap.piper.ConfigurationLoader
+import com.sap.piper.ConfigurationMerger
+import com.sap.piper.GitUtils
+import com.sap.piper.Utils
+import com.sap.piper.versioning.ArtifactVersioning
+
+import groovy.text.SimpleTemplateEngine
+
+def call(Map parameters = [:]) {
+
+ def stepName = 'artifactSetVersion'
+
+ handlePipelineStepErrors (stepName: stepName, stepParameters: parameters) {
+
+ def gitUtils = parameters.juStabGitUtils
+ if (gitUtils == null) {
+ gitUtils = new GitUtils()
+ }
+
+ if (sh(returnStatus: true, script: 'git diff --quiet HEAD') != 0)
+ error "[${stepName}] Files in the workspace have been changed previously - aborting ${stepName}"
+
+ def script = parameters.script
+ if (script == null)
+ script = [commonPipelineEnvironment: commonPipelineEnvironment]
+
+ prepareDefaultValues script: script
+
+ final Map stepDefaults = ConfigurationLoader.defaultStepConfiguration(script, stepName)
+ final Map stepConfiguration = ConfigurationLoader.stepConfiguration(script, stepName)
+
+ List parameterKeys = [
+ 'artifactType',
+ 'buildTool',
+ 'dockerVersionSource',
+ 'filePath',
+ 'gitCommitId',
+ 'gitCredentialsId',
+ 'gitUserEMail',
+ 'gitUserName',
+ 'gitSshUrl',
+ 'tagPrefix',
+ 'timestamp',
+ 'timestampTemplate',
+ 'versioningTemplate'
+ ]
+ Map pipelineDataMap = [
+ gitCommitId: gitUtils.getGitCommitId()
+ ]
+ List stepConfigurationKeys = [
+ 'artifactType',
+ 'buildTool',
+ 'dockerVersionSource',
+ 'filePath',
+ 'gitCredentialsId',
+ 'gitUserEMail',
+ 'gitUserName',
+ 'gitSshUrl',
+ 'tagPrefix',
+ 'timestamp',
+ 'timestampTemplate',
+ 'versioningTemplate'
+ ]
+
+ Map configuration = ConfigurationMerger.mergeWithPipelineData(parameters, parameterKeys, pipelineDataMap, stepConfiguration, stepConfigurationKeys, stepDefaults)
+
+ def utils = new Utils()
+ def buildTool = utils.getMandatoryParameter(configuration, 'buildTool')
+
+ if (!configuration.filePath)
+ configuration.filePath = configuration[buildTool].filePath //use default configuration
+
+ def newVersion
+ def artifactVersioning = ArtifactVersioning.getArtifactVersioning(buildTool, this, configuration)
+
+ if(configuration.artifactType == 'appContainer' && configuration.dockerVersionSource == 'appVersion'){
+ if (script.commonPipelineEnvironment.getArtifactVersion())
+ //replace + sign if available since + is not allowed in a Docker tag
+ newVersion = script.commonPipelineEnvironment.getArtifactVersion().replace('+', '_')
+ else
+ error ("[${stepName}] No artifact version available for 'dockerVersionSource: appVersion' -> executeBuild needs to run for the application artifact first to set the artifactVersion for the application artifact.'")
+ } else {
+ def currentVersion = artifactVersioning.getVersion()
+
+ def timestamp = configuration.timestamp ? configuration.timestamp : getTimestamp(configuration.timestampTemplate)
+
+ def versioningTemplate = configuration.versioningTemplate ? configuration.versioningTemplate : configuration[configuration.buildTool].versioningTemplate
+ //defined in default configuration
+ def binding = [version: currentVersion, timestamp: timestamp, commitId: configuration.gitCommitId]
+ def templatingEngine = new SimpleTemplateEngine()
+ def template = templatingEngine.createTemplate(versioningTemplate).make(binding)
+ newVersion = template.toString()
+ }
+
+ artifactVersioning.setVersion(newVersion)
+
+ sh 'git add .'
+
+ def gitCommitId
+
+ sshagent([configuration.gitCredentialsId]) {
+ def gitUserMailConfig = ''
+ if (configuration.gitUserName && configuration.gitUserEMail)
+ gitUserMailConfig = "-c user.email=\"${configuration.gitUserEMail}\" -c user.name \"${configuration.gitUserName}\""
+
+ try {
+ sh "git ${gitUserMailConfig} commit -m 'update version ${newVersion}'"
+ } catch (e) {
+ error "[${stepName}]git commit failed: ${e}"
+ }
+ sh "git remote set-url origin ${configuration.gitSshUrl}"
+ sh "git tag ${configuration.tagPrefix}${newVersion}"
+ sh "git push origin ${configuration.tagPrefix}${newVersion}"
+
+ gitCommitId = gitUtils.getGitCommitId()
+
+ }
+
+ if(buildTool == 'docker' && configuration.artifactType == 'appContainer') {
+ script.commonPipelineEnvironment.setAppContainerProperty('artifactVersion', newVersion)
+ script.commonPipelineEnvironment.setAppContainerProperty('gitCommitId', gitCommitId)
+ } else {
+ //standard case
+ script.commonPipelineEnvironment.setArtifactVersion(newVersion)
+ script.commonPipelineEnvironment.setGitCommitId(gitCommitId)
+ }
+ echo "[${stepName}]New version: ${newVersion}"
+ }
+}
+
+def getTimestamp(pattern){
+ return sh(returnStdout: true, script: "date +'${pattern}'").trim()
+}
+
+
+
+
+
diff --git a/vars/commonPipelineEnvironment.groovy b/vars/commonPipelineEnvironment.groovy
index c2807a92e..1ff5bdea6 100644
--- a/vars/commonPipelineEnvironment.groovy
+++ b/vars/commonPipelineEnvironment.groovy
@@ -4,6 +4,13 @@ class commonPipelineEnvironment implements Serializable {
//stores version of the artifact which is build during pipeline run
def artifactVersion
+ //stores the gitCommitId as well as additional git information for the build during pipeline run
+ private String gitCommitId
+ private String gitSshUrl
+
+ //stores properties for a pipeline which build an artifact and then bundles it into a container
+ private Map appContainerProperties = [:]
+
Map configuration = [:]
Map defaultConfiguration = [:]
@@ -14,6 +21,14 @@ class commonPipelineEnvironment implements Serializable {
private String mtarFilePath
+ def setAppContainerProperty(property, value) {
+ appContainerProperties[property] = value
+ }
+
+ def getAppContainerProperty(property) {
+ return appContainerProperties[property]
+ }
+
def setArtifactVersion(version) {
artifactVersion = version
}
@@ -41,6 +56,22 @@ class commonPipelineEnvironment implements Serializable {
return configProperties[property]
}
+ def setGitCommitId(commitId) {
+ gitCommitId = commitId
+ }
+
+ def getGitCommitId() {
+ return gitCommitId
+ }
+
+ def setGitSshUrl(url) {
+ gitSshUrl = url
+ }
+
+ def getGitSshUrl() {
+ return gitSshUrl
+ }
+
def getInfluxCustomData() {
return influxCustomData
}