From 793df723cfd49e347ff5ac5983a835e601734776 Mon Sep 17 00:00:00 2001 From: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> Date: Wed, 13 Feb 2019 16:45:35 +0100 Subject: [PATCH 01/11] add step slackSendNotification (#338) * add step slackSendNotification This step allows to send Slack notifications in case of pipeline failures. * add SWA reporting * remove allowBuildFailure * add GENERAL_CONFIG_KEYS * update STEP_NAME * add missing import * fix MD findings * adjust rule name to be aligned with #455 --- .../docs/steps/slackSendNotification.md | 73 +++++++++++++++ documentation/mkdocs.yml | 1 + resources/default_pipeline_environment.yml | 3 + test/groovy/SlackSendNotificationTest.groovy | 88 +++++++++++++++++++ vars/slackSendNotification.groovy | 53 +++++++++++ 5 files changed, 218 insertions(+) create mode 100644 documentation/docs/steps/slackSendNotification.md create mode 100644 test/groovy/SlackSendNotificationTest.groovy create mode 100644 vars/slackSendNotification.groovy diff --git a/documentation/docs/steps/slackSendNotification.md b/documentation/docs/steps/slackSendNotification.md new file mode 100644 index 000000000..4357d0978 --- /dev/null +++ b/documentation/docs/steps/slackSendNotification.md @@ -0,0 +1,73 @@ +# slackSendNotification + +## Description + +Sends notifications to the Slack channel about the build status. + +Notification contains: + +* Build status; +* Repo Owner; +* Repo Name; +* Branch Name; +* Jenkins Build Number; +* Jenkins Build URL. + +## Prerequisites + +Installed and configured [Jenkins Slack plugin](https://github.com/jenkinsci/slack-plugin). + +## Example + +Usage of pipeline step: + +```groovy +try { + stage('..') {..} + stage('..') {..} + stage('..') {..} + currentBuild.result = 'SUCCESS' +} catch (Throwable err) { + currentBuild.result = 'FAILURE' + throw err +} finally { + stage('report') { + slackSendNotification script: this + } +} +``` + +## Parameters + +| parameter | mandatory | default | possible values | +| ----------|-----------|---------|-----------------| +|script|yes||| +|baseUrl|no||| +|channel|no||| +|color|no|`${buildStatus == 'SUCCESS'?'#008000':'#E60000'}`|| +|credentialsId|no||| +|message|no||| + +### 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. +* `baseUrl` allows overriding the Slack Plugin Integration Base Url specified in the global configuration. +* `color` defines the message color. +* If `channel` is defined another than the default channel will be used. +* `credentialsId` defines the Jenkins credentialId which holds the Slack token +* With parameter `message` a custom message can be defined which is sent into the Slack channel. + +## Step configuration + +We recommend to define values of step parameters via [config.yml file](../configuration.md). + +In following sections the configuration is possible: + +| parameter | general | step | stage | +| ----------|-----------|---------|-----------------| +|script|||| +|baseUrl||X|X| +|channel||X|X| +|color||X|X| +|credentialsId||X|X| +|message||X|X| diff --git a/documentation/mkdocs.yml b/documentation/mkdocs.yml index 4ad088c00..f766e9799 100644 --- a/documentation/mkdocs.yml +++ b/documentation/mkdocs.yml @@ -30,6 +30,7 @@ nav: - prepareDefaultValues: steps/prepareDefaultValues.md - seleniumExecuteTests: steps/seleniumExecuteTests.md - setupCommonPipelineEnvironment: steps/setupCommonPipelineEnvironment.md + - slackSendNotification: steps/slackSendNotification.md - testsPublishResults: steps/testsPublishResults.md - toolValidate: steps/toolValidate.md - transportRequestCreate: steps/transportRequestCreate.md diff --git a/resources/default_pipeline_environment.yml b/resources/default_pipeline_environment.yml index 9c781f17b..2d8d65327 100644 --- a/resources/default_pipeline_environment.yml +++ b/resources/default_pipeline_environment.yml @@ -305,6 +305,9 @@ steps: dockerImage: 'node:8-stretch' dockerName: 'npm' dockerWorkspace: '/home/node' + slackSendNotification: + color: "${buildStatus == 'SUCCESS'?'#008000':'#E60000'}" + defaultMessage: "${buildStatus}: Job ${env.JOB_NAME} <${env.BUILD_URL}|#${env.BUILD_NUMBER}>" snykExecute: buildDescriptorFile: './package.json' dockerImage: 'node:8-stretch' diff --git a/test/groovy/SlackSendNotificationTest.groovy b/test/groovy/SlackSendNotificationTest.groovy new file mode 100644 index 000000000..c59f82b41 --- /dev/null +++ b/test/groovy/SlackSendNotificationTest.groovy @@ -0,0 +1,88 @@ +#!groovy +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.RuleChain +import util.BasePiperTest +import util.JenkinsLoggingRule +import util.JenkinsReadYamlRule +import util.JenkinsStepRule +import util.Rules + +import static org.junit.Assert.* + +class SlackSendNotificationTest extends BasePiperTest { + def slackCallMap = [:] + + private JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this) + private JenkinsStepRule stepRule = new JenkinsStepRule(this) + + @Rule + public RuleChain ruleChain = Rules + .getCommonRules(this) + .around(new JenkinsReadYamlRule(this)) + .around(loggingRule) + .around(stepRule) + + @Before + void init() throws Exception { + helper.registerAllowedMethod("slackSend", [Map.class], {m -> slackCallMap = m}) + } + + @Test + void testNotificationBuildSuccessDefaultChannel() throws Exception { + stepRule.step.slackSendNotification(script: [currentBuild: [result: 'SUCCESS']]) + // asserts + assertEquals('Message not set correctly', 'SUCCESS: Job p ', slackCallMap.message.toString()) + assertNull('Channel not set correctly', slackCallMap.channel) + assertEquals('Color not set correctly', '#008000', slackCallMap.color) + assertJobStatusSuccess() + } + + @Test + void testNotificationBuildSuccessCustomChannel() throws Exception { + stepRule.step.slackSendNotification(script: [currentBuild: [result: 'SUCCCESS']], channel: 'Test') + // asserts + assertEquals('Channel not set correctly', 'Test', slackCallMap.channel) + assertJobStatusSuccess() + } + + @Test + void testNotificationBuildFailed() throws Exception { + stepRule.step.slackSendNotification(script: [currentBuild: [result: 'FAILURE']]) + // asserts + assertEquals('Message not set correctly', 'FAILURE: Job p ', slackCallMap.message.toString()) + assertEquals('Color not set correctly', '#E60000', slackCallMap.color) + } + + @Test + void testNotificationBuildStatusNull() throws Exception { + stepRule.step.slackSendNotification(script: [currentBuild: [:]]) + // asserts + assertTrue('Missing build status not detected', loggingRule.log.contains('currentBuild.result is not set. Skipping Slack notification')) + assertJobStatusSuccess() + } + + @Test + void testNotificationCustomMessageAndColor() throws Exception { + stepRule.step.slackSendNotification(script: [currentBuild: [:]], message: 'Custom Message', color: '#AAAAAA') + // asserts + assertEquals('Custom message not set correctly', 'Custom Message', slackCallMap.message.toString()) + assertEquals('Custom color not set correctly', '#AAAAAA', slackCallMap.color) + assertJobStatusSuccess() + } + + @Test + void testNotificationWithCustomCredentials() throws Exception { + stepRule.step.slackSendNotification( + script: [currentBuild: [:]], + message: 'I am no Message', + baseUrl: 'https://my.base.url', + credentialsId: 'MY_TOKEN_ID' + ) + // asserts + assertEquals('Custom base url not set correctly', 'https://my.base.url', slackCallMap.baseUrl) + assertEquals('Custom token id not set correctly', 'MY_TOKEN_ID', slackCallMap.tokenCredentialId) + assertJobStatusSuccess() + } +} diff --git a/vars/slackSendNotification.groovy b/vars/slackSendNotification.groovy new file mode 100644 index 000000000..33c1a0cee --- /dev/null +++ b/vars/slackSendNotification.groovy @@ -0,0 +1,53 @@ +import static com.sap.piper.Prerequisites.checkScript + +import com.sap.piper.ConfigurationHelper +import com.sap.piper.Utils +import groovy.transform.Field +import groovy.text.SimpleTemplateEngine + +@Field String STEP_NAME = getClass().getName() + +@Field Set GENERAL_CONFIG_KEYS = [] +@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([ + 'baseUrl', + 'channel', + 'color', + 'credentialsId', + 'message' +]) +@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS + +void call(Map parameters = [:]) { + handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) { + def utils = parameters.juStabUtils ?: new Utils() + def script = checkScript(this, parameters) ?: this + // load default & individual configuration + Map config = ConfigurationHelper.newInstance(this) + .loadStepDefaults() + .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS) + .mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS) + .mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS) + .mixin(parameters, PARAMETER_KEYS) + .use() + + new Utils().pushToSWA([step: STEP_NAME], config) + + def buildStatus = script.currentBuild.result + // resolve templates + config.color = SimpleTemplateEngine.newInstance().createTemplate(config.color).make([buildStatus: buildStatus]).toString() + if (!config?.message){ + if (!buildStatus) { + echo "[${STEP_NAME}] currentBuild.result is not set. Skipping Slack notification" + return + } + config.message = SimpleTemplateEngine.newInstance().createTemplate(config.defaultMessage).make([buildStatus: buildStatus, env: env]).toString() + } + Map options = [:] + if(config.credentialsId) + options.put('tokenCredentialId', config.credentialsId) + for(String entry : STEP_CONFIG_KEYS.minus('credentialsId')) + if(config.get(entry)) + options.put(entry, config.get(entry)) + slackSend(options) + } +} From 523fc067f1a70c7b12aa0f05efbbe80381cff1b3 Mon Sep 17 00:00:00 2001 From: weloli <45266922+weloli@users.noreply.github.com> Date: Thu, 14 Feb 2019 08:45:20 +0100 Subject: [PATCH 02/11] fix general config for param changeManagement (#513) --- vars/checkChangeInDevelopment.groovy | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/vars/checkChangeInDevelopment.groovy b/vars/checkChangeInDevelopment.groovy index fdd8540a6..46a9ae4c0 100644 --- a/vars/checkChangeInDevelopment.groovy +++ b/vars/checkChangeInDevelopment.groovy @@ -16,17 +16,13 @@ import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrati @Field def STEP_NAME = getClass().getName() -@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS - -@Field Set STEP_CONFIG_KEYS = [ - 'changeManagement', +@Field Set GENERAL_CONFIG_KEYS = ['changeManagement'] +@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus( /** * When set to `false` the step will not fail in case the step is not in status 'in development'. * @possibleValues `true`, `false` */ - 'failIfStatusIsNotInDevelopment' - ] - + 'failIfStatusIsNotInDevelopment') @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus('changeDocumentId') /** From 58c8063e6de1f9e27446dd91cb8b12eb01570e8f Mon Sep 17 00:00:00 2001 From: Florian Wilhelm <2292245+fwilhe@users.noreply.github.com> Date: Thu, 14 Feb 2019 09:58:04 +0100 Subject: [PATCH 03/11] Add consumer tests for s4sdk pipeline (#506) Additional tests for running an example pipeline with the s4-sdk address manager example application. --- .gitignore | 2 ++ .travis.yml | 4 +++- consumer-test/jenkins.yml | 29 +++++++++++++++++++++++++++++ consumer-test/runTests.sh | 14 ++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 consumer-test/jenkins.yml create mode 100755 consumer-test/runTests.sh diff --git a/.gitignore b/.gitignore index 8e150e0a0..e286faf6a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ hs_err_pid* target/ targets/ documentation/docs-gen + +consumer-test/workspace diff --git a/.travis.yml b/.travis.yml index e0ab22dfd..d5cae0e77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,9 @@ jobs: cp -r documentation/docs documentation/docs-tmp documentation/bin/createDocu.sh vars documentation/docs-tmp/steps docker run --rm -it -v ${TRAVIS_BUILD_DIR}:/docs -w /docs/documentation squidfunk/mkdocs-material:3.0.4 build --clean --verbose --strict - + - name: Consumer Tests for s4sdk pipeline + script: cd consumer-test && chmod +x runTests.sh && ./runTests.sh + - stage: Docs name: Deploy if: repo = "SAP/jenkins-library" AND branch = master AND NOT type = pull_request diff --git a/consumer-test/jenkins.yml b/consumer-test/jenkins.yml new file mode 100644 index 000000000..84eff57ee --- /dev/null +++ b/consumer-test/jenkins.yml @@ -0,0 +1,29 @@ +jenkins: + numExecutors: 10 +unclassified: + globallibraries: + libraries: + - defaultVersion: "master" + name: "s4sdk-pipeline-library" + retriever: + modernSCM: + scm: + git: + remote: "https://github.com/SAP/cloud-s4-sdk-pipeline-lib.git" + - defaultVersion: "master" + name: "piper-library-os" + retriever: + modernSCM: + scm: + git: + remote: "https://github.com/__REPO_SLUG__.git" +credentials: + system: + domainCredentials: + - credentials: + - usernamePassword: + scope: GLOBAL + id: "devops-docker-images-IT-cf" + username: ${CX_INFRA_IT_CF_USERNAME} + password: ${CX_INFRA_IT_CF_PASSWORD} + description: "SAP CP Trail account for test deployment" diff --git a/consumer-test/runTests.sh b/consumer-test/runTests.sh new file mode 100755 index 000000000..9a3095f20 --- /dev/null +++ b/consumer-test/runTests.sh @@ -0,0 +1,14 @@ +#!/bin/bash -e + +LIBRARY_VERSION_UNDER_TEST=$(git log --format="%H" -n 1) +REPOSITORY_UNDER_TEST=${TRAVIS_REPO_SLUG:-SAP/jenkins-library} + +rm -rf workspace +git clone -b consumer-test https://github.com/sap/cloud-s4-sdk-book workspace +cp -f jenkins.yml workspace +cd workspace +sed -i -e "s:__REPO_SLUG__:${REPOSITORY_UNDER_TEST}:g" jenkins.yml +echo "@Library(\"piper-library-os@$LIBRARY_VERSION_UNDER_TEST\") _" | cat - Jenkinsfile > temp && mv temp Jenkinsfile +git commit --all --author="piper-testing-bot " --message="Set piper lib version for test" + +docker run -v /var/run/docker.sock:/var/run/docker.sock -v "${PWD}":/workspace -v /tmp -e CASC_JENKINS_CONFIG=/workspace/jenkins.yml -e CX_INFRA_IT_CF_USERNAME -e CX_INFRA_IT_CF_PASSWORD -e BRANCH_NAME=consumer-test ppiper/jenkinsfile-runner From d2b6be4e259e0e3a83f11a6609eb7b6b463d3cb3 Mon Sep 17 00:00:00 2001 From: Florian Wilhelm <2292245+fwilhe@users.noreply.github.com> Date: Fri, 15 Feb 2019 13:48:34 +0100 Subject: [PATCH 04/11] Configure default mta build image to ppiper/mta-archive-builder (#515) --- documentation/docs/steps/mtaBuild.md | 16 ++++------------ resources/default_pipeline_environment.yml | 3 ++- test/groovy/MtaBuildTest.groovy | 18 +++++++++--------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/documentation/docs/steps/mtaBuild.md b/documentation/docs/steps/mtaBuild.md index 393d702dd..f2c21843f 100644 --- a/documentation/docs/steps/mtaBuild.md +++ b/documentation/docs/steps/mtaBuild.md @@ -8,29 +8,21 @@ Before doing this, validates that SAP Multitarget Application Archive Builder ex Note that a version is formed by `major.minor.patch`, and a version is compatible to another version if the minor and patch versions are higher, but the major version is not, e.g. if 3.39.10 is the expected version, 3.39.11 and 3.40.1 would be compatible versions, but 4.0.1 would not be a compatible version. -## Prerequisites - -* A docker image meeting the following requirements - * **SAP MTA Archive Builder 1.0.6 or compatible version** - can be downloaded from [SAP Development Tools](https://tools.hana.ondemand.com/#cloud). - * **Java 8 or compatible version** - necessary to run the `mta.jar` file. - * **NodeJS installed** - the MTA Builder uses `npm` to download node module dependencies such as `grunt`. - ## Parameters | parameter | mandatory | default | possible values | | -----------------|-----------|--------------------------------------------------------|--------------------| | `script` | yes | | | -| `dockerImage` | yes | | | +| `dockerImage` | no | `ppiper/mta-archive-builder` | | | `dockerOptions` | no | '' | | | `buildTarget` | yes | `'NEO'` | 'CF', 'NEO', 'XSA' | -| `extension` | no | | | -| `mtaJarLocation` | no | `'mta.jar'` | | +| `extension` | no | | | +| `mtaJarLocation` | no | `'/opt/sap/mta/lib/mta.jar'` | | | `applicationName`| no | | | * `script` - The common script environment of the Jenkinsfile running. Typically the reference to the script calling the pipeline step is provided with the `this` parameter, as in `script: this`. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for retrieving, for example, configuration parameters. * `dockerImage` - The Docker image to execute the MTA build. - A custom built image needs to include Multi-target Application Archive Builder. - Refer to [SAP Help Portal](https://help.sap.com/viewer/58746c584026430a890170ac4d87d03b/Cloud/en-US/ba7dd5a47b7a4858a652d15f9673c28d.html) for information on how to set it up. + Note that you can provide your own image if required, but for most cases, the default should be fine. * `dockerOptions` Docker options to be set when starting the container. It can be a list or a string. * `buildTarget` - The target platform to which the mtar can be deployed. * `extension` - The path to the extension descriptor file. diff --git a/resources/default_pipeline_environment.yml b/resources/default_pipeline_environment.yml index 2d8d65327..030d791b0 100644 --- a/resources/default_pipeline_environment.yml +++ b/resources/default_pipeline_environment.yml @@ -232,7 +232,8 @@ steps: logSuccessfulMavenTransfers: false mtaBuild: buildTarget: 'NEO' - mtaJarLocation: 'mta.jar' + mtaJarLocation: '/opt/sap/mta/lib/mta.jar' + dockerImage: 'ppiper/mta-archive-builder' neoDeploy: dockerImage: 's4sdk/docker-neo-cli' deployMode: 'mta' diff --git a/test/groovy/MtaBuildTest.groovy b/test/groovy/MtaBuildTest.groovy index 7f0ca874c..d5de756cc 100644 --- a/test/groovy/MtaBuildTest.groovy +++ b/test/groovy/MtaBuildTest.groovy @@ -73,7 +73,7 @@ public class MtaBuildTest extends BasePiperTest { @Test - void mtarFilePathFromCommonPipelineEnviromentTest() { + void mtarFilePathFromCommonPipelineEnvironmentTest() { stepRule.step.mtaBuild(script: nullScript, buildTarget: 'NEO') @@ -163,9 +163,9 @@ public class MtaBuildTest extends BasePiperTest { stepRule.step.mtaBuild(script: nullScript, buildTarget: 'NEO') - assert shellRule.shell.find(){ c -> c.contains("-jar mta.jar --mtar")} - assert loggingRule.log.contains("SAP Multitarget Application Archive Builder file 'mta.jar' retrieved from configuration.") - assert loggingRule.log.contains("Using SAP Multitarget Application Archive Builder 'mta.jar'.") + assert shellRule.shell.find(){ c -> c.contains("-jar /opt/sap/mta/lib/mta.jar --mtar")} + assert loggingRule.log.contains("SAP Multitarget Application Archive Builder file '/opt/sap/mta/lib/mta.jar' retrieved from configuration.") + assert loggingRule.log.contains("Using SAP Multitarget Application Archive Builder '/opt/sap/mta/lib/mta.jar'.") } @@ -174,7 +174,7 @@ public class MtaBuildTest extends BasePiperTest { stepRule.step.mtaBuild(script: nullScript, buildTarget: 'NEO') - assert shellRule.shell.find { c -> c.contains('java -jar mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO build')} + assert shellRule.shell.find { c -> c.contains('java -jar /opt/sap/mta/lib/mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO build')} } @@ -185,7 +185,7 @@ public class MtaBuildTest extends BasePiperTest { stepRule.step.mtaBuild(script: nullScript) - assert shellRule.shell.find(){ c -> c.contains('java -jar mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO build')} + assert shellRule.shell.find(){ c -> c.contains('java -jar /opt/sap/mta/lib/mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO build')} } @Test @@ -211,7 +211,7 @@ public class MtaBuildTest extends BasePiperTest { stepRule.step.mtaBuild(script: nullScript) - assert shellRule.shell.find { c -> c.contains('java -jar mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO build')} + assert shellRule.shell.find { c -> c.contains('java -jar /opt/sap/mta/lib/mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO build')} } @@ -220,7 +220,7 @@ public class MtaBuildTest extends BasePiperTest { stepRule.step.mtaBuild(script: nullScript, buildTarget: 'NEO', extension: 'param_extension') - assert shellRule.shell.find { c -> c.contains('java -jar mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO --extension=param_extension build')} + assert shellRule.shell.find { c -> c.contains('java -jar /opt/sap/mta/lib/mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO --extension=param_extension build')} } @@ -231,7 +231,7 @@ public class MtaBuildTest extends BasePiperTest { stepRule.step.mtaBuild(script: nullScript) - assert shellRule.shell.find(){ c -> c.contains('java -jar mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO --extension=config_extension build')} + assert shellRule.shell.find(){ c -> c.contains('java -jar /opt/sap/mta/lib/mta.jar --mtar com.mycompany.northwind.mtar --build-target=NEO --extension=config_extension build')} } From cb31e173fe192a68d568507846c76acc344f6a8a Mon Sep 17 00:00:00 2001 From: Marcus Holl Date: Wed, 20 Feb 2019 09:29:33 +0100 Subject: [PATCH 05/11] Remove unused pipeline script --- Jenkinsfile | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 713d24ebf..000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,19 +0,0 @@ -node { - try { - lock(resource: "sap-jenkins-library/10", inversePrecedence: true) { - milestone 10 - deleteDir() - stage ('Checkout'){ - checkout scm - } - stage ('Test') { - sh "mvn clean test --batch-mode" - } - } - } catch (Throwable err) { - echo "Error occured: ${err}" - currentBuild.result = 'FAILURE' - mail subject: '[Build failed] SAP/jenkins-library', body: 'Fix the build.', to: 'marcus.holl@sap.com,oliver.nocon@sap.com' - throw err - } -} From 02afb22c74f8f2c22ab64d3d7b6595cd303d3bb8 Mon Sep 17 00:00:00 2001 From: Florian Wilhelm <2292245+fwilhe@users.noreply.github.com> Date: Thu, 21 Feb 2019 13:56:20 +0100 Subject: [PATCH 06/11] Change telemetry disabled message to be more kind (#530) Please, don't use exclamation marks in user interfaces. --- src/com/sap/piper/analytics/Telemetry.groovy | 2 +- test/groovy/com/sap/piper/analytics/TelemetryTest.groovy | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/sap/piper/analytics/Telemetry.groovy b/src/com/sap/piper/analytics/Telemetry.groovy index 1a386d6b9..d721afb86 100644 --- a/src/com/sap/piper/analytics/Telemetry.groovy +++ b/src/com/sap/piper/analytics/Telemetry.groovy @@ -30,7 +30,7 @@ class Telemetry implements Serializable{ static notify(Script steps, Map config, Map payload){ //allow opt-out via configuration if (!config?.collectTelemetryData) { - steps.echo "[${payload.step}] Telemetry reporting disabled!" + steps.echo "[${payload.step}] Sending telemetry data is disabled." return } diff --git a/test/groovy/com/sap/piper/analytics/TelemetryTest.groovy b/test/groovy/com/sap/piper/analytics/TelemetryTest.groovy index 2d930930f..dbb0c0c21 100644 --- a/test/groovy/com/sap/piper/analytics/TelemetryTest.groovy +++ b/test/groovy/com/sap/piper/analytics/TelemetryTest.groovy @@ -82,7 +82,7 @@ class TelemetryTest extends BasePiperTest { Telemetry.notify(nullScript, [collectTelemetryData: false], [step: 'anyStep', anything: 'something']) // asserts assertThat(Telemetry.getInstance().listenerList, is(not(empty()))) - assertThat(jlr.log, containsString("[anyStep] Telemetry reporting disabled!")) + assertThat(jlr.log, containsString("[anyStep] Sending telemetry data is disabled.")) assertThat(notificationPayload.keySet(), is(empty())) } @@ -99,7 +99,7 @@ class TelemetryTest extends BasePiperTest { Telemetry.notify(nullScript, [:], [step: 'anyStep', anything: 'something']) // asserts assertThat(Telemetry.getInstance().listenerList, is(not(empty()))) - assertThat(jlr.log, containsString("[anyStep] Telemetry reporting disabled!")) + assertThat(jlr.log, containsString("[anyStep] Sending telemetry data is disabled.")) assertThat(notificationPayload.keySet(), is(empty())) } @@ -116,7 +116,7 @@ class TelemetryTest extends BasePiperTest { Telemetry.notify(nullScript, null, [step: 'anyStep', anything: 'something']) // asserts assertThat(Telemetry.getInstance().listenerList, is(not(empty()))) - assertThat(jlr.log, containsString("[anyStep] Telemetry reporting disabled!")) + assertThat(jlr.log, containsString("[anyStep] Sending telemetry data is disabled.")) assertThat(notificationPayload.keySet(), is(empty())) } From ada3ed909d11b6a90711bdfadaa3d04a3eb0ca3e Mon Sep 17 00:00:00 2001 From: Florian Wilhelm <2292245+fwilhe@users.noreply.github.com> Date: Thu, 21 Feb 2019 15:46:17 +0100 Subject: [PATCH 07/11] Don't print messages in all uppercase letters (#531) --- documentation/docs/steps/handlePipelineStepErrors.md | 12 ++++++------ resources/com.sap.piper/templates/error.log | 8 ++++---- test/groovy/HandlePipelineStepErrorTest.groovy | 12 ++++++------ vars/handlePipelineStepErrors.groovy | 6 +++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/documentation/docs/steps/handlePipelineStepErrors.md b/documentation/docs/steps/handlePipelineStepErrors.md index df2b7fd95..67f61fd40 100644 --- a/documentation/docs/steps/handlePipelineStepErrors.md +++ b/documentation/docs/steps/handlePipelineStepErrors.md @@ -19,23 +19,23 @@ none * `stepParameters` - The parameters from the step to be executed. The list of parameters is then shown in the console output. * `stepName` - The name of the step executed to be shown in the console output. * `echoDetails` - If set to true the following will be output to the console: - 1. Step beginning: `--- BEGIN LIBRARY STEP: ${stepName}.groovy ---` - 2. Step end: `--- END LIBRARY STEP: ${stepName}.groovy ---` + 1. Step beginning: `--- Begin library step: ${stepName}.groovy ---` + 2. Step end: `--- End library step: ${stepName}.groovy ---` 3. Step errors: ```log ---------------------------------------------------------- - --- ERROR OCCURED IN LIBRARY STEP: ${stepName} + --- An error occurred in the library step: ${stepName} ---------------------------------------------------------- - FOLLOWING PARAMETERS WERE AVAILABLE TO THIS STEP: + The following parameters were available to the step: *** ${stepParameters} *** - ERROR WAS: + The error was: *** ${err} *** - FURTHER INFORMATION: + Further information: * Documentation of step ${stepName}: .../${stepName}/ * Pipeline documentation: https://... * GitHub repository for pipeline steps: https://... diff --git a/resources/com.sap.piper/templates/error.log b/resources/com.sap.piper/templates/error.log index 3058ed649..6cfcd9f3b 100644 --- a/resources/com.sap.piper/templates/error.log +++ b/resources/com.sap.piper/templates/error.log @@ -1,18 +1,18 @@ ---------------------------------------------------------- ---- ERROR OCCURRED IN LIBRARY STEP: ${stepName} +--- An error occurred in the library step: ${stepName} ---------------------------------------------------------- -FOLLOWING PARAMETERS WERE AVAILABLE TO THIS STEP: +The following parameters were available to the step: *** ${stepParameters} *** -ERROR WAS: +The error was: *** ${error} *** -FURTHER INFORMATION: +Further information: * Documentation of library step ${stepName}: https://sap.github.io/jenkins-library/steps/${stepName}/ * Source code of library step ${stepName}: https://github.com/SAP/jenkins-library/blob/master/vars/${stepName}.groovy * Library documentation: https://sap.github.io/jenkins-library/ diff --git a/test/groovy/HandlePipelineStepErrorTest.groovy b/test/groovy/HandlePipelineStepErrorTest.groovy index 1ccf80c84..394101466 100644 --- a/test/groovy/HandlePipelineStepErrorTest.groovy +++ b/test/groovy/HandlePipelineStepErrorTest.groovy @@ -37,8 +37,8 @@ class HandlePipelineStepErrorsTest extends BasePiperTest { } // asserts assertThat(isExecuted, is(true)) - assertThat(loggingRule.log, containsString('--- BEGIN LIBRARY STEP: testStep')) - assertThat(loggingRule.log, containsString('--- END LIBRARY STEP: testStep')) + assertThat(loggingRule.log, containsString('--- Begin library step of: testStep')) + assertThat(loggingRule.log, containsString('--- End library step of: testStep')) } @Test @@ -54,9 +54,9 @@ class HandlePipelineStepErrorsTest extends BasePiperTest { } catch (ignore) { } finally { // asserts - assertThat(loggingRule.log, not(containsString('--- BEGIN LIBRARY STEP: testStep'))) - assertThat(loggingRule.log, not(containsString('--- END LIBRARY STEP: testStep'))) - assertThat(loggingRule.log, not(containsString('--- ERROR OCCURRED IN LIBRARY STEP: testStep'))) + assertThat(loggingRule.log, not(containsString('--- Begin library step of: testStep'))) + assertThat(loggingRule.log, not(containsString('--- End library step: testStep'))) + assertThat(loggingRule.log, not(containsString('--- An error occurred in the library step: testStep'))) } } @@ -75,7 +75,7 @@ class HandlePipelineStepErrorsTest extends BasePiperTest { } finally { // asserts assertThat(isReported, is(true)) - assertThat(loggingRule.log, containsString('--- ERROR OCCURRED IN LIBRARY STEP: testStep')) + assertThat(loggingRule.log, containsString('--- An error occurred in the library step: testStep')) assertThat(loggingRule.log, containsString('[something:anything]')) } } diff --git a/vars/handlePipelineStepErrors.groovy b/vars/handlePipelineStepErrors.groovy index c304ac7f0..bf05f027b 100644 --- a/vars/handlePipelineStepErrors.groovy +++ b/vars/handlePipelineStepErrors.groovy @@ -10,10 +10,10 @@ void call(Map parameters = [:], body) { def message = '' try { if (stepParameters == null && stepName == null) - error "step handlePipelineStepErrors requires following mandatory parameters: stepParameters, stepName" + error "The step handlePipelineStepErrors requires following mandatory parameters: stepParameters, stepName" if (verbose) - echo "--- BEGIN LIBRARY STEP: ${stepName} ---" + echo "--- Begin library step of: ${stepName} ---" body() } catch (Throwable err) { @@ -28,7 +28,7 @@ void call(Map parameters = [:], body) { throw err } finally { if (verbose) - message += "--- END LIBRARY STEP: ${stepName} ---" + message += "--- End library step of: ${stepName} ---" echo message } } From 38c5a0d7793297d9743c4afba7a5787968cb2ea2 Mon Sep 17 00:00:00 2001 From: yemengsap <38942126+yemengsap@users.noreply.github.com> Date: Thu, 21 Feb 2019 19:14:48 +0100 Subject: [PATCH 08/11] Add npmExecute step (#491) --- .../docs/steps/checkChangeInDevelopment.md | 6 +- documentation/docs/steps/dockerExecute.md | 6 +- .../docs/steps/dockerExecuteOnKubernetes.md | 6 +- documentation/docs/steps/npmExecute.md | 23 ++++++ .../docs/steps/uiVeri5ExecuteTests.md | 6 +- documentation/mkdocs.yml | 1 + resources/default_pipeline_environment.yml | 2 + test/groovy/NpmExecuteTest.groovy | 56 ++++++++++++++ vars/npmExecute.groovy | 73 +++++++++++++++++++ 9 files changed, 167 insertions(+), 12 deletions(-) create mode 100644 documentation/docs/steps/npmExecute.md create mode 100644 test/groovy/NpmExecuteTest.groovy create mode 100644 vars/npmExecute.groovy diff --git a/documentation/docs/steps/checkChangeInDevelopment.md b/documentation/docs/steps/checkChangeInDevelopment.md index ecf035b39..b164dce27 100644 --- a/documentation/docs/steps/checkChangeInDevelopment.md +++ b/documentation/docs/steps/checkChangeInDevelopment.md @@ -2,7 +2,7 @@ ## Description -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Prerequisites @@ -10,11 +10,11 @@ Content here is generated from corresponnding step, see `vars`. ## Parameters -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Step configuration -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Exceptions diff --git a/documentation/docs/steps/dockerExecute.md b/documentation/docs/steps/dockerExecute.md index 5b4eaa1e9..bb327eb1e 100644 --- a/documentation/docs/steps/dockerExecute.md +++ b/documentation/docs/steps/dockerExecute.md @@ -2,11 +2,11 @@ ## Description -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Parameters -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Kubernetes support @@ -14,7 +14,7 @@ If the Jenkins is setup on a Kubernetes cluster, then you can execute the closur ## Step configuration -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Side effects diff --git a/documentation/docs/steps/dockerExecuteOnKubernetes.md b/documentation/docs/steps/dockerExecuteOnKubernetes.md index 22ddbbbfb..013ce042a 100644 --- a/documentation/docs/steps/dockerExecuteOnKubernetes.md +++ b/documentation/docs/steps/dockerExecuteOnKubernetes.md @@ -2,7 +2,7 @@ ## Description -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Prerequisites @@ -13,11 +13,11 @@ Content here is generated from corresponnding step, see `vars`. ## Parameters -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Step configuration -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Side effects diff --git a/documentation/docs/steps/npmExecute.md b/documentation/docs/steps/npmExecute.md new file mode 100644 index 000000000..619cb9cb1 --- /dev/null +++ b/documentation/docs/steps/npmExecute.md @@ -0,0 +1,23 @@ +# npmExecute + +## Description + +Content here is generated from corresponding step, see `vars`. + +## Parameters + +Content here is generated from corresponding step, see `vars`. + +## Step configuration + +Content here is generated from corresponding step, see `vars`. + +## Exceptions + +None + +## Examples + +```groovy +npmExecute script: this, dockerImage: 'node:8-stretch', npmCommand: 'run build' +``` diff --git a/documentation/docs/steps/uiVeri5ExecuteTests.md b/documentation/docs/steps/uiVeri5ExecuteTests.md index 09816bffa..25e4d9e39 100644 --- a/documentation/docs/steps/uiVeri5ExecuteTests.md +++ b/documentation/docs/steps/uiVeri5ExecuteTests.md @@ -2,17 +2,17 @@ ## Description -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Prerequisites ## Parameters -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Step configuration -Content here is generated from corresponnding step, see `vars`. +Content here is generated from corresponding step, see `vars`. ## Exceptions diff --git a/documentation/mkdocs.yml b/documentation/mkdocs.yml index f766e9799..84af48355 100644 --- a/documentation/mkdocs.yml +++ b/documentation/mkdocs.yml @@ -24,6 +24,7 @@ nav: - mtaBuild: steps/mtaBuild.md - neoDeploy: steps/neoDeploy.md - newmanExecute: steps/newmanExecute.md + - npmExecute: steps/npmExecute.md - pipelineExecute: steps/pipelineExecute.md - pipelineRestartSteps: steps/pipelineRestartSteps.md - pipelineStashFiles: steps/pipelineStashFiles.md diff --git a/resources/default_pipeline_environment.yml b/resources/default_pipeline_environment.yml index 030d791b0..1a7b95c89 100644 --- a/resources/default_pipeline_environment.yml +++ b/resources/default_pipeline_environment.yml @@ -252,6 +252,8 @@ steps: newmanRunCommand: "run '${config.newmanCollection}' --environment '${config.newmanEnvironment}' --globals '${config.newmanGlobals}' --reporters junit,html --reporter-junit-export 'target/newman/TEST-${collectionDisplayName}.xml' --reporter-html-export 'target/newman/TEST-${collectionDisplayName}.html'" stashContent: - 'tests' + npmExecute: + dockerImage: 'node:8-stretch' pipelineRestartSteps: sendMail: true timeoutInSeconds: 900 diff --git a/test/groovy/NpmExecuteTest.groovy b/test/groovy/NpmExecuteTest.groovy new file mode 100644 index 000000000..610f23ad3 --- /dev/null +++ b/test/groovy/NpmExecuteTest.groovy @@ -0,0 +1,56 @@ +import static org.junit.Assert.assertEquals +import hudson.AbortException +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException +import org.junit.rules.RuleChain +import util.BasePiperTest +import util.JenkinsDockerExecuteRule +import util.JenkinsReadYamlRule +import util.JenkinsShellCallRule +import util.JenkinsStepRule +import util.Rules + +class NpmExecuteTest extends BasePiperTest { + + private ExpectedException thrown = new ExpectedException().none() + private JenkinsShellCallRule shellRule = new JenkinsShellCallRule(this) + private JenkinsDockerExecuteRule dockerExecuteRule = new JenkinsDockerExecuteRule(this) + private JenkinsStepRule stepRule = new JenkinsStepRule(this) + private JenkinsReadYamlRule yamlRule = new JenkinsReadYamlRule(this) + + @Rule + public RuleChain ruleChain = Rules + .getCommonRules(this) + .around(thrown) + .around(yamlRule) + .around(dockerExecuteRule) + .around(shellRule) + .around(stepRule) + + @Before + void init() { + helper.registerAllowedMethod 'fileExists', [String], { s -> s == 'package.json' } + } + + @Test + void testNpmExecute() { + stepRule.step.npmExecute(script: nullScript, dockerImage: 'node:8-stretch') + assertEquals 'node:8-stretch', dockerExecuteRule.dockerParams.dockerImage + } + + @Test + void testNpmExecuteWithClosure() { + stepRule.step.npmExecute(script: nullScript, dockerImage: 'node:8-stretch', npmCommand: 'run build') { } + assert shellRule.shell.find { c -> c.contains('npm run build') } + } + + @Test + void testNoPackageJson() { + helper.registerAllowedMethod 'fileExists', [String], { false } + thrown.expect AbortException + thrown.expectMessage '[npmExecute] package.json is not found.' + stepRule.step.npmExecute(script: nullScript, dockerImage: 'node:8-stretch', npmCommand: 'run build') + } +} diff --git a/vars/npmExecute.groovy b/vars/npmExecute.groovy new file mode 100644 index 000000000..06e980737 --- /dev/null +++ b/vars/npmExecute.groovy @@ -0,0 +1,73 @@ +import static com.sap.piper.Prerequisites.checkScript +import com.sap.piper.GenerateDocumentation +import com.sap.piper.ConfigurationHelper +import com.sap.piper.Utils +import groovy.transform.Field + +@Field def STEP_NAME = getClass().getName() +@Field Set GENERAL_CONFIG_KEYS = [] +@Field Set STEP_CONFIG_KEYS = [ + /** + * Name of the docker image that should be used, in which node should be installed and configured. Default value is 'node:8-stretch'. + */ + 'dockerImage', + /** + * URL of default NPM registry + */ + 'defaultNpmRegistry', + /** + * Which NPM command should be executed. + */ + 'npmCommand'] +@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS + [ + /** + * Docker options to be set when starting the container. + */ + 'dockerOptions'] +/** + * Executes NPM commands inside a docker container. + * Docker image, docker options and npm commands can be specified or configured. + */ +@GenerateDocumentation +void call(Map parameters = [:], body = null) { + handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) { + + final script = checkScript(this, parameters) ?: this + + // load default & individual configuration + Map configuration = ConfigurationHelper.newInstance(this) + .loadStepDefaults() + .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS) + .mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS) + .mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS) + .mixin(parameters, PARAMETER_KEYS) + .use() + + new Utils().pushToSWA([ + step: STEP_NAME, + stepParamKey1: 'scriptMissing', + stepParam1: parameters?.script == null + ], configuration) + + try { + if (!fileExists('package.json')) { + error "[${STEP_NAME}] package.json is not found." + } + dockerExecute(script: script, dockerImage: configuration.dockerImage, dockerOptions: configuration.dockerOptions) { + if (configuration.defaultNpmRegistry) { + sh "npm config set registry ${configuration.defaultNpmRegistry}" + } + if (configuration.npmCommand) { + sh "npm ${configuration.npmCommand}" + } + if (body) { + body() + } + } + } catch (Exception e) { + println "Error while executing npm. Here are the logs:" + sh "cat ~/.npm/_logs/*" + throw e + } + } +} From 35451738d084f6fb37d79e9a7444dadc2ea4ba5d Mon Sep 17 00:00:00 2001 From: Florian Wilhelm <2292245+fwilhe@users.noreply.github.com> Date: Fri, 22 Feb 2019 10:24:51 +0100 Subject: [PATCH 09/11] Add jenkins controller utility classes for integration tests (#477) --- src/com/sap/piper/Utils.groovy | 8 ++ .../piper/testutils/JenkinsController.groovy | 122 ++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 src/com/sap/piper/testutils/JenkinsController.groovy diff --git a/src/com/sap/piper/Utils.groovy b/src/com/sap/piper/Utils.groovy index 47f1e8f49..c8587bb7f 100644 --- a/src/com/sap/piper/Utils.groovy +++ b/src/com/sap/piper/Utils.groovy @@ -2,6 +2,7 @@ package com.sap.piper import com.cloudbees.groovy.cps.NonCPS import com.sap.piper.analytics.Telemetry +import groovy.text.SimpleTemplateEngine import java.nio.charset.StandardCharsets import java.security.MessageDigest @@ -95,3 +96,10 @@ void pushToSWA(Map parameters, Map config) { // some error occured in telemetry reporting. This should not break anything though. } } + +@NonCPS +static String fillTemplate(String templateText, Map binding){ + def engine = new SimpleTemplateEngine() + String result = engine.createTemplate(templateText).make(binding) + return result +} diff --git a/src/com/sap/piper/testutils/JenkinsController.groovy b/src/com/sap/piper/testutils/JenkinsController.groovy new file mode 100644 index 000000000..1e4d0476d --- /dev/null +++ b/src/com/sap/piper/testutils/JenkinsController.groovy @@ -0,0 +1,122 @@ +package com.sap.piper.jenkins + +import com.cloudbees.groovy.cps.NonCPS + +class JenkinsController implements Serializable { + def script + String jenkinsUrl + def timeout + + JenkinsController(script, String jenkinsUrl = "http://localhost:8080", timeout = 3600) { + this.script = script + this.jenkinsUrl = jenkinsUrl + this.timeout = timeout + } + + def waitForJenkinsStarted() { + def timeout = 120 + def timePerLoop = 5 + + for (int i = 0; i < timeout; i += timePerLoop) { + script.sleep timePerLoop + try { + if (retrieveJenkinsStatus() == 'NORMAL') { + return true + } + } catch (Exception e) { + script.echo "Could not retrieve status for Jenkins at ${jenkinsUrl}/api/json. Message: ${e.getMessage()}. Retrying..." + e.printStackTrace() + continue + } + return false + } + script.error("Timeout: Jenkins did not start within the expected time frame.") + } + + private retrieveJenkinsStatus() { + def apiUrl = "${jenkinsUrl}/api/json" + script.echo "Checking Jenkins Status" + def response = getTextFromUrl(apiUrl) + def result = script.readJSON text: response + return result.mode + } + + //Trigger scanning of the multi branch builds + def buildJob(String jobName) { + script.sh "curl -s -X POST ${jenkinsUrl}/job/${URLEncoder.encode(jobName, 'UTF-8')}/build" + } + + def waitForSuccess(String jobName, String branch) { + if (this.waitForJobStatus(jobName, branch, 'SUCCESS')) { + this.printConsoleText(jobName, branch) + script.echo "Build was successful" + } else { + this.printConsoleText(jobName, branch) + script.error("Build of ${jobName} ${branch} was not successfull") + } + } + + def getBuildUrl(String jobName, String branch) { + return "${jenkinsUrl}/job/${URLEncoder.encode(jobName, 'UTF-8')}/job/${URLEncoder.encode(branch, 'UTF-8')}/lastBuild/" + } + + def waitForJobStatus(String jobName, String branch, String status) { + def buildUrl = getBuildUrl(jobName, branch) + def timePerLoop = 10 + + for (int i = 0; i < timeout; i += timePerLoop) { + script.sleep timePerLoop + try { + script.echo "Checking Build Status of ${jobName} ${branch}" + def buildInformation = retrieveBuildInformation(jobName, branch) + + if (buildInformation.building) { + script.echo "Build is still in progress" + continue + } + if (buildInformation.result == status) { + return true + } + } catch (Exception e) { + script.echo "Could not retrieve status for ${buildUrl}. Message: ${e.getMessage()}. Retrying..." + continue + } + return false + } + script.error("Timeout: Build of job ${jobName}, branch ${branch} did not finish in the expected time frame.") + } + + def getConsoleText(String jobName, String branch) { + def consoleUrl = this.getBuildUrl(jobName, branch) + "/consoleText" + return getTextFromUrl(consoleUrl) + } + + def printConsoleText(String jobName, String branch) { + String consoleOutput = getConsoleText(jobName, branch) + + script.echo '***********************************************' + script.echo '** Begin Output of Example Application Build **' + script.echo '***********************************************' + + script.echo consoleOutput + + script.echo '*********************************************' + script.echo '** End Output of Example Application Build **' + script.echo '*********************************************' + } + + def retrieveBuildInformation(String jobName, String branch) { + def buildUrl = getBuildUrl(jobName, branch) + def url = "${buildUrl}/api/json" + script.echo "Checking Build Status of ${jobName} ${branch}" + script.echo "${jenkinsUrl}/job/${URLEncoder.encode(jobName, 'UTF-8')}/job/${URLEncoder.encode(branch, 'UTF-8')}/" + def response = getTextFromUrl(url) + def result = script.readJSON text: response + return result + } + + @NonCPS + private static String getTextFromUrl(url) { + return new URL(url).getText() + } +} From b13c6e1202809ea74f04ab82763c588dec4bb611 Mon Sep 17 00:00:00 2001 From: Florian Wilhelm <2292245+fwilhe@users.noreply.github.com> Date: Fri, 22 Feb 2019 13:31:50 +0100 Subject: [PATCH 10/11] Create s4sdk consumer tests for neo environment (#524) --- .gitignore | 2 +- .travis.yml | 6 ++++-- consumer-test/runTests.sh | 14 ------------- consumer-test/s4sdk/CloudFoundry/runTests.sh | 6 ++++++ .../s4sdk/NeoEnvironment/runTests.sh | 6 ++++++ consumer-test/{ => s4sdk}/jenkins.yml | 0 consumer-test/s4sdk/prepareTests.sh | 20 +++++++++++++++++++ 7 files changed, 37 insertions(+), 17 deletions(-) delete mode 100755 consumer-test/runTests.sh create mode 100755 consumer-test/s4sdk/CloudFoundry/runTests.sh create mode 100755 consumer-test/s4sdk/NeoEnvironment/runTests.sh rename consumer-test/{ => s4sdk}/jenkins.yml (100%) create mode 100755 consumer-test/s4sdk/prepareTests.sh diff --git a/.gitignore b/.gitignore index e286faf6a..f26049779 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,4 @@ target/ targets/ documentation/docs-gen -consumer-test/workspace +consumer-test/**/workspace diff --git a/.travis.yml b/.travis.yml index d5cae0e77..50b9ca4c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,10 @@ jobs: cp -r documentation/docs documentation/docs-tmp documentation/bin/createDocu.sh vars documentation/docs-tmp/steps docker run --rm -it -v ${TRAVIS_BUILD_DIR}:/docs -w /docs/documentation squidfunk/mkdocs-material:3.0.4 build --clean --verbose --strict - - name: Consumer Tests for s4sdk pipeline - script: cd consumer-test && chmod +x runTests.sh && ./runTests.sh + - name: Consumer Tests for s4sdk pipeline (CloudFoundry) + script: cd consumer-test/s4sdk/CloudFoundry && chmod +x runTests.sh && ./runTests.sh + - name: Consumer Tests for s4sdk pipeline (Neo Environment) + script: cd consumer-test/s4sdk/NeoEnvironment && chmod +x runTests.sh && ./runTests.sh - stage: Docs name: Deploy diff --git a/consumer-test/runTests.sh b/consumer-test/runTests.sh deleted file mode 100755 index 9a3095f20..000000000 --- a/consumer-test/runTests.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -e - -LIBRARY_VERSION_UNDER_TEST=$(git log --format="%H" -n 1) -REPOSITORY_UNDER_TEST=${TRAVIS_REPO_SLUG:-SAP/jenkins-library} - -rm -rf workspace -git clone -b consumer-test https://github.com/sap/cloud-s4-sdk-book workspace -cp -f jenkins.yml workspace -cd workspace -sed -i -e "s:__REPO_SLUG__:${REPOSITORY_UNDER_TEST}:g" jenkins.yml -echo "@Library(\"piper-library-os@$LIBRARY_VERSION_UNDER_TEST\") _" | cat - Jenkinsfile > temp && mv temp Jenkinsfile -git commit --all --author="piper-testing-bot " --message="Set piper lib version for test" - -docker run -v /var/run/docker.sock:/var/run/docker.sock -v "${PWD}":/workspace -v /tmp -e CASC_JENKINS_CONFIG=/workspace/jenkins.yml -e CX_INFRA_IT_CF_USERNAME -e CX_INFRA_IT_CF_PASSWORD -e BRANCH_NAME=consumer-test ppiper/jenkinsfile-runner diff --git a/consumer-test/s4sdk/CloudFoundry/runTests.sh b/consumer-test/s4sdk/CloudFoundry/runTests.sh new file mode 100755 index 000000000..74130533b --- /dev/null +++ b/consumer-test/s4sdk/CloudFoundry/runTests.sh @@ -0,0 +1,6 @@ +#!/bin/bash -e + +source ../prepareTests.sh consumer-test + +docker run -v /var/run/docker.sock:/var/run/docker.sock -v "${PWD}":/workspace -v /tmp -e CASC_JENKINS_CONFIG=/workspace/jenkins.yml \ + -e CX_INFRA_IT_CF_USERNAME -e CX_INFRA_IT_CF_PASSWORD -e BRANCH_NAME=consumer-test ppiper/jenkinsfile-runner diff --git a/consumer-test/s4sdk/NeoEnvironment/runTests.sh b/consumer-test/s4sdk/NeoEnvironment/runTests.sh new file mode 100755 index 000000000..5fc36bab1 --- /dev/null +++ b/consumer-test/s4sdk/NeoEnvironment/runTests.sh @@ -0,0 +1,6 @@ +#!/bin/bash -e + +source ../prepareTests.sh consumer-test-neo + +docker run -v /var/run/docker.sock:/var/run/docker.sock -v "${PWD}":/workspace -v /tmp -e CASC_JENKINS_CONFIG=/workspace/jenkins.yml \ + -e CX_INFRA_IT_CF_USERNAME -e CX_INFRA_IT_CF_PASSWORD -e BRANCH_NAME=consumer-test-neo ppiper/jenkinsfile-runner diff --git a/consumer-test/jenkins.yml b/consumer-test/s4sdk/jenkins.yml similarity index 100% rename from consumer-test/jenkins.yml rename to consumer-test/s4sdk/jenkins.yml diff --git a/consumer-test/s4sdk/prepareTests.sh b/consumer-test/s4sdk/prepareTests.sh new file mode 100755 index 000000000..2663a1c9b --- /dev/null +++ b/consumer-test/s4sdk/prepareTests.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +EXAMPLE_PROJECT_BRANCH=$1 + +LIBRARY_VERSION_UNDER_TEST=$(git log --format="%H" -n 1) +REPOSITORY_UNDER_TEST=${TRAVIS_REPO_SLUG:-SAP/jenkins-library} + +rm -rf workspace +git clone -b "${EXAMPLE_PROJECT_BRANCH}" https://github.com/sap/cloud-s4-sdk-book workspace +cp -f ../jenkins.yml workspace +cd workspace || exit 1 + +# Configure path to library-repository under test in Jenkins config +sed -i -e "s:__REPO_SLUG__:${REPOSITORY_UNDER_TEST}:g" jenkins.yml + +# Force usage of library version under test by setting it in the Jenkinsfile which is then the first definition and thus has the highest precedence +echo "@Library(\"piper-library-os@$LIBRARY_VERSION_UNDER_TEST\") _" | cat - Jenkinsfile > temp && mv temp Jenkinsfile + +# Commit the changed version because artifactSetVersion expects the git repo not to be dirty +git commit --all --author="piper-testing-bot " --message="Set piper lib version for test" From 70a002b094473d53486c97eb38190382b7e8f177 Mon Sep 17 00:00:00 2001 From: Christoph Szymanski Date: Tue, 26 Feb 2019 14:38:44 +0100 Subject: [PATCH 11/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3167d9055..edcecd3df 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ Register to our [google group][google-group] in order to get updates or for aski Read and understand our [contribution guidelines][piper-library-contribution] before opening a pull request. -# [License][piper-library-license] +# License Copyright (c) 2017 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted