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

Merge pull request #155 from SAP/stashFiles

add steps for file stashing
This commit is contained in:
Thorsten Duda 2018-05-30 14:19:14 +02:00 committed by GitHub
commit 6e6e26f809
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 828 additions and 39 deletions

20
pom.xml
View File

@ -109,6 +109,26 @@
<version>1.19</version> <version>1.19</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.10.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.5.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
<sourceDirectory>src</sourceDirectory> <sourceDirectory>src</sourceDirectory>

View File

@ -14,18 +14,6 @@ steps:
docker: docker:
filePath: 'Dockerfile' filePath: 'Dockerfile'
versioningTemplate: '${version}-${timestamp}${commitId?"_"+commitId:""}' versioningTemplate: '${version}-${timestamp}${commitId?"_"+commitId:""}'
mavenExecute:
dockerImage: 'maven:3.5-jdk-7'
influxWriteData:
influxServer: 'jenkins'
mtaBuild:
buildTarget: 'NEO'
mtaJarLocation: 'mta.jar'
neoDeploy:
deployMode: 'mta'
warAction: 'deploy'
vmSize: 'lite'
neoCredentialsId: 'CI_CREDENTIALS_ID'
checksPublishResults: checksPublishResults:
aggregation: aggregation:
active: true active: true
@ -85,6 +73,48 @@ steps:
fail: fail:
high: '0' high: '0'
archive: false archive: false
influxWriteData:
influxServer: 'jenkins'
mavenExecute:
dockerImage: 'maven:3.5-jdk-7'
mtaBuild:
buildTarget: 'NEO'
mtaJarLocation: 'mta.jar'
neoDeploy:
deployMode: 'mta'
warAction: 'deploy'
vmSize: 'lite'
neoCredentialsId: 'CI_CREDENTIALS_ID'
pipelineStashFilesAfterBuild:
stashIncludes:
checkmarx: '**/*.js, **/*.scala, **/*.py, **/*.go, **/*.xml, **/*.html'
classFiles: '**/target/classes/**/*.class, **/target/test-classes/**/*.class'
sonar: '**/jacoco*.exec, **/sonar-project.properties'
stashExcludes:
checkmarx: '**/*.mockserver.js, node_modules/**/*.js'
classFiles: ''
sonar: ''
pipelineStashFilesBeforeBuild:
stashIncludes:
buildDescriptor: '**/pom.xml, **/.mvn/**, **/assembly.xml, **/.swagger-codegen-ignore, **/package.json, **/requirements.txt, **/setup.py, **/whitesource_config.py, **/mta*.y*ml, **/.npmrc, **/whitesource.*.json, **/whitesource-fs-agent.config, .xmake.cfg, Dockerfile, **/VERSION, **/version.txt, **/build.sbt, **/sbtDescriptor.json, **/project/*'
deployDescriptor: '**/manifest*.y*ml, **/*.mtaext.y*ml, **/*.mtaext, **/xs-app.json, helm/**, *.y*ml'
git: '**/gitmetadata/**'
opa5: '**/*.*'
'opensource configuration': '**/srcclr.yml, **/vulas-custom.properties, **/.nsprc, **/.retireignore, **/.retireignore.json, **/'
pipelineConfigAndTests: '.pipeline/*.*'
securityDescriptor: '**/xs-security.json'
'snyk configuration': '**/.snyk'
tests: '**/pom.xml, **/*.json, **/*.xml, **/src/**, **/node_modules/**, **/specs/**, **/env/**, **/*.js'
stashExcludes:
buildDescriptor: '**/node_modules/**/package.json'
deployDescriptor: ''
git: ''
opa5: ''
'opensource configuration': ''
pipelineConfigAndTests: ''
securityDescriptor: ''
'snyk configuration': ''
tests: ''
testsPublishResults: testsPublishResults:
junit: junit:
pattern: '**/target/surefire-reports/*.xml' pattern: '**/target/surefire-reports/*.xml'

View File

@ -15,3 +15,39 @@ def getMandatoryParameter(Map map, paramName, defaultValue = null) {
return paramValue return paramValue
} }
def stash(name, include = '**/*.*', exclude = '') {
echo "Stash content: ${name} (include: ${include}, exclude: ${exclude})"
steps.stash name: name, includes: include, excludes: exclude
}
def stashWithMessage(name, msg, include = '**/*.*', exclude = '') {
try {
stash(name, include, exclude)
} catch (e) {
echo msg + name + " (${e.getMessage()})"
}
}
def unstash(name, msg = "Unstash failed:") {
def unstashedContent = []
try {
echo "Unstash content: ${name}"
steps.unstash name
unstashedContent += name
} catch (e) {
echo "$msg $name (${e.getMessage()})"
}
return unstashedContent
}
def unstashAll(stashContent) {
def unstashedContent = []
if (stashContent) {
for (i = 0; i < stashContent.size(); i++) {
unstashedContent += unstash(stashContent[i])
}
}
return unstashedContent
}

View File

@ -63,7 +63,7 @@ class InfluxWriteDataTest extends BasePipelineTest {
assertEquals('testInflux', stepMap.selectedTarget) assertEquals('testInflux', stepMap.selectedTarget)
assertEquals(null, stepMap.customPrefix) assertEquals(null, stepMap.customPrefix)
assertEquals([:], stepMap.customData) assertEquals([:], stepMap.customData)
assertEquals([pipeline_data:[:]], stepMap.customDataMap) assertEquals([pipeline_data: [:], step_data: [:]], stepMap.customDataMap)
assertTrue(fileMap.containsKey('jenkins_data.json')) assertTrue(fileMap.containsKey('jenkins_data.json'))
assertTrue(fileMap.containsKey('pipeline_data.json')) assertTrue(fileMap.containsKey('pipeline_data.json'))

View File

@ -9,10 +9,11 @@ import com.lesfurets.jenkins.unit.BasePipelineTest
import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertTrue import static org.junit.Assert.assertTrue
import util.BasePiperTest
import util.JenkinsShellCallRule import util.JenkinsShellCallRule
import util.Rules import util.Rules
class MavenExecuteTest extends BasePipelineTest { class MavenExecuteTest extends BasePiperTest {
Map dockerParameters Map dockerParameters
@ -23,7 +24,6 @@ class MavenExecuteTest extends BasePipelineTest {
.around(jscr) .around(jscr)
def mavenExecuteScript def mavenExecuteScript
def cpe
@Before @Before
void init() { void init() {
@ -37,13 +37,12 @@ class MavenExecuteTest extends BasePipelineTest {
}) })
mavenExecuteScript = loadScript("mavenExecute.groovy").mavenExecute mavenExecuteScript = loadScript("mavenExecute.groovy").mavenExecute
cpe = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment
} }
@Test @Test
void testExecuteBasicMavenCommand() throws Exception { void testExecuteBasicMavenCommand() throws Exception {
mavenExecuteScript.call(script: [commonPipelineEnvironment: cpe], goals: 'clean install') mavenExecuteScript.call(script: nullScript, goals: 'clean install')
assertEquals('maven:3.5-jdk-7', dockerParameters.dockerImage) assertEquals('maven:3.5-jdk-7', dockerParameters.dockerImage)
assert jscr.shell[0] == 'mvn clean install' assert jscr.shell[0] == 'mvn clean install'
@ -53,7 +52,7 @@ class MavenExecuteTest extends BasePipelineTest {
void testExecuteMavenCommandWithParameter() throws Exception { void testExecuteMavenCommandWithParameter() throws Exception {
mavenExecuteScript.call( mavenExecuteScript.call(
script: [commonPipelineEnvironment: cpe], script: nullScript,
dockerImage: 'maven:3.5-jdk-8-alpine', dockerImage: 'maven:3.5-jdk-8-alpine',
goals: 'clean install', goals: 'clean install',
globalSettingsFile: 'globalSettingsFile.xml', globalSettingsFile: 'globalSettingsFile.xml',
@ -70,7 +69,7 @@ class MavenExecuteTest extends BasePipelineTest {
@Test @Test
void testMavenCommandForwardsDockerOptions() throws Exception { void testMavenCommandForwardsDockerOptions() throws Exception {
mavenExecuteScript.call(script: [commonPipelineEnvironment: cpe], goals: 'clean install') mavenExecuteScript.call(script: nullScript, goals: 'clean install')
assertEquals('maven:3.5-jdk-7', dockerParameters.dockerImage) assertEquals('maven:3.5-jdk-7', dockerParameters.dockerImage)
assert jscr.shell[0] == 'mvn clean install' assert jscr.shell[0] == 'mvn clean install'

View File

@ -0,0 +1,72 @@
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import util.*
import static org.hamcrest.Matchers.containsString
import static org.junit.Assert.assertFalse
import static org.junit.Assert.assertThat
class PipelineStashFilesAfterBuildTest extends BasePiperTest {
JenkinsStepRule jsr = new JenkinsStepRule(this)
JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
JenkinsReadJsonRule jrj = new JenkinsReadJsonRule(this)
@Rule
public RuleChain rules = Rules
.getCommonRules(this)
.around(jrj)
.around(jlr)
.around(jsr)
@Test
void testStashAfterBuild() {
helper.registerAllowedMethod("fileExists", [String.class], {
searchTerm ->
return false
})
jsr.step.call(
script: nullScript,
juStabUtils: utils
)
// asserts
assertFalse(jlr.log.contains('Stash content: checkmarx'))
assertThat(jlr.log, containsString('Stash content: classFiles (include: **/target/classes/**/*.class, **/target/test-classes/**/*.class, exclude: )'))
assertThat(jlr.log, containsString('Stash content: sonar (include: **/jacoco*.exec, **/sonar-project.properties, exclude: )'))
assertFalse(jlr.log.contains('Stash content: postStagedFiles'))
}
@Test
void testStashAfterBuildWithCheckmarx() {
helper.registerAllowedMethod("fileExists", [String.class], {
searchTerm ->
return true
})
jsr.step.call(
script: nullScript,
juStabUtils: utils,
runCheckmarx: true
)
// asserts
assertThat(jlr.log, containsString('Stash content: checkmarx (include: **/*.js, **/*.scala, **/*.py, **/*.go, **/*.xml, **/*.html, exclude: **/*.mockserver.js, node_modules/**/*.js)'))
assertThat(jlr.log, containsString('Stash content: classFiles (include: **/target/classes/**/*.class, **/target/test-classes/**/*.class, exclude: )'))
assertThat(jlr.log, containsString('Stash content: sonar (include: **/jacoco*.exec, **/sonar-project.properties, exclude: )'))
}
@Test
void testStashAfterBuildWithCheckmarxConfig() {
helper.registerAllowedMethod("fileExists", [String.class], {
searchTerm ->
return true
})
jsr.step.call(
script: [commonPipelineEnvironment: [configuration: [steps: [executeCheckmarxScan: [checkmarxProject: 'TestProject']]]]],
juStabUtils: utils,
)
// asserts
assertThat(jlr.log, containsString('Stash content: checkmarx (include: **/*.js, **/*.scala, **/*.py, **/*.go, **/*.xml, **/*.html, exclude: **/*.mockserver.js, node_modules/**/*.js)'))
assertThat(jlr.log, containsString('Stash content: classFiles (include: **/target/classes/**/*.class, **/target/test-classes/**/*.class, exclude: )'))
assertThat(jlr.log, containsString('Stash content: sonar (include: **/jacoco*.exec, **/sonar-project.properties, exclude: )'))
}
}

View File

@ -0,0 +1,76 @@
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import util.*
import static org.hamcrest.Matchers.containsString
import static org.junit.Assert.*
class PipelineStashFilesBeforeBuildTest extends BasePiperTest {
JenkinsStepRule jsr = new JenkinsStepRule(this)
JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
//JenkinsReadJsonRule jrj = new JenkinsReadJsonRule(this)
@Rule
public RuleChain rules = Rules
.getCommonRules(this)
//.around(jrj)
.around(jlr)
.around(jscr)
.around(jsr)
@Test
void testStashBeforeBuildNoOpa() {
jsr.step.call(script: nullScript, juStabUtils: utils)
// asserts
assertEquals('mkdir -p gitmetadata', jscr.shell[0])
assertEquals('cp -rf .git/* gitmetadata', jscr.shell[1])
assertEquals('chmod -R u+w gitmetadata', jscr.shell[2])
assertFalse(jlr.log.contains('Stash content: opa5'))
assertThat(jlr.log, containsString('Stash content: git (include: **/gitmetadata/**, exclude: )'))
assertThat(jlr.log, containsString('Stash content: tests (include: **/pom.xml, **/*.json, **/*.xml, **/src/**, **/node_modules/**, **/specs/**, **/env/**, **/*.js, exclude: )'))
assertThat(jlr.log, containsString('Stash content: buildDescriptor (include: **/pom.xml, **/.mvn/**, **/assembly.xml, **/.swagger-codegen-ignore, **/package.json, **/requirements.txt, **/setup.py, **/whitesource_config.py, **/mta*.y*ml, **/.npmrc, **/whitesource.*.json, **/whitesource-fs-agent.config, .xmake.cfg, Dockerfile, **/VERSION, **/version.txt, **/build.sbt, **/sbtDescriptor.json, **/project/*, exclude: **/node_modules/**/package.json)'))
assertThat(jlr.log, containsString('Stash content: deployDescriptor (include: **/manifest*.y*ml, **/*.mtaext.y*ml, **/*.mtaext, **/xs-app.json, helm/**, *.y*ml, exclude: )'))
assertThat(jlr.log, containsString('Stash content: opensource configuration (include: **/srcclr.yml'))
assertThat(jlr.log, containsString('Stash content: snyk configuration (include: **/.snyk'))
assertThat(jlr.log, containsString('Stash content: pipelineConfigAndTests (include: .pipeline/*.*'))
assertThat(jlr.log, containsString('Stash content: securityDescriptor (include: **/xs-security.json'))
}
@Test
void testStashBeforeBuildOpa() {
jsr.step.call(script: nullScript, juStabUtils: utils, runOpaTests: true)
// asserts
assertThat(jlr.log, containsString('Stash content: opa5'))
assertThat(jlr.log, containsString('Stash content: git'))
assertThat(jlr.log, containsString('Stash content: tests'))
assertThat(jlr.log, containsString('Stash content: buildDescriptor'))
assertThat(jlr.log, containsString('Stash content: deployDescriptor'))
assertThat(jlr.log, containsString('Stash content: opensource configuration'))
assertThat(jlr.log, containsString('Stash content: snyk configuration'))
assertThat(jlr.log, containsString('Stash content: pipelineConfigAndTests'))
assertThat(jlr.log, containsString('Stash content: securityDescriptor'))
}
@Test
void testStashBeforeBuildOpaCompatibility() {
jsr.step.call(script: nullScript, juStabUtils: utils, runOpaTests: 'true')
// asserts
assertThat(jlr.log, containsString('Stash content: opa5'))
assertThat(jlr.log, containsString('Stash content: git'))
assertThat(jlr.log, containsString('Stash content: tests'))
assertThat(jlr.log, containsString('Stash content: buildDescriptor'))
assertThat(jlr.log, containsString('Stash content: deployDescriptor'))
assertThat(jlr.log, containsString('Stash content: opensource configuration'))
assertThat(jlr.log, containsString('Stash content: snyk configuration'))
assertThat(jlr.log, containsString('Stash content: pipelineConfigAndTests'))
assertThat(jlr.log, containsString('Stash content: securityDescriptor'))
}
}

View File

@ -6,13 +6,14 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.ExpectedException import org.junit.rules.ExpectedException
import org.junit.rules.RuleChain import org.junit.rules.RuleChain
import util.BasePiperTest
import util.JenkinsReadMavenPomRule import util.JenkinsReadMavenPomRule
import util.JenkinsShellCallRule import util.JenkinsShellCallRule
import util.Rules import util.Rules
import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals
class MavenArtifactVersioningTest extends BasePipelineTest{ class MavenArtifactVersioningTest extends BasePiperTest{
Map dockerParameters Map dockerParameters
def mavenExecuteScript def mavenExecuteScript
@ -21,10 +22,12 @@ class MavenArtifactVersioningTest extends BasePipelineTest{
MavenArtifactVersioning av MavenArtifactVersioning av
JenkinsShellCallRule jscr = new JenkinsShellCallRule(this) JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
ExpectedException thrown = ExpectedException.none()
@Rule @Rule
public RuleChain ruleChain = Rules.getCommonRules(this).around(jscr).around(thrown).around(new JenkinsReadMavenPomRule(this, 'test/resources/MavenArtifactVersioning')) public RuleChain ruleChain = Rules
.getCommonRules(this)
.around(jscr)
.around(new JenkinsReadMavenPomRule(this, 'test/resources/MavenArtifactVersioning'))
@Before @Before
void init() { void init() {
@ -35,16 +38,11 @@ class MavenArtifactVersioningTest extends BasePipelineTest{
dockerParameters = parameters dockerParameters = parameters
closure() closure()
}) })
mavenExecuteScript = loadScript("mavenExecute.groovy").mavenExecute
commonPipelineEnvironment = loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment
prepareObjectInterceptors(this)
} }
@Test @Test
void testVersioning() { void testVersioning() {
av = new MavenArtifactVersioning(this, [filePath: 'pom.xml']) av = new MavenArtifactVersioning(nullScript, [filePath: 'pom.xml'])
assertEquals('1.2.3', av.getVersion()) assertEquals('1.2.3', av.getVersion())
av.setVersion('1.2.3-20180101') av.setVersion('1.2.3-20180101')
assertEquals('mvn --file \'pom.xml\' versions:set -DnewVersion=1.2.3-20180101', jscr.shell[0]) assertEquals('mvn --file \'pom.xml\' versions:set -DnewVersion=1.2.3-20180101', jscr.shell[0])
@ -52,15 +50,9 @@ class MavenArtifactVersioningTest extends BasePipelineTest{
@Test @Test
void testVersioningCustomFilePathSnapshot() { void testVersioningCustomFilePathSnapshot() {
av = new MavenArtifactVersioning(this, [filePath: 'snapshot/pom.xml']) av = new MavenArtifactVersioning(nullScript, [filePath: 'snapshot/pom.xml'])
assertEquals('1.2.3', av.getVersion()) assertEquals('1.2.3', av.getVersion())
av.setVersion('1.2.3-20180101') av.setVersion('1.2.3-20180101')
assertEquals('mvn --file \'snapshot/pom.xml\' versions:set -DnewVersion=1.2.3-20180101', jscr.shell[0]) assertEquals('mvn --file \'snapshot/pom.xml\' versions:set -DnewVersion=1.2.3-20180101', jscr.shell[0])
} }
void prepareObjectInterceptors(object) {
object.metaClass.invokeMethod = helper.getMethodInterceptor()
object.metaClass.static.invokeMethod = helper.getMethodInterceptor()
object.metaClass.methodMissing = helper.getMethodMissingInterceptor()
}
} }

View File

@ -0,0 +1,52 @@
#!groovy
package util
import com.lesfurets.jenkins.unit.BasePipelineTest
import com.sap.piper.Utils
import org.junit.Before
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.TestExecutionListeners
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
@RunWith(SpringJUnit4ClassRunner)
@ContextConfiguration(classes = [BasePiperTestContext.class])
@TestExecutionListeners(listeners = [LibraryLoadingTestExecutionListener.class], mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
abstract class BasePiperTest extends BasePipelineTest {
@Autowired
MockHelper mockHelper
@Autowired
Script nullScript
@Autowired
Utils utils
@Override
@Before
void setUp() throws Exception {
helper = LibraryLoadingTestExecutionListener.singletonInstance
if(!isHelperInitialized()) {
super.setScriptRoots('.', 'vars')
super.setUp()
}
}
boolean isHelperInitialized() {
try {
helper.loadScript('dummy.groovy')
} catch (Exception e) {
if (e.getMessage().startsWith('GroovyScriptEngine is not initialized:'))
return false
}
return true
}
@Deprecated
void prepareObjectInterceptors(Object object) {
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(object)
}
}

View File

@ -0,0 +1,37 @@
#!groovy
package util
import com.sap.piper.Utils
import org.codehaus.groovy.runtime.InvokerHelper
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class BasePiperTestContext {
@Bean
Script nullScript() {
def nullScript = InvokerHelper.createScript(null, new Binding())
nullScript.currentBuild = [:]
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(nullScript)
return nullScript
}
@Bean
Utils mockUtils() {
def mockUtils = new Utils()
mockUtils.steps = [
stash : { m -> println "stash name = ${m.name}" },
unstash: { println "unstash called ..." }
]
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(mockUtils)
return mockUtils
}
@Bean
MockHelper mockHelper() {
return new MockHelper()
}
}

View File

@ -21,6 +21,11 @@ class JenkinsEnvironmentRule implements TestRule {
@Override @Override
void evaluate() throws Throwable { void evaluate() throws Throwable {
env = testInstance.loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment env = testInstance.loadScript('commonPipelineEnvironment.groovy').commonPipelineEnvironment
try {
testInstance?.nullScript.commonPipelineEnvironment = env
} catch (MissingPropertyException e) {
//kept for backward compatibility before all tests inherit from BasePiperTest
}
base.evaluate() base.evaluate()
} }
} }

View File

@ -0,0 +1,45 @@
package util
import com.lesfurets.jenkins.unit.BasePipelineTest
import groovy.json.JsonSlurper
import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement
class JenkinsReadJsonRule implements TestRule {
final BasePipelineTest testInstance
final String testRoot
JenkinsReadJsonRule(BasePipelineTest testInstance, testRoot = '') {
this.testInstance = testInstance
this.testRoot = testRoot
}
@Override
Statement apply(Statement base, Description description) {
return statement(base)
}
private Statement statement(final Statement base) {
return new Statement() {
@Override
void evaluate() throws Throwable {
testInstance.helper.registerAllowedMethod("readJSON", [Map], { Map m ->
if(m.text) {
def js = new JsonSlurper()
return js.parseText(m.text)
} else if(m.file) {
def js = new JsonSlurper()
def reader = new BufferedReader(new FileReader( "${this.testRoot}${m.file}" ))
return js.parse(reader)
} else {
throw new IllegalArgumentException("Key 'text' is missing in map ${m}.")
}
})
base.evaluate()
}
}
}
}

View File

@ -0,0 +1,253 @@
package util
import com.lesfurets.jenkins.unit.InterceptingGCL
import com.lesfurets.jenkins.unit.MethodSignature
import com.lesfurets.jenkins.unit.PipelineTestHelper
import org.codehaus.groovy.control.CompilerConfiguration
import org.springframework.test.context.TestContext
import org.springframework.test.context.support.AbstractTestExecutionListener
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener
import static com.lesfurets.jenkins.unit.MethodSignature.method
class LibraryLoadingTestExecutionListener extends AbstractTestExecutionListener {
static PipelineTestHelper singletonInstance
static CompilerConfiguration configuration
static GroovyClassLoader cLoader
static {
configuration = new CompilerConfiguration()
cLoader = new InterceptingGCL(singletonInstance, LibraryLoadingTestExecutionListener.class.getClassLoader(), configuration)
}
static List TRACKED_ON_CLASS = []
static List TRACKED_ON_METHODS = []
static HashMap RESTORE_ON_CLASS = [:]
static HashMap RESTORE_ON_METHODS = [:]
static boolean START_METHOD_TRACKING = false
static boolean START_CLASS_TRACKING = false
@Override
int getOrder() {
return 2500
}
static void setSingletonInstance(PipelineTestHelper helper) {
if(null != helper) {
helper.metaClass.invokeMethod = {
String name, Object[] args ->
if ((LibraryLoadingTestExecutionListener.START_METHOD_TRACKING || LibraryLoadingTestExecutionListener.START_CLASS_TRACKING)
&& name.equals("registerAllowedMethod")) {
List list
HashMap restore
if (LibraryLoadingTestExecutionListener.START_METHOD_TRACKING) {
list = LibraryLoadingTestExecutionListener.TRACKED_ON_METHODS
restore = LibraryLoadingTestExecutionListener.RESTORE_ON_METHODS
} else if (LibraryLoadingTestExecutionListener.START_CLASS_TRACKING) {
list = LibraryLoadingTestExecutionListener.TRACKED_ON_CLASS
restore = LibraryLoadingTestExecutionListener.RESTORE_ON_CLASS
}
Object methodName = args[0]
def key
if (args[1] instanceof List) {
List<Class> parameters = args[1]
key = method(methodName, parameters.toArray(new Class[parameters.size()]))
} else if (!(args[0] instanceof MethodSignature)) {
key = method(methodName, args[1])
}
if (null != key) {
list.add(key)
def existingValue = helper.removeAllowedMethodCallback(key)
if (!restore.containsKey(key)) {
restore.put(key, existingValue)
}
}
}
def m = delegate.metaClass.getMetaMethod(name, *args)
if( null != m)
return m.invoke(delegate, *args)
}
}
singletonInstance = helper
}
static PipelineTestHelper getSingletonInstance() {
if (singletonInstance == null) {
setSingletonInstance(new LibraryLoadingTestExecutionListener.PipelineTestHelperHook().helper)
}
return singletonInstance
}
@Override
void beforeTestClass(TestContext testContext) throws Exception {
super.beforeTestClass(testContext)
def helper = LibraryLoadingTestExecutionListener.getSingletonInstance()
registerDefaultAllowedMethods(helper)
LibraryLoadingTestExecutionListener.START_CLASS_TRACKING = true
}
@Override
void afterTestClass(TestContext testContext) throws Exception {
super.afterTestClass(testContext)
PipelineTestHelper helper = LibraryLoadingTestExecutionListener.getSingletonInstance()
helper.clearAllowedMethodCallbacks(LibraryLoadingTestExecutionListener.TRACKED_ON_CLASS)
LibraryLoadingTestExecutionListener.TRACKED_ON_CLASS.clear()
helper.putAllAllowedMethodCallbacks(LibraryLoadingTestExecutionListener.RESTORE_ON_CLASS)
LibraryLoadingTestExecutionListener.RESTORE_ON_CLASS.clear()
LibraryLoadingTestExecutionListener.START_CLASS_TRACKING = false
if (Boolean.TRUE.equals(testContext.getAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE))) {
LibraryLoadingTestExecutionListener.singletonInstance = null
PipelineTestHelper newHeiper = LibraryLoadingTestExecutionListener.getSingletonInstance()
def applicationContext = testContext.getApplicationContext()
def beanNames = applicationContext.getBeanDefinitionNames()
beanNames.each { name ->
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(applicationContext.getBean(name))
}
}
}
@Override
void beforeTestMethod(TestContext testContext) throws Exception {
super.beforeTestMethod(testContext)
def testInstance = testContext.getTestInstance()
testInstance.binding.setVariable('currentBuild', [result: 'SUCCESS'])
PipelineTestHelper helper = LibraryLoadingTestExecutionListener.getSingletonInstance()
LibraryLoadingTestExecutionListener.START_METHOD_TRACKING = true
}
@Override
void afterTestMethod(TestContext testContext) throws Exception {
super.afterTestMethod(testContext)
def testInstance = testContext.getTestInstance()
PipelineTestHelper helper = LibraryLoadingTestExecutionListener.getSingletonInstance()
helper.clearCallStack()
helper.clearAllowedMethodCallbacks(LibraryLoadingTestExecutionListener.TRACKED_ON_METHODS)
LibraryLoadingTestExecutionListener.TRACKED_ON_METHODS.clear()
LibraryLoadingTestExecutionListener.START_METHOD_TRACKING = false
testInstance.getNullScript().commonPipelineEnvironment.reset()
}
def registerDefaultAllowedMethods(helper) {
helper.registerAllowedMethod("stage", [String.class, Closure.class], null)
helper.registerAllowedMethod("stage", [String.class, Closure.class], null)
helper.registerAllowedMethod("node", [String.class, Closure.class], null)
helper.registerAllowedMethod("node", [Closure.class], null)
helper.registerAllowedMethod( method('sh', Map.class), {m ->
println "sh-command: $m.script"
return ""
} )
helper.registerAllowedMethod( method('sh', String.class), {s ->
println "sh-command: $s"
return ""
} )
helper.registerAllowedMethod("checkout", [Map.class], null)
helper.registerAllowedMethod("echo", [String.class], null)
helper.registerAllowedMethod("timeout", [Map.class, Closure.class], null)
helper.registerAllowedMethod("step", [Map.class], null)
helper.registerAllowedMethod("input", [String.class], null)
helper.registerAllowedMethod("gitlabCommitStatus", [String.class, Closure.class], { String name, Closure c ->
c.delegate = delegate
helper.callClosure(c)
})
helper.registerAllowedMethod("gitlabBuilds", [Map.class, Closure.class], null)
helper.registerAllowedMethod("logRotator", [Map.class], null)
helper.registerAllowedMethod("buildDiscarder", [Object.class], null)
helper.registerAllowedMethod("pipelineTriggers", [List.class], null)
helper.registerAllowedMethod("properties", [List.class], null)
helper.registerAllowedMethod("dir", [String.class, Closure.class], null)
helper.registerAllowedMethod("archiveArtifacts", [Map.class], null)
helper.registerAllowedMethod("junit", [String.class], null)
helper.registerAllowedMethod("readFile", [String.class], null)
helper.registerAllowedMethod("disableConcurrentBuilds", [], null)
helper.registerAllowedMethod("gatlingArchive", [], null)
helper.registerAllowedMethod("unstash", [String.class], null)
helper.registerAllowedMethod("unstash", [Object.class, String.class], null)
helper.registerAllowedMethod("stash", [Map.class], null)
helper.registerAllowedMethod("echo", [String.class], null)
}
static def prepareObjectInterceptors(Object object) {
object.metaClass.invokeMethod = LibraryLoadingTestExecutionListener.singletonInstance.getMethodInterceptor()
object.metaClass.static.invokeMethod = LibraryLoadingTestExecutionListener.singletonInstance.getMethodInterceptor()
object.metaClass.methodMissing = LibraryLoadingTestExecutionListener.singletonInstance.getMethodMissingInterceptor()
}
static class PipelineTestHelperHook {
def helper = new PipelineTestHelper() {
def clearAllowedMethodCallbacks(Collection c = []) {
List itemsToRemove = []
c.each {
key ->
allowedMethodCallbacks.entrySet().each {
entry ->
if (entry?.getKey().equals(key))
itemsToRemove.add(entry.getKey())
}
}
allowedMethodCallbacks.keySet().removeAll(itemsToRemove)
}
def removeAllowedMethodCallback(Object key) {
def itemToRemove
allowedMethodCallbacks.entrySet().each {
entry ->
if (entry?.getKey().equals(key)) {
itemToRemove = entry.getKey()
}
}
if (null != itemToRemove) {
def itemValue = allowedMethodCallbacks.remove(itemToRemove)
return itemValue
}
return null
}
def putAllAllowedMethodCallbacks(HashMap m) {
m.entrySet().each {
entry ->
if(null != entry.getValue())
allowedMethodCallbacks.put(entry.getKey(), entry.getValue())
else
allowedMethodCallbacks.remove(entry.getKey())
}
}
protected void setGlobalVars(Binding binding) {
libLoader.libRecords.values().stream()
.flatMap { it.definedGlobalVars.entrySet().stream() }
.forEach { e ->
if (e.value instanceof Script) {
Script script = Script.cast(e.value)
// invoke setBinding from method to avoid interception
SCRIPT_SET_BINDING.invoke(script, binding)
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(script)
script.metaClass.getMethods().findAll { it.name == 'call' }.forEach { m ->
LibraryLoadingTestExecutionListener.singletonInstance.registerAllowedMethod(method(e.value.class.name, m.getNativeParameterTypes()),
{ args ->
m.doMethodInvoke(e.value, args)
})
}
}
binding.setVariable(e.key, e.value)
}
}
}
}
}

View File

@ -13,8 +13,9 @@ public class Rules {
public static RuleChain getCommonRules(BasePipelineTest testCase, LibraryConfiguration libConfig) { public static RuleChain getCommonRules(BasePipelineTest testCase, LibraryConfiguration libConfig) {
return RuleChain.outerRule(new JenkinsSetupRule(testCase, libConfig)) return RuleChain.outerRule(new JenkinsSetupRule(testCase, libConfig))
.around(new JenkinsReadYamlRule(testCase)) .around(new JenkinsReadYamlRule(testCase))
.around(new JenkinsResetDefaultCacheRule()) .around(new JenkinsResetDefaultCacheRule())
.around(new JenkinsErrorRule(testCase)) .around(new JenkinsErrorRule(testCase))
.around(new JenkinsEnvironmentRule(testCase))
} }
} }

View File

@ -15,12 +15,28 @@ class commonPipelineEnvironment implements Serializable {
Map defaultConfiguration = [:] Map defaultConfiguration = [:]
//each Map in influxCustomDataMap represents a measurement in Influx. Additional measurements can be added as a new Map entry of influxCustomDataMap //each Map in influxCustomDataMap represents a measurement in Influx. Additional measurements can be added as a new Map entry of influxCustomDataMap
private Map influxCustomDataMap = [pipeline_data: [:]] private Map influxCustomDataMap = [pipeline_data: [:], step_data: [:]]
//influxCustomData represents measurement jenkins_custom_data in Influx. Metrics can be written into this map //influxCustomData represents measurement jenkins_custom_data in Influx. Metrics can be written into this map
private Map influxCustomData = [:] private Map influxCustomData = [:]
private String mtarFilePath private String mtarFilePath
def reset() {
appContainerProperties = [:]
artifactVersion = null
configProperties = [:]
configuration = [:]
gitCommitId = null
gitSshUrl = null
influxCustomData = [:]
influxCustomDataMap = [pipeline_data: [:], step_data: [:]]
mtarFilePath = null
}
def setAppContainerProperty(property, value) { def setAppContainerProperty(property, value) {
appContainerProperties[property] = value appContainerProperties[property] = value
} }

View File

@ -0,0 +1,7 @@
def call(Map parameters = [:], body) {
handlePipelineStepErrors (stepName: 'pipelineStashFiles', stepParameters: parameters) {
pipelineStashFilesBeforeBuild(parameters)
body() //execute build
pipelineStashFilesAfterBuild(parameters)
}
}

View File

@ -0,0 +1,51 @@
import com.sap.piper.Utils
import com.sap.piper.ConfigurationHelper
import groovy.transform.Field
@Field String STEP_NAME = 'pipelineStashFilesAfterBuild'
@Field Set STEP_CONFIG_KEYS = ['runCheckmarx', 'stashIncludes', 'stashExcludes']
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
def call(Map parameters = [:]) {
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters, stepNameDoc: 'stashFiles') {
def utils = parameters.juStabUtils
if (utils == null) {
utils = new Utils()
}
def script = parameters.script
if (script == null)
script = [commonPipelineEnvironment: commonPipelineEnvironment]
//additional includes via passing e.g. stashIncludes: [opa5: '**/*.include']
//additional excludes via passing e.g. stashExcludes: [opa5: '**/*.exclude']
Map config = ConfigurationHelper
.loadStepDefaults(this)
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
.mixin(parameters, PARAMETER_KEYS)
.addIfEmpty('runCheckmarx', (script.commonPipelineEnvironment.configuration?.steps?.executeCheckmarxScan?.checkmarxProject != null && script.commonPipelineEnvironment.configuration.steps.executeCheckmarxScan.checkmarxProject.length()>0))
.use()
// store files to be checked with checkmarx
if (config.runCheckmarx) {
utils.stash('checkmarx', config.stashIncludes?.get('checkmarx')?config.stashIncludes.checkmarx:'**/*.js, **/*.scala, **/*.py, **/*.go, **/*.xml, **/*.html', config.stashExcludes?.get('checkmarx')?config.stashExcludes.checkmarx:'**/*.mockserver.js, node_modules/**/*.js')
}
utils.stashWithMessage(
'classFiles',
'[${STEP_NAME}] Failed to stash class files.',
config.stashIncludes.classFiles,
config.stashExcludes.classFiles
)
utils.stashWithMessage(
'sonar',
'[${STEP_NAME}] Failed to stash sonar files.',
config.stashIncludes.sonar,
config.stashExcludes.sonar
)
}
}

View File

@ -0,0 +1,97 @@
import com.sap.piper.Utils
import com.sap.piper.ConfigurationHelper
import groovy.transform.Field
@Field String STEP_NAME = 'pipelineStashFilesBeforeBuild'
@Field Set STEP_CONFIG_KEYS = ['runOpaTests', 'stashIncludes', 'stashExcludes']
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
def call(Map parameters = [:]) {
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters, stepNameDoc: 'stashFiles') {
def utils = parameters.juStabUtils
if (utils == null) {
utils = new Utils()
}
def script = parameters.script
if (script == null)
script = [commonPipelineEnvironment: commonPipelineEnvironment]
//additional includes via passing e.g. stashIncludes: [opa5: '**/*.include']
//additional excludes via passing e.g. stashExcludes: [opa5: '**/*.exclude']
Map config = ConfigurationHelper
.loadStepDefaults(this)
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
.mixin(parameters, PARAMETER_KEYS)
.use()
if (config.runOpaTests){
utils.stash('opa5', config.stashIncludes?.get('opa5')?config.stashIncludes.opa5:'**/*.*', config.stashExcludes?.get('opa5')?config.stashExcludes.opa5:'')
}
//store git metadata for SourceClear agent
sh "mkdir -p gitmetadata"
sh "cp -rf .git/* gitmetadata"
sh "chmod -R u+w gitmetadata"
utils.stashWithMessage(
'git',
'[${STEP_NAME}] no git repo files detected: ',
config.stashIncludes.git,
config.stashExcludes.git
)
//store files required for tests, e.g. Gauge, SUT, ...
utils.stashWithMessage(
'tests',
'[${STEP_NAME}] no files for tests provided: ',
config.stashIncludes.tests,
config.stashExcludes.tests
)
//store build descriptor files depending on technology, e.g. pom.xml, package.json
utils.stash(
'buildDescriptor',
config.stashIncludes.buildDescriptor,
config.stashExcludes.buildDescriptor
)
//store deployment descriptor files depending on technology, e.g. *.mtaext.yml
utils.stashWithMessage(
'deployDescriptor',
'[${STEP_NAME}] no deployment descriptor files provided: ',
config.stashIncludes.deployDescriptor,
config.stashExcludes.deployDescriptor
)
//store nsp & retire exclusion file for future use
utils.stashWithMessage(
'opensource configuration',
'[${STEP_NAME}] no opensource configuration files provided: ',
config.stashIncludes.get('opensource configuration'),
config.stashExcludes.get('opensource configuration')
)
//store snyk config file for future use
utils.stashWithMessage(
'snyk configuration',
'[${STEP_NAME}] no snyk configuration files provided: ',
config.stashIncludes.get('snyk configuration'),
config.stashExcludes.get('snyk configuration')
)
//store pipeline configuration including additional groovy test scripts for future use
utils.stashWithMessage(
'pipelineConfigAndTests',
'[${STEP_NAME}] no pipeline configuration and test files found: ',
config.stashIncludes.pipelineConfigAndTests,
config.stashExcludes.pipelineConfigAndTests
)
utils.stashWithMessage(
'securityDescriptor',
'[${STEP_NAME}] no security descriptor found: ',
config.stashIncludes.securityDescriptor,
config.stashExcludes.securityDescriptor
)
}
}