Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

buildDockerImage() #147

Merged
merged 6 commits into from
May 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this already added by declarative pipeline or is it too long?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/shrug
is it? its not super googleable

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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is a master tag needed as well as latest?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, latest really could be anything, while master is master branch

But yea, i donno, i mostly copy and pasted it from my own shared pipeline which had this, but I'm not sure i ever used anything other than latest and tag

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