diff --git a/.env b/.env new file mode 100644 index 0000000..7bf5c5a --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +#!/bin/sh +CCG_PROJECT=devpi +DOCKER_DEVPI_SERVER_VERSION=4.1.1 +DOCKER_DEVPI_CLIENT_VERSION=2.7.0 +DOCKER_DEVPI_WEB_VERSION=3.1.1 +DOCKER_ROUTE +BRANCH_NAME diff --git a/Dockerfile b/Dockerfile index 4e3b491..ce8a750 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,17 @@ # -FROM python:2.7-alpine -MAINTAINER https://github.com/muccg - -ARG ARG_DEVPI_VERSION -ARG ARG_PIP_OPTS="--upgrade --no-cache-dir" - -ENV DEVPI_VERSION $ARG_DEVPI_VERSION +FROM python:3.5-alpine +MAINTAINER https://github.com/muccg/ + +ARG ARG_DEVPI_SERVER_VERSION +ARG ARG_DEVPI_WEB_VERSION +ARG ARG_DEVPI_CLIENT_VERSION + +ENV DEVPI_SERVER_VERSION $ARG_DEVPI_SERVER_VERSION +ENV DEVPI_WEB_VERSION $ARG_DEVPI_WEB_VERSION +ENV DEVPI_CLIENT_VERSION $ARG_DEVPI_CLIENT_VERSION +ENV PIP_NO_CACHE_DIR="off" +ENV PIP_INDEX_URL="https://pypi.python.org/simple" +ENV PIP_TRUSTED_HOST="127.0.0.1" ENV VIRTUAL_ENV /env # devpi user @@ -16,15 +22,15 @@ RUN addgroup -S -g 1000 devpi \ RUN apk add --no-cache bash # create a virtual env in $VIRTUAL_ENV, ensure it respects pip version -RUN pip install $ARG_PIP_OPTS virtualenv \ +RUN pip install virtualenv \ && virtualenv $VIRTUAL_ENV \ - && $VIRTUAL_ENV/bin/pip install $ARG_PIP_OPTS pip==$PYTHON_PIP_VERSION + && $VIRTUAL_ENV/bin/pip install pip==$PYTHON_PIP_VERSION ENV PATH $VIRTUAL_ENV/bin:$PATH -RUN pip install $ARG_PIP_OPTS \ - "devpi-client==2.6.4" \ - "devpi-web==3.1.1" \ - "devpi-server==$DEVPI_VERSION" +RUN pip install \ + "devpi-client==${DEVPI_CLIENT_VERSION}" \ + "devpi-web==${DEVPI_WEB_VERSION}" \ + "devpi-server==${DEVPI_SERVER_VERSION}" EXPOSE 3141 VOLUME /data diff --git a/Jenkinsfile b/Jenkinsfile index 8802056..f0f507e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,18 +1,71 @@ #!groovy node { - stage 'Checkout' + def deployable_branches = ["master"] + + stage('Checkout') { checkout scm + } - stage 'Build' + dockerStage('Build') { echo "Branch is: ${env.BRANCH_NAME}" echo "Build is: ${env.BUILD_NUMBER}" - env.DOCKER_USE_HUB = 1 - withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'dockerbot', - usernameVariable: 'DOCKER_USERNAME', - passwordVariable: 'DOCKER_PASSWORD']]) { - wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) { - sh './build.sh' + sh(''' + ./develop.sh sanity + ./develop.sh build prod + ./develop.sh build latest + ''') + } + + if (deployable_branches.contains(env.BRANCH_NAME)) { + + dockerStage('Publish') { + withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'dockerbot', + usernameVariable: 'DOCKER_USERNAME', + passwordVariable: 'DOCKER_PASSWORD']]) { + sh(""" + docker login -u "${env.DOCKER_USERNAME}" --password="${env.DOCKER_PASSWORD}" + ./develop.sh push prod + ./develop.sh push latest + """) + } + } + } +} + + +/* + * dockerStage + * + * Custom stage that wraps the stage in timestamps and AnsiColorBuildWrapper + * Prior to exit wrfy is used to kill all running containers and cleanup. + */ +def dockerStage(String label, + List artifacts=[], + List testResults=[], + Closure body) { + + stage(label) { + try { + timestamps { + wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'XTerm']) { + body.call() + } + } + } catch (Exception e) { + currentBuild.result = 'FAILURE' + throw e + } finally { + for (artifact in artifacts) { + step([$class: 'ArtifactArchiver', artifacts: artifact, fingerprint: false, excludes: null]) + } + for (testResult in testResults) { + step([$class: 'JUnitResultArchiver', testResults: testResult]) } + sh(''' + /env/bin/wrfy kill-all --force + /env/bin/wrfy scrub --force + ''') } + } } diff --git a/build.sh b/build.sh deleted file mode 100755 index cea5406..0000000 --- a/build.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# -# Script to build images -# - -# break on error -set -e -set -x -set -a -: ${DOCKER_USE_HUB:="0"} - -DATE=`date +%Y.%m.%d` -DOCKER_DEVPI_VERSION=4.1.0 - - -ci_docker_login() { - if [ -z ${DOCKER_EMAIL+x} ]; then - DOCKER_EMAIL=${bamboo_DOCKER_EMAIL} - fi - if [ -z ${DOCKER_USERNAME+x} ]; then - DOCKER_USERNAME=${bamboo_DOCKER_USERNAME} - fi - if [ -z ${DOCKER_PASSWORD+x} ]; then - DOCKER_PASSWORD=${bamboo_DOCKER_PASSWORD} - fi - - docker login -e "${DOCKER_EMAIL}" -u ${DOCKER_USERNAME} --password="${DOCKER_PASSWORD}" -} - - -# warm up cache -docker pull muccg/devpi:latest || true - -docker-compose build devpi -docker inspect muccg/devpi:latest - -docker tag muccg/devpi:latest muccg/devpi:latest-${DATE} -docker tag muccg/devpi:latest muccg/devpi:${DOCKER_DEVPI_VERSION} - -if [ ${DOCKER_USE_HUB} = "1" ]; then - ci_docker_login - docker push muccg/devpi:latest - docker push muccg/devpi:latest-${DATE} - docker push muccg/devpi:${DOCKER_DEVPI_VERSION} -fi diff --git a/develop.sh b/develop.sh new file mode 100755 index 0000000..6a8d4ad --- /dev/null +++ b/develop.sh @@ -0,0 +1,48 @@ +#!/bin/sh +set +x +set -e + +: "${CCG_DOCKER_ORG:=muccg}" +: "${CCG_COMPOSER:=ccg-composer}" +: "${CCG_COMPOSER_VERSION:=latest}" +: "${CCG_PIP_PROXY=0}" +: "${CCG_HTTP_PROXY=0}" + +export CCG_DOCKER_ORG CCG_COMPOSER CCG_COMPOSER_VERSION CCG_PIP_PROXY CCG_HTTP_PROXY + +# ensure we have an .env file +ENV_FILE_OPT='' +if [ -f .env ]; then + ENV_FILE_OPT='--env-file .env' + set +e + . ./.env > /dev/null 2>&1 + set -e +else + echo ".env file not found, settings such as project name and proxies will not be set" +fi + +# Pass through the ip of the host if we can +# There is no docker0 interface on Mac OS, so don't do any proxy detection +if [ "$(uname)" != "Darwin" ]; then + set +e + DOCKER_ROUTE=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+') + set -e + export DOCKER_ROUTE +fi + +TTY_OPTS= +if [ -t 0 ]; then + TTY_OPTS='--interactive --tty' +fi + +ENV_OPTS="$(env | sort | cut -d= -f1 | grep "^CCG_[a-zA-Z0-9_]*$" | awk '{print "-e", $1}')" +# shellcheck disable=SC2086 disable=SC2048 +docker run --rm ${TTY_OPTS} ${ENV_FILE_OPT} \ + ${ENV_OPTS} \ + -v /etc/timezone:/etc/timezone:ro \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v "$(pwd)":"$(pwd)" \ + -v "${HOME}"/.docker:/data/.docker \ + -w "$(pwd)" \ + "${CCG_DOCKER_ORG}"/"${CCG_COMPOSER}":"${CCG_COMPOSER_VERSION}" \ + "$@" diff --git a/docker-compose-build.yml b/docker-compose-build.yml new file mode 100644 index 0000000..b15e136 --- /dev/null +++ b/docker-compose-build.yml @@ -0,0 +1,23 @@ +version: '2' +services: + + dev: + build: + context: ./ + args: + ARG_DEVPI_SERVER_VERSION: ${DOCKER_DEVPI_SERVER_VERSION} + ARG_DEVPI_WEB_VERSION: ${DOCKER_DEVPI_WEB_VERSION} + ARG_DEVPI_CLIENT_VERSION: ${DOCKER_DEVPI_CLIENT_VERSION} + image: muccg/devpi:${GIT_BRANCH} + + prod: + extends: + file: docker-compose-build.yml + service: dev + image: muccg/devpi:${DOCKER_DEVPI_SERVER_VERSION} + + latest: + extends: + file: docker-compose-build.yml + service: dev + image: muccg/devpi:latest diff --git a/docker-compose.yml b/docker-compose.yml index c1ad139..b959d01 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,11 +2,7 @@ version: '2' services: devpi: - build: - context: ./ - args: - ARG_DEVPI_VERSION: ${DOCKER_DEVPI_VERSION} - image: muccg/devpi + image: muccg/devpi:latest volumes: - ./data:/data ports: