1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-20 05:19:40 +02:00

Add step buildExecute (#527)

This step should serve as generic entry point in pipelines for building artifacts.

Build principle: build once.

Purpose of the step:
- build using a defined build technology
- store build result for future use in testing etc.
This commit is contained in:
Oliver Nocon 2019-07-02 13:00:36 +02:00 committed by GitHub
parent d84e81f88e
commit 5bb6d59753
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 969 additions and 0 deletions

View File

@ -0,0 +1,23 @@
# ${docGenStepName}
## ${docGenDescription}
## Prerequsites
When performing a Docker build you need to maintain the respective credentials in your Jenkins credentials store.<br />
Further details
* for builds when a Docker deamon: see step [containerPushToRegistry](containerPushToRegistry.md)
* for builds using Kaniko: see step [kanikoExecute](kanikoExecute.md)
## Example
```groovy
buildExecute script:this, buildTool: 'maven'
```
## ${docGenParameters}
## ${docGenConfiguration}
## ${docJenkinsPluginDependencies}

View File

@ -0,0 +1,44 @@
# ${docGenStepName}
## ${docGenDescription}
## Prerequisites
You need to have a valid user with write permissions in the target docker registry.
Credentials for the target docker registry have been configured in Jenkins with a dedicated Id.
You can create the credentials in your Jenkins<br />
via _Jenkins_ -> _Credentials_ -> _System_ -> _Global credentials (unrestricted)_ -> _Add Credentials_ ->
* Kind: _Username with Password_
* ID: specify id which you then use for the configuration of `dockerCredentialsId` (see below)
## Example
Usage of pipeline step:
**OPTION A:** To pull a Docker image from an existing docker registry and push to a different docker registry:
```groovy
containerPushToRegistry script: this,
dockerCredentialsId: 'myTargetRegistryCredentials',
sourceRegistryUrl: 'https://mysourceRegistry.url',
sourceImage: 'path/to/mySourceImageWith:tag',
dockerRegistryUrl: 'https://my.target.docker.registry:50000'
```
**OPTION B:** To push a locally build docker image into the target registry (only possible when a Docker deamon is available on your Jenkins node):
```groovy
containerPushToRegistry script: this,
dockerCredentialsId: 'myTargetRegistryCredentials',
dockerImage: 'path/to/myImageWith:tag',
dockerRegistryUrl: 'https://my.target.docker.registry:50000'
```
## ${docGenParameters}
## ${docGenConfiguration}
## ${docJenkinsPluginDependencies}

View File

@ -0,0 +1,57 @@
package com.sap.piper
class DockerUtils implements Serializable {
private static Script script
DockerUtils(Script script) {
this.script = script
}
public boolean withDockerDaemon() {
def returnCode = script.sh script: 'docker ps -q > /dev/null', returnStatus: true
return (returnCode == 0)
}
public boolean onKubernetes() {
return (Boolean.valueOf(script.env.ON_K8S))
}
public String getRegistryFromUrl(dockerRegistryUrl) {
URL url = new URL(dockerRegistryUrl)
return "${url.getHost()}${(url.getPort() != -1) ? ':' + url.getPort() : ''}"
}
public String getProtocolFromUrl(dockerRegistryUrl) {
URL url = new URL(dockerRegistryUrl)
return url.getProtocol()
//return dockerRegistryUrl.split(/:\/\//)[0]
}
public void moveImage(Map source, Map target) {
//expects source/target in the format [image: '', registryUrl: '', credentialsId: '']
def sourceDockerRegistry = source.registryUrl ? "${getRegistryFromUrl(source.registryUrl)}/" : ''
def sourceImageFullName = sourceDockerRegistry + source.image
def targetDockerRegistry = target.registryUrl ? "${getRegistryFromUrl(target.registryUrl)}/" : ''
def targetImageFullName = targetDockerRegistry + target.image
if (!withDockerDaemon()) {
script.withCredentials([script.usernamePassword(
credentialsId: target.credentialsId,
passwordVariable: 'password',
usernameVariable: 'userid'
)]) {
skopeoMoveImage(sourceImageFullName, targetImageFullName, script.userid, script.password)
}
}
//else not yet implemented here - available directly via containerPushToRegistry
}
private void skopeoMoveImage(sourceImageFullName, targetImageFullName, targetUserId, targetPassword) {
script.sh "skopeo copy --src-tls-verify=false --dest-tls-verify=false --dest-creds=${BashUtils.quoteAndEscape(targetUserId)}:${BashUtils.quoteAndEscape(targetPassword)} docker://${sourceImageFullName} docker://${targetImageFullName}"
}
}

View File

@ -0,0 +1,230 @@
#!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.BasePiperTest
import util.JenkinsDockerExecuteRule
import util.JenkinsReadYamlRule
import util.JenkinsShellCallRule
import util.JenkinsStepRule
import util.Rules
import static org.hamcrest.CoreMatchers.containsString
import static org.hamcrest.CoreMatchers.hasItem
import static org.hamcrest.CoreMatchers.is
import static org.hamcrest.CoreMatchers.nullValue
import static org.junit.Assert.assertThat
class BuildExecuteTest extends BasePiperTest {
private ExpectedException exception = ExpectedException.none()
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
private JenkinsDockerExecuteRule dockerRule = new JenkinsDockerExecuteRule(this)
private JenkinsShellCallRule shellCallRule = new JenkinsShellCallRule(this)
@Rule
public RuleChain rules = Rules
.getCommonRules(this)
.around(new JenkinsReadYamlRule(this))
.around(exception)
.around(shellCallRule)
.around(dockerRule)
.around(stepRule)
def dockerMockArgs = [:]
class DockerMock {
DockerMock(name){
dockerMockArgs.name = name
}
def build(image, options) {
return [image: image, options: options]
}
}
@Before
void init() {
}
@Test
void testDefaultError() {
exception.expectMessage(containsString('buildTool not set and no dockerImage & dockerCommand provided'))
stepRule.step.buildExecute(
script: nullScript,
)
}
@Test
void testDefaultWithDockerImage() {
stepRule.step.buildExecute(
script: nullScript,
dockerImage: 'path/to/myImage:tag',
dockerCommand: 'myTestCommand'
)
assertThat(dockerRule.dockerParams.dockerImage, is('path/to/myImage:tag'))
assertThat(shellCallRule.shell, hasItem('myTestCommand'))
}
@Test
void testMaven() {
def buildToolCalled = false
helper.registerAllowedMethod('mavenExecute', [Map.class], {m ->
buildToolCalled = true
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'maven',
)
assertThat(buildToolCalled, is(true))
}
@Test
void testMta() {
def buildToolCalled = false
helper.registerAllowedMethod('mtaBuild', [Map.class], {m ->
buildToolCalled = true
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'mta',
)
assertThat(buildToolCalled, is(true))
}
@Test
void testNpm() {
def buildToolCalled = false
helper.registerAllowedMethod('npmExecute', [Map.class], {m ->
buildToolCalled = true
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'npm',
)
assertThat(buildToolCalled, is(true))
}
@Test
void testDocker() {
binding.setVariable('docker', new DockerMock('test'))
def pushParams= [:]
helper.registerAllowedMethod('containerPushToRegistry', [Map.class], {m ->
pushParams = m
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'docker',
dockerImageName: 'path/to/myImage',
dockerImageTag: 'myTag',
dockerRegistryUrl: 'https://my.registry:55555'
)
assertThat(pushParams.dockerBuildImage.image.toString(), is('path/to/myImage:myTag'))
assertThat(pushParams.dockerRegistryUrl.toString(), is('https://my.registry:55555'))
assertThat(nullScript.commonPipelineEnvironment.getValue('containerImage').toString(), is('path/to/myImage:myTag'))
}
@Test
void testDockerWithEnv() {
nullScript.commonPipelineEnvironment.setArtifactVersion('1.0.0')
binding.setVariable('docker', new DockerMock('test'))
def pushParams= [:]
helper.registerAllowedMethod('containerPushToRegistry', [Map.class], {m ->
pushParams = m
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'docker',
dockerImageName: 'path/to/myImage',
dockerRegistryUrl: 'https://my.registry:55555'
)
assertThat(pushParams.dockerBuildImage.image.toString(), is('path/to/myImage:1.0.0'))
assertThat(pushParams.dockerRegistryUrl.toString(), is('https://my.registry:55555'))
assertThat(nullScript.commonPipelineEnvironment.getValue('containerImage').toString(), is('path/to/myImage:1.0.0'))
}
@Test
void testDockerNoPush() {
binding.setVariable('docker', new DockerMock('test'))
def pushParams= [:]
helper.registerAllowedMethod('containerPushToRegistry', [Map.class], {m ->
pushParams = m
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'docker',
dockerImageName: 'path/to/myImage',
dockerImageTag: 'myTag',
dockerRegistryUrl: ''
)
assertThat(pushParams.dockerBuildImage, nullValue())
assertThat(pushParams.dockerRegistryUrl, nullValue())
}
@Test
void testKaniko() {
def kanikoParams = [:]
helper.registerAllowedMethod('kanikoExecute', [Map.class], {m ->
kanikoParams = m
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'kaniko',
dockerImageName: 'path/to/myImage',
dockerImageTag: 'myTag',
dockerRegistryUrl: 'https://my.registry:55555'
)
assertThat(kanikoParams.containerImageNameAndTag.toString(), is('my.registry:55555/path/to/myImage:myTag'))
}
@Test
void testKanikoNoPush() {
def kanikoParams = [:]
helper.registerAllowedMethod('kanikoExecute', [Map.class], {m ->
kanikoParams = m
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'kaniko',
dockerImageName: 'path/to/myImage',
dockerImageTag: 'myTag',
dockerRegistryUrl: ''
)
assertThat(kanikoParams.containerImageNameAndTag, is(''))
}
@Test
void testSwitchToKaniko() {
shellCallRule.setReturnValue('docker ps -q > /dev/null', 1)
def kanikoParams = [:]
helper.registerAllowedMethod('kanikoExecute', [Map.class], {m ->
kanikoParams = m
return
})
stepRule.step.buildExecute(
script: nullScript,
buildTool: 'kaniko',
dockerImageName: 'path/to/myImage',
dockerImageTag: 'myTag',
dockerRegistryUrl: 'https://my.registry:55555'
)
assertThat(kanikoParams.containerImageNameAndTag.toString(), is('my.registry:55555/path/to/myImage:myTag'))
}
}

View File

@ -1,3 +1,4 @@
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -43,6 +44,11 @@ class ContainerExecuteStructureTestsTest extends BasePiperTest {
})
}
@After
void cleanup() {
nullScript.env = [ON_K8S: null]
}
@Test
void testExecuteContainterStructureTestsDefault() throws Exception {
helper.registerAllowedMethod('readFile', [String.class], {s ->

View File

@ -0,0 +1,264 @@
#!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.BasePiperTest
import util.JenkinsCredentialsRule
import util.JenkinsDockerExecuteRule
import util.JenkinsReadYamlRule
import util.JenkinsShellCallRule
import util.JenkinsStepRule
import util.Rules
import static org.hamcrest.CoreMatchers.containsString
import static org.hamcrest.CoreMatchers.hasItem
import static org.hamcrest.CoreMatchers.is
import static org.hamcrest.CoreMatchers.not
import static org.junit.Assert.assertThat
class ContainerPushToRegistryTest extends BasePiperTest {
private ExpectedException exception = ExpectedException.none()
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
private JenkinsDockerExecuteRule dockerRule = new JenkinsDockerExecuteRule(this)
private JenkinsShellCallRule shellCallRule = new JenkinsShellCallRule(this)
@Rule
public RuleChain rules = Rules
.getCommonRules(this)
.around(new JenkinsReadYamlRule(this))
.around(exception)
.around(shellCallRule)
.around(dockerRule)
.around(new JenkinsCredentialsRule(this)
.withCredentials('testCredentialsId', 'registryUser', '********')
)
.around(stepRule)
def dockerMockArgs = [:]
class DockerMock {
DockerMock(name){
dockerMockArgs.name = name
}
def withRegistry(paramRegistry, paramCredentials, paramClosure){
dockerMockArgs.paramRegistry = paramRegistry
dockerMockArgs.paramCredentials = paramCredentials
return paramClosure()
}
def withRegistry(paramRegistry, paramClosure){
dockerMockArgs.paramRegistryAnonymous = paramRegistry.toString()
return paramClosure()
}
def image(name) {
dockerMockArgs.name = name
return new ContainerImageMock()
}
}
def dockerMockPushes = []
def dockerMockPull = false
class ContainerImageMock {
ContainerImageMock(){}
def push(tag){
dockerMockPushes.add(tag)
}
def push(){
push('default')
}
def pull(){
dockerMockPull = true
}
}
@Before
void init() {
binding.setVariable('docker', new DockerMock('test'))
}
@Test
void testNoImageProvided() {
exception.expectMessage(containsString('Please provide a dockerImage'))
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerRegistryUrl: 'https://testRegistry',
dockerCredentialsId: 'testCredentialsId',
)
}
@Test
void testDefault() {
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerRegistryUrl: 'https://testRegistry',
dockerCredentialsId: 'testCredentialsId',
dockerImage: 'testImage:tag',
)
assertThat(dockerMockArgs.paramRegistry, is('https://testRegistry'))
assertThat(dockerMockArgs.paramCredentials, is('testCredentialsId'))
assertThat(dockerMockArgs.name, is('testImage:tag'))
assertThat(dockerMockPushes, hasItem('default'))
assertThat(dockerMockPushes, not(hasItem('latest')))
}
@Test
void testBuildImagePushLatest() {
def dockerBuildImage = new ContainerImageMock()
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerRegistryUrl: 'https://testRegistry',
dockerCredentialsId: 'testCredentialsId',
dockerBuildImage: dockerBuildImage,
tagLatest: true
)
assertThat(dockerMockArgs.paramRegistry, is('https://testRegistry'))
assertThat(dockerMockArgs.paramCredentials, is('testCredentialsId'))
assertThat(dockerMockArgs.paramRegistryAnonymous, is(null))
assertThat(dockerMockArgs.name, is('test'))
assertThat(dockerMockPushes, hasItem('default'))
assertThat(dockerMockPushes, hasItem('latest'))
}
@Test
void testFromEnv() {
nullScript.commonPipelineEnvironment.setValue('containerImage', 'path/testImage:tag')
nullScript.commonPipelineEnvironment.setValue('containerRegistryUrl', 'https://testRegistry:55555')
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerRegistryUrl: 'https://testRegistry',
dockerCredentialsId: 'testCredentialsId',
)
assertThat(dockerMockArgs.paramRegistryAnonymous, is('https://testRegistry:55555'))
assertThat(dockerMockArgs.name, is('path/testImage:tag'))
assertThat(shellCallRule.shell, hasItem('docker tag testRegistry:55555/path/testImage:tag path/testImage:tag'))
assertThat(dockerMockPull, is(true))
}
@Test
void testWithSourceImageAndRegistry() {
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerCredentialsId: 'testCredentialsId',
dockerRegistryUrl: 'https://testRegistry',
sourceImage: 'testSourceName:testSourceTag',
sourceRegistryUrl: 'http://testSourceRegistry'
)
assertThat(dockerMockArgs.paramRegistryAnonymous, is('http://testSourceRegistry'))
assertThat(dockerMockArgs.name, is('testSourceName:testSourceTag'))
assertThat(shellCallRule.shell, hasItem('docker tag testSourceRegistry/testSourceName:testSourceTag testSourceName:testSourceTag'))
assertThat(dockerMockPull, is(true))
}
@Test
void testWithSourceAndTarget() {
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerCredentialsId: 'testCredentialsId',
dockerImage: 'testImage:tag',
dockerRegistryUrl: 'https://testRegistry',
sourceImage: 'testSourceName:testSourceTag',
sourceRegistryUrl: 'http://testSourceRegistry'
)
assertThat(dockerMockArgs.paramRegistryAnonymous, is('http://testSourceRegistry'))
assertThat(dockerMockArgs.name, is('testSourceName:testSourceTag'))
assertThat(shellCallRule.shell, hasItem('docker tag testSourceRegistry/testSourceName:testSourceTag testImage:tag'))
assertThat(dockerMockPull, is(true))
}
@Test
void testKubernetesMove() {
binding.setVariable('docker', null)
shellCallRule.setReturnValue('docker ps -q > /dev/null', 1)
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerCredentialsId: 'testCredentialsId',
dockerImage: 'testImage:tag',
dockerRegistryUrl: 'https://my.registry:55555',
skopeoImage: 'skopeo:latest',
sourceImage: 'sourceImage:sourceTag',
sourceRegistryUrl: 'https://my.source.registry:44444'
)
assertThat(shellCallRule.shell, hasItem('skopeo copy --src-tls-verify=false --dest-tls-verify=false --dest-creds=\'registryUser\':\'********\' docker://my.source.registry:44444/sourceImage:sourceTag docker://my.registry:55555/testImage:tag'))
assertThat(dockerRule.dockerParams.dockerImage, is('skopeo:latest'))
}
@Test
void testKubernetesMoveTagLatest() {
binding.setVariable('docker', null)
shellCallRule.setReturnValue('docker ps -q > /dev/null', 1)
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerCredentialsId: 'testCredentialsId',
dockerImage: 'testImage:tag',
dockerRegistryUrl: 'https://my.registry:55555',
sourceImage: 'sourceImage:sourceTag',
sourceRegistryUrl: 'https://my.source.registry:44444',
tagLatest: true
)
assertThat(shellCallRule.shell, hasItem('skopeo copy --src-tls-verify=false --dest-tls-verify=false --dest-creds=\'registryUser\':\'********\' docker://my.source.registry:44444/sourceImage:sourceTag docker://my.registry:55555/testImage:tag'))
assertThat(shellCallRule.shell, hasItem('skopeo copy --src-tls-verify=false --dest-tls-verify=false --dest-creds=\'registryUser\':\'********\' docker://my.source.registry:44444/sourceImage:sourceTag docker://my.registry:55555/testImage:latest'))
}
@Test
void testKubernetesSourceOnly() {
binding.setVariable('docker', null)
shellCallRule.setReturnValue('docker ps -q > /dev/null', 1)
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerCredentialsId: 'testCredentialsId',
dockerRegistryUrl: 'https://my.registry:55555',
sourceImage: 'sourceImage:sourceTag',
sourceRegistryUrl: 'https://my.source.registry:44444'
)
assertThat(shellCallRule.shell, hasItem('skopeo copy --src-tls-verify=false --dest-tls-verify=false --dest-creds=\'registryUser\':\'********\' docker://my.source.registry:44444/sourceImage:sourceTag docker://my.registry:55555/sourceImage:sourceTag'))
}
@Test
void testKubernetesSourceRegistryFromEnv() {
binding.setVariable('docker', null)
shellCallRule.setReturnValue('docker ps -q > /dev/null', 1)
nullScript.commonPipelineEnvironment.setValue('containerImage', 'sourceImage:sourceTag')
nullScript.commonPipelineEnvironment.setValue('containerRegistryUrl', 'https://my.source.registry:44444')
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerCredentialsId: 'testCredentialsId',
dockerRegistryUrl: 'https://my.registry:55555',
sourceImage: 'sourceImage:sourceTag',
)
assertThat(shellCallRule.shell, hasItem('skopeo copy --src-tls-verify=false --dest-tls-verify=false --dest-creds=\'registryUser\':\'********\' docker://my.source.registry:44444/sourceImage:sourceTag docker://my.registry:55555/sourceImage:sourceTag'))
}
@Test
void testKubernetesPushTar() {
binding.setVariable('docker', null)
shellCallRule.setReturnValue('docker ps -q > /dev/null', 1)
exception.expectMessage('Only moving images')
stepRule.step.containerPushToRegistry(
script: nullScript,
dockerCredentialsId: 'testCredentialsId',
dockerArchive: 'myImage.tar',
dockerImage: 'testImage:tag',
dockerRegistryUrl: 'https://my.registry:55555',
)
}
}

View File

@ -0,0 +1,97 @@
package com.sap.piper
import hudson.AbortException
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import org.junit.rules.RuleChain
import util.BasePiperTest
import util.JenkinsCredentialsRule
import util.JenkinsShellCallRule
import util.Rules
import static org.hamcrest.CoreMatchers.hasItem
import static org.hamcrest.CoreMatchers.is
import static org.junit.Assert.assertThat
class DockerUtilsTest extends BasePiperTest {
public ExpectedException exception = ExpectedException.none()
public JenkinsShellCallRule shellCallRule = new JenkinsShellCallRule(this)
def dockerMockArgs = [:]
class DockerMock {
def withRegistry(paramRegistry, paramClosure){
dockerMockArgs.paramRegistryAnonymous = paramRegistry.toString()
return paramClosure()
}
}
@Rule
public RuleChain ruleChain = Rules.getCommonRules(this)
.around(shellCallRule)
.around(exception)
.around(new JenkinsCredentialsRule(this)
.withCredentials('testCredentialsId', 'registryUser', '********')
)
@Before
void init() {
nullScript.binding.setVariable('docker', new DockerMock())
}
@Test
void testWithDockerDaemon() {
DockerUtils dockerUtils = new DockerUtils(nullScript)
assertThat(dockerUtils.withDockerDaemon(), is(true))
}
@Test
void testWithoutDockerDaemon() {
shellCallRule.setReturnValue('docker ps -q > /dev/null', 1)
DockerUtils dockerUtils = new DockerUtils(nullScript)
assertThat(dockerUtils.withDockerDaemon(), is(false))
}
@Test
void testOnKubernetes() {
nullScript.env.ON_K8S = 'true'
DockerUtils dockerUtils = new DockerUtils(nullScript)
assertThat(dockerUtils.onKubernetes(), is(true))
}
@Test
void testMoveImageKubernetes() {
shellCallRule.setReturnValue('docker ps -q > /dev/null', 1)
DockerUtils dockerUtils = new DockerUtils(nullScript)
dockerUtils.moveImage(
[
registryUrl: 'https://my.source.registry:44444',
image: 'sourceImage:sourceTag'
],
[
registryUrl: 'https://my.registry:55555',
image: 'testImage:tag',
credentialsId: 'testCredentialsId'
]
)
assertThat(shellCallRule.shell, hasItem('skopeo copy --src-tls-verify=false --dest-tls-verify=false --dest-creds=\'registryUser\':\'********\' docker://my.source.registry:44444/sourceImage:sourceTag docker://my.registry:55555/testImage:tag'))
}
@Test
void testGetRegistryFromUrl() {
DockerUtils dockerUtils = new DockerUtils(nullScript)
assertThat(dockerUtils.getRegistryFromUrl('https://my.registry.com:55555'), is('my.registry.com:55555'))
assertThat(dockerUtils.getRegistryFromUrl('http://my.registry.com:55555'), is('my.registry.com:55555'))
assertThat(dockerUtils.getRegistryFromUrl('https://my.registry.com'), is('my.registry.com'))
}
@Test
void testGetProtocolFromUrl() {
DockerUtils dockerUtils = new DockerUtils(nullScript)
assertThat(dockerUtils.getProtocolFromUrl('https://my.registry.com:55555'), is('https'))
assertThat(dockerUtils.getProtocolFromUrl('http://my.registry.com:55555'), is('http'))
}
}

117
vars/buildExecute.groovy Normal file
View File

@ -0,0 +1,117 @@
import com.sap.piper.DockerUtils
import com.sap.piper.GenerateDocumentation
import com.sap.piper.Utils
import com.sap.piper.ConfigurationHelper
import groovy.text.SimpleTemplateEngine
import groovy.transform.Field
import static com.sap.piper.Prerequisites.checkScript
@Field String STEP_NAME = getClass().getName()
@Field Set GENERAL_CONFIG_KEYS = [
/**
* Defines the tool used for the build.
* @possibleValues `docker`, `kaniko`, `maven`, `mta`, `npm`
*/
'buildTool',
/** For Docker builds only (mandatory): name of the image to be built. */
'dockerImageName',
/** For Docker builds only: Defines the registry url where the image should be pushed to, incl. the protocol like `https://my.registry.com`. If it is not defined, image will not be pushed to a registry.*/
'dockerRegistryUrl',
]
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
/** Only for Docker builds on the local deamon: Defines the build options for the build.*/
'containerBuildOptions',
/** For custom build types: Defines the command to be executed within the `dockerImage` in order to execute the build. */
'dockerCommand',
/** For custom build types: Image to be used for builds in case they should run inside a custom Docker container */
'dockerImage',
/** For Docker builds only (mandatory): tag of the image to be built. */
'dockerImageTag',
])
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
/**
* This step serves as generic entry point in pipelines for building artifacts.
*
* You can use pre-defined `buildTool`s.
*
* Alternatively you can define a command via `dockerCommand` which should be executed in `dockerImage`.<br />
* This allows you to trigger any build tool using a defined Docker container which provides the required build infrastructure.
*
* When using `buildTool: docker` or `buildTool: kaniko` the created container image is uploaded to a container registry.<br />
* You need to make sure that the required credentials are provided to the step.
*
* For all other `buildTool`s the artifact will just be stored in the workspace and could then be `stash`ed for later use.
*
*/
@GenerateDocumentation
void call(Map parameters = [:]) {
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
final script = checkScript(this, parameters) ?: this
def utils = parameters.juStabUtils ?: new Utils()
// handle deprecated parameters
// 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('dockerImageTag', script.commonPipelineEnvironment.getArtifactVersion())
.use()
// telemetry reporting
utils.pushToSWA([stepParam1: config.buildTool, 'buildTool': config.buildTool], config)
switch(config.buildTool){
case 'maven':
mavenExecute script: script
break
case 'mta':
mtaBuild script: script
break
case 'npm':
npmExecute script: script
break
case ['docker', 'kaniko']:
DockerUtils dockerUtils = new DockerUtils(script)
if (config.buildTool == 'docker' && !dockerUtils.withDockerDaemon()) {
config.buildTool = 'kaniko'
echo "[${STEP_NAME}] No Docker daemon available, thus switching to Kaniko build"
}
ConfigurationHelper.newInstance(this, config)
.withMandatoryProperty('dockerImageName')
.withMandatoryProperty('dockerImageTag')
def dockerImageNameAndTag = "${config.dockerImageName}:${config.dockerImageTag}"
if (config.buildTool == 'kaniko') {
def containerImageNameAndTag = config.dockerRegistryUrl ? "${dockerUtils.getRegistryFromUrl(config.dockerRegistryUrl)}/${dockerImageNameAndTag}" : ''
kanikoExecute script: script, containerImageNameAndTag: containerImageNameAndTag
} else {
def dockerBuildImage = docker.build(dockerImageNameAndTag, "${config.containerBuildOptions} .")
//only push if registry is defined
if (config.dockerRegistryUrl) {
containerPushToRegistry script: this, dockerBuildImage: dockerBuildImage, dockerRegistryUrl: config.dockerRegistryUrl
}
}
script.commonPipelineEnvironment.setValue('containerImage', dockerImageNameAndTag)
break
default:
if (config.dockerImage && config.dockerCommand) {
dockerExecute(
script: script,
dockerImage: config.dockerImage,
) {
sh "${config.dockerCommand}"
}
} else {
error "[${STEP_NAME}] buildTool not set and no dockerImage & dockerCommand provided."
}
}
}
}

View File

@ -0,0 +1,130 @@
import com.sap.piper.GenerateDocumentation
import com.sap.piper.Utils
import com.sap.piper.ConfigurationHelper
import com.sap.piper.DockerUtils
import groovy.transform.Field
import static com.sap.piper.Prerequisites.checkScript
@Field String STEP_NAME = getClass().getName()
@Field Set GENERAL_CONFIG_KEYS = [
/**
* Defines the id of the Jenkins username/password credentials containing the credentials for the target Docker registry.
*/
'dockerCredentialsId',
/** Defines the registry url where the image should be pushed to, incl. the protocol like `https://my.registry.com`*/
'dockerRegistryUrl',
]
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
/** Not supported yet - Docker archive to be pushed to registry*/
'dockerArchive',
/** For images built locally on the Docker Deamon, reference to the image object resulting from `docker.build` execution */
'dockerBuildImage',
/** Defines the name (incl. tag) of the target image*/
'dockerImage',
/**
* Only if no Docker daemon available on your Jenkins image: Docker image to be used for [Skopeo](https://github.com/containers/skopeo) calls
* Unfortunately no proper image known to be available.
* Simple custom Dockerfile could look as follows: <br>
* ```
* FROM fedora:29
* RUN dnf install -y skopeo
* ```
*/
'skopeoImage',
/** Defines the name (incl. tag) of the source image to be pushed to a new image defined in `dockerImage`.<br>
* This is helpful for moving images from one location to another.
*/
'sourceImage',
/** Defines a registry url from where the image should optionally be pulled from, incl. the protocol like `https://my.registry.com`*/
'sourceRegistryUrl',
/** Defines if the image should be tagged as `latest`*/
'tagLatest'
])
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
/**
* This step allows you to push a Docker image into a dedicated Container registry.
*
* By default an image available via the local Docker daemon will be pushed.
*
* In case you want to pull an existing image from a remote container registry, a source image and source registry needs to be specified.<br />
* This makes it possible to move an image from one registry to another.
*/
@GenerateDocumentation
void call(Map parameters = [:]) {
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
final script = checkScript(this, parameters) ?: this
// load default & individual configuration
Map config = ConfigurationHelper.newInstance(this)
.loadStepDefaults()
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
.mixin(parameters, PARAMETER_KEYS)
.addIfEmpty('sourceImage', script.commonPipelineEnvironment.getValue('containerImage'))
.addIfEmpty('sourceRegistryUrl', script.commonPipelineEnvironment.getValue('containerRegistryUrl'))
.withMandatoryProperty('dockerCredentialsId')
.withMandatoryProperty('dockerRegistryUrl')
.use()
DockerUtils dockerUtils = new DockerUtils(script)
if (config.sourceRegistryUrl) {
config.sourceRegistry = dockerUtils.getRegistryFromUrl(config.sourceRegistryUrl)
}
// telemetry reporting
new Utils().pushToSWA([
step: STEP_NAME
], config)
if (!config.dockerImage)
config.dockerImage = config.sourceImage
if (dockerUtils.withDockerDaemon()) {
//Prevent NullPointerException in case no dockerImage nor dockerBuildImage is provided
if (!config.dockerImage && !config.dockerBuildImage) {
error "[${STEP_NAME}] Please provide a dockerImage (either in your config.yml or via step parameter)."
}
config.dockerBuildImage = config.dockerBuildImage?:docker.image(config.dockerImage)
if (config.sourceRegistry && config.sourceImage) {
def sourceBuildImage = docker.image(config.sourceImage)
docker.withRegistry(config.sourceRegistryUrl) {
sourceBuildImage.pull()
}
sh "docker tag ${config.sourceRegistry}/${config.sourceImage} ${config.dockerImage}"
}
docker.withRegistry(
config.dockerRegistryUrl,
config.dockerCredentialsId
) {
config.dockerBuildImage.push()
if (config.tagLatest)
config.dockerBuildImage.push('latest')
}
} else {
//handling for Kubernetes case
dockerExecute(
script: script,
dockerImage: config.skopeoImage
) {
if (!config.dockerArchive && !config.dockerBuildImage) {
dockerUtils.moveImage([image: config.sourceImage, registryUrl: config.sourceRegistryUrl], [image: config.dockerImage, registryUrl: config.dockerRegistryUrl, credentialsId: config.dockerCredentialsId])
if (config.tagLatest) {
def latestImage = "${config.dockerImage.split(':')[0]}:latest"
dockerUtils.moveImage([image: config.sourceImage, registryUrl: config.sourceRegistryUrl], [image: latestImage, registryUrl: config.dockerRegistryUrl, credentialsId: config.dockerCredentialsId])
}
} else {
error "[${STEP_NAME}] Running on Kubernetes: Only moving images from one registry to another supported."
}
}
}
}
}

View File

@ -67,6 +67,7 @@ void call(Map parameters = [:]) {
.mixin(parameters, PARAMETER_KEYS)
.use()
// telemetry reporting
new Utils().pushToSWA([
step: STEP_NAME
], config)