Skip to content

Commit

Permalink
Merge pull request #147 from halkeye/buildDockerImage
Browse files Browse the repository at this point in the history
buildDockerImage()
  • Loading branch information
oleg-nenashev authored May 26, 2020
2 parents 0c78670 + b2e941d commit c88ea13
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 10 deletions.
19 changes: 19 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,25 @@ Supported parameters:
runBenchmarks('jmh-report.json')
----

=== buildDockerImage

Builds a standard docker image and on master/tags pushes it to dockerhub

Supported parameters:

`imageName`::
Name of the docker image to build

`configs`::
(Optional) extra flags such as override the default registry of jenkinsciinfra or jenkins4eval


===== Example
[source, groovy]
----
buildDockerImage('plugins-site-api')
----

=== Design documents for runATH and runPCT

The design and some more details about the runATH and runPCT steps can be found link:https://wiki.jenkins.io/display/JENKINS/runATH+and+runPCT+step+design[here]
9 changes: 8 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
</license>
</licenses>

<repositories>
<repository>
<id>jenkins-ci-releases</id>
<url>https://repo.jenkins-ci.org/releases/</url>
</repository>
</repositories>

<scm>
<connection>scm:git:git://github.com/jenkins-infra/pipeline-library.git</connection>
<developerConnection>scm:git:ssh://git@github.com/jenkins-infra/pipeline-library.git</developerConnection>
Expand All @@ -27,7 +34,7 @@
<!-- Dependency versions -->
<groovy.version>2.4.17</groovy.version>
<junit.version>4.12</junit.version>
<jenkins-pipeline-unit.version>1.1</jenkins-pipeline-unit.version>
<jenkins-pipeline-unit.version>1.4</jenkins-pipeline-unit.version>
<groovy-eclipse-compiler.version>3.4.0-01</groovy-eclipse-compiler.version>
</properties>

Expand Down
64 changes: 64 additions & 0 deletions test/groovy/BuildDockerImageTests.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import com.lesfurets.jenkins.unit.declarative.DeclarativePipelineTest
import mock.CurrentBuild
import mock.Infra
import org.junit.Before
import org.junit.Test
import org.junit.Ignore
import static com.lesfurets.jenkins.unit.MethodCall.callArgsToString
import static org.junit.Assert.assertTrue
import static org.junit.Assert.assertFalse
import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertNotNull

class BuildDockerImageTests extends DeclarativePipelineTest {
static final String scriptName = "vars/buildDockerImage.groovy"
Map env = [:]

@Override
@Before
void setUp() throws Exception {
super.setUp()

binding.setVariable('env', env)
binding.setProperty('scm', new String())
binding.setProperty('mvnSettingsFile', 'settings.xml')
binding.setProperty('infra', new Infra())

helper.registerAllowedMethod('ansiColor', [String.class], { s -> s })

helper.registerAllowedMethod('sh', [Map], {m->
if (m.returnStdout) {
cmd = m.script
// cmd.contains is helpful to filter sh call which should fail the pipeline
if (cmd.contains("git log -n 1 --pretty=format:'%h'")) {
return 'abc123'
}
if (cmd.contains('git remote show origin')) {
return 'git@github.com:jenkins-infra/pipeline-library.git'
}
if (cmd.contains('date --rfc-3339=seconds')) {
return '2020-05-25T07:11:16+00:00'
}
}
})
}

@Test
@Ignore("until https://github.com/jenkinsci/JenkinsPipelineUnit/pull/220 is merged and released")
void testCallsDockerBuild() throws Exception {
helper.registerAllowedMethod("buildingTag", [], { false })

def script = loadScript(scriptName)
script("jenkins-wiki-exporter")

def calls = helper.callStack.findAll { call ->
call.methodName == 'sh'
}.findAll { call ->
callArgsToString(call).contains('docker build')
}.collect { call ->
callArgsToString(call).replaceAll(/\s+/, ' ').trim()
}
//printCallStack()
assertEquals(calls, ['docker build -t jenkins4eval/jenkins-wiki-exporter --build-arg "GIT_COMMIT_REV=abc123" --build-arg "GIT_SCM_URL=git@github.com:jenkins-infra/pipeline-library.git" --build-arg "BUILD_DATE=2020-05-25T07:11:16+00:00" --label "org.opencontainers.image.source=git@github.com:jenkins-infra/pipeline-library.git" --label "org.label-schema.vcs-url=git@github.com:jenkins-infra/pipeline-library.git" --label "org.opencontainers.image.url==https://github.com/jenkins-infra/pipeline-library.git" --label "org.label-schema.url=https://github.com/jenkins-infra/pipeline-library.git" --label "org.opencontainers.image.revision=abc123" --label "org.label-schema.vcs-ref=abc123" --label "org.opencontainers.created=2020-05-25T07:11:16+00:00" --label "org.label-schema.build-date=2020-05-25T07:11:16+00:00" .'])
}
}
9 changes: 5 additions & 4 deletions test/groovy/InfraStepTests.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import org.junit.Ignore
import org.junit.Test
import static org.junit.Assert.assertTrue
import static org.junit.Assert.assertFalse
import static org.junit.Assert.assertEquals

class InfraStepTests extends BaseTest {
static final String scriptName = "vars/infra.groovy"
Expand Down Expand Up @@ -60,15 +61,15 @@ class InfraStepTests extends BaseTest {
void testCheckoutWithEnvVariable() throws Exception {
def script = loadScript(scriptName)
env.BRANCH_NAME = 'BRANCH'
script.checkout()
script.checkoutSCM()
printCallStack()
assertJobStatusSuccess()
}

@Test
void testCheckoutWithArgument() throws Exception {
def script = loadScript(scriptName)
script.checkout('foo.git')
script.checkoutSCM('foo.git')
printCallStack()
assertJobStatusSuccess()
}
Expand All @@ -77,12 +78,12 @@ class InfraStepTests extends BaseTest {
void testCheckoutWithoutArgument() throws Exception {
def script = loadScript(scriptName)
try {
script.checkout()
script.checkoutSCM()
} catch(e){
//NOOP
}
printCallStack()
assertTrue(assertMethodCallContainsPattern('error', 'buildPlugin must be used as part of a Multibranch Pipeline'))
assertTrue(assertMethodCallContainsPattern('error', 'buildPlugin must be used as part of a Multibranch Pipeline *or* a `repo` argument must be provided'))
assertJobStatusFailure()
}

Expand Down
2 changes: 1 addition & 1 deletion test/groovy/mock/Infra.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Infra implements Serializable {
private boolean trusted
private boolean buildError

public void checkout(String repo = null) { }
public void checkoutSCM(String repo = null) { }

public String retrieveMavenSettingsFile(String location) {
return location
Expand Down
87 changes: 87 additions & 0 deletions vars/buildDockerImage.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
def call(String imageName, Map config=[:]) {
if (!config.registry) {
if (infra.isTrusted()) {
config.registry = "jenkinsciinfra/"
} else {
config.registry = "jenkins4eval/"
}
}

pipeline {
agent {
label 'docker&&linux'
}

options {
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '5', artifactNumToKeepStr: '5'))
timeout(time: 60, unit: "MINUTES")
ansiColor("xterm")
}

stages {
stage("Build") {
steps {
script {
GIT_COMMIT_REV = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
GIT_SCM_URL = sh(returnStdout: true, script: "git remote show origin | grep 'Fetch URL' | awk '{print \$3}'").trim()
SCM_URI = GIT_SCM_URL.replace("git@github.com:", "https://github.com/")
BUILD_DATE = sh(returnStdout: true, script: "TZ=UTC date --rfc-3339=seconds | sed 's/ /T/'").trim()
}
sh """
docker build \
-t ${config.registry}${imageName} \
--build-arg "GIT_COMMIT_REV=${GIT_COMMIT_REV}" \
--build-arg "GIT_SCM_URL=${GIT_SCM_URL}" \
--build-arg "BUILD_DATE=${BUILD_DATE}" \
--label "org.opencontainers.image.source=${GIT_SCM_URL}" \
--label "org.label-schema.vcs-url=${GIT_SCM_URL}" \
--label "org.opencontainers.image.url==${SCM_URI}" \
--label "org.label-schema.url=${SCM_URI}" \
--label "org.opencontainers.image.revision=${GIT_COMMIT_REV}" \
--label "org.label-schema.vcs-ref=${GIT_COMMIT_REV}" \
--label "org.opencontainers.created=${BUILD_DATE}" \
--label "org.label-schema.build-date=${BUILD_DATE}" \
.
"""
}
}
stage("Deploy master as latest") {
when { branch "master" }
steps {
sh "docker tag ${config.registry}${imageName} ${config.registry}${imageName}:master"
sh "docker tag ${config.registry}${imageName} ${config.registry}${imageName}:${GIT_COMMIT}"
script {
infra.withDockerCredentials {
sh "docker push ${config.registry}${imageName}:master"
sh "docker push ${config.registry}${imageName}:${GIT_COMMIT}"
sh "docker push ${config.registry}${imageName}"
}
if (currentBuild.description) {
currentBuild.description = currentBuild.description + " / "
}
currentBuild.description = "master / ${GIT_COMMIT}"
}
}
}
stage("Deploy tag as tag") {
// semver regex from https://gist.github.com/jhorsman/62eeea161a13b80e39f5249281e17c39
// when { tag pattern: "v([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+)?\$ ", comparator: "REGEXP"}
// for now since testing only handles simple string, start with that
when { tag "v*" }
steps {
sh "docker tag ${config.registry}${imageName} ${config.registry}${imageName}:${TAG_NAME}"
script {
infra.withDockerCredentials {
sh "docker push ${config.registry}${imageName}:${TAG_NAME}"
}
if (currentBuild.description) {
currentBuild.description = currentBuild.description + " / "
}
currentBuild.description = "${TAG_NAME}"
}
}
}
}
}
}
10 changes: 10 additions & 0 deletions vars/buildDockerImage.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<p>
Builds a docker image with some caveats
if on trusted, use jenkinsciinfra dockerhub registry, otherwise use jenkins4eval

</p>

<!--
vim: ft=html
-->

2 changes: 1 addition & 1 deletion vars/buildPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def call(Map params = [:]) {
boolean incrementals // cf. JEP-305

stage("Checkout (${stageIdentifier})") {
infra.checkout(repo)
infra.checkoutSCM(repo)
isMaven = fileExists('pom.xml')
incrementals = fileExists('.mvn/extensions.xml') &&
readFile('.mvn/extensions.xml').contains('git-changelist-maven-extension')
Expand Down
2 changes: 1 addition & 1 deletion vars/buildPluginWithGradle.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def call(Map params = [:]) {
}

stage("Checkout (${stageIdentifier})") {
infra.checkout(repo)
infra.checkoutSCM(repo)
}

stage("Build (${stageIdentifier})") {
Expand Down
2 changes: 1 addition & 1 deletion vars/essentialsTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def call(Map params = [:]) {

node(labels) {
stage("Checkout") {
infra.checkout()
infra.checkoutSCM()
}

dir(baseDir) {
Expand Down
4 changes: 4 additions & 0 deletions vars/infra.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Object withDockerCredentials(Closure body) {
}

Object checkout(String repo = null) {
checkoutSCM(repo);
}

Object checkoutSCM(String repo = null) {
if (env.BRANCH_NAME) {
checkout scm
} else if ((env.BRANCH_NAME == null) && (repo)) {
Expand Down
2 changes: 1 addition & 1 deletion vars/runBenchmarks.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def call(String artifacts = null) {
node('highmem') {

stage('Checkout repo') {
infra.checkout()
infra.checkoutSCM()
}

stage('Run Benchmarks') {
Expand Down

0 comments on commit c88ea13

Please sign in to comment.