1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00

Merge remote-tracking branch 'github/master' into HEAD

This commit is contained in:
Marcus Holl 2019-02-13 09:05:28 +01:00
commit 2d7079a8c9
14 changed files with 208 additions and 85 deletions

View File

@ -72,7 +72,7 @@ class TemplateHelper {
parameters.keySet().toSorted().each {
def props = parameters.get(it)
t += "| `${it}` | ${props.GENERAL_CONFIG ? 'X' : ''} | ${props.STEP_CONFIG ? 'X' : ''} | ${props.STAGE_CONFIG ? 'X' : ''} |\n"
t += "| `${it}` | ${props.GENERAL_CONFIG ? 'X' : ''} | ${props.STEP_CONFIG ? 'X' : ''} | ${props.STAGE_CONFIG ? 'X' : ''} |\n"
}
t.trim()

View File

@ -0,0 +1,65 @@
# Build and Deploy Applications with Jenkins and the SAP Cloud Application Programming Model
Set up a basic continuous delivery process for developing applications according to the SAP Cloud Application Programming Model.
## Prerequisites
* You have an account on SAP Cloud Platform in the Cloud Foundry environment. See [Accounts](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/8ed4a705efa0431b910056c0acdbf377.html).
* You have downloaded and installed the Cloud Foundry command line interface (CLI). See [Download and Install the Cloud Foundry Command Line Interface](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/afc3f643ec6942a283daad6cdf1b4936.html).
* You have installed the multi-target application plug-in for the Cloud Foundry command line interface. See [Install the Multi-Target Application Plug-in in the Cloud Foundry Environment](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/27f3af39c2584d4ea8c15ba8c282fd75.html).
* You have installed the Java Runtime Environment 8.
* You have installed Jenkins 2.60.3 or higher.
* You have set up Project “Piper”. See [README](https://github.com/SAP/jenkins-library/blob/master/README.md).
* You have installed the Multi-Target Application (MTA) Archive Builder 1.0.6 or newer. See [SAP Development Tools](https://tools.hana.ondemand.com/#cloud).
* You have installed Node.js including node and npm. See [Node.js](https://nodejs.org/en/download/).
## Context
The Application Programming Model for SAP Cloud Platform is an end-to-end best practice guide for developing applications on SAP Cloud Platform and provides a supportive set of APIs, languages, and libraries. For more information about the SAP Cloud Application Programming Model, see [Working with the SAP Cloud Application Programming Model](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/00823f91779d4d42aa29a498e0535cdf.html).
In this scenario, we want to show how to implement a basic continuous delivery process for developing applications according to this programming model with the help of project "Piper" on Jenkins. This basic scenario can be adapted and enriched according to your specific needs.
## Example
### Jenkinsfile
```groovy
@Library('piper-library-os') _
node(){
stage('Prepare') {
deleteDir()
checkout scm
setupCommonPipelineEnvironment script:this
}
stage('Build') {
mtaBuild script:this
}
stage('Deploy') {
cloudFoundryDeploy script:this, deployTool:'mtaDeployPlugin'
}
}
```
### Configuration (`.pipeline/config.yml`)
```yaml
steps:
mtaBuild
buildTarget: 'CF'
cloudFoundryDeploy:
cloudFoundry:
credentialsId: 'CF'
apiEndpoint: '<CF Endpoint>'
org: '<CF Organization>'
space: '<CF Space>'
```
### Parameters
For the detailed description of the relevant parameters, see:
* [mtaBuild](https://sap.github.io/jenkins-library/steps/mtaBuild/)
* [cloudFoundryDeploy](https://sap.github.io/jenkins-library/steps/cloudFoundryDeploy/)

View File

@ -38,7 +38,7 @@ The basic workflow is as follows:
5. As soon as the development process is completed, the change document in SAP Solution Manager can be set to status `to be tested` and all components can be transported to the test system.
![Hybrid Application Development Workflow](../images/Scenario_SolMan.png "Hybrid Application Development Workflow")
##### Hybrid Application Development Worflow
###### Hybrid Application Development Workflow
## Example

View File

@ -2,7 +2,7 @@
## Description
Executes a closure inside a container in a kubernetes pod. Proxy environment variables defined on the Jenkins machine are also available in the container.
Content here is generated from corresponnding step, see `vars`.
## Prerequisites
@ -13,65 +13,11 @@ Executes a closure inside a container in a kubernetes pod. Proxy environment var
## Parameters
| parameter | mandatory | default | possible values |
| ----------|-----------|---------|-----------------|
|script|yes|||
|containerCommand|no|||
|containerCommands|no|||
|containerEnvVars|no|||
|containerPullImageFlags|no|true|boolean value: `true`, `false` |
|containerMap|no|`[:]`||
|containerName|no|||
|containerPortMappings|no|||
|containerShell|no|||
|containerWorkspaces|no|||
|dockerEnvVars|no|`[:]`||
|dockerImage|yes|||
|dockerPullImage|no|true|boolean value: `true`, `false` |
|dockerWorkspace|no|`''`||
|jenkinsKubernetes|no|`[jnlpAgent:s4sdk/jenkins-agent-k8s:latest]`||
|stashExcludes|no|`[workspace:nohup.out]`||
|stashIncludes|no|`[workspace:**/*.*]`||
* `script` defines the global script environment of the Jenkins file run. Typically `this` is passed to this parameter. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for storing the measured duration.
* `containerCommand`: allows to specify start command for container created with dockerImage parameter to overwrite Piper default (`/usr/bin/tail -f /dev/null`).
* `containerCommands` specifies start command for containers to overwrite Piper default (`/usr/bin/tail -f /dev/null`). If container's defaultstart command should be used provide empty string like: `['selenium/standalone-chrome': '']`.
* `containerEnvVars` specifies environment variables per container. If not provided `dockerEnvVars` will be used.
* `containerPullImageFlags` specifies the pullImage flag per container.
* `containerMap` A map of docker image to the name of the container. The pod will be created with all the images from this map and they are labled based on the value field of each map entry.
Example: `['maven:3.5-jdk-8-alpine': 'mavenExecute', 'selenium/standalone-chrome': 'selenium', 'famiko/jmeter-base': 'checkJMeter', 's4sdk/docker-cf-cli': 'cloudfoundry']`
* `containerName`: optional configuration in combination with containerMap to define the container where the commands should be executed in
* `containerPortMappings`: Map which defines per docker image the port mappings, like `containerPortMappings: ['selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]]`
* `containerShell` allows to specify the shell to be executed for container with containerName
* `containerWorkspaces` specifies workspace (=home directory of user) per container. If not provided `dockerWorkspace` will be used. If empty, home directory will not be set.
* `dockerImage` Name of the docker image that should be used. If empty, Docker is not used.
* `dockerEnvVars` Environment variables to set in the container, e.g. [http_proxy:'proxy:8080']
* `dockerPullImage`: Set this to 'false' to bypass a docker image pull. Usefull during development process. Allows testing of images which are available in the local registry only.
* `dockerWorkspace` Docker options to be set when starting the container. It can be a list or a string.
Content here is generated from corresponnding step, see `vars`.
## 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||||
|containerCommands||X|X|
|containerEnvVars||X|X|
|containerPullImageFlags||X|X|
|containerMap||X|X|
|containerName||X|X|
|containerPortMappings||X|X|
|containerWorkspaces||X|X|
|dockerEnvVars||X|X|
|dockerImage||X|X|
|dockerPullImage||X|X|
|dockerWorkspace||X|X|
|jenkinsKubernetes|X|||
|stashExcludes||X|X|
|stashIncludes||X|X|
Content here is generated from corresponnding step, see `vars`.
## Side effects

View File

@ -55,7 +55,9 @@ testsPublishResults script: this, junit: [pattern: '**/newman/TEST-*.xml']
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 |
In following sections the configuration is possible:
| parameter | general | step | stage |
|-----------|---------|------|-------|
| `dockerImage` |  | X | X |
| `failOnError` |  | X | X |

View File

@ -33,6 +33,7 @@ Available parameters:
| parameter | mandatory | default | possible values |
| ----------|-----------|---------|-----------------|
| script | yes | | |
| `failOnError` | no | `false` | `true`, `false` |
| junit | no | `false` | true, false |
| jacoco | no | `false` | true, false |
| cobertura | no | `false` | true, false |
@ -43,6 +44,7 @@ Available parameters:
with the `this` parameter, as in `script: this`.
This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md)
for retrieving, for example, configuration parameters.
* `failOnError` - If `failOnError` it set to `true` the step will fail the build if JUnit detected any failing tests.
* `junit` - Publishes test results files in JUnit format with the [JUnit Plugin](https://plugins.jenkins.io/junit).
* `jacoco` - Publishes code coverage with the [JaCoCo plugin](https://plugins.jenkins.io/jacoco) .
* `cobertura` - Publishes code coverage with the [Cobertura plugin](https://plugins.jenkins.io/cobertura).

View File

@ -35,9 +35,11 @@ nav:
- transportRequestCreate: steps/transportRequestCreate.md
- transportRequestRelease: steps/transportRequestRelease.md
- transportRequestUploadFile: steps/transportRequestUploadFile.md
- uiVeri5ExecuteTests: steps/uiVeri5ExecuteTests.md
- 'Scenarios':
- 'Build and Deploy Hybrid Applications with Jenkins and SAP Solution Manager': scenarios/changeManagement.md
- 'Create a Pipeline for SAP UI5 or SAP Fiori on SAP Cloud Platform': scenarios/ui5-sap-cp/Readme.md
- 'Build and Deploy SAP UI5 or SAP Fiori Applications on SAP Cloud Platform with Jenkins': scenarios/ui5-sap-cp/Readme.md
- 'Build and Deploy Applications with Jenkins and the SAP Cloud Application Programming Model': scenarios/CAP_Scenario.md
- 'Required Plugins': jenkins/requiredPlugins.md
theme:

View File

@ -317,6 +317,7 @@ steps:
toJson: false
toHtml: false
testsPublishResults:
failOnError: false
junit:
pattern: '**/TEST-*.xml'
updateResults: false

View File

@ -3,6 +3,7 @@ package com.sap.piper
import com.cloudbees.groovy.cps.NonCPS
import jenkins.model.Jenkins
import org.jenkinsci.plugins.workflow.steps.MissingContextVariableException
import hudson.tasks.junit.TestResultAction
@API
@NonCPS
@ -10,6 +11,14 @@ static def isPluginActive(pluginId) {
return Jenkins.instance.pluginManager.plugins.find { p -> p.isActive() && p.getShortName() == pluginId }
}
static boolean hasTestFailures(build){
//build: https://javadoc.jenkins.io/plugin/workflow-support/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapper.html
//getRawBuild: https://javadoc.jenkins.io/plugin/workflow-job/org/jenkinsci/plugins/workflow/job/WorkflowRun.html
//getAction: http://www.hudson-ci.org/javadoc/hudson/tasks/junit/TestResultAction.html
def action = build?.getRawBuild()?.getAction(TestResultAction.class)
return action && action.getFailCount() != 0
}
def nodeAvailable() {
try {
sh "echo 'Node is available!'"

View File

@ -3,6 +3,7 @@ import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.rules.ExpectedException
import util.BasePiperTest
import util.JenkinsReadYamlRule
@ -16,12 +17,14 @@ class TestsPublishResultsTest extends BasePiperTest {
Map publisherStepOptions
List archiveStepPatterns
private ExpectedException thrown = ExpectedException.none()
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
@Rule
public RuleChain ruleChain = Rules
.getCommonRules(this)
.around(new JenkinsReadYamlRule(this))
.around(thrown)
.around(stepRule)
@Before
@ -126,4 +129,40 @@ class TestsPublishResultsTest extends BasePiperTest {
assertTrue('Cobertura options are not empty', publisherStepOptions.cobertura == null)
assertTrue('JMeter options are not empty', publisherStepOptions.jmeter == null)
}
@Test
void testBuildResultStatus() throws Exception {
stepRule.step.testsPublishResults(script: nullScript)
assertJobStatusSuccess()
}
@Test
void testBuildWithTestFailuresAndWithoutFailOnError() throws Exception {
nullScript.currentBuild.getRawBuild = {
return [getAction: { type ->
return [getFailCount: {
return 6
}]
}]
}
stepRule.step.testsPublishResults(script: nullScript)
assertJobStatusSuccess()
}
@Test
void testBuildWithTestFailuresAndWithFailOnError() throws Exception {
nullScript.currentBuild.getRawBuild = {
return [getAction: { type ->
return [getFailCount: {
return 6
}]
}]
}
thrown.expect(hudson.AbortException)
thrown.expectMessage('[testsPublishResults] Some tests failed!')
stepRule.step.testsPublishResults(script: nullScript, failOnError: true)
}
}

View File

@ -1,5 +1,4 @@
#!groovy
package steps
import static org.hamcrest.Matchers.*

View File

@ -152,11 +152,9 @@ class LibraryLoadingTestExecutionListener extends AbstractTestExecutionListener
helper.registerAllowedMethod("node", [String.class, Closure.class], null)
helper.registerAllowedMethod("node", [Closure.class], null)
helper.registerAllowedMethod( method('sh', Map.class), {m ->
println "sh-command: $m.script"
return ""
} )
helper.registerAllowedMethod( method('sh', String.class), {s ->
println "sh-command: $s"
return ""
} )
helper.registerAllowedMethod("checkout", [Map.class], null)

View File

@ -1,6 +1,7 @@
import static com.sap.piper.Prerequisites.checkScript
import com.sap.piper.ConfigurationHelper
import com.sap.piper.GenerateDocumentation
import com.sap.piper.JenkinsUtils
import com.sap.piper.Utils
import com.sap.piper.k8s.SystemEnv
@ -9,25 +10,77 @@ import hudson.AbortException
@Field def STEP_NAME = getClass().getName()
@Field def PLUGIN_ID_KUBERNETES = 'kubernetes'
@Field Set GENERAL_CONFIG_KEYS = [
'jenkinsKubernetes'
]
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
'containerCommand', // specify start command for container created with dockerImage parameter to overwrite Piper default (`/usr/bin/tail -f /dev/null`).
'containerCommands', //specify start command for containers to overwrite Piper default (`/usr/bin/tail -f /dev/null`). If container's default start command should be used provide empty string like: `['selenium/standalone-chrome': '']`
'containerEnvVars', //specify environment variables per container. If not provided dockerEnvVars will be used
'containerPullImageFlags', // specifies the pullImage flag per container.
'containerMap', //specify multiple images which then form a kubernetes pod, example: containerMap: ['maven:3.5-jdk-8-alpine': 'mavenexecute','selenium/standalone-chrome': 'selenium']
'containerName', //optional configuration in combination with containerMap to define the container where the commands should be executed in
'containerPortMappings', //map which defines per docker image the port mappings, like containerPortMappings: ['selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]]
'containerShell', // allows to specify the shell to be executed for container with containerName
'containerWorkspaces', //specify workspace (=home directory of user) per container. If not provided dockerWorkspace will be used. If empty, home directory will not be set.
'dockerImage',
'dockerPullImage',
'dockerWorkspace',
/**
* Allows to specify start command for container created with dockerImage parameter to overwrite Piper default (`/usr/bin/tail -f /dev/null`).
*/
'containerCommand',
/**
* Specifies start command for containers to overwrite Piper default (`/usr/bin/tail -f /dev/null`).
* If container's defaultstart command should be used provide empty string like: `['selenium/standalone-chrome': '']`.
*/
'containerCommands',
/**
* Specifies environment variables per container. If not provided `dockerEnvVars` will be used.
*/
'containerEnvVars',
/**
* A map of docker image to the name of the container. The pod will be created with all the images from this map and they are labled based on the value field of each map entry.
* Example: `['maven:3.5-jdk-8-alpine': 'mavenExecute', 'selenium/standalone-chrome': 'selenium', 'famiko/jmeter-base': 'checkJMeter', 's4sdk/docker-cf-cli': 'cloudfoundry']`
*/
'containerMap',
/**
* Optional configuration in combination with containerMap to define the container where the commands should be executed in.
*/
'containerName',
/**
* Map which defines per docker image the port mappings, e.g. `containerPortMappings: ['selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]]`.
*/
'containerPortMappings',
/**
* Specifies the pullImage flag per container.
*/
'containerPullImageFlags',
/**
* Allows to specify the shell to be executed for container with containerName.
*/
'containerShell',
/**
* Specifies a dedicated user home directory per container which will be passed as value for environment variable `HOME`. If not provided `dockerWorkspace` will be used.
*/
'containerWorkspaces',
/**
* Environment variables to set in the container, e.g. [http_proxy:'proxy:8080'].
*/
'dockerEnvVars',
/**
* Name of the docker image that should be used. If empty, Docker is not used.
*/
'dockerImage',
/**
* Set this to 'false' to bypass a docker image pull.
* Usefull during development process. Allows testing of images which are available in the local registry only.
*/
'dockerPullImage',
/**
* Specifies a dedicated user home directory for the container which will be passed as value for environment variable `HOME`.
*/
'dockerWorkspace',
/**
* Specific stashes that should be considered for the step execution.
*/
'stashContent',
/**
*
*/
'stashExcludes',
/**
*
*/
'stashIncludes'
])
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.minus([
@ -35,6 +88,11 @@ import hudson.AbortException
'stashExcludes'
])
/**
* Executes a closure inside a container in a kubernetes pod.
* Proxy environment variables defined on the Jenkins machine are also available in the container.
*/
@GenerateDocumentation
void call(Map parameters = [:], body) {
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
@ -175,7 +233,7 @@ private List getContainerList(config) {
return result
}
/**
/*
* Returns a list of envVar object consisting of set
* environment variables, params (Parametrized Build) and working directory.
* (Kubernetes-Plugin only!)

View File

@ -3,6 +3,7 @@ import static com.sap.piper.Prerequisites.checkScript
import com.cloudbees.groovy.cps.NonCPS
import com.sap.piper.ConfigurationHelper
import com.sap.piper.JenkinsUtils
import com.sap.piper.MapUtils
import com.sap.piper.Utils
import groovy.transform.Field
@ -13,7 +14,9 @@ import groovy.transform.Field
@Field def STEP_NAME = getClass().getName()
@Field Set GENERAL_CONFIG_KEYS = TOOLS
@Field Set STEP_CONFIG_KEYS = TOOLS
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
'failOnError'
])
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
/**
@ -24,10 +27,7 @@ import groovy.transform.Field
*/
void call(Map parameters = [:]) {
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
def script = checkScript(this, parameters)
if (script == null)
script = this
def script = checkScript(this, parameters) ?: this
prepare(parameters)
@ -46,13 +46,15 @@ void call(Map parameters = [:]) {
stepParam1: parameters?.script == null
], configuration)
// UNIT TESTS
publishJUnitReport(configuration.get('junit'))
// CODE COVERAGE
publishJacocoReport(configuration.get('jacoco'))
publishCoberturaReport(configuration.get('cobertura'))
// PERFORMANCE
publishJMeterReport(configuration.get('jmeter'))
if (configuration.failOnError && JenkinsUtils.hasTestFailures(script.currentBuild)) {
script.currentBuild.result = 'FAILURE'
error "[${STEP_NAME}] Some tests failed!"
}
}
}