Release.Jenkinsfile 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #!groovy
  2. def dockerVersions = ['19.03.5', '18.09.9']
  3. def baseImages = ['alpine', 'debian']
  4. def pythonVersions = ['py27', 'py37']
  5. pipeline {
  6. agent none
  7. options {
  8. skipDefaultCheckout(true)
  9. buildDiscarder(logRotator(daysToKeepStr: '30'))
  10. timeout(time: 2, unit: 'HOURS')
  11. timestamps()
  12. }
  13. stages {
  14. stage('Build test images') {
  15. // TODO use declarative 1.5.0 `matrix` once available on CI
  16. parallel {
  17. stage('alpine') {
  18. agent {
  19. label 'linux'
  20. }
  21. steps {
  22. buildImage('alpine')
  23. }
  24. }
  25. stage('debian') {
  26. agent {
  27. label 'linux'
  28. }
  29. steps {
  30. buildImage('debian')
  31. }
  32. }
  33. }
  34. }
  35. stage('Test') {
  36. steps {
  37. // TODO use declarative 1.5.0 `matrix` once available on CI
  38. script {
  39. def testMatrix = [:]
  40. baseImages.each { baseImage ->
  41. dockerVersions.each { dockerVersion ->
  42. pythonVersions.each { pythonVersion ->
  43. testMatrix["${baseImage}_${dockerVersion}_${pythonVersion}"] = runTests(dockerVersion, pythonVersion, baseImage)
  44. }
  45. }
  46. }
  47. parallel testMatrix
  48. }
  49. }
  50. }
  51. stage('Generate Changelog') {
  52. agent {
  53. label 'linux'
  54. }
  55. steps {
  56. checkout scm
  57. withCredentials([string(credentialsId: 'github-compose-release-test-token', variable: 'GITHUB_TOKEN')]) {
  58. sh "./script/release/generate_changelog.sh"
  59. }
  60. archiveArtifacts artifacts: 'CHANGELOG.md'
  61. stash( name: "changelog", includes: 'CHANGELOG.md' )
  62. }
  63. }
  64. stage('Package') {
  65. parallel {
  66. stage('macosx binary') {
  67. agent {
  68. label 'mac-python'
  69. }
  70. steps {
  71. checkout scm
  72. sh './script/setup/osx'
  73. sh 'tox -e py27,py37 -- tests/unit'
  74. sh './script/build/osx'
  75. dir ('dist') {
  76. sh 'openssl sha256 -r -out docker-compose-Darwin-x86_64.sha256 docker-compose-Darwin-x86_64'
  77. sh 'openssl sha256 -r -out docker-compose-Darwin-x86_64.tgz.sha256 docker-compose-Darwin-x86_64.tgz'
  78. }
  79. archiveArtifacts artifacts: 'dist/*', fingerprint: true
  80. dir("dist") {
  81. stash name: "bin-darwin"
  82. }
  83. }
  84. }
  85. stage('linux binary') {
  86. agent {
  87. label 'linux'
  88. }
  89. steps {
  90. checkout scm
  91. sh ' ./script/build/linux'
  92. dir ('dist') {
  93. sh 'openssl sha256 -r -out docker-compose-Linux-x86_64.sha256 docker-compose-Linux-x86_64'
  94. }
  95. archiveArtifacts artifacts: 'dist/*', fingerprint: true
  96. dir("dist") {
  97. stash name: "bin-linux"
  98. }
  99. }
  100. }
  101. stage('windows binary') {
  102. agent {
  103. label 'windows-python'
  104. }
  105. environment {
  106. PATH = "$PATH;C:\\Python37;C:\\Python37\\Scripts"
  107. }
  108. steps {
  109. checkout scm
  110. bat 'tox.exe -e py27,py37 -- tests/unit'
  111. powershell '.\\script\\build\\windows.ps1'
  112. dir ('dist') {
  113. sh 'openssl sha256 -r -out docker-compose-Windows-x86_64.exe.sha256 docker-compose-Windows-x86_64.exe'
  114. }
  115. archiveArtifacts artifacts: 'dist/*', fingerprint: true
  116. dir("dist") {
  117. stash name: "bin-win"
  118. }
  119. }
  120. }
  121. stage('alpine image') {
  122. agent {
  123. label 'linux'
  124. }
  125. steps {
  126. buildRuntimeImage('alpine')
  127. }
  128. }
  129. stage('debian image') {
  130. agent {
  131. label 'linux'
  132. }
  133. steps {
  134. buildRuntimeImage('debian')
  135. }
  136. }
  137. }
  138. }
  139. stage('Release') {
  140. when {
  141. buildingTag()
  142. }
  143. parallel {
  144. stage('Pushing images') {
  145. agent {
  146. label 'linux'
  147. }
  148. steps {
  149. pushRuntimeImage('alpine')
  150. pushRuntimeImage('debian')
  151. }
  152. }
  153. stage('Creating Github Release') {
  154. agent {
  155. label 'linux'
  156. }
  157. steps {
  158. checkout scm
  159. sh 'mkdir -p dist'
  160. dir("dist") {
  161. unstash "bin-darwin"
  162. unstash "bin-linux"
  163. unstash "bin-win"
  164. githubRelease()
  165. }
  166. }
  167. }
  168. stage('Publishing Python packages') {
  169. agent {
  170. label 'linux'
  171. }
  172. steps {
  173. checkout scm
  174. withCredentials([[$class: "FileBinding", credentialsId: 'pypirc-docker-dsg-cibot', variable: 'PYPIRC']]) {
  175. sh './script/release/python-package'
  176. }
  177. archiveArtifacts artifacts: 'dist/*', fingerprint: true
  178. }
  179. }
  180. stage('Publishing binaries to Bintray') {
  181. agent {
  182. label 'linux'
  183. }
  184. steps {
  185. checkout scm
  186. dir("dist") {
  187. unstash "bin-darwin"
  188. unstash "bin-linux"
  189. unstash "bin-win"
  190. }
  191. withCredentials([usernamePassword(credentialsId: 'bintray-docker-dsg-cibot', usernameVariable: 'BINTRAY_USER', passwordVariable: 'BINTRAY_TOKEN')]) {
  192. sh './script/release/push-binaries'
  193. }
  194. }
  195. }
  196. }
  197. }
  198. }
  199. }
  200. def buildImage(baseImage) {
  201. def scmvar = checkout(scm)
  202. def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
  203. image = docker.image(imageName)
  204. withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
  205. try {
  206. image.pull()
  207. } catch (Exception exc) {
  208. ansiColor('xterm') {
  209. sh """docker build -t ${imageName} \\
  210. --target build \\
  211. --build-arg BUILD_PLATFORM="${baseImage}" \\
  212. --build-arg GIT_COMMIT="${scmvar.GIT_COMMIT}" \\
  213. .\\
  214. """
  215. sh "docker push ${imageName}"
  216. }
  217. echo "${imageName}"
  218. return imageName
  219. }
  220. }
  221. }
  222. def runTests(dockerVersion, pythonVersion, baseImage) {
  223. return {
  224. stage("python=${pythonVersion} docker=${dockerVersion} ${baseImage}") {
  225. node("linux") {
  226. def scmvar = checkout(scm)
  227. def imageName = "dockerbuildbot/compose:${baseImage}-${scmvar.GIT_COMMIT}"
  228. def storageDriver = sh(script: "docker info -f \'{{.Driver}}\'", returnStdout: true).trim()
  229. echo "Using local system's storage driver: ${storageDriver}"
  230. withDockerRegistry(credentialsId:'dockerbuildbot-index.docker.io') {
  231. sh """docker run \\
  232. -t \\
  233. --rm \\
  234. --privileged \\
  235. --volume="\$(pwd)/.git:/code/.git" \\
  236. --volume="/var/run/docker.sock:/var/run/docker.sock" \\
  237. -e "TAG=${imageName}" \\
  238. -e "STORAGE_DRIVER=${storageDriver}" \\
  239. -e "DOCKER_VERSIONS=${dockerVersion}" \\
  240. -e "BUILD_NUMBER=${env.BUILD_NUMBER}" \\
  241. -e "PY_TEST_VERSIONS=${pythonVersion}" \\
  242. --entrypoint="script/test/ci" \\
  243. ${imageName} \\
  244. --verbose
  245. """
  246. }
  247. }
  248. }
  249. }
  250. }
  251. def buildRuntimeImage(baseImage) {
  252. scmvar = checkout scm
  253. def imageName = "docker/compose:${baseImage}-${env.BRANCH_NAME}"
  254. ansiColor('xterm') {
  255. sh """docker build -t ${imageName} \\
  256. --build-arg BUILD_PLATFORM="${baseImage}" \\
  257. --build-arg GIT_COMMIT="${scmvar.GIT_COMMIT.take(7)}" \\
  258. .
  259. """
  260. }
  261. sh "mkdir -p dist"
  262. sh "docker save ${imageName} -o dist/docker-compose-${baseImage}.tar"
  263. stash name: "compose-${baseImage}", includes: "dist/docker-compose-${baseImage}.tar"
  264. }
  265. def pushRuntimeImage(baseImage) {
  266. unstash "compose-${baseImage}"
  267. sh 'echo -n "${DOCKERHUB_CREDS_PSW}" | docker login --username "${DOCKERHUB_CREDS_USR}" --password-stdin'
  268. sh "docker load -i dist/docker-compose-${baseImage}.tar"
  269. withDockerRegistry(credentialsId: 'dockerbuildbot-hub.docker.com') {
  270. sh "docker push docker/compose:${baseImage}-${env.TAG_NAME}"
  271. if (baseImage == "alpine" && env.TAG_NAME != null) {
  272. sh "docker tag docker/compose:alpine-${env.TAG_NAME} docker/compose:${env.TAG_NAME}"
  273. sh "docker push docker/compose:${env.TAG_NAME}"
  274. }
  275. }
  276. }
  277. def githubRelease() {
  278. withCredentials([string(credentialsId: 'github-compose-release-test-token', variable: 'GITHUB_TOKEN')]) {
  279. def prerelease = !( env.TAG_NAME ==~ /v[0-9\.]+/ )
  280. def data = """{
  281. \"tag_name\": \"${env.TAG_NAME}\",
  282. \"name\": \"${env.TAG_NAME}\",
  283. \"draft\": true,
  284. \"prerelease\": ${prerelease},
  285. \"body\" : \"${changelog}\"
  286. """
  287. echo $data
  288. def url = "https://api.github.com/repos/docker/compose/releases"
  289. def upload_url = sh(returnStdout: true, script: """
  290. curl -sSf -H 'Authorization: token ${GITHUB_TOKEN}' -H 'Accept: application/json' -H 'Content-type: application/json' -X POST -d '$data' $url") \\
  291. | jq '.upload_url | .[:rindex("{")]'
  292. """)
  293. sh("""
  294. for f in * ; do
  295. curl -sf -H 'Authorization: token ${GITHUB_TOKEN}' -H 'Accept: application/json' -H 'Content-type: application/octet-stream' \\
  296. -X POST --data-binary @\$f ${upload_url}?name=\$f;
  297. done
  298. """)
  299. }
  300. }