mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-03-03 15:02:35 +02:00
Merge branch 'master' into whitesource-step
This commit is contained in:
commit
259619f00f
@ -8,13 +8,7 @@ none
|
||||
|
||||
## ${docGenParameters}
|
||||
|
||||
## Step configuration
|
||||
|
||||
none
|
||||
|
||||
## Exceptions
|
||||
|
||||
none
|
||||
## ${docGenConfiguration}
|
||||
|
||||
## Example
|
||||
|
||||
@ -23,7 +17,7 @@ handlePipelineStepErrors (stepName: 'executeHealthCheck', stepParameters: parame
|
||||
def url = new Utils().getMandatoryParameter(parameters, 'url', null)
|
||||
def statusCode = curl(url)
|
||||
if (statusCode != '200')
|
||||
error "Health Check failed: ${statusCode}"
|
||||
error "Health Check failed: \${statusCode}"
|
||||
}
|
||||
```
|
||||
|
||||
@ -41,14 +35,14 @@ If `echoDetails` is set to true the following information will be output to the
|
||||
----------------------------------------------------------
|
||||
The following parameters were available to the step:
|
||||
***
|
||||
${stepParameters}
|
||||
\${stepParameters}
|
||||
***
|
||||
The error was:
|
||||
***
|
||||
${err}
|
||||
\${err}
|
||||
***
|
||||
Further information:
|
||||
* Documentation of step ${stepName}: .../${stepName}/
|
||||
* Documentation of step \${stepName}: .../\${stepName}/
|
||||
* Pipeline documentation: https://...
|
||||
* GitHub repository for pipeline steps: https://...
|
||||
----------------------------------------------------------
|
||||
|
@ -14,3 +14,75 @@ If you see an error like `fatal: Not a git repository (or any parent up to mount
|
||||
Please make sure to point parameter `testOptions` to your `conf.js` file like `testOptions: './path/to/my/tests/conf.js'`
|
||||
|
||||
## Examples
|
||||
|
||||
### Passing credentials from Jenkins
|
||||
|
||||
When running acceptance tests in a real environment, authentication will be enabled in most cases. UIVeri5 includes [features to automatically perform the login](https://github.com/SAP/ui5-uiveri5/blob/master/docs/config/authentication.md) with credentials in the `conf.js`. However, having credentials to the acceptance system stored in plain text is not an optimal solution.
|
||||
|
||||
Therefore, UIVeri5 allows templating to set parameters at runtime, as shown in the following example `conf.js`:
|
||||
|
||||
```js
|
||||
// Read environment variables
|
||||
const defaultParams = {
|
||||
url: process.env.TARGET_SERVER_URL,
|
||||
user: process.env.TEST_USER,
|
||||
pass: process.env.TEST_PASS
|
||||
};
|
||||
|
||||
// Resolve path to specs relative to the working directory
|
||||
const path = require('path');
|
||||
const specs = path.relative(process.cwd(), path.join(__dirname, '*.spec.js'));
|
||||
|
||||
// export UIVeri5 config
|
||||
exports.config = {
|
||||
profile: 'integration',
|
||||
baseUrl: '${params.url}',
|
||||
specs: specs,
|
||||
params: defaultParams, // can be overridden via cli `--params.<key>=<value>`
|
||||
auth: {
|
||||
// set up authorization for CF XSUAA
|
||||
'sapcloud-form': {
|
||||
user: '${params.user}',
|
||||
pass: '${params.pass}',
|
||||
userFieldSelector: 'input[name="username"]',
|
||||
passFieldSelector: 'input[name="password"]',
|
||||
logonButtonSelector: 'input[type="submit"]',
|
||||
redirectUrl: /cp.portal\/site/
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
While default values for `baseUrl`, `user` and `pass` are read from the environment, they can also be overridden when calling the CLI.
|
||||
|
||||
In a custom Pipeline, this is very simple: Just wrap the call to `uiVeri5ExecuteTests` in `withCredentials` (`TARGET_SERVER_URL` is read from `config.yml`):
|
||||
|
||||
```groovy
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: 'MY_ACCEPTANCE_CREDENTIALS',
|
||||
passwordVariable: 'password',
|
||||
usernameVariable: 'username'
|
||||
)]) {
|
||||
uiVeri5ExecuteTests script: this, testOptions: "./uiveri5/conf.js --params.user=${username} --params.pass=${password}"
|
||||
}
|
||||
```
|
||||
|
||||
In a Pipeline Template, a [Stage Exit](#) can be used to fetch the credentials and store them in the environment. As the environment is passed down to uiVeri5ExecuteTests, the variables will be present there. This is an example for the stage exit `.pipeline/extensions/Acceptance.groovy` where the `credentialsId` is read from the `config.yml`:
|
||||
|
||||
```groovy
|
||||
void call(Map params) {
|
||||
// read username and password from the credential store
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: params.config.acceptanceCredentialsId,
|
||||
passwordVariable: 'password',
|
||||
usernameVariable: 'username'
|
||||
)]) {
|
||||
// store the result in the environment variables for executeUIVeri5Test
|
||||
withEnv(["TEST_USER=${username}", "TEST_PASS=${password}"]) {
|
||||
//execute original stage as defined in the template
|
||||
params.originalStage()
|
||||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
```
|
||||
|
@ -223,8 +223,10 @@ steps:
|
||||
testOptions: 'specs'
|
||||
handlePipelineStepErrors:
|
||||
echoDetails: true
|
||||
failOnError: true
|
||||
libraryDocumentationUrl: 'https://sap.github.io/jenkins-library/'
|
||||
libraryRepositoryUrl: 'https://github.com/SAP/jenkins-library/'
|
||||
mandatorySteps: []
|
||||
healthExecuteCheck:
|
||||
healthEndpoint: ''
|
||||
influxWriteData:
|
||||
|
@ -26,7 +26,11 @@ class ConfigurationLoader implements Serializable {
|
||||
|
||||
@NonCPS
|
||||
static Map generalConfiguration(script){
|
||||
return script?.commonPipelineEnvironment?.configuration?.general ?: [:]
|
||||
try {
|
||||
return script?.commonPipelineEnvironment?.configuration?.general ?: [:]
|
||||
} catch (groovy.lang.MissingPropertyException mpe) {
|
||||
return [:]
|
||||
}
|
||||
}
|
||||
|
||||
@NonCPS
|
||||
@ -43,7 +47,12 @@ class ConfigurationLoader implements Serializable {
|
||||
private static Map loadConfiguration(script, String type, String entryName, ConfigurationType configType){
|
||||
switch (configType) {
|
||||
case ConfigurationType.CUSTOM_CONFIGURATION:
|
||||
return script?.commonPipelineEnvironment?.configuration?.get(type)?.get(entryName) ?: [:]
|
||||
try {
|
||||
return script?.commonPipelineEnvironment?.configuration?.get(type)?.get(entryName) ?: [:]
|
||||
} catch (groovy.lang.MissingPropertyException mpe) {
|
||||
return [:]
|
||||
}
|
||||
|
||||
case ConfigurationType.DEFAULT_CONFIGURATION:
|
||||
return DefaultValueCache.getInstance()?.getDefaultValues()?.get(type)?.get(entryName) ?: [:]
|
||||
default:
|
||||
|
@ -1,4 +1,6 @@
|
||||
#!groovy
|
||||
import hudson.AbortException
|
||||
|
||||
import static org.hamcrest.Matchers.is
|
||||
import static org.hamcrest.Matchers.not
|
||||
import static org.hamcrest.Matchers.containsString
|
||||
@ -81,4 +83,62 @@ class HandlePipelineStepErrorsTest extends BasePiperTest {
|
||||
assertThat(loggingRule.log, containsString('[something:anything]'))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleErrorsIgnoreFailure() {
|
||||
def errorOccured = false
|
||||
try {
|
||||
stepRule.step.handlePipelineStepErrors([
|
||||
stepName: 'test',
|
||||
stepParameters: [jenkinsUtilsStub: jenkinsUtils, script: nullScript],
|
||||
failOnError: false
|
||||
]) {
|
||||
throw new AbortException('TestError')
|
||||
}
|
||||
} catch (err) {
|
||||
errorOccured = true
|
||||
}
|
||||
assertThat(errorOccured, is(false))
|
||||
assertThat(nullScript.currentBuild.result, is('UNSTABLE'))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleErrorsIgnoreFailureBlacklist() {
|
||||
def errorOccured = false
|
||||
|
||||
//define blacklist in defaults
|
||||
helper.registerAllowedMethod("readYaml", [Map], { Map m ->
|
||||
return [steps: [handlePipelineStepErrors: [mandatorySteps: ['step1', 'test']]]]
|
||||
})
|
||||
|
||||
try {
|
||||
stepRule.step.handlePipelineStepErrors([
|
||||
stepName: 'test',
|
||||
stepParameters: [jenkinsUtilsStub: jenkinsUtils, script: nullScript],
|
||||
failOnError: false
|
||||
]) {
|
||||
throw new AbortException('TestError')
|
||||
}
|
||||
} catch (err) {
|
||||
errorOccured = true
|
||||
}
|
||||
assertThat(errorOccured, is(true))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleErrorsIgnoreFailureNoScript() {
|
||||
def errorOccured = false
|
||||
try {
|
||||
stepRule.step.handlePipelineStepErrors([
|
||||
stepName: 'test',
|
||||
stepParameters: [jenkinsUtilsStub: jenkinsUtils],
|
||||
failOnError: false
|
||||
]) {
|
||||
throw new AbortException('TestError')
|
||||
}
|
||||
} catch (err) {
|
||||
errorOccured = true
|
||||
}
|
||||
assertThat(errorOccured, is(false))
|
||||
}
|
||||
}
|
@ -5,12 +5,21 @@ import com.sap.piper.ConfigurationHelper
|
||||
|
||||
import groovy.text.SimpleTemplateEngine
|
||||
import groovy.transform.Field
|
||||
import hudson.AbortException
|
||||
|
||||
@Field STEP_NAME = getClass().getName()
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = []
|
||||
@Field Set STEP_CONFIG_KEYS = []
|
||||
@Field Set PARAMETER_KEYS = [
|
||||
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
|
||||
/**
|
||||
* Defines the behavior, in case an error occurs which is handled by this step. When set to `false` an error results in an "UNSTABLE" build result and the pipeline can continue.
|
||||
* @possibleValues `true`, `false`
|
||||
*/
|
||||
'failOnError',
|
||||
/** Defines a list of mandatory steps (step names) which have to be successful (=stop the pipeline), even if `failOnError: false` */
|
||||
'mandatorySteps'
|
||||
])
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([
|
||||
/**
|
||||
* If it is set to true details will be output to the console. See example below.
|
||||
* @possibleValues `true`, `false`
|
||||
@ -20,13 +29,13 @@ import groovy.transform.Field
|
||||
'libraryDocumentationUrl',
|
||||
/** Defines the url of the library's repository that will be used to generate the corresponding links to the step implementation.*/
|
||||
'libraryRepositoryUrl',
|
||||
/** Defines the name of the step executed that will be shown in the console output.*/
|
||||
/** Defines the name of the step for which the error handling is active. It will be shown in the console log.*/
|
||||
'stepName',
|
||||
/** */
|
||||
/** Defines the documented step, in case the documentation reference should point to a different step. */
|
||||
'stepNameDoc',
|
||||
/** Defines the parameters from the step to be executed. The list of parameters is then shown in the console output.*/
|
||||
/** Passes the parameters of the step which uses the error handling onto the error handling. The list of parameters is then shown in the console output.*/
|
||||
'stepParameters'
|
||||
]
|
||||
])
|
||||
|
||||
/**
|
||||
* Used by other steps to make error analysis easier. Lists parameters and other data available to the step in which the error occurs.
|
||||
@ -34,8 +43,12 @@ import groovy.transform.Field
|
||||
@GenerateDocumentation
|
||||
void call(Map parameters = [:], body) {
|
||||
// load default & individual configuration
|
||||
def cpe = parameters.stepParameters?.script?.commonPipelineEnvironment ?: commonPipelineEnvironment
|
||||
Map config = ConfigurationHelper.newInstance(this)
|
||||
.loadStepDefaults()
|
||||
.mixinGeneralConfig(cpe, GENERAL_CONFIG_KEYS)
|
||||
.mixinStepConfig(cpe, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(cpe, parameters.stepParameters?.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.withMandatoryProperty('stepParameters')
|
||||
.withMandatoryProperty('stepName')
|
||||
@ -48,6 +61,19 @@ void call(Map parameters = [:], body) {
|
||||
echo "--- Begin library step of: ${config.stepName} ---"
|
||||
|
||||
body()
|
||||
} catch (AbortException ae) {
|
||||
if (config.echoDetails)
|
||||
message += formatErrorMessage(config, ae)
|
||||
writeErrorToInfluxData(config, ae)
|
||||
if (config.failOnError || config.stepName in config.mandatorySteps) {
|
||||
throw ae
|
||||
}
|
||||
if (config.stepParameters?.script) {
|
||||
config.stepParameters?.script.currentBuild.result = 'UNSTABLE'
|
||||
} else {
|
||||
currentBuild.result = 'UNSTABLE'
|
||||
}
|
||||
|
||||
} catch (Throwable error) {
|
||||
if (config.echoDetails)
|
||||
message += formatErrorMessage(config, error)
|
||||
|
Loading…
x
Reference in New Issue
Block a user