summaryrefslogtreecommitdiff
path: root/script
diff options
context:
space:
mode:
Diffstat (limited to 'script')
-rwxr-xr-xscript/build/image17
-rwxr-xr-xscript/build/linux13
-rwxr-xr-xscript/build/linux-entrypoint15
-rwxr-xr-xscript/build/osx15
-rwxr-xr-xscript/build/test-image17
-rw-r--r--script/build/windows.ps160
-rwxr-xr-xscript/build/write-git-sha7
-rwxr-xr-xscript/ci8
-rwxr-xr-xscript/clean7
-rwxr-xr-xscript/release/build-binaries40
-rwxr-xr-xscript/release/cherry-pick-pr34
-rwxr-xr-xscript/release/contributors30
-rwxr-xr-xscript/release/download-binaries32
-rwxr-xr-xscript/release/make-branch86
-rwxr-xr-xscript/release/push-release82
-rwxr-xr-xscript/release/rebase-bump-commit38
-rw-r--r--script/release/utils.sh23
-rw-r--r--script/run/run.ps122
-rwxr-xr-xscript/run/run.sh57
-rwxr-xr-xscript/setup/osx52
-rwxr-xr-xscript/test/all64
-rwxr-xr-xscript/test/ci25
-rwxr-xr-xscript/test/default19
-rwxr-xr-xscript/test/versions.py162
-rw-r--r--script/travis/bintray.json.tmpl29
-rwxr-xr-xscript/travis/build-binary13
-rwxr-xr-xscript/travis/ci10
-rwxr-xr-xscript/travis/install10
-rwxr-xr-xscript/travis/render-bintray-config.py13
29 files changed, 1000 insertions, 0 deletions
diff --git a/script/build/image b/script/build/image
new file mode 100755
index 00000000..a3198c99
--- /dev/null
+++ b/script/build/image
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+if [ -z "$1" ]; then
+ >&2 echo "First argument must be image tag."
+ exit 1
+fi
+
+TAG=$1
+
+VERSION="$(python setup.py --version)"
+
+./script/build/write-git-sha
+python setup.py sdist bdist_wheel
+./script/build/linux
+docker build -t docker/compose:$TAG -f Dockerfile.run .
diff --git a/script/build/linux b/script/build/linux
new file mode 100755
index 00000000..1a4cd4d9
--- /dev/null
+++ b/script/build/linux
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -ex
+
+./script/clean
+
+TAG="docker-compose"
+docker build -t "$TAG" . | tail -n 200
+docker run \
+ --rm --entrypoint="script/build/linux-entrypoint" \
+ -v $(pwd)/dist:/code/dist \
+ -v $(pwd)/.git:/code/.git \
+ "$TAG"
diff --git a/script/build/linux-entrypoint b/script/build/linux-entrypoint
new file mode 100755
index 00000000..bf515060
--- /dev/null
+++ b/script/build/linux-entrypoint
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -ex
+
+TARGET=dist/docker-compose-$(uname -s)-$(uname -m)
+VENV=/code/.tox/py27
+
+mkdir -p `pwd`/dist
+chmod 777 `pwd`/dist
+
+$VENV/bin/pip install -q -r requirements-build.txt
+./script/build/write-git-sha
+su -c "$VENV/bin/pyinstaller docker-compose.spec" user
+mv dist/docker-compose $TARGET
+$TARGET version
diff --git a/script/build/osx b/script/build/osx
new file mode 100755
index 00000000..3de34576
--- /dev/null
+++ b/script/build/osx
@@ -0,0 +1,15 @@
+#!/bin/bash
+set -ex
+
+PATH="/usr/local/bin:$PATH"
+
+rm -rf venv
+
+virtualenv -p /usr/local/bin/python venv
+venv/bin/pip install -r requirements.txt
+venv/bin/pip install -r requirements-build.txt
+venv/bin/pip install --no-deps .
+./script/build/write-git-sha
+venv/bin/pyinstaller docker-compose.spec
+mv dist/docker-compose dist/docker-compose-Darwin-x86_64
+dist/docker-compose-Darwin-x86_64 version
diff --git a/script/build/test-image b/script/build/test-image
new file mode 100755
index 00000000..a2eb62cd
--- /dev/null
+++ b/script/build/test-image
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+if [ -z "$1" ]; then
+ >&2 echo "First argument must be image tag."
+ exit 1
+fi
+
+TAG=$1
+
+docker build -t docker-compose-tests:tmp .
+ctnr_id=$(docker create --entrypoint=tox docker-compose-tests:tmp)
+docker commit $ctnr_id docker/compose-tests:latest
+docker tag docker/compose-tests:latest docker/compose-tests:$TAG
+docker rm -f $ctnr_id
+docker rmi -f docker-compose-tests:tmp
diff --git a/script/build/windows.ps1 b/script/build/windows.ps1
new file mode 100644
index 00000000..db643274
--- /dev/null
+++ b/script/build/windows.ps1
@@ -0,0 +1,60 @@
+# Builds the Windows binary.
+#
+# From a fresh 64-bit Windows 10 install, prepare the system as follows:
+#
+# 1. Install Git:
+#
+# http://git-scm.com/download/win
+#
+# 2. Install Python 2.7.10:
+#
+# https://www.python.org/downloads/
+#
+# 3. Append ";C:\Python27;C:\Python27\Scripts" to the "Path" environment variable:
+#
+# https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/sysdm_advancd_environmnt_addchange_variable.mspx?mfr=true
+#
+# 4. In Powershell, run the following commands:
+#
+# $ pip install virtualenv
+# $ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
+#
+# 5. Clone the repository:
+#
+# $ git clone https://github.com/docker/compose.git
+# $ cd compose
+#
+# 6. Build the binary:
+#
+# .\script\build\windows.ps1
+
+$ErrorActionPreference = "Stop"
+
+# Remove virtualenv
+if (Test-Path venv) {
+ Remove-Item -Recurse -Force .\venv
+}
+
+# Remove .pyc files
+Get-ChildItem -Recurse -Include *.pyc | foreach ($_) { Remove-Item $_.FullName }
+
+# Create virtualenv
+virtualenv .\venv
+
+# pip and pyinstaller generate lots of warnings, so we need to ignore them
+$ErrorActionPreference = "Continue"
+
+# Install dependencies
+.\venv\Scripts\pip install pypiwin32==219
+.\venv\Scripts\pip install -r requirements.txt
+.\venv\Scripts\pip install --no-deps .
+.\venv\Scripts\pip install --allow-external pyinstaller -r requirements-build.txt
+
+git rev-parse --short HEAD | out-file -encoding ASCII compose\GITSHA
+
+# Build binary
+.\venv\Scripts\pyinstaller .\docker-compose.spec
+$ErrorActionPreference = "Stop"
+
+Move-Item -Force .\dist\docker-compose.exe .\dist\docker-compose-Windows-x86_64.exe
+.\dist\docker-compose-Windows-x86_64.exe --version
diff --git a/script/build/write-git-sha b/script/build/write-git-sha
new file mode 100755
index 00000000..d16743c6
--- /dev/null
+++ b/script/build/write-git-sha
@@ -0,0 +1,7 @@
+#!/bin/bash
+#
+# Write the current commit sha to the file GITSHA. This file is included in
+# packaging so that `docker-compose version` can include the git sha.
+#
+set -e
+git rev-parse --short HEAD > compose/GITSHA
diff --git a/script/ci b/script/ci
new file mode 100755
index 00000000..34bf9a4b
--- /dev/null
+++ b/script/ci
@@ -0,0 +1,8 @@
+#!/bin/bash
+#
+# Backwards compatibility for jenkins
+#
+# TODO: remove this script after all current PRs and jenkins are updated with
+# the new script/test/ci change
+set -e
+exec script/test/ci
diff --git a/script/clean b/script/clean
new file mode 100755
index 00000000..fb7ba3be
--- /dev/null
+++ b/script/clean
@@ -0,0 +1,7 @@
+#!/bin/sh
+set -e
+
+find . -type f -name '*.pyc' -delete
+find . -name .coverage.* -delete
+find . -name __pycache__ -delete
+rm -rf docs/_site build dist docker-compose.egg-info
diff --git a/script/release/build-binaries b/script/release/build-binaries
new file mode 100755
index 00000000..a39b186d
--- /dev/null
+++ b/script/release/build-binaries
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# Build the release binaries
+#
+
+. "$(dirname "${BASH_SOURCE[0]}")/utils.sh"
+
+function usage() {
+ >&2 cat << EOM
+Build binaries for the release.
+
+This script requires that 'git config branch.${BRANCH}.release' is set to the
+release version for the release branch.
+
+EOM
+ exit 1
+}
+
+BRANCH="$(git rev-parse --abbrev-ref HEAD)"
+VERSION="$(git config "branch.${BRANCH}.release")" || usage
+REPO=docker/compose
+
+# Build the binaries
+script/clean
+script/build/linux
+
+echo "Building the container distribution"
+script/build/image $VERSION
+
+echo "Building the compose-tests image"
+script/build/test-image $VERSION
+
+echo "Create a github release"
+# TODO: script more of this https://developer.github.com/v3/repos/releases/
+browser https://github.com/$REPO/releases/new
+
+echo "Don't forget to download the osx and windows binaries from appveyor/bintray\!"
+echo "https://dl.bintray.com/docker-compose/$BRANCH/"
+echo "https://ci.appveyor.com/project/docker/compose"
+echo
diff --git a/script/release/cherry-pick-pr b/script/release/cherry-pick-pr
new file mode 100755
index 00000000..f4a5a740
--- /dev/null
+++ b/script/release/cherry-pick-pr
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Cherry-pick a PR into the release branch
+#
+
+set -e
+set -o pipefail
+
+
+function usage() {
+ >&2 cat << EOM
+Cherry-pick commits from a github pull request.
+
+Usage:
+
+ $0 <github PR number>
+EOM
+ exit 1
+}
+
+[ -n "$1" ] || usage
+
+if [ -z "$(command -v hub 2> /dev/null)" ]; then
+ >&2 echo "$0 requires https://hub.github.com/."
+ >&2 echo "Please install it and make sure it is available on your \$PATH."
+ exit 2
+fi
+
+
+REPO=docker/compose
+GITHUB=https://github.com/$REPO/pull
+PR=$1
+url="$GITHUB/$PR"
+hub am -3 $url
diff --git a/script/release/contributors b/script/release/contributors
new file mode 100755
index 00000000..4657dd80
--- /dev/null
+++ b/script/release/contributors
@@ -0,0 +1,30 @@
+#!/bin/bash
+set -e
+
+
+function usage() {
+ >&2 cat << EOM
+Print the list of github contributors for the release
+
+Usage:
+
+ $0 <previous release tag>
+EOM
+ exit 1
+}
+
+[[ -n "$1" ]] || usage
+PREV_RELEASE=$1
+BRANCH="$(git rev-parse --abbrev-ref HEAD)"
+URL="https://api.github.com/repos/docker/compose/compare"
+
+contribs=$(curl -sf "$URL/$PREV_RELEASE...$BRANCH" | \
+ jq -r '.commits[].author.login' | \
+ sort | \
+ uniq -c | \
+ sort -nr)
+
+echo "Contributions by user: "
+echo "$contribs"
+echo
+echo "$contribs" | awk '{print "@"$2","}' | xargs
diff --git a/script/release/download-binaries b/script/release/download-binaries
new file mode 100755
index 00000000..5d01f5f7
--- /dev/null
+++ b/script/release/download-binaries
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+function usage() {
+ >&2 cat << EOM
+Download Linux, Mac OS and Windows binaries from remote endpoints
+
+Usage:
+
+ $0 <version>
+
+Options:
+
+ version version string for the release (ex: 1.6.0)
+
+EOM
+ exit 1
+}
+
+
+[ -n "$1" ] || usage
+VERSION=$1
+BASE_BINTRAY_URL=https://dl.bintray.com/docker-compose/bump-$VERSION/
+DESTINATION=binaries-$VERSION
+APPVEYOR_URL=https://ci.appveyor.com/api/projects/docker/compose/\
+artifacts/dist%2Fdocker-compose-Windows-x86_64.exe?branch=bump-$VERSION
+
+mkdir $DESTINATION
+
+
+wget -O $DESTINATION/docker-compose-Darwin-x86_64 $BASE_BINTRAY_URL/docker-compose-Darwin-x86_64
+wget -O $DESTINATION/docker-compose-Linux-x86_64 $BASE_BINTRAY_URL/docker-compose-Linux-x86_64
+wget -O $DESTINATION/docker-compose-Windows-x86_64.exe $APPVEYOR_URL
diff --git a/script/release/make-branch b/script/release/make-branch
new file mode 100755
index 00000000..b8a0cd31
--- /dev/null
+++ b/script/release/make-branch
@@ -0,0 +1,86 @@
+#!/bin/bash
+#
+# Prepare a new release branch
+#
+
+. "$(dirname "${BASH_SOURCE[0]}")/utils.sh"
+
+function usage() {
+ >&2 cat << EOM
+Create a new release branch 'release-<version>'
+
+Usage:
+
+ $0 <version> [<base_version>]
+
+Options:
+
+ version version string for the release (ex: 1.6.0)
+ base_version branch or tag to start from. Defaults to master. For
+ bug-fix releases use the previous stage release tag.
+
+EOM
+ exit 1
+}
+
+
+[ -n "$1" ] || usage
+VERSION=$1
+BRANCH=bump-$VERSION
+REPO=docker/compose
+GITHUB_REPO=git@github.com:$REPO
+
+if [ -z "$2" ]; then
+ BASE_VERSION="master"
+else
+ BASE_VERSION=$2
+fi
+
+
+DEFAULT_REMOTE=release
+REMOTE="$(find_remote "$GITHUB_REPO")"
+# If we don't have a docker remote add one
+if [ -z "$REMOTE" ]; then
+ echo "Creating $DEFAULT_REMOTE remote"
+ git remote add ${DEFAULT_REMOTE} ${GITHUB_REPO}
+fi
+
+# handle the difference between a branch and a tag
+if [ -z "$(git name-rev --tags $BASE_VERSION | grep tags)" ]; then
+ BASE_VERSION=$REMOTE/$BASE_VERSION
+fi
+
+echo "Creating a release branch $VERSION from $BASE_VERSION"
+read -n1 -r -p "Continue? (ctrl+c to cancel)"
+git fetch $REMOTE -p
+git checkout -b $BRANCH $BASE_VERSION
+
+echo "Merging remote release branch into new release branch"
+git merge --strategy=ours --no-edit $REMOTE/release
+
+# Store the release version for this branch in git, so that other release
+# scripts can use it
+git config "branch.${BRANCH}.release" $VERSION
+
+
+editor=${EDITOR:-vim}
+
+echo "Update versions in compose/__init__.py, script/run/run.sh"
+$editor compose/__init__.py
+$editor script/run/run.sh
+
+
+echo "Write release notes in CHANGELOG.md"
+browser "https://github.com/docker/compose/issues?q=milestone%3A$VERSION+is%3Aclosed"
+$editor CHANGELOG.md
+
+
+git diff
+echo "Verify changes before commit. Exit the shell to commit changes"
+$SHELL || true
+git commit -a -m "Bump $VERSION" --signoff --no-verify
+
+
+echo "Push branch to docker remote"
+git push $REMOTE
+browser https://github.com/$REPO/compare/docker:release...$BRANCH?expand=1
diff --git a/script/release/push-release b/script/release/push-release
new file mode 100755
index 00000000..0578aaff
--- /dev/null
+++ b/script/release/push-release
@@ -0,0 +1,82 @@
+#!/bin/bash
+#
+# Create the official release
+#
+
+. "$(dirname "${BASH_SOURCE[0]}")/utils.sh"
+
+function usage() {
+ >&2 cat << EOM
+Publish a release by building all artifacts and pushing them.
+
+This script requires that 'git config branch.${BRANCH}.release' is set to the
+release version for the release branch.
+
+EOM
+ exit 1
+}
+
+BRANCH="$(git rev-parse --abbrev-ref HEAD)"
+VERSION="$(git config "branch.${BRANCH}.release")" || usage
+
+if [ -z "$(command -v jq 2> /dev/null)" ]; then
+ >&2 echo "$0 requires https://stedolan.github.io/jq/"
+ >&2 echo "Please install it and make sure it is available on your \$PATH."
+ exit 2
+fi
+
+
+if [ -z "$(command -v pandoc 2> /dev/null)" ]; then
+ >&2 echo "$0 requires http://pandoc.org/"
+ >&2 echo "Please install it and make sure it is available on your \$PATH."
+ exit 2
+fi
+
+API=https://api.github.com/repos
+REPO=docker/compose
+GITHUB_REPO=git@github.com:$REPO
+
+# Check the build status is green
+sha=$(git rev-parse HEAD)
+url=$API/$REPO/statuses/$sha
+build_status=$(curl -s $url | jq -r '.[0].state')
+if [ -n "$SKIP_BUILD_CHECK" ]; then
+ echo "Skipping build status check..."
+elif [[ "$build_status" != "success" ]]; then
+ >&2 echo "Build status is $build_status, but it should be success."
+ exit -1
+fi
+
+echo "Tagging the release as $VERSION"
+git tag $VERSION
+git push $GITHUB_REPO $VERSION
+
+echo "Uploading the docker image"
+docker push docker/compose:$VERSION
+
+echo "Uploading the compose-tests image"
+docker push docker/compose-tests:latest
+docker push docker/compose-tests:$VERSION
+
+echo "Uploading package to PyPI"
+pandoc -f markdown -t rst README.md -o README.rst
+sed -i -e 's/logo.png?raw=true/https:\/\/github.com\/docker\/compose\/raw\/master\/logo.png?raw=true/' README.rst
+./script/build/write-git-sha
+python setup.py sdist bdist_wheel
+if [ "$(command -v twine 2> /dev/null)" ]; then
+ twine upload ./dist/docker-compose-${VERSION/-/}.tar.gz ./dist/docker_compose-${VERSION/-/}-py2.py3-none-any.whl
+else
+ python setup.py upload
+fi
+
+echo "Testing pip package"
+deactivate || true
+virtualenv venv-test
+source venv-test/bin/activate
+pip install docker-compose==$VERSION
+docker-compose version
+deactivate
+rm -rf venv-test
+
+echo "Now publish the github release, and test the downloads."
+echo "Email maintainers@dockerproject.org and engineering@docker.com about the new release."
diff --git a/script/release/rebase-bump-commit b/script/release/rebase-bump-commit
new file mode 100755
index 00000000..3c2ae72b
--- /dev/null
+++ b/script/release/rebase-bump-commit
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# Move the "bump to <version>" commit to the HEAD of the branch
+#
+
+. "$(dirname "${BASH_SOURCE[0]}")/utils.sh"
+
+function usage() {
+ >&2 cat << EOM
+Move the "bump to <version>" commit to the HEAD of the branch
+
+This script requires that 'git config branch.${BRANCH}.release' is set to the
+release version for the release branch.
+
+EOM
+ exit 1
+}
+
+
+BRANCH="$(git rev-parse --abbrev-ref HEAD)"
+VERSION="$(git config "branch.${BRANCH}.release")" || usage
+
+
+COMMIT_MSG="Bump $VERSION"
+sha="$(git log --grep "$COMMIT_MSG\$" --format="%H")"
+if [ -z "$sha" ]; then
+ >&2 echo "No commit with message \"$COMMIT_MSG\""
+ exit 2
+fi
+if [[ "$sha" == "$(git rev-parse HEAD)" ]]; then
+ >&2 echo "Bump commit already at HEAD"
+ exit 0
+fi
+
+commits=$(git log --format="%H" "$sha..HEAD" | wc -l | xargs echo)
+
+git rebase --onto $sha~1 HEAD~$commits $BRANCH
+git cherry-pick $sha
diff --git a/script/release/utils.sh b/script/release/utils.sh
new file mode 100644
index 00000000..321c1fb7
--- /dev/null
+++ b/script/release/utils.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+#
+# Util functions for release scripts
+#
+
+set -e
+set -o pipefail
+
+
+function browser() {
+ local url=$1
+ xdg-open $url || open $url
+}
+
+
+function find_remote() {
+ local url=$1
+ for remote in $(git remote); do
+ git config --get remote.${remote}.url | grep $url > /dev/null && echo -n $remote
+ done
+ # Always return true, extra remotes cause it to return false
+ true
+}
diff --git a/script/run/run.ps1 b/script/run/run.ps1
new file mode 100644
index 00000000..47ec5469
--- /dev/null
+++ b/script/run/run.ps1
@@ -0,0 +1,22 @@
+# Run docker-compose in a container via boot2docker.
+#
+# The current directory will be mirrored as a volume and additional
+# volumes (or any other options) can be mounted by using
+# $Env:DOCKER_COMPOSE_OPTIONS.
+
+if ($Env:DOCKER_COMPOSE_VERSION -eq $null -or $Env:DOCKER_COMPOSE_VERSION.Length -eq 0) {
+ $Env:DOCKER_COMPOSE_VERSION = "latest"
+}
+
+if ($Env:DOCKER_COMPOSE_OPTIONS -eq $null) {
+ $Env:DOCKER_COMPOSE_OPTIONS = ""
+}
+
+if (-not $Env:DOCKER_HOST) {
+ docker-machine env --shell=powershell default | Invoke-Expression
+ if (-not $?) { exit $LastExitCode }
+}
+
+$local="/$($PWD -replace '^(.):(.*)$', '"$1".ToLower()+"$2".Replace("\","/")' | Invoke-Expression)"
+docker run --rm -ti -v /var/run/docker.sock:/var/run/docker.sock -v "${local}:$local" -w "$local" $Env:DOCKER_COMPOSE_OPTIONS "docker/compose:$Env:DOCKER_COMPOSE_VERSION" $args
+exit $LastExitCode
diff --git a/script/run/run.sh b/script/run/run.sh
new file mode 100755
index 00000000..58483196
--- /dev/null
+++ b/script/run/run.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Run docker-compose in a container
+#
+# This script will attempt to mirror the host paths by using volumes for the
+# following paths:
+# * $(pwd)
+# * $(dirname $COMPOSE_FILE) if it's set
+# * $HOME if it's set
+#
+# You can add additional volumes (or any docker run options) using
+# the $COMPOSE_OPTIONS environment variable.
+#
+
+
+set -e
+
+VERSION="1.17.1"
+IMAGE="docker/compose:$VERSION"
+
+
+# Setup options for connecting to docker host
+if [ -z "$DOCKER_HOST" ]; then
+ DOCKER_HOST="/var/run/docker.sock"
+fi
+if [ -S "$DOCKER_HOST" ]; then
+ DOCKER_ADDR="-v $DOCKER_HOST:$DOCKER_HOST -e DOCKER_HOST"
+else
+ DOCKER_ADDR="-e DOCKER_HOST -e DOCKER_TLS_VERIFY -e DOCKER_CERT_PATH"
+fi
+
+
+# Setup volume mounts for compose config and context
+if [ "$(pwd)" != '/' ]; then
+ VOLUMES="-v $(pwd):$(pwd)"
+fi
+if [ -n "$COMPOSE_FILE" ]; then
+ COMPOSE_OPTIONS="$COMPOSE_OPTIONS -e COMPOSE_FILE=$COMPOSE_FILE"
+ compose_dir=$(realpath $(dirname $COMPOSE_FILE))
+fi
+# TODO: also check --file argument
+if [ -n "$compose_dir" ]; then
+ VOLUMES="$VOLUMES -v $compose_dir:$compose_dir"
+fi
+if [ -n "$HOME" ]; then
+ VOLUMES="$VOLUMES -v $HOME:$HOME -v $HOME:/root" # mount $HOME in /root to share docker.config
+fi
+
+# Only allocate tty if we detect one
+if [ -t 1 ]; then
+ DOCKER_RUN_OPTIONS="-t"
+fi
+if [ -t 0 ]; then
+ DOCKER_RUN_OPTIONS="$DOCKER_RUN_OPTIONS -i"
+fi
+
+exec docker run --rm $DOCKER_RUN_OPTIONS $DOCKER_ADDR $COMPOSE_OPTIONS $VOLUMES -w "$(pwd)" $IMAGE "$@"
diff --git a/script/setup/osx b/script/setup/osx
new file mode 100755
index 00000000..e0c2bd0a
--- /dev/null
+++ b/script/setup/osx
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+set -ex
+
+python_version() {
+ python -V 2>&1
+}
+
+openssl_version() {
+ python -c "import ssl; print ssl.OPENSSL_VERSION"
+}
+
+desired_python_version="2.7.12"
+desired_python_brew_version="2.7.12"
+python_formula="https://raw.githubusercontent.com/Homebrew/homebrew-core/737a2e34a89b213c1f0a2a24fc1a3c06635eed04/Formula/python.rb"
+
+desired_openssl_version="1.0.2j"
+desired_openssl_brew_version="1.0.2j"
+openssl_formula="https://raw.githubusercontent.com/Homebrew/homebrew-core/30d3766453347f6e22b3ed6c74bb926d6def2eb5/Formula/openssl.rb"
+
+PATH="/usr/local/bin:$PATH"
+
+if !(which brew); then
+ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+fi
+
+brew update > /dev/null
+
+if !(python_version | grep "$desired_python_version"); then
+ if brew list | grep python; then
+ brew unlink python
+ fi
+
+ brew install "$python_formula"
+ brew switch python "$desired_python_brew_version"
+fi
+
+if !(openssl_version | grep "$desired_openssl_version"); then
+ if brew list | grep openssl; then
+ brew unlink openssl
+ fi
+
+ brew install "$openssl_formula"
+ brew switch openssl "$desired_openssl_brew_version"
+fi
+
+echo "*** Using $(python_version)"
+echo "*** Using $(openssl_version)"
+
+if !(which virtualenv); then
+ pip install virtualenv
+fi
diff --git a/script/test/all b/script/test/all
new file mode 100755
index 00000000..1200c496
--- /dev/null
+++ b/script/test/all
@@ -0,0 +1,64 @@
+#!/bin/bash
+# This should be run inside a container built from the Dockerfile
+# at the root of the repo - script/test will do it automatically.
+
+set -e
+
+>&2 echo "Running lint checks"
+docker run --rm \
+ --tty \
+ ${GIT_VOLUME} \
+ --entrypoint="tox" \
+ "$TAG" -e pre-commit
+
+get_versions="docker run --rm
+ --entrypoint=/code/.tox/py27/bin/python
+ $TAG
+ /code/script/test/versions.py docker/docker-ce,moby/moby"
+
+if [ "$DOCKER_VERSIONS" == "" ]; then
+ DOCKER_VERSIONS="$($get_versions default)"
+elif [ "$DOCKER_VERSIONS" == "all" ]; then
+ DOCKER_VERSIONS=$($get_versions -n 2 recent)
+fi
+
+
+BUILD_NUMBER=${BUILD_NUMBER-$USER}
+PY_TEST_VERSIONS=${PY_TEST_VERSIONS:-py27,py34}
+
+for version in $DOCKER_VERSIONS; do
+ >&2 echo "Running tests against Docker $version"
+
+ daemon_container="compose-dind-$version-$BUILD_NUMBER"
+
+ function on_exit() {
+ if [[ "$?" != "0" ]]; then
+ docker logs "$daemon_container" 2>&1 | tail -n 100
+ fi
+ docker rm -vf "$daemon_container"
+ }
+
+ trap "on_exit" EXIT
+
+ repo="dockerswarm/dind"
+
+ docker run \
+ -d \
+ --name "$daemon_container" \
+ --privileged \
+ --volume="/var/lib/docker" \
+ "$repo:$version" \
+ dockerd -H tcp://0.0.0.0:2375 $DOCKER_DAEMON_ARGS \
+ 2>&1 | tail -n 10
+
+ docker run \
+ --rm \
+ --tty \
+ --link="$daemon_container:docker" \
+ --env="DOCKER_HOST=tcp://docker:2375" \
+ --env="DOCKER_VERSION=$version" \
+ --entrypoint="tox" \
+ "$TAG" \
+ -e "$PY_TEST_VERSIONS" -- "$@"
+
+done
diff --git a/script/test/ci b/script/test/ci
new file mode 100755
index 00000000..c5927b2c
--- /dev/null
+++ b/script/test/ci
@@ -0,0 +1,25 @@
+#!/bin/bash
+# This should be run inside a container built from the Dockerfile
+# at the root of the repo:
+#
+# $ TAG="docker-compose:$(git rev-parse --short HEAD)"
+# $ docker build -t "$TAG" .
+# $ docker run --rm \
+# --volume="/var/run/docker.sock:/var/run/docker.sock" \
+# --volume="$(pwd)/.git:/code/.git" \
+# -e "TAG=$TAG" \
+# --entrypoint="script/test/ci" "$TAG"
+
+set -ex
+
+docker version
+
+export DOCKER_VERSIONS=all
+STORAGE_DRIVER=${STORAGE_DRIVER:-overlay}
+export DOCKER_DAEMON_ARGS="--storage-driver=$STORAGE_DRIVER"
+
+GIT_VOLUME="--volumes-from=$(hostname)"
+. script/test/all
+
+>&2 echo "Building Linux binary"
+. script/build/linux-entrypoint
diff --git a/script/test/default b/script/test/default
new file mode 100755
index 00000000..aabb4e42
--- /dev/null
+++ b/script/test/default
@@ -0,0 +1,19 @@
+#!/bin/bash
+# See CONTRIBUTING.md for usage.
+
+set -ex
+
+TAG="docker-compose:$(git rev-parse --short HEAD)"
+
+# By default use the Dockerfile, but can be overriden to use an alternative file
+# e.g DOCKERFILE=Dockerfile.armhf script/test/default
+DOCKERFILE="${DOCKERFILE:-Dockerfile}"
+
+rm -rf coverage-html
+# Create the host directory so it's owned by $USER
+mkdir -p coverage-html
+
+docker build -f ${DOCKERFILE} -t "$TAG" .
+
+GIT_VOLUME="--volume=$(pwd)/.git:/code/.git"
+. script/test/all
diff --git a/script/test/versions.py b/script/test/versions.py
new file mode 100755
index 00000000..46872ed9
--- /dev/null
+++ b/script/test/versions.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python
+"""
+Query the github API for the git tags of a project, and return a list of
+version tags for recent releases, or the default release.
+
+The default release is the most recent non-RC version.
+
+Recent is a list of unique major.minor versions, where each is the most
+recent version in the series.
+
+For example, if the list of versions is:
+
+ 1.8.0-rc2
+ 1.8.0-rc1
+ 1.7.1
+ 1.7.0
+ 1.7.0-rc1
+ 1.6.2
+ 1.6.1
+
+`default` would return `1.7.1` and
+`recent -n 3` would return `1.8.0-rc2 1.7.1 1.6.2`
+"""
+from __future__ import absolute_import
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import argparse
+import itertools
+import operator
+import sys
+from collections import namedtuple
+
+import requests
+
+
+GITHUB_API = 'https://api.github.com/repos'
+
+
+class Version(namedtuple('_Version', 'major minor patch rc edition')):
+
+ @classmethod
+ def parse(cls, version):
+ edition = None
+ version = version.lstrip('v')
+ version, _, rc = version.partition('-')
+ if rc:
+ if 'rc' not in rc:
+ edition = rc
+ rc = None
+ elif '-' in rc:
+ edition, rc = rc.split('-')
+
+ major, minor, patch = version.split('.', 3)
+ return cls(major, minor, patch, rc, edition)
+
+ @property
+ def major_minor(self):
+ return self.major, self.minor
+
+ @property
+ def order(self):
+ """Return a representation that allows this object to be sorted
+ correctly with the default comparator.
+ """
+ # rc releases should appear before official releases
+ rc = (0, self.rc) if self.rc else (1, )
+ return (int(self.major), int(self.minor), int(self.patch)) + rc
+
+ def __str__(self):
+ rc = '-{}'.format(self.rc) if self.rc else ''
+ edition = '-{}'.format(self.edition) if self.edition else ''
+ return '.'.join(map(str, self[:3])) + edition + rc
+
+
+def group_versions(versions):
+ """Group versions by `major.minor` releases.
+
+ Example:
+
+ >>> group_versions([
+ Version(1, 0, 0),
+ Version(2, 0, 0, 'rc1'),
+ Version(2, 0, 0),
+ Version(2, 1, 0),
+ ])
+
+ [
+ [Version(1, 0, 0)],
+ [Version(2, 0, 0), Version(2, 0, 0, 'rc1')],
+ [Version(2, 1, 0)],
+ ]
+ """
+ return list(
+ list(releases)
+ for _, releases
+ in itertools.groupby(versions, operator.attrgetter('major_minor'))
+ )
+
+
+def get_latest_versions(versions, num=1):
+ """Return a list of the most recent versions for each major.minor version
+ group.
+ """
+ versions = group_versions(versions)
+ num = min(len(versions), num)
+ return [versions[index][0] for index in range(num)]
+
+
+def get_default(versions):
+ """Return a :class:`Version` for the latest non-rc version."""
+ for version in versions:
+ if not version.rc:
+ return version
+
+
+def get_versions(tags):
+ for tag in tags:
+ try:
+ yield Version.parse(tag['name'])
+ except ValueError:
+ print("Skipping invalid tag: {name}".format(**tag), file=sys.stderr)
+
+
+def get_github_releases(projects):
+ """Query the Github API for a list of version tags and return them in
+ sorted order.
+
+ See https://developer.github.com/v3/repos/#list-tags
+ """
+ versions = []
+ for project in projects:
+ url = '{}/{}/tags'.format(GITHUB_API, project)
+ response = requests.get(url)
+ response.raise_for_status()
+ versions.extend(get_versions(response.json()))
+ return sorted(versions, reverse=True, key=operator.attrgetter('order'))
+
+
+def parse_args(argv):
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('project', help="Github project name (ex: docker/docker)")
+ parser.add_argument('command', choices=['recent', 'default'])
+ parser.add_argument('-n', '--num', type=int, default=2,
+ help="Number of versions to return from `recent`")
+ return parser.parse_args(argv)
+
+
+def main(argv=None):
+ args = parse_args(argv)
+ versions = get_github_releases(args.project.split(','))
+
+ if args.command == 'recent':
+ print(' '.join(map(str, get_latest_versions(versions, args.num))))
+ elif args.command == 'default':
+ print(get_default(versions))
+ else:
+ raise ValueError("Unknown command {}".format(args.command))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/script/travis/bintray.json.tmpl b/script/travis/bintray.json.tmpl
new file mode 100644
index 00000000..f9728558
--- /dev/null
+++ b/script/travis/bintray.json.tmpl
@@ -0,0 +1,29 @@
+{
+ "package": {
+ "name": "${TRAVIS_OS_NAME}",
+ "repo": "${TRAVIS_BRANCH}",
+ "subject": "docker-compose",
+ "desc": "Automated build of master branch from travis ci.",
+ "website_url": "https://github.com/docker/compose",
+ "issue_tracker_url": "https://github.com/docker/compose/issues",
+ "vcs_url": "https://github.com/docker/compose.git",
+ "licenses": ["Apache-2.0"]
+ },
+
+ "version": {
+ "name": "${TRAVIS_BRANCH}",
+ "desc": "Automated build of the ${TRAVIS_BRANCH} branch.",
+ "released": "${DATE}",
+ "vcs_tag": "master"
+ },
+
+ "files": [
+ {
+ "includePattern": "dist/(.*)",
+ "excludePattern": ".*\.tar.gz",
+ "uploadPattern": "$1",
+ "matrixParams": { "override": 1 }
+ }
+ ],
+ "publish": true
+}
diff --git a/script/travis/build-binary b/script/travis/build-binary
new file mode 100755
index 00000000..7707a1ee
--- /dev/null
+++ b/script/travis/build-binary
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -ex
+
+if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+ script/build/linux
+ # TODO: requires auth to push, so disable for now
+ # script/build/image master
+ # docker push docker/compose:master
+else
+ script/setup/osx
+ script/build/osx
+fi
diff --git a/script/travis/ci b/script/travis/ci
new file mode 100755
index 00000000..cd4fcc6d
--- /dev/null
+++ b/script/travis/ci
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -e
+
+if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+ tox -e py27,py34 -- tests/unit
+else
+ # TODO: we could also install py34 and test against it
+ tox -e py27 -- tests/unit
+fi
diff --git a/script/travis/install b/script/travis/install
new file mode 100755
index 00000000..d4b34786
--- /dev/null
+++ b/script/travis/install
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -ex
+
+if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+ pip install tox==2.1.1
+else
+ sudo pip install --upgrade pip tox==2.1.1 virtualenv
+ pip --version
+fi
diff --git a/script/travis/render-bintray-config.py b/script/travis/render-bintray-config.py
new file mode 100755
index 00000000..b5364a0b
--- /dev/null
+++ b/script/travis/render-bintray-config.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+from __future__ import absolute_import
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import datetime
+import os.path
+import sys
+
+os.environ['DATE'] = str(datetime.date.today())
+
+for line in sys.stdin:
+ print(os.path.expandvars(line), end='')