Skip to content

Commit 78118eb

Browse files
feat(CI): refactor CI to build and then pass around a test image (#181)
1 parent 2103657 commit 78118eb

11 files changed

Lines changed: 171 additions & 238 deletions

File tree

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Dockerfile

Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FROM quay.io/deis/go-dev:0.17.0
2+
# This Dockerfile is used to bundle the source and all dependencies into an image for testing.
3+
4+
RUN echo "deb http://packages.cloud.google.com/apt cloud-sdk-jessie main" \
5+
| tee /etc/apt/sources.list.d/google-cloud-sdk.list \
6+
&& curl https://packages.cloud.google.com/apt/doc/apt-key.gpg \
7+
| apt-key add - \
8+
&& apt-get update \
9+
&& apt-get install -y google-cloud-sdk \
10+
--no-install-recommends \
11+
&& rm -rf /var/lib/apt/lists/*
12+
13+
ENV CGO_ENABLED=0
14+
15+
COPY glide.yaml /go/src/github.com/deis/workflow-cli/
16+
COPY glide.lock /go/src/github.com/deis/workflow-cli/
17+
18+
WORKDIR /go/src/github.com/deis/workflow-cli
19+
20+
RUN glide install --strip-vcs --strip-vendor
21+
22+
COPY ./_scripts /usr/local/bin
23+
24+
COPY . /go/src/github.com/deis/workflow-cli

Jenkinsfile

Lines changed: 112 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
def workpath_linux = "/src/github.com/deis/workflow-cli"
21
def windows = 'windows'
32
def linux = 'linux'
43
def git_commit = ''
@@ -9,58 +8,6 @@ def getBasePath = { String filepath ->
98
return filepath.substring(0, filename)
109
}
1110

12-
def make = { String target ->
13-
try {
14-
sh "make ${target} fileperms"
15-
} catch(error) {
16-
sh "make fileperms"
17-
throw error
18-
}
19-
}
20-
21-
def gcs_cleanup_cmd = "sh -c 'rm -rf /upload/* /.config/*'"
22-
def gcs_bucket = "gs://workflow-cli"
23-
def gcs_key = "tmp/key.json"
24-
25-
def gcs_cmd = { String cmd ->
26-
gcs_cmd = "docker run --rm -v ${pwd()}/tmp:/.config -v ${pwd()}/_dist:/upload google/cloud-sdk:latest "
27-
try {
28-
sh(gcs_cmd + cmd)
29-
} catch(error) {
30-
sh(gcs_cmd + gcs_cleanup_cmd)
31-
throw error
32-
}
33-
}
34-
35-
def upload_artifacts = { boolean cache ->
36-
withCredentials([[$class: 'FileBinding', credentialsId: 'e80fd033-dd76-4d96-be79-6c272726fb82', variable: 'GCSKEY']]) {
37-
sh "mkdir -p ${getBasePath(gcs_key)}"
38-
sh "cat \"\${GCSKEY}\" > ${gcs_key}"
39-
gcs_cmd 'gcloud auth activate-service-account -q --key-file /.config/key.json'
40-
41-
headers = "-h 'x-goog-meta-git-branch:${git_branch}' "
42-
headers += "-h 'x-goog-meta-git-sha:${git_commit}' "
43-
headers += "-h 'x-goog-meta-ci-job:${env.JOB_NAME}' "
44-
headers += "-h 'x-goog-meta-ci-number:${env.BUILD_NUMBER}' "
45-
headers += "-h 'x-goog-meta-ci-url:${env.BUILD_URL}'"
46-
if(!cache) {
47-
headers += ' -h "Cache-Control:no-cache"'
48-
}
49-
gcs_cmd "gsutil -mq ${headers} cp -a public-read -r /upload/* ${gcs_bucket}"
50-
gcs_cmd gcs_cleanup_cmd
51-
}
52-
}
53-
54-
def gopath_linux = {
55-
def gopath = pwd() + "/gopath"
56-
env.GOPATH = gopath
57-
gopath
58-
}
59-
60-
def workdir_linux = { String gopath ->
61-
gopath + workpath_linux
62-
}
63-
6411
def sh = { String cmd ->
6512
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) {
6613
sh cmd
@@ -100,97 +47,143 @@ node(windows) {
10047
}
10148
}
10249

50+
stage 'Git Info'
10351
node(linux) {
104-
def gopath = gopath_linux()
105-
def workdir = workdir_linux(gopath)
106-
107-
dir(workdir) {
108-
stage 'Checkout Linux'
109-
checkout scm
110-
stage 'Install Linux'
111-
bootstrap linux
112-
stage 'Test Linux'
113-
make 'test-cover'
114-
stage 'Upload to Codeconv'
115-
withCredentials([[$class: 'StringBinding', credentialsId: '995d99a7-466b-4beb-bf75-f3ba91cbbc18', variable: 'CODECOV_TOKEN']]) {
116-
sh 'curl -s https://codecov.io/bash | bash'
117-
}
52+
checkout scm
53+
54+
// HACK: Recommended approach for getting command output is writing to and then reading a file.
55+
sh 'mkdir -p tmp'
56+
sh 'git describe --all > tmp/GIT_BRANCH'
57+
sh 'git rev-parse HEAD > tmp/GIT_COMMIT'
58+
git_branch = readFile('tmp/GIT_BRANCH').trim()
59+
git_commit = readFile('tmp/GIT_COMMIT').trim()
60+
61+
if (git_branch != "remotes/origin/master") {
62+
// Determine actual PR commit, if necessary
63+
sh 'git rev-parse HEAD | git log --pretty=%P -n 1 --date-order > tmp/MERGE_COMMIT_PARENTS'
64+
sh 'cat tmp/MERGE_COMMIT_PARENTS'
65+
merge_commit_parents = readFile('tmp/MERGE_COMMIT_PARENTS').trim()
66+
if (merge_commit_parents.length() > 40) {
67+
echo 'More than one merge commit parent signifies that the merge commit is not the PR commit'
68+
echo "Changing git_commit from '${git_commit}' to '${merge_commit_parents.take(40)}'"
69+
git_commit = merge_commit_parents.take(40)
70+
} else {
71+
echo 'Only one merge commit parent signifies that the merge commit is also the PR commit'
72+
echo "Keeping git_commit as '${git_commit}'"
73+
}
11874
}
11975
}
12076

121-
stage 'Git Info'
77+
def test_image = "quay.io/deisci/workflow-cli-dev:${git_commit.take(7)}"
78+
def mutable_image = 'quay.io/deisci/workflow-cli-dev:latest'
79+
12280
node(linux) {
81+
stage 'Build and push test container'
82+
checkout scm
83+
def quayUsername = "deisci+jenkins"
84+
def quayEmail = "deis+jenkins@deis.com"
85+
withCredentials([[$class: 'StringBinding',
86+
credentialsId: 'c67dc0a1-c8c4-4568-a73d-53ad8530ceeb',
87+
variable: 'QUAY_PASSWORD']]) {
88+
89+
sh """
90+
docker login -e="${quayEmail}" -u="${quayUsername}" -p="\${QUAY_PASSWORD}" quay.io
91+
docker build -t ${test_image} .
92+
docker push ${test_image}
93+
"""
94+
95+
if (git_branch == "remotes/origin/master") {
96+
sh """
97+
docker tag ${test_image} ${mutable_image}
98+
docker push ${mutable_image}
99+
"""
100+
}
101+
}
102+
}
123103

124-
def gopath = gopath_linux()
125-
def workdir = workdir_linux(gopath)
126104

127-
dir(workdir) {
128-
checkout scm
129-
130-
// HACK: Recommended approach for getting command output is writing to and then reading a file.
131-
sh 'mkdir -p tmp'
132-
sh 'git describe --all > tmp/GIT_BRANCH'
133-
sh 'git rev-parse HEAD > tmp/GIT_COMMIT'
134-
git_branch = readFile('tmp/GIT_BRANCH').trim()
135-
git_commit = readFile('tmp/GIT_COMMIT').trim()
136-
137-
if (git_branch != "remotes/origin/master") {
138-
// Determine actual PR commit, if necessary
139-
sh 'git rev-parse HEAD | git log --pretty=%P -n 1 --date-order > tmp/MERGE_COMMIT_PARENTS'
140-
sh 'cat tmp/MERGE_COMMIT_PARENTS'
141-
merge_commit_parents = readFile('tmp/MERGE_COMMIT_PARENTS').trim()
142-
if (merge_commit_parents.length() > 40) {
143-
echo 'More than one merge commit parent signifies that the merge commit is not the PR commit'
144-
echo "Changing git_commit from '${git_commit}' to '${merge_commit_parents.take(40)}'"
145-
git_commit = merge_commit_parents.take(40)
146-
} else {
147-
echo 'Only one merge commit parent signifies that the merge commit is also the PR commit'
148-
echo "Keeping git_commit as '${git_commit}'"
105+
stage 'Lint and test container'
106+
parallel(
107+
lint: {
108+
node(linux) {
109+
sh "docker run --rm ${test_image} lint"
110+
}
111+
},
112+
test: {
113+
node(linux) {
114+
withCredentials([[$class: 'StringBinding',
115+
credentialsId: '995d99a7-466b-4beb-bf75-f3ba91cbbc18',
116+
variable: 'CODECOV_TOKEN']]) {
117+
sh "docker run -e CODECOV_TOKEN=\${CODECOV_TOKEN} --rm ${test_image} sh -c 'test-cover.sh && curl -s https://codecov.io/bash | bash'"
149118
}
150119
}
151120
}
152-
}
121+
)
153122

154123
stage 'Build and Upload Artifacts'
155124

125+
def gcs_bucket = "gs://workflow-cli"
126+
127+
def upload_artifacts = { String dist_dir, boolean cache ->
128+
headers = "-h 'x-goog-meta-git-branch:${git_branch}' "
129+
headers += "-h 'x-goog-meta-git-sha:${git_commit}' "
130+
headers += "-h 'x-goog-meta-ci-job:${env.JOB_NAME}' "
131+
headers += "-h 'x-goog-meta-ci-number:${env.BUILD_NUMBER}' "
132+
headers += "-h 'x-goog-meta-ci-url:${env.BUILD_URL}'"
133+
if(!cache) {
134+
headers += ' -h "Cache-Control:no-cache"'
135+
}
136+
137+
script = "sh -c 'echo \${GCS_KEY_JSON} | base64 -d - > /tmp/key.json "
138+
script += "&& gcloud auth activate-service-account -q --key-file /tmp/key.json "
139+
script += "&& gsutil -mq ${headers} cp -a public-read -r /upload/* ${gcs_bucket} "
140+
script += "&& rm -rf /upload/*'"
141+
142+
withCredentials([[$class: 'StringBinding',
143+
credentialsId: '6561701c-b7b4-4796-83c4-9d87946799e4',
144+
variable: 'GCSKEY']]) {
145+
sh "docker run ${dist_dir} -e GCS_KEY_JSON=\"\${GCSKEY}\" --rm ${test_image} ${script}"
146+
}
147+
sh "rm -rf ${tmp_dir}"
148+
}
149+
150+
def mktmp = {
151+
// Create tmp directory to store files
152+
sh 'mktemp -d > tmp_dir'
153+
tmp = readFile('tmp_dir').trim()
154+
echo "Storing binaries in ${tmp}"
155+
sh 'rm tmp_dir'
156+
return tmp
157+
}
158+
156159
parallel(
157160
revision: {
158161
node(linux) {
159-
def gopath = gopath_linux()
160-
def workdir = workdir_linux(gopath)
161162

162-
dir(workdir) {
163-
checkout scm
163+
flags = ""
164+
if (git_branch != "remotes/origin/master") {
165+
echo "Skipping build of 386 binaries to shorten CI for Pull Requests"
166+
flags += "-e BUILD_ARCH=amd64"
167+
}
164168

165-
if (git_branch != "remotes/origin/master") {
166-
echo "Skipping build of 386 binaries to shorten CI for Pull Requests"
167-
env.BUILD_ARCH = "amd64"
168-
}
169+
tmp_dir = mktmp()
170+
dist_dir = "-e DIST_DIR=/upload -v ${tmp_dir}:/upload"
171+
sh "docker run ${flags} -e REVISION=${git_commit.take(7)} ${dist_dir} --rm ${test_image} make build-revision"
169172

170-
make 'bootstrap'
171-
env.REVISION = git_commit.take(7)
172-
make 'build-revision'
173173

174-
upload_artifacts(true)
175-
}
174+
upload_artifacts(dist_dir, true)
176175
}
177176
},
178177
latest: {
179178
node(linux) {
180-
def gopath = gopath_linux()
181-
def workdir = workdir_linux(gopath)
179+
if (git_branch == "remotes/origin/master") {
180+
tmp_dir = mktmp()
181+
dist_dir = "-e DIST_DIR=/upload -v ${tmp_dir}:/upload"
182+
sh "docker run ${dist_dir} --rm ${test_image} make build-latest"
182183

183-
dir(workdir) {
184-
checkout scm
185-
186-
if (git_branch == "remotes/origin/master") {
187-
make 'bootstrap'
188-
make 'build-latest'
189-
190-
upload_artifacts(false)
191-
} else {
192-
echo "Skipping build of latest artifacts because this build is not on the master branch (branch: ${git_branch})"
193-
}
184+
upload_artifacts(dist_dir, false)
185+
} else {
186+
echo "Skipping build of latest artifacts because this build is not on the master branch (branch: ${git_branch})"
194187
}
195188
}
196189
}

0 commit comments

Comments
 (0)