mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-30 05:59:39 +02:00
Merge remote-tracking branch 'github/master' into HEAD
This commit is contained in:
commit
4b8b1abb1c
17
.codeclimate.yml
Normal file
17
.codeclimate.yml
Normal file
@ -0,0 +1,17 @@
|
||||
plugins:
|
||||
codenarc:
|
||||
enabled: true
|
||||
editorconfig:
|
||||
enabled: true
|
||||
config:
|
||||
editorconfig: .editorconfig
|
||||
fixme:
|
||||
enabled: true
|
||||
config:
|
||||
strings:
|
||||
- TODO
|
||||
- FIXME
|
||||
markdownlint:
|
||||
enabled: true
|
||||
shellcheck:
|
||||
enabled: true
|
49
.travis.yml
49
.travis.yml
@ -5,33 +5,38 @@ language: groovy
|
||||
sudo: required
|
||||
services:
|
||||
- docker
|
||||
before_install:
|
||||
- docker pull squidfunk/mkdocs-material
|
||||
script:
|
||||
- mvn clean test --batch-mode
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
|
||||
# Travis Lifecycle: https://docs.travis-ci.com/user/job-lifecycle#the-job-lifecycle
|
||||
# Travis Stages: https://docs.travis-ci.com/user/build-stages/
|
||||
# Travis Conditions: https://docs.travis-ci.com/user/conditional-builds-stages-jobs
|
||||
jobs:
|
||||
include:
|
||||
- stage: Tests
|
||||
name: Unit Tests
|
||||
script: mvn clean test --batch-mode
|
||||
after_success: mvn -DrepoToken=$COVERALLS_REPO_TOKEN org.jacoco:jacoco-maven-plugin:report org.eluder.coveralls:coveralls-maven-plugin:report
|
||||
|
||||
- stage: Docs
|
||||
name: Build
|
||||
if: type = pull_request
|
||||
install: docker pull squidfunk/mkdocs-material:3.0.4
|
||||
script: docker run --rm -it -v ${TRAVIS_BUILD_DIR}:/docs -w /docs/documentation squidfunk/mkdocs-material:3.0.4 build --clean --verbose --strict
|
||||
|
||||
- name: Deploy
|
||||
if: repo = "SAP/jenkins-library" AND branch = master AND NOT type = pull_request
|
||||
install:
|
||||
- docker pull squidfunk/mkdocs-material:3.0.4
|
||||
- |
|
||||
if [[ "${TRAVIS_PULL_REQUEST}" != "false" ]]
|
||||
then
|
||||
docker run --rm -it -v ${TRAVIS_BUILD_DIR}:/docs -w /docs/documentation squidfunk/mkdocs-material build --clean --verbose --strict
|
||||
else
|
||||
# Only in case we are in master branch of the leading SAP repo we would like to deploy,
|
||||
# not from the forks.
|
||||
if [[ "${TRAVIS_BRANCH}" == "master" && "${TRAVIS_REPO_SLUG}" == "SAP/jenkins-library" ]]
|
||||
then
|
||||
echo "Found change on master: Deployment of documentation"
|
||||
PRIVATE_KEY="cfg/id_rsa"
|
||||
openssl aes-256-cbc -K $encrypted_12c8071d2874_key -iv $encrypted_12c8071d2874_iv -in cfg/id_rsa.enc -out "${PRIVATE_KEY}" -d
|
||||
chmod a+x gh-pages-deploy.sh
|
||||
docker run --rm -it --entrypoint "./gh-pages-deploy.sh" -e "TRAVIS_REPO_SLUG=${TRAVIS_REPO_SLUG}" -v ${TRAVIS_BUILD_DIR}:/docs -w /docs squidfunk/mkdocs-material
|
||||
else
|
||||
echo "Publishing documentation skipped."
|
||||
fi
|
||||
fi
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
after_success:
|
||||
- mvn -DrepoToken=$COVERALLS_REPO_TOKEN org.jacoco:jacoco-maven-plugin:report org.eluder.coveralls:coveralls-maven-plugin:report
|
||||
script: docker run --rm -it --entrypoint "./gh-pages-deploy.sh" -e "TRAVIS_REPO_SLUG=${TRAVIS_REPO_SLUG}" -v ${TRAVIS_BUILD_DIR}:/docs -w /docs squidfunk/mkdocs-material:3.0.4
|
||||
# TODO: make use of GHPages deploy provider: https://docs.travis-ci.com/user/deployment/pages/
|
||||
|
||||
#notifications:
|
||||
# slack:
|
||||
# secure: UYzfd4QYLtAX39r8LzV1dYp7cKMhYRRjI/xswMEkR+RgdMWxVPPH3kcsNLwkdNGSPn1b8Aidz8YLss9JolrepWjwI283dK8EUthZAOw03+PmL5X/3nOJ7aGv0sxwYqF5ypltBrerTf6jtPUTcQdtao+0O8bgnzShc6nWWE4MLXonjOm1pZLRUo81un+0bzm8C2ABIeHC6xuZCRycXP5u1mW1nDLK3900uY1rxIDTSZKEzA0IzLQhE9uROvI1r48fW8cKJQQjMMO5PPorq+0eDl2YTE8rQr9ldvuRE7A/ubsOQR0N5F8iAv1JTZXuXGt62fw6eKDQ1h94suEk7X+baV0EwlfhsHXcI1MxRFwxNSr9k1WaVFfA4TrM8XYBAcW3JGRA51ZK3q4EcjpuxpupaA7kZDtH53W7ePzH2TIp6yknln1q+yfcsP7cGv38sSKpKwOyMgAPRElkZzcoo31kw/PLzKPXYJEovRqx/0lWzczbFSscsroNaGCavC02++bUnyUXW2W+PG4gDSBFVZjtrvTPKnZ6DpHXV97x6xC/CzyhFj/Nf+ao/J9IIfocnc4vXJojwS550KIvM7xCDJwa/+29dajj2l6dQqrcOe3UT3O5UGU9I0KkGEDMfkLOD71eRy58qiYz3y953e52DvvzWQJbvfuk8ubMO+Fmn4GyRz8=
|
||||
|
@ -84,14 +84,14 @@ class TemplateHelper {
|
||||
//
|
||||
class Helper {
|
||||
|
||||
static getConfigHelper(classLoader, roots) {
|
||||
static getConfigHelper(classLoader, roots, script) {
|
||||
|
||||
def compilerConfig = new CompilerConfiguration()
|
||||
compilerConfig.setClasspathList( roots )
|
||||
|
||||
new GroovyClassLoader(classLoader, compilerConfig, true)
|
||||
.parseClass(new File('src/com/sap/piper/ConfigurationHelper.groovy'))
|
||||
.newInstance()
|
||||
.newInstance(script, [:])
|
||||
}
|
||||
|
||||
|
||||
@ -439,7 +439,9 @@ def handleStep(stepName, prepareDefaultValuesStep, gse) {
|
||||
|
||||
System.err << "[INFO] Handling step '${stepName}'.\n"
|
||||
|
||||
def defaultConfig = Helper.getConfigHelper(getClass().getClassLoader(), roots).loadStepDefaults(Helper.getDummyScript(prepareDefaultValuesStep, stepName)).use()
|
||||
def defaultConfig = Helper.getConfigHelper(getClass().getClassLoader(),
|
||||
roots,
|
||||
Helper.getDummyScript(prepareDefaultValuesStep, stepName)).use()
|
||||
|
||||
def params = [] as Set
|
||||
|
||||
|
BIN
documentation/docs/images/githubRelease.png
Normal file
BIN
documentation/docs/images/githubRelease.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
@ -61,6 +61,10 @@ Deployment can be done
|
||||
- cfOrg
|
||||
- cfSpace
|
||||
|
||||
!!! note
|
||||
Due to [an incompatible change](https://github.com/cloudfoundry/cli/issues/1445) in the Cloud Foundry CLI, multiple buildpacks are not supported by this step.
|
||||
If your `application` contains a list of `buildpacks` instead a single `buildpack`, this will be automatically re-written by the step when blue-green deployment is used.
|
||||
|
||||
* `deployTool` defines the tool which should be used for deployment.
|
||||
* `deployType` defines the type of deployment, either `standard` deployment which results in a system downtime or a zero-downtime `blue-green` deployment.
|
||||
* `dockerImage` defines the Docker image containing the deployment tools (like cf cli, ...) and `dockerWorkspace` defines the home directory of the default user of the `dockerImage`
|
||||
@ -106,7 +110,11 @@ The following parameters can also be specified as step/stage/general parameters
|
||||
## Example
|
||||
|
||||
```groovy
|
||||
artifactSetVersion script: this, buildTool: 'maven'
|
||||
cloudFoundryDeploy(
|
||||
script: script,
|
||||
deployType: 'blue-green',
|
||||
cloudFoundry: [apiEndpoint: 'https://test.server.com', appName:'cfAppName', credentialsId: 'cfCredentialsId', manifest: 'cfManifest', org: 'cfOrg', space: 'cfSpace'],
|
||||
deployTool: 'cf_native'
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@ Proxy environment variables defined on the Jenkins machine are also available in
|
||||
* `containerPortMappings`: Map which defines per docker image the port mappings, like `containerPortMappings: ['selenium/standalone-chrome': [[name: 'selPort', containerPort: 4444, hostPort: 4444]]]`
|
||||
* `dockerEnvVars`: Environment variables to set in the container, e.g. [http_proxy:'proxy:8080']
|
||||
* `dockerImage`: Name of the docker image that should be used. If empty, Docker is not used and the command is executed directly on the Jenkins system.
|
||||
* `dockerName`: only relevant for Kubernetes case: Name of the container launching `dockerImage`
|
||||
* `dockerName`: Kubernetes case: Name of the container launching `dockerImage`, SideCar: Name of the container in local network
|
||||
* `dockerOptions` Docker options to be set when starting the container. It can be a list or a string.
|
||||
* `dockerVolumeBind` Volumes that should be mounted into the container.
|
||||
* `dockerWorkspace`: only relevant for Kubernetes case: specifies a dedicated user home directory for the container which will be passed as value for environment variable `HOME`
|
||||
|
102
documentation/docs/steps/gaugeExecuteTests.md
Normal file
102
documentation/docs/steps/gaugeExecuteTests.md
Normal file
@ -0,0 +1,102 @@
|
||||
# gaugeExecuteTests
|
||||
|
||||
## Description
|
||||
In this step Gauge ([getgauge.io](http:getgauge.io)) acceptance tests are executed.
|
||||
Using Gauge it will be possible to have a three-tier test layout:
|
||||
* Acceptance Criteria
|
||||
* Test implemenation layer
|
||||
* Application driver layer
|
||||
|
||||
This layout is propagated by Jez Humble and Dave Farley in their book "Continuous Delivery" as a way to create maintainable acceptance test suites (see "Continuous Delivery", p. 190ff).
|
||||
|
||||
Using Gauge it is possible to write test specifications in [Markdown syntax](http://daringfireball.net/projects/markdown/syntax) and therefore allow e.g. product owners to write the relevant acceptance test specifications. At the same time it allows the developer to implement the steps described in the specification in her development environment.
|
||||
|
||||
You can use the sample projects of Gauge, for example: https://github.com/getgauge/gauge-mvn-archetypes
|
||||
|
||||
!!! note "Make sure to run against a Selenium Hub configuration"
|
||||
In the test example of _gauge-archetype-selenium_ please make sure to allow it to run against a Selenium hub:
|
||||
|
||||
Please extend DriverFactory.java for example in following way:
|
||||
|
||||
``` java
|
||||
String hubUrl = System.getenv("HUB_URL");
|
||||
//when running on a Docker deamon (and not using Kubernetes plugin), Docker images will be linked
|
||||
//in this case hubUrl will be http://selenium:4444/wd/hub due to the linking of the containers
|
||||
hubUrl = (hubUrl == null) ? "http://localhost:4444/wd/hub" : hubUrl;
|
||||
Capabilities chromeCapabilities = DesiredCapabilities.chrome();
|
||||
System.out.println("Running on Selenium Hub: " + hubUrl);
|
||||
return new RemoteWebDriver(new URL(hubUrl), chromeCapabilities);
|
||||
```
|
||||
|
||||
## Prerequsites
|
||||
|
||||
none
|
||||
|
||||
## Example
|
||||
|
||||
Pipeline step:
|
||||
```groovy
|
||||
gaugeExecuteTests script: this, testServerUrl: 'http://test.url'
|
||||
```
|
||||
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|buildTool|no|`maven`||
|
||||
|dockerEnvVars|no|`[HUB:TRUE, HUB_URL:http://localhost:4444/wd/hub]`||
|
||||
|dockerImage|no|buildTool=`maven`: `maven:3.5-jdk-8`<br />buildTool=`npm`: `node:8-stretch`<br />||
|
||||
|dockerName|no|buildTool=`maven`: `maven`<br />buildTool=`npm`: `npm`<br />||
|
||||
|dockerWorkspace|no|buildTool=`maven`: ``<br />buildTool=`npm`: `/home/node`<br />||
|
||||
|failOnError|no|`false`||
|
||||
|gitBranch|no|||
|
||||
|gitSshKeyCredentialsId|no|``||
|
||||
|installCommand|no|`curl -SsL https://downloads.gauge.org/stable | sh -s -- --location=$HOME/bin/gauge`||
|
||||
|languageRunner|no|buildTool=`maven`: `java`<br />buildTool=`npm`: `js`<br />||
|
||||
|runCommand|no|buildTool=`maven`: `mvn test-compile gauge:execute`<br />buildTool=`npm`: `gauge run`<br />||
|
||||
|stashContent|no|<ul><li>`buildDescriptor`</li><li>`tests`</li></ul>||
|
||||
|testOptions|no|buildTool=`maven`: `-DspecsDir=specs`<br />buildTool=`npm`: `specs`<br />||
|
||||
|testRepository|no|||
|
||||
|testServerUrl|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.
|
||||
* `buildTool` defines the build tool to be used for the test execution.
|
||||
* `dockerEnvVars`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerImage`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerName`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerWorkspace`, see step [dockerExecute](dockerExecute.md)
|
||||
* With `failOnError` you can define the behavior, in case tests fail. When this is set to `true` test results cannot be recorded using the `publishTestResults` step afterwards.
|
||||
* `installCommand` defines the command for installing Gauge. In case the `dockerImage` already contains Gauge it can be set to empty: ``.
|
||||
* `languageRunner` defines the Gauge language runner to be used.
|
||||
* `runCommand` defines the command which is used for executing Gauge.
|
||||
* If specific stashes should be considered for the tests, you can pass this via parameter `stashContent`
|
||||
* `testOptions` allows to set specific options for the Gauge execution. Details can be found for example [in the Gauge Maven plugin documentation](https://github.com/getgauge/gauge-maven-plugin#executing-specs)
|
||||
* In case the test implementation is stored in a different repository than the code itself, you can define the repository containing the tests using parameter `testRepository` and if required `gitBranch` (for a different branch than master) and `gitSshKeyCredentialsId` (for protected repositories). For protected repositories the `testRepository` needs to contain the ssh git url.
|
||||
* `testServerUrl` is passed as environment variable `TARGET_SERVER_URL` to the test execution. Tests running against the system should read the host information from this environment variable in order to be infrastructure agnostic.
|
||||
|
||||
## 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||||
|
||||
|buildTool||X|X|
|
||||
|dockerEnvVars||X|X|
|
||||
|dockerImage||X|X|
|
||||
|dockerName||X|X|
|
||||
|dockerWorkspace||X|X|
|
||||
|failOnError||X|X|
|
||||
|gitBranch||X|X|
|
||||
|gitSshKeyCredentialsId||X|X|
|
||||
|stashContent||X|X|
|
||||
|testOptions||X|X|
|
||||
|testRepository||X|X|
|
||||
|testServerUrl||X|X|
|
77
documentation/docs/steps/githubPublishRelease.md
Normal file
77
documentation/docs/steps/githubPublishRelease.md
Normal file
@ -0,0 +1,77 @@
|
||||
# githubPublishRelease
|
||||
|
||||
## Description
|
||||
This step creates a tag in your GitHub repository together with a release.
|
||||
|
||||
The release can be filled with text plus additional information like:
|
||||
|
||||
* Closed pull request since last release
|
||||
* Closed issues since last release
|
||||
* link to delta information showing all commits since last release
|
||||
|
||||
The result looks like
|
||||
|
||||
![Example release](../images/githubRelease.png)
|
||||
|
||||
## Prerequisites
|
||||
You need to create a personal access token within GitHub and add this to the Jenkins credentials store.
|
||||
|
||||
Please see [GitHub documentation for details about creating the personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/).
|
||||
|
||||
## Example
|
||||
|
||||
Usage of pipeline step:
|
||||
|
||||
```groovy
|
||||
githubPublishRelease script: this, releaseBodyHeader: "**This is the latest success!**<br />"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|addClosedIssues|no|`false`||
|
||||
|addDeltaToLastRelease|no|`false`||
|
||||
|customFilterExtension|no|``||
|
||||
|excludeLabels|no|<ul><li>`duplicate`</li><li>`invalid`</li><li>`question`</li><li>`wontfix`</li></ul>||
|
||||
|githubApiUrl|no|`//https://api.github.com`||
|
||||
|githubOrg|yes|`script.commonPipelineEnvironment.getGitFolder()`||
|
||||
|githubRepo|yes|`script.commonPipelineEnvironment.getGitRepo()`||
|
||||
|githubServerUrl|no|`https://github.com`||
|
||||
|githubTokenCredentialsId|yes|||
|
||||
|releaseBodyHeader|no|||
|
||||
|version|yes|`script.commonPipelineEnvironment.getArtifactVersion()`||
|
||||
|
||||
### 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.
|
||||
* All GitHub related properties allow you to overwrite the default behavior of identifying e.g. GitHub organization, GitHub repository.
|
||||
* `version` defines the version number which will be written as tag as well as release name
|
||||
* By defining the `releaseBodyHeader` you can specify the content which will appear for the release
|
||||
* If you set `addClosedIssues` to `true`, a list of all closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`
|
||||
* If you set `addDeltaToLastRelease` to `true`, a link will be added to the relese information that brings up all commits since the last release.
|
||||
* By passing the parameter `customFilterExtension` it is possible to pass additional filter criteria for retrieving closed issues since the last release. Additional criteria could be for example specific `label`, or `filter` according to [GitHub API documentation](https://developer.github.com/v3/issues/).
|
||||
* It is possible to exclude issues with dedicated labels using parameter `excludeLabels`. Usage is like `excludeLabels: ['label1', 'label2']`
|
||||
|
||||
|
||||
## 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||||
|
||||
|addClosedIssues||X|X|
|
||||
|addDeltaToLastRelease||X|X|
|
||||
|customFilterExtension||X|X|
|
||||
|excludeLabels||X|X|
|
||||
|githubApiUrl|X|X|X|
|
||||
|githubOrg||X|X|
|
||||
|githubRepo||X|X|
|
||||
|githubServerUrl|X|X|X|
|
||||
|githubTokenCredentialsId|X|X|X|
|
||||
|releaseBodyHeader||X|X|
|
||||
|version||X|X|
|
96
documentation/docs/steps/mailSendNotification.md
Normal file
96
documentation/docs/steps/mailSendNotification.md
Normal file
@ -0,0 +1,96 @@
|
||||
# mailSendNotification
|
||||
|
||||
## Description
|
||||
Sends notifications to all potential culprits of a current or previous build failure plus to fixed list of recipients.
|
||||
It will attach the current build log to the email.
|
||||
|
||||
Notifications are sent in following cases:
|
||||
|
||||
* current build failed or is unstable
|
||||
* current build is successful and previous build failed or was unstable
|
||||
|
||||
## Prerequsites
|
||||
none
|
||||
|
||||
## Example
|
||||
|
||||
Usage of pipeline step:
|
||||
|
||||
```groovy
|
||||
mailSendNotification script: this
|
||||
```
|
||||
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|buildResult|no|||
|
||||
|gitCommitId|no|`script.commonPipelineEnvironment.getGitCommitId()`||
|
||||
|gitSshKeyCredentialsId|no|``||
|
||||
|gitUrl|no|||
|
||||
|notificationAttachment|no|`true`||
|
||||
|notificationRecipients|no|||
|
||||
|notifyCulprits|no|`true`||
|
||||
|numLogLinesInBody|no|`100`||
|
||||
|projectName|no|||
|
||||
|wrapInNode|no|`false`||
|
||||
|
||||
### 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.
|
||||
* `buildResult` may be used to overrule the build result coming from `currentBuild.result`. This is for example used in the step `pipelineRestartSteps`
|
||||
* `gitCommitId` defines a dedicated git commitId for culprit retrieval.
|
||||
* `gitUrl` and `gitCommitId` are used to retrieve culprit information.
|
||||
* `gitSshKeyCredentialsId` only required if your git repository is protected. It defines the credentialsId for the git ssh credentials.
|
||||
* `notificationAttachment` defines if the console log file should be attached to the notification mail.
|
||||
* `notificationRecipients` defines the fixed list of recipient that always get the notification. In case you want to send the notification to the culprits only set it to an empty string `''`.
|
||||
|
||||
!!! note
|
||||
Multiple recipients need to be separated with the `space` character.
|
||||
In case you do not want to have any fixed recipients of the notifications leave the property empty.
|
||||
|
||||
* `notifyCulprits` defines if potential culprits should receive an email.
|
||||
* `numLogLinesInBody` defines the number of log lines (=last lines of the log) which are included into the body of the notification email.
|
||||
* `projectName` may be used to specify a different name in the email subject.
|
||||
* `wrapInNode` needs to be set to `true` if step is used outside of a node context, e.g. post actions in a declarative pipeline script.
|
||||
|
||||
|
||||
## 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||||
|
||||
|buildResult||X|X|
|
||||
|gitCommitId||X|X|
|
||||
|gitSshKeyCredentialsId|X|X|X|
|
||||
|gitUrl||X|X|
|
||||
|notificationAttachment||X|X|
|
||||
|notificationRecipients||X|X|
|
||||
|notifyCulprits||X|X|
|
||||
|numLogLinesInBody||X|X|
|
||||
|projectName||X|X|
|
||||
|wrapInNode||X|X|
|
||||
|
||||
## Return value
|
||||
none
|
||||
|
||||
## Side effects
|
||||
none
|
||||
|
||||
## Exceptions
|
||||
none
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ The following parameters can also be specified as step parameters using the glob
|
||||
* `applicationName`
|
||||
|
||||
## Return value
|
||||
The file name of the resulting archive is returned with this step. The file name is extracted from the key `ID` defined in `mta.yaml`.
|
||||
none
|
||||
|
||||
## Side effects
|
||||
1. The file name of the resulting archive is written to the `commonPipelineEnvironment` with variable name `mtarFileName`.
|
||||
|
75
documentation/docs/steps/pipelineRestartSteps.md
Normal file
75
documentation/docs/steps/pipelineRestartSteps.md
Normal file
@ -0,0 +1,75 @@
|
||||
# pipelineRestartSteps
|
||||
|
||||
## Description
|
||||
Support of restarting failed stages or steps in a pipeline is limited in Jenkins.
|
||||
|
||||
This has been documented in the [Jenkins Jira issue JENKINS-33846](https://issues.jenkins-ci.org/browse/JENKINS-33846).
|
||||
|
||||
For declarative pipelines there is a solution available which partially addresses this topic:
|
||||
https://jenkins.io/doc/book/pipeline/running-pipelines/#restart-from-a-stage.
|
||||
|
||||
Nonetheless, still features are missing, so it can't be used in all cases.
|
||||
The more complex Piper pipelines which share a state via [`commonPipelineEnvironment`](commonPipelineEnvironment.md) will for example not work with the standard _restart-from-stage_.
|
||||
|
||||
The step `pipelineRestartSteps` aims to address this gap and allows individual parts of a pipeline (e.g. a failed deployment) to be restarted.
|
||||
|
||||
This is done in a way that the pipeline waits for user input to restart the pipeline in case of a failure. In case this user input is not provided the pipeline stops after a timeout which can be configured.
|
||||
|
||||
## Prerequisites
|
||||
none
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
Usage of pipeline step:
|
||||
|
||||
```groovy
|
||||
pipelineRestartSteps (script: this) {
|
||||
node {
|
||||
//your steps ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! caution
|
||||
Use `node` inside the step. If a `node` exists outside the step context, the `input` step which is triggered in the process will block a Jenkins executor.
|
||||
|
||||
In case you cannot use `node` inside this step, please choose the parameter `timeoutInSeconds` carefully!
|
||||
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|sendMail|no|`true`||
|
||||
|timeoutInSeconds|no|`900`||
|
||||
|
||||
### 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.
|
||||
* If `sendMail: true` the step `mailSendNotification` will be triggered in case of an error
|
||||
* `timeoutInSeconds` defines the time period where the job waits for input. Default is 15 minutes. Once this time is passed the job enters state FAILED.
|
||||
|
||||
|
||||
## 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||||
|
||||
|sendMail|X|X|X|
|
||||
|timeoutInSeconds|X|X|X|
|
||||
|
||||
## Return value
|
||||
none
|
||||
|
||||
## Side effects
|
||||
none
|
||||
|
||||
## Exceptions
|
||||
none
|
||||
|
@ -77,8 +77,10 @@ webdriverio
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|buildTool|no|`npm`|`maven`, `npm`|
|
||||
|containerPortMappings|no|`[selenium/standalone-chrome:[[containerPort:4444, hostPort:4444]]]`||
|
||||
|dockerImage|no|buildTool=`maven`: `maven:3.5-jdk-7`<br />buildTool=`npm`: `node:8-stretch`<br />||
|
||||
|dockerEnvVars|no|||
|
||||
|dockerImage|no|buildTool=`maven`: `maven:3.5-jdk-8`<br />buildTool=`npm`: `node:8-stretch`<br />||
|
||||
|dockerName|no|buildTool=`maven`: `maven`<br />buildTool=`npm`: `npm`<br />||
|
||||
|dockerWorkspace|no|buildTool=`maven`: ``<br />buildTool=`npm`: `/home/node`<br />||
|
||||
|failOnError|no|`true`||
|
||||
@ -92,7 +94,9 @@ webdriverio
|
||||
|testRepository|no|||
|
||||
|
||||
* `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.
|
||||
* `buildTool` defines the build tool to be used for the test execution.
|
||||
* `containerPortMappings`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerEnvVars`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerImage`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerName`, see step [dockerExecute](dockerExecute.md)
|
||||
* `dockerWorkspace`, see step [dockerExecute](dockerExecute.md)
|
||||
@ -113,7 +117,9 @@ In following sections the configuration is possible:
|
||||
| parameter | general | step | stage |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script||||
|
||||
|buildTool||X|X|
|
||||
|containerPortMappings|X|X|X|
|
||||
|dockerEnvVars|X|X|X|
|
||||
|dockerImage|X|X|X|
|
||||
|dockerName|X|X|X|
|
||||
|dockerWorkspace|X|X|X|
|
||||
|
@ -1,7 +1,10 @@
|
||||
# transportRequestCreate
|
||||
|
||||
## Description
|
||||
Creates a Transport Request for a Change Document on the Solution Manager.
|
||||
Creates
|
||||
|
||||
* a Transport Request for a Change Document on the Solution Manager (type `SOLMAN`) or
|
||||
* a Transport Request inside an ABAP system (type`CTS`)
|
||||
|
||||
## Prerequisites
|
||||
* **[Change Management Client 2.0.0 or compatible version](http://central.maven.org/maven2/com/sap/devops/cmclient/dist.cli/)** - available for download on Maven Central.
|
||||
@ -10,7 +13,10 @@ Creates a Transport Request for a Change Document on the Solution Manager.
|
||||
| parameter | mandatory | default | possible values |
|
||||
| -----------------|-----------|--------------------------------------------------------|--------------------|
|
||||
| `script` | yes | | |
|
||||
| `changeDocumentId` | yes | | |
|
||||
| `changeDocumentId` | for `SOLMAN` | | |
|
||||
| `transportType` | for `CTS` | no | |
|
||||
| `targetSystem` | for `CTS` | no | |
|
||||
| `description` | for `CTS` | no | |
|
||||
| `changeManagement/credentialsId` | yes | | |
|
||||
| `changeManagement/endpoint` | yes | | |
|
||||
| `changeManagement/clientOpts` | no | | |
|
||||
@ -18,16 +24,21 @@ Creates a Transport Request for a Change Document on the Solution Manager.
|
||||
| `changeManagement/git/to` | no | `HEAD` | |
|
||||
| `changeManagement/changeDocumentLabel` | no | `ChangeDocument\s?:` | regex pattern |
|
||||
| `changeManagement/git/format` | no | `%b` | see `git log --help` |
|
||||
| `changeManagement/type` | no | `SOLMAN` | `SOLMAN`, `CTS` |
|
||||
|
||||
* `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.
|
||||
* `changeDocumentId` - The id of the change document to transport.
|
||||
* `changeManagement/credentialsId` - The credentials to connect to the Solution Manager.
|
||||
* `changeManagement/endpoint` - The address of the Solution Manager.
|
||||
* `changeDocumentId` - for `SOLMAN` only. The id of the change document to that the transport request is bound to. Typically this value is provided via commit message in the commit history.
|
||||
* `changeManagement/type` Where/how the transport request is created (via SAP Solution Manager, ABAP).
|
||||
* `changeManagement/credentialsId` - The credentials to connect to the service endpoint (Solution Manager, ABAP System).
|
||||
* `changeManagement/endpoint` - The service endpoint (Solution Manager, ABAP System).
|
||||
* `changeManagement/clientOpts`- Options forwarded to JVM used by the CM client, like `JAVA_OPTS`
|
||||
* `changeManagement/git/from` - The starting point for retrieving the change document id
|
||||
* `changeManagement/git/to` - The end point for retrieving the change document id
|
||||
* `changeManagement/changeDocumentLabel` - A pattern used for identifying lines holding the change document id.
|
||||
* `changeManagement/changeDocumentLabel` - For type `SOLMAN` only. A pattern used for identifying lines holding the change document id.
|
||||
* `changeManagement/git/format` - Specifies what part of the commit is scanned. By default the body of the commit message is scanned.
|
||||
* `description` - for `CTS` only. The description of the transport request.
|
||||
* `targetSystem` - for `CTS` only. The system receiving the transport request.
|
||||
* `transportType` - for type `CTS` only. Typically `W` (workbench) or `C` customizing.
|
||||
|
||||
## Step configuration
|
||||
The step is configured using a customer configuration file provided as
|
||||
@ -55,6 +66,7 @@ general:
|
||||
changeDocumentLabel: 'ChangeDocument\s?:'
|
||||
cmClientOpts: '-Djavax.net.ssl.trustStore=<path to truststore>'
|
||||
credentialsId: 'CM'
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
git:
|
||||
from: 'HEAD~1'
|
||||
@ -72,6 +84,7 @@ The properties can also be configured on a per-step basis:
|
||||
steps:
|
||||
transportRequestCreate:
|
||||
changeManagement:
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
[...]
|
||||
```
|
||||
@ -89,9 +102,20 @@ The id of the Transport Request that has been created.
|
||||
|
||||
## Example
|
||||
```groovy
|
||||
// SOLMAN
|
||||
def transportRequestId = transportRequestCreate script:this,
|
||||
changeDocumentId: '001,'
|
||||
changeManagement: [
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
]
|
||||
// CTS
|
||||
def transportRequestId = transportRequestCreate script:this,
|
||||
transportType: 'W',
|
||||
targetSystem: 'XYZ',
|
||||
description: 'the description',
|
||||
changeManagement: [
|
||||
type: 'CTS'
|
||||
endpoint: 'https://example.org/cm'
|
||||
]
|
||||
```
|
||||
|
@ -1,7 +1,7 @@
|
||||
# transportRequestRelease
|
||||
|
||||
## Description
|
||||
Releases a Transport Request for a Change Document on the Solution Manager.
|
||||
Releases a Transport Request.
|
||||
|
||||
## Prerequisites
|
||||
* **[Change Management Client 2.0.0 or compatible version](http://central.maven.org/maven2/com/sap/devops/cmclient/dist.cli/)** - available for download on Maven Central.
|
||||
@ -10,7 +10,7 @@ Releases a Transport Request for a Change Document on the Solution Manager.
|
||||
| parameter | mandatory | default | possible values |
|
||||
| -----------------|-----------|--------------------------------------------------------|--------------------|
|
||||
| `script` | yes | | |
|
||||
| `changeDocumentId` | yes | | |
|
||||
| `changeDocumentId` | `SOLMAN` only | | |
|
||||
| `transportRequestId`| yes | | |
|
||||
| `changeManagement/changeDocumentLabel` | no | `ChangeDocument\s?:` | regex pattern |
|
||||
| `changeManagment/transportRequestLabel` | no | `TransportRequest\s?:` | regex pattern |
|
||||
@ -19,16 +19,17 @@ Releases a Transport Request for a Change Document on the Solution Manager.
|
||||
| `changeManagement/git/from` | no | `origin/master` | |
|
||||
| `changeManagement/git/to` | no | `HEAD` | |
|
||||
| `changeManagement/git/format` | no | `%b` | see `git log --help` |
|
||||
| `changeManagement/type` | no | `SOLMAN` | `SOLMAN`, `CTS` |
|
||||
|
||||
* `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.
|
||||
* `changeDocumentId` - The id of the change document related to the transport request to release.
|
||||
* `changeDocumentId` - for `SOLMAN` only. The id of the change document related to the transport request to release.
|
||||
* `transportRequestId` - The id of the transport request to release.
|
||||
* `changeManagement/changeDocumentLabel` - A pattern used for identifying lines holding the change document id.
|
||||
* `changeManagement/changeDocumentLabel` - for `SOLMAN` only. A pattern used for identifying lines holding the change document id.
|
||||
* `changeManagment/transportRequestLabel` - A pattern used for identifying lines holding the transport request id.
|
||||
* `changeManagement/credentialsId` - The id of the credentials to connect to the Solution Manager. The credentials needs to be maintained on Jenkins.
|
||||
* `changeManagement/endpoint` - The address of the Solution Manager.
|
||||
* `changeManagement/git/from` - The starting point for retrieving the change document id
|
||||
* `changeManagement/git/to` - The end point for retrieving the change document id
|
||||
* `changeManagement/credentialsId` - The credentials to connect to the service endpoint (Solution Manager, ABAP System).
|
||||
* `changeManagement/endpoint` - The service endpoint (Solution Manager, ABAP System).
|
||||
* `changeManagement/git/from` - The starting point for retrieving the change document id and/or transport request id
|
||||
* `changeManagement/git/to` - The end point for retrieving the change document id and/or transport request id
|
||||
* `changeManagement/git/format` - Specifies what part of the commit is scanned. By default the body of the commit message is scanned.
|
||||
|
||||
## Step configuration
|
||||
@ -57,6 +58,7 @@ general:
|
||||
changeDocumentLabel: 'ChangeDocument\s?:'
|
||||
cmClientOpts: '-Djavax.net.ssl.trustStore=<path to truststore>'
|
||||
credentialsId: 'CM'
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
git:
|
||||
from: 'HEAD~1'
|
||||
@ -73,6 +75,7 @@ The properties can also be configured on a per-step basis:
|
||||
steps:
|
||||
transportRequestRelease:
|
||||
changeManagement:
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
[...]
|
||||
```
|
||||
@ -84,17 +87,26 @@ None.
|
||||
|
||||
## Exceptions
|
||||
* `IllegalArgumentException`:
|
||||
* If the change id is not provided.
|
||||
* If the change id is not provided (`SOLMAN` only)
|
||||
* If the transport request id is not provided.
|
||||
* `AbortException`:
|
||||
* If the release of the transport request fails.
|
||||
|
||||
## Example
|
||||
```groovy
|
||||
// SOLMAN
|
||||
transportRequestRelease script:this,
|
||||
changeDocumentId: '001',
|
||||
transportRequestId: '001',
|
||||
changeManagement: [
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
]
|
||||
// CTS
|
||||
transportRequestRelease script:this,
|
||||
transportRequestId: '001',
|
||||
changeManagement: [
|
||||
type: 'CTS'
|
||||
endpoint: 'https://example.org/cm'
|
||||
]
|
||||
```
|
||||
|
@ -1,7 +1,7 @@
|
||||
# transportRequestUploadFile
|
||||
|
||||
## Description
|
||||
Uploads a file to a Transport Request for a Change Document on the Solution Manager.
|
||||
Uploads a file to a Transport Request.
|
||||
|
||||
## Prerequisites
|
||||
* **[Change Management Client 2.0.0 or compatible version](http://central.maven.org/maven2/com/sap/devops/cmclient/dist.cli/)** - available for download on Maven Central.
|
||||
@ -10,9 +10,9 @@ Uploads a file to a Transport Request for a Change Document on the Solution Mana
|
||||
| parameter | mandatory | default | possible values |
|
||||
| -----------------|-----------|--------------------------------------------------------|--------------------|
|
||||
| `script` | yes | | |
|
||||
| `changeDocumentId` | yes | | |
|
||||
| `changeDocumentId` | `SOLMAN` only | | |
|
||||
| `transportRequestId`| yes | | |
|
||||
| `applicationId` | yes | | |
|
||||
| `applicationId` | `SOLMAN` only | | |
|
||||
| `filePath` | yes | | |
|
||||
| `changeManagement/credentialsId` | yes | | |
|
||||
| `changeManagement/endpoint` | yes | | |
|
||||
@ -21,18 +21,20 @@ Uploads a file to a Transport Request for a Change Document on the Solution Mana
|
||||
| `changeManagement/changeDocumentLabel` | no | `ChangeDocument\s?:` | regex pattern |
|
||||
| `changeManagement/transportRequestLabel` | no | `TransportRequest\s?:` | regex pattern |
|
||||
| `changeManagement/git/format` | no | `%b` | see `git log --help` |
|
||||
| `changeManagement/type` | no | `SOLMAN` | `SOLMAN`, `CTS` |
|
||||
|
||||
* `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.
|
||||
* `changeDocumentId` - The id of the change document related to the transport request to release.
|
||||
* `transportRequestId` - The id of the transport request to release.
|
||||
* `applicationId` - The id of the application.
|
||||
* `changeDocumentId` - For type `SOLMAN` only. The id of the change document related to the transport request to release. Typically provided via commit history.
|
||||
* `transportRequestId` - The id of the transport request to release. Typically provided via commit history.
|
||||
* `applicationId` - For type `SOLMAN` only. The id of the application.
|
||||
* `filePath` - The path of the file to upload.
|
||||
* `changeManagement/credentialsId` - The credentials to connect to the Solution Manager.
|
||||
* `changeManagement/endpoint` - The address of the Solution Manager.
|
||||
* `changeManagement/git/from` - The starting point for retrieving the change document id
|
||||
* `changeManagement/git/to` - The end point for retrieving the change document id
|
||||
* `changeManagement/changeDocumentLabel` - A pattern used for identifying lines holding the change document id.
|
||||
* `changeManagement/credentialsId` - The credentials to connect to the service endpoint (Solution Manager, ABAP System).
|
||||
* `changeManagement/endpoint` - The service endpoint (Solution Manager, ABAP System).
|
||||
* `changeManagement/git/from` - The starting point for retrieving the change document id and/or transport request id
|
||||
* `changeManagement/git/to` - The end point for retrieving the change document id and/or transport request id
|
||||
* `changeManagement/changeDocumentLabel` - For type `SOLMAN` only. A pattern used for identifying lines holding the change document id.
|
||||
* `changeManagement/transportRequestLabel` - A pattern used for identifying lines holding the transport request id.
|
||||
* `changeManagement/type` Where/how the transport request is created (via SAP Solution Manager, ABAP).
|
||||
* `changeManagement/git/format` - Specifies what part of the commit is scanned. By default the body of the commit message is scanned.
|
||||
|
||||
## Step configuration
|
||||
@ -61,6 +63,7 @@ general:
|
||||
changeDocumentLabel: 'ChangeDocument\s?:'
|
||||
cmClientOpts: '-Djavax.net.ssl.trustStore=<path to truststore>'
|
||||
credentialsId: 'CM'
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
git:
|
||||
from: 'HEAD~1'
|
||||
@ -78,6 +81,7 @@ The properties can also be configured on a per-step basis:
|
||||
transportRequestUploadFile:
|
||||
applicationId: 'FOO'
|
||||
changeManagement:
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
[...]
|
||||
```
|
||||
@ -89,21 +93,31 @@ None.
|
||||
|
||||
## Exceptions
|
||||
* `IllegalArgumentException`:
|
||||
* If the change id is not provided.
|
||||
* If the change id is not provided (`SOLMAN` only).
|
||||
* If the transport request id is not provided.
|
||||
* If the application id is not provided.
|
||||
* If the application id is not provided (`SOLMAN` only).
|
||||
* If the file path is not provided.
|
||||
* `AbortException`:
|
||||
* If the upload fails.
|
||||
|
||||
## Example
|
||||
```groovy
|
||||
// SOLMAN
|
||||
transportRequestUploadFile script:this,
|
||||
changeDocumentId: '001',
|
||||
transportRequestId: '001',
|
||||
changeDocumentId: '001', // typically provided via git commit history
|
||||
transportRequestId: '001', // typically provided via git commit history
|
||||
applicationId: '001',
|
||||
filePath: '/path',
|
||||
changeManagement:[
|
||||
type: 'SOLMAN'
|
||||
endpoint: 'https://example.org/cm'
|
||||
]
|
||||
// CTS
|
||||
transportRequestUploadFile script:this,
|
||||
transportRequestId: '001', // typically provided via git commit history
|
||||
filePath: '/path',
|
||||
changeManagement:[
|
||||
type: 'CTS'
|
||||
endpoint: 'https://example.org/cm'
|
||||
]
|
||||
```
|
||||
|
@ -6,22 +6,28 @@ nav:
|
||||
- artifactSetVersion: steps/artifactSetVersion.md
|
||||
- batsExecuteTests: steps/batsExecuteTests.md
|
||||
- checkChangeInDevelopment: steps/checkChangeInDevelopment.md
|
||||
- checksPublishResults: steps/checksPublishResults.md
|
||||
- cloudFoundryDeploy: steps/cloudFoundryDeploy.md
|
||||
- commonPipelineEnvironment: steps/commonPipelineEnvironment.md
|
||||
- dockerExecute: steps/dockerExecute.md
|
||||
- dockerExecuteOnKubernetes: steps/dockerExecuteOnKubernetes.md
|
||||
- durationMeasure: steps/durationMeasure.md
|
||||
- githubPublishRelease: steps/githubPublishRelease.md
|
||||
- gaugeExecuteTests: steps/gaugeExecuteTests.md
|
||||
- handlePipelineStepErrors: steps/handlePipelineStepErrors.md
|
||||
- healthExecuteCheck: steps/healthExecuteCheck.md
|
||||
- influxWriteData: steps/influxWriteData.md
|
||||
- mailSendNotification: steps/mailSendNotification.md
|
||||
- mavenExecute: steps/mavenExecute.md
|
||||
- mtaBuild: steps/mtaBuild.md
|
||||
- neoDeploy: steps/neoDeploy.md
|
||||
- pipelineExecute: steps/pipelineExecute.md
|
||||
- pipelineRestartSteps: steps/pipelineRestartSteps.md
|
||||
- pipelineStashFiles: steps/pipelineStashFiles.md
|
||||
- prepareDefaultValues: steps/prepareDefaultValues.md
|
||||
- seleniumExecuteTests: steps/seleniumExecuteTests.md
|
||||
- setupCommonPipelineEnvironment: steps/setupCommonPipelineEnvironment.md
|
||||
- testsPublishResults: steps/testsPublishResults.md
|
||||
- toolValidate: steps/toolValidate.md
|
||||
- transportRequestCreate: steps/transportRequestCreate.md
|
||||
- transportRequestRelease: steps/transportRequestRelease.md
|
||||
|
18
pom.xml
18
pom.xml
@ -10,7 +10,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.sap.cp.jenkins</groupId>
|
||||
<artifactId>jenkins-library</artifactId>
|
||||
<version>0.7</version>
|
||||
<version>0.8</version>
|
||||
|
||||
<name>SAP CP Piper Library</name>
|
||||
<description>Shared library containing steps and utilities to set up continuous deployment processes for SAP technologies.</description>
|
||||
@ -132,7 +132,6 @@
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
@ -140,8 +139,21 @@
|
||||
<version>1.12</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-test-source</id>
|
||||
<id>add-groovy-sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src</source>
|
||||
<source>vars</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>add-groovy-test-sources</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals>
|
||||
<goal>add-test-source</goal>
|
||||
</goals>
|
||||
|
21
resources/com.sap.piper/templates/error.log
Normal file
21
resources/com.sap.piper/templates/error.log
Normal file
@ -0,0 +1,21 @@
|
||||
----------------------------------------------------------
|
||||
--- ERROR OCCURRED IN LIBRARY STEP: ${stepName}
|
||||
----------------------------------------------------------
|
||||
|
||||
FOLLOWING PARAMETERS WERE AVAILABLE TO THIS STEP:
|
||||
***
|
||||
${stepParameters}
|
||||
***
|
||||
|
||||
ERROR WAS:
|
||||
***
|
||||
${error}
|
||||
***
|
||||
|
||||
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/
|
||||
* Library repository: https://github.com/SAP/jenkins-library
|
||||
|
||||
----------------------------------------------------------
|
6
resources/com.sap.piper/templates/mailFailure.html
Normal file
6
resources/com.sap.piper/templates/mailFailure.html
Normal file
@ -0,0 +1,6 @@
|
||||
<a href="${env.BUILD_URL}">${env.BUILD_URL}</a>
|
||||
<br>
|
||||
To have a detailed look at the different pipeline stages: <a href="${env.RUN_DISPLAY_URL}">${env.RUN_DISPLAY_URL}</a>
|
||||
<br>
|
||||
<h3>Last lines of output</h3>
|
||||
<pre>${log}</pre>
|
3
resources/com.sap.piper/templates/mailRecover.html
Normal file
3
resources/com.sap.piper/templates/mailRecover.html
Normal file
@ -0,0 +1,3 @@
|
||||
<a href="${env.BUILD_URL}">${env.BUILD_URL}</a>
|
||||
<br>
|
||||
To have a detailed look at the different pipeline stages: <a href="${env.RUN_DISPLAY_URL}">${env.RUN_DISPLAY_URL}</a>
|
@ -3,6 +3,7 @@ general:
|
||||
productiveBranch: 'master'
|
||||
collectTelemetryData: true
|
||||
changeManagement:
|
||||
type: 'NONE' # SOLMAN, CTS, NONE
|
||||
transportRequestLabel: 'TransportRequest\s?:'
|
||||
changeDocumentLabel: 'ChangeDocument\s?:'
|
||||
clientOpts: ''
|
||||
@ -11,6 +12,8 @@ general:
|
||||
from: 'origin/master'
|
||||
to: 'HEAD'
|
||||
format: '%b'
|
||||
githubApiUrl: 'https://api.github.com'
|
||||
githubServerUrl: 'https://github.com'
|
||||
gitSshKeyCredentialsId: '' #needed to allow sshagent to run with local ssh key
|
||||
jenkinsKubernetes:
|
||||
jnlpAgent: 's4sdk/jenkins-agent-k8s:latest'
|
||||
@ -139,10 +142,48 @@ steps:
|
||||
workspace: '**/*.*'
|
||||
stashExcludes:
|
||||
workspace: 'nohup.out'
|
||||
githubPublishRelease:
|
||||
addClosedIssues: false
|
||||
addDeltaToLastRelease: false
|
||||
customFilterExtension: ''
|
||||
excludeLabels:
|
||||
- 'duplicate'
|
||||
- 'invalid'
|
||||
- 'question'
|
||||
- 'wontfix'
|
||||
gaugeExecuteTests:
|
||||
buildTool: 'maven'
|
||||
dockerEnvVars:
|
||||
HUB: 'TRUE'
|
||||
HUB_URL: 'http://localhost:4444/wd/hub'
|
||||
failOnError: false
|
||||
installCommand: 'curl -SsL https://downloads.gauge.org/stable | sh -s -- --location=$HOME/bin/gauge'
|
||||
stashContent:
|
||||
- 'buildDescriptor'
|
||||
- 'tests'
|
||||
maven:
|
||||
dockerImage: 'maven:3.5-jdk-8'
|
||||
dockerName: 'maven'
|
||||
dockerWorkspace: ''
|
||||
languageRunner: 'java'
|
||||
runCommand: 'mvn test-compile gauge:execute'
|
||||
testOptions: '-DspecsDir=specs'
|
||||
npm:
|
||||
dockerImage: 'node:8-stretch'
|
||||
dockerName: 'npm'
|
||||
dockerWorkspace: '/home/node'
|
||||
languageRunner: 'js'
|
||||
runCommand: 'gauge run'
|
||||
testOptions: 'specs'
|
||||
healthExecuteCheck:
|
||||
healthEndpoint: ''
|
||||
influxWriteData:
|
||||
influxServer: 'jenkins'
|
||||
mailSendNotification:
|
||||
notificationAttachment: true
|
||||
notifyCulprits: true
|
||||
numLogLinesInBody: 100
|
||||
wrapInNode: false
|
||||
mavenExecute:
|
||||
dockerImage: 'maven:3.5-jdk-7'
|
||||
logSuccessfulMavenTransfers: false
|
||||
@ -164,6 +205,9 @@ 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'
|
||||
pipelineRestartSteps:
|
||||
sendMail: true
|
||||
timeoutInSeconds: 900
|
||||
pipelineStashFilesAfterBuild:
|
||||
runOpaTests: false
|
||||
stashIncludes:
|
||||
@ -200,7 +244,6 @@ steps:
|
||||
'selenium/standalone-chrome':
|
||||
- containerPort: 4444
|
||||
hostPort: 4444
|
||||
dockerLinkAlias: 'selenium'
|
||||
failOnError: true
|
||||
sidecarImage: 'selenium/standalone-chrome'
|
||||
sidecarName: 'selenium'
|
||||
@ -209,7 +252,7 @@ steps:
|
||||
stashContent:
|
||||
- 'tests'
|
||||
maven:
|
||||
dockerImage: 'maven:3.5-jdk-7'
|
||||
dockerImage: 'maven:3.5-jdk-8'
|
||||
dockerName: 'maven'
|
||||
dockerWorkspace: ''
|
||||
npm:
|
||||
|
26
src/com/sap/piper/CfManifestUtils.groovy
Normal file
26
src/com/sap/piper/CfManifestUtils.groovy
Normal file
@ -0,0 +1,26 @@
|
||||
package com.sap.piper
|
||||
|
||||
import com.cloudbees.groovy.cps.NonCPS
|
||||
|
||||
class CfManifestUtils {
|
||||
@NonCPS
|
||||
static Map transform(Map manifest) {
|
||||
if (manifest.applications[0].buildpacks) {
|
||||
manifest['applications'].each { Map application ->
|
||||
def buildpacks = application['buildpacks']
|
||||
if (buildpacks) {
|
||||
if (buildpacks instanceof List) {
|
||||
if (buildpacks.size > 1) {
|
||||
throw new RuntimeException('More than one Cloud Foundry Buildpack is not supported. Please check your manifest.yaml file.')
|
||||
}
|
||||
application['buildpack'] = buildpacks[0]
|
||||
application.remove('buildpacks')
|
||||
} else {
|
||||
throw new RuntimeException('"buildpacks" in manifest.yaml is not a list. Please check your manifest.yaml file.')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return manifest
|
||||
}
|
||||
}
|
@ -3,31 +3,27 @@ package com.sap.piper
|
||||
import com.cloudbees.groovy.cps.NonCPS
|
||||
|
||||
class ConfigurationHelper implements Serializable {
|
||||
static ConfigurationHelper loadStepDefaults(Script step){
|
||||
return new ConfigurationHelper(step)
|
||||
.initDefaults(step)
|
||||
.loadDefaults()
|
||||
|
||||
static ConfigurationHelper newInstance(Script step, Map config = [:]) {
|
||||
new ConfigurationHelper(step, config)
|
||||
}
|
||||
|
||||
private Map config = [:]
|
||||
private String name
|
||||
ConfigurationHelper loadStepDefaults() {
|
||||
this.step.prepareDefaultValues()
|
||||
this.config = ConfigurationLoader.defaultGeneralConfiguration()
|
||||
mixin(ConfigurationLoader.defaultStepConfiguration(null, name))
|
||||
}
|
||||
|
||||
private Map config
|
||||
private Script step
|
||||
private String name
|
||||
private Map validationResults = null
|
||||
|
||||
ConfigurationHelper(Script step){
|
||||
name = step.STEP_NAME
|
||||
if(!name) throw new IllegalArgumentException('Step has no public name property!')
|
||||
}
|
||||
|
||||
private final ConfigurationHelper initDefaults(Script step){
|
||||
step.prepareDefaultValues()
|
||||
return this
|
||||
}
|
||||
|
||||
private final ConfigurationHelper loadDefaults(){
|
||||
config = ConfigurationLoader.defaultGeneralConfiguration()
|
||||
mixin(ConfigurationLoader.defaultStepConfiguration(null, name))
|
||||
return this
|
||||
private ConfigurationHelper(Script step, Map config){
|
||||
this.config = config ?: [:]
|
||||
this.step = step
|
||||
this.name = step.STEP_NAME
|
||||
if(!this.name) throw new IllegalArgumentException('Step has no public name property!')
|
||||
}
|
||||
|
||||
ConfigurationHelper collectValidationFailures() {
|
||||
@ -35,25 +31,24 @@ class ConfigurationHelper implements Serializable {
|
||||
return this
|
||||
}
|
||||
|
||||
ConfigurationHelper mixinGeneralConfig(commonPipelineEnvironment, Set filter = null, Script step = null, Map compatibleParameters = [:]){
|
||||
ConfigurationHelper mixinGeneralConfig(commonPipelineEnvironment, Set filter = null, Map compatibleParameters = [:]){
|
||||
Map stepConfiguration = ConfigurationLoader.generalConfiguration([commonPipelineEnvironment: commonPipelineEnvironment])
|
||||
return mixin(stepConfiguration, filter, step, compatibleParameters)
|
||||
return mixin(stepConfiguration, filter, compatibleParameters)
|
||||
}
|
||||
|
||||
ConfigurationHelper mixinStageConfig(commonPipelineEnvironment, stageName, Set filter = null, Script step = null, Map compatibleParameters = [:]){
|
||||
ConfigurationHelper mixinStageConfig(commonPipelineEnvironment, stageName, Set filter = null, Map compatibleParameters = [:]){
|
||||
Map stageConfiguration = ConfigurationLoader.stageConfiguration([commonPipelineEnvironment: commonPipelineEnvironment], stageName)
|
||||
return mixin(stageConfiguration, filter, step, compatibleParameters)
|
||||
return mixin(stageConfiguration, filter, compatibleParameters)
|
||||
}
|
||||
|
||||
ConfigurationHelper mixinStepConfig(commonPipelineEnvironment, Set filter = null, Script step = null, Map compatibleParameters = [:]){
|
||||
if(!name) throw new IllegalArgumentException('Step has no public name property!')
|
||||
ConfigurationHelper mixinStepConfig(commonPipelineEnvironment, Set filter = null, Map compatibleParameters = [:]){
|
||||
Map stepConfiguration = ConfigurationLoader.stepConfiguration([commonPipelineEnvironment: commonPipelineEnvironment], name)
|
||||
return mixin(stepConfiguration, filter, step, compatibleParameters)
|
||||
return mixin(stepConfiguration, filter, compatibleParameters)
|
||||
}
|
||||
|
||||
ConfigurationHelper mixin(Map parameters, Set filter = null, Script step = null, Map compatibleParameters = [:]){
|
||||
final ConfigurationHelper mixin(Map parameters, Set filter = null, Map compatibleParameters = [:]){
|
||||
if (parameters.size() > 0 && compatibleParameters.size() > 0) {
|
||||
parameters = ConfigurationMerger.merge(handleCompatibility(step, compatibleParameters, parameters), null, parameters)
|
||||
parameters = ConfigurationMerger.merge(handleCompatibility(compatibleParameters, parameters), null, parameters)
|
||||
}
|
||||
if (filter) {
|
||||
filter.add('collectTelemetryData')
|
||||
@ -62,12 +57,12 @@ class ConfigurationHelper implements Serializable {
|
||||
return this
|
||||
}
|
||||
|
||||
private Map handleCompatibility(Script step, Map compatibleParameters, String paramStructure = '', Map configMap ) {
|
||||
private Map handleCompatibility(Map compatibleParameters, String paramStructure = '', Map configMap ) {
|
||||
Map newConfig = [:]
|
||||
compatibleParameters.each {entry ->
|
||||
if (entry.getValue() instanceof Map) {
|
||||
paramStructure = (paramStructure ? paramStructure + '.' : '') + entry.getKey()
|
||||
newConfig[entry.getKey()] = handleCompatibility(step, entry.getValue(), paramStructure, configMap)
|
||||
newConfig[entry.getKey()] = handleCompatibility(entry.getValue(), paramStructure, configMap)
|
||||
} else {
|
||||
def configSubMap = configMap
|
||||
for(String key in paramStructure.tokenize('.')){
|
||||
@ -76,8 +71,8 @@ class ConfigurationHelper implements Serializable {
|
||||
if (configSubMap == null || (configSubMap != null && configSubMap[entry.getKey()] == null)) {
|
||||
newConfig[entry.getKey()] = configMap[entry.getValue()]
|
||||
def paramName = (paramStructure ? paramStructure + '.' : '') + entry.getKey()
|
||||
if (step && configMap[entry.getValue()] != null) {
|
||||
step.echo ("[INFO] The parameter '${entry.getValue()}' is COMPATIBLE to the parameter '${paramName}'")
|
||||
if (configMap[entry.getValue()] != null) {
|
||||
this.step.echo ("[INFO] The parameter '${entry.getValue()}' is COMPATIBLE to the parameter '${paramName}'")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,10 +108,6 @@ class ConfigurationHelper implements Serializable {
|
||||
return config
|
||||
}
|
||||
|
||||
ConfigurationHelper(Map config = [:]){
|
||||
this.config = config
|
||||
}
|
||||
|
||||
/* private */ def getConfigPropertyNested(key) {
|
||||
return getConfigPropertyNested(config, key)
|
||||
}
|
||||
|
@ -2,8 +2,19 @@ package com.sap.piper
|
||||
|
||||
import com.cloudbees.groovy.cps.NonCPS
|
||||
import jenkins.model.Jenkins
|
||||
import org.jenkinsci.plugins.workflow.steps.MissingContextVariableException
|
||||
|
||||
@NonCPS
|
||||
static def isPluginActive(pluginId) {
|
||||
return Jenkins.instance.pluginManager.plugins.find { p -> p.isActive() && p.getShortName() == pluginId }
|
||||
}
|
||||
|
||||
def nodeAvailable() {
|
||||
try {
|
||||
sh "echo 'Node is available!'"
|
||||
} catch (MissingContextVariableException e) {
|
||||
echo "No node context available."
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
5
src/com/sap/piper/cm/BackendType.groovy
Normal file
5
src/com/sap/piper/cm/BackendType.groovy
Normal file
@ -0,0 +1,5 @@
|
||||
package com.sap.piper.cm;
|
||||
|
||||
public enum BackendType {
|
||||
SOLMAN, CTS, NONE
|
||||
}
|
@ -63,7 +63,8 @@ public class ChangeManagement implements Serializable {
|
||||
}
|
||||
|
||||
boolean isChangeInDevelopment(String changeId, String endpoint, String credentialsId, String clientOpts = '') {
|
||||
int rc = executeWithCredentials(endpoint, credentialsId, 'is-change-in-development', ['-cID', "'${changeId}'", '--return-code'],
|
||||
int rc = executeWithCredentials(BackendType.SOLMAN, endpoint, credentialsId, 'is-change-in-development', ['-cID', "'${changeId}'", '--return-code'],
|
||||
false,
|
||||
clientOpts) as int
|
||||
|
||||
if (rc == 0) {
|
||||
@ -75,21 +76,51 @@ public class ChangeManagement implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
String createTransportRequest(String changeId, String developmentSystemId, String endpoint, String credentialsId, String clientOpts = '') {
|
||||
String createTransportRequestCTS(String transportType, String targetSystemId, String description, String endpoint, String credentialsId, String clientOpts = '') {
|
||||
try {
|
||||
def transportRequest = executeWithCredentials(endpoint, credentialsId, 'create-transport', ['-cID', changeId, '-dID', developmentSystemId],
|
||||
def transportRequest = executeWithCredentials(BackendType.CTS, endpoint, credentialsId, 'create-transport',
|
||||
['-tt', transportType, '-ts', targetSystemId, '-d', "\"${description}\""],
|
||||
true,
|
||||
clientOpts)
|
||||
return transportRequest.trim() as String
|
||||
return (transportRequest as String)?.trim()
|
||||
}catch(AbortException e) {
|
||||
throw new ChangeManagementException("Cannot create a transport request. $e.message.")
|
||||
}
|
||||
}
|
||||
|
||||
String createTransportRequestSOLMAN(String changeId, String developmentSystemId, String endpoint, String credentialsId, String clientOpts = '') {
|
||||
|
||||
try {
|
||||
def transportRequest = executeWithCredentials(BackendType.SOLMAN, endpoint, credentialsId, 'create-transport', ['-cID', changeId, '-dID', developmentSystemId],
|
||||
true,
|
||||
clientOpts)
|
||||
return (transportRequest as String)?.trim()
|
||||
}catch(AbortException e) {
|
||||
throw new ChangeManagementException("Cannot create a transport request for change id '$changeId'. $e.message.")
|
||||
}
|
||||
}
|
||||
|
||||
void uploadFileToTransportRequest(BackendType type, String changeId, String transportRequestId, String applicationId, String filePath, String endpoint, String credentialsId, String cmclientOpts = '') {
|
||||
|
||||
void uploadFileToTransportRequest(String changeId, String transportRequestId, String applicationId, String filePath, String endpoint, String credentialsId, String cmclientOpts = '') {
|
||||
int rc = executeWithCredentials(endpoint, credentialsId, 'upload-file-to-transport', ['-cID', changeId,
|
||||
def args = null
|
||||
|
||||
if(type == BackendType.SOLMAN) {
|
||||
args = ['-cID', changeId,
|
||||
'-tID', transportRequestId,
|
||||
applicationId, "\"$filePath\""],
|
||||
applicationId, "\"$filePath\""]
|
||||
} else if (type == BackendType.CTS) {
|
||||
args = ['-tID', transportRequestId,
|
||||
"\"$filePath\""]
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid backend type: ${type}")
|
||||
}
|
||||
|
||||
int rc = executeWithCredentials(type,
|
||||
endpoint,
|
||||
credentialsId,
|
||||
'upload-file-to-transport',
|
||||
args,
|
||||
false,
|
||||
cmclientOpts) as int
|
||||
|
||||
if(rc == 0) {
|
||||
@ -100,27 +131,48 @@ public class ChangeManagement implements Serializable {
|
||||
|
||||
}
|
||||
|
||||
def executeWithCredentials(String endpoint, String credentialsId, String command, List<String> args, String clientOpts = '') {
|
||||
def executeWithCredentials(BackendType type, String endpoint, String credentialsId, String command, List<String> args, boolean returnStdout = false, String clientOpts = '') {
|
||||
script.withCredentials([script.usernamePassword(
|
||||
credentialsId: credentialsId,
|
||||
passwordVariable: 'password',
|
||||
usernameVariable: 'username')]) {
|
||||
def cmScript = getCMCommandLine(endpoint, script.username, script.password,
|
||||
def cmScript = getCMCommandLine(type, endpoint, script.username, script.password,
|
||||
command, args,
|
||||
clientOpts)
|
||||
|
||||
Map shArgs = [:]
|
||||
if(returnStdout)
|
||||
shArgs.put('returnStdout', true)
|
||||
else
|
||||
shArgs.put('returnStatus', true)
|
||||
|
||||
shArgs.put('script', cmScript)
|
||||
|
||||
// user and password are masked by withCredentials
|
||||
script.echo """[INFO] Executing command line: "${cmScript}"."""
|
||||
def returnValue = script.sh(returnStatus: true,
|
||||
script: cmScript)
|
||||
return returnValue;
|
||||
|
||||
return script.sh(shArgs)
|
||||
}
|
||||
}
|
||||
|
||||
void releaseTransportRequest(BackendType type,String changeId, String transportRequestId, String endpoint, String credentialsId, String clientOpts = '') {
|
||||
|
||||
def cmd
|
||||
List args = []
|
||||
|
||||
if(type == BackendType.SOLMAN) {
|
||||
cmd = 'release-transport'
|
||||
args << '-cID'
|
||||
args << changeId
|
||||
} else if(type == BackendType.CTS) {
|
||||
cmd = 'export-transport'
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid backend type: '${type}'")
|
||||
}
|
||||
|
||||
void releaseTransportRequest(String changeId, String transportRequestId, String endpoint, String credentialsId, String clientOpts = '') {
|
||||
int rc = executeWithCredentials( endpoint, credentialsId, 'release-transport', ['-cID', changeId,
|
||||
'-tID', transportRequestId], clientOpts) as int
|
||||
args << '-tID'
|
||||
args << transportRequestId
|
||||
|
||||
int rc = executeWithCredentials(type, endpoint, credentialsId, cmd, args, false, clientOpts) as int
|
||||
if(rc == 0) {
|
||||
return
|
||||
} else {
|
||||
@ -128,7 +180,8 @@ public class ChangeManagement implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
String getCMCommandLine(String endpoint,
|
||||
String getCMCommandLine(BackendType type,
|
||||
String endpoint,
|
||||
String username,
|
||||
String password,
|
||||
String command,
|
||||
@ -143,7 +196,7 @@ public class ChangeManagement implements Serializable {
|
||||
cmclient -e '$endpoint' \
|
||||
-u '$username' \
|
||||
-p '$password' \
|
||||
-t SOLMAN \
|
||||
-t ${type} \
|
||||
${command} ${(args as Iterable).join(' ')}
|
||||
"""
|
||||
return cmCommandLine
|
||||
|
29
src/com/sap/piper/cm/StepHelpers.groovy
Normal file
29
src/com/sap/piper/cm/StepHelpers.groovy
Normal file
@ -0,0 +1,29 @@
|
||||
package com.sap.piper.cm;
|
||||
|
||||
import com.cloudbees.groovy.cps.NonCPS
|
||||
|
||||
public class StepHelpers {
|
||||
|
||||
@NonCPS
|
||||
static BackendType getBackendTypeAndLogInfoIfCMIntegrationDisabled(def step, Map configuration) {
|
||||
|
||||
BackendType backendType
|
||||
|
||||
try {
|
||||
backendType = configuration.changeManagement.type as BackendType
|
||||
} catch(IllegalArgumentException e) {
|
||||
step.error "Invalid backend type: '${configuration.changeManagement.type}'. " +
|
||||
"Valid values: [${BackendType.values().join(', ')}]. " +
|
||||
"Configuration: 'changeManagement/type'."
|
||||
}
|
||||
|
||||
if (backendType == BackendType.NONE) {
|
||||
step.echo "[INFO] Change management integration intentionally switched off. " +
|
||||
"In order to enable it provide 'changeManagement/type with one of " +
|
||||
"[${BackendType.values().minus(BackendType.NONE).join(', ')}] and maintain " +
|
||||
"other required properties like 'endpoint', 'credentialsId'."
|
||||
}
|
||||
|
||||
return backendType
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import com.sap.piper.cm.ChangeManagementException
|
||||
import hudson.AbortException
|
||||
import util.BasePiperTest
|
||||
import util.JenkinsCredentialsRule
|
||||
import util.JenkinsLoggingRule
|
||||
import util.JenkinsReadYamlRule
|
||||
import util.JenkinsStepRule
|
||||
import util.Rules
|
||||
@ -19,6 +20,7 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
|
||||
private ExpectedException thrown = ExpectedException.none()
|
||||
private JenkinsStepRule jsr = new JenkinsStepRule(this)
|
||||
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
|
||||
|
||||
@Rule
|
||||
public RuleChain ruleChain = Rules
|
||||
@ -26,6 +28,7 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(thrown)
|
||||
.around(jsr)
|
||||
.around(jlr)
|
||||
.around(new JenkinsCredentialsRule(this)
|
||||
.withCredentials('CM', 'anonymous', '********'))
|
||||
|
||||
@ -40,17 +43,22 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
public void changeIsInStatusDevelopmentTest() {
|
||||
|
||||
ChangeManagement cm = getChangeManagementUtils(true)
|
||||
boolean inDevelopment = jsr.step.checkChangeInDevelopment(
|
||||
jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
cmUtils: cm,
|
||||
changeManagement: [endpoint: 'https://example.org/cm'])
|
||||
changeManagement: [
|
||||
type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm'],
|
||||
failIfStatusIsNotInDevelopment: true)
|
||||
|
||||
assert inDevelopment
|
||||
assert cmUtilReceivedParams == [
|
||||
changeId: '001',
|
||||
endpoint: 'https://example.org/cm',
|
||||
credentialsId: 'CM',
|
||||
cmclientOpts: ''
|
||||
]
|
||||
|
||||
// no exception in thrown, so the change is in status 'in development'.
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -61,8 +69,10 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
|
||||
ChangeManagement cm = getChangeManagementUtils(false)
|
||||
jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
cmUtils: cm,
|
||||
changeManagement: [endpoint: 'https://example.org/cm'])
|
||||
changeManagement: [type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm'])
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -70,6 +80,7 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
|
||||
ChangeManagement cm = getChangeManagementUtils(false)
|
||||
boolean inDevelopment = jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
cmUtils: cm,
|
||||
changeManagement: [endpoint: 'https://example.org/cm'],
|
||||
failIfStatusIsNotInDevelopment: false)
|
||||
@ -81,9 +92,11 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
ChangeManagement cm = getChangeManagementUtils(true, '0815')
|
||||
|
||||
jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
changeDocumentId: '42',
|
||||
cmUtils: cm,
|
||||
changeManagement: [endpoint: 'https://example.org/cm'])
|
||||
changeManagement: [type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm'])
|
||||
|
||||
assert cmUtilReceivedParams.changeId == '42'
|
||||
}
|
||||
@ -93,8 +106,10 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
ChangeManagement cm = getChangeManagementUtils(true, '0815')
|
||||
|
||||
jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
cmUtils: cm,
|
||||
changeManagement : [endpoint: 'https://example.org/cm'])
|
||||
changeManagement : [type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm'])
|
||||
|
||||
assert cmUtilReceivedParams.changeId == '0815'
|
||||
}
|
||||
@ -118,8 +133,10 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
}
|
||||
|
||||
jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
cmUtils: cm,
|
||||
changeManagement: [endpoint: 'https://example.org/cm'])
|
||||
changeManagement: [type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm'])
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -132,8 +149,10 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
|
||||
ChangeManagement cm = getChangeManagementUtils(false, null)
|
||||
jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
cmUtils: cm,
|
||||
changeManagement: [endpoint: 'https://example.org/cm'])
|
||||
changeManagement: [endpoint: 'https://example.org/cm',
|
||||
type: 'SOLMAN'])
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -146,8 +165,21 @@ class CheckChangeInDevelopmentTest extends BasePiperTest {
|
||||
|
||||
ChangeManagement cm = getChangeManagementUtils(false, '')
|
||||
jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
cmUtils: cm,
|
||||
changeManagement: [endpoint: 'https://example.org/cm'])
|
||||
changeManagement: [type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm'])
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cmIntegrationSwichtedOffTest() {
|
||||
|
||||
jlr.expect('[INFO] Change management integration intentionally switched off.')
|
||||
|
||||
jsr.step.checkChangeInDevelopment(
|
||||
script: nullScript,
|
||||
changeManagement: [type: 'NONE'])
|
||||
|
||||
}
|
||||
|
||||
private ChangeManagement getChangeManagementUtils(boolean inDevelopment, String changeDocumentId = '001') {
|
||||
|
@ -105,6 +105,11 @@ class CloudFoundryDeployTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testCfNativeWithAppName() {
|
||||
jryr.registerYaml('test.yml', "applications: [[name: 'manifestAppName']]")
|
||||
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
|
||||
generatedFile = parameters.file
|
||||
data = parameters.data
|
||||
})
|
||||
jsr.step.cloudFoundryDeploy([
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
@ -125,6 +130,11 @@ class CloudFoundryDeployTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testCfNativeWithAppNameCustomApi() {
|
||||
jryr.registerYaml('test.yml', "applications: [[name: 'manifestAppName']]")
|
||||
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
|
||||
generatedFile = parameters.file
|
||||
data = parameters.data
|
||||
})
|
||||
jsr.step.cloudFoundryDeploy([
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
@ -142,6 +152,11 @@ class CloudFoundryDeployTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testCfNativeWithAppNameCompatible() {
|
||||
jryr.registerYaml('test.yml', "applications: [[name: 'manifestAppName']]")
|
||||
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
|
||||
generatedFile = parameters.file
|
||||
data = parameters.data
|
||||
})
|
||||
jsr.step.cloudFoundryDeploy([
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
@ -165,7 +180,11 @@ class CloudFoundryDeployTest extends BasePiperTest {
|
||||
@Test
|
||||
void testCfNativeAppNameFromManifest() {
|
||||
helper.registerAllowedMethod('fileExists', [String.class], { s -> return true })
|
||||
jryr.registerYaml('test.yml', "[applications: [[name: 'manifestAppName']]]")
|
||||
jryr.registerYaml('test.yml', "applications: [[name: 'manifestAppName']]")
|
||||
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
|
||||
generatedFile = parameters.file
|
||||
data = parameters.data
|
||||
})
|
||||
|
||||
jsr.step.cloudFoundryDeploy([
|
||||
script: nullScript,
|
||||
@ -185,6 +204,10 @@ class CloudFoundryDeployTest extends BasePiperTest {
|
||||
void testCfNativeWithoutAppName() {
|
||||
helper.registerAllowedMethod('fileExists', [String.class], { s -> return true })
|
||||
jryr.registerYaml('test.yml', "applications: [[]]")
|
||||
helper.registerAllowedMethod('writeYaml', [Map], { Map parameters ->
|
||||
generatedFile = parameters.file
|
||||
data = parameters.data
|
||||
})
|
||||
thrown.expect(hudson.AbortException)
|
||||
thrown.expectMessage('[cloudFoundryDeploy] ERROR: No appName available in manifest test.yml.')
|
||||
|
||||
|
@ -2,8 +2,10 @@ import static java.util.stream.Collectors.toList
|
||||
import static org.hamcrest.Matchers.empty
|
||||
import static org.hamcrest.Matchers.is
|
||||
import static org.junit.Assert.assertThat
|
||||
import static org.junit.Assert.fail
|
||||
|
||||
import java.lang.reflect.Field
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Rule
|
||||
@ -12,6 +14,7 @@ import org.junit.rules.RuleChain
|
||||
|
||||
import groovy.io.FileType
|
||||
import util.BasePiperTest
|
||||
|
||||
import util.Rules
|
||||
|
||||
/*
|
||||
@ -22,6 +25,69 @@ public class CommonStepsTest extends BasePiperTest{
|
||||
@Rule
|
||||
public RuleChain ruleChain = Rules.getCommonRules(this)
|
||||
|
||||
private static fieldRelatedWhitelist = [
|
||||
'toolValidate', // step is intended to be configured by other steps
|
||||
'durationMeasure', // only expects parameters via signature
|
||||
'prepareDefaultValues', // special step (infrastructure)
|
||||
'pipelineStashFilesAfterBuild', // intended to be called from pipelineStashFiles
|
||||
'pipelineStashFilesBeforeBuild', // intended to be called from pipelineStashFiles
|
||||
'pipelineStashFiles', // only forwards to before/after step
|
||||
'pipelineExecute', // special step (infrastructure)
|
||||
'commonPipelineEnvironment', // special step (infrastructure)
|
||||
'handlePipelineStepErrors', // special step (infrastructure)
|
||||
]
|
||||
|
||||
@Test
|
||||
public void generalConfigKeysSetPresentTest() {
|
||||
|
||||
def fieldName = 'GENERAL_CONFIG_KEYS'
|
||||
// the steps added to the fieldRelatedWhitelist do not take the general config at all
|
||||
def stepsWithoutGeneralConfigKeySet = fieldCheck(fieldName, fieldRelatedWhitelist.plus(['gaugeExecuteTests',
|
||||
'pipelineRestartSteps']))
|
||||
|
||||
assertThat("Steps without ${fieldName} field (or that field is not a Set): ${stepsWithoutGeneralConfigKeySet}",
|
||||
stepsWithoutGeneralConfigKeySet, is(empty()))
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stepConfigKeysSetPresentTest() {
|
||||
|
||||
def fieldName = 'STEP_CONFIG_KEYS'
|
||||
def stepsWithoutStepConfigKeySet = fieldCheck(fieldName, fieldRelatedWhitelist.plus('setupCommonPipelineEnvironment'))
|
||||
|
||||
assertThat("Steps without ${fieldName} field (or that field is not a Set): ${stepsWithoutStepConfigKeySet}",
|
||||
stepsWithoutStepConfigKeySet, is(empty()))
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parametersKeysSetPresentTest() {
|
||||
|
||||
def fieldName = 'PARAMETER_KEYS'
|
||||
def stepsWithoutParametersKeySet = fieldCheck(fieldName, fieldRelatedWhitelist.plus('setupCommonPipelineEnvironment'))
|
||||
|
||||
assertThat("Steps without ${fieldName} field (or that field is not a Set): ${stepsWithoutParametersKeySet}",
|
||||
stepsWithoutParametersKeySet, is(empty()))
|
||||
}
|
||||
|
||||
private fieldCheck(fieldName, whitelist) {
|
||||
|
||||
def stepsWithoutGeneralConfigKeySet = []
|
||||
|
||||
for(def step in getSteps()) {
|
||||
if(whitelist.contains(step)) continue
|
||||
|
||||
def fields = loadScript("${step}.groovy").getClass().getDeclaredFields() as Set
|
||||
Field generalConfigKeyField = fields.find{ it.getName() == fieldName}
|
||||
if(! generalConfigKeyField ||
|
||||
! generalConfigKeyField
|
||||
.getType()
|
||||
.isAssignableFrom(Set.class)) {
|
||||
stepsWithoutGeneralConfigKeySet.add(step)
|
||||
}
|
||||
}
|
||||
return stepsWithoutGeneralConfigKeySet
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stepsWithWrongFieldNameTest() {
|
||||
|
||||
@ -64,6 +130,35 @@ public class CommonStepsTest extends BasePiperTest{
|
||||
assertThat("Steps with wrong step name or without STEP_NAME field.: ${stepsWithWrongStepName}",
|
||||
stepsWithWrongStepName, is(empty()))
|
||||
}
|
||||
/*
|
||||
* With that test we ensure that all return types of the call methods of all the steps
|
||||
* are void. Return types other than void are not possible when running inside declarative
|
||||
* pipelines. Parameters shared between several steps needs to be shared via the commonPipelineEnvironment.
|
||||
*/
|
||||
@Test
|
||||
public void returnTypeForCallMethodsIsVoidTest() {
|
||||
|
||||
def stepsWithCallMethodsOtherThanVoid = []
|
||||
|
||||
def whitelist = [
|
||||
'transportRequestCreate',
|
||||
'durationMeasure',
|
||||
]
|
||||
|
||||
for(def step in getSteps()) {
|
||||
def methods = loadScript("${step}.groovy").getClass().getDeclaredMethods() as List
|
||||
Collection callMethodsWithReturnTypeOtherThanVoid =
|
||||
methods.stream()
|
||||
.filter { ! whitelist.contains(step) }
|
||||
.filter { it.getName() == 'call' &&
|
||||
it.getReturnType() != Void.TYPE }
|
||||
.collect(toList())
|
||||
if(!callMethodsWithReturnTypeOtherThanVoid.isEmpty()) stepsWithCallMethodsOtherThanVoid << step
|
||||
}
|
||||
|
||||
assertThat("Steps with call methods with return types other than void: ${stepsWithCallMethodsOtherThanVoid}",
|
||||
stepsWithCallMethodsOtherThanVoid, is(empty()))
|
||||
}
|
||||
|
||||
private static getSteps() {
|
||||
List steps = []
|
||||
|
@ -115,17 +115,6 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
assertTrue(bodyExecuted)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteInsideDockerNoScript() throws Exception {
|
||||
jsr.step.dockerExecute(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().trim())
|
||||
assertTrue(bodyExecuted)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteInsideDockerContainerWithParameters() throws Exception {
|
||||
jsr.step.dockerExecute(script: nullScript,
|
||||
@ -172,6 +161,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
void testSidecarDefault(){
|
||||
jsr.step.dockerExecute(
|
||||
script: nullScript,
|
||||
dockerName: 'maven',
|
||||
dockerImage: 'maven:3.5-jdk-8-alpine',
|
||||
sidecarEnvVars: ['testEnv':'testVal'],
|
||||
sidecarImage: 'selenium/standalone-chrome',
|
||||
@ -186,9 +176,14 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
assertThat(docker.imagePullCount, is(2))
|
||||
assertThat(docker.sidecarParameters, allOf(
|
||||
containsString('--env testEnv=testVal'),
|
||||
containsString('--volume /dev/shm:/dev/shm')
|
||||
containsString('--volume /dev/shm:/dev/shm'),
|
||||
containsString('--network sidecar-'),
|
||||
containsString('--network-alias testAlias')
|
||||
))
|
||||
assertThat(docker.parameters, allOf(
|
||||
containsString('--network sidecar-'),
|
||||
containsString('--network-alias maven')
|
||||
))
|
||||
assertThat(docker.parameters, containsString('--link uniqueId:testAlias'))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -217,8 +212,7 @@ class DockerExecuteTest extends BasePiperTest {
|
||||
sidecarEnvVars: ['testEnv':'testVal'],
|
||||
sidecarImage: 'selenium/standalone-chrome',
|
||||
sidecarName: 'selenium',
|
||||
sidecarVolumeBind: ['/dev/shm':'/dev/shm'],
|
||||
dockerLinkAlias: 'testAlias',
|
||||
sidecarVolumeBind: ['/dev/shm':'/dev/shm']
|
||||
) {
|
||||
bodyExecuted = true
|
||||
}
|
||||
|
137
test/groovy/GaugeExecuteTestsTest.groovy
Normal file
137
test/groovy/GaugeExecuteTestsTest.groovy
Normal file
@ -0,0 +1,137 @@
|
||||
#!groovy
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import util.*
|
||||
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class GaugeExecuteTestsTest extends BasePiperTest {
|
||||
private JenkinsStepRule jsr = new JenkinsStepRule(this)
|
||||
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
|
||||
private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
|
||||
private JenkinsEnvironmentRule jer = new JenkinsEnvironmentRule(this)
|
||||
private ExpectedException thrown = ExpectedException.none()
|
||||
|
||||
@Rule
|
||||
public RuleChain rules = Rules
|
||||
.getCommonRules(this)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(jscr)
|
||||
.around(jlr)
|
||||
.around(jer)
|
||||
.around(jsr)
|
||||
.around(thrown)
|
||||
|
||||
def gitParams = [:]
|
||||
def seleniumParams = [:]
|
||||
|
||||
@Before
|
||||
void init() throws Exception {
|
||||
helper.registerAllowedMethod("git", [Map.class], { map -> gitParams = map })
|
||||
helper.registerAllowedMethod("unstash", [String.class], { s -> return [s]})
|
||||
|
||||
helper.registerAllowedMethod('seleniumExecuteTests', [Map.class, Closure.class], {map, body ->
|
||||
seleniumParams = map
|
||||
return body()
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteGaugeDefaultSuccess() throws Exception {
|
||||
jsr.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
testServerUrl: 'http://test.url'
|
||||
)
|
||||
assertThat(jscr.shell, hasItem(stringContainsInOrder([
|
||||
'export HOME=${HOME:-$(pwd)}',
|
||||
'if [ "$HOME" = "/" ]; then export HOME=$(pwd); fi',
|
||||
'export PATH=$HOME/bin/gauge:$PATH',
|
||||
'mkdir -p $HOME/bin/gauge',
|
||||
'curl -SsL https://downloads.gauge.org/stable | sh -s -- --location=$HOME/bin/gauge',
|
||||
'gauge telemetry off',
|
||||
'gauge install java',
|
||||
'gauge install html-report',
|
||||
'gauge install xml-report',
|
||||
'mvn test-compile gauge:execute -DspecsDir=specs'
|
||||
])))
|
||||
assertThat(seleniumParams.dockerImage, is('maven:3.5-jdk-8'))
|
||||
assertThat(seleniumParams.dockerEnvVars, hasEntry('TARGET_SERVER_URL', 'http://test.url'))
|
||||
assertThat(seleniumParams.dockerName, is('maven'))
|
||||
assertThat(seleniumParams.dockerWorkspace, is(''))
|
||||
assertThat(seleniumParams.stashContent, hasSize(2))
|
||||
assertThat(seleniumParams.stashContent, allOf(hasItem('buildDescriptor'), hasItem('tests')))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteGaugeNode() throws Exception {
|
||||
jsr.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
buildTool: 'npm',
|
||||
dockerEnvVars: ['TARGET_SERVER_URL':'http://custom.url'],
|
||||
juStabUtils: utils,
|
||||
testOptions: 'testSpec'
|
||||
)
|
||||
assertThat(jscr.shell, hasItem(stringContainsInOrder([
|
||||
'gauge install js',
|
||||
'gauge run testSpec'
|
||||
])))
|
||||
assertThat(seleniumParams.dockerImage, is('node:8-stretch'))
|
||||
assertThat(seleniumParams.dockerEnvVars, hasEntry('TARGET_SERVER_URL', 'http://custom.url'))
|
||||
assertThat(seleniumParams.dockerName, is('npm'))
|
||||
assertThat(seleniumParams.dockerWorkspace, is('/home/node'))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteCustomWithError() throws Exception {
|
||||
helper.registerAllowedMethod("sh", [String.class], { s ->
|
||||
throw new RuntimeException('Test Error')
|
||||
})
|
||||
thrown.expect(RuntimeException)
|
||||
thrown.expectMessage('Test Error')
|
||||
try {
|
||||
jsr.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
dockerImage: 'testImage',
|
||||
dockerName: 'testImageName',
|
||||
dockerWorkspace: '/home/test',
|
||||
failOnError: true,
|
||||
stashContent: ['testStash'],
|
||||
)
|
||||
|
||||
} finally{
|
||||
assertThat(seleniumParams.dockerImage, is('testImage'))
|
||||
assertThat(seleniumParams.dockerName, is('testImageName'))
|
||||
assertThat(seleniumParams.dockerWorkspace, is('/home/test'))
|
||||
assertThat(seleniumParams.stashContent, hasSize(1))
|
||||
assertThat(jlr.log, containsString('[gaugeExecuteTests] One or more tests failed'))
|
||||
assertThat(nullScript.currentBuild.result, is('UNSTABLE'))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteGaugeCustomRepo() throws Exception {
|
||||
helper.registerAllowedMethod('git', [String.class], null)
|
||||
helper.registerAllowedMethod('stash', [String.class], null)
|
||||
|
||||
jsr.step.gaugeExecuteTests(
|
||||
script: nullScript,
|
||||
juStabUtils: utils,
|
||||
testRepository: 'myTestRepo',
|
||||
failOnError: true
|
||||
)
|
||||
|
||||
// nested matchers do not work correctly
|
||||
assertThat(seleniumParams.stashContent, hasItem(startsWith('testContent-')))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
}
|
196
test/groovy/GithubPublishReleaseTest.groovy
Normal file
196
test/groovy/GithubPublishReleaseTest.groovy
Normal file
File diff suppressed because one or more lines are too long
82
test/groovy/HandlePipelineStepErrorTest.groovy
Normal file
82
test/groovy/HandlePipelineStepErrorTest.groovy
Normal file
@ -0,0 +1,82 @@
|
||||
#!groovy
|
||||
import static org.hamcrest.Matchers.is
|
||||
import static org.hamcrest.Matchers.not
|
||||
import static org.hamcrest.Matchers.containsString
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
import util.BasePiperTest
|
||||
import util.JenkinsLoggingRule
|
||||
import util.JenkinsStepRule
|
||||
import util.Rules
|
||||
|
||||
class HandlePipelineStepErrorsTest extends BasePiperTest {
|
||||
private JenkinsStepRule jsr = new JenkinsStepRule(this)
|
||||
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
|
||||
private ExpectedException thrown = ExpectedException.none()
|
||||
|
||||
@Rule
|
||||
public RuleChain rules = Rules
|
||||
.getCommonRules(this)
|
||||
.around(jlr)
|
||||
.around(jsr)
|
||||
.around(thrown)
|
||||
|
||||
@Test
|
||||
void testBeginAndEndMessage() {
|
||||
def isExecuted
|
||||
jsr.step.handlePipelineStepErrors([
|
||||
stepName: 'testStep',
|
||||
stepParameters: ['something': 'anything']
|
||||
]) {
|
||||
isExecuted = true
|
||||
}
|
||||
// asserts
|
||||
assertThat(isExecuted, is(true))
|
||||
assertThat(jlr.log, containsString('--- BEGIN LIBRARY STEP: testStep'))
|
||||
assertThat(jlr.log, containsString('--- END LIBRARY STEP: testStep'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNonVerbose() {
|
||||
try {
|
||||
jsr.step.handlePipelineStepErrors([
|
||||
stepName: 'testStep',
|
||||
stepParameters: ['something': 'anything'],
|
||||
echoDetails: false
|
||||
]) {
|
||||
throw new Exception('TestError')
|
||||
}
|
||||
} catch (ignore) {
|
||||
} finally {
|
||||
// asserts
|
||||
assertThat(jlr.log, not(containsString('--- BEGIN LIBRARY STEP: testStep')))
|
||||
assertThat(jlr.log, not(containsString('--- END LIBRARY STEP: testStep')))
|
||||
assertThat(jlr.log, not(containsString('--- ERROR OCCURRED IN LIBRARY STEP: testStep')))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorsMessage() {
|
||||
def isReported
|
||||
try {
|
||||
jsr.step.handlePipelineStepErrors([
|
||||
stepName: 'testStep',
|
||||
stepParameters: ['something': 'anything']
|
||||
]) {
|
||||
throw new Exception('TestError')
|
||||
}
|
||||
} catch (ignore) {
|
||||
isReported = true
|
||||
} finally {
|
||||
// asserts
|
||||
assertThat(isReported, is(true))
|
||||
assertThat(jlr.log, containsString('--- ERROR OCCURRED IN LIBRARY STEP: testStep'))
|
||||
assertThat(jlr.log, containsString('[something:anything]'))
|
||||
}
|
||||
}
|
||||
}
|
240
test/groovy/MailSendNotificationTest.groovy
Normal file
240
test/groovy/MailSendNotificationTest.groovy
Normal file
@ -0,0 +1,240 @@
|
||||
#!groovy
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.RuleChain
|
||||
import util.*
|
||||
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class MailSendNotificationTest extends BasePiperTest {
|
||||
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
|
||||
private JenkinsStepRule jsr = new JenkinsStepRule(this)
|
||||
private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
|
||||
|
||||
@Rule
|
||||
public RuleChain ruleChain = Rules
|
||||
.getCommonRules(this)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(jlr)
|
||||
.around(jscr)
|
||||
.around(jsr)
|
||||
|
||||
@Before
|
||||
void init() throws Exception {
|
||||
// register Jenkins commands with mock values
|
||||
helper.registerAllowedMethod("deleteDir", [], null)
|
||||
helper.registerAllowedMethod("sshagent", [Map.class, Closure.class], null)
|
||||
|
||||
nullScript.commonPipelineEnvironment.configuration = nullScript.commonPipelineEnvironment.configuration ?: [:]
|
||||
nullScript.commonPipelineEnvironment.configuration['general'] = nullScript.commonPipelineEnvironment.configuration['general'] ?: [:]
|
||||
nullScript.commonPipelineEnvironment.configuration['steps'] = nullScript.commonPipelineEnvironment.configuration['steps'] ?: [:]
|
||||
nullScript.commonPipelineEnvironment.configuration['steps']['mailSendNotification'] = nullScript.commonPipelineEnvironment.configuration['steps']['mailSendNotification'] ?: [:]
|
||||
|
||||
helper.registerAllowedMethod('requestor', [], { -> return [$class: 'RequesterRecipientProvider']})
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDistinctRecipients() throws Exception {
|
||||
// git log -10 --pretty=format:"%ae %ce"
|
||||
def input = '''user1@domain.com noreply+github@domain.com
|
||||
user1@domain.com noreply+github@domain.com
|
||||
user3@domain.com noreply+github@domain.com
|
||||
user2@domain.com user1@domain.com
|
||||
user1@domain.com noreply+github@domain.com
|
||||
user3@domain.com noreply+github@domain.com
|
||||
user3@domain.com noreply+github@domain.com
|
||||
user3@domain.com noreply+github@domain.com
|
||||
user3@domain.com noreply+github@domain.com
|
||||
user3@domain.com noreply+github@domain.com'''
|
||||
|
||||
def result = jsr.step.getDistinctRecipients(input)
|
||||
// asserts
|
||||
assertThat(result.split(' '), arrayWithSize(3))
|
||||
assertThat(result, containsString('user1@domain.com'))
|
||||
assertThat(result, containsString('user2@domain.com'))
|
||||
assertThat(result, containsString('user3@domain.com'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCulpritsFromGitCommit() throws Exception {
|
||||
def gitCommand = "git log -2 --pretty=format:'%ae %ce'"
|
||||
def expected = "user2@domain.com user3@domain.com"
|
||||
|
||||
jscr.setReturnValue("git log -2 --pretty=format:'%ae %ce'", 'user2@domain.com user3@domain.com')
|
||||
|
||||
def result = jsr.step.getCulprits(
|
||||
[
|
||||
gitSSHCredentialsId: '',
|
||||
gitUrl: 'git@github.wdf.domain.com:IndustryCloudFoundation/pipeline-test-node.git',
|
||||
gitCommitId: 'f0973368a35a2b973612acb86f932c61f2635f6e'
|
||||
],
|
||||
'master',
|
||||
2)
|
||||
println("LOGS: ${jlr.log}")
|
||||
println("RESULT: ${result}")
|
||||
// asserts
|
||||
assertThat(result, containsString('user2@domain.com'))
|
||||
assertThat(result, containsString('user3@domain.com'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCulpritsWithEmptyGitCommit() throws Exception {
|
||||
|
||||
jscr.setReturnValue('git log > /dev/null 2>&1',1)
|
||||
|
||||
jsr.step.getCulprits(
|
||||
[
|
||||
gitSSHCredentialsId: '',
|
||||
gitUrl: 'git@github.wdf.domain.com:IndustryCloudFoundation/pipeline-test-node.git',
|
||||
gitCommitId: ''
|
||||
],
|
||||
'master',
|
||||
2)
|
||||
// asserts
|
||||
assertThat(jlr.log, containsString('[mailSendNotification] No git context available to retrieve culprits'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCulpritsWithoutGitCommit() throws Exception {
|
||||
|
||||
jscr.setReturnValue('git log > /dev/null 2>&1',1)
|
||||
|
||||
jsr.step.getCulprits(
|
||||
[
|
||||
gitSSHCredentialsId: '',
|
||||
gitUrl: 'git@github.wdf.domain.com:IndustryCloudFoundation/pipeline-test-node.git',
|
||||
gitCommitId: null
|
||||
],
|
||||
'master',
|
||||
2)
|
||||
// asserts
|
||||
assertThat(jlr.log, containsString('[mailSendNotification] No git context available to retrieve culprits'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCulpritsWithoutBranch() throws Exception {
|
||||
|
||||
jscr.setReturnValue('git log > /dev/null 2>&1',1)
|
||||
|
||||
jsr.step.getCulprits(
|
||||
[
|
||||
gitSSHCredentialsId: '',
|
||||
gitUrl: 'git@github.wdf.domain.com:IndustryCloudFoundation/pipeline-test-node.git',
|
||||
gitCommitId: ''
|
||||
],
|
||||
null,
|
||||
2)
|
||||
// asserts
|
||||
assertThat(jlr.log, containsString('[mailSendNotification] No git context available to retrieve culprits'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendNotificationMail() throws Exception {
|
||||
def emailParameters = [:]
|
||||
def buildMock = [
|
||||
fullProjectName: 'testProjectName',
|
||||
displayName: 'testDisplayName',
|
||||
result: 'FAILURE',
|
||||
rawBuild: [
|
||||
getLog: { cnt -> return ['Setting http proxy: proxy.wdf.domain.com:8080',
|
||||
' > git fetch --no-tags --progress https://github.com/SAP/jenkins-library.git +refs/heads/*:refs/remotes/origin/*',
|
||||
'Checking out Revision myUniqueCommitId (master)',
|
||||
' > git config core.sparsecheckout # timeout=10',
|
||||
' > git checkout -f myUniqueCommitId',
|
||||
'Commit message: "Merge pull request #147 from marcusholl/pr/useGitRevParseForInsideGitRepoCheck"',
|
||||
' > git rev-list --no-walk myUniqueCommitId # timeout=10',
|
||||
'[Pipeline] node',
|
||||
'Running on Jenkins in /var/jenkins_home/workspace/Test/UserId/ECHO',
|
||||
'[Pipeline] {',
|
||||
'[Pipeline] stage',
|
||||
'[Pipeline] { (A)',
|
||||
'[Pipeline] script',
|
||||
'[Pipeline] {']
|
||||
}
|
||||
],
|
||||
getPreviousBuild: {
|
||||
return null
|
||||
}
|
||||
]
|
||||
nullScript.currentBuild = buildMock
|
||||
nullScript.commonPipelineEnvironment.configuration['steps']['mailSendNotification']['notificationRecipients'] = 'piper@domain.com'
|
||||
helper.registerAllowedMethod('emailext', [Map.class], { map ->
|
||||
emailParameters = map
|
||||
return ''
|
||||
})
|
||||
|
||||
jsr.step.mailSendNotification(
|
||||
script: nullScript,
|
||||
notifyCulprits: false,
|
||||
gitUrl: 'git@github.wdf.domain.com:IndustryCloudFoundation/pipeline-test-node.git'
|
||||
)
|
||||
// asserts
|
||||
assertThat(emailParameters.to, is('piper@domain.com'))
|
||||
assertThat(emailParameters.subject, is('FAILURE: Build testProjectName testDisplayName'))
|
||||
assertThat(emailParameters.body, startsWith('<a href="http://build.url">http://build.url</a>\n<br>\nTo have a detailed look at the different pipeline stages: <a href="null">null</a>\n<br>\n<h3>Last lines of output</h3>'))
|
||||
assertThat(emailParameters.body, containsString(' > git fetch --no-tags --progress https://github.com/SAP/jenkins-library.git +refs/heads/*:refs/remotes/origin/*'))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendNotificationMailWithGeneralConfig() throws Exception {
|
||||
def credentials
|
||||
nullScript.currentBuild = [
|
||||
fullProjectName: 'testProjectName',
|
||||
displayName: 'testDisplayName',
|
||||
result: 'FAILURE',
|
||||
rawBuild: [ getLog: { cnt -> return ['empty'] } ],
|
||||
getChangeSets: { return null },
|
||||
getPreviousBuild: { return null }
|
||||
]
|
||||
nullScript.commonPipelineEnvironment.configuration['general']['gitSshKeyCredentialsId'] = 'myCredentialsId'
|
||||
helper.registerAllowedMethod('emailext', [Map.class], null)
|
||||
helper.registerAllowedMethod("sshagent", [Map.class, Closure.class], { map, closure ->
|
||||
credentials = map.credentials
|
||||
return null
|
||||
})
|
||||
|
||||
jscr.setReturnValue("git log -0 --pretty=format:'%ae %ce'", 'user2@domain.com user3@domain.com')
|
||||
|
||||
jsr.step.mailSendNotification(
|
||||
script: nullScript,
|
||||
gitCommitId: 'abcd1234',
|
||||
//notifyCulprits: true,
|
||||
gitUrl: 'git@github.wdf.domain.com:IndustryCloudFoundation/pipeline-test-node.git'
|
||||
)
|
||||
// asserts
|
||||
assertThat(credentials, hasItem('myCredentialsId'))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSendNotificationMailWithEmptySshKey() throws Exception {
|
||||
def credentials
|
||||
nullScript.currentBuild = [
|
||||
fullProjectName: 'testProjectName',
|
||||
displayName: 'testDisplayName',
|
||||
result: 'FAILURE',
|
||||
rawBuild: [ getLog: { cnt -> return ['empty'] } ],
|
||||
getChangeSets: { return null },
|
||||
getPreviousBuild: { return null }
|
||||
]
|
||||
helper.registerAllowedMethod('emailext', [Map.class], null)
|
||||
helper.registerAllowedMethod("sshagent", [Map.class, Closure.class], { map, closure ->
|
||||
credentials = map.credentials
|
||||
return null
|
||||
})
|
||||
|
||||
jscr.setReturnValue("git log -0 --pretty=format:'%ae %ce'", 'user2@domain.com user3@domain.com')
|
||||
|
||||
jsr.step.mailSendNotification(
|
||||
script: nullScript,
|
||||
gitCommitId: 'abcd1234',
|
||||
gitUrl: 'git@github.wdf.domain.com:IndustryCloudFoundation/pipeline-test-node.git'
|
||||
)
|
||||
// asserts
|
||||
assertThat(credentials, hasItem(''))
|
||||
assertJobStatusSuccess()
|
||||
}
|
||||
}
|
126
test/groovy/PipelineRestartStepsTest.groovy
Normal file
126
test/groovy/PipelineRestartStepsTest.groovy
Normal file
@ -0,0 +1,126 @@
|
||||
#!groovy
|
||||
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.RuleChain
|
||||
import util.*
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString
|
||||
import static org.hamcrest.CoreMatchers.is
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class PipelineRestartStepsTest extends BasePiperTest {
|
||||
|
||||
private JenkinsErrorRule jer = new JenkinsErrorRule(this)
|
||||
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
|
||||
private JenkinsStepRule jsr = new JenkinsStepRule(this)
|
||||
|
||||
@Rule
|
||||
public RuleChain chain = Rules.getCommonRules(this)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(jer)
|
||||
.around(jlr)
|
||||
.around(jsr)
|
||||
|
||||
@Test
|
||||
void testError() throws Exception {
|
||||
|
||||
def mailBuildResult = ''
|
||||
helper.registerAllowedMethod('mailSendNotification', [Map.class], { m ->
|
||||
mailBuildResult = m.buildResult
|
||||
return null
|
||||
})
|
||||
|
||||
helper.registerAllowedMethod('timeout', [Map.class, Closure.class], { m, closure ->
|
||||
assertThat(m.time, is(1))
|
||||
assertThat(m.unit, is('SECONDS'))
|
||||
return closure()
|
||||
})
|
||||
|
||||
def iterations = 0
|
||||
helper.registerAllowedMethod('input', [Map.class], { m ->
|
||||
iterations ++
|
||||
assertThat(m.message, is('Do you want to restart?'))
|
||||
assertThat(m.ok, is('Restart'))
|
||||
if (iterations > 1) {
|
||||
throw new FlowInterruptedException()
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
jsr.step.pipelineRestartSteps ([
|
||||
script: nullScript,
|
||||
jenkinsUtilsStub: jenkinsUtils,
|
||||
sendMail: true,
|
||||
timeoutInSeconds: 1
|
||||
|
||||
]) {
|
||||
throw new hudson.AbortException('I just created an error')
|
||||
}
|
||||
} catch(err) {
|
||||
assertThat(jlr.log, containsString('ERROR occured: hudson.AbortException: I just created an error'))
|
||||
assertThat(mailBuildResult, is('UNSTABLE'))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorNoMail() throws Exception {
|
||||
|
||||
def mailBuildResult = ''
|
||||
helper.registerAllowedMethod('mailSendNotification', [Map.class], { m ->
|
||||
mailBuildResult = m.buildResult
|
||||
return null
|
||||
})
|
||||
|
||||
helper.registerAllowedMethod('timeout', [Map.class, Closure.class], { m, closure ->
|
||||
assertThat(m.time, is(1))
|
||||
assertThat(m.unit, is('SECONDS'))
|
||||
return closure()
|
||||
})
|
||||
|
||||
def iterations = 0
|
||||
helper.registerAllowedMethod('input', [Map.class], { m ->
|
||||
iterations ++
|
||||
assertThat(m.message, is('Do you want to restart?'))
|
||||
assertThat(m.ok, is('Restart'))
|
||||
if (iterations > 1) {
|
||||
throw new FlowInterruptedException()
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
jsr.step.pipelineRestartSteps ([
|
||||
script: nullScript,
|
||||
jenkinsUtilsStub: jenkinsUtils,
|
||||
sendMail: false,
|
||||
timeoutInSeconds: 1
|
||||
|
||||
]) {
|
||||
throw new hudson.AbortException('I just created an error')
|
||||
}
|
||||
} catch(err) {
|
||||
assertThat(jlr.log, containsString('ERROR occured: hudson.AbortException: I just created an error'))
|
||||
assertThat(mailBuildResult, is(''))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess() throws Exception {
|
||||
|
||||
jsr.step.pipelineRestartSteps ([
|
||||
script: nullScript,
|
||||
jenkinsUtilsStub: jenkinsUtils,
|
||||
sendMail: false,
|
||||
timeoutInSeconds: 1
|
||||
|
||||
]) {
|
||||
nullScript.echo 'This is a test'
|
||||
}
|
||||
|
||||
assertThat(jlr.log, containsString('This is a test'))
|
||||
}
|
||||
}
|
@ -47,6 +47,7 @@ class SeleniumExecuteTestsTest extends BasePiperTest {
|
||||
}
|
||||
assertThat(bodyExecuted, is(true))
|
||||
assertThat(jedr.dockerParams.containerPortMappings, is(['selenium/standalone-chrome': [[containerPort: 4444, hostPort: 4444]]]))
|
||||
assertThat(jedr.dockerParams.dockerEnvVars, is(null))
|
||||
assertThat(jedr.dockerParams.dockerImage, is('node:8-stretch'))
|
||||
assertThat(jedr.dockerParams.dockerName, is('npm'))
|
||||
assertThat(jedr.dockerParams.dockerWorkspace, is('/home/node'))
|
||||
@ -56,6 +57,20 @@ class SeleniumExecuteTestsTest extends BasePiperTest {
|
||||
assertThat(jedr.dockerParams.sidecarVolumeBind, is(['/dev/shm': '/dev/shm']))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecuteSeleniumCustomBuildTool() {
|
||||
jsr.step.seleniumExecuteTests(
|
||||
script: nullScript,
|
||||
buildTool: 'maven',
|
||||
juStabUtils: utils
|
||||
) {
|
||||
bodyExecuted = true
|
||||
}
|
||||
assertThat(bodyExecuted, is(true))
|
||||
assertThat(jedr.dockerParams.dockerImage, is('maven:3.5-jdk-8'))
|
||||
assertThat(jedr.dockerParams.dockerName, is('maven'))
|
||||
assertThat(jedr.dockerParams.dockerWorkspace, is(''))
|
||||
}
|
||||
@Test
|
||||
void testExecuteSeleniumError() {
|
||||
thrown.expectMessage('Error occured')
|
||||
|
@ -48,7 +48,7 @@ class TestsPublishResultsTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testPublishNothingWithDefaultSettings() throws Exception {
|
||||
jsr.step.testsPublishResults()
|
||||
jsr.step.testsPublishResults(script: nullScript)
|
||||
|
||||
// ensure nothing is published
|
||||
assertTrue('WarningsPublisher options not empty', publisherStepOptions.junit == null)
|
||||
@ -59,7 +59,7 @@ class TestsPublishResultsTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testPublishNothingWithAllDisabled() throws Exception {
|
||||
jsr.step.testsPublishResults(junit: false, jacoco: false, cobertura: false, jmeter: false)
|
||||
jsr.step.testsPublishResults(script: nullScript, junit: false, jacoco: false, cobertura: false, jmeter: false)
|
||||
|
||||
// ensure nothing is published
|
||||
assertTrue('WarningsPublisher options not empty', publisherStepOptions.junit == null)
|
||||
@ -70,7 +70,7 @@ class TestsPublishResultsTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testPublishUnitTestsWithDefaultSettings() throws Exception {
|
||||
jsr.step.testsPublishResults(junit: true)
|
||||
jsr.step.testsPublishResults(script: nullScript, junit: true)
|
||||
|
||||
assertTrue('JUnit options are empty', publisherStepOptions.junit != null)
|
||||
// ensure default patterns are set
|
||||
@ -84,7 +84,7 @@ class TestsPublishResultsTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testPublishCoverageWithDefaultSettings() throws Exception {
|
||||
jsr.step.testsPublishResults(jacoco: true, cobertura: true)
|
||||
jsr.step.testsPublishResults(script: nullScript, jacoco: true, cobertura: true)
|
||||
|
||||
assertTrue('JaCoCo options are empty', publisherStepOptions.jacoco != null)
|
||||
assertTrue('Cobertura options are empty', publisherStepOptions.cobertura != null)
|
||||
@ -99,7 +99,7 @@ class TestsPublishResultsTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testPublishJMeterWithDefaultSettings() throws Exception {
|
||||
jsr.step.testsPublishResults(jmeter: true)
|
||||
jsr.step.testsPublishResults(script: nullScript, jmeter: true)
|
||||
|
||||
assertTrue('JMeter options are empty', publisherStepOptions.jmeter != null)
|
||||
assertEquals('JMeter default pattern not set',
|
||||
@ -113,7 +113,7 @@ class TestsPublishResultsTest extends BasePiperTest {
|
||||
|
||||
@Test
|
||||
void testPublishUnitTestsWithCustomSettings() throws Exception {
|
||||
jsr.step.testsPublishResults(junit: [pattern: 'fancy/file/path', archive: true, active: true])
|
||||
jsr.step.testsPublishResults(script: nullScript, junit: [pattern: 'fancy/file/path', archive: true, active: true])
|
||||
|
||||
assertTrue('JUnit options are empty', publisherStepOptions.junit != null)
|
||||
// ensure default patterns are set
|
||||
|
@ -4,6 +4,7 @@ import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
|
||||
import com.sap.piper.cm.BackendType
|
||||
import com.sap.piper.cm.ChangeManagement
|
||||
import com.sap.piper.cm.ChangeManagementException
|
||||
|
||||
@ -40,6 +41,7 @@ public class TransportRequestCreateTest extends BasePiperTest {
|
||||
|
||||
[
|
||||
credentialsId: 'CM',
|
||||
type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm',
|
||||
clientOpts: '-DmyProp=myVal',
|
||||
changeDocumentLabel: 'ChangeId\\s?:',
|
||||
@ -84,7 +86,8 @@ public class TransportRequestCreateTest extends BasePiperTest {
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
|
||||
String createTransportRequest(String changeId,
|
||||
String createTransportRequestSOLMAN(
|
||||
String changeId,
|
||||
String developmentSystemId,
|
||||
String cmEndpoint,
|
||||
String credentialId,
|
||||
@ -102,13 +105,14 @@ public class TransportRequestCreateTest extends BasePiperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createTransportRequestSuccessTest() {
|
||||
public void createTransportRequestSuccessSOLMANTest() {
|
||||
|
||||
def result = [:]
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
|
||||
String createTransportRequest(String changeId,
|
||||
String createTransportRequestSOLMAN(
|
||||
String changeId,
|
||||
String developmentSystemId,
|
||||
String cmEndpoint,
|
||||
String credentialId,
|
||||
@ -118,7 +122,6 @@ public class TransportRequestCreateTest extends BasePiperTest {
|
||||
result.developmentSystemId = developmentSystemId
|
||||
result.cmEndpoint = cmEndpoint
|
||||
result.credentialId = credentialId
|
||||
|
||||
result.clientOpts = clientOpts
|
||||
return '001'
|
||||
}
|
||||
@ -137,4 +140,58 @@ public class TransportRequestCreateTest extends BasePiperTest {
|
||||
assert jlr.log.contains("[INFO] Creating transport request for change document '001' and development system '001'.")
|
||||
assert jlr.log.contains("[INFO] Transport Request '001' has been successfully created.")
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createTransportRequestSuccessCTSTest() {
|
||||
|
||||
def result = [:]
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
|
||||
String createTransportRequestCTS(
|
||||
String transportType,
|
||||
String targetSystemId,
|
||||
String description,
|
||||
String endpoint,
|
||||
String credentialsId,
|
||||
String clientOpts
|
||||
) {
|
||||
result.transportType = transportType
|
||||
result.targetSystemId = targetSystemId
|
||||
result.description = description
|
||||
result.endpoint = endpoint
|
||||
result.credentialsId = credentialsId
|
||||
result.clientOpts = clientOpts
|
||||
return '001'
|
||||
}
|
||||
}
|
||||
|
||||
def transportId = jsr.step.call(script: nullScript,
|
||||
transportType: 'W',
|
||||
targetSystem: 'XYZ',
|
||||
description: 'desc',
|
||||
changeManagement: [type: 'CTS'],
|
||||
cmUtils: cm)
|
||||
|
||||
assert transportId == '001'
|
||||
assert result == [transportType: 'W',
|
||||
targetSystemId: 'XYZ',
|
||||
description: 'desc',
|
||||
endpoint: 'https://example.org/cm',
|
||||
credentialsId: 'CM',
|
||||
clientOpts: '-DmyProp=myVal'
|
||||
]
|
||||
|
||||
assert jlr.log.contains("[INFO] Creating transport request.")
|
||||
assert jlr.log.contains("[INFO] Transport Request '001' has been successfully created.")
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cmIntegrationSwichtedOffTest() {
|
||||
|
||||
jlr.expect('[INFO] Change management integration intentionally switched off.')
|
||||
|
||||
jsr.step.call(
|
||||
changeManagement: [type: 'NONE'])
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
|
||||
import com.sap.piper.cm.BackendType
|
||||
import com.sap.piper.cm.ChangeManagement
|
||||
import com.sap.piper.cm.ChangeManagementException
|
||||
|
||||
@ -39,6 +40,7 @@ public class TransportRequestReleaseTest extends BasePiperTest {
|
||||
[changeManagement:
|
||||
[
|
||||
credentialsId: 'CM',
|
||||
type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm'
|
||||
]
|
||||
]
|
||||
@ -89,7 +91,8 @@ public class TransportRequestReleaseTest extends BasePiperTest {
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
|
||||
void releaseTransportRequest(String changeId,
|
||||
void releaseTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String endpoint,
|
||||
String credentialsId,
|
||||
@ -111,12 +114,14 @@ public class TransportRequestReleaseTest extends BasePiperTest {
|
||||
Map receivedParams = [:]
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
void releaseTransportRequest(String changeId,
|
||||
void releaseTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String endpoint,
|
||||
String credentialsId,
|
||||
String clientOpts) {
|
||||
|
||||
receivedParams.type = type
|
||||
receivedParams.changeId = changeId
|
||||
receivedParams.transportRequestId = transportRequestId
|
||||
receivedParams.endpoint = endpoint
|
||||
@ -127,10 +132,20 @@ public class TransportRequestReleaseTest extends BasePiperTest {
|
||||
|
||||
jsr.step.call(script: nullScript, changeDocumentId: '001', transportRequestId: '002', cmUtils: cm)
|
||||
|
||||
assert receivedParams == [changeId: '001',
|
||||
assert receivedParams == [type: BackendType.SOLMAN,
|
||||
changeId: '001',
|
||||
transportRequestId: '002',
|
||||
endpoint: 'https://example.org/cm',
|
||||
credentialsId: 'CM',
|
||||
clientOpts: '']
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cmIntegrationSwichtedOffTest() {
|
||||
|
||||
jlr.expect('[INFO] Change management integration intentionally switched off.')
|
||||
|
||||
jsr.step.call(
|
||||
changeManagement: [type: 'NONE'])
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
|
||||
import com.sap.piper.cm.BackendType
|
||||
import com.sap.piper.cm.ChangeManagement
|
||||
import com.sap.piper.cm.ChangeManagementException
|
||||
|
||||
@ -44,6 +45,7 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
[changeManagement:
|
||||
[
|
||||
credentialsId: 'CM',
|
||||
type: 'SOLMAN',
|
||||
endpoint: 'https://example.org/cm'
|
||||
]
|
||||
]
|
||||
@ -51,7 +53,11 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeDocumentIdNotProvidedTest() {
|
||||
public void changeDocumentIdNotProvidedSOLMANTest() {
|
||||
|
||||
// we expect the failure only for SOLMAN (which is the default).
|
||||
// Use case for CTS without change document id is checked by the
|
||||
// straight forward test case for CTS
|
||||
|
||||
thrown.expect(IllegalArgumentException)
|
||||
thrown.expectMessage("Change document id not provided (parameter: 'changeDocumentId' or via commit history).")
|
||||
@ -91,7 +97,11 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applicationIdNotProvidedTest() {
|
||||
public void applicationIdNotProvidedSOLMANTest() {
|
||||
|
||||
// we expect the failure only for SOLMAN (which is the default).
|
||||
// Use case for CTS without applicationId is checked by the
|
||||
// straight forward test case for CTS
|
||||
|
||||
thrown.expect(IllegalArgumentException)
|
||||
thrown.expectMessage("ERROR - NO VALUE AVAILABLE FOR applicationId")
|
||||
@ -112,7 +122,8 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
public void uploadFileToTransportRequestFailureTest() {
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
void uploadFileToTransportRequest(String changeId,
|
||||
void uploadFileToTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String applicationId,
|
||||
String filePath,
|
||||
@ -135,13 +146,14 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uploadFileToTransportRequestSuccessTest() {
|
||||
public void uploadFileToTransportRequestCTSSuccessTest() {
|
||||
|
||||
jlr.expect("[INFO] Uploading file '/path' to transport request '002' of change document '001'.")
|
||||
jlr.expect("[INFO] File '/path' has been successfully uploaded to transport request '002' of change document '001'.")
|
||||
jlr.expect("[INFO] Uploading file '/path' to transport request '002'.")
|
||||
jlr.expect("[INFO] File '/path' has been successfully uploaded to transport request '002'.")
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
void uploadFileToTransportRequest(String changeId,
|
||||
void uploadFileToTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String applicationId,
|
||||
String filePath,
|
||||
@ -149,6 +161,53 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
String credentialsId,
|
||||
String cmclientOpts) {
|
||||
|
||||
cmUtilReceivedParams.type = type
|
||||
cmUtilReceivedParams.changeId = changeId
|
||||
cmUtilReceivedParams.transportRequestId = transportRequestId
|
||||
cmUtilReceivedParams.applicationId = applicationId
|
||||
cmUtilReceivedParams.filePath = filePath
|
||||
cmUtilReceivedParams.endpoint = endpoint
|
||||
cmUtilReceivedParams.credentialsId = credentialsId
|
||||
cmUtilReceivedParams.cmclientOpts = cmclientOpts
|
||||
}
|
||||
}
|
||||
|
||||
jsr.step.call(script: nullScript,
|
||||
changeManagement: [type: 'CTS'],
|
||||
transportRequestId: '002',
|
||||
filePath: '/path',
|
||||
cmUtils: cm)
|
||||
|
||||
assert cmUtilReceivedParams ==
|
||||
[
|
||||
type: BackendType.CTS,
|
||||
changeId: null,
|
||||
transportRequestId: '002',
|
||||
applicationId: null,
|
||||
filePath: '/path',
|
||||
endpoint: 'https://example.org/cm',
|
||||
credentialsId: 'CM',
|
||||
cmclientOpts: ''
|
||||
]
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uploadFileToTransportRequestSOLMANSuccessTest() {
|
||||
|
||||
jlr.expect("[INFO] Uploading file '/path' to transport request '002' of change document '001'.")
|
||||
jlr.expect("[INFO] File '/path' has been successfully uploaded to transport request '002' of change document '001'.")
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
void uploadFileToTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String applicationId,
|
||||
String filePath,
|
||||
String endpoint,
|
||||
String credentialsId,
|
||||
String cmclientOpts) {
|
||||
|
||||
cmUtilReceivedParams.type = type
|
||||
cmUtilReceivedParams.changeId = changeId
|
||||
cmUtilReceivedParams.transportRequestId = transportRequestId
|
||||
cmUtilReceivedParams.applicationId = applicationId
|
||||
@ -168,6 +227,7 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
|
||||
assert cmUtilReceivedParams ==
|
||||
[
|
||||
type: BackendType.SOLMAN,
|
||||
changeId: '001',
|
||||
transportRequestId: '002',
|
||||
applicationId: 'app',
|
||||
@ -186,7 +246,8 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
[applicationId: 'AppIdfromConfig']]])
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
void uploadFileToTransportRequest(String changeId,
|
||||
void uploadFileToTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String applicationId,
|
||||
String filePath,
|
||||
@ -215,7 +276,8 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
nullScript.commonPipelineEnvironment.setMtarFilePath('/path2')
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
void uploadFileToTransportRequest(String changeId,
|
||||
void uploadFileToTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String applicationId,
|
||||
String filePath,
|
||||
@ -244,7 +306,8 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
nullScript.commonPipelineEnvironment.setMtarFilePath('/path2')
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
void uploadFileToTransportRequest(String changeId,
|
||||
void uploadFileToTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String applicationId,
|
||||
String filePath,
|
||||
@ -272,7 +335,8 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
thrown.expectMessage('Upload failure.')
|
||||
|
||||
ChangeManagement cm = new ChangeManagement(nullScript) {
|
||||
void uploadFileToTransportRequest(String changeId,
|
||||
void uploadFileToTransportRequest(BackendType type,
|
||||
String changeId,
|
||||
String transportRequestId,
|
||||
String applicationId,
|
||||
String filePath,
|
||||
@ -291,4 +355,26 @@ public class TransportRequestUploadFileTest extends BasePiperTest {
|
||||
cmUtils: cm)
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidBackendTypeTest() {
|
||||
thrown.expect(AbortException)
|
||||
thrown.expectMessage('Invalid backend type: \'DUMMY\'. Valid values: [SOLMAN, CTS, NONE]. ' +
|
||||
'Configuration: \'changeManagement/type\'.')
|
||||
|
||||
jsr.step.call(script: nullScript,
|
||||
applicationId: 'app',
|
||||
filePath: '/path',
|
||||
changeManagement: [type: 'DUMMY'])
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cmIntegrationSwichtedOffTest() {
|
||||
|
||||
jlr.expect('[INFO] Change management integration intentionally switched off.')
|
||||
|
||||
jsr.step.call(
|
||||
changeManagement: [type: 'NONE'])
|
||||
}
|
||||
|
||||
}
|
||||
|
30
test/groovy/com/sap/piper/CfManifestUtilsTest.groovy
Normal file
30
test/groovy/com/sap/piper/CfManifestUtilsTest.groovy
Normal file
@ -0,0 +1,30 @@
|
||||
package com.sap.piper
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
class CfManifestUtilsTest {
|
||||
|
||||
@Test
|
||||
void testManifestTransform() {
|
||||
Map testFixture = [applications: [[buildpacks: ['sap_java_buildpack']]]]
|
||||
Map expected = [applications: [[buildpack: 'sap_java_buildpack']]]
|
||||
def actual = CfManifestUtils.transform(testFixture)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException)
|
||||
void testManifestTransformMultipleBuildpacks() {
|
||||
Map testFixture = [applications: [[buildpacks: ['sap_java_buildpack', 'another_buildpack']]]]
|
||||
CfManifestUtils.transform(testFixture)
|
||||
}
|
||||
|
||||
@Test
|
||||
void testManifestTransformShouldNotChange() {
|
||||
Map testFixture = [applications: [[buildpack: 'sap_java_buildpack']]]
|
||||
Map expected = [applications: [[buildpack: 'sap_java_buildpack']]]
|
||||
def actual = CfManifestUtils.transform(testFixture)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
}
|
@ -14,6 +14,18 @@ import org.junit.rules.ExpectedException
|
||||
|
||||
class ConfigurationHelperTest {
|
||||
|
||||
Script mockScript = new Script() {
|
||||
|
||||
def run() {
|
||||
// it never runs
|
||||
throw new UnsupportedOperationException()
|
||||
}
|
||||
|
||||
def STEP_NAME = 'mock'
|
||||
def echo(message) {
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none()
|
||||
|
||||
@ -37,6 +49,7 @@ class ConfigurationHelperTest {
|
||||
assertThat(ConfigurationHelper.getConfigPropertyNested([a:[b: 'c']], 'a/c'), is((nullValue())))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetPropertyNestedPathStartsWithTokenizer() {
|
||||
assertThat(ConfigurationHelper.getConfigPropertyNested([k:'v'], '/k'), is(('v')))
|
||||
}
|
||||
@ -53,14 +66,14 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testConfigurationLoaderWithDefaults() {
|
||||
Map config = new ConfigurationHelper([property1: '27']).use()
|
||||
Map config = ConfigurationHelper.newInstance(mockScript, [property1: '27']).use()
|
||||
// asserts
|
||||
Assert.assertThat(config, hasEntry('property1', '27'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testConfigurationLoaderWithCustomSettings() {
|
||||
Map config = new ConfigurationHelper([property1: '27'])
|
||||
Map config = ConfigurationHelper.newInstance(mockScript, [property1: '27'])
|
||||
.mixin([property1: '41'])
|
||||
.use()
|
||||
// asserts
|
||||
@ -70,7 +83,7 @@ class ConfigurationHelperTest {
|
||||
@Test
|
||||
void testConfigurationLoaderWithFilteredCustomSettings() {
|
||||
Set filter = ['property2']
|
||||
Map config = new ConfigurationHelper([property1: '27'])
|
||||
Map config = ConfigurationHelper.newInstance(mockScript, [property1: '27'])
|
||||
.mixin([property1: '41', property2: '28', property3: '29'], filter)
|
||||
.use()
|
||||
// asserts
|
||||
@ -81,7 +94,7 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testConfigurationLoaderWithBooleanValue() {
|
||||
Map config = new ConfigurationHelper([property1: '27'])
|
||||
Map config = ConfigurationHelper.newInstance(mockScript, [property1: '27'])
|
||||
.mixin([property1: false])
|
||||
.mixin([property2: false])
|
||||
.use()
|
||||
@ -92,7 +105,7 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testConfigurationLoaderWithMixinDependent() {
|
||||
Map config = new ConfigurationHelper([
|
||||
Map config = ConfigurationHelper.newInstance(mockScript, [
|
||||
type: 'maven',
|
||||
maven: [dockerImage: 'mavenImage', dockerWorkspace: 'mavenWorkspace'],
|
||||
npm: [dockerImage: 'npmImage', dockerWorkspace: 'npmWorkspace', executeDocker: true, executeDocker3: false],
|
||||
@ -122,8 +135,8 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testHandleCompatibility() {
|
||||
def configuration = new ConfigurationHelper()
|
||||
.mixin([old1: 'oldValue1', old2: 'oldValue2', test: 'testValue'], null, null, [newStructure: [new1: 'old1', new2: 'old2']])
|
||||
def configuration = ConfigurationHelper.newInstance(mockScript)
|
||||
.mixin([old1: 'oldValue1', old2: 'oldValue2', test: 'testValue'], null, [newStructure: [new1: 'old1', new2: 'old2']])
|
||||
.use()
|
||||
|
||||
Assert.assertThat(configuration.size(), is(4))
|
||||
@ -133,8 +146,8 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testHandleCompatibilityFlat() {
|
||||
def configuration = new ConfigurationHelper()
|
||||
.mixin([old1: 'oldValue1', old2: 'oldValue2', test: 'testValue'], null, null, [new1: 'old1', new2: 'old2'])
|
||||
def configuration = ConfigurationHelper.newInstance(mockScript)
|
||||
.mixin([old1: 'oldValue1', old2: 'oldValue2', test: 'testValue'], null, [new1: 'old1', new2: 'old2'])
|
||||
.use()
|
||||
|
||||
Assert.assertThat(configuration.size(), is(5))
|
||||
@ -144,8 +157,8 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testHandleCompatibilityDeep() {
|
||||
def configuration = new ConfigurationHelper()
|
||||
.mixin([old1: 'oldValue1', old2: 'oldValue2', test: 'testValue'], null, null, [deep:[deeper:[newStructure: [new1: 'old1', new2: 'old2']]]])
|
||||
def configuration = ConfigurationHelper.newInstance(mockScript)
|
||||
.mixin([old1: 'oldValue1', old2: 'oldValue2', test: 'testValue'], null, [deep:[deeper:[newStructure: [new1: 'old1', new2: 'old2']]]])
|
||||
.use()
|
||||
|
||||
Assert.assertThat(configuration.size(), is(4))
|
||||
@ -155,8 +168,8 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testHandleCompatibilityNewAvailable() {
|
||||
def configuration = new ConfigurationHelper([old1: 'oldValue1', newStructure: [new1: 'newValue1'], test: 'testValue'])
|
||||
.mixin([old1: 'oldValue1', newStructure: [new1: 'newValue1'], test: 'testValue'], null, null, [newStructure: [new1: 'old1', new2: 'old2']])
|
||||
def configuration = ConfigurationHelper.newInstance(mockScript, [old1: 'oldValue1', newStructure: [new1: 'newValue1'], test: 'testValue'])
|
||||
.mixin([old1: 'oldValue1', newStructure: [new1: 'newValue1'], test: 'testValue'], null, [newStructure: [new1: 'old1', new2: 'old2']])
|
||||
.use()
|
||||
|
||||
Assert.assertThat(configuration.size(), is(3))
|
||||
@ -165,8 +178,8 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testHandleCompatibilityOldNotSet() {
|
||||
def configuration = new ConfigurationHelper([old1: null, test: 'testValue'])
|
||||
.mixin([old1: null, test: 'testValue'], null, null, [newStructure: [new1: 'old1', new2: 'old2']])
|
||||
def configuration = ConfigurationHelper.newInstance(mockScript, [old1: null, test: 'testValue'])
|
||||
.mixin([old1: null, test: 'testValue'], null, [newStructure: [new1: 'old1', new2: 'old2']])
|
||||
.use()
|
||||
|
||||
Assert.assertThat(configuration.size(), is(2))
|
||||
@ -175,8 +188,8 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
void testHandleCompatibilityNoneAvailable() {
|
||||
def configuration = new ConfigurationHelper([old1: null, test: 'testValue'])
|
||||
.mixin([test: 'testValue'], null, null, [newStructure: [new1: 'old1', new2: 'old2']])
|
||||
def configuration = ConfigurationHelper.newInstance(mockScript, [old1: null, test: 'testValue'])
|
||||
.mixin([test: 'testValue'], null, [newStructure: [new1: 'old1', new2: 'old2']])
|
||||
.use()
|
||||
|
||||
Assert.assertThat(configuration.size(), is(2))
|
||||
@ -189,7 +202,7 @@ class ConfigurationHelperTest {
|
||||
thrown.expect(IllegalArgumentException)
|
||||
thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR myKey')
|
||||
|
||||
new ConfigurationHelper().withMandatoryProperty('myKey')
|
||||
ConfigurationHelper.newInstance(mockScript).withMandatoryProperty('myKey')
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -198,22 +211,22 @@ class ConfigurationHelperTest {
|
||||
thrown.expect(IllegalArgumentException)
|
||||
thrown.expectMessage('My error message')
|
||||
|
||||
new ConfigurationHelper().withMandatoryProperty('myKey', 'My error message')
|
||||
ConfigurationHelper.newInstance(mockScript).withMandatoryProperty('myKey', 'My error message')
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMandoryParameterDefaultCustomFailureMessageProvidedSucceeds() {
|
||||
new ConfigurationHelper([myKey: 'myValue']).withMandatoryProperty('myKey', 'My error message')
|
||||
ConfigurationHelper.newInstance(mockScript, [myKey: 'myValue']).withMandatoryProperty('myKey', 'My error message')
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMandoryParameterDefaultCustomFailureMessageNotProvidedSucceeds() {
|
||||
new ConfigurationHelper([myKey: 'myValue']).withMandatoryProperty('myKey')
|
||||
ConfigurationHelper.newInstance(mockScript, [myKey: 'myValue']).withMandatoryProperty('myKey')
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMandoryWithFalseCondition() {
|
||||
new ConfigurationHelper([verify: false])
|
||||
ConfigurationHelper.newInstance(mockScript, [verify: false])
|
||||
.withMandatoryProperty('missingKey', null, { c -> return c.get('verify') })
|
||||
}
|
||||
|
||||
@ -222,20 +235,20 @@ class ConfigurationHelperTest {
|
||||
thrown.expect(IllegalArgumentException)
|
||||
thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR missingKey')
|
||||
|
||||
new ConfigurationHelper([verify: true])
|
||||
ConfigurationHelper.newInstance(mockScript, [verify: true])
|
||||
.withMandatoryProperty('missingKey', null, { c -> return c.get('verify') })
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithMandoryWithTrueConditionExistingValue() {
|
||||
new ConfigurationHelper([existingKey: 'anyValue', verify: true])
|
||||
ConfigurationHelper.newInstance(mockScript, [existingKey: 'anyValue', verify: true])
|
||||
.withMandatoryProperty('existingKey', null, { c -> return c.get('verify') })
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTelemetryConfigurationAvailable() {
|
||||
Set filter = ['test']
|
||||
def configuration = new ConfigurationHelper([test: 'testValue'])
|
||||
def configuration = ConfigurationHelper.newInstance(mockScript, [test: 'testValue'])
|
||||
.mixin([collectTelemetryData: false], filter)
|
||||
.use()
|
||||
|
||||
@ -257,7 +270,7 @@ class ConfigurationHelperTest {
|
||||
assert bGString instanceof GString
|
||||
assert cGString instanceof GString
|
||||
|
||||
def config = new ConfigurationHelper([a: aGString,
|
||||
def config = ConfigurationHelper.newInstance(mockScript, [a: aGString,
|
||||
nextLevel: [b: bGString]])
|
||||
.mixin([c : cGString])
|
||||
.use()
|
||||
@ -272,7 +285,7 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
public void testWithMandatoryParameterCollectFailuresAllParamtersArePresentResultsInNoExceptionThrown() {
|
||||
new ConfigurationHelper([myKey1: 'a', myKey2: 'b'])
|
||||
ConfigurationHelper.newInstance(mockScript, [myKey1: 'a', myKey2: 'b'])
|
||||
.collectValidationFailures()
|
||||
.withMandatoryProperty('myKey1')
|
||||
.withMandatoryProperty('myKey2')
|
||||
@ -281,7 +294,7 @@ class ConfigurationHelperTest {
|
||||
|
||||
@Test
|
||||
public void testWithMandatoryParameterCollectFailuresMultipleMissingParametersDoNotResultInFailuresDuringWithMandatoryProperties() {
|
||||
new ConfigurationHelper([:]).collectValidationFailures()
|
||||
ConfigurationHelper.newInstance(mockScript, [:]).collectValidationFailures()
|
||||
.withMandatoryProperty('myKey1')
|
||||
.withMandatoryProperty('myKey2')
|
||||
}
|
||||
@ -290,7 +303,7 @@ class ConfigurationHelperTest {
|
||||
public void testWithMandatoryParameterCollectFailuresMultipleMissingParametersResultsInFailureDuringUse() {
|
||||
thrown.expect(IllegalArgumentException)
|
||||
thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR: myKey2, myKey3')
|
||||
new ConfigurationHelper([myKey1:'a']).collectValidationFailures()
|
||||
ConfigurationHelper.newInstance(mockScript, [myKey1:'a']).collectValidationFailures()
|
||||
.withMandatoryProperty('myKey1')
|
||||
.withMandatoryProperty('myKey2')
|
||||
.withMandatoryProperty('myKey3')
|
||||
@ -301,7 +314,7 @@ class ConfigurationHelperTest {
|
||||
public void testWithMandatoryParameterCollectFailuresOneMissingParametersResultsInFailureDuringUse() {
|
||||
thrown.expect(IllegalArgumentException)
|
||||
thrown.expectMessage('ERROR - NO VALUE AVAILABLE FOR myKey2')
|
||||
new ConfigurationHelper([myKey1:'a']).collectValidationFailures()
|
||||
ConfigurationHelper.newInstance(mockScript, [myKey1:'a']).collectValidationFailures()
|
||||
.withMandatoryProperty('myKey1')
|
||||
.withMandatoryProperty('myKey2')
|
||||
.use()
|
||||
|
45
test/groovy/com/sap/piper/JenkinsUtilsTest.groovy
Normal file
45
test/groovy/com/sap/piper/JenkinsUtilsTest.groovy
Normal file
@ -0,0 +1,45 @@
|
||||
package com.sap.piper
|
||||
|
||||
import org.jenkinsci.plugins.workflow.steps.MissingContextVariableException
|
||||
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.JenkinsLoggingRule
|
||||
import util.JenkinsShellCallRule
|
||||
import util.Rules
|
||||
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class JenkinsUtilsTest extends BasePiperTest {
|
||||
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
|
||||
private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
|
||||
|
||||
@Rule
|
||||
public RuleChain rules = Rules
|
||||
.getCommonRules(this)
|
||||
.around(jscr)
|
||||
.around(jlr)
|
||||
|
||||
@Test
|
||||
void testNodeAvailable() {
|
||||
def result = jenkinsUtils.nodeAvailable()
|
||||
assertThat(jscr.shell, contains("echo 'Node is available!'"))
|
||||
assertThat(result, is(true))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoNodeAvailable() {
|
||||
helper.registerAllowedMethod('sh', [String.class], {s ->
|
||||
throw new MissingContextVariableException(String.class)
|
||||
})
|
||||
|
||||
def result = jenkinsUtils.nodeAvailable()
|
||||
assertThat(jlr.log, containsString('No node context available.'))
|
||||
assertThat(result, is(false))
|
||||
}
|
||||
|
||||
}
|
@ -130,7 +130,8 @@ public class ChangeManagementTest extends BasePiperTest {
|
||||
@Test
|
||||
public void testGetCommandLineWithoutCMClientOpts() {
|
||||
String commandLine = new ChangeManagement(nullScript, null)
|
||||
.getCMCommandLine('https://example.org/cm',
|
||||
.getCMCommandLine(BackendType.SOLMAN,
|
||||
'https://example.org/cm',
|
||||
"me",
|
||||
"topSecret",
|
||||
"the-command",
|
||||
@ -143,7 +144,8 @@ public class ChangeManagementTest extends BasePiperTest {
|
||||
@Test
|
||||
public void testGetCommandLineWithCMClientOpts() {
|
||||
String commandLine = new ChangeManagement(nullScript, null)
|
||||
.getCMCommandLine('https://example.org/cm',
|
||||
.getCMCommandLine(BackendType.SOLMAN,
|
||||
'https://example.org/cm',
|
||||
"me",
|
||||
"topSecret",
|
||||
"the-command",
|
||||
@ -154,10 +156,28 @@ public void testGetCommandLineWithCMClientOpts() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTransportRequestSucceeds() {
|
||||
public void testCreateTransportRequestSOLMANSucceeds() {
|
||||
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, ".*cmclient.*create-transport -cID 001 -dID 002.*", '004')
|
||||
def transportRequestId = new ChangeManagement(nullScript).createTransportRequest('001', '002', '003', 'me')
|
||||
def transportRequestId = new ChangeManagement(nullScript).createTransportRequestSOLMAN( '001', '002', '003', 'me')
|
||||
|
||||
// the check for the transportRequestID is sufficient. This checks implicit the command line since that value is
|
||||
// returned only in case the shell call matches.
|
||||
assert transportRequestId == '004'
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateTransportRequestCTSSucceeds() {
|
||||
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'cmclient.* -t CTS .*create-transport -tt W -ts XYZ -d "desc 123"$', '004')
|
||||
def transportRequestId = new ChangeManagement(nullScript)
|
||||
.createTransportRequestCTS(
|
||||
'W', // transport type
|
||||
'XYZ', // target system
|
||||
'desc 123', // description
|
||||
'https://example.org/cm',
|
||||
'me')
|
||||
|
||||
// the check for the transportRequestID is sufficient. This checks implicit the command line since that value is
|
||||
// returned only in case the shell call matches.
|
||||
@ -174,7 +194,8 @@ public void testGetCommandLineWithCMClientOpts() {
|
||||
thrown.expectMessage('Cannot upload file \'/path\' for change document \'001\''+
|
||||
' with transport request \'002\'. Return code from cmclient: 1.')
|
||||
|
||||
new ChangeManagement(nullScript).uploadFileToTransportRequest('001',
|
||||
new ChangeManagement(nullScript).uploadFileToTransportRequest(BackendType.SOLMAN,
|
||||
'001',
|
||||
'002',
|
||||
'XXX',
|
||||
'/path',
|
||||
@ -183,12 +204,14 @@ public void testGetCommandLineWithCMClientOpts() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadFileToTransportSucceeds() {
|
||||
public void testUploadFileToTransportSucceedsSOLMAN() {
|
||||
|
||||
// the regex provided below is an implicit check that the command line is fine.
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX,, 'upload-file-to-transport.*-cID 001 -tID 002 XXX "/path"', 0)
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'upload-file-to-transport.*-cID 001 -tID 002 XXX "/path"', 0)
|
||||
|
||||
new ChangeManagement(nullScript).uploadFileToTransportRequest('001',
|
||||
new ChangeManagement(nullScript).uploadFileToTransportRequest(
|
||||
BackendType.SOLMAN,
|
||||
'001',
|
||||
'002',
|
||||
'XXX',
|
||||
'/path',
|
||||
@ -199,6 +222,25 @@ public void testGetCommandLineWithCMClientOpts() {
|
||||
// the command line.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadFileToTransportSucceedsCTS() {
|
||||
|
||||
// the regex provided below is an implicit check that the command line is fine.
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, '-t CTS upload-file-to-transport -tID 002 "/path"', 0)
|
||||
|
||||
new ChangeManagement(nullScript).uploadFileToTransportRequest(
|
||||
BackendType.CTS,
|
||||
null,
|
||||
'002',
|
||||
null,
|
||||
'/path',
|
||||
'https://example.org/cm',
|
||||
'me')
|
||||
|
||||
// no assert required here, since the regex registered above to the script rule is an implicit check for
|
||||
// the command line.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadFileToTransportFails() {
|
||||
|
||||
@ -208,7 +250,8 @@ public void testGetCommandLineWithCMClientOpts() {
|
||||
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX,, 'upload-file-to-transport', 1)
|
||||
|
||||
new ChangeManagement(nullScript).uploadFileToTransportRequest('001',
|
||||
new ChangeManagement(nullScript).uploadFileToTransportRequest(BackendType.SOLMAN,
|
||||
'001',
|
||||
'002',
|
||||
'XXX',
|
||||
'/path',
|
||||
@ -217,12 +260,32 @@ public void testGetCommandLineWithCMClientOpts() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseTransportRequestSucceeds() {
|
||||
public void testReleaseTransportRequestSucceedsSOLMAN() {
|
||||
|
||||
// the regex provided below is an implicit check that the command line is fine.
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'release-transport.*-cID 001.*-tID 002', 0)
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, '-t SOLMAN release-transport.*-cID 001.*-tID 002', 0)
|
||||
|
||||
new ChangeManagement(nullScript).releaseTransportRequest('001',
|
||||
new ChangeManagement(nullScript).releaseTransportRequest(
|
||||
BackendType.SOLMAN,
|
||||
'001',
|
||||
'002',
|
||||
'https://example.org',
|
||||
'me',
|
||||
'openSesame')
|
||||
|
||||
// no assert required here, since the regex registered above to the script rule is an implicit check for
|
||||
// the command line.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReleaseTransportRequestSucceedsCTS() {
|
||||
|
||||
// the regex provided below is an implicit check that the command line is fine.
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, '-t CTS export-transport.*-tID 002', 0)
|
||||
|
||||
new ChangeManagement(nullScript).releaseTransportRequest(
|
||||
BackendType.CTS,
|
||||
null,
|
||||
'002',
|
||||
'https://example.org',
|
||||
'me',
|
||||
@ -241,7 +304,9 @@ public void testGetCommandLineWithCMClientOpts() {
|
||||
// the regex provided below is an implicit check that the command line is fine.
|
||||
script.setReturnValue(JenkinsShellCallRule.Type.REGEX, 'release-transport.*-cID 001.*-tID 002', 1)
|
||||
|
||||
new ChangeManagement(nullScript).releaseTransportRequest('001',
|
||||
new ChangeManagement(nullScript).releaseTransportRequest(
|
||||
BackendType.SOLMAN,
|
||||
'001',
|
||||
'002',
|
||||
'https://example.org',
|
||||
'me',
|
||||
|
@ -4,6 +4,7 @@ package util
|
||||
|
||||
import com.lesfurets.jenkins.unit.BasePipelineTest
|
||||
import com.sap.piper.GitUtils
|
||||
import com.sap.piper.JenkinsUtils
|
||||
import com.sap.piper.Utils
|
||||
import org.junit.Before
|
||||
import org.junit.runner.RunWith
|
||||
@ -23,6 +24,9 @@ abstract class BasePiperTest extends BasePipelineTest {
|
||||
@Autowired
|
||||
Utils utils
|
||||
|
||||
@Autowired
|
||||
JenkinsUtils jenkinsUtils
|
||||
|
||||
@Override
|
||||
@Before
|
||||
void setUp() throws Exception {
|
||||
|
@ -3,6 +3,7 @@
|
||||
package util
|
||||
|
||||
import com.sap.piper.GitUtils
|
||||
import com.sap.piper.JenkinsUtils
|
||||
import com.sap.piper.Utils
|
||||
import org.codehaus.groovy.runtime.InvokerHelper
|
||||
import org.springframework.context.annotation.Bean
|
||||
@ -36,4 +37,11 @@ class BasePiperTestContext {
|
||||
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(mockUtils)
|
||||
return mockUtils
|
||||
}
|
||||
|
||||
@Bean
|
||||
JenkinsUtils mockJenkinsUtils() {
|
||||
def mockJenkinsUtils = new JenkinsUtils()
|
||||
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(mockJenkinsUtils)
|
||||
return mockJenkinsUtils
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ class JenkinsSetupRule implements TestRule {
|
||||
testInstance.binding.setVariable('env', [
|
||||
JOB_NAME : 'p',
|
||||
BUILD_NUMBER: '1',
|
||||
BUILD_URL : ''
|
||||
BUILD_URL : 'http://build.url',
|
||||
])
|
||||
|
||||
base.evaluate()
|
||||
|
@ -72,6 +72,7 @@ class JenkinsShellCallRule implements TestRule {
|
||||
}
|
||||
}
|
||||
if(result instanceof Closure) result = result()
|
||||
if (!result && m.returnStatus) result = 0
|
||||
return result
|
||||
}
|
||||
})
|
||||
|
@ -8,6 +8,9 @@ import groovy.text.SimpleTemplateEngine
|
||||
|
||||
@Field String STEP_NAME = 'artifactSetVersion'
|
||||
@Field Map CONFIG_KEY_COMPATIBILITY = [gitSshKeyCredentialsId: 'gitCredentialsId']
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'artifactType',
|
||||
'buildTool',
|
||||
@ -23,9 +26,10 @@ import groovy.text.SimpleTemplateEngine
|
||||
'timestampTemplate',
|
||||
'versioningTemplate'
|
||||
]
|
||||
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus('gitCommitId')
|
||||
|
||||
def call(Map parameters = [:], Closure body = null) {
|
||||
void call(Map parameters = [:], Closure body = null) {
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
@ -41,13 +45,13 @@ def call(Map parameters = [:], Closure body = null) {
|
||||
script = this
|
||||
|
||||
// load default & individual configuration
|
||||
ConfigurationHelper configHelper = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS, this, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS, this, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS, this, CONFIG_KEY_COMPATIBILITY)
|
||||
ConfigurationHelper configHelper = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixin(gitCommitId: gitUtils.getGitCommitIdOrNull())
|
||||
.mixin(parameters, PARAMETER_KEYS, this, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixin(parameters, PARAMETER_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||
.withMandatoryProperty('buildTool')
|
||||
.dependingOn('buildTool').mixin('filePath')
|
||||
.dependingOn('buildTool').mixin('versioningTemplate')
|
||||
@ -77,7 +81,7 @@ def call(Map parameters = [:], Closure body = null) {
|
||||
}
|
||||
|
||||
if (config.commitVersion) {
|
||||
config = new ConfigurationHelper(config)
|
||||
config = ConfigurationHelper.newInstance(this, config)
|
||||
.addIfEmpty('gitSshUrl', isAppContainer(config)
|
||||
?script.commonPipelineEnvironment.getAppContainerProperty('gitSshUrl')
|
||||
:script.commonPipelineEnvironment.getGitSshUrl())
|
||||
|
@ -5,6 +5,9 @@ import groovy.text.SimpleTemplateEngine
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'batsExecuteTests'
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'dockerImage',
|
||||
'dockerWorkspace',
|
||||
@ -19,17 +22,18 @@ import groovy.transform.Field
|
||||
'testPath',
|
||||
'testRepository'
|
||||
]
|
||||
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
def utils = parameters.juStabUtils ?: new Utils()
|
||||
def script = parameters.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
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)
|
||||
|
@ -5,11 +5,16 @@ import hudson.AbortException
|
||||
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.ConfigurationMerger
|
||||
import com.sap.piper.cm.BackendType
|
||||
import com.sap.piper.cm.ChangeManagement
|
||||
import com.sap.piper.cm.ChangeManagementException
|
||||
|
||||
import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrationDisabled
|
||||
|
||||
@Field def STEP_NAME = 'checkChangeInDevelopment'
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'changeManagement',
|
||||
/**
|
||||
@ -21,8 +26,6 @@ import com.sap.piper.cm.ChangeManagementException
|
||||
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus('changeDocumentId')
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
/**
|
||||
* Checks if a Change Document in SAP Solution Manager is in status 'in development'. The change document id is retrieved from the git commit history. The change document id
|
||||
* can also be provided via parameter `changeDocumentId`. Any value provided as parameter has a higher precedence than a value from the commit history.
|
||||
@ -31,7 +34,7 @@ import com.sap.piper.cm.ChangeManagementException
|
||||
* range and the pattern can be configured. For details see 'parameters' table.
|
||||
*
|
||||
*/
|
||||
def call(parameters = [:]) {
|
||||
void call(parameters = [:]) {
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
@ -41,12 +44,21 @@ def call(parameters = [:]) {
|
||||
|
||||
ChangeManagement cm = parameters?.cmUtils ?: new ChangeManagement(script, gitUtils)
|
||||
|
||||
ConfigurationHelper configHelper = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
ConfigurationHelper configHelper = 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)
|
||||
|
||||
Map configuration = configHelper.use()
|
||||
|
||||
BackendType backendType = getBackendTypeAndLogInfoIfCMIntegrationDisabled(this, configuration)
|
||||
if(backendType == BackendType.NONE) return
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], configuration)
|
||||
|
||||
configHelper
|
||||
// for the following parameters we expect defaults
|
||||
/**
|
||||
* A pattern used for identifying lines holding the change document id.
|
||||
@ -82,10 +94,6 @@ def call(parameters = [:]) {
|
||||
.withMandatoryProperty('changeManagement/endpoint')
|
||||
|
||||
|
||||
Map configuration = configHelper.use()
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], configuration)
|
||||
|
||||
def changeId = configuration.changeDocumentId
|
||||
|
||||
if(changeId?.trim()) {
|
||||
@ -142,14 +150,12 @@ def call(parameters = [:]) {
|
||||
|
||||
if(isInDevelopment) {
|
||||
echo "[INFO] Change '${changeId}' is in status 'in development'."
|
||||
return true
|
||||
} else {
|
||||
if(configuration.failIfStatusIsNotInDevelopment.toBoolean()) {
|
||||
throw new AbortException("Change '${changeId}' is not in status 'in development'.")
|
||||
|
||||
} else {
|
||||
echo "[WARNING] Change '${changeId}' is not in status 'in development'. Failing the pipeline has been explicitly disabled."
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import groovy.transform.Field
|
||||
*
|
||||
* @param others document all parameters
|
||||
*/
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters.script
|
||||
if (script == null)
|
||||
@ -30,8 +30,8 @@ def call(Map parameters = [:]) {
|
||||
prepare(parameters)
|
||||
|
||||
// load default & individual configuration
|
||||
Map configuration = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
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)
|
||||
|
@ -1,9 +1,13 @@
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.CfManifestUtils
|
||||
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'cloudFoundryDeploy'
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'cloudFoundry',
|
||||
'deployUser',
|
||||
@ -18,9 +22,10 @@ import groovy.transform.Field
|
||||
'smokeTestStatusCode',
|
||||
'stashContent']
|
||||
@Field Map CONFIG_KEY_COMPATIBILITY = [cloudFoundry: [apiEndpoint: 'cfApiEndpoint', appName:'cfAppName', credentialsId: 'cfCredentialsId', manifest: 'cfManifest', org: 'cfOrg', space: 'cfSpace']]
|
||||
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
@ -33,12 +38,12 @@ def call(Map parameters = [:]) {
|
||||
if (script == null)
|
||||
script = [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS, this, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS, this, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS, this, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixin(parameters, PARAMETER_KEYS, this, CONFIG_KEY_COMPATIBILITY)
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||
.mixin(parameters, PARAMETER_KEYS, CONFIG_KEY_COMPATIBILITY)
|
||||
.dependingOn('deployTool').mixin('dockerImage')
|
||||
.dependingOn('deployTool').mixin('dockerWorkspace')
|
||||
.withMandatoryProperty('cloudFoundry/org')
|
||||
@ -54,7 +59,7 @@ def call(Map parameters = [:]) {
|
||||
|
||||
if (config.deployTool == 'mtaDeployPlugin') {
|
||||
// set default mtar path
|
||||
config = new ConfigurationHelper(config)
|
||||
config = ConfigurationHelper.newInstance(this, config)
|
||||
.addIfEmpty('mtaPath', config.mtaPath?:findMtar())
|
||||
.use()
|
||||
|
||||
@ -112,6 +117,7 @@ def deployCfNative (config) {
|
||||
def deployCommand = 'push'
|
||||
if (config.deployType == 'blue-green') {
|
||||
deployCommand = 'blue-green-deploy'
|
||||
handleLegacyCfManifest(config)
|
||||
} else {
|
||||
config.smokeTest = ''
|
||||
}
|
||||
@ -166,3 +172,18 @@ def deployMta (config) {
|
||||
sh "cf logout"
|
||||
}
|
||||
}
|
||||
|
||||
def handleLegacyCfManifest(config) {
|
||||
def manifest = readYaml file: config.cloudFoundry.manifest
|
||||
String originalManifest = manifest.toString()
|
||||
manifest = CfManifestUtils.transform(manifest)
|
||||
String transformedManifest = manifest.toString()
|
||||
if (originalManifest != transformedManifest) {
|
||||
echo """The file ${config.cloudFoundry.manifest} is not compatible with the Cloud Foundry blue-green deployment plugin. Re-writing inline.
|
||||
See this issue if you are interested in the background: https://github.com/cloudfoundry/cli/issues/1445.\n
|
||||
Original manifest file content: $originalManifest\n
|
||||
Transformed manifest file content: $transformedManifest"""
|
||||
sh "rm ${config.cloudFoundry.manifest}"
|
||||
writeYaml file: config.cloudFoundry.manifest, data: manifest
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,18 @@ class commonPipelineEnvironment implements Serializable {
|
||||
//stores version of the artifact which is build during pipeline run
|
||||
def artifactVersion
|
||||
|
||||
//Stores the current buildResult
|
||||
String buildResult = 'SUCCESS'
|
||||
|
||||
//stores the gitCommitId as well as additional git information for the build during pipeline run
|
||||
String gitCommitId
|
||||
String gitSshUrl
|
||||
String gitHttpsUrl
|
||||
String gitBranch
|
||||
|
||||
//GiutHub specific information
|
||||
String githubOrg
|
||||
String githubRepo
|
||||
|
||||
//stores properties for a pipeline which build an artifact and then bundles it into a container
|
||||
private Map appContainerProperties = [:]
|
||||
@ -30,6 +39,11 @@ class commonPipelineEnvironment implements Serializable {
|
||||
|
||||
gitCommitId = null
|
||||
gitSshUrl = null
|
||||
gitHttpsUrl = null
|
||||
gitBranch = null
|
||||
|
||||
githubOrg = null
|
||||
githubRepo = null
|
||||
|
||||
influxCustomData = [:]
|
||||
influxCustomDataMap = [pipeline_data: [:], step_data: [:]]
|
||||
|
@ -17,9 +17,9 @@ import groovy.transform.Field
|
||||
'dockerOptions',
|
||||
'dockerWorkspace',
|
||||
'dockerVolumeBind',
|
||||
'sidecarName',
|
||||
'sidecarEnvVars',
|
||||
'sidecarImage',
|
||||
'sidecarName',
|
||||
'sidecarOptions',
|
||||
'sidecarWorkspace',
|
||||
'sidecarVolumeBind'
|
||||
@ -31,8 +31,8 @@ void call(Map parameters = [:], body) {
|
||||
final script = parameters.script
|
||||
if (script == null)
|
||||
script = [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
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)
|
||||
@ -111,16 +111,28 @@ void call(Map parameters = [:], body) {
|
||||
body()
|
||||
}
|
||||
} else {
|
||||
def networkName = "sidecar-${UUID.randomUUID()}"
|
||||
sh "docker network create ${networkName}"
|
||||
try{
|
||||
def sidecarImage = docker.image(config.sidecarImage)
|
||||
sidecarImage.pull()
|
||||
config.sidecarOptions = config.sidecarOptions?:[]
|
||||
if(config.sidecarName)
|
||||
config.sidecarOptions.add("--network-alias ${config.sidecarName}")
|
||||
config.sidecarOptions.add("--network ${networkName}")
|
||||
sidecarImage.withRun(getDockerOptions(config.sidecarEnvVars, config.sidecarVolumeBind, config.sidecarOptions)) { c ->
|
||||
config.dockerOptions = config.dockerOptions?:[]
|
||||
config.dockerOptions.add("--link ${c.id}:${config.sidecarName}")
|
||||
if(config.dockerName)
|
||||
config.dockerOptions.add("--network-alias ${config.dockerName}")
|
||||
config.dockerOptions.add("--network ${networkName}")
|
||||
image.inside(getDockerOptions(config.dockerEnvVars, config.dockerVolumeBind, config.dockerOptions)) {
|
||||
echo "[INFO][${STEP_NAME}] Running with sidecar container."
|
||||
body()
|
||||
}
|
||||
}
|
||||
}finally{
|
||||
sh "docker network remove ${networkName}"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "[INFO][${STEP_NAME}] Running on local environment."
|
||||
|
@ -29,8 +29,8 @@ void call(Map parameters = [:], body) {
|
||||
if (script == null)
|
||||
script = [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
ConfigurationHelper configHelper = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
ConfigurationHelper configHelper = 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)
|
||||
|
94
vars/gaugeExecuteTests.groovy
Normal file
94
vars/gaugeExecuteTests.groovy
Normal file
@ -0,0 +1,94 @@
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.GitUtils
|
||||
import groovy.text.SimpleTemplateEngine
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'gaugeExecuteTests'
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'buildTool',
|
||||
'dockerEnvVars',
|
||||
'dockerImage',
|
||||
'dockerName',
|
||||
'dockerWorkspace',
|
||||
'failOnError',
|
||||
'gitBranch',
|
||||
'gitSshKeyCredentialsId',
|
||||
'installCommand',
|
||||
'languageRunner',
|
||||
'runCommand',
|
||||
'stashContent',
|
||||
'testOptions',
|
||||
'testRepository',
|
||||
'testServerUrl'
|
||||
]
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
def utils = parameters.juStabUtils ?: new Utils()
|
||||
|
||||
script.commonPipelineEnvironment.setInfluxStepData('gauge', false)
|
||||
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.dependingOn('buildTool').mixin('dockerImage')
|
||||
.dependingOn('buildTool').mixin('dockerName')
|
||||
.dependingOn('buildTool').mixin('dockerWorkspace')
|
||||
.dependingOn('buildTool').mixin('languageRunner')
|
||||
.dependingOn('buildTool').mixin('runCommand')
|
||||
.dependingOn('buildTool').mixin('testOptions')
|
||||
.use()
|
||||
|
||||
utils.pushToSWA([step: STEP_NAME, stepParam1: config.buildTool, stepParam2: config.dockerName], config)
|
||||
|
||||
if(!config.dockerEnvVars.TARGET_SERVER_URL && config.testServerUrl)
|
||||
config.dockerEnvVars.TARGET_SERVER_URL = config.testServerUrl
|
||||
|
||||
if (config.testRepository) {
|
||||
// handle separate test repository
|
||||
config.stashContent = [GitUtils.handleTestRepository(this, config)]
|
||||
} else {
|
||||
config.stashContent = utils.unstashAll(config.stashContent)
|
||||
}
|
||||
|
||||
seleniumExecuteTests (
|
||||
script: script,
|
||||
buildTool: config.buildTool,
|
||||
dockerEnvVars: config.dockerEnvVars,
|
||||
dockerImage: config.dockerImage,
|
||||
dockerName: config.dockerName,
|
||||
dockerWorkspace: config.dockerWorkspace,
|
||||
stashContent: config.stashContent
|
||||
) {
|
||||
String gaugeScript = ''
|
||||
if (config.installCommand) {
|
||||
gaugeScript = '''export HOME=${HOME:-$(pwd)}
|
||||
if [ "$HOME" = "/" ]; then export HOME=$(pwd); fi
|
||||
export PATH=$HOME/bin/gauge:$PATH
|
||||
mkdir -p $HOME/bin/gauge
|
||||
''' + config.installCommand + '''
|
||||
gauge telemetry off
|
||||
gauge install ''' + config.languageRunner + '''
|
||||
gauge install html-report
|
||||
gauge install xml-report
|
||||
'''
|
||||
}
|
||||
gaugeScript += config.runCommand
|
||||
|
||||
try {
|
||||
sh "${gaugeScript} ${config.testOptions}"
|
||||
script.commonPipelineEnvironment.setInfluxStepData('gauge', true)
|
||||
} catch (err) {
|
||||
echo "[${STEP_NAME}] One or more tests failed"
|
||||
script.currentBuild.result = 'UNSTABLE'
|
||||
if (config.failOnError) throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
134
vars/githubPublishRelease.groovy
Normal file
134
vars/githubPublishRelease.groovy
Normal file
@ -0,0 +1,134 @@
|
||||
import com.sap.piper.Utils
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'githubPublishRelease'
|
||||
@Field Set GENERAL_CONFIG_KEYS = ['githubApiUrl', 'githubTokenCredentialsId', 'githubServerUrl']
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'addClosedIssues',
|
||||
'addDeltaToLastRelease',
|
||||
'customFilterExtension',
|
||||
'excludeLabels',
|
||||
'githubApiUrl',
|
||||
'githubTokenCredentialsId',
|
||||
'githubOrg',
|
||||
'githubRepo',
|
||||
'githubServerUrl',
|
||||
'releaseBodyHeader',
|
||||
'version'
|
||||
]
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
// 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)
|
||||
.addIfEmpty('githubOrg', script.commonPipelineEnvironment.getGithubOrg())
|
||||
.addIfEmpty('githubRepo', script.commonPipelineEnvironment.getGithubRepo())
|
||||
.addIfEmpty('version', script.commonPipelineEnvironment.getArtifactVersion())
|
||||
.withMandatoryProperty('githubOrg')
|
||||
.withMandatoryProperty('githubRepo')
|
||||
.withMandatoryProperty('githubTokenCredentialsId')
|
||||
.withMandatoryProperty('version')
|
||||
.use()
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], config)
|
||||
|
||||
withCredentials([string(credentialsId: config.githubTokenCredentialsId, variable: 'TOKEN')]) {
|
||||
def releaseBody = config.releaseBodyHeader?"${config.releaseBodyHeader}<br />":''
|
||||
def content = getLastRelease(config, TOKEN)
|
||||
if (config.addClosedIssues)
|
||||
releaseBody += addClosedIssue(config, TOKEN, content.published_at)
|
||||
if (config.addDeltaToLastRelease)
|
||||
releaseBody += addDeltaToLastRelease(config, content.tag_name)
|
||||
postNewRelease(config, TOKEN, releaseBody)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map getLastRelease(config, TOKEN){
|
||||
def result = [:]
|
||||
|
||||
def response = httpRequest "${config.githubApiUrl}/repos/${config.githubOrg}/${config.githubRepo}/releases/latest?access_token=${TOKEN}"
|
||||
if (response.status == 200) {
|
||||
result = readJSON text: response.content
|
||||
} else {
|
||||
echo "[${STEP_NAME}] This is the first release - no previous releases available"
|
||||
config.addDeltaToLastRelease = false
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
String addClosedIssue(config, TOKEN, publishedAt){
|
||||
if (config.customFilterExtension) {
|
||||
config.customFilterExtension = "&${config.customFilterExtension}"
|
||||
}
|
||||
|
||||
def publishedAtFilter = publishedAt ? "&since=${publishedAt}": ''
|
||||
|
||||
def response = httpRequest "${config.githubApiUrl}/repos/${config.githubOrg}/${config.githubRepo}/issues?access_token=${TOKEN}&per_page=100&state=closed&direction=asc${publishedAtFilter}${config.customFilterExtension}"
|
||||
def result = ''
|
||||
|
||||
content = readJSON text: response.content
|
||||
|
||||
//list closed pull-requests
|
||||
result += '<br />**List of closed pull-requests since last release**<br />'
|
||||
for (def item : content) {
|
||||
if (item.pull_request && !isExcluded(item, config.excludeLabels)) {
|
||||
result += "[#${item.number}](${item.html_url}): ${item.title}<br />"
|
||||
}
|
||||
}
|
||||
//list closed issues
|
||||
result += '<br />**List of closed issues since last release**<br />'
|
||||
for (def item : content) {
|
||||
if (!item.pull_request && !isExcluded(item, config.excludeLabels)) {
|
||||
result += "[#${item.number}](${item.html_url}): ${item.title}<br />"
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
String addDeltaToLastRelease(config, latestTag){
|
||||
def result = ''
|
||||
//add delta link to previous release
|
||||
result += '<br />**Changes**<br />'
|
||||
result += "[${latestTag}...${config.version}](${config.githubServerUrl}/${config.githubOrg}/${config.githubRepo}/compare/${latestTag}...${config.version}) <br />"
|
||||
return result
|
||||
}
|
||||
|
||||
void postNewRelease(config, TOKEN, releaseBody){
|
||||
releaseBody = releaseBody.replace('"', '\\"')
|
||||
//write release information
|
||||
def data = "{\"tag_name\": \"${config.version}\",\"target_commitish\": \"master\",\"name\": \"${config.version}\",\"body\": \"${releaseBody}\",\"draft\": false,\"prerelease\": false}"
|
||||
try {
|
||||
httpRequest httpMode: 'POST', requestBody: data, url: "${config.githubApiUrl}/repos/${config.githubOrg}/${config.githubRepo}/releases?access_token=${TOKEN}"
|
||||
} catch (e) {
|
||||
echo """[${STEP_NAME}] Error occured when writing release information
|
||||
---------------------------------------------------------------------
|
||||
Request body was:
|
||||
---------------------------------------------------------------------
|
||||
${data}
|
||||
---------------------------------------------------------------------"""
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
boolean isExcluded(item, excludeLabels){
|
||||
def result = false
|
||||
excludeLabels.each {labelName ->
|
||||
item.labels.each { label ->
|
||||
if (label.name == labelName) {
|
||||
result = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
@ -1,50 +1,34 @@
|
||||
import groovy.text.SimpleTemplateEngine
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field STEP_NAME = 'handlePipelineStepErrors'
|
||||
|
||||
|
||||
def call(Map parameters = [:], body) {
|
||||
|
||||
void call(Map parameters = [:], body) {
|
||||
def stepParameters = parameters.stepParameters //mandatory
|
||||
def stepName = parameters.stepName //mandatory
|
||||
def echoDetails = parameters.get('echoDetails', true)
|
||||
|
||||
def verbose = parameters.get('echoDetails', true)
|
||||
def message = ''
|
||||
try {
|
||||
|
||||
if (stepParameters == null && stepName == null)
|
||||
error "step handlePipelineStepErrors requires following mandatory parameters: stepParameters, stepName"
|
||||
|
||||
if (echoDetails)
|
||||
echo "--- BEGIN LIBRARY STEP: ${stepName}.groovy ---"
|
||||
if (verbose)
|
||||
echo "--- BEGIN LIBRARY STEP: ${stepName} ---"
|
||||
|
||||
body()
|
||||
|
||||
} catch (Throwable err) {
|
||||
if (echoDetails)
|
||||
echo """----------------------------------------------------------
|
||||
--- ERROR OCCURED IN LIBRARY STEP: ${stepName}
|
||||
----------------------------------------------------------
|
||||
|
||||
FOLLOWING PARAMETERS WERE AVAILABLE TO THIS STEP:
|
||||
***
|
||||
${stepParameters}
|
||||
***
|
||||
|
||||
ERROR WAS:
|
||||
***
|
||||
${err}
|
||||
***
|
||||
|
||||
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/
|
||||
* Library repository: https://github.com/SAP/jenkins-library
|
||||
|
||||
----------------------------------------------------------"""
|
||||
if (verbose)
|
||||
message += SimpleTemplateEngine.newInstance()
|
||||
.createTemplate(libraryResource('com.sap.piper/templates/error.log'))
|
||||
.make([
|
||||
stepName: stepName,
|
||||
stepParameters: stepParameters?.toString(),
|
||||
error: err
|
||||
]).toString()
|
||||
throw err
|
||||
} finally {
|
||||
if (echoDetails)
|
||||
echo "--- END LIBRARY STEP: ${stepName}.groovy ---"
|
||||
if (verbose)
|
||||
message += "--- END LIBRARY STEP: ${stepName} ---"
|
||||
echo message
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,33 @@
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
|
||||
import com.sap.piper.Utils
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'healthExecuteCheck'
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'healthEndpoint',
|
||||
'testServerUrl'
|
||||
]
|
||||
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
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)
|
||||
.withMandatoryProperty('testServerUrl')
|
||||
.use()
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], config)
|
||||
|
||||
def checkUrl = config.testServerUrl
|
||||
if(config.healthEndpoint){
|
||||
if(!checkUrl.endsWith('/'))
|
||||
|
@ -17,15 +17,15 @@ import groovy.transform.Field
|
||||
'artifactVersion'
|
||||
])
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters, allowBuildFailure: true) {
|
||||
def script = parameters.script
|
||||
if (script == null)
|
||||
script = [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
// load default & individual configuration
|
||||
Map configuration = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
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)
|
||||
|
194
vars/mailSendNotification.groovy
Normal file
194
vars/mailSendNotification.groovy
Normal file
@ -0,0 +1,194 @@
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.Utils
|
||||
import groovy.text.SimpleTemplateEngine
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'mailSendNotification'
|
||||
@Field Set GENERAL_CONFIG_KEYS = ['gitSshKeyCredentialsId']
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'projectName',
|
||||
'buildResult',
|
||||
'gitUrl',
|
||||
'gitCommitId',
|
||||
'gitSshKeyCredentialsId',
|
||||
'wrapInNode',
|
||||
'notifyCulprits',
|
||||
'notificationAttachment',
|
||||
'notificationRecipients',
|
||||
'numLogLinesInBody'
|
||||
]
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters, allowBuildFailure: true) {
|
||||
def script = parameters.script?:[commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
// 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(
|
||||
projectName: script.currentBuild.fullProjectName,
|
||||
displayName: script.currentBuild.displayName,
|
||||
buildResult: script.currentBuild.result,
|
||||
gitUrl: script.commonPipelineEnvironment.getGitSshUrl(),
|
||||
gitCommitId: script.commonPipelineEnvironment.getGitCommitId()
|
||||
)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.use()
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], config)
|
||||
|
||||
//this takes care that terminated builds due to milestone-locking do not cause an error
|
||||
if (script.commonPipelineEnvironment.getBuildResult() == 'ABORTED') return
|
||||
|
||||
def subject = "${config.buildResult}: Build ${config.projectName} ${config.displayName}"
|
||||
def log = ''
|
||||
def mailTemplate
|
||||
if (config.buildResult == 'UNSTABLE' || config.buildResult == 'FAILURE'){
|
||||
mailTemplate = 'com.sap.piper/templates/mailFailure.html'
|
||||
log = script.currentBuild.rawBuild.getLog(config.numLogLinesInBody).join('\n')
|
||||
}else if(hasRecovered(config.buildResult, script.currentBuild)){
|
||||
mailTemplate = 'com.sap.piper/templates/mailRecover.html'
|
||||
subject += ' is back to normal'
|
||||
}
|
||||
if(mailTemplate){
|
||||
def mailContent = SimpleTemplateEngine.newInstance().createTemplate(libraryResource(mailTemplate)).make([env: env, log: log]).toString()
|
||||
def recipientList = ''
|
||||
if(config.notifyCulprits){
|
||||
if (!config.gitUrl) {
|
||||
echo "[${STEP_NAME}] no gitUrl available, -> exiting without sending mails"
|
||||
return
|
||||
}
|
||||
recipientList += getCulpritCommitters(config, script.currentBuild)
|
||||
}
|
||||
if(config.notificationRecipients)
|
||||
recipientList += " ${config.notificationRecipients}"
|
||||
emailext(
|
||||
mimeType: 'text/html',
|
||||
subject: subject.trim(),
|
||||
body: mailContent,
|
||||
to: recipientList.trim(),
|
||||
recipientProviders: [requestor()],
|
||||
attachLog: config.notificationAttachment
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getNumberOfCommits(buildList){
|
||||
def numCommits = 0
|
||||
if(buildList != null)
|
||||
for(actBuild in buildList) {
|
||||
def changeLogSets = actBuild.getChangeSets()
|
||||
if(changeLogSets != null)
|
||||
for(changeLogSet in changeLogSets)
|
||||
for(change in changeLogSet)
|
||||
numCommits++
|
||||
}
|
||||
return numCommits
|
||||
}
|
||||
|
||||
def getCulpritCommitters(config, currentBuild) {
|
||||
def recipients
|
||||
def buildList = []
|
||||
def build = currentBuild
|
||||
|
||||
if (build != null) {
|
||||
// At least add the current build
|
||||
buildList.add(build)
|
||||
|
||||
// Now collect FAILED or ABORTED ones
|
||||
build = build.getPreviousBuild()
|
||||
while (build != null) {
|
||||
if (build.getResult() != 'SUCCESS') {
|
||||
buildList.add(build)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
build = build.getPreviousBuild()
|
||||
}
|
||||
}
|
||||
def numberOfCommits = getNumberOfCommits(buildList)
|
||||
if(config.wrapInNode){
|
||||
node(){
|
||||
try{
|
||||
recipients = getCulprits(config, env.BRANCH_NAME, numberOfCommits)
|
||||
}finally{
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
}else{
|
||||
try{
|
||||
recipients = getCulprits(config, env.BRANCH_NAME, numberOfCommits)
|
||||
}finally{
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
echo "[${STEP_NAME}] last ${numberOfCommits} commits revealed following responsibles ${recipients}"
|
||||
return recipients
|
||||
}
|
||||
|
||||
def getCulprits(config, branch, numberOfCommits) {
|
||||
if (branch?.startsWith('PR-')) {
|
||||
//special GitHub Pull Request handling
|
||||
deleteDir()
|
||||
sshagent(
|
||||
credentials: [config.gitSshKeyCredentialsId],
|
||||
ignoreMissing: true
|
||||
) {
|
||||
def pullRequestID = branch.replaceAll('PR-', '')
|
||||
def localBranchName = "pr" + pullRequestID;
|
||||
sh """git init
|
||||
git fetch ${config.gitUrl} pull/${pullRequestID}/head:${localBranchName} > /dev/null 2>&1
|
||||
git checkout -f ${localBranchName} > /dev/null 2>&1
|
||||
"""
|
||||
}
|
||||
} else {
|
||||
//standard git/GitHub handling
|
||||
if (config.gitCommitId) {
|
||||
deleteDir()
|
||||
sshagent(
|
||||
credentials: [config.gitSshKeyCredentialsId],
|
||||
ignoreMissing: true
|
||||
) {
|
||||
sh """git clone ${config.gitUrl} .
|
||||
git checkout ${config.gitCommitId} > /dev/null 2>&1"""
|
||||
}
|
||||
} else {
|
||||
def retCode = sh(returnStatus: true, script: 'git log > /dev/null 2>&1')
|
||||
if (retCode != 0) {
|
||||
echo "[${STEP_NAME}] No git context available to retrieve culprits"
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def recipients = sh(returnStdout: true, script: "git log -${numberOfCommits} --pretty=format:'%ae %ce'")
|
||||
return getDistinctRecipients(recipients)
|
||||
}
|
||||
|
||||
def getDistinctRecipients(recipients){
|
||||
def result
|
||||
def recipientAddresses = recipients.split()
|
||||
def knownAddresses = new HashSet<String>()
|
||||
if(recipientAddresses != null) {
|
||||
for(address in recipientAddresses) {
|
||||
address = address.trim()
|
||||
if(address
|
||||
&& address.contains("@")
|
||||
&& !address.startsWith("noreply")
|
||||
&& !knownAddresses.contains(address)) {
|
||||
knownAddresses.add(address)
|
||||
}
|
||||
}
|
||||
result = knownAddresses.join(" ")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
def hasRecovered(buildResult, currentBuild){
|
||||
return buildResult == 'SUCCESS' && currentBuild.getPreviousBuild()?.result != 'SUCCESS'
|
||||
}
|
@ -21,13 +21,13 @@ import groovy.transform.Field
|
||||
'logSuccessfulMavenTransfers'
|
||||
])
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
final script = parameters.script
|
||||
|
||||
// load default & individual configuration
|
||||
Map configuration = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
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)
|
||||
|
@ -20,13 +20,13 @@ import groovy.transform.Field
|
||||
'dockerOptions'
|
||||
])
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
final script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
// load default & individual configuration
|
||||
Map configuration = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
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)
|
||||
|
@ -29,7 +29,7 @@ import groovy.transform.Field
|
||||
'warAction'
|
||||
])
|
||||
|
||||
def call(parameters = [:]) {
|
||||
void call(parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
@ -72,8 +72,8 @@ def call(parameters = [:]) {
|
||||
// Backward compatibility end
|
||||
|
||||
// load default & individual configuration
|
||||
Map configuration = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
Map configuration = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
|
||||
.mixin(stepCompatibilityConfiguration)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
|
@ -5,6 +5,9 @@ import groovy.text.SimpleTemplateEngine
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'newmanExecute'
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'dockerImage',
|
||||
'failOnError',
|
||||
@ -17,17 +20,18 @@ import groovy.transform.Field
|
||||
'stashContent',
|
||||
'testRepository'
|
||||
]
|
||||
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
def utils = parameters?.juStabUtils ?: new Utils()
|
||||
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
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)
|
||||
|
@ -11,7 +11,7 @@ import groovy.transform.Field
|
||||
* Load and executes a pipeline from another git repository.
|
||||
*
|
||||
*/
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
|
||||
node() {
|
||||
|
||||
|
52
vars/pipelineRestartSteps.groovy
Normal file
52
vars/pipelineRestartSteps.groovy
Normal file
@ -0,0 +1,52 @@
|
||||
import com.sap.piper.JenkinsUtils
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'pipelineRestartSteps'
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'sendMail',
|
||||
'timeoutInSeconds'
|
||||
]
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
void call(Map parameters = [:], body) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
def jenkinsUtils = parameters.jenkinsUtilsStub ?: new JenkinsUtils()
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.use()
|
||||
|
||||
def restart = true
|
||||
while (restart) {
|
||||
try {
|
||||
body()
|
||||
restart = false
|
||||
} catch (Throwable err) {
|
||||
echo "ERROR occured: ${err}"
|
||||
if (config.sendMail)
|
||||
if (jenkinsUtils.nodeAvailable()) {
|
||||
mailSendNotification script: script, buildResult: 'UNSTABLE'
|
||||
} else {
|
||||
node {
|
||||
mailSendNotification script: script, buildResult: 'UNSTABLE'
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
timeout(time: config.timeoutInSeconds, unit: 'SECONDS') {
|
||||
input message: 'Do you want to restart?', ok: 'Restart'
|
||||
}
|
||||
} catch(e) {
|
||||
restart = false
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ import groovy.transform.Field
|
||||
|
||||
@Field STEP_NAME = 'pipelineStashFiles'
|
||||
|
||||
def call(Map parameters = [:], body) {
|
||||
void call(Map parameters = [:], body) {
|
||||
handlePipelineStepErrors (stepName: 'pipelineStashFiles', stepParameters: parameters) {
|
||||
pipelineStashFilesBeforeBuild(parameters)
|
||||
body() //execute build
|
||||
|
@ -6,7 +6,7 @@ import groovy.transform.Field
|
||||
@Field Set STEP_CONFIG_KEYS = ['runCheckmarx', 'stashIncludes', 'stashExcludes']
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters, stepNameDoc: 'stashFiles') {
|
||||
def utils = parameters.juStabUtils
|
||||
@ -20,8 +20,8 @@ def call(Map parameters = [:]) {
|
||||
//additional includes via passing e.g. stashIncludes: [opa5: '**/*.include']
|
||||
//additional excludes via passing e.g. stashExcludes: [opa5: '**/*.exclude']
|
||||
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
|
@ -6,7 +6,7 @@ import groovy.transform.Field
|
||||
@Field Set STEP_CONFIG_KEYS = ['runOpaTests', 'stashIncludes', 'stashExcludes']
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters, stepNameDoc: 'stashFiles') {
|
||||
|
||||
@ -22,8 +22,8 @@ def call(Map parameters = [:]) {
|
||||
//additional includes via passing e.g. stashIncludes: [opa5: '**/*.include']
|
||||
//additional excludes via passing e.g. stashExcludes: [opa5: '**/*.exclude']
|
||||
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
|
@ -5,7 +5,7 @@ import groovy.transform.Field
|
||||
|
||||
@Field STEP_NAME = 'prepareDefaultValues'
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: 'prepareDefaultValues', stepParameters: parameters) {
|
||||
if(!DefaultValueCache.getInstance() || parameters.customDefaults) {
|
||||
def defaultValues = [:]
|
||||
|
@ -6,8 +6,13 @@ import groovy.transform.Field
|
||||
import groovy.text.SimpleTemplateEngine
|
||||
|
||||
@Field String STEP_NAME = 'seleniumExecuteTests'
|
||||
|
||||
@Field GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'buildTool', //defines the tool which is used for executing the tests
|
||||
'containerPortMappings', //port mappings required for containers. This will only take effect inside a Kubernetes pod, format [[containerPort: 1111, hostPort: 1111]]
|
||||
'dockerEnvVars', //envVars to be set in the execution container if required
|
||||
'dockerImage', //Docker image for code execution
|
||||
'dockerName', //name of the Docker container. This will only take effect inside a Kubernetes pod.
|
||||
'dockerWorkspace', //user home directory for Docker execution. This will only take effect inside a Kubernetes pod.
|
||||
@ -21,17 +26,18 @@ import groovy.text.SimpleTemplateEngine
|
||||
'stashContent', //list of stash names which are required to be unstashed before test run
|
||||
'testRepository' //if tests are in a separate repository, git url can be defined. For protected repositories the git ssh url is required
|
||||
]
|
||||
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
def call(Map parameters = [:], Closure body) {
|
||||
void call(Map parameters = [:], Closure body) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
def utils = parameters?.juStabUtils ?: new Utils()
|
||||
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
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)
|
||||
@ -45,6 +51,7 @@ def call(Map parameters = [:], Closure body) {
|
||||
dockerExecute(
|
||||
script: script,
|
||||
containerPortMappings: config.containerPortMappings,
|
||||
dockerEnvVars: config.dockerEnvVars,
|
||||
dockerImage: config.dockerImage,
|
||||
dockerName: config.dockerName,
|
||||
dockerWorkspace: config.dockerWorkspace,
|
||||
|
@ -5,7 +5,7 @@ import groovy.transform.Field
|
||||
@Field String STEP_NAME = 'setupCommonPipelineEnvironment'
|
||||
@Field Set GENERAL_CONFIG_KEYS = ['collectTelemetryData']
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
@ -17,8 +17,8 @@ def call(Map parameters = [:]) {
|
||||
|
||||
loadConfigurationFromFile(script, configFile)
|
||||
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
|
||||
.use()
|
||||
|
||||
|
@ -19,13 +19,13 @@ import groovy.transform.Field
|
||||
])
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def utils = parameters.juStabUtils ?: new Utils()
|
||||
def script = parameters.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
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)
|
||||
|
@ -10,6 +10,7 @@ import groovy.transform.Field
|
||||
]
|
||||
|
||||
@Field def STEP_NAME = 'testsPublishResults'
|
||||
@Field Set GENERAL_CONFIG_KEYS = TOOLS
|
||||
@Field Set STEP_CONFIG_KEYS = TOOLS
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@ -19,7 +20,7 @@ import groovy.transform.Field
|
||||
* @param script global script environment of the Jenkinsfile run
|
||||
* @param others document all parameters
|
||||
*/
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters.script
|
||||
if (script == null)
|
||||
@ -27,9 +28,9 @@ def call(Map parameters = [:]) {
|
||||
prepare(parameters)
|
||||
|
||||
// load default & individual configuration
|
||||
Map configuration = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
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)
|
||||
|
@ -9,7 +9,7 @@ import hudson.AbortException
|
||||
|
||||
@Field STEP_NAME = 'toolValidate'
|
||||
|
||||
def call(Map parameters = [:]) {
|
||||
void call(Map parameters = [:]) {
|
||||
|
||||
handlePipelineStepErrors (stepName: 'toolValidate', stepParameters: parameters) {
|
||||
|
||||
|
@ -2,50 +2,69 @@ import com.sap.piper.Utils
|
||||
import groovy.transform.Field
|
||||
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.cm.BackendType
|
||||
import com.sap.piper.cm.ChangeManagement
|
||||
import com.sap.piper.cm.ChangeManagementException
|
||||
|
||||
import hudson.AbortException
|
||||
import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrationDisabled
|
||||
|
||||
import hudson.AbortException
|
||||
|
||||
@Field def STEP_NAME = 'transportRequestCreate'
|
||||
|
||||
@Field Set stepConfigurationKeys = [
|
||||
@Field GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'changeManagement',
|
||||
'developmentSystemId'
|
||||
'description', // CTS
|
||||
'developmentSystemId', // SOLMAN
|
||||
'targetSystem', // CTS
|
||||
'transportType', // CTS
|
||||
]
|
||||
|
||||
@Field Set parameterKeys = stepConfigurationKeys.plus(['changeDocumentId'])
|
||||
|
||||
@Field generalConfigurationKeys = stepConfigurationKeys
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus(['changeDocumentId'])
|
||||
|
||||
def call(parameters = [:]) {
|
||||
|
||||
def transportRequestId
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
|
||||
ChangeManagement cm = parameters.cmUtils ?: new ChangeManagement(script)
|
||||
|
||||
ConfigurationHelper configHelper = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, generalConfigurationKeys)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, stepConfigurationKeys)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, stepConfigurationKeys)
|
||||
.mixin(parameters, parameterKeys)
|
||||
ConfigurationHelper configHelper = 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)
|
||||
|
||||
|
||||
Map configuration = configHelper.use()
|
||||
|
||||
BackendType backendType = getBackendTypeAndLogInfoIfCMIntegrationDisabled(this, configuration)
|
||||
if(backendType == BackendType.NONE) return
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], configuration)
|
||||
|
||||
configHelper
|
||||
.withMandatoryProperty('changeManagement/clientOpts')
|
||||
.withMandatoryProperty('changeManagement/credentialsId')
|
||||
.withMandatoryProperty('changeManagement/endpoint')
|
||||
.withMandatoryProperty('changeManagement/git/from')
|
||||
.withMandatoryProperty('changeManagement/git/to')
|
||||
.withMandatoryProperty('changeManagement/git/format')
|
||||
.withMandatoryProperty('developmentSystemId')
|
||||
.withMandatoryProperty('transportType', null, { backendType == BackendType.CTS})
|
||||
.withMandatoryProperty('targetSystem', null, { backendType == BackendType.CTS})
|
||||
.withMandatoryProperty('description', null, { backendType == BackendType.CTS})
|
||||
|
||||
Map configuration = configHelper.use()
|
||||
def changeDocumentId = null
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], configuration)
|
||||
if(backendType == BackendType.SOLMAN) {
|
||||
|
||||
def changeDocumentId = configuration.changeDocumentId
|
||||
changeDocumentId = configuration.changeDocumentId
|
||||
|
||||
if(changeDocumentId?.trim()) {
|
||||
|
||||
@ -70,28 +89,47 @@ def call(parameters = [:]) {
|
||||
echo "[WARN] Cannot retrieve changeDocumentId from commit history: ${ex.getMessage()}."
|
||||
}
|
||||
}
|
||||
|
||||
configuration = configHelper.mixin([changeDocumentId: changeDocumentId?.trim() ?: null], ['changeDocumentId'] as Set)
|
||||
configHelper.mixin([changeDocumentId: changeDocumentId?.trim() ?: null], ['changeDocumentId'] as Set)
|
||||
.withMandatoryProperty('developmentSystemId')
|
||||
.withMandatoryProperty('changeDocumentId',
|
||||
"Change document id not provided (parameter: \'changeDocumentId\' or via commit history).")
|
||||
.use()
|
||||
}
|
||||
|
||||
def transportRequestId
|
||||
configuration = configHelper.use()
|
||||
|
||||
echo "[INFO] Creating transport request for change document '${configuration.changeDocumentId}' and development system '${configuration.developmentSystemId}'."
|
||||
def creatingMessage = ["[INFO] Creating transport request"]
|
||||
if(backendType == BackendType.SOLMAN) {
|
||||
creatingMessage << " for change document '${configuration.changeDocumentId}' and development system '${configuration.developmentSystemId}'"
|
||||
}
|
||||
creatingMessage << '.'
|
||||
echo creatingMessage.join()
|
||||
|
||||
try {
|
||||
transportRequestId = cm.createTransportRequest(configuration.changeDocumentId,
|
||||
if(backendType == BackendType.SOLMAN) {
|
||||
transportRequestId = cm.createTransportRequestSOLMAN(
|
||||
configuration.changeDocumentId,
|
||||
configuration.developmentSystemId,
|
||||
configuration.changeManagement.endpoint,
|
||||
configuration.changeManagement.credentialsId,
|
||||
configuration.changeManagement.clientOpts)
|
||||
} else if(backendType == BackendType.CTS) {
|
||||
transportRequestId = cm.createTransportRequestCTS(
|
||||
configuration.transportType,
|
||||
configuration.targetSystem,
|
||||
configuration.description,
|
||||
configuration.changeManagement.endpoint,
|
||||
configuration.changeManagement.credentialsId,
|
||||
configuration.changeManagement.clientOpts)
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid backend type: '${backendType}'.")
|
||||
}
|
||||
} catch(ChangeManagementException ex) {
|
||||
throw new AbortException(ex.getMessage())
|
||||
}
|
||||
|
||||
|
||||
echo "[INFO] Transport Request '$transportRequestId' has been successfully created."
|
||||
}
|
||||
|
||||
return transportRequestId
|
||||
}
|
||||
}
|
||||
|
@ -2,26 +2,28 @@ import com.sap.piper.Utils
|
||||
import groovy.transform.Field
|
||||
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.cm.BackendType
|
||||
import com.sap.piper.cm.ChangeManagement
|
||||
import com.sap.piper.cm.ChangeManagementException
|
||||
|
||||
import hudson.AbortException
|
||||
|
||||
import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrationDisabled
|
||||
|
||||
@Field def STEP_NAME = 'transportRequestRelease'
|
||||
|
||||
@Field Set stepConfigurationKeys = [
|
||||
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'changeManagement'
|
||||
]
|
||||
|
||||
@Field Set parameterKeys = stepConfigurationKeys.plus([
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([
|
||||
'changeDocumentId',
|
||||
'transportRequestId',
|
||||
])
|
||||
|
||||
@Field Set generalConfigurationKeys = stepConfigurationKeys
|
||||
|
||||
def call(parameters = [:]) {
|
||||
void call(parameters = [:]) {
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
@ -29,12 +31,20 @@ def call(parameters = [:]) {
|
||||
|
||||
ChangeManagement cm = parameters.cmUtils ?: new ChangeManagement(script)
|
||||
|
||||
ConfigurationHelper configHelper = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, generalConfigurationKeys)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, stepConfigurationKeys)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, stepConfigurationKeys)
|
||||
.mixin(parameters, parameterKeys)
|
||||
ConfigurationHelper configHelper = 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)
|
||||
|
||||
|
||||
Map configuration = configHelper.use()
|
||||
|
||||
BackendType backendType = getBackendTypeAndLogInfoIfCMIntegrationDisabled(this, configuration)
|
||||
if(backendType == BackendType.NONE) return
|
||||
|
||||
configHelper
|
||||
.withMandatoryProperty('changeManagement/clientOpts')
|
||||
.withMandatoryProperty('changeManagement/credentialsId')
|
||||
.withMandatoryProperty('changeManagement/endpoint')
|
||||
@ -42,8 +52,6 @@ def call(parameters = [:]) {
|
||||
.withMandatoryProperty('changeManagement/git/from')
|
||||
.withMandatoryProperty('changeManagement/git/format')
|
||||
|
||||
Map configuration = configHelper.use()
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], configuration)
|
||||
|
||||
def transportRequestId = configuration.transportRequestId
|
||||
@ -72,7 +80,11 @@ def call(parameters = [:]) {
|
||||
}
|
||||
}
|
||||
|
||||
def changeDocumentId = configuration.changeDocumentId
|
||||
def changeDocumentId = null
|
||||
|
||||
if(backendType == BackendType.SOLMAN) {
|
||||
|
||||
changeDocumentId = configuration.changeDocumentId
|
||||
|
||||
if(changeDocumentId?.trim()) {
|
||||
|
||||
@ -98,19 +110,26 @@ def call(parameters = [:]) {
|
||||
}
|
||||
}
|
||||
|
||||
configuration = configHelper
|
||||
.mixin([transportRequestId: transportRequestId?.trim() ?: null,
|
||||
changeDocumentId: changeDocumentId?.trim() ?: null], ['transportRequestId', 'changeDocumentId'] as Set)
|
||||
.withMandatoryProperty('transportRequestId',
|
||||
"Transport request id not provided (parameter: \'transportRequestId\' or via commit history).")
|
||||
configHelper.mixin([changeDocumentId: changeDocumentId?.trim() ?: null], ['changeDocumentId'] as Set)
|
||||
.withMandatoryProperty('changeDocumentId',
|
||||
"Change document id not provided (parameter: \'changeDocumentId\' or via commit history).")
|
||||
|
||||
}
|
||||
|
||||
configuration = configHelper
|
||||
.mixin([transportRequestId: transportRequestId?.trim() ?: null], ['transportRequestId'] as Set)
|
||||
.withMandatoryProperty('transportRequestId',
|
||||
"Transport request id not provided (parameter: \'transportRequestId\' or via commit history).")
|
||||
.use()
|
||||
|
||||
echo "[INFO] Closing transport request '${configuration.transportRequestId}' for change document '${configuration.changeDocumentId}'."
|
||||
def closingMessage = ["[INFO] Closing transport request '${configuration.transportRequestId}'"]
|
||||
if(backendType == BackendType.SOLMAN) closingMessage << " for change document '${configuration.changeDocumentId}'"
|
||||
closingMessage << '.'
|
||||
echo closingMessage.join()
|
||||
|
||||
try {
|
||||
cm.releaseTransportRequest(configuration.changeDocumentId,
|
||||
cm.releaseTransportRequest(backendType,
|
||||
configuration.changeDocumentId,
|
||||
configuration.transportRequestId,
|
||||
configuration.changeManagement.endpoint,
|
||||
configuration.changeManagement.credentialsId,
|
||||
|
@ -3,27 +3,29 @@ import groovy.transform.Field
|
||||
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
import com.sap.piper.cm.ChangeManagement
|
||||
import com.sap.piper.cm.BackendType
|
||||
import com.sap.piper.cm.ChangeManagementException
|
||||
|
||||
import hudson.AbortException
|
||||
|
||||
import static com.sap.piper.cm.StepHelpers.getBackendTypeAndLogInfoIfCMIntegrationDisabled
|
||||
|
||||
@Field def STEP_NAME = 'transportRequestUploadFile'
|
||||
|
||||
@Field Set generalConfigurationKeys = [
|
||||
@Field Set GENERAL_CONFIG_KEYS = [
|
||||
'changeManagement'
|
||||
]
|
||||
|
||||
@Field Set stepConfigurationKeys = generalConfigurationKeys.plus([
|
||||
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
|
||||
'applicationId'
|
||||
])
|
||||
|
||||
@Field Set parameterKeys = stepConfigurationKeys.plus([
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([
|
||||
'changeDocumentId',
|
||||
'filePath',
|
||||
'transportRequestId'])
|
||||
|
||||
def call(parameters = [:]) {
|
||||
void call(parameters = [:]) {
|
||||
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
|
||||
@ -31,28 +33,37 @@ def call(parameters = [:]) {
|
||||
|
||||
ChangeManagement cm = parameters.cmUtils ?: new ChangeManagement(script)
|
||||
|
||||
ConfigurationHelper configHelper = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, generalConfigurationKeys)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, stepConfigurationKeys)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, stepConfigurationKeys)
|
||||
.mixin(parameters, parameterKeys)
|
||||
ConfigurationHelper configHelper = 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)
|
||||
.addIfEmpty('filePath', script.commonPipelineEnvironment.getMtarFilePath())
|
||||
.withMandatoryProperty('applicationId')
|
||||
|
||||
Map configuration = configHelper.use()
|
||||
|
||||
BackendType backendType = getBackendTypeAndLogInfoIfCMIntegrationDisabled(this, configuration)
|
||||
if(backendType == BackendType.NONE) return
|
||||
|
||||
configHelper
|
||||
.withMandatoryProperty('changeManagement/changeDocumentLabel')
|
||||
.withMandatoryProperty('changeManagement/clientOpts')
|
||||
.withMandatoryProperty('changeManagement/credentialsId')
|
||||
.withMandatoryProperty('changeManagement/endpoint')
|
||||
.withMandatoryProperty('changeManagement/type')
|
||||
.withMandatoryProperty('changeManagement/git/from')
|
||||
.withMandatoryProperty('changeManagement/git/to')
|
||||
.withMandatoryProperty('changeManagement/git/format')
|
||||
.withMandatoryProperty('filePath')
|
||||
|
||||
Map configuration = configHelper.use()
|
||||
new Utils().pushToSWA([step: STEP_NAME, stepParam1: configuration.changeManagement.type], configuration)
|
||||
|
||||
new Utils().pushToSWA([step: STEP_NAME], configuration)
|
||||
def changeDocumentId = null
|
||||
|
||||
def changeDocumentId = configuration.changeDocumentId
|
||||
if(backendType == BackendType.SOLMAN) {
|
||||
|
||||
changeDocumentId = configuration.changeDocumentId
|
||||
|
||||
if(changeDocumentId?.trim()) {
|
||||
|
||||
@ -77,6 +88,7 @@ def call(parameters = [:]) {
|
||||
echo "[WARN] Cannot retrieve changeDocumentId from commit history: ${ex.getMessage()}."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def transportRequestId = configuration.transportRequestId
|
||||
|
||||
@ -104,21 +116,33 @@ def call(parameters = [:]) {
|
||||
}
|
||||
}
|
||||
|
||||
configuration = configHelper
|
||||
configHelper
|
||||
.mixin([changeDocumentId: changeDocumentId?.trim() ?: null,
|
||||
transportRequestId: transportRequestId?.trim() ?: null], ['changeDocumentId', 'transportRequestId'] as Set)
|
||||
|
||||
if(backendType == BackendType.SOLMAN) {
|
||||
configHelper
|
||||
.withMandatoryProperty('changeDocumentId',
|
||||
"Change document id not provided (parameter: \'changeDocumentId\' or via commit history).")
|
||||
.withMandatoryProperty('applicationId')
|
||||
}
|
||||
configuration = configHelper
|
||||
.withMandatoryProperty('transportRequestId',
|
||||
"Transport request id not provided (parameter: \'transportRequestId\' or via commit history).")
|
||||
.use()
|
||||
|
||||
echo "[INFO] Uploading file '${configuration.filePath}' to transport request '${configuration.transportRequestId}' of change document '${configuration.changeDocumentId}'."
|
||||
def uploadingMessage = ["[INFO] Uploading file '${configuration.filePath}' to transport request '${configuration.transportRequestId}'"]
|
||||
if(backendType == BackendType.SOLMAN)
|
||||
uploadingMessage << " of change document '${configuration.changeDocumentId}'"
|
||||
uploadingMessage << '.'
|
||||
|
||||
echo uploadingMessage.join()
|
||||
|
||||
try {
|
||||
|
||||
|
||||
cm.uploadFileToTransportRequest(configuration.changeDocumentId,
|
||||
cm.uploadFileToTransportRequest(backendType,
|
||||
configuration.changeDocumentId,
|
||||
configuration.transportRequestId,
|
||||
configuration.applicationId,
|
||||
configuration.filePath,
|
||||
@ -131,6 +155,10 @@ def call(parameters = [:]) {
|
||||
}
|
||||
|
||||
|
||||
echo "[INFO] File '${configuration.filePath}' has been successfully uploaded to transport request '${configuration.transportRequestId}' of change document '${configuration.changeDocumentId}'."
|
||||
def uploadedMessage = ["[INFO] File '${configuration.filePath}' has been successfully uploaded to transport request '${configuration.transportRequestId}'"]
|
||||
if(backendType == BackendType.SOLMAN)
|
||||
uploadedMessage << " of change document '${configuration.changeDocumentId}'"
|
||||
uploadedMessage << '.'
|
||||
echo uploadedMessage.join()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user