From 33daaa2c9cf80f8e3e0a21b4640b6f5d9838d1ef Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Thu, 28 Dec 2017 13:10:11 +0100 Subject: [PATCH 01/32] Add support for WAR file deployment/rolling-update --- documentation/docs/steps/neoDeploy.md | 58 +++++++++++++++--- vars/neoDeploy.groovy | 87 +++++++++++++++++++++++---- 2 files changed, 125 insertions(+), 20 deletions(-) diff --git a/documentation/docs/steps/neoDeploy.md b/documentation/docs/steps/neoDeploy.md index 7bed8573e..661b388b9 100644 --- a/documentation/docs/steps/neoDeploy.md +++ b/documentation/docs/steps/neoDeploy.md @@ -16,22 +16,58 @@ needs to be extracted into the folder provided by `neoHome`. In case this parame * **Java 8 or higher** - needed by the *Neo-Java-Web-SDK* -## Parameters -| parameter | mandatory | default | possible values | -| -------------------|-----------|----------------------------------------------------------------------------------------------|-----------------| -| `script` | yes | | | -| `archivePath` | yes | | | -| `deployHost` | no | `'DEPLOY_HOST'` from `commonPipelineEnvironment` | | -| `deployAccount` | no | `'CI_DEPLOY_ACCOUNT'` from `commonPipelineEnvironment` | | -| `neoCredentialsId` | no | `'CI_CREDENTIALS_ID'` | | -| `neoHome` | no | Environment is checked for `NEO_HOME`,
otherwise the neo toolset is expected in the path | | +## Parameters when using MTA deployment method +| parameter | mandatory | default | possible values | +| -------------------|-----------|----------------------------------------------------------------------------------------------|-------------------------------------------------| +| `deployMode` | yes | `'MTA'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | +| `script` | yes | | | +| `archivePath` | yes | | | +| `deployHost` | no | `'DEPLOY_HOST'` from `commonPipelineEnvironment` | | +| `deployAccount` | no | `'CI_DEPLOY_ACCOUNT'` from `commonPipelineEnvironment` | | +| `neoCredentialsId` | no | `'CI_CREDENTIALS_ID'` | | +| `neoHome` | no | Environment is checked for `NEO_HOME`,
otherwise the neo toolset is expected in the path | | +## Parameters when using WAR file deployment method with .properties file +| parameter | mandatory | default | possible values | +| -------------------|-----------|----------------------------------------------------------------------------------------------|-------------------------------------------------| +| `deployMode` | yes | `'WAR_PROPERTIESFILE'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | +| `warAction` | yes | `'deploy'` | `'deploy'`, `'rolling-update'` | +| `script` | yes | | | +| `archivePath` | yes | | | +| `neoCredentialsId` | no | `'CI_CREDENTIALS_ID'` | | +| `neoHome` | no | Environment is checked for `NEO_HOME`,
otherwise the neo toolset is expected in the path | | +| `propertiesFile` | yes | | | + +## Parameters when using WAR file deployment method witout .properties file - with parameters +| parameter | mandatory | default | possible values | +| -------------------|-----------|----------------------------------------------------------------------------------------------|-------------------------------------------------| +| `deployMode` | yes | `'WAR_PARAMS'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | +| `warAction` | yes | `'deploy'` | `'deploy'`, `'rolling-update'` | +| `script` | yes | | | +| `archivePath` | yes | | | +| `deployHost` | no | `'DEPLOY_HOST'` from `commonPipelineEnvironment` | | +| `deployAccount` | no | `'CI_DEPLOY_ACCOUNT'` from `commonPipelineEnvironment` | | +| `neoCredentialsId` | no | `'CI_CREDENTIALS_ID'` | | +| `neoHome` | no | Environment is checked for `NEO_HOME`,
otherwise the neo toolset is expected in the path | | +| `applicationName` | yes | | | +| `runtime` | yes | | | +| `runtime-version` | yes | | | +| `size` | no | `'lite'` | `'lite'`, `'pro'`, `'prem'`, `'prem-plus'` | + + +* `deployMode` - The deployment mode which should be used. Available options are `'MTA'` (default), `'WAR_PARAMS'` (deploying WAR file and passing all the deployment parameters via the function call) and `'WAR_PROPERTIESFILE'` (deploying WAR file and putting all the deployment parameters in a .properties file) * `script` - The common 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. * `archivePath`- The path to the archive for deployment to SAP CP. * `deployHost` - The SAP Cloud Platform host to deploy to. * `deployAccount` - The SAP Cloud Platform account to deploy to. * `credentialsId` - The Jenkins credentials containing user and password used for SAP CP deployment. * `neoHome` - The path to the `neo-java-web-sdk` tool used for SAP CP deployment. If no parameter is provided, the path is retrieved from the Jenkins environment variables using `env.NEO_HOME`. If this Jenkins environment variable is not set it is assumed that the tool is available in the `PATH`. +* `propertiesFile` - The path to the .properties file in which all necessary deployment properties for the application are defined. +* `warAction` - Action mode when using WAR file mode. Available options are `deploy` (default) and `rolling-update` which performs update of an application without downtime in one go. +* `applicationName` - Name of the application you want to manage, configure, or deploy +* `runtime` - Name of SAP Cloud Platform application runtime +* `runtime-version` - Version of SAP Cloud Platform application runtime +* `size` - Compute unit (VM) size. Acceptable values: lite, pro, prem, prem-plus. ## Return value none @@ -42,6 +78,10 @@ none ## Exceptions * `Exception`: * If `archivePath` is not provided. + * If `propertiesFile` is not provided (when using `'WAR_PROPERTIESFILE'` deployment mode). + * If `applicationName` is not provided (when using `'WAR_PARAMS'` deployment mode). + * If `runtime` is not provided (when using `'WAR_PARAMS'` deployment mode). + * If `runtime-version` is not provided (when using `'WAR_PARAMS'` deployment mode). * `AbortException`: * If neo-java-web-sdk is not installed, or `neoHome`is wrong. * If `deployHost` is wrong. diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index ca883e3ec..ead8db676 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -3,11 +3,11 @@ import com.sap.piper.Utils def call(parameters = [:]) { - handlePipelineStepErrors (stepName: 'neoDeploy', stepParameters: parameters) { + handlePipelineStepErrors(stepName: 'neoDeploy', stepParameters: parameters) { def utils = new Utils() def script = parameters.script - if (script == null){ + if (script == null) { script = [commonPipelineEnvironment: commonPipelineEnvironment] } @@ -15,10 +15,34 @@ def call(parameters = [:]) { if (!archivePath.isAbsolute()) { archivePath = new File(pwd(), archivePath.getPath()) } - if (!archivePath.exists()){ + if (!archivePath.exists()) { error "Archive cannot be found with parameter archivePath: '${archivePath}'." } + def deployMode = utils.getMandatoryParameter(parameters, 'deployMode', 'MTA') + + def propertiesFile + def warAction + if (deployMode == 'WAR_PROPERTIESFILE') { + propertiesFile = new File(utils.getMandatoryParameter(parameters, 'propertiesFile', null)) + if (!propertiesFile.isAbsolute()) { + propertiesFile = new File(pwd(), propertiesFile.getPath()) + } + warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') + } + + def applicationName + def runtime + def runtimeVersion + def vmSize + if (deployMode == 'WAR_PARAMS') { + applicationName = utils.getMandatoryParameter(parameters, 'applicationName', null) + runtime = utils.getMandatoryParameter(parameters, 'runtime', null) + runtimeVersion = utils.getMandatoryParameter(parameters, 'runtimeVersion', null) + vmSize = utils.getMandatoryParameter(parameters, 'vmSize', 'lite') + warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') + } + def defaultDeployHost = script.commonPipelineEnvironment.getConfigProperty('DEPLOY_HOST') def defaultDeployAccount = script.commonPipelineEnvironment.getConfigProperty('CI_DEPLOY_ACCOUNT') def defaultCredentialsId = script.commonPipelineEnvironment.getConfigProperty('neoCredentialsId') @@ -26,26 +50,67 @@ def call(parameters = [:]) { defaultCredentialsId = 'CI_CREDENTIALS_ID' } - def deployHost = utils.getMandatoryParameter(parameters, 'deployHost', defaultDeployHost) - def deployAccount = utils.getMandatoryParameter(parameters, 'deployAccount', defaultDeployAccount) + def deployHost + def deployAccount + if (deployMode.equals('MTA') || deployMode.equals('WAR_PARAMS')) { + deployHost = utils.getMandatoryParameter(parameters, 'deployHost', defaultDeployHost) + deployAccount = utils.getMandatoryParameter(parameters, 'deployAccount', defaultDeployAccount) + } + def credentialsId = parameters.get('neoCredentialsId', defaultCredentialsId) def neoExecutable = getNeoExecutable(parameters) - withCredentials([usernamePassword( + if (deployMode == 'MTA') { + withCredentials([usernamePassword( credentialsId: credentialsId, passwordVariable: 'password', - usernameVariable: 'username' - )]) { - sh """#!/bin/bash - "${neoExecutable}" deploy-mta \ + usernameVariable: 'username')]) { + sh """#!/bin/bash + "${neoExecutable}" deploy-mta \ --user '${username}' \ --host '${deployHost}' \ --source "${archivePath.getAbsolutePath()}" \ --account '${deployAccount}' \ --password '${password}' \ --synchronous - """ + """ + } + } + + if (deployMode == 'WAR_PARAMS') { + withCredentials([usernamePassword( + credentialsId: credentialsId, + passwordVariable: 'password', + usernameVariable: 'username')]) { + sh """#!/bin/bash + "${neoExecutable}" "${warAction}" \ + --user '${username}' \ + --password '${password}' \ + --host '${deployHost}' \ + --account ${deployAccount} \ + --application '${applicationName}' \ + --runtime '${runtime}' \ + --runtime-version '${runtimeVersion}' \ + --size '${vmSize}' \ + --source '${archivePath.getAbsolutePath()}' + """ + } + } + + if (deployMode == 'WAR_PROPERTIESFILE') { + withCredentials([usernamePassword( + credentialsId: credentialsId, + passwordVariable: 'password', + usernameVariable: 'username')]) { + sh """#!/bin/bash + "${neoExecutable}" "${warAction}" \ + '${propertiesFile.getAbsolutePath()}' \ + --user '${username}' \ + --password '${password}' \ + --source '${archivePath.getAbsolutePath()}' + """ + } } } } From 848a8fc9e70580b86c32c56ac43e355e7c159e74 Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Thu, 28 Dec 2017 16:16:02 +0100 Subject: [PATCH 02/32] Update documentation for neoDeploy --- documentation/docs/steps/neoDeploy.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/documentation/docs/steps/neoDeploy.md b/documentation/docs/steps/neoDeploy.md index 661b388b9..dfa9d9621 100644 --- a/documentation/docs/steps/neoDeploy.md +++ b/documentation/docs/steps/neoDeploy.md @@ -2,21 +2,21 @@ ## Description Deploys an Application to SAP Cloud Platform (SAP CP) using the SAP Cloud Platform Console Client (Neo Java Web SDK). - + ## Prerequisites * **SAP CP account** - the account to where the application is deployed. * **SAP CP user for deployment** - a user with deployment permissions in the given account. * **Jenkins credentials for deployment** - must be configured in Jenkins credentials with a dedicated Id. ![Jenkins credentials configuration](../images/neo_credentials.png) - + * **Neo Java Web SDK** - can be downloaded from [Maven Central](http://central.maven.org/maven2/com/sap/cloud/neo-java-web-sdk/). The Neo Java Web SDK needs to be extracted into the folder provided by `neoHome`. In case this parameters is not provided and there is no NEO_HOME parameter in the environment `/tools` needs to be in the `PATH`. * **Java 8 or higher** - needed by the *Neo-Java-Web-SDK* -## Parameters when using MTA deployment method +## Parameters when using MTA deployment method (default - MTA) | parameter | mandatory | default | possible values | | -------------------|-----------|----------------------------------------------------------------------------------------------|-------------------------------------------------| | `deployMode` | yes | `'MTA'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | @@ -27,10 +27,10 @@ needs to be extracted into the folder provided by `neoHome`. In case this parame | `neoCredentialsId` | no | `'CI_CREDENTIALS_ID'` | | | `neoHome` | no | Environment is checked for `NEO_HOME`,
otherwise the neo toolset is expected in the path | | -## Parameters when using WAR file deployment method with .properties file +## Parameters when using WAR file deployment method with .properties file (WAR_PROPERTIESFILE) | parameter | mandatory | default | possible values | | -------------------|-----------|----------------------------------------------------------------------------------------------|-------------------------------------------------| -| `deployMode` | yes | `'WAR_PROPERTIESFILE'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | +| `deployMode` | yes | `'MTA'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | | `warAction` | yes | `'deploy'` | `'deploy'`, `'rolling-update'` | | `script` | yes | | | | `archivePath` | yes | | | @@ -38,10 +38,10 @@ needs to be extracted into the folder provided by `neoHome`. In case this parame | `neoHome` | no | Environment is checked for `NEO_HOME`,
otherwise the neo toolset is expected in the path | | | `propertiesFile` | yes | | | -## Parameters when using WAR file deployment method witout .properties file - with parameters +## Parameters when using WAR file deployment method witout .properties file - with parameters (WAR_PARAMS) | parameter | mandatory | default | possible values | | -------------------|-----------|----------------------------------------------------------------------------------------------|-------------------------------------------------| -| `deployMode` | yes | `'WAR_PARAMS'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | +| `deployMode` | yes | `'MTA'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | | `warAction` | yes | `'deploy'` | `'deploy'`, `'rolling-update'` | | `script` | yes | | | | `archivePath` | yes | | | From ac27605e7a188365dca836cbc97f71d121de56f6 Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Wed, 10 Jan 2018 13:22:36 +0100 Subject: [PATCH 03/32] Check for invalid deployment mode && Refactoring --- vars/neoDeploy.groovy | 64 ++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index ead8db676..a2c1592ca 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -3,11 +3,11 @@ import com.sap.piper.Utils def call(parameters = [:]) { - handlePipelineStepErrors(stepName: 'neoDeploy', stepParameters: parameters) { + handlePipelineStepErrors (stepName: 'neoDeploy', stepParameters: parameters) { def utils = new Utils() def script = parameters.script - if (script == null) { + if (script == null){ script = [commonPipelineEnvironment: commonPipelineEnvironment] } @@ -15,7 +15,7 @@ def call(parameters = [:]) { if (!archivePath.isAbsolute()) { archivePath = new File(pwd(), archivePath.getPath()) } - if (!archivePath.exists()) { + if (!archivePath.exists()){ error "Archive cannot be found with parameter archivePath: '${archivePath}'." } @@ -52,6 +52,11 @@ def call(parameters = [:]) { def deployHost def deployAccount + + if (!deployMode.equals('MTA') && !deployMode.equals('WAR_PARAMS') && !deployMode.equals('WAR_PROPERTIESFILE')) { + echo "[neoDeploy] Invalid deployment mode \"${deployMode}\". Deployment will be skipped." + } + if (deployMode.equals('MTA') || deployMode.equals('WAR_PARAMS')) { deployHost = utils.getMandatoryParameter(parameters, 'deployHost', defaultDeployHost) deployAccount = utils.getMandatoryParameter(parameters, 'deployAccount', defaultDeployAccount) @@ -61,54 +66,45 @@ def call(parameters = [:]) { def neoExecutable = getNeoExecutable(parameters) - if (deployMode == 'MTA') { - withCredentials([usernamePassword( - credentialsId: credentialsId, - passwordVariable: 'password', - usernameVariable: 'username')]) { + withCredentials([usernamePassword( + credentialsId: credentialsId, + passwordVariable: 'password', + usernameVariable: 'username')]) { + + def commonDeployParams = + """--user '${username}' \ + --password '${password}' \ + --source '${archivePath.getAbsolutePath()}' \ + """ + + if (deployMode == 'MTA') { sh """#!/bin/bash "${neoExecutable}" deploy-mta \ - --user '${username}' \ + '${commonDeployParams}' \ --host '${deployHost}' \ - --source "${archivePath.getAbsolutePath()}" \ --account '${deployAccount}' \ - --password '${password}' \ --synchronous """ } - } - if (deployMode == 'WAR_PARAMS') { - withCredentials([usernamePassword( - credentialsId: credentialsId, - passwordVariable: 'password', - usernameVariable: 'username')]) { + if (deployMode == 'WAR_PARAMS') { sh """#!/bin/bash - "${neoExecutable}" "${warAction}" \ - --user '${username}' \ - --password '${password}' \ + "${neoExecutable}" '${warAction}' \ + '${commonDeployParams}' \ --host '${deployHost}' \ - --account ${deployAccount} \ + --account '${deployAccount}' \ --application '${applicationName}' \ --runtime '${runtime}' \ --runtime-version '${runtimeVersion}' \ - --size '${vmSize}' \ - --source '${archivePath.getAbsolutePath()}' + --size '${vmSize}' """ } - } - if (deployMode == 'WAR_PROPERTIESFILE') { - withCredentials([usernamePassword( - credentialsId: credentialsId, - passwordVariable: 'password', - usernameVariable: 'username')]) { + if (deployMode == 'WAR_PROPERTIESFILE') { sh """#!/bin/bash - "${neoExecutable}" "${warAction}" \ - '${propertiesFile.getAbsolutePath()}' \ - --user '${username}' \ - --password '${password}' \ - --source '${archivePath.getAbsolutePath()}' + "${neoExecutable}" '${warAction}' \ + '${commonDeployParams}' \ + '${propertiesFile.getAbsolutePath()}' """ } } From ced5307eb5170dfa995f966a51dcba2bfa1226d7 Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Wed, 10 Jan 2018 15:25:50 +0100 Subject: [PATCH 04/32] Adjusting UnitTests --- test/groovy/NeoDeploymentTest.groovy | 8 ++++---- vars/neoDeploy.groovy | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 47182ef20..f2b457cc3 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -60,7 +60,7 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(defaultPipeline()).execute(archivePath, 'myCredentialsId') - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --host 'test\.deploy\.host\.com' --source ".*" --account 'trialuser123' --password '\*\*\*\*\*\*\*\*' --synchronous/ + assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." @@ -90,7 +90,7 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(noCredentialsIdPipeline()).execute(archivePath) - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --host 'test\.deploy\.host\.com' --source ".*" --account 'trialuser123' --password '\*\*\*\*\*\*\*\*' --synchronous/ + assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." } @@ -103,7 +103,7 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(noCredentialsIdPipeline()).execute(archivePath) - assert shellCalls[0] =~ /#!\/bin\/bash "neo" deploy-mta --user 'defaultUser' --host 'test\.deploy\.host\.com' --source ".*" --account 'trialuser123' --password '\*\*\*\*\*\*\*\*' --synchronous/ + assert shellCalls[0] =~ /#!\/bin\/bash "neo" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ assert messages[1] == "Using Neo executable from PATH." } @@ -116,7 +116,7 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(neoHomeParameterPipeline()).execute(archivePath, 'myCredentialsId') - assert shellCalls[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --host 'test\.deploy\.host\.com' --source ".*" --account 'trialuser123' --password '\*\*\*\*\*\*\*\*' --synchronous.*/ + assert shellCalls[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ assert messages[1] == "[neoDeploy] Neo executable \"/etc/neo/tools/neo.sh\" retrieved from parameters." diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index a2c1592ca..5e9b2918b 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -74,13 +74,13 @@ def call(parameters = [:]) { def commonDeployParams = """--user '${username}' \ --password '${password}' \ - --source '${archivePath.getAbsolutePath()}' \ + --source "${archivePath.getAbsolutePath()}" \ """ if (deployMode == 'MTA') { sh """#!/bin/bash "${neoExecutable}" deploy-mta \ - '${commonDeployParams}' \ + ${commonDeployParams} \ --host '${deployHost}' \ --account '${deployAccount}' \ --synchronous @@ -90,7 +90,7 @@ def call(parameters = [:]) { if (deployMode == 'WAR_PARAMS') { sh """#!/bin/bash "${neoExecutable}" '${warAction}' \ - '${commonDeployParams}' \ + ${commonDeployParams} \ --host '${deployHost}' \ --account '${deployAccount}' \ --application '${applicationName}' \ @@ -103,7 +103,7 @@ def call(parameters = [:]) { if (deployMode == 'WAR_PROPERTIESFILE') { sh """#!/bin/bash "${neoExecutable}" '${warAction}' \ - '${commonDeployParams}' \ + ${commonDeployParams} \ '${propertiesFile.getAbsolutePath()}' """ } From d3d35cc140befc0ce9344c0ed1eace8e0b5f3552 Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Thu, 11 Jan 2018 15:25:58 +0100 Subject: [PATCH 05/32] Unit tests for the new deployMode in NeoDeploy --- test/groovy/NeoDeploymentTest.groovy | 189 +++++++++++++++++++++++++++ vars/neoDeploy.groovy | 15 ++- 2 files changed, 201 insertions(+), 3 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index f2b457cc3..8add8a401 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -19,6 +19,8 @@ class NeoDeploymentTest extends PiperTestBase { public TemporaryFolder tmp = new TemporaryFolder() def archivePath + def warArchivePath + def propertiesFilePath @Before void setUp() { @@ -26,6 +28,8 @@ class NeoDeploymentTest extends PiperTestBase { super.setUp() archivePath = "${tmp.newFolder("workspace").toURI().getPath()}archiveName.mtar" + warArchivePath = "${tmp.getRoot().toURI().getPath()}workspace/warArchive.war" + propertiesFilePath = "${tmp.getRoot().toURI().getPath()}workspace/config.properties" helper.registerAllowedMethod('error', [String], { s -> throw new AbortException(s) }) helper.registerAllowedMethod('usernamePassword', [Map], { m -> return m }) @@ -157,6 +161,69 @@ class NeoDeploymentTest extends PiperTestBase { } + @Test + void mtaDeployModeTest() { + binding.getVariable('env')['NEO_HOME'] = '/opt/neo' + new File(archivePath) << "dummy archive" + + withPipeline(mtaDeployModePiepeline()).execute(archivePath, 'MTA') + + assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ + assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + } + + @Test + void warFileParamsDeployModeTest() { + binding.getVariable('env')['NEO_HOME'] = '/opt/neo' + new File(warArchivePath) << "dummy war archive" + + withPipeline(warParamsDeployModePiepeline()).execute(warArchivePath, 'WAR_PARAMS') + + assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ + assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + } + + @Test + void warPropertiesFileDeployModeTest() { + binding.getVariable('env')['NEO_HOME'] = '/opt/neo' + new File(warArchivePath) << "dummy war archive" + new File(propertiesFilePath) << "dummy properties file" + + withPipeline(warPropertiesFileDeployModePiepeline()).execute(warArchivePath, propertiesFilePath, 'WAR_PROPERTIESFILE') + + assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ + assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + } + + @Test + void applicationNameNotProvidedTest() { + new File(warArchivePath) << "dummy war archive" + + thrown.expect(Exception) + thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR applicationName') + + withPipeline(noApplicationNamePiepeline()).execute(warArchivePath, 'WAR_PARAMS') + } + + @Test + void runtimeNotProvidedTest() { + new File(warArchivePath) << "dummy war archive" + + thrown.expect(Exception) + thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtime') + + withPipeline(noRuntimePiepeline()).execute(warArchivePath, 'WAR_PARAMS') + } + + @Test + void runtimeVersionNotProvidedTest() { + new File(warArchivePath) << "dummy war archive" + + thrown.expect(Exception) + thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtimeVersion') + + withPipeline(noRuntimeVersionPiepeline()).execute(warArchivePath, 'WAR_PARAMS') + } private defaultPipeline(){ return """ @@ -250,4 +317,126 @@ class NeoDeploymentTest extends PiperTestBase { """ } + private noApplicationNamePiepeline() { + return """ + @Library('piper-library-os') + + execute(warArchivePath, deployMode) { + + commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + def runtime = 'neo-javaee6-wp' + def runtimeVersion = '2.125' + + node() { + neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, runtime: runtime, runtimeVersion: runtimeVersion + } + + } + + return this + """ + } + + private noRuntimePiepeline() { + return """ + @Library('piper-library-os') + + execute(warArchivePath, deployMode) { + + commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + def appName = 'testApp' + def runtime = 'neo-javaee6-wp' + def runtimeVersion = '2.125' + + node() { + neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, applicationName: appName, runtimeVersion: runtimeVersion + } + + } + + return this + """ + } + + private noRuntimeVersionPiepeline() { + return """ + @Library('piper-library-os') + + execute(warArchivePath, deployMode) { + + commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + def appName = 'testApp' + def runtime = 'neo-javaee6-wp' + def runtimeVersion = '2.125' + + node() { + neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, applicationName: appName, runtime: runtime + } + + } + + return this + """ + } + + private warPropertiesFileDeployModePiepeline() { + return """ + @Library('piper-library-os') + + execute(warArchivePath, propertiesFilePath, deployMode) { + + node() { + neoDeploy script: this, deployMode: deployMode, archivePath: warArchivePath, propertiesFile: propertiesFilePath + } + + } + + return this + """ + } + + private warParamsDeployModePiepeline() { + return """ + @Library('piper-library-os') + + execute(warArchivePath, deployMode) { + + commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + def appName = 'testApp' + def runtime = 'neo-javaee6-wp' + def runtimeVersion = '2.125' + + node() { + neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, applicationName: appName, runtime: runtime, runtimeVersion: runtimeVersion + } + + } + + return this + """ + } + + private mtaDeployModePiepeline() { + return """ + @Library('piper-library-os') + + execute(archivePath, deployMode) { + + commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + node() { + neoDeploy script: this, archivePath: archivePath, deployMode: deployMode + } + + } + + return this + """ + } + } diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index 5e9b2918b..2bc321b22 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -28,7 +28,13 @@ def call(parameters = [:]) { if (!propertiesFile.isAbsolute()) { propertiesFile = new File(pwd(), propertiesFile.getPath()) } + if (!propertiesFile.exists()){ + error "Properties file cannot be found with parameter propertiesFile: '${propertiesFile}'." + } warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') + if (warAction != 'warAction' || warAction != 'deploy') { + warAction = 'deploy' + } } def applicationName @@ -40,6 +46,9 @@ def call(parameters = [:]) { runtime = utils.getMandatoryParameter(parameters, 'runtime', null) runtimeVersion = utils.getMandatoryParameter(parameters, 'runtimeVersion', null) vmSize = utils.getMandatoryParameter(parameters, 'vmSize', 'lite') + if (vmSize != 'lite' || vmSize !='pro' || vmSize != 'prem' || vmSize != 'prem-plus') { + vmSize = 'lite' + } warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') } @@ -89,7 +98,7 @@ def call(parameters = [:]) { if (deployMode == 'WAR_PARAMS') { sh """#!/bin/bash - "${neoExecutable}" '${warAction}' \ + "${neoExecutable}" ${warAction} \ ${commonDeployParams} \ --host '${deployHost}' \ --account '${deployAccount}' \ @@ -102,9 +111,9 @@ def call(parameters = [:]) { if (deployMode == 'WAR_PROPERTIESFILE') { sh """#!/bin/bash - "${neoExecutable}" '${warAction}' \ + "${neoExecutable}" ${warAction} \ ${commonDeployParams} \ - '${propertiesFile.getAbsolutePath()}' + ${propertiesFile.getAbsolutePath()} """ } } From 998abed37721efbf3dd2f235a69a006f441c941e Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Mon, 15 Jan 2018 15:06:02 +0100 Subject: [PATCH 06/32] Switch library identifier to piper-library-os this identifier is commonly used. --- test/groovy/util/SharedLibraryCreator.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/groovy/util/SharedLibraryCreator.groovy b/test/groovy/util/SharedLibraryCreator.groovy index 420cc2641..e589a5d14 100644 --- a/test/groovy/util/SharedLibraryCreator.groovy +++ b/test/groovy/util/SharedLibraryCreator.groovy @@ -5,7 +5,7 @@ import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library class SharedLibraryCreator { static def lazyLoadedLibrary = library() - .name('piper-library') + .name('piper-library-os') .retriever(new ProjectSource()) .targetPath('is/not/necessary') .defaultVersion("master") @@ -14,7 +14,7 @@ class SharedLibraryCreator { .build() static def implicitLoadedLibrary = library() - .name('piper-library') + .name('piper-library-os') .retriever(new ProjectSource()) .targetPath('is/not/necessary') .defaultVersion("master") From 2a7a35db29e3ce7dad300a37da5b99c7696b95ef Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Tue, 16 Jan 2018 09:43:24 +0100 Subject: [PATCH 07/32] [refactoring] Remove redundant code --- test/groovy/util/SharedLibraryCreator.groovy | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/test/groovy/util/SharedLibraryCreator.groovy b/test/groovy/util/SharedLibraryCreator.groovy index e589a5d14..81bb34124 100644 --- a/test/groovy/util/SharedLibraryCreator.groovy +++ b/test/groovy/util/SharedLibraryCreator.groovy @@ -4,21 +4,18 @@ import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library class SharedLibraryCreator { - static def lazyLoadedLibrary = library() - .name('piper-library-os') - .retriever(new ProjectSource()) - .targetPath('is/not/necessary') - .defaultVersion("master") - .allowOverride(true) - .implicit(false) - .build() + static def lazyLoadedLibrary = getLibraryConfiguration(false) - static def implicitLoadedLibrary = library() + static def implicitLoadedLibrary = getLibraryConfiguration(true) + + private static def getLibraryConfiguration(def implicit) { + library() .name('piper-library-os') .retriever(new ProjectSource()) .targetPath('is/not/necessary') .defaultVersion("master") .allowOverride(true) - .implicit(true) + .implicit(implicit) .build() + } } From a794e9270ba06730ac934ff316963a55c020a7e2 Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Mon, 15 Jan 2018 15:21:48 +0100 Subject: [PATCH 08/32] remove printing the callstack I guess nobody is interested in the callstack printed into the log during the tests. --- test/groovy/util/JenkinsSetupRule.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/test/groovy/util/JenkinsSetupRule.groovy b/test/groovy/util/JenkinsSetupRule.groovy index 7b3487be8..57bcd21ca 100644 --- a/test/groovy/util/JenkinsSetupRule.groovy +++ b/test/groovy/util/JenkinsSetupRule.groovy @@ -44,7 +44,6 @@ class JenkinsSetupRule implements TestRule { base.evaluate() - testInstance.printCallStack() } } } From dd4f9a1b1d241f1e7b8add17c36598411db2c915 Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Tue, 16 Jan 2018 10:54:17 +0100 Subject: [PATCH 09/32] Exception in case of illegal arguments + tests --- test/groovy/NeoDeploymentTest.groovy | 58 +++++++++++++++++++++------- vars/neoDeploy.groovy | 23 +++++------ 2 files changed, 56 insertions(+), 25 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 8add8a401..76859133e 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -166,7 +166,7 @@ class NeoDeploymentTest extends PiperTestBase { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' new File(archivePath) << "dummy archive" - withPipeline(mtaDeployModePiepeline()).execute(archivePath, 'MTA') + withPipeline(mtaDeployModePipeline()).execute(archivePath, 'MTA') assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." @@ -177,7 +177,7 @@ class NeoDeploymentTest extends PiperTestBase { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' new File(warArchivePath) << "dummy war archive" - withPipeline(warParamsDeployModePiepeline()).execute(warArchivePath, 'WAR_PARAMS') + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'WAR_PARAMS', 'lite', 'deploy') assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." @@ -189,7 +189,7 @@ class NeoDeploymentTest extends PiperTestBase { new File(warArchivePath) << "dummy war archive" new File(propertiesFilePath) << "dummy properties file" - withPipeline(warPropertiesFileDeployModePiepeline()).execute(warArchivePath, propertiesFilePath, 'WAR_PROPERTIESFILE') + withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'WAR_PROPERTIESFILE') assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." @@ -202,7 +202,7 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR applicationName') - withPipeline(noApplicationNamePiepeline()).execute(warArchivePath, 'WAR_PARAMS') + withPipeline(noApplicationNamePipeline()).execute(warArchivePath, 'WAR_PARAMS') } @Test @@ -212,7 +212,7 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtime') - withPipeline(noRuntimePiepeline()).execute(warArchivePath, 'WAR_PARAMS') + withPipeline(noRuntimePipeline()).execute(warArchivePath, 'WAR_PARAMS') } @Test @@ -222,7 +222,37 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtimeVersion') - withPipeline(noRuntimeVersionPiepeline()).execute(warArchivePath, 'WAR_PARAMS') + withPipeline(noRuntimeVersionPipeline()).execute(warArchivePath, 'WAR_PARAMS') + } + + @Test + void illegalDeployModeTest() { + new File(warArchivePath) << "dummy war archive" + + thrown.expect(IllegalArgumentException) + thrown.expectMessage("[neoDeploy] Invalid deployMode = 'ILLEGAL_MODE'. Valid 'deployMode' values are: 'MTA', 'WAR_PARAMS' and 'WAR_PROPERTIESFILE'") + + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'ILLEGAL_MODE', 'lite', 'deploy') + } + + @Test + void illegalVMSizeTest() { + new File(warArchivePath) << "dummy war archive" + + thrown.expect(IllegalArgumentException) + thrown.expectMessage("[neoDeploy] Invalid vmSize = 'illegalVM'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") + + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'WAR_PARAMS', 'illegalVM', 'deploy') + } + + @Test + void illegalWARActionTest() { + new File(warArchivePath) << "dummy war archive" + + thrown.expect(IllegalArgumentException) + thrown.expectMessage("[neoDeploy] Invalid warAction = 'illegalWARAction'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") + + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'WAR_PARAMS', 'lite', 'illegalWARAction') } private defaultPipeline(){ @@ -317,7 +347,7 @@ class NeoDeploymentTest extends PiperTestBase { """ } - private noApplicationNamePiepeline() { + private noApplicationNamePipeline() { return """ @Library('piper-library-os') @@ -338,7 +368,7 @@ class NeoDeploymentTest extends PiperTestBase { """ } - private noRuntimePiepeline() { + private noRuntimePipeline() { return """ @Library('piper-library-os') @@ -360,7 +390,7 @@ class NeoDeploymentTest extends PiperTestBase { """ } - private noRuntimeVersionPiepeline() { + private noRuntimeVersionPipeline() { return """ @Library('piper-library-os') @@ -382,7 +412,7 @@ class NeoDeploymentTest extends PiperTestBase { """ } - private warPropertiesFileDeployModePiepeline() { + private warPropertiesFileDeployModePipeline() { return """ @Library('piper-library-os') @@ -398,11 +428,11 @@ class NeoDeploymentTest extends PiperTestBase { """ } - private warParamsDeployModePiepeline() { + private warParamsDeployModePipeline() { return """ @Library('piper-library-os') - execute(warArchivePath, deployMode) { + execute(warArchivePath, deployMode, vmSize, warAction) { commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') @@ -411,7 +441,7 @@ class NeoDeploymentTest extends PiperTestBase { def runtimeVersion = '2.125' node() { - neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, applicationName: appName, runtime: runtime, runtimeVersion: runtimeVersion + neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, applicationName: appName, runtime: runtime, runtimeVersion: runtimeVersion, warAction: warAction, vmSize: vmSize } } @@ -420,7 +450,7 @@ class NeoDeploymentTest extends PiperTestBase { """ } - private mtaDeployModePiepeline() { + private mtaDeployModePipeline() { return """ @Library('piper-library-os') diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index 2bc321b22..63c8f51ab 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -21,8 +21,18 @@ def call(parameters = [:]) { def deployMode = utils.getMandatoryParameter(parameters, 'deployMode', 'MTA') + if (deployMode != 'MTA' && deployMode != 'WAR_PARAMS' && deployMode != 'WAR_PROPERTIESFILE') { + throw new IllegalArgumentException("[neoDeploy] Invalid deployMode = '${deployMode}'. Valid 'deployMode' values are: 'MTA', 'WAR_PARAMS' and 'WAR_PROPERTIESFILE'") + } + def propertiesFile def warAction + if (deployMode == 'WAR_PROPERTIESFILE' || deployMode == 'WAR_PARAMS') { + warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') + if (warAction != 'warAction' && warAction != 'deploy') { + throw new IllegalArgumentException("[neoDeploy] Invalid warAction = '${warAction}'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") + } + } if (deployMode == 'WAR_PROPERTIESFILE') { propertiesFile = new File(utils.getMandatoryParameter(parameters, 'propertiesFile', null)) if (!propertiesFile.isAbsolute()) { @@ -31,10 +41,6 @@ def call(parameters = [:]) { if (!propertiesFile.exists()){ error "Properties file cannot be found with parameter propertiesFile: '${propertiesFile}'." } - warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') - if (warAction != 'warAction' || warAction != 'deploy') { - warAction = 'deploy' - } } def applicationName @@ -46,10 +52,9 @@ def call(parameters = [:]) { runtime = utils.getMandatoryParameter(parameters, 'runtime', null) runtimeVersion = utils.getMandatoryParameter(parameters, 'runtimeVersion', null) vmSize = utils.getMandatoryParameter(parameters, 'vmSize', 'lite') - if (vmSize != 'lite' || vmSize !='pro' || vmSize != 'prem' || vmSize != 'prem-plus') { - vmSize = 'lite' + if (vmSize != 'lite' && vmSize !='pro' && vmSize != 'prem' && vmSize != 'prem-plus') { + throw new IllegalArgumentException("[neoDeploy] Invalid vmSize = '${vmSize}'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") } - warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') } def defaultDeployHost = script.commonPipelineEnvironment.getConfigProperty('DEPLOY_HOST') @@ -62,10 +67,6 @@ def call(parameters = [:]) { def deployHost def deployAccount - if (!deployMode.equals('MTA') && !deployMode.equals('WAR_PARAMS') && !deployMode.equals('WAR_PROPERTIESFILE')) { - echo "[neoDeploy] Invalid deployment mode \"${deployMode}\". Deployment will be skipped." - } - if (deployMode.equals('MTA') || deployMode.equals('WAR_PARAMS')) { deployHost = utils.getMandatoryParameter(parameters, 'deployHost', defaultDeployHost) deployAccount = utils.getMandatoryParameter(parameters, 'deployAccount', defaultDeployAccount) From 98a0c5b548e4e4eec4fdcc812feba3a892d66bd4 Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Wed, 17 Jan 2018 11:17:24 +0100 Subject: [PATCH 10/32] Converting parameters names to lower-case Requested by Oliver Nocon --- test/groovy/NeoDeploymentTest.groovy | 20 ++++++++++---------- vars/neoDeploy.groovy | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 76859133e..596c840dd 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -166,7 +166,7 @@ class NeoDeploymentTest extends PiperTestBase { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' new File(archivePath) << "dummy archive" - withPipeline(mtaDeployModePipeline()).execute(archivePath, 'MTA') + withPipeline(mtaDeployModePipeline()).execute(archivePath, 'mta') assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." @@ -177,7 +177,7 @@ class NeoDeploymentTest extends PiperTestBase { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' new File(warArchivePath) << "dummy war archive" - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'WAR_PARAMS', 'lite', 'deploy') + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'deploy') assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." @@ -189,7 +189,7 @@ class NeoDeploymentTest extends PiperTestBase { new File(warArchivePath) << "dummy war archive" new File(propertiesFilePath) << "dummy properties file" - withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'WAR_PROPERTIESFILE') + withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'warPropertiesFile') assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." @@ -202,7 +202,7 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR applicationName') - withPipeline(noApplicationNamePipeline()).execute(warArchivePath, 'WAR_PARAMS') + withPipeline(noApplicationNamePipeline()).execute(warArchivePath, 'warParams') } @Test @@ -212,7 +212,7 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtime') - withPipeline(noRuntimePipeline()).execute(warArchivePath, 'WAR_PARAMS') + withPipeline(noRuntimePipeline()).execute(warArchivePath, 'warParams') } @Test @@ -222,7 +222,7 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtimeVersion') - withPipeline(noRuntimeVersionPipeline()).execute(warArchivePath, 'WAR_PARAMS') + withPipeline(noRuntimeVersionPipeline()).execute(warArchivePath, 'warParams') } @Test @@ -230,9 +230,9 @@ class NeoDeploymentTest extends PiperTestBase { new File(warArchivePath) << "dummy war archive" thrown.expect(IllegalArgumentException) - thrown.expectMessage("[neoDeploy] Invalid deployMode = 'ILLEGAL_MODE'. Valid 'deployMode' values are: 'MTA', 'WAR_PARAMS' and 'WAR_PROPERTIESFILE'") + thrown.expectMessage("[neoDeploy] Invalid deployMode = 'illegalMode'. Valid 'deployMode' values are: 'mta', 'warParams' and 'warPropertiesFile'") - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'ILLEGAL_MODE', 'lite', 'deploy') + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'illegalMode', 'lite', 'deploy') } @Test @@ -242,7 +242,7 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(IllegalArgumentException) thrown.expectMessage("[neoDeploy] Invalid vmSize = 'illegalVM'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'WAR_PARAMS', 'illegalVM', 'deploy') + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'illegalVM', 'deploy') } @Test @@ -252,7 +252,7 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(IllegalArgumentException) thrown.expectMessage("[neoDeploy] Invalid warAction = 'illegalWARAction'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'WAR_PARAMS', 'lite', 'illegalWARAction') + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'illegalWARAction') } private defaultPipeline(){ diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index 63c8f51ab..32a103ff3 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -19,21 +19,21 @@ def call(parameters = [:]) { error "Archive cannot be found with parameter archivePath: '${archivePath}'." } - def deployMode = utils.getMandatoryParameter(parameters, 'deployMode', 'MTA') + def deployMode = utils.getMandatoryParameter(parameters, 'deployMode', 'mta') - if (deployMode != 'MTA' && deployMode != 'WAR_PARAMS' && deployMode != 'WAR_PROPERTIESFILE') { - throw new IllegalArgumentException("[neoDeploy] Invalid deployMode = '${deployMode}'. Valid 'deployMode' values are: 'MTA', 'WAR_PARAMS' and 'WAR_PROPERTIESFILE'") + if (deployMode != 'mta' && deployMode != 'warParams' && deployMode != 'warPropertiesFile') { + throw new IllegalArgumentException("[neoDeploy] Invalid deployMode = '${deployMode}'. Valid 'deployMode' values are: 'mta', 'warParams' and 'warPropertiesFile'") } def propertiesFile def warAction - if (deployMode == 'WAR_PROPERTIESFILE' || deployMode == 'WAR_PARAMS') { + if (deployMode == 'warPropertiesFile' || deployMode == 'warParams') { warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') if (warAction != 'warAction' && warAction != 'deploy') { throw new IllegalArgumentException("[neoDeploy] Invalid warAction = '${warAction}'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") } } - if (deployMode == 'WAR_PROPERTIESFILE') { + if (deployMode == 'warPropertiesFile') { propertiesFile = new File(utils.getMandatoryParameter(parameters, 'propertiesFile', null)) if (!propertiesFile.isAbsolute()) { propertiesFile = new File(pwd(), propertiesFile.getPath()) @@ -47,7 +47,7 @@ def call(parameters = [:]) { def runtime def runtimeVersion def vmSize - if (deployMode == 'WAR_PARAMS') { + if (deployMode == 'warParams') { applicationName = utils.getMandatoryParameter(parameters, 'applicationName', null) runtime = utils.getMandatoryParameter(parameters, 'runtime', null) runtimeVersion = utils.getMandatoryParameter(parameters, 'runtimeVersion', null) @@ -67,7 +67,7 @@ def call(parameters = [:]) { def deployHost def deployAccount - if (deployMode.equals('MTA') || deployMode.equals('WAR_PARAMS')) { + if (deployMode.equals('mta') || deployMode.equals('warParams')) { deployHost = utils.getMandatoryParameter(parameters, 'deployHost', defaultDeployHost) deployAccount = utils.getMandatoryParameter(parameters, 'deployAccount', defaultDeployAccount) } @@ -87,7 +87,7 @@ def call(parameters = [:]) { --source "${archivePath.getAbsolutePath()}" \ """ - if (deployMode == 'MTA') { + if (deployMode == 'mta') { sh """#!/bin/bash "${neoExecutable}" deploy-mta \ ${commonDeployParams} \ @@ -97,7 +97,7 @@ def call(parameters = [:]) { """ } - if (deployMode == 'WAR_PARAMS') { + if (deployMode == 'warParams') { sh """#!/bin/bash "${neoExecutable}" ${warAction} \ ${commonDeployParams} \ @@ -110,7 +110,7 @@ def call(parameters = [:]) { """ } - if (deployMode == 'WAR_PROPERTIESFILE') { + if (deployMode == 'warPropertiesFile') { sh """#!/bin/bash "${neoExecutable}" ${warAction} \ ${commonDeployParams} \ From 62b0cae3ace5661f150604de457b983a6fd1832c Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Wed, 17 Jan 2018 11:19:02 +0100 Subject: [PATCH 11/32] Changing IllegalArgumentException to general Exception Requested by Oliver Nocon --- test/groovy/NeoDeploymentTest.groovy | 6 +++--- vars/neoDeploy.groovy | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 596c840dd..34a901604 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -229,7 +229,7 @@ class NeoDeploymentTest extends PiperTestBase { void illegalDeployModeTest() { new File(warArchivePath) << "dummy war archive" - thrown.expect(IllegalArgumentException) + thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid deployMode = 'illegalMode'. Valid 'deployMode' values are: 'mta', 'warParams' and 'warPropertiesFile'") withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'illegalMode', 'lite', 'deploy') @@ -239,7 +239,7 @@ class NeoDeploymentTest extends PiperTestBase { void illegalVMSizeTest() { new File(warArchivePath) << "dummy war archive" - thrown.expect(IllegalArgumentException) + thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid vmSize = 'illegalVM'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'illegalVM', 'deploy') @@ -249,7 +249,7 @@ class NeoDeploymentTest extends PiperTestBase { void illegalWARActionTest() { new File(warArchivePath) << "dummy war archive" - thrown.expect(IllegalArgumentException) + thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid warAction = 'illegalWARAction'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'illegalWARAction') diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index 32a103ff3..b586e35b6 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -22,7 +22,7 @@ def call(parameters = [:]) { def deployMode = utils.getMandatoryParameter(parameters, 'deployMode', 'mta') if (deployMode != 'mta' && deployMode != 'warParams' && deployMode != 'warPropertiesFile') { - throw new IllegalArgumentException("[neoDeploy] Invalid deployMode = '${deployMode}'. Valid 'deployMode' values are: 'mta', 'warParams' and 'warPropertiesFile'") + throw new Exception("[neoDeploy] Invalid deployMode = '${deployMode}'. Valid 'deployMode' values are: 'mta', 'warParams' and 'warPropertiesFile'") } def propertiesFile @@ -30,7 +30,7 @@ def call(parameters = [:]) { if (deployMode == 'warPropertiesFile' || deployMode == 'warParams') { warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') if (warAction != 'warAction' && warAction != 'deploy') { - throw new IllegalArgumentException("[neoDeploy] Invalid warAction = '${warAction}'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") + throw new Exception("[neoDeploy] Invalid warAction = '${warAction}'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") } } if (deployMode == 'warPropertiesFile') { @@ -53,7 +53,7 @@ def call(parameters = [:]) { runtimeVersion = utils.getMandatoryParameter(parameters, 'runtimeVersion', null) vmSize = utils.getMandatoryParameter(parameters, 'vmSize', 'lite') if (vmSize != 'lite' && vmSize !='pro' && vmSize != 'prem' && vmSize != 'prem-plus') { - throw new IllegalArgumentException("[neoDeploy] Invalid vmSize = '${vmSize}'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") + throw new Exception("[neoDeploy] Invalid vmSize = '${vmSize}'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") } } From 48fb7c76e32085b3ecc382025babcf700a7e15e6 Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Wed, 17 Jan 2018 13:48:26 +0100 Subject: [PATCH 12/32] Bug when checking for valid warAction --- vars/neoDeploy.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index b586e35b6..35e718019 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -29,7 +29,7 @@ def call(parameters = [:]) { def warAction if (deployMode == 'warPropertiesFile' || deployMode == 'warParams') { warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') - if (warAction != 'warAction' && warAction != 'deploy') { + if (warAction != 'deploy' && warAction != 'rolling-update') { throw new Exception("[neoDeploy] Invalid warAction = '${warAction}'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") } } From d9e8128860d50063900b3b816861b0124ffb1e15 Mon Sep 17 00:00:00 2001 From: Milko Todorov Date: Wed, 17 Jan 2018 14:01:15 +0100 Subject: [PATCH 13/32] Unit test for warAction: rolling-update --- test/groovy/NeoDeploymentTest.groovy | 29 +++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 34a901604..8e13fdf27 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -183,18 +183,41 @@ class NeoDeploymentTest extends PiperTestBase { assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." } + @Test + void warFileParamsDeployModeRollingUpdateTest() { + binding.getVariable('env')['NEO_HOME'] = '/opt/neo' + new File(warArchivePath) << "dummy war archive" + + withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'rolling-update') + + assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ + assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + } + @Test void warPropertiesFileDeployModeTest() { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' new File(warArchivePath) << "dummy war archive" new File(propertiesFilePath) << "dummy properties file" - withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'warPropertiesFile') + withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'warPropertiesFile', 'deploy') assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." } + @Test + void warPropertiesFileDeployModeRollingUpdateTest() { + binding.getVariable('env')['NEO_HOME'] = '/opt/neo' + new File(warArchivePath) << "dummy war archive" + new File(propertiesFilePath) << "dummy properties file" + + withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'warPropertiesFile', 'rolling-update') + + assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ + assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + } + @Test void applicationNameNotProvidedTest() { new File(warArchivePath) << "dummy war archive" @@ -416,10 +439,10 @@ class NeoDeploymentTest extends PiperTestBase { return """ @Library('piper-library-os') - execute(warArchivePath, propertiesFilePath, deployMode) { + execute(warArchivePath, propertiesFilePath, deployMode, warAction) { node() { - neoDeploy script: this, deployMode: deployMode, archivePath: warArchivePath, propertiesFile: propertiesFilePath + neoDeploy script: this, deployMode: deployMode, archivePath: warArchivePath, propertiesFile: propertiesFilePath, warAction: warAction } } From 492d4a1f68cd857eef898f995ae450bcf215e2d8 Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Tue, 16 Jan 2018 09:33:13 +0100 Subject: [PATCH 14/32] Make use of Jenkins setup and logging rules --- test/groovy/DockerExecuteTest.groovy | 22 +++++--- test/groovy/MTABuildTest.groovy | 29 ++++++---- test/groovy/MavenExecuteTest.groovy | 11 ++-- test/groovy/NeoDeploymentTest.groovy | 32 +++++------ test/groovy/PipelineExecuteTest.groovy | 12 +++-- test/groovy/PiperTestBase.groovy | 18 +------ .../SetupCommonPipelineEnvironmentTest.groovy | 9 +++- test/groovy/ToolValidateTest.groovy | 53 ++++++++++--------- 8 files changed, 101 insertions(+), 85 deletions(-) diff --git a/test/groovy/DockerExecuteTest.groovy b/test/groovy/DockerExecuteTest.groovy index 3c895aff4..af7523df8 100644 --- a/test/groovy/DockerExecuteTest.groovy +++ b/test/groovy/DockerExecuteTest.groovy @@ -1,6 +1,11 @@ import org.junit.Before +import org.junit.Rule import org.junit.Test +import org.junit.rules.RuleChain + +import util.JenkinsLoggingRule +import util.JenkinsSetupRule import static org.junit.Assert.assertEquals import static org.junit.Assert.assertTrue @@ -9,20 +14,21 @@ import static org.junit.Assert.assertFalse class DockerExecuteTest extends PiperTestBase { private DockerMock docker - String echos + private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this) + + @Rule + public RuleChain ruleChain = RuleChain.outerRule(new JenkinsSetupRule(this)) + .around(jlr) int whichDockerReturnValue = 0 @Before - void setUp() { - super.setUp() + void init() { docker = new DockerMock() binding.setVariable('docker', docker) binding.setVariable('Jenkins', [instance: [pluginManager: [plugins: [new PluginMock()]]]]) - echos = '' - helper.registerAllowedMethod("echo", [String.class], { String s -> echos += " $s" }) helper.registerAllowedMethod('sh', [Map.class], {return whichDockerReturnValue}) } @@ -33,7 +39,7 @@ class DockerExecuteTest extends PiperTestBase { assertEquals('maven:3.5-jdk-8-alpine', docker.getImageName()) assertTrue(docker.isImagePulled()) assertEquals(' --env http_proxy --env https_proxy --env no_proxy --env HTTP_PROXY --env HTTPS_PROXY --env NO_PROXY', docker.getParameters()) - assertTrue(echos.contains('Inside Docker')) + assertTrue(jlr.log.contains('Inside Docker')) } @Test @@ -54,8 +60,8 @@ class DockerExecuteTest extends PiperTestBase { def script = loadScript("test/resources/pipelines/dockerExecuteTest/executeInsideDockerWithParameters.groovy") script.execute() - assertTrue(echos.contains('No docker environment found')) - assertTrue(echos.contains('Running on local environment')) + assertTrue(jlr.log.contains('No docker environment found')) + assertTrue(jlr.log.contains('Running on local environment')) assertFalse(docker.isImagePulled()) } diff --git a/test/groovy/MTABuildTest.groovy b/test/groovy/MTABuildTest.groovy index a508b8973..7eef11591 100644 --- a/test/groovy/MTABuildTest.groovy +++ b/test/groovy/MTABuildTest.groovy @@ -4,17 +4,25 @@ import org.jenkinsci.plugins.pipeline.utility.steps.shaded.org.yaml.snakeyaml.pa import org.junit.Before import org.junit.Rule import org.junit.Test - import org.junit.rules.ExpectedException +import org.junit.rules.RuleChain import org.junit.rules.TemporaryFolder +import util.JenkinsLoggingRule +import util.JenkinsSetupRule + public class MTABuildTest extends PiperTestBase { - @Rule - public ExpectedException thrown = new ExpectedException() + private ExpectedException thrown = new ExpectedException() + private TemporaryFolder tmp = new TemporaryFolder() + private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this) @Rule - public TemporaryFolder tmp = new TemporaryFolder() + public RuleChain ruleChain = + RuleChain.outerRule(thrown) + .around(tmp) + .around(new JenkinsSetupRule(this)) + .around(jlr) def currentDir def otherDir @@ -22,9 +30,8 @@ public class MTABuildTest extends PiperTestBase { @Before - void setUp() { + void init() { - super.setUp() currentDir = tmp.newFolder().toURI().getPath()[0..-2] //omit final '/' otherDir = tmp.newFolder().toURI().getPath()[0..-2] //omit final '/' @@ -69,7 +76,7 @@ public class MTABuildTest extends PiperTestBase { assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" - assert messages[1] == "[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment." + assert jlr.log.contains( "[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment.") } @@ -90,7 +97,7 @@ public class MTABuildTest extends PiperTestBase { assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" - assert messages[1] == "[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment." + assert jlr.log.contains("[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment.") } @@ -113,7 +120,7 @@ public class MTABuildTest extends PiperTestBase { assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" - assert messages[1] == "[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment." + assert jlr.log.contains("[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment.") } @Test @@ -131,7 +138,7 @@ public class MTABuildTest extends PiperTestBase { assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" - assert messages[1] == "[mtaBuild] Using MTA JAR from current working directory." + assert jlr.log.contains( "[mtaBuild] Using MTA JAR from current working directory." ) } @@ -150,7 +157,7 @@ public class MTABuildTest extends PiperTestBase { assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" - assert messages[1] == "[mtaBuild] MTA JAR \"/etc/mta/mta.jar\" retrieved from parameters." + assert jlr.log.contains("[mtaBuild] MTA JAR \"/etc/mta/mta.jar\" retrieved from parameters.".toString()) } diff --git a/test/groovy/MavenExecuteTest.groovy b/test/groovy/MavenExecuteTest.groovy index 7575a174e..ce928ad1e 100644 --- a/test/groovy/MavenExecuteTest.groovy +++ b/test/groovy/MavenExecuteTest.groovy @@ -1,18 +1,23 @@ -import junit.framework.TestCase + import org.junit.Before +import org.junit.Rule import org.junit.Test import static org.junit.Assert.assertEquals import static org.junit.Assert.assertTrue +import util.JenkinsSetupRule + class MavenExecuteTest extends PiperTestBase { Map dockerParameters List shellCalls + @Rule + public JenkinsSetupRule jsr = new JenkinsSetupRule(this) + @Before - void setUp() { - super.setUp() + void init() { shellCalls = [] dockerParameters = [:] diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 8e13fdf27..a391045dc 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -1,31 +1,31 @@ import hudson.AbortException import org.junit.rules.TemporaryFolder - -import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library - -import static ProjectSource.projectSource - 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.JenkinsSetupRule class NeoDeploymentTest extends PiperTestBase { - @Rule - public ExpectedException thrown = new ExpectedException().none() + private ExpectedException thrown = new ExpectedException().none() + private TemporaryFolder tmp = new TemporaryFolder() + private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this) @Rule - public TemporaryFolder tmp = new TemporaryFolder() - + public RuleChain ruleChain = RuleChain.outerRule(thrown) + .around(tmp) + .around(new JenkinsSetupRule(this)) + .around(jlr) def archivePath def warArchivePath def propertiesFilePath @Before - void setUp() { - - super.setUp() + void init() { archivePath = "${tmp.newFolder("workspace").toURI().getPath()}archiveName.mtar" warArchivePath = "${tmp.getRoot().toURI().getPath()}workspace/warArchive.war" @@ -66,7 +66,7 @@ class NeoDeploymentTest extends PiperTestBase { assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ - assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @@ -96,7 +96,7 @@ class NeoDeploymentTest extends PiperTestBase { assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ - assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @@ -109,7 +109,7 @@ class NeoDeploymentTest extends PiperTestBase { assert shellCalls[0] =~ /#!\/bin\/bash "neo" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ - assert messages[1] == "Using Neo executable from PATH." + assert jlr.log.contains("Using Neo executable from PATH.") } @@ -122,7 +122,7 @@ class NeoDeploymentTest extends PiperTestBase { assert shellCalls[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ - assert messages[1] == "[neoDeploy] Neo executable \"/etc/neo/tools/neo.sh\" retrieved from parameters." + assert jlr.log.contains("[neoDeploy] Neo executable \"/etc/neo/tools/neo.sh\" retrieved from parameters.") } diff --git a/test/groovy/PipelineExecuteTest.groovy b/test/groovy/PipelineExecuteTest.groovy index e7b9cc14b..3a036cdf0 100644 --- a/test/groovy/PipelineExecuteTest.groovy +++ b/test/groovy/PipelineExecuteTest.groovy @@ -1,23 +1,27 @@ import hudson.AbortException +import util.JenkinsSetupRule + import org.junit.rules.TemporaryFolder import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException +import org.junit.rules.RuleChain class PipelineExecuteTest extends PiperTestBase { + private ExpectedException thrown = new ExpectedException().none() + @Rule - public ExpectedException thrown = new ExpectedException().none() + public RuleChain ruleChain = RuleChain.outerRule(thrown) + .around(new JenkinsSetupRule(this)) def pipelinePath def checkoutParameters = [:] def load @Before - void setUp() { - - super.setUp() + void init() { pipelinePath = null checkoutParameters.clear() diff --git a/test/groovy/PiperTestBase.groovy b/test/groovy/PiperTestBase.groovy index ac45b1d32..8b88d5efe 100644 --- a/test/groovy/PiperTestBase.groovy +++ b/test/groovy/PiperTestBase.groovy @@ -15,18 +15,14 @@ public class PiperTestBase extends BasePipelineTest { private File pipeline - protected messages = [], shellCalls = [] + protected shellCalls = [] void setUp() { super.setUp() - messages.clear() shellCalls.clear() - preparePiperLib() - - helper.registerAllowedMethod('echo', [String], {s -> messages.add(s)} ) helper.registerAllowedMethod('sh', [String], { s -> shellCalls.add(s.replaceAll(/\s+/, " ").trim()) }) @@ -45,16 +41,4 @@ public class PiperTestBase extends BasePipelineTest { pipeline << p loadScript(pipeline.toURI().getPath()) } - - private preparePiperLib() { - def piperLib = library() - .name('piper-library-os') - .retriever(projectSource()) - .targetPath('clonePath/is/not/necessary') - .defaultVersion('') - .allowOverride(true) - .implicit(false) - .build() - helper.registerSharedLibrary(piperLib) - } } diff --git a/test/groovy/SetupCommonPipelineEnvironmentTest.groovy b/test/groovy/SetupCommonPipelineEnvironmentTest.groovy index fe07cc323..ed087f7e6 100644 --- a/test/groovy/SetupCommonPipelineEnvironmentTest.groovy +++ b/test/groovy/SetupCommonPipelineEnvironmentTest.groovy @@ -1,7 +1,10 @@ import org.junit.Before +import org.junit.Rule import org.junit.Test import org.yaml.snakeyaml.Yaml +import util.JenkinsSetupRule + import static org.junit.Assert.assertEquals import static org.junit.Assert.assertNotNull @@ -9,9 +12,11 @@ class SetupCommonPipelineEnvironmentTest extends PiperTestBase { def usedConfigFile + @Rule + public JenkinsSetupRule jsr = new JenkinsSetupRule(this) + @Before - void setUp() { - super.setUp() + void init() { def examplePipelineConfig = new File('test/resources/test_pipeline_config.yml').text diff --git a/test/groovy/ToolValidateTest.groovy b/test/groovy/ToolValidateTest.groovy index 3efbac42b..7968f90f7 100644 --- a/test/groovy/ToolValidateTest.groovy +++ b/test/groovy/ToolValidateTest.groovy @@ -4,25 +4,30 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException +import org.junit.rules.RuleChain import org.junit.rules.TemporaryFolder +import util.JenkinsLoggingRule +import util.JenkinsSetupRule + class ToolValidateTest extends PiperTestBase { + private ExpectedException thrown = new ExpectedException().none() + private TemporaryFolder tmp = new TemporaryFolder() + private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this) @Rule - public ExpectedException thrown = new ExpectedException().none() - - @Rule - public TemporaryFolder tmp = new TemporaryFolder() + public RuleChain ruleChain = + RuleChain.outerRule(tmp) + .around(thrown) + .around(new JenkinsSetupRule(this)) + .around(jlr) private notEmptyDir private script - @Before - void setUp() { - - super.setUp() + void init() { script = withPipeline(defaultPipeline()) @@ -199,10 +204,10 @@ class ToolValidateTest extends PiperTestBase { script.execute() - assert messages[0].contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') - assert messages[1].contains('[INFO] Validating Java version 1.8.0 or compatible version.') - assert messages[2].contains('[INFO] Java version 1.8.0 is installed.') - assert messages[3].contains('--- END LIBRARY STEP: toolValidate.groovy ---') + assert jlr.log.contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') + assert jlr.log.contains('[INFO] Validating Java version 1.8.0 or compatible version.') + assert jlr.log.contains('[INFO] Java version 1.8.0 is installed.') + assert jlr.log.contains('--- END LIBRARY STEP: toolValidate.groovy ---') } @Test @@ -213,10 +218,10 @@ class ToolValidateTest extends PiperTestBase { script.execute() - assert messages[0].contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') - assert messages[1].contains('[INFO] Validating SAP Multitarget Application Archive Builder version 1.0.6 or compatible version.') - assert messages[2].contains('[INFO] SAP Multitarget Application Archive Builder version 1.0.6 is installed.') - assert messages[3].contains('--- END LIBRARY STEP: toolValidate.groovy ---') + assert jlr.log.contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') + assert jlr.log.contains('[INFO] Validating SAP Multitarget Application Archive Builder version 1.0.6 or compatible version.') + assert jlr.log.contains('[INFO] SAP Multitarget Application Archive Builder version 1.0.6 is installed.') + assert jlr.log.contains('--- END LIBRARY STEP: toolValidate.groovy ---') } @Test @@ -227,10 +232,10 @@ class ToolValidateTest extends PiperTestBase { script.execute() - assert messages[0].contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') - assert messages[1].contains('[INFO] Validating SAP Cloud Platform Console Client version 3.39.10 or compatible version.') - assert messages[2].contains('[INFO] SAP Cloud Platform Console Client version 3.39.10 is installed.') - assert messages[3].contains('--- END LIBRARY STEP: toolValidate.groovy ---') + assert jlr.log.contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') + assert jlr.log.contains('[INFO] Validating SAP Cloud Platform Console Client version 3.39.10 or compatible version.') + assert jlr.log.contains('[INFO] SAP Cloud Platform Console Client version 3.39.10 is installed.') + assert jlr.log.contains('--- END LIBRARY STEP: toolValidate.groovy ---') } @Test @@ -241,10 +246,10 @@ class ToolValidateTest extends PiperTestBase { script.execute() - assert messages[0].contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') - assert messages[1].contains('[INFO] Validating Change Management Command Line Interface version 0.0.1 or compatible version.') - assert messages[2].contains('[INFO] Change Management Command Line Interface version 0.0.1 is installed.') - assert messages[3].contains('--- END LIBRARY STEP: toolValidate.groovy ---') + assert jlr.log.contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') + assert jlr.log.contains('[INFO] Validating Change Management Command Line Interface version 0.0.1 or compatible version.') + assert jlr.log.contains('[INFO] Change Management Command Line Interface version 0.0.1 is installed.') + assert jlr.log.contains('--- END LIBRARY STEP: toolValidate.groovy ---') } From 1089e192f33e6097ad626f167a47804f4178e0ba Mon Sep 17 00:00:00 2001 From: Thorsten Duda Date: Tue, 16 Jan 2018 14:39:42 +0100 Subject: [PATCH 15/32] added JenkinsShellCallRule class --- test/groovy/util/JenkinsShellCallRule.groovy | 38 ++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test/groovy/util/JenkinsShellCallRule.groovy diff --git a/test/groovy/util/JenkinsShellCallRule.groovy b/test/groovy/util/JenkinsShellCallRule.groovy new file mode 100644 index 000000000..128fd4577 --- /dev/null +++ b/test/groovy/util/JenkinsShellCallRule.groovy @@ -0,0 +1,38 @@ +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 JenkinsShellCallRule implements TestRule { + + final BasePipelineTest testInstance + + String shell = "" + + JenkinsShellCallRule(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("sh", [String.class], { + command -> + command = command.replaceAll(/\s+/," ").trim() + shell += "$command \n" + }) + + base.evaluate() + } + } + } +} From 106a8b46933b91a9dc82ca33303d5a4e1fe95563 Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Tue, 16 Jan 2018 15:03:00 +0100 Subject: [PATCH 16/32] Make use of JenkinsShellCallRule --- test/groovy/MTABuildTest.groovy | 33 +++++++++++--------- test/groovy/MavenExecuteTest.groovy | 15 +++++---- test/groovy/NeoDeploymentTest.groovy | 31 +++++++++--------- test/groovy/PiperTestBase.groovy | 8 ----- test/groovy/util/JenkinsShellCallRule.groovy | 5 ++- 5 files changed, 46 insertions(+), 46 deletions(-) diff --git a/test/groovy/MTABuildTest.groovy b/test/groovy/MTABuildTest.groovy index 7eef11591..5ed2dd30e 100644 --- a/test/groovy/MTABuildTest.groovy +++ b/test/groovy/MTABuildTest.groovy @@ -10,12 +10,14 @@ import org.junit.rules.TemporaryFolder import util.JenkinsLoggingRule import util.JenkinsSetupRule +import util.JenkinsShellCallRule public class MTABuildTest extends PiperTestBase { private ExpectedException thrown = new ExpectedException() private TemporaryFolder tmp = new TemporaryFolder() private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this) + private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this) @Rule public RuleChain ruleChain = @@ -23,6 +25,7 @@ public class MTABuildTest extends PiperTestBase { .around(tmp) .around(new JenkinsSetupRule(this)) .around(jlr) + .around(jscr) def currentDir def otherDir @@ -68,11 +71,11 @@ public class MTABuildTest extends PiperTestBase { def mtarFilePath = withPipeline(defaultPipeline()).execute() - assert shellCalls[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/ + assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/ - assert shellCalls[1].contains("PATH=./node_modules/.bin:/usr/bin") + assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin") - assert shellCalls[1].contains(' -jar /opt/mta/mta.jar --mtar ') + assert jscr.shell[1].contains(' -jar /opt/mta/mta.jar --mtar ') assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" @@ -89,11 +92,11 @@ public class MTABuildTest extends PiperTestBase { def mtarFilePath = withPipeline(returnMtarFilePathFromCommonPipelineEnvironmentPipeline()).execute() - assert shellCalls[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/ + assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/ - assert shellCalls[1].contains("PATH=./node_modules/.bin:/usr/bin") + assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin") - assert shellCalls[1].contains(' -jar /opt/mta/mta.jar --mtar ') + assert jscr.shell[1].contains(' -jar /opt/mta/mta.jar --mtar ') assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" @@ -112,11 +115,11 @@ public class MTABuildTest extends PiperTestBase { def mtarFilePath = withPipeline(withSurroundingDirPipeline()).execute(newDirName) - assert shellCalls[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/newDir\/mta.yaml"$/ + assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/newDir\/mta.yaml"$/ - assert shellCalls[1].contains("PATH=./node_modules/.bin:/usr/bin") + assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin") - assert shellCalls[1].contains(' -jar /opt/mta/mta.jar --mtar ') + assert jscr.shell[1].contains(' -jar /opt/mta/mta.jar --mtar ') assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" @@ -130,11 +133,11 @@ public class MTABuildTest extends PiperTestBase { def mtarFilePath = withPipeline(defaultPipeline()).execute() - assert shellCalls[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/ + assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/ - assert shellCalls[1].contains("PATH=./node_modules/.bin:/usr/bin") + assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin") - assert shellCalls[1].contains(' -jar mta.jar --mtar ') + assert jscr.shell[1].contains(' -jar mta.jar --mtar ') assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" @@ -149,11 +152,11 @@ public class MTABuildTest extends PiperTestBase { def mtarFilePath = withPipeline(mtaJarLocationAsParameterPipeline()).execute() - assert shellCalls[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/ + assert jscr.shell[0] =~ /sed -ie "s\/\\\$\{timestamp\}\/`date \+%Y%m%d%H%M%S`\/g" ".*\/mta.yaml"$/ - assert shellCalls[1].contains("PATH=./node_modules/.bin:/usr/bin") + assert jscr.shell[1].contains("PATH=./node_modules/.bin:/usr/bin") - assert shellCalls[1].contains(' -jar /etc/mta/mta.jar --mtar ') + assert jscr.shell[1].contains(' -jar /etc/mta/mta.jar --mtar ') assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" diff --git a/test/groovy/MavenExecuteTest.groovy b/test/groovy/MavenExecuteTest.groovy index ce928ad1e..f9336c969 100644 --- a/test/groovy/MavenExecuteTest.groovy +++ b/test/groovy/MavenExecuteTest.groovy @@ -2,24 +2,27 @@ import org.junit.Before import org.junit.Rule import org.junit.Test +import org.junit.rules.RuleChain import static org.junit.Assert.assertEquals import static org.junit.Assert.assertTrue import util.JenkinsSetupRule +import util.JenkinsShellCallRule class MavenExecuteTest extends PiperTestBase { Map dockerParameters - List shellCalls + + private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this) @Rule - public JenkinsSetupRule jsr = new JenkinsSetupRule(this) + public RuleChain ruleChain = RuleChain.outerRule(new JenkinsSetupRule(this)) + .around(jscr) @Before void init() { - shellCalls = [] dockerParameters = [:] helper.registerAllowedMethod("dockerExecute", [Map.class, Closure.class], @@ -27,7 +30,6 @@ class MavenExecuteTest extends PiperTestBase { dockerParameters = parameters closure() }) - helper.registerAllowedMethod('sh', [String], { s -> shellCalls.add(s) }) } @Test @@ -35,7 +37,8 @@ class MavenExecuteTest extends PiperTestBase { def script = loadScript("test/resources/pipelines/mavenExecuteTest/executeBasicMavenCommand.groovy") script.execute() assertEquals('maven:3.5-jdk-7', dockerParameters.dockerImage) - assertTrue(shellCalls.contains('mvn clean install')) + + assert jscr.shell[0] == 'mvn clean install' } @Test @@ -44,6 +47,6 @@ class MavenExecuteTest extends PiperTestBase { script.execute() assertEquals('maven:3.5-jdk-8-alpine', dockerParameters.dockerImage) String mvnCommand = "mvn --global-settings 'globalSettingsFile.xml' -Dmaven.repo.local='m2Path' --settings 'projectSettingsFile.xml' --file 'pom.xml' -o clean install -Dmaven.tests.skip=true" - assertTrue(shellCalls.contains(mvnCommand)) + assertTrue(jscr.shell.contains(mvnCommand)) } } diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index a391045dc..afc846fd1 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -8,18 +8,21 @@ import org.junit.rules.RuleChain import util.JenkinsLoggingRule import util.JenkinsSetupRule +import util.JenkinsShellCallRule class NeoDeploymentTest extends PiperTestBase { private ExpectedException thrown = new ExpectedException().none() private TemporaryFolder tmp = new TemporaryFolder() private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this) + private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this) @Rule public RuleChain ruleChain = RuleChain.outerRule(thrown) .around(tmp) .around(new JenkinsSetupRule(this)) .around(jlr) + .around(jscr) def archivePath def warArchivePath def propertiesFilePath @@ -64,7 +67,7 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(defaultPipeline()).execute(archivePath, 'myCredentialsId') - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -94,7 +97,7 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(noCredentialsIdPipeline()).execute(archivePath) - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @@ -107,7 +110,7 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(noCredentialsIdPipeline()).execute(archivePath) - assert shellCalls[0] =~ /#!\/bin\/bash "neo" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ + assert jscr.shell[0] =~ /#!\/bin\/bash "neo" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ assert jlr.log.contains("Using Neo executable from PATH.") } @@ -120,7 +123,7 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(neoHomeParameterPipeline()).execute(archivePath, 'myCredentialsId') - assert shellCalls[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ assert jlr.log.contains("[neoDeploy] Neo executable \"/etc/neo/tools/neo.sh\" retrieved from parameters.") @@ -168,8 +171,8 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(mtaDeployModePipeline()).execute(archivePath, 'mta') - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ - assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @Test @@ -179,8 +182,8 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'deploy') - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ - assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @Test @@ -190,8 +193,8 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'rolling-update') - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ - assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @Test @@ -202,8 +205,8 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'warPropertiesFile', 'deploy') - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ - assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @Test @@ -214,8 +217,8 @@ class NeoDeploymentTest extends PiperTestBase { withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'warPropertiesFile', 'rolling-update') - assert shellCalls[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ - assert messages[1] == "[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment." + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @Test diff --git a/test/groovy/PiperTestBase.groovy b/test/groovy/PiperTestBase.groovy index 8b88d5efe..3ab5d22ca 100644 --- a/test/groovy/PiperTestBase.groovy +++ b/test/groovy/PiperTestBase.groovy @@ -15,18 +15,10 @@ public class PiperTestBase extends BasePipelineTest { private File pipeline - protected shellCalls = [] - void setUp() { super.setUp() - shellCalls.clear() - - helper.registerAllowedMethod('sh', [String], { s -> - shellCalls.add(s.replaceAll(/\s+/, " ").trim()) - }) - helper.registerAllowedMethod("readYaml", [Map], { Map parameters -> Yaml yamlParser = new Yaml() return yamlParser.load(parameters.text) diff --git a/test/groovy/util/JenkinsShellCallRule.groovy b/test/groovy/util/JenkinsShellCallRule.groovy index 128fd4577..ce17ce7d6 100644 --- a/test/groovy/util/JenkinsShellCallRule.groovy +++ b/test/groovy/util/JenkinsShellCallRule.groovy @@ -9,7 +9,7 @@ class JenkinsShellCallRule implements TestRule { final BasePipelineTest testInstance - String shell = "" + List shell = [] JenkinsShellCallRule(BasePipelineTest testInstance) { this.testInstance = testInstance @@ -27,8 +27,7 @@ class JenkinsShellCallRule implements TestRule { testInstance.helper.registerAllowedMethod("sh", [String.class], { command -> - command = command.replaceAll(/\s+/," ").trim() - shell += "$command \n" + shell.add(command.replaceAll(/\s+/," ").trim()) }) base.evaluate() From e8363e9637f2e8499f32cbfc4b497334605e640d Mon Sep 17 00:00:00 2001 From: Thorsten Duda Date: Tue, 16 Jan 2018 15:42:11 +0100 Subject: [PATCH 17/32] introduce JenkinsConfigRule --- test/groovy/DockerExecuteTest.groovy | 6 ++-- test/groovy/MTABuildTest.groovy | 3 +- test/groovy/MavenExecuteTest.groovy | 2 ++ test/groovy/NeoDeploymentTest.groovy | 2 ++ test/groovy/PipelineExecuteTest.groovy | 2 ++ test/groovy/PiperTestBase.groovy | 8 +---- test/groovy/ToolValidateTest.groovy | 3 ++ test/groovy/util/JenkinsConfigRule.groovy | 38 +++++++++++++++++++++++ 8 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 test/groovy/util/JenkinsConfigRule.groovy diff --git a/test/groovy/DockerExecuteTest.groovy b/test/groovy/DockerExecuteTest.groovy index af7523df8..da4bac757 100644 --- a/test/groovy/DockerExecuteTest.groovy +++ b/test/groovy/DockerExecuteTest.groovy @@ -4,6 +4,7 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.RuleChain +import util.JenkinsConfigRule import util.JenkinsLoggingRule import util.JenkinsSetupRule @@ -19,6 +20,7 @@ class DockerExecuteTest extends PiperTestBase { @Rule public RuleChain ruleChain = RuleChain.outerRule(new JenkinsSetupRule(this)) .around(jlr) + .around(new JenkinsConfigRule(this)) int whichDockerReturnValue = 0 @@ -53,8 +55,8 @@ class DockerExecuteTest extends PiperTestBase { assertTrue(docker.getParameters().contains(' --volume my_vol:/my_vol')) } - @Test - void testDockerNotInstalledResultsInLocalExecution() throws Exception { + @Test + void testDockerNotInstalledResultsInLocalExecution() throws Exception { whichDockerReturnValue = 1 def script = loadScript("test/resources/pipelines/dockerExecuteTest/executeInsideDockerWithParameters.groovy") diff --git a/test/groovy/MTABuildTest.groovy b/test/groovy/MTABuildTest.groovy index 5ed2dd30e..8cd934bf6 100644 --- a/test/groovy/MTABuildTest.groovy +++ b/test/groovy/MTABuildTest.groovy @@ -7,7 +7,7 @@ import org.junit.Test import org.junit.rules.ExpectedException import org.junit.rules.RuleChain import org.junit.rules.TemporaryFolder - +import util.JenkinsConfigRule import util.JenkinsLoggingRule import util.JenkinsSetupRule import util.JenkinsShellCallRule @@ -26,6 +26,7 @@ public class MTABuildTest extends PiperTestBase { .around(new JenkinsSetupRule(this)) .around(jlr) .around(jscr) + .around(new JenkinsConfigRule(this)) def currentDir def otherDir diff --git a/test/groovy/MavenExecuteTest.groovy b/test/groovy/MavenExecuteTest.groovy index f9336c969..19b2b832f 100644 --- a/test/groovy/MavenExecuteTest.groovy +++ b/test/groovy/MavenExecuteTest.groovy @@ -7,6 +7,7 @@ import org.junit.rules.RuleChain import static org.junit.Assert.assertEquals import static org.junit.Assert.assertTrue +import util.JenkinsConfigRule import util.JenkinsSetupRule import util.JenkinsShellCallRule @@ -19,6 +20,7 @@ class MavenExecuteTest extends PiperTestBase { @Rule public RuleChain ruleChain = RuleChain.outerRule(new JenkinsSetupRule(this)) .around(jscr) + .around(new JenkinsConfigRule(this)) @Before void init() { diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index afc846fd1..0e9731c38 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -6,6 +6,7 @@ import org.junit.Test import org.junit.rules.ExpectedException import org.junit.rules.RuleChain +import util.JenkinsConfigRule import util.JenkinsLoggingRule import util.JenkinsSetupRule import util.JenkinsShellCallRule @@ -23,6 +24,7 @@ class NeoDeploymentTest extends PiperTestBase { .around(new JenkinsSetupRule(this)) .around(jlr) .around(jscr) + .around(new JenkinsConfigRule(this)) def archivePath def warArchivePath def propertiesFilePath diff --git a/test/groovy/PipelineExecuteTest.groovy b/test/groovy/PipelineExecuteTest.groovy index 3a036cdf0..62771b419 100644 --- a/test/groovy/PipelineExecuteTest.groovy +++ b/test/groovy/PipelineExecuteTest.groovy @@ -1,4 +1,5 @@ import hudson.AbortException +import util.JenkinsConfigRule import util.JenkinsSetupRule import org.junit.rules.TemporaryFolder @@ -15,6 +16,7 @@ class PipelineExecuteTest extends PiperTestBase { @Rule public RuleChain ruleChain = RuleChain.outerRule(thrown) .around(new JenkinsSetupRule(this)) + .around(new JenkinsConfigRule(this)) def pipelinePath def checkoutParameters = [:] diff --git a/test/groovy/PiperTestBase.groovy b/test/groovy/PiperTestBase.groovy index 3ab5d22ca..14caf7105 100644 --- a/test/groovy/PiperTestBase.groovy +++ b/test/groovy/PiperTestBase.groovy @@ -1,5 +1,5 @@ import com.lesfurets.jenkins.unit.BasePipelineTest -import com.sap.piper.DefaultValueCache + import org.yaml.snakeyaml.Yaml import static ProjectSource.projectSource @@ -19,14 +19,8 @@ public class PiperTestBase extends BasePipelineTest { super.setUp() - helper.registerAllowedMethod("readYaml", [Map], { Map parameters -> - Yaml yamlParser = new Yaml() - return yamlParser.load(parameters.text) - }) - pipeline = pipelineFolder.newFile() - DefaultValueCache.reset() } protected withPipeline(p) { diff --git a/test/groovy/ToolValidateTest.groovy b/test/groovy/ToolValidateTest.groovy index 7968f90f7..30b386363 100644 --- a/test/groovy/ToolValidateTest.groovy +++ b/test/groovy/ToolValidateTest.groovy @@ -7,6 +7,7 @@ import org.junit.rules.ExpectedException import org.junit.rules.RuleChain import org.junit.rules.TemporaryFolder +import util.JenkinsConfigRule import util.JenkinsLoggingRule import util.JenkinsSetupRule @@ -15,6 +16,7 @@ class ToolValidateTest extends PiperTestBase { private ExpectedException thrown = new ExpectedException().none() private TemporaryFolder tmp = new TemporaryFolder() private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this) + private JenkinsConfigRule jcr = new JenkinsConfigRule(this) @Rule public RuleChain ruleChain = @@ -22,6 +24,7 @@ class ToolValidateTest extends PiperTestBase { .around(thrown) .around(new JenkinsSetupRule(this)) .around(jlr) + .around(jcr) private notEmptyDir private script diff --git a/test/groovy/util/JenkinsConfigRule.groovy b/test/groovy/util/JenkinsConfigRule.groovy new file mode 100644 index 000000000..2779501e5 --- /dev/null +++ b/test/groovy/util/JenkinsConfigRule.groovy @@ -0,0 +1,38 @@ +package util + +import com.lesfurets.jenkins.unit.BasePipelineTest +import com.sap.piper.DefaultValueCache +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement +import org.yaml.snakeyaml.Yaml + +class JenkinsConfigRule implements TestRule { + + final BasePipelineTest testInstance + + + JenkinsConfigRule(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("readYaml", [Map], { Map parameters -> + Yaml yamlParser = new Yaml() + return yamlParser.load(parameters.text) + }) + DefaultValueCache.reset() + + base.evaluate() + } + } + } +} From 749aa5e7edbe097421f298e37822010c51a0348d Mon Sep 17 00:00:00 2001 From: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> Date: Wed, 24 Jan 2018 09:55:38 +0100 Subject: [PATCH 18/32] InfluxDB support (#52) * adding step for writing metrics to InfluxDB including dependencies * added documentation * incorporated PR feedback --- .../docs/scripts/configurationMerger.md | 69 ++++++- documentation/docs/scripts/jsonUtils.md | 30 +++ documentation/docs/scripts/utils.md | 2 +- .../docs/steps/commonPipelineEnvironment.md | 139 ++++++++++++- documentation/docs/steps/durationMeasure.md | 37 ++++ documentation/docs/steps/influxWriteData.md | 195 ++++++++++++++++++ documentation/mkdocs.yml | 13 +- resources/default_pipeline_environment.yml | 3 + src/com/sap/piper/ConfigurationMerger.groovy | 15 ++ src/com/sap/piper/JsonUtils.groovy | 8 + src/com/sap/piper/Utils.groovy | 2 +- test/groovy/DurationMeasureTest.groovy | 25 +++ test/groovy/InfluxWriteDataTest.groovy | 99 +++++++++ .../sap/piper/ConfigurationMergerTest.groovy | 13 ++ vars/commonPipelineEnvironment.groovy | 34 ++- vars/durationMeasure.groovy | 19 ++ vars/influxWriteData.groovy | 62 ++++++ 17 files changed, 751 insertions(+), 14 deletions(-) create mode 100644 documentation/docs/scripts/jsonUtils.md create mode 100644 documentation/docs/steps/durationMeasure.md create mode 100644 documentation/docs/steps/influxWriteData.md create mode 100644 src/com/sap/piper/JsonUtils.groovy create mode 100644 test/groovy/DurationMeasureTest.groovy create mode 100644 test/groovy/InfluxWriteDataTest.groovy create mode 100644 vars/durationMeasure.groovy create mode 100644 vars/influxWriteData.groovy diff --git a/documentation/docs/scripts/configurationMerger.md b/documentation/docs/scripts/configurationMerger.md index 52597053b..8f2d708cb 100644 --- a/documentation/docs/scripts/configurationMerger.md +++ b/documentation/docs/scripts/configurationMerger.md @@ -1,7 +1,7 @@ # ConfigurationMerger ## Description -A helper script that can merge the configurations from multiple sources. +A helper script that can merge the configurations from multiple sources. ## Static Method Details @@ -10,8 +10,8 @@ A helper script that can merge the configurations from multiple sources. #### Description A step is usually configured by default values, configuration values from the configuration file and the parameters. -The methods can merge these sources. -Default values are overwritten by configuration file values. +The method can merge these sources. +Default values are overwritten by configuration file values. These are overwritten by parameters. #### Parameters @@ -25,9 +25,9 @@ These are overwritten by parameters. | `defaults` | yes | Map | * `parameters` Parameters map given to the step -* `parameterKeys` List of parameter names (keys) that should be considered while merging. +* `parameterKeys` List of parameter names (keys) that should be considered while merging. * `configurationMap` Configuration map loaded from the configuration file. -* `configurationKeys` List of configuration keys that should be considered while merging. +* `configurationKeys` List of configuration keys that should be considered while merging. * `defaults` Map of default values, e.g. loaded from the default value configuration file. #### Side effects @@ -62,3 +62,62 @@ List stepConfigurationKeys = [ Map configuration = ConfigurationMerger.merge(parameters, parameterKeys, stepConfiguration, stepConfigurationKeys, stepDefaults) ``` + +### mergeWithPipelineData + +#### Description + +A step is usually configured by default values, configuration values from the configuration file and the parameters. +In certain cases also information previously generated in the pipeline should be mixed in, like for example an artifactVersion created earlier. +The method can merge these sources. +Default values are overwritten by configuration file values. +Those are overwritten by information previously generated in the pipeline (e.g. stored in [commonPipelineEnvironment](../steps/commonPipelineEnvironment.md)). +These are overwritten by parameters passed directly to the step. + +#### Parameters + +| parameter | mandatory | Class | +| -------------------|-----------|-----------------------------------| +| `parameters` | yes | Map | +| `parameterKeys` | yes | List | +| `pipelineDataMap` | yes | Map | +| `configurationMap` | yes | Map | +| `configurationKeys`| yes | List | +| `defaults` | yes | Map | + +* `parameters` Parameters map given to the step +* `parameterKeys` List of parameter names (keys) that should be considered while merging. +* `configurationMap` Configuration map loaded from the configuration file. +* `pipelineDataMap` Values available to the step during pipeline run. +* `configurationKeys` List of configuration keys that should be considered while merging. +* `defaults` Map of default values, e.g. loaded from the default value configuration file. + +#### Side effects + +none + +#### Example + +```groovy +def stepName = 'influxWriteData' +prepareDefaultValues script: script + +final Map stepDefaults = ConfigurationLoader.defaultStepConfiguration(script, stepName) +final Map stepConfiguration = ConfigurationLoader.stepConfiguration(script, stepName) +final Map generalConfiguration = ConfigurationLoader.generalConfiguration(script) + +List parameterKeys = [ + 'artifactVersion', + 'influxServer', + 'influxPrefix' +] +Map pipelineDataMap = [ + artifactVersion: commonPipelineEnvironment.getArtifactVersion() +] +List stepConfigurationKeys = [ + 'influxServer', + 'influxPrefix' +] + +Map configuration = ConfigurationMerger.mergeWithPipelineData(parameters, parameterKeys, pipelineDataMap, stepConfiguration, stepConfigurationKeys, stepDefaults) +``` diff --git a/documentation/docs/scripts/jsonUtils.md b/documentation/docs/scripts/jsonUtils.md new file mode 100644 index 000000000..f414fa0b9 --- /dev/null +++ b/documentation/docs/scripts/jsonUtils.md @@ -0,0 +1,30 @@ +# JsonUtils + +## Description +Provides json related utility functions. + +## Constructors + +### JsonUtils() +Default no-argument constructor. Instances of the Utils class does not hold any instance specific state. + +#### Example +```groovy +new JsonUtils() +``` + +## Method Details + +### getPrettyJsonString(object) + +#### Description +Creates a pretty-printed json string. + +#### Parameters +* `object` - A object (e.g. Map or List). + +#### Return value +A pretty printed `String`. + +#### Side effects +none diff --git a/documentation/docs/scripts/utils.md b/documentation/docs/scripts/utils.md index 695b0bc5e..5b69bae95 100644 --- a/documentation/docs/scripts/utils.md +++ b/documentation/docs/scripts/utils.md @@ -24,7 +24,7 @@ Retrieves the parameter value for parameter `paramName` from parameter map `map` #### Parameters * `map` - A map containing configuration parameters. * `paramName` - The key of the parameter which should be looked up. -* `defaultValue` - The value which is returned in case there is no parameter with key `paramName` contained in `map`. +* optional: `defaultValue` - The value which is returned in case there is no parameter with key `paramName` contained in `map`. If it is not provided the default is `null`. #### Return value The value to the parameter to be retrieved, or the default value if the former is `null`, either since there is no such key or the key is associated with value `null`. In case the parameter is not defined or the value for that parameter is `null`and there is no default value an exception is thrown. diff --git a/documentation/docs/steps/commonPipelineEnvironment.md b/documentation/docs/steps/commonPipelineEnvironment.md index dc89c56aa..14ab7496b 100644 --- a/documentation/docs/steps/commonPipelineEnvironment.md +++ b/documentation/docs/steps/commonPipelineEnvironment.md @@ -6,9 +6,52 @@ Provides project specific settings. ## Prerequisites none - ## Method details +### getArtifactVersion() + +#### Description +Returns the version of the artifact which is build in the pipeline. + +#### Parameters +none + +#### Return value +A `String` containing the version. + +#### Side effects +none + +#### Exceptions +none + +#### Example +```groovy +def myVersion = commonPipelineEnvironment.getArtifactVersion() +``` + +### setArtifactVersion(version) + +#### Description +Sets the version of the artifact which is build in the pipeline. + +#### Parameters +none + +#### Return value +none + +#### Side effects +none + +#### Exceptions +none + +#### Example +```groovy +commonPipelineEnvironment.setArtifactVersion('1.2.3') +``` + ### getConfigProperties() #### Description @@ -102,6 +145,53 @@ none commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'my-deploy-host.com') ``` +### getInfluxCustomData() + +#### Description +Returns the Influx custom data which can be collected during pipeline run. + +#### Parameters +none + +#### Return value +A `Map` containing the data collected. + +#### Side effects +none + +#### Exceptions +none + +#### Example +```groovy +def myInfluxData = commonPipelineEnvironment.getInfluxCustomData() +``` + +### getInfluxCustomDataMap() + +#### Description +Returns the Influx custom data map which can be collected during pipeline run. +It is used for example by step [`influxWriteData`](../steps/influxWriteData.md). +The data map is a map of maps, like `[pipeline_data: [:], my_measurement: [:]]` +Each map inside the map represents a dedicated measurement in the InfluxDB. + + +#### Parameters +none + +#### Return value +A `Map` containing a `Map`s with data collected. + +#### Side effects +none + +#### Exceptions +none + +#### Example +```groovy +def myInfluxDataMap = commonPipelineEnvironment.getInfluxCustomDataMap() +``` ### getMtarFileName() @@ -143,3 +233,50 @@ none ```groovy commonPipelineEnvironment.setMtarFileName('path/to/foo.mtar') ``` + +### getPipelineMeasurement(measurementName) + +#### Description +Returns the value of a specific pipeline measurement. +The measurements are collected with step [`durationMeasure`](../steps/durationMeasure.md) + +#### Parameters +Name of the measurement + +#### Return value +Value of the measurement + +#### Side effects +none + +#### Exceptions +none + +#### Example +```groovy +def myMeasurementValue = commonPipelineEnvironment.getPipelineMeasurement('build_stage_duration') +``` + +### setPipelineMeasurement(measurementName, value) + +#### Description +**This is an internal function!** +Sets the value of a specific pipeline measurement. +Please use the step [`durationMeasure`](../steps/durationMeasure.md) in a pipeline, instead. + +#### Parameters +Name of the measurement and its value. + +#### Return value +none + +#### Side effects +none + +#### Exceptions +none + +#### Example +```groovy +commonPipelineEnvironment.setPipelineMeasurement('build_stage_duration', 2345) +``` diff --git a/documentation/docs/steps/durationMeasure.md b/documentation/docs/steps/durationMeasure.md new file mode 100644 index 000000000..27ffbe2a1 --- /dev/null +++ b/documentation/docs/steps/durationMeasure.md @@ -0,0 +1,37 @@ +# durationMeasure + +## Description +This step is used to measure the duration of a set of steps, e.g. a certain stage. +The duration is stored in a Map. The measurement data can then be written to an Influx database using step [influxWriteData](influxWriteData.md). + +!!! tip + Measuring for example the duration of pipeline stages helps to identify potential bottlenecks within the deployment pipeline. + This then helps to counter identified issues with respective optimization measures, e.g parallelization of tests. + +## Prerequisites +none + +## Pipeline configuration +none + +## Explanation of pipeline step +Usage of pipeline step: + +```groovy +durationMeasure (script: this, measurementName: 'build_duration') { + //execute your build +} +``` + +Available parameters: + +| parameter | mandatory | default | possible values | +| ----------|-----------|---------|-----------------| +| script | no | empty `globalPipelineEnvironment` | | +| measurementName | no | test_duration | | + +Details: + +* `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 storing the measured duration. +* `measurementName` defines the name of the measurement which is written to the Influx database. + diff --git a/documentation/docs/steps/influxWriteData.md b/documentation/docs/steps/influxWriteData.md new file mode 100644 index 000000000..503753afb --- /dev/null +++ b/documentation/docs/steps/influxWriteData.md @@ -0,0 +1,195 @@ +# influxWriteData + +## Description +Since your Continuous Delivery Pipeline in Jenkins provides your productive development and delivery infrastructure you should monitor the pipeline to ensure it runs as expected. How to setup this monitoring is described in the following. + +You basically need three components: + +- The [InfluxDB Jenkins plugin](https://wiki.jenkins-ci.org/display/JENKINS/InfluxDB+Plugin) which allows you to send build metrics to InfluxDB servers +- The [InfluxDB](https://www.influxdata.com/time-series-platform/influxdb/) to store this data (Docker available) +- A [Grafana](http://grafana.org/) dashboard to visualize the data stored in InfluxDB (Docker available) + +!!! note "no InfluxDB available?" + If you don't have an InfluxDB available yet this step will still provide you some benefit. + + It will create following files for you and archive them into your build: + + * `jenkins_data.json`: This file gives you build-specific information, like e.g. build result, stage where the build failed + * `pipeline_data.json`: This file gives you detailed information about your pipeline, e.g. stage durations, steps executed, ... + +## Prerequisites + +### Setting up InfluxDB with Grafana + +The easiest way to start with is using the available official docker images. +You can either run these docker containers on the same host on which you run your Jenkins or each docker on individual VMs (hosts). +Very basic setup can be done like that (with user "admin" and password "adminPwd" for both InfluxDB and Grafana): + + docker run -d -p 8083:8083 -p 8086:8086 --restart=always --name influxdb -v /var/influx_data:/var/lib/influxdb influxdb + docker run -d -p 3000:3000 --name grafana --restart=always --link influxdb:influxdb -e "GF_SECURITY_ADMIN_PASSWORD=adminPwd" grafana/grafana + +For more advanced setup please reach out to the respective documentation: + +- https://hub.docker.com/_/influxdb/ (and https://github.com/docker-library/docs/tree/master/influxdb) +- https://hub.docker.com/r/grafana/grafana/ (and https://github.com/grafana/grafana-docker) + + +After you have started your InfluxDB docker you need to create a database: + +- in a Webbrowser open the InfluxDB Web-UI using the following URL: <host of your docker>:8083 (port 8083 is used for access via Web-UI, for Jenkins you use port 8086 to access the DB) +- create new DB (the name of this DB you need to provide later to Jenkins) +- create Admin user (this user you need to provide later to Jenkins) + +!!! hint "With InfluxDB version 1.1 the InfluxDB Web-UI is deprecated" + + +You can perform the above steps via commandline: + + - The following command will create a database with name <databasename> + + `curl -i -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE \"` + + - The admin user with the name <adminusername> and the password <adminuserpwd> can be created with + + `curl -i -XPOST http://localhost:8086/query --data-urlencode "q=CREATE USER \ WITH PASSWORD '\' WITH ALL PRIVILEGES"` + +Once you have started both docker containers and Influx and Grafana are running you need to configure the Jenkins Plugin according to your settings. + +## Pipeline configuration + +To setup your Jenkins you need to do two configuration steps: + +1. Configure Jenkins (via Manage Jenkins) +2. Adapt pipeline configuration + +### Configure Jenkins + +Once the plugin is available in your Jenkins: + +* go to "Manage Jenkins" > "Configure System" > scroll down to section "influxdb target" +* maintain Influx data + +!!! note "Jenkins as a Service" + For Jenkins as a Service instances this is already preset to the local InfluxDB with the name `jenkins`. In this case there is not need to do any additional configuration. + +### Adapt pipeline configuration + +You need to define the influxDB server in your pipeline as it is defined in the InfluxDb plugin configuration (see above). + +```properties +influxDBServer=jenkins +``` + +## Explanation of pipeline step + +Example usage of pipeline step: + +```groovy +influxWriteData script: this +``` + +Available parameters: + + +| parameter | mandatory | default | possible values | +| ----------|-----------|---------|-----------------| +| script | no | empty `commonPipelineEnvironment` | | +| artifactVersion | yes | commonPipelineEnvironment.getArtifactVersion() | | +| influxServer | no | `jenkins` | | +| influxPrefix | no | `null` | | + + +## Work with InfluxDB and Grafana + +You can access your **Grafana** via Web-UI: <host of your grafana(-docker)>:<port3000> +(or another port in case you have defined another one when starting your docker) + +As a first step you need to add your InfluxDB as Data source to your Grafana: +- Login as user admin (PW as defined when starting your docker) +- in the navigation go to data sources -> add data source: + - name + - type: InfluxDB + - Url: \http://<host of your InfluxDB server>:<port> + - Access: direct (not via proxy) + - database: <name of the DB as specified above> + - User: <name of the admin user as specified in step above> + - Password: <password of the admin user as specified in step above> + +!!! note "Jenkins as a Service" + For Jenkins as a Service the data source configuration is already available. + + Therefore no need to go through the data source configuration step unless you want to add addtional data sources. + + +## Data collected in InfluxDB + +The Influx plugin collects following data in the Piper context: + +* All data as per default [InfluxDB plugin capabilities](https://wiki.jenkins.io/display/JENKINS/InfluxDB+Plugin) +* Additional data collected via `commonPipelineEnvironment.setInfluxCustomDataProperty()` and via `commonPipelineEnvironment.setPipelineMeasurement()` + +!!! note "Add custom information to your InfluxDB" + You can simply add custom data collected during your pipeline runs via available data objects. + Example: + + ```groovy + //add data to measurement jenkins_custom_data - value can be a String or a Number + commonPipelineEnvironment.setInfluxCustomDataProperty('myProperty', 2018) + ``` + +### Collected InfluxDB measurements +Measurements are potentially pre-fixed - see parameter `influxPrefix` above. + +| Measurement name | data column | description | +| ---------------- | ----------- | ----------- | +| **All measurements** |
  • build_number
  • project_name
| All below measurements will have these columns.
Details see [InfluxDB plugin documentation](https://wiki.jenkins.io/display/JENKINS/InfluxDB+Plugin)| +| jenkins_data |
  • build_result
  • build_time
  • last_successful_build
  • tests_failed
  • tests_skipped
  • tests_total
  • ...
| Details see [InfluxDB plugin documentation](https://wiki.jenkins.io/display/JENKINS/InfluxDB+Plugin)| +| cobertura_data |
  • cobertura_branch_coverage_rate
  • cobertura_class_coverage_rate
  • cobertura_line_coverage_rate
  • cobertura_package_coverage_rate
  • ...
| Details see [InfluxDB plugin documentation](https://wiki.jenkins.io/display/JENKINS/InfluxDB+Plugin) | +| jacoco_data |
  • jacoco_branch_coverage_rate
  • jacoco_class_coverage_rate
  • jacoco_instruction_coverage_rate
  • jacoco_line_coverage_rate
  • jacoco_method_coverage_rate
| Details see [InfluxDB plugin documentation](https://wiki.jenkins.io/display/JENKINS/InfluxDB+Plugin) | +| performance_data |
  • 90Percentile
  • average
  • max
  • median
  • min
  • error_count
  • error_percent
  • ...
| Details see [InfluxDB plugin documentation](https://wiki.jenkins.io/display/JENKINS/InfluxDB+Plugin) | +| sonarqube_data |
  • blocker_issues
  • critical_issues
  • info_issues
  • major_issues
  • minor_issues
  • lines_of_code
  • ...
| Details see [InfluxDB plugin documentation](https://wiki.jenkins.io/display/JENKINS/InfluxDB+Plugin) | +| jenkins_custom_data | Piper fills following colums by default:
  • build_result
  • build_result_key
  • build_step (->step in case of error)
  • build_error (->error message in case of error)
| filled by `commonPipelineEnvironment.setInfluxCustomDataProperty()` | +| pipeline_data | Examples from the Piper templates:
  • build_duration
  • opa_duration
  • deploy_test_duration
  • deploy_test_duration
  • fortify_duration
  • release_duration
  • ...
| filled by step [`measureDuration`](durationMeasure.md) using parameter `measurementName`| +| step_data | Considered, e.g.:
  • build_quality (Milestone/Release)
  • build_url
  • bats
  • checkmarx
  • fortify
  • gauge
  • nsp
  • opa
  • opensourcedependency
  • ppms
  • jmeter
  • supa
  • snyk
  • sonar
  • sourceclear
  • uiveri5
  • vulas
  • whitesource
  • traceability
  • ...
  • xmakestage
  • xmakepromote
| filled by `commonPipelineEnvironment.setInfluxStepData()` | + + +### Examples for InfluxDB queries which can be used in Grafana + +!!! caution "Project Names containing dashes (-)" + The InfluxDB plugin replaces dashes (-) with underscores (\_). + + Please keep this in mind when specifying your project_name for a InfluxDB query. + + +#### Example 1: Select last 10 successful builds + +``` +select top(build_number,10), build_result from jenkins_data WHERE build_result = 'SUCCESS' +``` + +#### Example 2: Select last 10 step names of failed builds + + +``` +select top(build_number,10), build_result, build_step from jenkins_custom_data WHERE build_result = 'FAILURE' +``` + +#### Example 3: Select build duration of step for a specific project + +``` +select build_duration / 1000 from "pipeline_data" WHERE project_name='PiperTestOrg_piper_test_master' +``` + +#### Example 4: Get transparency about successful/failed steps for a specific project + +``` +select top(build_number,10) AS "Build", build_url, build_quality, fortify, gauge, vulas, opa from step_data WHERE project_name='PiperTestOrg_piper_test_master' +``` + +!!! note + With this query you can create transparency about which steps ran successfully / not successfully in your pipeline and which ones were not executed at all. + + By specifying all the steps you consider relevant in your select statement it is very easy to create this transparency. + + + diff --git a/documentation/mkdocs.yml b/documentation/mkdocs.yml index 1d04a6ac9..b3791bda0 100644 --- a/documentation/mkdocs.yml +++ b/documentation/mkdocs.yml @@ -3,17 +3,20 @@ pages: - Home: index.md - 'Library steps': - commonPipelineEnvironment: steps/commonPipelineEnvironment.md + - dockerExecute: steps/dockerExecute.md + - durationMeasure: steps/durationMeasure.md - handlePipelineStepErrors: steps/handlePipelineStepErrors.md - - pipelineExecute: steps/pipelineExecute.md - - toolValidate: steps/toolValidate.md + - influxWriteData: steps/influxWriteData.md + - mavenExecute: steps/mavenExecute.md - mtaBuild: steps/mtaBuild.md - neoDeploy: steps/neoDeploy.md - - setupCommonPipelineEnvironment: steps/setupCommonPipelineEnvironment.md - - mavenExecute: steps/mavenExecute.md - - dockerExecute: steps/dockerExecute.md + - pipelineExecute: steps/pipelineExecute.md - prepareDefaultValues: steps/prepareDefaultValues.md + - setupCommonPipelineEnvironment: steps/setupCommonPipelineEnvironment.md + - toolValidate: steps/toolValidate.md - 'Library scripts': - FileUtils: scripts/fileUtils.md + - JsonUtils: scripts/jsonUtils.md - Utils: scripts/utils.md - Version: scripts/version.md - ConfigurationLoader: scripts/configurationLoader.md diff --git a/resources/default_pipeline_environment.yml b/resources/default_pipeline_environment.yml index 50fa99fa6..1bab1b628 100644 --- a/resources/default_pipeline_environment.yml +++ b/resources/default_pipeline_environment.yml @@ -6,3 +6,6 @@ general: steps: mavenExecute: dockerImage: 'maven:3.5-jdk-7' + influxWriteData: + influxServer: 'jenkins' + diff --git a/src/com/sap/piper/ConfigurationMerger.groovy b/src/com/sap/piper/ConfigurationMerger.groovy index 23dc69fb8..17e9321f6 100644 --- a/src/com/sap/piper/ConfigurationMerger.groovy +++ b/src/com/sap/piper/ConfigurationMerger.groovy @@ -20,6 +20,21 @@ class ConfigurationMerger { return merged } + @NonCPS + def static mergeWithPipelineData(Map parameters, List parameterKeys, + Map pipelineDataMap, + Map configurationMap, List configurationKeys, + Map stepDefaults=[:] + ){ + Map merged = [:] + merged.putAll(stepDefaults) + merged.putAll(filterByKeyAndNull(configurationMap, configurationKeys)) + merged.putAll(pipelineDataMap) + merged.putAll(filterByKeyAndNull(parameters, parameterKeys)) + + return merged + } + @NonCPS private static filterByKeyAndNull(Map map, List keys) { Map filteredMap = map.findAll { diff --git a/src/com/sap/piper/JsonUtils.groovy b/src/com/sap/piper/JsonUtils.groovy new file mode 100644 index 000000000..cbee37f58 --- /dev/null +++ b/src/com/sap/piper/JsonUtils.groovy @@ -0,0 +1,8 @@ +package com.sap.piper + +import com.cloudbees.groovy.cps.NonCPS + +@NonCPS +def getPrettyJsonString(object) { + return groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson(object)) +} diff --git a/src/com/sap/piper/Utils.groovy b/src/com/sap/piper/Utils.groovy index e097f0b17..5b6792db0 100644 --- a/src/com/sap/piper/Utils.groovy +++ b/src/com/sap/piper/Utils.groovy @@ -3,7 +3,7 @@ package com.sap.piper import com.cloudbees.groovy.cps.NonCPS @NonCPS -def getMandatoryParameter(Map map, paramName, defaultValue) { +def getMandatoryParameter(Map map, paramName, defaultValue = null) { def paramValue = map[paramName] diff --git a/test/groovy/DurationMeasureTest.groovy b/test/groovy/DurationMeasureTest.groovy new file mode 100644 index 000000000..2b01720c2 --- /dev/null +++ b/test/groovy/DurationMeasureTest.groovy @@ -0,0 +1,25 @@ +#!groovy +import com.lesfurets.jenkins.unit.BasePipelineTest +import org.junit.Rule +import org.junit.Test +import util.JenkinsSetupRule +import static org.junit.Assert.assertTrue + +class DurationMeasureTest extends BasePipelineTest { + + @Rule + public JenkinsSetupRule setupRule = new JenkinsSetupRule(this) + + @Test + void testDurationMeasurement() throws Exception { + def cpe = loadScript("commonPipelineEnvironment.groovy").commonPipelineEnvironment + def script = loadScript("durationMeasure.groovy") + def bodyExecuted = false + script.call(script: [commonPipelineEnvironment: cpe], measurementName: 'test') { + bodyExecuted = true + } + assertTrue(cpe.getPipelineMeasurement('test') != null) + assertTrue(bodyExecuted) + assertJobStatusSuccess() + } +} diff --git a/test/groovy/InfluxWriteDataTest.groovy b/test/groovy/InfluxWriteDataTest.groovy new file mode 100644 index 000000000..d86fd18b7 --- /dev/null +++ b/test/groovy/InfluxWriteDataTest.groovy @@ -0,0 +1,99 @@ +#!groovy +import com.lesfurets.jenkins.unit.BasePipelineTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.RuleChain +import util.JenkinsLoggingRule +import util.JenkinsSetupRule + +import static org.junit.Assert.assertTrue +import static org.junit.Assert.assertEquals + +class InfluxWriteDataTest extends BasePipelineTest { + + Script influxWriteDataScript + + Map fileMap = [:] + Map stepMap = [:] + String echoLog = '' + + def cpe + + public JenkinsSetupRule setupRule = new JenkinsSetupRule(this) + public JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this) + + @Rule + public RuleChain ruleChain = + RuleChain.outerRule(setupRule) + .around(loggingRule) + + @Before + void init() throws Exception { + + //reset stepMap + stepMap = [:] + //reset fileMap + fileMap = [:] + + helper.registerAllowedMethod('readYaml', [Map.class], { map -> + return [ + general: [productiveBranch: 'develop'], + steps : [influxWriteData: [influxServer: 'testInflux']] + ] + }) + + helper.registerAllowedMethod('writeFile', [Map.class],{m -> fileMap[m.file] = m.text}) + helper.registerAllowedMethod('step', [Map.class],{m -> stepMap = m}) + + cpe = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment + influxWriteDataScript = loadScript("influxWriteData.groovy") + } + + + @Test + void testInfluxWriteDataWithDefault() throws Exception { + + cpe.setArtifactVersion('1.2.3') + influxWriteDataScript.call(script: [commonPipelineEnvironment: cpe]) + + assertTrue(loggingRule.log.contains('Artifact version: 1.2.3')) + + assertEquals('testInflux', stepMap.selectedTarget) + assertEquals(null, stepMap.customPrefix) + assertEquals([:], stepMap.customData) + assertEquals([pipeline_data:[:]], stepMap.customDataMap) + + assertTrue(fileMap.containsKey('jenkins_data.json')) + assertTrue(fileMap.containsKey('pipeline_data.json')) + + assertJobStatusSuccess() + } + + @Test + void testInfluxWriteDataNoInflux() throws Exception { + + cpe.setArtifactVersion('1.2.3') + influxWriteDataScript.call(script: [commonPipelineEnvironment: cpe], influxServer: '') + + assertEquals(0, stepMap.size()) + + assertTrue(fileMap.containsKey('jenkins_data.json')) + assertTrue(fileMap.containsKey('pipeline_data.json')) + + assertJobStatusSuccess() + } + + @Test + void testInfluxWriteDataNoArtifactVersion() throws Exception { + + influxWriteDataScript.call(script: [commonPipelineEnvironment: cpe]) + + assertEquals(0, stepMap.size()) + assertEquals(0, fileMap.size()) + + assertTrue(loggingRule.log.contains('no artifact version available -> exiting writeInflux without writing data')) + + assertJobStatusSuccess() + } +} diff --git a/test/groovy/com/sap/piper/ConfigurationMergerTest.groovy b/test/groovy/com/sap/piper/ConfigurationMergerTest.groovy index efdb2159b..544f51588 100644 --- a/test/groovy/com/sap/piper/ConfigurationMergerTest.groovy +++ b/test/groovy/com/sap/piper/ConfigurationMergerTest.groovy @@ -26,4 +26,17 @@ class ConfigurationMergerTest { Map merged = ConfigurationMerger.merge(parameters, parameterKeys, defaults) Assert.assertEquals([], merged.nonErpDestinations) } + + @Test + void testMergeCustomPipelineValues(){ + Map defaults = [dockerImage: 'mvn'] + Map parameters = [goals: 'install', flags: ''] + List parameterKeys = ['flags'] + Map configuration = [flags: '-B'] + List configurationKeys = ['flags'] + Map pipelineDataMap = [artifactVersion: '1.2.3', flags: 'test'] + Map merged = ConfigurationMerger.mergeWithPipelineData(parameters, parameterKeys, pipelineDataMap, configuration, configurationKeys, defaults) + Assert.assertEquals('', merged.flags) + Assert.assertEquals('1.2.3', merged.artifactVersion) + } } diff --git a/vars/commonPipelineEnvironment.groovy b/vars/commonPipelineEnvironment.groovy index c23765844..c2807a92e 100644 --- a/vars/commonPipelineEnvironment.groovy +++ b/vars/commonPipelineEnvironment.groovy @@ -1,11 +1,27 @@ class commonPipelineEnvironment implements Serializable { private Map configProperties = [:] - Map defaultConfiguration = [:] + //stores version of the artifact which is build during pipeline run + def artifactVersion + Map configuration = [:] + Map defaultConfiguration = [:] + + //each Map in influxCustomDataMap represents a measurement in Influx. Additional measurements can be added as a new Map entry of influxCustomDataMap + private Map influxCustomDataMap = [pipeline_data: [:]] + //influxCustomData represents measurement jenkins_custom_data in Influx. Metrics can be written into this map + private Map influxCustomData = [:] private String mtarFilePath + def setArtifactVersion(version) { + artifactVersion = version + } + + def getArtifactVersion() { + return artifactVersion + } + def setConfigProperties(map) { configProperties = map } @@ -25,6 +41,14 @@ class commonPipelineEnvironment implements Serializable { return configProperties[property] } + def getInfluxCustomData() { + return influxCustomData + } + + def getInfluxCustomDataMap() { + return influxCustomDataMap + } + def getMtarFilePath() { return mtarFilePath } @@ -32,4 +56,12 @@ class commonPipelineEnvironment implements Serializable { void setMtarFilePath(mtarFilePath) { this.mtarFilePath = mtarFilePath } + + def setPipelineMeasurement (measurementName, value) { + influxCustomDataMap.pipeline_data[measurementName] = value + } + + def getPipelineMeasurement (measurementName) { + return influxCustomDataMap.pipeline_data[measurementName] + } } diff --git a/vars/durationMeasure.groovy b/vars/durationMeasure.groovy new file mode 100644 index 000000000..aee5b0e60 --- /dev/null +++ b/vars/durationMeasure.groovy @@ -0,0 +1,19 @@ +def call(Map parameters = [:], body) { + + def script = parameters.script + def measurementName = parameters.get('measurementName', 'test_duration') + + //start measurement + def start = System.currentTimeMillis() + + body() + + //record measurement + def duration = System.currentTimeMillis() - start + + if (script != null) + script.commonPipelineEnvironment.setPipelineMeasurement(measurementName, duration) + + return duration +} + diff --git a/vars/influxWriteData.groovy b/vars/influxWriteData.groovy new file mode 100644 index 000000000..d4f8b3751 --- /dev/null +++ b/vars/influxWriteData.groovy @@ -0,0 +1,62 @@ +import com.sap.piper.ConfigurationLoader +import com.sap.piper.ConfigurationMerger +import com.sap.piper.JsonUtils + +def call(Map parameters = [:]) { + + def stepName = 'influxWriteData' + + handlePipelineStepErrors (stepName: stepName, stepParameters: parameters, allowBuildFailure: true) { + + 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 = [ + 'artifactVersion', + 'influxServer', + 'influxPrefix' + ] + Map pipelineDataMap = [ + artifactVersion: commonPipelineEnvironment.getArtifactVersion() + ] + List stepConfigurationKeys = [ + 'influxServer', + 'influxPrefix' + ] + + Map configuration = ConfigurationMerger.mergeWithPipelineData(parameters, parameterKeys, pipelineDataMap, stepConfiguration, stepConfigurationKeys, stepDefaults) + + def artifactVersion = configuration.artifactVersion + if (!artifactVersion) { + //this takes care that terminated builds due to milestone-locking do not cause an error + echo "[${stepName}] no artifact version available -> exiting writeInflux without writing data" + return + } + + def influxServer = configuration.influxServer + def influxPrefix = configuration.influxPrefix + + echo """[${stepName}]---------------------------------------------------------- +Artifact version: ${artifactVersion} +Influx server: ${influxServer} +Influx prefix: ${influxPrefix} +InfluxDB data: ${script.commonPipelineEnvironment.getInfluxCustomData()} +InfluxDB data map: ${script.commonPipelineEnvironment.getInfluxCustomDataMap()} +[${stepName}]----------------------------------------------------------""" + + if (influxServer) + step([$class: 'InfluxDbPublisher', selectedTarget: influxServer, customPrefix: influxPrefix, customData: script.commonPipelineEnvironment.getInfluxCustomData(), customDataMap: script.commonPipelineEnvironment.getInfluxCustomDataMap()]) + + //write results into json file for archiving - also benefitial when no InfluxDB is available yet + def jsonUtils = new JsonUtils() + writeFile file: 'jenkins_data.json', text: jsonUtils.getPrettyJsonString(script.commonPipelineEnvironment.getInfluxCustomData()) + writeFile file: 'pipeline_data.json', text: jsonUtils.getPrettyJsonString(script.commonPipelineEnvironment.getInfluxCustomDataMap()) + archiveArtifacts artifacts: '*data.json', allowEmptyArchive: true + } +} From 808170b88ae892dd4d06c85428780e63a199305f Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Tue, 16 Jan 2018 17:06:25 +0100 Subject: [PATCH 19/32] Call pipeline steps directly, without using a pipeline snippet --- test/groovy/DockerExecuteTest.groovy | 45 +- test/groovy/MTABuildTest.groovy | 113 ++--- test/groovy/MavenExecuteTest.groovy | 27 +- test/groovy/NeoDeploymentTest.groovy | 395 +++++++----------- test/groovy/PipelineExecuteTest.groovy | 62 +-- test/groovy/PiperTestBase.groovy | 30 -- .../SetupCommonPipelineEnvironmentTest.groovy | 20 +- test/groovy/ToolValidateTest.groovy | 86 ++-- .../executeInsideDocker.groovy | 11 - .../executeInsideDockerWithParameters.groovy | 11 - .../executeBasicMavenCommand.groovy | 9 - .../executeMavenCommandWithParameters.groovy | 21 - .../loadConfiguration.groovy | 11 - 13 files changed, 302 insertions(+), 539 deletions(-) delete mode 100644 test/groovy/PiperTestBase.groovy delete mode 100644 test/resources/pipelines/dockerExecuteTest/executeInsideDocker.groovy delete mode 100644 test/resources/pipelines/dockerExecuteTest/executeInsideDockerWithParameters.groovy delete mode 100644 test/resources/pipelines/mavenExecuteTest/executeBasicMavenCommand.groovy delete mode 100644 test/resources/pipelines/mavenExecuteTest/executeMavenCommandWithParameters.groovy delete mode 100644 test/resources/pipelines/setupCommonPipelineEnvironmentTest/loadConfiguration.groovy diff --git a/test/groovy/DockerExecuteTest.groovy b/test/groovy/DockerExecuteTest.groovy index da4bac757..9c6c425c6 100644 --- a/test/groovy/DockerExecuteTest.groovy +++ b/test/groovy/DockerExecuteTest.groovy @@ -4,6 +4,8 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.RuleChain +import com.lesfurets.jenkins.unit.BasePipelineTest + import util.JenkinsConfigRule import util.JenkinsLoggingRule import util.JenkinsSetupRule @@ -12,7 +14,7 @@ import static org.junit.Assert.assertEquals import static org.junit.Assert.assertTrue import static org.junit.Assert.assertFalse -class DockerExecuteTest extends PiperTestBase { +class DockerExecuteTest extends BasePipelineTest { private DockerMock docker private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this) @@ -24,46 +26,72 @@ class DockerExecuteTest extends PiperTestBase { int whichDockerReturnValue = 0 + def bodyExecuted + + def cpe + def dockerExecuteScript; + @Before void init() { + bodyExecuted = false docker = new DockerMock() binding.setVariable('docker', docker) binding.setVariable('Jenkins', [instance: [pluginManager: [plugins: [new PluginMock()]]]]) helper.registerAllowedMethod('sh', [Map.class], {return whichDockerReturnValue}) + + cpe = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment + dockerExecuteScript = loadScript('dockerExecute.groovy').dockerExecute } @Test void testExecuteInsideDocker() throws Exception { - def script = loadScript("test/resources/pipelines/dockerExecuteTest/executeInsideDocker.groovy") - script.execute() + + dockerExecuteScript.call(script: [commonPipelineEnvironment: cpe], + dockerImage: 'maven:3.5-jdk-8-alpine') { + bodyExecuted = true + } + assertEquals('maven:3.5-jdk-8-alpine', docker.getImageName()) assertTrue(docker.isImagePulled()) assertEquals(' --env http_proxy --env https_proxy --env no_proxy --env HTTP_PROXY --env HTTPS_PROXY --env NO_PROXY', docker.getParameters()) - assertTrue(jlr.log.contains('Inside Docker')) + assertTrue(bodyExecuted) } @Test void testExecuteInsideDockerWithParameters() throws Exception { - def script = loadScript("test/resources/pipelines/dockerExecuteTest/executeInsideDockerWithParameters.groovy") - script.execute() + dockerExecuteScript.call(script: [commonPipelineEnvironment: cpe], + dockerImage: 'maven:3.5-jdk-8-alpine', + dockerOptions: '-it', + dockerVolumeBind: ['my_vol': '/my_vol'], + dockerEnvVars: ['http_proxy': 'http://proxy:8000']) { + bodyExecuted = true + } assertTrue(docker.getParameters().contains(' --env https_proxy ')) assertTrue(docker.getParameters().contains(' --env http_proxy=http://proxy:8000')) assertTrue(docker.getParameters().contains(' -it')) assertTrue(docker.getParameters().contains(' --volume my_vol:/my_vol')) + assertTrue(bodyExecuted) } @Test void testDockerNotInstalledResultsInLocalExecution() throws Exception { whichDockerReturnValue = 1 - def script = loadScript("test/resources/pipelines/dockerExecuteTest/executeInsideDockerWithParameters.groovy") - script.execute() + dockerExecuteScript.call(script: [commonPipelineEnvironment: cpe], + dockerImage: 'maven:3.5-jdk-8-alpine', + dockerOptions: '-it', + dockerVolumeBind: ['my_vol': '/my_vol'], + dockerEnvVars: ['http_proxy': 'http://proxy:8000']) { + bodyExecuted = true + } + assertTrue(jlr.log.contains('No docker environment found')) assertTrue(jlr.log.contains('Running on local environment')) + assertTrue(bodyExecuted) assertFalse(docker.isImagePulled()) } @@ -107,5 +135,4 @@ class DockerExecuteTest extends PiperTestBase { return true } } - } diff --git a/test/groovy/MTABuildTest.groovy b/test/groovy/MTABuildTest.groovy index 8cd934bf6..999b3b220 100644 --- a/test/groovy/MTABuildTest.groovy +++ b/test/groovy/MTABuildTest.groovy @@ -7,12 +7,15 @@ import org.junit.Test import org.junit.rules.ExpectedException import org.junit.rules.RuleChain import org.junit.rules.TemporaryFolder + +import com.lesfurets.jenkins.unit.BasePipelineTest + import util.JenkinsConfigRule import util.JenkinsLoggingRule import util.JenkinsSetupRule import util.JenkinsShellCallRule -public class MTABuildTest extends PiperTestBase { +public class MTABuildTest extends BasePipelineTest { private ExpectedException thrown = new ExpectedException() private TemporaryFolder tmp = new TemporaryFolder() @@ -32,6 +35,8 @@ public class MTABuildTest extends PiperTestBase { def otherDir def mtaBuildShEnv + def mtaBuildScript + def cpe @Before void init() { @@ -60,6 +65,8 @@ public class MTABuildTest extends PiperTestBase { binding.setVariable('JAVA_HOME', '/opt/java') binding.setVariable('env', [:]) + mtaBuildScript = loadScript("mtaBuild.groovy").mtaBuild + cpe = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment } @@ -70,7 +77,8 @@ public class MTABuildTest extends PiperTestBase { new File("${currentDir}/mta.yaml") << defaultMtaYaml() - def mtarFilePath = withPipeline(defaultPipeline()).execute() + 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"$/ @@ -91,7 +99,10 @@ public class MTABuildTest extends PiperTestBase { new File("${currentDir}/mta.yaml") << defaultMtaYaml() - def mtarFilePath = withPipeline(returnMtarFilePathFromCommonPipelineEnvironmentPipeline()).execute() + 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"$/ @@ -111,10 +122,14 @@ public class MTABuildTest extends PiperTestBase { binding.getVariable('env')['MTA_JAR_LOCATION'] = '/opt/mta' def newDirName = 'newDir' - new File("${currentDir}/${newDirName}").mkdirs() - new File("${currentDir}/${newDirName}/mta.yaml") << defaultMtaYaml() + def newDir = new File("${currentDir}/${newDirName}") - def mtarFilePath = withPipeline(withSurroundingDirPipeline()).execute(newDirName) + newDir.mkdirs() + new File(newDir, 'mta.yaml') << defaultMtaYaml() + + helper.registerAllowedMethod('pwd', [], { newDir } ) + + 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" ".*\/newDir\/mta.yaml"$/ @@ -122,7 +137,7 @@ public class MTABuildTest extends PiperTestBase { assert jscr.shell[1].contains(' -jar /opt/mta/mta.jar --mtar ') - assert mtarFilePath == "${currentDir}/com.mycompany.northwind.mtar" + assert mtarFilePath == "${currentDir}/${newDirName}/com.mycompany.northwind.mtar" assert jlr.log.contains("[mtaBuild] MTA JAR \"/opt/mta/mta.jar\" retrieved from environment.") } @@ -132,7 +147,7 @@ public class MTABuildTest extends PiperTestBase { new File("${currentDir}/mta.yaml") << defaultMtaYaml() - def mtarFilePath = withPipeline(defaultPipeline()).execute() + 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"$/ @@ -151,17 +166,17 @@ public class MTABuildTest extends PiperTestBase { new File("${currentDir}/mta.yaml") << defaultMtaYaml() - def mtarFilePath = withPipeline(mtaJarLocationAsParameterPipeline()).execute() + 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") - assert jscr.shell[1].contains(' -jar /etc/mta/mta.jar --mtar ') + 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 \"/etc/mta/mta.jar\" retrieved from parameters.".toString()) + assert jlr.log.contains("[mtaBuild] MTA JAR \"/mylocation/mta/mta.jar\" retrieved from parameters.".toString()) } @@ -169,7 +184,8 @@ public class MTABuildTest extends PiperTestBase { public void noMtaPresentTest(){ thrown.expect(FileNotFoundException) - withPipeline(defaultPipeline()).execute() + mtaBuildScript.call(script: [commonPipelineEnvironment: cpe], + buildTarget: 'NEO') } @@ -180,7 +196,8 @@ public class MTABuildTest extends PiperTestBase { new File("${currentDir}/mta.yaml") << badMtaYaml() - withPipeline(defaultPipeline()).execute() + mtaBuildScript.call(script: [commonPipelineEnvironment: cpe], + buildTarget: 'NEO') } @@ -191,7 +208,8 @@ public class MTABuildTest extends PiperTestBase { new File("${currentDir}/mta.yaml") << noIdMtaYaml() - withPipeline(defaultPipeline()).execute() + mtaBuildScript.call(script: [commonPipelineEnvironment: cpe], + buildTarget: 'NEO') } @@ -202,74 +220,9 @@ public class MTABuildTest extends PiperTestBase { new File("${currentDir}/mta.yaml") << defaultMtaYaml() - withPipeline(noBuildTargetPipeline()).execute() + mtaBuildScript.call(script: [commonPipelineEnvironment: cpe]) } - - private defaultPipeline(){ - return ''' - @Library('piper-library-os') - - execute(){ - mtaBuild buildTarget: 'NEO' - } - - return this - ''' - } - - private returnMtarFilePathFromCommonPipelineEnvironmentPipeline(){ - return ''' - @Library('piper-library-os') - - execute(){ - mtaBuild buildTarget: 'NEO' - return commonPipelineEnvironment.getMtarFilePath() - } - - return this - ''' - } - - private mtaJarLocationAsParameterPipeline(){ - return ''' - @Library('piper-library-os') - - execute(){ - mtaBuild mtaJarLocation: '/etc/mta', buildTarget: 'NEO' - } - - return this - ''' - } - - private withSurroundingDirPipeline(){ - return ''' - @Library('piper-library-os') - - execute(dirPath){ - dir("${dirPath}"){ - mtaBuild buildTarget: 'NEO' - } - } - - return this - ''' - } - - private noBuildTargetPipeline(){ - return ''' - @Library('piper-library-os') - - execute(){ - mtaBuild() - } - - return this - ''' - } - - private defaultMtaYaml(){ return ''' _schema-version: "2.0.0" diff --git a/test/groovy/MavenExecuteTest.groovy b/test/groovy/MavenExecuteTest.groovy index 19b2b832f..2f62af7d7 100644 --- a/test/groovy/MavenExecuteTest.groovy +++ b/test/groovy/MavenExecuteTest.groovy @@ -4,6 +4,8 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.RuleChain +import com.lesfurets.jenkins.unit.BasePipelineTest + import static org.junit.Assert.assertEquals import static org.junit.Assert.assertTrue @@ -11,7 +13,7 @@ import util.JenkinsConfigRule import util.JenkinsSetupRule import util.JenkinsShellCallRule -class MavenExecuteTest extends PiperTestBase { +class MavenExecuteTest extends BasePipelineTest { Map dockerParameters @@ -22,6 +24,9 @@ class MavenExecuteTest extends PiperTestBase { .around(jscr) .around(new JenkinsConfigRule(this)) + def mavenExecuteScript + def cpe + @Before void init() { @@ -32,12 +37,15 @@ class MavenExecuteTest extends PiperTestBase { dockerParameters = parameters closure() }) + + mavenExecuteScript = loadScript("mavenExecute.groovy").mavenExecute + cpe = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment } @Test void testExecuteBasicMavenCommand() throws Exception { - def script = loadScript("test/resources/pipelines/mavenExecuteTest/executeBasicMavenCommand.groovy") - script.execute() + + mavenExecuteScript.call(script: [commonPipelineEnvironment: cpe], goals: 'clean install') assertEquals('maven:3.5-jdk-7', dockerParameters.dockerImage) assert jscr.shell[0] == 'mvn clean install' @@ -45,8 +53,17 @@ class MavenExecuteTest extends PiperTestBase { @Test void testExecuteMavenCommandWithParameter() throws Exception { - def script = loadScript("test/resources/pipelines/mavenExecuteTest/executeMavenCommandWithParameters.groovy") - script.execute() + + mavenExecuteScript.call( + script: [commonPipelineEnvironment: cpe], + dockerImage: 'maven:3.5-jdk-8-alpine', + goals: 'clean install', + globalSettingsFile: 'globalSettingsFile.xml', + projectSettingsFile: 'projectSettingsFile.xml', + pomPath: 'pom.xml', + flags: '-o', + m2Path: 'm2Path', + defines: '-Dmaven.tests.skip=true') assertEquals('maven:3.5-jdk-8-alpine', dockerParameters.dockerImage) String mvnCommand = "mvn --global-settings 'globalSettingsFile.xml' -Dmaven.repo.local='m2Path' --settings 'projectSettingsFile.xml' --file 'pom.xml' -o clean install -Dmaven.tests.skip=true" assertTrue(jscr.shell.contains(mvnCommand)) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 0e9731c38..eeced3418 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -1,5 +1,8 @@ import hudson.AbortException import org.junit.rules.TemporaryFolder + +import com.lesfurets.jenkins.unit.BasePipelineTest + import org.junit.Before import org.junit.Rule import org.junit.Test @@ -11,7 +14,7 @@ import util.JenkinsLoggingRule import util.JenkinsSetupRule import util.JenkinsShellCallRule -class NeoDeploymentTest extends PiperTestBase { +class NeoDeploymentTest extends BasePipelineTest { private ExpectedException thrown = new ExpectedException().none() private TemporaryFolder tmp = new TemporaryFolder() @@ -29,6 +32,9 @@ class NeoDeploymentTest extends PiperTestBase { def warArchivePath def propertiesFilePath + def neoDeployScript + def cpe + @Before void init() { @@ -57,6 +63,10 @@ class NeoDeploymentTest extends PiperTestBase { binding.setVariable('env', [:]) + neoDeployScript = loadScript("neoDeploy.groovy").neoDeploy + cpe = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment + + } @@ -67,7 +77,13 @@ class NeoDeploymentTest extends PiperTestBase { new File(archivePath) << "dummy archive" - withPipeline(defaultPipeline()).execute(archivePath, 'myCredentialsId') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: archivePath, + neoCredentialsId: 'myCredentialsId' + ) assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ @@ -85,8 +101,13 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(MissingPropertyException) - withPipeline(defaultPipeline()).execute(archivePath, 'badCredentialsId') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: archivePath, + neoCredentialsId: 'badCredentialsId' + ) } @@ -97,7 +118,12 @@ class NeoDeploymentTest extends PiperTestBase { new File(archivePath) << "dummy archive" - withPipeline(noCredentialsIdPipeline()).execute(archivePath) + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: archivePath + ) assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ @@ -110,7 +136,12 @@ class NeoDeploymentTest extends PiperTestBase { new File(archivePath) << "dummy archive" - withPipeline(noCredentialsIdPipeline()).execute(archivePath) + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: archivePath + ) assert jscr.shell[0] =~ /#!\/bin\/bash "neo" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ @@ -123,7 +154,14 @@ class NeoDeploymentTest extends PiperTestBase { new File(archivePath) << "dummy archive" - withPipeline(neoHomeParameterPipeline()).execute(archivePath, 'myCredentialsId') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: archivePath, + neoCredentialsId: 'myCredentialsId', + neoHome: '/etc/neo' + ) assert jscr.shell[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ @@ -138,8 +176,10 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR archivePath') - withPipeline(noArchivePathPipeline()).execute() + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + neoDeployScript.call(script: [commonPipelineEnvironment: cpe]) } @@ -149,8 +189,11 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(AbortException) thrown.expectMessage("Archive cannot be found with parameter archivePath: '") - withPipeline(defaultPipeline()).execute(archivePath, 'myCredentialsId') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: archivePath) } @@ -162,8 +205,7 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR deployHost') - withPipeline(noScriptPipeline()).execute(archivePath) - + neoDeployScript.call(archivePath: archivePath) } @Test @@ -171,7 +213,11 @@ class NeoDeploymentTest extends PiperTestBase { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' new File(archivePath) << "dummy archive" - withPipeline(mtaDeployModePipeline()).execute(archivePath, 'mta') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], archivePath: archivePath, deployMode: 'mta') + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -182,7 +228,21 @@ class NeoDeploymentTest extends PiperTestBase { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' new File(warArchivePath) << "dummy war archive" - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'deploy') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + def appName = 'testApp' + def runtime = 'neo-javaee6-wp' + def runtimeVersion = '2.125' + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + applicationName: 'testApp', + runtime: 'neo-javaee6-wp', + runtimeVersion: '2.125', + deployMode: 'warParams', + vmSize: 'lite', + warAction: 'deploy', + archivePath: warArchivePath) assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -193,7 +253,17 @@ class NeoDeploymentTest extends PiperTestBase { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' new File(warArchivePath) << "dummy war archive" - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'rolling-update') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + deployMode: 'warParams', + applicationName: 'testApp', + runtime: 'neo-javaee6-wp', + runtimeVersion: '2.125', + warAction: 'rolling-update', + vmSize: 'lite') assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -205,7 +275,15 @@ class NeoDeploymentTest extends PiperTestBase { new File(warArchivePath) << "dummy war archive" new File(propertiesFilePath) << "dummy properties file" - withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'warPropertiesFile', 'deploy') + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + deployMode: 'warPropertiesFile', + propertiesFile: propertiesFilePath, + applicationName: 'testApp', + runtime: 'neo-javaee6-wp', + runtimeVersion: '2.125', + warAction: 'deploy', + vmSize: 'lite') assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -217,7 +295,15 @@ class NeoDeploymentTest extends PiperTestBase { new File(warArchivePath) << "dummy war archive" new File(propertiesFilePath) << "dummy properties file" - withPipeline(warPropertiesFileDeployModePipeline()).execute(warArchivePath, propertiesFilePath, 'warPropertiesFile', 'rolling-update') + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + deployMode: 'warPropertiesFile', + propertiesFile: propertiesFilePath, + applicationName: 'testApp', + runtime: 'neo-javaee6-wp', + runtimeVersion: '2.125', + warAction: 'rolling-update', + vmSize: 'lite') assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -230,7 +316,15 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR applicationName') - withPipeline(noApplicationNamePipeline()).execute(warArchivePath, 'warParams') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + deployMode: 'warParams', + runtime: 'neo-javaee6-wp', + runtimeVersion: '2.125' + ) } @Test @@ -240,7 +334,14 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtime') - withPipeline(noRuntimePipeline()).execute(warArchivePath, 'warParams') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + applicationName: 'testApp', + deployMode: 'warParams', + runtimeVersion: '2.125') } @Test @@ -250,7 +351,14 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtimeVersion') - withPipeline(noRuntimeVersionPipeline()).execute(warArchivePath, 'warParams') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + applicationName: 'testApp', + deployMode: 'warParams', + runtime: 'neo-javaee6-wp') } @Test @@ -260,7 +368,17 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid deployMode = 'illegalMode'. Valid 'deployMode' values are: 'mta', 'warParams' and 'warPropertiesFile'") - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'illegalMode', 'lite', 'deploy') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + deployMode: 'illegalMode', + applicationName: 'testApp', + runtime: 'neo-javaee6-wp', + runtimeVersion: '2.125', + warAction: 'deploy', + vmSize: 'lite') } @Test @@ -270,7 +388,17 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid vmSize = 'illegalVM'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'illegalVM', 'deploy') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + deployMode: 'warParams', + applicationName: 'testApp', + runtime: 'neo-javaee6-wp', + runtimeVersion: '2.125', + warAction: 'deploy', + vmSize: 'illegalVM') } @Test @@ -280,221 +408,16 @@ class NeoDeploymentTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid warAction = 'illegalWARAction'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") - withPipeline(warParamsDeployModePipeline()).execute(warArchivePath, 'warParams', 'lite', 'illegalWARAction') + cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: warArchivePath, + deployMode: 'warParams', + applicationName: 'testApp', + runtime: 'neo-javaee6-wp', + runtimeVersion: '2.125', + warAction: 'illegalWARAction', + vmSize: 'lite') } - - private defaultPipeline(){ - return """ - @Library('piper-library-os') - - execute(archivePath, neoCredentialsId) { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - - node() { - neoDeploy script: this, archivePath: archivePath, neoCredentialsId: neoCredentialsId - } - - } - - return this - """ - } - - private noCredentialsIdPipeline(){ - return """ - @Library('piper-library-os') - - execute(archivePath) { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - - node() { - neoDeploy script: this, archivePath: archivePath - } - - } - - return this - """ - } - - private neoHomeParameterPipeline(){ - return """ - @Library('piper-library-os') - - execute(archivePath, neoCredentialsId) { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - - node() { - neoDeploy script: this, archivePath: archivePath, neoCredentialsId: neoCredentialsId, neoHome: '/etc/neo' - } - - } - - return this - """ - } - - private noArchivePathPipeline(){ - return """ - @Library('piper-library-os') - - execute() { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - - node() { - neoDeploy script: this - } - - } - - return this - """ - } - - private noScriptPipeline(){ - return """ - @Library('piper-library-os') - - execute(archivePath) { - - node() { - neoDeploy archivePath: archivePath - } - - } - - return this - """ - } - - private noApplicationNamePipeline() { - return """ - @Library('piper-library-os') - - execute(warArchivePath, deployMode) { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - def runtime = 'neo-javaee6-wp' - def runtimeVersion = '2.125' - - node() { - neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, runtime: runtime, runtimeVersion: runtimeVersion - } - - } - - return this - """ - } - - private noRuntimePipeline() { - return """ - @Library('piper-library-os') - - execute(warArchivePath, deployMode) { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - def appName = 'testApp' - def runtime = 'neo-javaee6-wp' - def runtimeVersion = '2.125' - - node() { - neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, applicationName: appName, runtimeVersion: runtimeVersion - } - - } - - return this - """ - } - - private noRuntimeVersionPipeline() { - return """ - @Library('piper-library-os') - - execute(warArchivePath, deployMode) { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - def appName = 'testApp' - def runtime = 'neo-javaee6-wp' - def runtimeVersion = '2.125' - - node() { - neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, applicationName: appName, runtime: runtime - } - - } - - return this - """ - } - - private warPropertiesFileDeployModePipeline() { - return """ - @Library('piper-library-os') - - execute(warArchivePath, propertiesFilePath, deployMode, warAction) { - - node() { - neoDeploy script: this, deployMode: deployMode, archivePath: warArchivePath, propertiesFile: propertiesFilePath, warAction: warAction - } - - } - - return this - """ - } - - private warParamsDeployModePipeline() { - return """ - @Library('piper-library-os') - - execute(warArchivePath, deployMode, vmSize, warAction) { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - def appName = 'testApp' - def runtime = 'neo-javaee6-wp' - def runtimeVersion = '2.125' - - node() { - neoDeploy script: this, archivePath: warArchivePath, deployMode: deployMode, applicationName: appName, runtime: runtime, runtimeVersion: runtimeVersion, warAction: warAction, vmSize: vmSize - } - - } - - return this - """ - } - - private mtaDeployModePipeline() { - return """ - @Library('piper-library-os') - - execute(archivePath, deployMode) { - - commonPipelineEnvironment.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') - commonPipelineEnvironment.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - - node() { - neoDeploy script: this, archivePath: archivePath, deployMode: deployMode - } - - } - - return this - """ - } - } diff --git a/test/groovy/PipelineExecuteTest.groovy b/test/groovy/PipelineExecuteTest.groovy index 62771b419..782f33679 100644 --- a/test/groovy/PipelineExecuteTest.groovy +++ b/test/groovy/PipelineExecuteTest.groovy @@ -3,13 +3,16 @@ import util.JenkinsConfigRule import util.JenkinsSetupRule import org.junit.rules.TemporaryFolder + +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 -class PipelineExecuteTest extends PiperTestBase { +class PipelineExecuteTest extends BasePipelineTest { private ExpectedException thrown = new ExpectedException().none() @@ -22,6 +25,8 @@ class PipelineExecuteTest extends PiperTestBase { def checkoutParameters = [:] def load + def pipelineExecuteScript + @Before void init() { @@ -38,13 +43,14 @@ class PipelineExecuteTest extends PiperTestBase { }) helper.registerAllowedMethod('load', [String], { s -> load = s }) + pipelineExecuteScript = loadScript("pipelineExecute.groovy").pipelineExecute } @Test void straightForwardTest() { - withPipeline(defaultPipeline()).execute() + pipelineExecuteScript.call(repoUrl: "https://test.com/myRepo.git") assert load == "Jenkinsfile" assert checkoutParameters.branch == 'master' assert checkoutParameters.repoUrl == "https://test.com/myRepo.git" @@ -56,7 +62,11 @@ class PipelineExecuteTest extends PiperTestBase { @Test void parameterizeTest() { - withPipeline(parameterizePipeline()).execute() + pipelineExecuteScript.call(repoUrl: "https://test.com/anotherRepo.git", + branch: 'feature', + path: 'path/to/Jenkinsfile', + credentialsId: 'abcd1234') + assert load == "path/to/Jenkinsfile" assert checkoutParameters.branch == 'feature' assert checkoutParameters.repoUrl == "https://test.com/anotherRepo.git" @@ -71,50 +81,6 @@ class PipelineExecuteTest extends PiperTestBase { thrown.expect(Exception) thrown.expectMessage("ERROR - NO VALUE AVAILABLE FOR repoUrl") - withPipeline(noRepoUrlPipeline()).execute() - - } - - - private defaultPipeline() { - return """ - @Library('piper-library-os') - - execute() { - - pipelineExecute repoUrl: "https://test.com/myRepo.git" - - } - - return this - """ - } - - private parameterizePipeline() { - return """ - @Library('piper-library-os') - - execute() { - - pipelineExecute repoUrl: "https://test.com/anotherRepo.git", branch: 'feature', path: 'path/to/Jenkinsfile', credentialsId: 'abcd1234' - - } - - return this - """ - } - - private noRepoUrlPipeline() { - return """ - @Library('piper-library-os') - - execute() { - - pipelineExecute() - - } - - return this - """ + pipelineExecuteScript.call() } } diff --git a/test/groovy/PiperTestBase.groovy b/test/groovy/PiperTestBase.groovy deleted file mode 100644 index 14caf7105..000000000 --- a/test/groovy/PiperTestBase.groovy +++ /dev/null @@ -1,30 +0,0 @@ -import com.lesfurets.jenkins.unit.BasePipelineTest - -import org.yaml.snakeyaml.Yaml - -import static ProjectSource.projectSource -import static com.lesfurets.jenkins.unit.global.lib.LibraryConfiguration.library - -import org.junit.Rule -import org.junit.rules.TemporaryFolder - -public class PiperTestBase extends BasePipelineTest { - - @Rule - public TemporaryFolder pipelineFolder = new TemporaryFolder() - - private File pipeline - - void setUp() { - - super.setUp() - - pipeline = pipelineFolder.newFile() - - } - - protected withPipeline(p) { - pipeline << p - loadScript(pipeline.toURI().getPath()) - } -} diff --git a/test/groovy/SetupCommonPipelineEnvironmentTest.groovy b/test/groovy/SetupCommonPipelineEnvironmentTest.groovy index ed087f7e6..0f4b9498d 100644 --- a/test/groovy/SetupCommonPipelineEnvironmentTest.groovy +++ b/test/groovy/SetupCommonPipelineEnvironmentTest.groovy @@ -3,15 +3,21 @@ import org.junit.Rule import org.junit.Test import org.yaml.snakeyaml.Yaml +import com.lesfurets.jenkins.unit.BasePipelineTest + import util.JenkinsSetupRule import static org.junit.Assert.assertEquals import static org.junit.Assert.assertNotNull -class SetupCommonPipelineEnvironmentTest extends PiperTestBase { +class SetupCommonPipelineEnvironmentTest extends BasePipelineTest { def usedConfigFile + def setupCommonPipelineEnvironmentScript + + def commonPipelineEnvironment + @Rule public JenkinsSetupRule jsr = new JenkinsSetupRule(this) @@ -33,16 +39,18 @@ class SetupCommonPipelineEnvironmentTest extends PiperTestBase { helper.registerAllowedMethod("fileExists", [String], { String path -> return path.endsWith('.pipeline/config.yml') }) + + setupCommonPipelineEnvironmentScript = loadScript("setupCommonPipelineEnvironment.groovy").setupCommonPipelineEnvironment + commonPipelineEnvironment = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment } @Test void testIsConfigurationAvailable() throws Exception { - def script = loadScript("test/resources/pipelines/setupCommonPipelineEnvironmentTest/loadConfiguration.groovy") - script.execute() + setupCommonPipelineEnvironmentScript.call(script: [commonPipelineEnvironment: commonPipelineEnvironment]) assertEquals('.pipeline/config.yml', usedConfigFile) - assertNotNull(script.commonPipelineEnvironment.configuration) - assertEquals('develop', script.commonPipelineEnvironment.configuration.general.productiveBranch) - assertEquals('my-maven-docker', script.commonPipelineEnvironment.configuration.steps.mavenExecute.dockerImage) + assertNotNull(commonPipelineEnvironment.configuration) + assertEquals('develop', commonPipelineEnvironment.configuration.general.productiveBranch) + assertEquals('my-maven-docker', commonPipelineEnvironment.configuration.steps.mavenExecute.dockerImage) } } diff --git a/test/groovy/ToolValidateTest.groovy b/test/groovy/ToolValidateTest.groovy index 30b386363..973f2dc59 100644 --- a/test/groovy/ToolValidateTest.groovy +++ b/test/groovy/ToolValidateTest.groovy @@ -7,11 +7,13 @@ import org.junit.rules.ExpectedException import org.junit.rules.RuleChain import org.junit.rules.TemporaryFolder +import com.lesfurets.jenkins.unit.BasePipelineTest + import util.JenkinsConfigRule import util.JenkinsLoggingRule import util.JenkinsSetupRule -class ToolValidateTest extends PiperTestBase { +class ToolValidateTest extends BasePipelineTest { private ExpectedException thrown = new ExpectedException().none() private TemporaryFolder tmp = new TemporaryFolder() @@ -27,13 +29,12 @@ class ToolValidateTest extends PiperTestBase { .around(jcr) private notEmptyDir - private script + + def toolValidateScript @Before void init() { - script = withPipeline(defaultPipeline()) - notEmptyDir = tmp.newFolder('notEmptyDir') def path = "${notEmptyDir.getAbsolutePath()}${File.separator}test.txt" File file = new File(path) @@ -41,8 +42,7 @@ class ToolValidateTest extends PiperTestBase { binding.setVariable('JAVA_HOME', notEmptyDir.getAbsolutePath()) - binding.setVariable('home', notEmptyDir.getAbsolutePath()) - + toolValidateScript = loadScript("toolValidate.groovy").toolValidate } @@ -52,10 +52,7 @@ class ToolValidateTest extends PiperTestBase { thrown.expect(IllegalArgumentException) thrown.expectMessage("The parameter 'home' can not be null or empty.") - binding.setVariable('tool', 'java') - binding.setVariable('home', null) - - script.execute() + toolValidateScript.call(tool: 'java', home: null) } @Test @@ -64,10 +61,7 @@ class ToolValidateTest extends PiperTestBase { thrown.expect(IllegalArgumentException) thrown.expectMessage("The parameter 'home' can not be null or empty.") - binding.setVariable('tool', 'java') - binding.setVariable('home', '') - - script.execute() + toolValidateScript.call(tool: 'java', home: '') } @Test @@ -76,9 +70,7 @@ class ToolValidateTest extends PiperTestBase { thrown.expect(IllegalArgumentException) thrown.expectMessage("The parameter 'tool' can not be null or empty.") - binding.setVariable('tool', null) - - script.execute() + toolValidateScript.call(tool: null) } @Test @@ -87,9 +79,7 @@ class ToolValidateTest extends PiperTestBase { thrown.expect(IllegalArgumentException) thrown.expectMessage("The parameter 'tool' can not be null or empty.") - binding.setVariable('tool', '') - - script.execute() + toolValidateScript.call(tool: '') } @Test @@ -98,9 +88,7 @@ class ToolValidateTest extends PiperTestBase { thrown.expect(AbortException) thrown.expectMessage("The tool 'test' is not supported.") - binding.setVariable('tool', 'test') - - script.execute() + toolValidateScript.call(tool: 'test', home: notEmptyDir.getAbsolutePath()) } @Test @@ -110,9 +98,8 @@ class ToolValidateTest extends PiperTestBase { thrown.expectMessage('The validation of Java failed.') helper.registerAllowedMethod('sh', [Map], { Map m -> getNoVersion(m) }) - binding.setVariable('tool', 'java') - script.execute() + toolValidateScript.call(tool: 'java', home: notEmptyDir.getAbsolutePath()) } @Test @@ -122,9 +109,8 @@ class ToolValidateTest extends PiperTestBase { thrown.expectMessage('The validation of SAP Multitarget Application Archive Builder failed.') helper.registerAllowedMethod('sh', [Map], { Map m -> getNoVersion(m) }) - binding.setVariable('tool', 'mta') - script.execute() + toolValidateScript.call(tool: 'mta', home: notEmptyDir.getAbsolutePath()) } @Test @@ -134,9 +120,8 @@ class ToolValidateTest extends PiperTestBase { thrown.expectMessage('The validation of SAP Cloud Platform Console Client failed.') helper.registerAllowedMethod('sh', [Map], { Map m -> getNoVersion(m) }) - binding.setVariable('tool', 'neo') - script.execute() + toolValidateScript.call(tool: 'neo', home: notEmptyDir.getAbsolutePath()) } @Test @@ -146,7 +131,8 @@ class ToolValidateTest extends PiperTestBase { thrown.expectMessage('The validation of Change Management Command Line Interface failed.') helper.registerAllowedMethod('sh', [Map], { Map m -> getNoVersion(m) }) - binding.setVariable('tool', 'cm') + + toolValidateScript.call(tool: 'cm', home: notEmptyDir.getAbsolutePath()) script.execute() } @@ -158,9 +144,8 @@ class ToolValidateTest extends PiperTestBase { thrown.expectMessage('The installed version of Java is 1.7.0.') helper.registerAllowedMethod('sh', [Map], { Map m -> getIncompatibleVersion(m) }) - binding.setVariable('tool', 'java') - script.execute() + toolValidateScript.call(tool: 'java', home: notEmptyDir.getAbsolutePath()) } @Test @@ -170,9 +155,8 @@ class ToolValidateTest extends PiperTestBase { thrown.expectMessage('The installed version of SAP Multitarget Application Archive Builder is 1.0.5.') helper.registerAllowedMethod('sh', [Map], { Map m -> getIncompatibleVersion(m) }) - binding.setVariable('tool', 'mta') - script.execute() + toolValidateScript.call(tool: 'mta', home: notEmptyDir.getAbsolutePath()) } @Test @@ -182,9 +166,8 @@ class ToolValidateTest extends PiperTestBase { thrown.expectMessage('The installed version of SAP Cloud Platform Console Client is 1.126.51.') helper.registerAllowedMethod('sh', [Map], { Map m -> getIncompatibleVersion(m) }) - binding.setVariable('tool', 'neo') - script.execute() + toolValidateScript.call(tool: 'neo', home: notEmptyDir.getAbsolutePath()) } @Test @@ -196,16 +179,15 @@ class ToolValidateTest extends PiperTestBase { helper.registerAllowedMethod('sh', [Map], { Map m -> getIncompatibleVersion(m) }) binding.setVariable('tool', 'cm') - script.execute() + toolValidateScript.call(tool: 'cm', home: notEmptyDir.getAbsolutePath()) } @Test void validateJavaTest() { helper.registerAllowedMethod('sh', [Map], { Map m -> getVersion(m) }) - binding.setVariable('tool', 'java') - script.execute() + toolValidateScript.call(tool: 'java', home: notEmptyDir.getAbsolutePath()) assert jlr.log.contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') assert jlr.log.contains('[INFO] Validating Java version 1.8.0 or compatible version.') @@ -217,9 +199,8 @@ class ToolValidateTest extends PiperTestBase { void validateMtaTest() { helper.registerAllowedMethod('sh', [Map], { Map m -> getVersion(m) }) - binding.setVariable('tool', 'mta') - script.execute() + toolValidateScript.call(tool: 'mta', home: notEmptyDir.getAbsolutePath()) assert jlr.log.contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') assert jlr.log.contains('[INFO] Validating SAP Multitarget Application Archive Builder version 1.0.6 or compatible version.') @@ -231,9 +212,8 @@ class ToolValidateTest extends PiperTestBase { void validateNeoTest() { helper.registerAllowedMethod('sh', [Map], { Map m -> getVersion(m) }) - binding.setVariable('tool', 'neo') - script.execute() + toolValidateScript.call(tool: 'neo', home: notEmptyDir.getAbsolutePath()) assert jlr.log.contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') assert jlr.log.contains('[INFO] Validating SAP Cloud Platform Console Client version 3.39.10 or compatible version.') @@ -245,9 +225,8 @@ class ToolValidateTest extends PiperTestBase { void validateCmTest() { helper.registerAllowedMethod('sh', [Map], { Map m -> getVersion(m) }) - binding.setVariable('tool', 'cm') - script.execute() + toolValidateScript.call(tool: 'cm', home: notEmptyDir.getAbsolutePath()) assert jlr.log.contains('--- BEGIN LIBRARY STEP: toolValidate.groovy ---') assert jlr.log.contains('[INFO] Validating Change Management Command Line Interface version 0.0.1 or compatible version.') @@ -255,23 +234,6 @@ class ToolValidateTest extends PiperTestBase { assert jlr.log.contains('--- END LIBRARY STEP: toolValidate.groovy ---') } - - private defaultPipeline(){ - return """ - @Library('piper-library-os') - - execute() { - - node() { - - toolValidate tool: tool, home: home - } - } - - return this - """ - } - private getNoVersion(Map m) { throw new AbortException('script returned exit code 127') } diff --git a/test/resources/pipelines/dockerExecuteTest/executeInsideDocker.groovy b/test/resources/pipelines/dockerExecuteTest/executeInsideDocker.groovy deleted file mode 100644 index 563628a10..000000000 --- a/test/resources/pipelines/dockerExecuteTest/executeInsideDocker.groovy +++ /dev/null @@ -1,11 +0,0 @@ -@Library('piper-library-os') - -execute() { - node() { - dockerExecute(script: this, dockerImage: 'maven:3.5-jdk-8-alpine') { - echo 'Inside Docker' - } - } -} - -return this diff --git a/test/resources/pipelines/dockerExecuteTest/executeInsideDockerWithParameters.groovy b/test/resources/pipelines/dockerExecuteTest/executeInsideDockerWithParameters.groovy deleted file mode 100644 index 9aa4b6366..000000000 --- a/test/resources/pipelines/dockerExecuteTest/executeInsideDockerWithParameters.groovy +++ /dev/null @@ -1,11 +0,0 @@ -@Library('piper-library-os') - -execute() { - node() { - dockerExecute(script: this, dockerImage: 'maven:3.5-jdk-8-alpine', dockerOptions: '-it', dockerVolumeBind: ['my_vol': '/my_vol'], dockerEnvVars: ['http_proxy': 'http://proxy:8000']) { - echo 'Inside Docker' - } - } -} - -return this diff --git a/test/resources/pipelines/mavenExecuteTest/executeBasicMavenCommand.groovy b/test/resources/pipelines/mavenExecuteTest/executeBasicMavenCommand.groovy deleted file mode 100644 index 58a54381a..000000000 --- a/test/resources/pipelines/mavenExecuteTest/executeBasicMavenCommand.groovy +++ /dev/null @@ -1,9 +0,0 @@ -@Library('piper-library-os') - -execute() { - node() { - mavenExecute script: this, goals: 'clean install' - } -} - -return this diff --git a/test/resources/pipelines/mavenExecuteTest/executeMavenCommandWithParameters.groovy b/test/resources/pipelines/mavenExecuteTest/executeMavenCommandWithParameters.groovy deleted file mode 100644 index e7d1ba483..000000000 --- a/test/resources/pipelines/mavenExecuteTest/executeMavenCommandWithParameters.groovy +++ /dev/null @@ -1,21 +0,0 @@ -@Library('piper-library-os') - -execute() { - node() { - mavenExecute( - script: this, - dockerImage: 'maven:3.5-jdk-8-alpine', - goals: 'clean install', - globalSettingsFile: 'globalSettingsFile.xml', - projectSettingsFile: 'projectSettingsFile.xml', - pomPath: 'pom.xml', - flags: '-o', - m2Path: 'm2Path', - defines: '-Dmaven.tests.skip=true' - ) - } -} - -return this - - diff --git a/test/resources/pipelines/setupCommonPipelineEnvironmentTest/loadConfiguration.groovy b/test/resources/pipelines/setupCommonPipelineEnvironmentTest/loadConfiguration.groovy deleted file mode 100644 index 54ef75bc0..000000000 --- a/test/resources/pipelines/setupCommonPipelineEnvironmentTest/loadConfiguration.groovy +++ /dev/null @@ -1,11 +0,0 @@ -@Library('piper-library-os') - -execute() { - node() { - setupCommonPipelineEnvironment script:this - } -} - -return this - - From 5f1e398f07cffeb2e5717e7744595fa8073ee7a1 Mon Sep 17 00:00:00 2001 From: Christoph Szymanski Date: Wed, 24 Jan 2018 12:07:26 +0100 Subject: [PATCH 20/32] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 349fac776..4093797c9 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ 4.0.0 com.sap.cp.jenkins jenkins-library - 0.0.1 + 0.1 SAP CP Piper Library Shared library containing steps and utilities to set up continuous deployment processes for SAP technologies. From ac14b8b00e151c6e3d72a95c8a7cc0bccc4feb3e Mon Sep 17 00:00:00 2001 From: Christoph Szymanski Date: Wed, 24 Jan 2018 12:08:52 +0100 Subject: [PATCH 21/32] Bump Version to 0.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4093797c9..b0725ab81 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ 4.0.0 com.sap.cp.jenkins jenkins-library - 0.1 + 0.2 SAP CP Piper Library Shared library containing steps and utilities to set up continuous deployment processes for SAP technologies. From 58d3907093cfbb3b099351516068414cbea009d0 Mon Sep 17 00:00:00 2001 From: Oliver Feldmann Date: Fri, 12 Jan 2018 13:02:48 +0100 Subject: [PATCH 22/32] Use fileExists to check whether archivePath really exists When running on a slave we have to use the Pipeline method fileExists, using the File class' exist on the absolute path fails. The neo deployment uses the relative path as well. The fileExists method is mocked with LesFurets. --- test/groovy/NeoDeploymentTest.groovy | 4 ++++ vars/neoDeploy.groovy | 18 ++++++------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index eeced3418..7b1af4366 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -43,6 +43,10 @@ class NeoDeploymentTest extends BasePipelineTest { propertiesFilePath = "${tmp.getRoot().toURI().getPath()}workspace/config.properties" helper.registerAllowedMethod('error', [String], { s -> throw new AbortException(s) }) + helper.registerAllowedMethod('fileExists', [String], { s -> + f = new File(s) + return f.exists() + }) helper.registerAllowedMethod('usernamePassword', [Map], { m -> return m }) helper.registerAllowedMethod('withCredentials', [List, Closure], { l, c -> if(l[0].credentialsId == 'myCredentialsId') { diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index 35e718019..f458e7149 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -11,11 +11,8 @@ def call(parameters = [:]) { script = [commonPipelineEnvironment: commonPipelineEnvironment] } - def archivePath = new File(utils.getMandatoryParameter(parameters, 'archivePath', null)) - if (!archivePath.isAbsolute()) { - archivePath = new File(pwd(), archivePath.getPath()) - } - if (!archivePath.exists()){ + def archivePath = utils.getMandatoryParameter(parameters, 'archivePath', null) + if (!fileExists(archivePath)){ error "Archive cannot be found with parameter archivePath: '${archivePath}'." } @@ -34,11 +31,8 @@ def call(parameters = [:]) { } } if (deployMode == 'warPropertiesFile') { - propertiesFile = new File(utils.getMandatoryParameter(parameters, 'propertiesFile', null)) - if (!propertiesFile.isAbsolute()) { - propertiesFile = new File(pwd(), propertiesFile.getPath()) - } - if (!propertiesFile.exists()){ + propertiesFile = utils.getMandatoryParameter(parameters, 'propertiesFile', null) + if (!fileExists(propertiesFile)){ error "Properties file cannot be found with parameter propertiesFile: '${propertiesFile}'." } } @@ -84,7 +78,7 @@ def call(parameters = [:]) { def commonDeployParams = """--user '${username}' \ --password '${password}' \ - --source "${archivePath.getAbsolutePath()}" \ + --source "${archivePath}" \ """ if (deployMode == 'mta') { @@ -114,7 +108,7 @@ def call(parameters = [:]) { sh """#!/bin/bash "${neoExecutable}" ${warAction} \ ${commonDeployParams} \ - ${propertiesFile.getAbsolutePath()} + ${propertiesFile} """ } } From ec9895ec3ef46002ec20600cfb56d7fbda1af150 Mon Sep 17 00:00:00 2001 From: Oliver Feldmann Date: Thu, 18 Jan 2018 10:40:18 +0100 Subject: [PATCH 23/32] Improve fileExists mock Before this commit the fileExists mock was not doing the same as the real fileExists method. To stay close to reality we changed it construct the absolute path and check for that when the fileExists method is called. Refactored to archiveName instead of archivePath, as this makes more sense now. --- test/groovy/NeoDeploymentTest.groovy | 99 ++++++++++++++-------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 7b1af4366..21068c194 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -28,9 +28,12 @@ class NeoDeploymentTest extends BasePipelineTest { .around(jlr) .around(jscr) .around(new JenkinsConfigRule(this)) - def archivePath - def warArchivePath - def propertiesFilePath + + def workspacePath + def warArchiveName + def propertiesFileName + def archiveName + def neoDeployScript def cpe @@ -38,15 +41,13 @@ class NeoDeploymentTest extends BasePipelineTest { @Before void init() { - archivePath = "${tmp.newFolder("workspace").toURI().getPath()}archiveName.mtar" - warArchivePath = "${tmp.getRoot().toURI().getPath()}workspace/warArchive.war" - propertiesFilePath = "${tmp.getRoot().toURI().getPath()}workspace/config.properties" + workspacePath = "${tmp.newFolder("workspace").toURI().getPath()}" + warArchiveName = 'warArchive.war' + propertiesFileName = 'config.properties' + archiveName = "archive.mtar" helper.registerAllowedMethod('error', [String], { s -> throw new AbortException(s) }) - helper.registerAllowedMethod('fileExists', [String], { s -> - f = new File(s) - return f.exists() - }) + 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 -> if(l[0].credentialsId == 'myCredentialsId') { @@ -79,13 +80,13 @@ class NeoDeploymentTest extends BasePipelineTest { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' - new File(archivePath) << "dummy archive" + new File(workspacePath, archiveName) << "dummy archive" cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: archivePath, + archivePath: archiveName, neoCredentialsId: 'myCredentialsId' ) @@ -101,7 +102,7 @@ class NeoDeploymentTest extends BasePipelineTest { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' - new File(archivePath) << "dummy archive" + new File(workspacePath, archiveName) << "dummy archive" thrown.expect(MissingPropertyException) @@ -109,7 +110,7 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: archivePath, + archivePath: archiveName, neoCredentialsId: 'badCredentialsId' ) } @@ -120,13 +121,13 @@ class NeoDeploymentTest extends BasePipelineTest { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' - new File(archivePath) << "dummy archive" + new File(workspacePath, archiveName) << "dummy archive" cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: archivePath + archivePath: archiveName ) assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ @@ -138,13 +139,13 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void neoHomeNotSetTest() { - new File(archivePath) << "dummy archive" + new File(workspacePath, archiveName) << "dummy archive" cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: archivePath + archivePath: archiveName ) assert jscr.shell[0] =~ /#!\/bin\/bash "neo" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ @@ -156,13 +157,13 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void neoHomeAsParameterTest() { - new File(archivePath) << "dummy archive" + new File(workspacePath, archiveName) << "dummy archive" cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: archivePath, + archivePath: archiveName, neoCredentialsId: 'myCredentialsId', neoHome: '/etc/neo' ) @@ -197,30 +198,30 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: archivePath) + archivePath: archiveName) } @Test void scriptNotProvidedTest() { - new File(archivePath) << "dummy archive" + new File(workspacePath, archiveName) << "dummy archive" thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR deployHost') - neoDeployScript.call(archivePath: archivePath) + neoDeployScript.call(archivePath: archiveName) } @Test void mtaDeployModeTest() { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' - new File(archivePath) << "dummy archive" + new File(workspacePath, archiveName) << "dummy archive" cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - neoDeployScript.call(script: [commonPipelineEnvironment: cpe], archivePath: archivePath, deployMode: 'mta') + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], archivePath: archiveName, deployMode: 'mta') assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ @@ -230,7 +231,7 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void warFileParamsDeployModeTest() { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' - new File(warArchivePath) << "dummy war archive" + new File(workspacePath, warArchiveName) << "dummy war archive" cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') @@ -246,7 +247,7 @@ class NeoDeploymentTest extends BasePipelineTest { deployMode: 'warParams', vmSize: 'lite', warAction: 'deploy', - archivePath: warArchivePath) + archivePath: warArchiveName) assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -255,13 +256,13 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void warFileParamsDeployModeRollingUpdateTest() { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' - new File(warArchivePath) << "dummy war archive" + new File(workspacePath, warArchiveName) << "dummy war archive" cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, deployMode: 'warParams', applicationName: 'testApp', runtime: 'neo-javaee6-wp', @@ -276,13 +277,13 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void warPropertiesFileDeployModeTest() { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' - new File(warArchivePath) << "dummy war archive" - new File(propertiesFilePath) << "dummy properties file" + new File(workspacePath, warArchiveName) << "dummy war archive" + new File(workspacePath, propertiesFileName) << "dummy properties file" neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, deployMode: 'warPropertiesFile', - propertiesFile: propertiesFilePath, + propertiesFile: propertiesFileName, applicationName: 'testApp', runtime: 'neo-javaee6-wp', runtimeVersion: '2.125', @@ -296,13 +297,13 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void warPropertiesFileDeployModeRollingUpdateTest() { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' - new File(warArchivePath) << "dummy war archive" - new File(propertiesFilePath) << "dummy properties file" + new File(workspacePath, warArchiveName) << "dummy war archive" + new File(workspacePath, propertiesFileName) << "dummy properties file" neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, deployMode: 'warPropertiesFile', - propertiesFile: propertiesFilePath, + propertiesFile: propertiesFileName, applicationName: 'testApp', runtime: 'neo-javaee6-wp', runtimeVersion: '2.125', @@ -315,7 +316,7 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void applicationNameNotProvidedTest() { - new File(warArchivePath) << "dummy war archive" + new File(workspacePath, warArchiveName) << "dummy war archive" thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR applicationName') @@ -324,7 +325,7 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, deployMode: 'warParams', runtime: 'neo-javaee6-wp', runtimeVersion: '2.125' @@ -333,7 +334,7 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void runtimeNotProvidedTest() { - new File(warArchivePath) << "dummy war archive" + new File(workspacePath, warArchiveName) << "dummy war archive" thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtime') @@ -342,7 +343,7 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, applicationName: 'testApp', deployMode: 'warParams', runtimeVersion: '2.125') @@ -350,7 +351,7 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void runtimeVersionNotProvidedTest() { - new File(warArchivePath) << "dummy war archive" + new File(workspacePath, warArchiveName) << "dummy war archive" thrown.expect(Exception) thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR runtimeVersion') @@ -359,7 +360,7 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, applicationName: 'testApp', deployMode: 'warParams', runtime: 'neo-javaee6-wp') @@ -367,7 +368,7 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void illegalDeployModeTest() { - new File(warArchivePath) << "dummy war archive" + new File(workspacePath, warArchiveName) << "dummy war archive" thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid deployMode = 'illegalMode'. Valid 'deployMode' values are: 'mta', 'warParams' and 'warPropertiesFile'") @@ -376,7 +377,7 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, deployMode: 'illegalMode', applicationName: 'testApp', runtime: 'neo-javaee6-wp', @@ -387,7 +388,7 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void illegalVMSizeTest() { - new File(warArchivePath) << "dummy war archive" + new File(workspacePath, warArchiveName) << "dummy war archive" thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid vmSize = 'illegalVM'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") @@ -396,7 +397,7 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, deployMode: 'warParams', applicationName: 'testApp', runtime: 'neo-javaee6-wp', @@ -407,7 +408,7 @@ class NeoDeploymentTest extends BasePipelineTest { @Test void illegalWARActionTest() { - new File(warArchivePath) << "dummy war archive" + new File(workspacePath, warArchiveName) << "dummy war archive" thrown.expect(Exception) thrown.expectMessage("[neoDeploy] Invalid warAction = 'illegalWARAction'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") @@ -416,7 +417,7 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') neoDeployScript.call(script: [commonPipelineEnvironment: cpe], - archivePath: warArchivePath, + archivePath: warArchiveName, deployMode: 'warParams', applicationName: 'testApp', runtime: 'neo-javaee6-wp', From e2676223091cfc159a3b85ea6ea034f500360d60 Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Mon, 11 Dec 2017 13:55:07 +0100 Subject: [PATCH 24/32] [refactor/streamline ]Use CPE is case the script is not available --- vars/neoDeploy.groovy | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index f458e7149..ebb4c8b75 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -6,10 +6,8 @@ def call(parameters = [:]) { handlePipelineStepErrors (stepName: 'neoDeploy', stepParameters: parameters) { def utils = new Utils() - def script = parameters.script - if (script == null){ - script = [commonPipelineEnvironment: commonPipelineEnvironment] - } + + def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment] def archivePath = utils.getMandatoryParameter(parameters, 'archivePath', null) if (!fileExists(archivePath)){ From 200181631894702d66045e2a279695331ca72f4d Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Thu, 25 Jan 2018 16:41:22 +0100 Subject: [PATCH 25/32] Remove unused variables inside test --- test/groovy/NeoDeploymentTest.groovy | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 21068c194..c0314027e 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -236,10 +236,6 @@ class NeoDeploymentTest extends BasePipelineTest { cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') - def appName = 'testApp' - def runtime = 'neo-javaee6-wp' - def runtimeVersion = '2.125' - neoDeployScript.call(script: [commonPipelineEnvironment: cpe], applicationName: 'testApp', runtime: 'neo-javaee6-wp', From 1ff46861e02647a98e2166481e7090c2918d30bb Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Mon, 11 Dec 2017 11:15:51 +0100 Subject: [PATCH 26/32] Introduce new config framework into neoDeploy --- resources/default_pipeline_environment.yml | 6 +- test/groovy/NeoDeploymentTest.groovy | 60 ++++++++- vars/neoDeploy.groovy | 143 +++++++++++++++------ 3 files changed, 162 insertions(+), 47 deletions(-) diff --git a/resources/default_pipeline_environment.yml b/resources/default_pipeline_environment.yml index 1bab1b628..0a89880df 100644 --- a/resources/default_pipeline_environment.yml +++ b/resources/default_pipeline_environment.yml @@ -8,4 +8,8 @@ steps: dockerImage: 'maven:3.5-jdk-7' influxWriteData: influxServer: 'jenkins' - + neoDeploy: + deployMode: 'mta' + warAction: 'deploy' + vmSize: 'lite' + neoCredentialsId: 'CI_CREDENTIALS_ID' diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index c0314027e..1c67c6696 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -1,4 +1,5 @@ import hudson.AbortException + import org.junit.rules.TemporaryFolder import com.lesfurets.jenkins.unit.BasePipelineTest @@ -76,7 +77,7 @@ class NeoDeploymentTest extends BasePipelineTest { @Test - void straightForwardTest() { + void straightForwardTestConfigViaConfigProperties() { binding.getVariable('env')['NEO_HOME'] = '/opt/neo' @@ -96,6 +97,53 @@ class NeoDeploymentTest extends BasePipelineTest { } + @Test + void straightForwardTestConfigViaConfiguration() { + + binding.getVariable('env')['NEO_HOME'] = '/opt/neo' + + new File(workspacePath, archiveName) << "dummy archive" + + cpe.configuration.put('steps', [neoDeploy: [host: 'test.deploy.host.com', + account: 'trialuser123']]) + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: archiveName, + neoCredentialsId: 'myCredentialsId' +) + + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ + + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") + + } + + @Test + void straightForwardTestConfigViaConfigurationAndViaConfigProperties() { + + //configuration via configurationFramekwork superseds. + binding.getVariable('env')['NEO_HOME'] = '/opt/neo' + + new File(workspacePath, archiveName) << "dummy archive" + + + cpe.setConfigProperty('DEPLOY_HOST', 'configProperties.deploy.host.com') + cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'configPropsUser123') + + cpe.configuration.put('steps', [neoDeploy: [host: 'configuration-frwk.deploy.host.com', + account: 'configurationFrwkUser123']]) + + neoDeployScript.call(script: [commonPipelineEnvironment: cpe], + archivePath: archiveName, + neoCredentialsId: 'myCredentialsId' + ) + + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'configuration-frwk\.deploy\.host\.com' --account 'configurationFrwkUser123' --synchronous/ + + assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") + + } + @Test void badCredentialsIdTest() { @@ -105,6 +153,7 @@ class NeoDeploymentTest extends BasePipelineTest { new File(workspacePath, archiveName) << "dummy archive" thrown.expect(MissingPropertyException) + thrown.expectMessage('No such property: username') cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') @@ -169,9 +218,6 @@ class NeoDeploymentTest extends BasePipelineTest { ) assert jscr.shell[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ - - assert jlr.log.contains("[neoDeploy] Neo executable \"/etc/neo/tools/neo.sh\" retrieved from parameters.") - } @@ -179,7 +225,7 @@ class NeoDeploymentTest extends BasePipelineTest { void archiveNotProvidedTest() { thrown.expect(Exception) - thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR archivePath') + thrown.expectMessage('Archive path not configured (parameter "archivePath").') cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') @@ -192,7 +238,7 @@ class NeoDeploymentTest extends BasePipelineTest { void wrongArchivePathProvidedTest() { thrown.expect(AbortException) - thrown.expectMessage("Archive cannot be found with parameter archivePath: '") + thrown.expectMessage("Archive cannot be found") cpe.setConfigProperty('DEPLOY_HOST', 'test.deploy.host.com') cpe.setConfigProperty('CI_DEPLOY_ACCOUNT', 'trialuser123') @@ -208,7 +254,7 @@ class NeoDeploymentTest extends BasePipelineTest { new File(workspacePath, archiveName) << "dummy archive" thrown.expect(Exception) - thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR deployHost') + thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR host') neoDeployScript.call(archivePath: archiveName) } diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index ebb4c8b75..6a79a4322 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -1,72 +1,137 @@ import com.sap.piper.Utils - +import com.sap.piper.ConfigurationLoader +import com.sap.piper.ConfigurationMerger +import com.sap.piper.ConfigurationType def call(parameters = [:]) { - handlePipelineStepErrors (stepName: 'neoDeploy', stepParameters: parameters) { + def stepName = 'neoDeploy' - def utils = new Utils() + List parameterKeys = [ + 'applicationName', + 'archivePath', + 'account', + 'deployMode', + 'dockerEnvVars', + 'dockerImage', + 'dockerOptions', + 'host', + 'neoCredentialsId', + 'neoHome', + 'propertiesFile', + 'runtime', + 'runtimeVersion', + 'vmSize', + 'warAction' + ] + + List stepConfigurationKeys = [ + 'account', + 'dockerEnvVars', + 'dockerImage', + 'dockerOptions', + 'host', + 'neoCredentialsId', + 'neoHome' + ] + + handlePipelineStepErrors (stepName: stepName, stepParameters: parameters) { def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment] - def archivePath = utils.getMandatoryParameter(parameters, 'archivePath', null) - if (!fileExists(archivePath)){ - error "Archive cannot be found with parameter archivePath: '${archivePath}'." + def utils = new Utils() + + prepareDefaultValues script: script + + final Map stepConfiguration = [:] + + // Backward compatibility: ensure old configuration is taken into account + // The old configuration in not stage / step specific + + def defaultDeployHost = script.commonPipelineEnvironment.getConfigProperty('DEPLOY_HOST') + if(defaultDeployHost) { + echo "[WARNING][${stepName}] A deprecated configuration framework is used for configuring parameter 'DEPLOY_HOST'. This configuration framework will be removed in future versions." + stepConfiguration.put('host', defaultDeployHost) } - def deployMode = utils.getMandatoryParameter(parameters, 'deployMode', 'mta') + def defaultDeployAccount = script.commonPipelineEnvironment.getConfigProperty('CI_DEPLOY_ACCOUNT') + if(defaultDeployAccount) { + echo "[WARNING][${stepName}] A deprecated configuration framework is used for configuring parameter 'DEPLOY_ACCOUNT'. This configuration framekwork will be removed in future versions." + stepConfiguration.put('account', defaultDeployAccount) + } + + if(parameters.DEPLOY_HOST && !parameters.host) { + echo "[WARNING][${stepName}] Deprecated parameter 'DEPLOY_HOST' is used. This will not work anymore in future versions. Use parameter 'host' instead." + parameters.put('host', parameters.DEPLOY_HOST) + } + + if(parameters.CI_DEPLOY_ACCOUNT && !parameters.account) { + echo "[WARNING][${stepName}] Deprecated parameter 'CI_DEPLOY_ACCOUNT' is used. This will not work anymore in future versions. Use parameter 'account' instead." + parameters.put('account', parameters.CI_DEPLOY_ACCOUNT) + } + + // Backward compatibility end + + stepConfiguration.putAll(ConfigurationLoader.stepConfiguration(script, stepName)) + + Map configuration = ConfigurationMerger.merge(parameters, parameterKeys, + stepConfiguration, stepConfigurationKeys, + ConfigurationLoader.defaultStepConfiguration(script, stepName)) + + def archivePath = configuration.archivePath + if(archivePath?.trim()) { + if (!fileExists(archivePath)) { + error "Archive cannot be found with parameter archivePath: '${archivePath}'." + } + } else { + error "Archive path not configured (parameter \"archivePath\")." + } + + def deployHost + def deployAccount + def credentialsId = configuration.get('neoCredentialsId', '') + def deployMode = configuration.deployMode + def warAction + def propertiesFile + def applicationName + def runtime + def runtimeVersion + def vmSize if (deployMode != 'mta' && deployMode != 'warParams' && deployMode != 'warPropertiesFile') { throw new Exception("[neoDeploy] Invalid deployMode = '${deployMode}'. Valid 'deployMode' values are: 'mta', 'warParams' and 'warPropertiesFile'") } - def propertiesFile - def warAction if (deployMode == 'warPropertiesFile' || deployMode == 'warParams') { - warAction = utils.getMandatoryParameter(parameters, 'warAction', 'deploy') + warAction = utils.getMandatoryParameter(configuration, 'warAction') if (warAction != 'deploy' && warAction != 'rolling-update') { throw new Exception("[neoDeploy] Invalid warAction = '${warAction}'. Valid 'warAction' values are: 'deploy' and 'rolling-update'.") } } + if (deployMode == 'warPropertiesFile') { - propertiesFile = utils.getMandatoryParameter(parameters, 'propertiesFile', null) + propertiesFile = utils.getMandatoryParameter(configuration, 'propertiesFile') if (!fileExists(propertiesFile)){ error "Properties file cannot be found with parameter propertiesFile: '${propertiesFile}'." } } - def applicationName - def runtime - def runtimeVersion - def vmSize if (deployMode == 'warParams') { - applicationName = utils.getMandatoryParameter(parameters, 'applicationName', null) - runtime = utils.getMandatoryParameter(parameters, 'runtime', null) - runtimeVersion = utils.getMandatoryParameter(parameters, 'runtimeVersion', null) - vmSize = utils.getMandatoryParameter(parameters, 'vmSize', 'lite') + applicationName = utils.getMandatoryParameter(configuration, 'applicationName') + runtime = utils.getMandatoryParameter(configuration, 'runtime') + runtimeVersion = utils.getMandatoryParameter(configuration, 'runtimeVersion') + vmSize = configuration.vmSize if (vmSize != 'lite' && vmSize !='pro' && vmSize != 'prem' && vmSize != 'prem-plus') { throw new Exception("[neoDeploy] Invalid vmSize = '${vmSize}'. Valid 'vmSize' values are: 'lite', 'pro', 'prem' and 'prem-plus'.") } } - def defaultDeployHost = script.commonPipelineEnvironment.getConfigProperty('DEPLOY_HOST') - def defaultDeployAccount = script.commonPipelineEnvironment.getConfigProperty('CI_DEPLOY_ACCOUNT') - def defaultCredentialsId = script.commonPipelineEnvironment.getConfigProperty('neoCredentialsId') - if (defaultCredentialsId == null) { - defaultCredentialsId = 'CI_CREDENTIALS_ID' + if (deployMode.equals('mta') || deployMode.equals('warParams')) { + deployHost = utils.getMandatoryParameter(configuration, 'host') + deployAccount = utils.getMandatoryParameter(configuration, 'account') } - def deployHost - def deployAccount - - if (deployMode.equals('mta') || deployMode.equals('warParams')) { - deployHost = utils.getMandatoryParameter(parameters, 'deployHost', defaultDeployHost) - deployAccount = utils.getMandatoryParameter(parameters, 'deployAccount', defaultDeployAccount) - } - - def credentialsId = parameters.get('neoCredentialsId', defaultCredentialsId) - - def neoExecutable = getNeoExecutable(parameters) + def neoExecutable = getNeoExecutable(configuration) withCredentials([usernamePassword( credentialsId: credentialsId, @@ -113,13 +178,13 @@ def call(parameters = [:]) { } } -private getNeoExecutable(parameters) { +private getNeoExecutable(configuration) { def neoExecutable = 'neo' // default, if nothing below applies maybe it is the path. - if (parameters?.neoHome) { - neoExecutable = "${parameters.neoHome}/tools/neo.sh" - echo "[neoDeploy] Neo executable \"${neoExecutable}\" retrieved from parameters." + if (configuration.neoHome) { + neoExecutable = "${configuration.neoHome}/tools/neo.sh" + echo "[neoDeploy] Neo executable \"${neoExecutable}\" retrieved from configuration." return neoExecutable } From b843ac0794d47613a7960f1dadc01420362a014b Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Wed, 27 Dec 2017 11:37:53 +0100 Subject: [PATCH 27/32] Adjust neo deploy docu wrt new config framework. --- documentation/docs/steps/neoDeploy.md | 30 ++++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/documentation/docs/steps/neoDeploy.md b/documentation/docs/steps/neoDeploy.md index dfa9d9621..2baef7adc 100644 --- a/documentation/docs/steps/neoDeploy.md +++ b/documentation/docs/steps/neoDeploy.md @@ -12,21 +12,20 @@ Deploys an Application to SAP Cloud Platform (SAP CP) using the SAP Cloud Platfo * **Neo Java Web SDK** - can be downloaded from [Maven Central](http://central.maven.org/maven2/com/sap/cloud/neo-java-web-sdk/). The Neo Java Web SDK needs to be extracted into the folder provided by `neoHome`. In case this parameters is not provided and there is no NEO_HOME parameter in the environment -`/tools` needs to be in the `PATH`. +`/tools` needs to be in the `PATH`. This step is also capable of triggering the neo deploy tool provided inside a docker image. * **Java 8 or higher** - needed by the *Neo-Java-Web-SDK* ## Parameters when using MTA deployment method (default - MTA) -| parameter | mandatory | default | possible values | -| -------------------|-----------|----------------------------------------------------------------------------------------------|-------------------------------------------------| +| parameter | mandatory | default | possible values | +| -------------------|-----------|----------------------------------------------------------------------------------------------------------------------------------|-----------------| | `deployMode` | yes | `'MTA'` | `'MTA'`, `'WAR_PARAMS'`, `'WAR_PROPERTIESFILE'` | -| `script` | yes | | | -| `archivePath` | yes | | | -| `deployHost` | no | `'DEPLOY_HOST'` from `commonPipelineEnvironment` | | -| `deployAccount` | no | `'CI_DEPLOY_ACCOUNT'` from `commonPipelineEnvironment` | | -| `neoCredentialsId` | no | `'CI_CREDENTIALS_ID'` | | -| `neoHome` | no | Environment is checked for `NEO_HOME`,
otherwise the neo toolset is expected in the path | | - +| `script` | yes | | | +| `archivePath` | yes | | | +| `deployHost` | no | `'account'` from step configuration `'neoDeploy'`, or propertey `'DEPLOY_HOST'` from `commonPipelineEnvironment` (deprecated) | | +| `deployAccount` | no | `'host'` from step configuration `'neoDeploy'`, or property `'CI_DEPLOY_ACCOUNT'` from `commonPipelineEnvironment` (deprecated) | | +| `neoCredentialsId` | no | `'neoCredentialsId'` from step configuration `'neoDeploy'` or hard coded value `'CI_CREDENTIALS_ID'` | | +| `neoHome` | no | Environment is checked for `NEO_HOME`,
otherwise the neo toolset is expected in the path | | ## Parameters when using WAR file deployment method with .properties file (WAR_PROPERTIESFILE) | parameter | mandatory | default | possible values | | -------------------|-----------|----------------------------------------------------------------------------------------------|-------------------------------------------------| @@ -93,3 +92,14 @@ none ```groovy neoDeploy script: this, archivePath: 'path/to/archiveFile.mtar', credentialsId: 'my-credentials-id' ``` + +Example configuration: + +``` +steps: + <...> + neoDeploy: + + account: + host: hana.example.org +``` From bc2fb935519de355cf3ada095e4dec3d09563ec9 Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Wed, 13 Dec 2017 10:05:19 +0100 Subject: [PATCH 28/32] Use dockerExecute inside neoDeploy --- test/groovy/NeoDeploymentTest.groovy | 23 +++++----- vars/neoDeploy.groovy | 63 +++++++++++++++------------- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 1c67c6696..1bdde7623 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -47,6 +47,7 @@ class NeoDeploymentTest extends BasePipelineTest { propertiesFileName = 'config.properties' 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 }) @@ -91,7 +92,7 @@ class NeoDeploymentTest extends BasePipelineTest { neoCredentialsId: 'myCredentialsId' ) - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -112,7 +113,7 @@ class NeoDeploymentTest extends BasePipelineTest { neoCredentialsId: 'myCredentialsId' ) - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -138,7 +139,7 @@ class NeoDeploymentTest extends BasePipelineTest { neoCredentialsId: 'myCredentialsId' ) - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'configuration-frwk\.deploy\.host\.com' --account 'configurationFrwkUser123' --synchronous/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --host 'configuration-frwk\.deploy\.host\.com' --account 'configurationFrwkUser123' --synchronous --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") @@ -179,7 +180,7 @@ class NeoDeploymentTest extends BasePipelineTest { archivePath: archiveName ) - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @@ -197,7 +198,7 @@ class NeoDeploymentTest extends BasePipelineTest { archivePath: archiveName ) - assert jscr.shell[0] =~ /#!\/bin\/bash "neo" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous/ + assert jscr.shell[0] =~ /#!\/bin\/bash "neo" deploy-mta --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*"/ assert jlr.log.contains("Using Neo executable from PATH.") } @@ -217,7 +218,7 @@ class NeoDeploymentTest extends BasePipelineTest { neoHome: '/etc/neo' ) - assert jscr.shell[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/etc\/neo\/tools\/neo\.sh" deploy-mta --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous --user 'anonymous' --password '\*\*\*\*\*\*\*\*' --source ".*"/ } @@ -270,7 +271,7 @@ class NeoDeploymentTest extends BasePipelineTest { neoDeployScript.call(script: [commonPipelineEnvironment: cpe], archivePath: archiveName, deployMode: 'mta') - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*" --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous.*/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy-mta --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @@ -291,7 +292,7 @@ class NeoDeploymentTest extends BasePipelineTest { warAction: 'deploy', archivePath: warArchiveName) - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite' --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @@ -312,7 +313,7 @@ class NeoDeploymentTest extends BasePipelineTest { warAction: 'rolling-update', vmSize: 'lite') - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite'/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --host 'test\.deploy\.host\.com' --account 'trialuser123' --application 'testApp' --runtime 'neo-javaee6-wp' --runtime-version '2\.125' --size 'lite' --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @@ -332,7 +333,7 @@ class NeoDeploymentTest extends BasePipelineTest { warAction: 'deploy', vmSize: 'lite') - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" deploy .*\.properties --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } @@ -352,7 +353,7 @@ class NeoDeploymentTest extends BasePipelineTest { warAction: 'rolling-update', vmSize: 'lite') - assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war" .*\.properties/ + assert jscr.shell[0] =~ /#!\/bin\/bash "\/opt\/neo\/tools\/neo\.sh" rolling-update .*\.properties --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*\.war"/ assert jlr.log.contains("[neoDeploy] Neo executable \"/opt/neo/tools/neo.sh\" retrieved from environment.") } diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index 6a79a4322..4d3d28dec 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -133,6 +133,36 @@ def call(parameters = [:]) { def neoExecutable = getNeoExecutable(configuration) + def neoDeployScript + + if (deployMode == 'mta') { + neoDeployScript = + """#!/bin/bash + "${neoExecutable}" deploy-mta \ + --host '${deployHost}' \ + --account '${deployAccount}' \ + --synchronous""" + } + + if (deployMode == 'warParams') { + neoDeployScript = + """#!/bin/bash + "${neoExecutable}" ${warAction} \ + --host '${deployHost}' \ + --account '${deployAccount}' \ + --application '${applicationName}' \ + --runtime '${runtime}' \ + --runtime-version '${runtimeVersion}' \ + --size '${vmSize}'""" + } + + if (deployMode == 'warPropertiesFile') { + neoDeployScript = + """#!/bin/bash + "${neoExecutable}" ${warAction} \ + ${propertiesFile}""" + } + withCredentials([usernamePassword( credentialsId: credentialsId, passwordVariable: 'password', @@ -143,35 +173,12 @@ def call(parameters = [:]) { --password '${password}' \ --source "${archivePath}" \ """ + dockerExecute(dockerImage: configuration.get('dockerImage'), + dockerEnvVars: configuration.get('dockerEnvVars'), + dockerOptions: configuration.get('dockerOptions')) { - if (deployMode == 'mta') { - sh """#!/bin/bash - "${neoExecutable}" deploy-mta \ - ${commonDeployParams} \ - --host '${deployHost}' \ - --account '${deployAccount}' \ - --synchronous - """ - } - - if (deployMode == 'warParams') { - sh """#!/bin/bash - "${neoExecutable}" ${warAction} \ - ${commonDeployParams} \ - --host '${deployHost}' \ - --account '${deployAccount}' \ - --application '${applicationName}' \ - --runtime '${runtime}' \ - --runtime-version '${runtimeVersion}' \ - --size '${vmSize}' - """ - } - - if (deployMode == 'warPropertiesFile') { - sh """#!/bin/bash - "${neoExecutable}" ${warAction} \ - ${commonDeployParams} \ - ${propertiesFile} + sh """${neoDeployScript} \ + ${commonDeployParams} """ } } From 9a96acff57ec64f9acb026226c7319b93c9ec211 Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Fri, 15 Dec 2017 15:34:25 +0100 Subject: [PATCH 29/32] change default for neo toolset from neo to neo.sh The bash script is named 'neo.sh', not 'neo'. 'neo' as default will not work despite somebody takes extra action to make it work. --- test/groovy/NeoDeploymentTest.groovy | 2 +- vars/neoDeploy.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/groovy/NeoDeploymentTest.groovy b/test/groovy/NeoDeploymentTest.groovy index 1bdde7623..101f4bb84 100644 --- a/test/groovy/NeoDeploymentTest.groovy +++ b/test/groovy/NeoDeploymentTest.groovy @@ -198,7 +198,7 @@ class NeoDeploymentTest extends BasePipelineTest { archivePath: archiveName ) - assert jscr.shell[0] =~ /#!\/bin\/bash "neo" deploy-mta --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*"/ + assert jscr.shell[0] =~ /#!\/bin\/bash "neo.sh" deploy-mta --host 'test\.deploy\.host\.com' --account 'trialuser123' --synchronous --user 'defaultUser' --password '\*\*\*\*\*\*\*\*' --source ".*"/ assert jlr.log.contains("Using Neo executable from PATH.") } diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index 4d3d28dec..e072ee2af 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -187,7 +187,7 @@ def call(parameters = [:]) { private getNeoExecutable(configuration) { - def neoExecutable = 'neo' // default, if nothing below applies maybe it is the path. + def neoExecutable = 'neo.sh' // default, if nothing below applies maybe it is the path. if (configuration.neoHome) { neoExecutable = "${configuration.neoHome}/tools/neo.sh" From 147d29a714d69b309868e01fcf6e71aa302f3606 Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Mon, 15 Jan 2018 13:42:57 +0100 Subject: [PATCH 30/32] Check for running docker daemon with docker ps. --- vars/dockerExecute.groovy | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vars/dockerExecute.groovy b/vars/dockerExecute.groovy index 11ad670fe..72ff9e758 100644 --- a/vars/dockerExecute.groovy +++ b/vars/dockerExecute.groovy @@ -23,6 +23,11 @@ def call(Map parameters = [:], body) { echo "[WARNING][${STEP_NAME}] No docker environment found (command 'which docker' did not return with '0'). Configured docker image '${dockerImage}' will not be used." dockerImage = null } + + returnCode = sh script: 'docker ps -q > /dev/null', returnStatus: true + if(returnCode != 0) { + echo "[WARNING][$STEP_NAME] Cannot connect to docker daemon (command 'docker ps' did not return with '0'). Configured docker image '${dockerImage}' will not be used." + } } if(!dockerImage){ From 678b55e771a8290344b884889e014c9bbb4c962d Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Mon, 15 Jan 2018 13:45:16 +0100 Subject: [PATCH 31/32] null docker image in case of missing docker daemon. --- vars/dockerExecute.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/vars/dockerExecute.groovy b/vars/dockerExecute.groovy index 72ff9e758..4cfbc07d3 100644 --- a/vars/dockerExecute.groovy +++ b/vars/dockerExecute.groovy @@ -27,6 +27,7 @@ def call(Map parameters = [:], body) { returnCode = sh script: 'docker ps -q > /dev/null', returnStatus: true if(returnCode != 0) { echo "[WARNING][$STEP_NAME] Cannot connect to docker daemon (command 'docker ps' did not return with '0'). Configured docker image '${dockerImage}' will not be used." + dockerImage = null } } From 8e3e60f1d536d89956ab843623c45c35d568fd71 Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Fri, 26 Jan 2018 15:39:04 +0100 Subject: [PATCH 32/32] Avoid interdependencies between tests --- test/groovy/InfluxWriteDataTest.groovy | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/groovy/InfluxWriteDataTest.groovy b/test/groovy/InfluxWriteDataTest.groovy index d86fd18b7..fd430ba04 100644 --- a/test/groovy/InfluxWriteDataTest.groovy +++ b/test/groovy/InfluxWriteDataTest.groovy @@ -1,5 +1,6 @@ #!groovy import com.lesfurets.jenkins.unit.BasePipelineTest +import com.sap.piper.DefaultValueCache import org.junit.Before import org.junit.Rule import org.junit.Test @@ -31,6 +32,13 @@ class InfluxWriteDataTest extends BasePipelineTest { @Before void init() throws Exception { + // + // Currently we have dependencies between the tests since + // DefaultValueCache is a singleton which keeps its status + // for all the tests. Depending on the test order we fail. + // As long as this status remains we need: + DefaultValueCache.reset() + //reset stepMap stepMap = [:] //reset fileMap