From 507376549cc8c999109bd25b60ddf1e70429277a Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 27 Apr 2018 12:24:43 -0700 Subject: [PATCH 01/20] Improve release automation Signed-off-by: Joffrey F --- script/release/release.py | 17 +++++++++++------ script/release/release.sh | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/script/release/release.py b/script/release/release.py index add8fb2d3..4357e36b9 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -78,10 +78,9 @@ def monitor_pr_status(pr_data): continue summary[detail.state] += 1 print('{pending} pending, {success} successes, {failure} failures'.format(**summary)) - if status.total_count == 0: - # Mostly for testing purposes against repos with no CI setup - return True - elif summary['pending'] == 0 and summary['failure'] == 0: + if summary['pending'] == 0 and summary['failure'] == 0 and summary['success'] > 0: + # This check assumes at least 1 non-DCO CI check to avoid race conditions. + # If testing on a repo without CI, use --skip-ci-check to avoid looping eternally return True elif summary['failure'] > 0: raise ScriptError('CI failures detected!') @@ -156,7 +155,8 @@ def resume(args): if not pr_data: pr_data = repository.create_release_pull_request(args.release) check_pr_mergeable(pr_data) - monitor_pr_status(pr_data) + if not args.skip_ci: + monitor_pr_status(pr_data) downloader = BinaryDownloader(args.destination) files = downloader.download_all(args.release) if not gh_release: @@ -195,7 +195,8 @@ def start(args): create_initial_branch(repository, args) pr_data = repository.create_release_pull_request(args.release) check_pr_mergeable(pr_data) - monitor_pr_status(pr_data) + if not args.skip_ci: + monitor_pr_status(pr_data) downloader = BinaryDownloader(args.destination) files = downloader.download_all(args.release) gh_release = create_release_draft(repository, args.release, pr_data, files) @@ -310,6 +311,10 @@ def main(): '--no-cherries', '-C', dest='cherries', action='store_false', help='If set, the program will not prompt the user for PR numbers to cherry-pick' ) + parser.add_argument( + '--skip-ci-checks', dest='skip_ci', action='store_true', + help='If set, the program will not wait for CI jobs to complete' + ) args = parser.parse_args() if args.action == 'start': diff --git a/script/release/release.sh b/script/release/release.sh index 2310429aa..f592365d3 100755 --- a/script/release/release.sh +++ b/script/release/release.sh @@ -19,6 +19,7 @@ docker run -e GITHUB_TOKEN=$GITHUB_TOKEN -e BINTRAY_TOKEN=$BINTRAY_TOKEN -it \ --mount type=bind,source=$(pwd),target=/src \ --mount type=bind,source=$(pwd)/.git,target=/src/.git \ --mount type=bind,source=$HOME/.docker,target=/root/.docker \ + --mount type=bind,source=$HOME/.gitconfig,target=/root/.gitconfig --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ --mount type=bind,source=$HOME/.ssh,target=/root/.ssh \ -v $HOME/.pypirc:/root/.pypirc \ From 7b4603dc22823fefb2cf3143d7017d261649c4a9 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 27 Apr 2018 14:35:13 -0700 Subject: [PATCH 02/20] Finalize fixes Signed-off-by: Joffrey F --- script/release/Dockerfile | 3 ++- script/release/release.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/script/release/Dockerfile b/script/release/Dockerfile index 0d4ec27e1..e5af676a5 100644 --- a/script/release/Dockerfile +++ b/script/release/Dockerfile @@ -3,7 +3,8 @@ RUN mkdir -p /src && pip install -U Jinja2==2.10 \ PyGithub==1.39 \ pypandoc==1.4 \ GitPython==2.1.9 \ - requests==2.18.4 && \ + requests==2.18.4 \ + twine==1.11.0 && \ apt-get update && apt-get install -y pandoc VOLUME /src/script/release diff --git a/script/release/release.py b/script/release/release.py index 4357e36b9..d0545a7e6 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -27,6 +27,7 @@ from release.utils import ScriptError from release.utils import update_init_py_version from release.utils import update_run_sh_version from release.utils import yesno +from twine.commands.upload import main as twine_upload def create_initial_branch(repository, args): @@ -240,8 +241,8 @@ def finalize(args): if not merge_status.merged: raise ScriptError('Unable to merge PR #{}: {}'.format(pr_data.number, merge_status.message)) print('Uploading to PyPi') - run_setup(os.path.join(REPO_ROOT, 'setup.py'), script_args=['upload']) - img_manager.push_images(args.release) + twine_upload(['dist/*']) + img_manager.push_images() repository.publish_release(gh_release) except ScriptError as e: print(e) From d3ca20074d5eebaec9f9417bbb1f5655731bb113 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 27 Apr 2018 18:36:48 -0700 Subject: [PATCH 03/20] Automatically detect pickable PRs for patch releases Signed-off-by: Joffrey F --- script/release/release.py | 9 +++++++++ script/release/release/repository.py | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/script/release/release.py b/script/release/release.py index d0545a7e6..e9a52c4aa 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -34,6 +34,15 @@ def create_initial_branch(repository, args): release_branch = repository.create_release_branch(args.release, args.base) if args.base and args.cherries: print('Detected patch version.') + auto_prs = repository.get_prs_in_milestone(args.release) + if auto_prs: + print( + 'Found the following PRs in this release\'s milestone: {}'.format(', '.join(auto_prs)) + ) + proceed = yesno('Automatically cherry-pick detected PRs? Y/n', default=True) + if proceed: + repository.cherry_pick_prs(release_branch, auto_prs) + cherries = input('Indicate (space-separated) PR numbers to cherry-pick then press Enter:\n') repository.cherry_pick_prs(release_branch, cherries.split()) diff --git a/script/release/release/repository.py b/script/release/release/repository.py index d4d1c7201..9a5d432c0 100644 --- a/script/release/release/repository.py +++ b/script/release/release/repository.py @@ -196,6 +196,24 @@ class Repository(object): f.flush() self.git_repo.git.am('--3way', f.name) + def get_prs_in_milestone(self, version): + milestones = self.gh_repo.get_milestones(state='open') + milestone = None + for ms in milestones: + if ms.title == version: + milestone = ms + break + if not milestone: + print('Didn\'t find a milestone matching "{}"'.format(version)) + return None + + issues = self.gh_repo.get_issues(milestone=milestone, state='all') + prs = [] + for issue in issues: + if issue.pull_request is not None: + prs.append(issue.number) + return sorted(prs) + def get_contributors(pr_data): commits = pr_data.get_commits() From d8b4b945859bebea6e5f30abc9b298d0a5381fbd Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 27 Apr 2018 18:43:05 -0700 Subject: [PATCH 04/20] Typo fix Signed-off-by: Joffrey F --- script/release/release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/release/release.sh b/script/release/release.sh index f592365d3..affbce37b 100755 --- a/script/release/release.sh +++ b/script/release/release.sh @@ -19,7 +19,7 @@ docker run -e GITHUB_TOKEN=$GITHUB_TOKEN -e BINTRAY_TOKEN=$BINTRAY_TOKEN -it \ --mount type=bind,source=$(pwd),target=/src \ --mount type=bind,source=$(pwd)/.git,target=/src/.git \ --mount type=bind,source=$HOME/.docker,target=/root/.docker \ - --mount type=bind,source=$HOME/.gitconfig,target=/root/.gitconfig + --mount type=bind,source=$HOME/.gitconfig,target=/root/.gitconfig \ --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ --mount type=bind,source=$HOME/.ssh,target=/root/.ssh \ -v $HOME/.pypirc:/root/.pypirc \ From f05f1699c4325153e98813d2d740a0727113cf2c Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 27 Apr 2018 18:48:30 -0700 Subject: [PATCH 05/20] Partial revert bc034415501 Signed-off-by: Joffrey F --- script/release/release.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/script/release/release.py b/script/release/release.py index e9a52c4aa..d0545a7e6 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -34,15 +34,6 @@ def create_initial_branch(repository, args): release_branch = repository.create_release_branch(args.release, args.base) if args.base and args.cherries: print('Detected patch version.') - auto_prs = repository.get_prs_in_milestone(args.release) - if auto_prs: - print( - 'Found the following PRs in this release\'s milestone: {}'.format(', '.join(auto_prs)) - ) - proceed = yesno('Automatically cherry-pick detected PRs? Y/n', default=True) - if proceed: - repository.cherry_pick_prs(release_branch, auto_prs) - cherries = input('Indicate (space-separated) PR numbers to cherry-pick then press Enter:\n') repository.cherry_pick_prs(release_branch, cherries.split()) From 064471e640e2fbf5594844cd1845dfaf3a3cc611 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Tue, 1 May 2018 17:11:14 -0700 Subject: [PATCH 06/20] iprange -> ip_range Signed-off-by: Joffrey F --- compose/config/config_schema_v2.0.json | 2 +- compose/config/config_schema_v2.1.json | 2 +- compose/config/config_schema_v2.2.json | 2 +- compose/config/config_schema_v2.3.json | 2 +- compose/config/config_schema_v2.4.json | 2 +- tests/unit/config/config_test.py | 32 ++++++++++++++++++++++++++ 6 files changed, 37 insertions(+), 5 deletions(-) diff --git a/compose/config/config_schema_v2.0.json b/compose/config/config_schema_v2.0.json index 793cef1d6..419f2e28c 100644 --- a/compose/config/config_schema_v2.0.json +++ b/compose/config/config_schema_v2.0.json @@ -311,7 +311,7 @@ "type": "object", "properties": { "subnet": {"type": "string"}, - "iprange": {"type": "string"}, + "ip_range": {"type": "string"}, "gateway": {"type": "string"}, "aux_addresses": { "type": "object", diff --git a/compose/config/config_schema_v2.1.json b/compose/config/config_schema_v2.1.json index 5ea763544..3cb1ee213 100644 --- a/compose/config/config_schema_v2.1.json +++ b/compose/config/config_schema_v2.1.json @@ -365,7 +365,7 @@ "type": "object", "properties": { "subnet": {"type": "string"}, - "iprange": {"type": "string"}, + "ip_range": {"type": "string"}, "gateway": {"type": "string"}, "aux_addresses": { "type": "object", diff --git a/compose/config/config_schema_v2.2.json b/compose/config/config_schema_v2.2.json index a19d4c945..8e1f288ba 100644 --- a/compose/config/config_schema_v2.2.json +++ b/compose/config/config_schema_v2.2.json @@ -374,7 +374,7 @@ "type": "object", "properties": { "subnet": {"type": "string"}, - "iprange": {"type": "string"}, + "ip_range": {"type": "string"}, "gateway": {"type": "string"}, "aux_addresses": { "type": "object", diff --git a/compose/config/config_schema_v2.3.json b/compose/config/config_schema_v2.3.json index 78b716a7a..659dbcd1a 100644 --- a/compose/config/config_schema_v2.3.json +++ b/compose/config/config_schema_v2.3.json @@ -418,7 +418,7 @@ "type": "object", "properties": { "subnet": {"type": "string"}, - "iprange": {"type": "string"}, + "ip_range": {"type": "string"}, "gateway": {"type": "string"}, "aux_addresses": { "type": "object", diff --git a/compose/config/config_schema_v2.4.json b/compose/config/config_schema_v2.4.json index a5796d5b1..47e118755 100644 --- a/compose/config/config_schema_v2.4.json +++ b/compose/config/config_schema_v2.4.json @@ -417,7 +417,7 @@ "type": "object", "properties": { "subnet": {"type": "string"}, - "iprange": {"type": "string"}, + "ip_range": {"type": "string"}, "gateway": {"type": "string"}, "aux_addresses": { "type": "object", diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index 4562a99ca..085a2d010 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -1344,6 +1344,38 @@ class ConfigTest(unittest.TestCase): assert ('networks.foo.ipam.config contains an invalid type,' ' it should be an object') in excinfo.exconly() + def test_config_valid_ipam_config(self): + ipam_config = { + 'subnet': '172.28.0.0/16', + 'ip_range': '172.28.5.0/24', + 'gateway': '172.28.5.254', + 'aux_addresses': { + 'host1': '172.28.1.5', + 'host2': '172.28.1.6', + 'host3': '172.28.1.7', + }, + } + networks = config.load( + build_config_details( + { + 'version': str(V2_1), + 'networks': { + 'foo': { + 'driver': 'default', + 'ipam': { + 'driver': 'default', + 'config': [ipam_config], + } + } + } + }, + filename='filename.yml', + ) + ).networks + + assert 'foo' in networks + assert networks['foo']['ipam']['config'] == [ipam_config] + def test_config_valid_service_names(self): for valid_name in ['_', '-', '.__.', '_what-up.', 'what_.up----', 'whatup']: services = config.load( From 7db742d3f2be826af002a4a20aded8fe7cf19374 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Sat, 28 Apr 2018 13:42:24 -0700 Subject: [PATCH 07/20] Esnure docker-compose binary is executable (fixes #5917) Signed-off-by: Joffrey F --- script/release/release/images.py | 1 + 1 file changed, 1 insertion(+) diff --git a/script/release/release/images.py b/script/release/release/images.py index 0c7bb2045..d238d4d7f 100644 --- a/script/release/release/images.py +++ b/script/release/release/images.py @@ -23,6 +23,7 @@ class ImageManager(object): distdir = os.path.join(REPO_ROOT, 'dist') os.makedirs(distdir, exist_ok=True) shutil.copy(files['docker-compose-Linux-x86_64'][0], distdir) + os.chmod(os.path.join(distdir, 'docker-compose-Linux-x86_64'), 0o755) print('Building docker/compose image') logstream = docker_client.build( REPO_ROOT, tag='docker/compose:{}'.format(self.version), dockerfile='Dockerfile.run', From f336694912ad603022063b8f5f142d7d7c259c76 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Wed, 2 May 2018 00:30:30 +0000 Subject: [PATCH 08/20] "Bump 1.21.2" Signed-off-by: Joffrey F --- CHANGELOG.md | 8 ++++++++ compose/__init__.py | 2 +- script/run/run.sh | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18742324f..b92117d16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ Change log ========== +1.21.2 (2018-05-03) +------------------- + +### Bugfixes + +- Fixed a bug where the ip_range attirbute in IPAM configs was prevented + from passing validation + 1.21.1 (2018-04-27) ------------------- diff --git a/compose/__init__.py b/compose/__init__.py index 6baeabc14..34974e804 100644 --- a/compose/__init__.py +++ b/compose/__init__.py @@ -1,4 +1,4 @@ from __future__ import absolute_import from __future__ import unicode_literals -__version__ = '1.21.1' +__version__ = '1.21.2' diff --git a/script/run/run.sh b/script/run/run.sh index 45e74febd..60e06996b 100755 --- a/script/run/run.sh +++ b/script/run/run.sh @@ -15,7 +15,7 @@ set -e -VERSION="1.21.1" +VERSION="1.21.2" IMAGE="docker/compose:$VERSION" From a133471152a3449920ee9f80e8b89e7e7328444c Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 20 Apr 2018 15:29:37 -0700 Subject: [PATCH 09/20] Fix appveyor build Signed-off-by: Joffrey F --- script/build/windows.ps1 | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/script/build/windows.ps1 b/script/build/windows.ps1 index 98a748158..1de9bbfa4 100644 --- a/script/build/windows.ps1 +++ b/script/build/windows.ps1 @@ -44,16 +44,10 @@ virtualenv .\venv # pip and pyinstaller generate lots of warnings, so we need to ignore them $ErrorActionPreference = "Continue" -# Install dependencies -# Fix for https://github.com/pypa/pip/issues/3964 -# Remove-Item -Recurse -Force .\venv\Lib\site-packages\pip -# .\venv\Scripts\easy_install pip==9.0.1 -# .\venv\Scripts\pip install --upgrade pip setuptools -# End fix .\venv\Scripts\pip install pypiwin32==220 .\venv\Scripts\pip install -r requirements.txt .\venv\Scripts\pip install --no-deps . -.\venv\Scripts\pip install --allow-external pyinstaller -r requirements-build.txt +.\venv\Scripts\pip install -r requirements-build.txt git rev-parse --short HEAD | out-file -encoding ASCII compose\GITSHA From e8af19daa32b5b5ccbad966df425b57cd3926299 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Thu, 21 Jun 2018 13:27:42 -0700 Subject: [PATCH 10/20] Fix release script Signed-off-by: Joffrey F --- script/release/release.py | 7 +++++-- script/release/release/bintray.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/script/release/release.py b/script/release/release.py index d0545a7e6..476adc4c3 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -58,8 +58,11 @@ def create_bump_commit(repository, release_branch, bintray_user, bintray_org): repository.push_branch_to_remote(release_branch) bintray_api = BintrayAPI(os.environ['BINTRAY_TOKEN'], bintray_user) - print('Creating data repository {} on bintray'.format(release_branch.name)) - bintray_api.create_repository(bintray_org, release_branch.name, 'generic') + if not bintray_api.repository_exists(bintray_org, release_branch.name): + print('Creating data repository {} on bintray'.format(release_branch.name)) + bintray_api.create_repository(bintray_org, release_branch.name, 'generic') + else: + print('Bintray repository {} already exists. Skipping'.format(release_branch.name)) def monitor_pr_status(pr_data): diff --git a/script/release/release/bintray.py b/script/release/release/bintray.py index 554611a40..d9986875d 100644 --- a/script/release/release/bintray.py +++ b/script/release/release/bintray.py @@ -29,6 +29,16 @@ class BintrayAPI(requests.Session): result.raise_for_status() return result + def repository_exists(self, subject, repo_name): + url = '{base}/repos/{subject}/{repo_name}'.format( + base=self.base_url, subject=subject, repo_name=repo_name, + ) + result = self.get(url) + if result.status_code == 404: + return False + result.raise_for_status() + return True + def delete_repository(self, subject, repo_name): url = '{base}/repos/{subject}/{repo_name}'.format( base=self.base_url, subject=subject, repo_name=repo_name, From 1fb50395850295adf405243e7f093107fc55301a Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Thu, 21 Jun 2018 18:48:04 +0000 Subject: [PATCH 11/20] Bump 1.22.0-rc1 Signed-off-by: Joffrey F --- CHANGELOG.md | 57 +++++++++++++++++++++++++++++++++++++++++++++ compose/__init__.py | 2 +- script/run/run.sh | 2 +- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18742324f..b5a22aad2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,63 @@ Change log ========== +1.22.0 (2018-06-30) +------------------- + +### Features + +#### Compose format version 3.7 + +- Introduced version 3.7 of the `docker-compose.yml` specification. + This version requires Docker Engine 18.06.0 or above. + +- Added support for `rollback_config` in the deploy configuration + +- Added support for the `init` parameter in service configurations + +- Added support for extension fields in service, network, volume, secret, + and config configurations + +#### Compose format version 2.4 + +- Added support for extension fields in service, network, + and volume configurations + +### Bugfixes + +- Fixed a bug that prevented deployment with some Compose files when + `DOCKER_DEFAULT_PLATFORM` was set + +- Compose will no longer try to create containers or volumes with + invalid starting characters + +- Fixed several bugs that prevented Compose commands from working properly + with containers created with an older version of Compose + +- Fixed an issue with the output of `docker-compose config` with the + `--compatibility-mode` flag enabled when the source file contains + attachable networks + +- Fixed a bug that prevented the `gcloud` credential store from working + properly when used with the Compose binary on UNIX + +- Fixed a bug that caused connection errors when trying to operate + over a non-HTTPS TCP connection on Windows + +- Fixed a bug that caused builds to fail on Windows if the Dockerfile + was located in a subdirectory of the build context + +- Fixed an issue that prevented proper parsing of UTF-8 BOM encoded + Compose files on Windows + +1.21.2 (2018-05-03) +------------------- + +### Bugfixes + +- Fixed a bug where the ip_range attirbute in IPAM configs was prevented + from passing validation + 1.21.1 (2018-04-27) ------------------- diff --git a/compose/__init__.py b/compose/__init__.py index 5eb2efd03..eb7195176 100644 --- a/compose/__init__.py +++ b/compose/__init__.py @@ -1,4 +1,4 @@ from __future__ import absolute_import from __future__ import unicode_literals -__version__ = '1.22.0dev' +__version__ = '1.22.0-rc1' diff --git a/script/run/run.sh b/script/run/run.sh index 45e74febd..86679bbec 100755 --- a/script/run/run.sh +++ b/script/run/run.sh @@ -15,7 +15,7 @@ set -e -VERSION="1.21.1" +VERSION="1.22.0-rc1" IMAGE="docker/compose:$VERSION" From e7de1bc3c9c9f7d65b1bf7f58136154618c90db1 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Thu, 21 Jun 2018 13:47:44 -0700 Subject: [PATCH 12/20] 3.7 --> API v1.38 Signed-off-by: Joffrey F --- compose/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose/const.py b/compose/const.py index 374a09711..ffb68db01 100644 --- a/compose/const.py +++ b/compose/const.py @@ -52,7 +52,7 @@ API_VERSIONS = { COMPOSEFILE_V3_4: '1.30', COMPOSEFILE_V3_5: '1.30', COMPOSEFILE_V3_6: '1.36', - COMPOSEFILE_V3_7: '1.36', + COMPOSEFILE_V3_7: '1.38', } API_VERSION_TO_ENGINE_VERSION = { From 969525c1903fc12c37b89fad80c2860a9a5e4d61 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 29 Jun 2018 13:05:20 -0700 Subject: [PATCH 13/20] Docker SDK -> 3.4.1 Signed-off-by: Joffrey F --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 05b38526a..a3d6e02d6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ backports.ssl-match-hostname==3.5.0.1; python_version < '3' cached-property==1.3.0 certifi==2017.4.17 chardet==3.0.4 -docker==3.4.0 +docker==3.4.1 docker-pycreds==0.3.0 dockerpty==0.4.1 docopt==0.6.2 diff --git a/setup.py b/setup.py index fc024078e..e0a26b0ec 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ install_requires = [ 'requests >= 2.6.1, != 2.11.0, != 2.12.2, != 2.18.0, < 2.19', 'texttable >= 0.9.0, < 0.10', 'websocket-client >= 0.32.0, < 1.0', - 'docker >= 3.4.0, < 4.0', + 'docker >= 3.4.1, < 4.0', 'dockerpty >= 0.4.1, < 0.5', 'six >= 1.3.0, < 2', 'jsonschema >= 2.5.1, < 3', From 15718810c07bc8251682809d7ab1501fc50d2c08 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Fri, 22 Jun 2018 15:56:53 -0700 Subject: [PATCH 14/20] Prevent attempts to create image names starting with - or _ Signed-off-by: Joffrey F --- compose/service.py | 4 +++- tests/integration/service_test.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/compose/service.py b/compose/service.py index 48cbc1702..e77780fd8 100644 --- a/compose/service.py +++ b/compose/service.py @@ -363,7 +363,9 @@ class Service(object): @property def image_name(self): - return self.options.get('image', '{s.project}_{s.name}'.format(s=self)) + return self.options.get('image', '{project}_{s.name}'.format( + s=self, project=self.project.lstrip('_-') + )) @property def platform(self): diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py index d8f4d094a..88123152c 100644 --- a/tests/integration/service_test.py +++ b/tests/integration/service_test.py @@ -1137,6 +1137,21 @@ class ServiceTest(DockerClientTestCase): service.build() assert service.image() + def test_build_with_illegal_leading_chars(self): + base_dir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, base_dir) + with open(os.path.join(base_dir, 'Dockerfile'), 'w') as f: + f.write('FROM busybox\nRUN echo "Embodiment of Scarlet Devil"\n') + service = Service( + 'build_leading_slug', client=self.client, + project='___-composetest', build={ + 'context': text_type(base_dir) + } + ) + assert service.image_name == 'composetest_build_leading_slug' + service.build() + assert service.image() + def test_start_container_stays_unprivileged(self): service = self.create_service('web') container = create_and_start_container(service).inspect() From 6817b533a89da4925ac91e6e2c2a96306dc81042 Mon Sep 17 00:00:00 2001 From: Matthieu Nottale Date: Thu, 5 Jul 2018 15:10:31 +0000 Subject: [PATCH 15/20] "Bump 1.22.0-rc2" Signed-off-by: Matthieu Nottale --- CHANGELOG.md | 5 +++++ compose/__init__.py | 2 +- script/release/release.py | 7 ++----- script/release/release.sh | 1 + script/release/release/bintray.py | 14 +------------- script/run/run.sh | 2 +- 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5a22aad2..45cba0516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,11 @@ Change log - Fixed an issue that prevented proper parsing of UTF-8 BOM encoded Compose files on Windows +- Fixed an issue with handling of the double-wildcard (`**`) pattern in `.dockerignore` files when using `docker-compose build` + +- Fixed a bug that caused auth values in legacy `.dockercfg` files to be ignored +- `docker-compose build` will no longer attempt to create image names starting with an invalid character + 1.21.2 (2018-05-03) ------------------- diff --git a/compose/__init__.py b/compose/__init__.py index eb7195176..a76ca8177 100644 --- a/compose/__init__.py +++ b/compose/__init__.py @@ -1,4 +1,4 @@ from __future__ import absolute_import from __future__ import unicode_literals -__version__ = '1.22.0-rc1' +__version__ = '1.22.0-rc2' diff --git a/script/release/release.py b/script/release/release.py index 476adc4c3..d0545a7e6 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -58,11 +58,8 @@ def create_bump_commit(repository, release_branch, bintray_user, bintray_org): repository.push_branch_to_remote(release_branch) bintray_api = BintrayAPI(os.environ['BINTRAY_TOKEN'], bintray_user) - if not bintray_api.repository_exists(bintray_org, release_branch.name): - print('Creating data repository {} on bintray'.format(release_branch.name)) - bintray_api.create_repository(bintray_org, release_branch.name, 'generic') - else: - print('Bintray repository {} already exists. Skipping'.format(release_branch.name)) + print('Creating data repository {} on bintray'.format(release_branch.name)) + bintray_api.create_repository(bintray_org, release_branch.name, 'generic') def monitor_pr_status(pr_data): diff --git a/script/release/release.sh b/script/release/release.sh index 201182657..eddc315b7 100755 --- a/script/release/release.sh +++ b/script/release/release.sh @@ -17,6 +17,7 @@ fi docker run -e GITHUB_TOKEN=$GITHUB_TOKEN -e BINTRAY_TOKEN=$BINTRAY_TOKEN -e SSH_AUTH_SOCK=$SSH_AUTH_SOCK -it \ --mount type=bind,source=$(pwd),target=/src \ + --mount type=bind,source=$(pwd)/.git,target=/src/.git \ --mount type=bind,source=$HOME/.docker,target=/root/.docker \ --mount type=bind,source=$HOME/.gitconfig,target=/root/.gitconfig \ --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ diff --git a/script/release/release/bintray.py b/script/release/release/bintray.py index d9986875d..d99d372c6 100644 --- a/script/release/release/bintray.py +++ b/script/release/release/bintray.py @@ -25,19 +25,7 @@ class BintrayAPI(requests.Session): 'desc': 'Automated release for {}: {}'.format(NAME, repo_name), 'labels': ['docker-compose', 'docker', 'release-bot'], } - result = self.post_json(url, data) - result.raise_for_status() - return result - - def repository_exists(self, subject, repo_name): - url = '{base}/repos/{subject}/{repo_name}'.format( - base=self.base_url, subject=subject, repo_name=repo_name, - ) - result = self.get(url) - if result.status_code == 404: - return False - result.raise_for_status() - return True + return self.post_json(url, data) def delete_repository(self, subject, repo_name): url = '{base}/repos/{subject}/{repo_name}'.format( diff --git a/script/run/run.sh b/script/run/run.sh index 86679bbec..7f4acb765 100755 --- a/script/run/run.sh +++ b/script/run/run.sh @@ -15,7 +15,7 @@ set -e -VERSION="1.22.0-rc1" +VERSION="1.22.0-rc2" IMAGE="docker/compose:$VERSION" From cb1b88c4f857c3a0a4a4f1f07881f35c8dd41d9a Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Mon, 9 Jul 2018 15:46:56 -0400 Subject: [PATCH 16/20] s/release.py/release.sh/ Signed-off-by: Joffrey F --- script/release/release.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/script/release/release.py b/script/release/release.py index d0545a7e6..ab56c8c38 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -125,7 +125,7 @@ def print_final_instructions(args): "You're almost done! Please verify that everything is in order and " "you are ready to make the release public, then run the following " "command:\n{exe} -b {user} finalize {version}".format( - exe=sys.argv[0], user=args.bintray_user, version=args.release + exe='./script/release/release.sh', user=args.bintray_user, version=args.release ) ) @@ -260,13 +260,13 @@ ACTIONS = [ EPILOG = '''Example uses: * Start a new feature release (includes all changes currently in master) - release.py -b user start 1.23.0 + release.sh -b user start 1.23.0 * Start a new patch release - release.py -b user --patch 1.21.0 start 1.21.1 + release.sh -b user --patch 1.21.0 start 1.21.1 * Cancel / rollback an existing release draft - release.py -b user cancel 1.23.0 + release.sh -b user cancel 1.23.0 * Restart a previously aborted patch release - release.py -b user -p 1.21.0 resume 1.21.1 + release.sh -b user -p 1.21.0 resume 1.21.1 ''' From d9545a5909a8abba81f2cd4d11352075bde4326f Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Mon, 9 Jul 2018 16:19:17 -0400 Subject: [PATCH 17/20] Add distclean to remove old build files Signed-off-by: Joffrey F --- script/release/release.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/script/release/release.py b/script/release/release.py index ab56c8c38..54e792c4c 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import argparse import os +import shutil import sys import time from distutils.core import run_setup @@ -130,8 +131,37 @@ def print_final_instructions(args): ) +def distclean(): + print('Running distclean...') + dirs = [ + os.path.join(REPO_ROOT, 'build'), os.path.join(REPO_ROOT, 'dist'), + os.path.join(REPO_ROOT, 'docker-compose.egg-info') + ] + files = [] + for base, dirnames, fnames in os.walk(REPO_ROOT): + for fname in fnames: + path = os.path.normpath(os.path.join(base, fname)) + if fname.endswith('.pyc'): + files.append(path) + elif fname.startswith('.coverage.'): + files.append(path) + for dirname in dirnames: + path = os.path.normpath(os.path.join(base, dirname)) + if dirname == '__pycache__': + dirs.append(path) + elif dirname == '.coverage-binfiles': + dirs.append(path) + + for file in files: + os.unlink(file) + + for folder in dirs: + shutil.rmtree(folder, ignore_errors=True) + + def resume(args): try: + distclean() repository = Repository(REPO_ROOT, args.repo) br_name = branch_name(args.release) if not repository.branch_exists(br_name): @@ -183,6 +213,7 @@ def cancel(args): bintray_api = BintrayAPI(os.environ['BINTRAY_TOKEN'], args.bintray_user) print('Removing Bintray data repository for {}'.format(args.release)) bintray_api.delete_repository(args.bintray_org, branch_name(args.release)) + distclean() except ScriptError as e: print(e) return 1 @@ -191,6 +222,7 @@ def cancel(args): def start(args): + distclean() try: repository = Repository(REPO_ROOT, args.repo) create_initial_branch(repository, args) @@ -213,6 +245,7 @@ def start(args): def finalize(args): + distclean() try: repository = Repository(REPO_ROOT, args.repo) img_manager = ImageManager(args.release) From 8c0411910d7f26d3c781a67fe14f51d5feb22a1c Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Mon, 9 Jul 2018 16:25:06 -0400 Subject: [PATCH 18/20] Avoid unrelated file uploads with twine Signed-off-by: Joffrey F --- script/release/release.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/script/release/release.py b/script/release/release.py index 54e792c4c..8ff5fb0c6 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -274,7 +274,10 @@ def finalize(args): if not merge_status.merged: raise ScriptError('Unable to merge PR #{}: {}'.format(pr_data.number, merge_status.message)) print('Uploading to PyPi') - twine_upload(['dist/*']) + twine_upload([ + 'dist/docker_compose-{}*.whl'.format(args.release), + 'dist/docker-compose-{}*.tar.gz'.format(args.release) + ]) img_manager.push_images() repository.publish_release(gh_release) except ScriptError as e: From cda827cbfc6628ff0bf0b3ffa2f657d439436379 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Mon, 9 Jul 2018 16:51:01 -0400 Subject: [PATCH 19/20] Improve finalize robustness and allow resume using special --finalize-resume flag Signed-off-by: Joffrey F --- script/release/release.py | 37 ++++++++++++++++++++++++++------ script/release/release/images.py | 4 ++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/script/release/release.py b/script/release/release.py index 8ff5fb0c6..23b93a528 100755 --- a/script/release/release.py +++ b/script/release/release.py @@ -28,6 +28,7 @@ from release.utils import ScriptError from release.utils import update_init_py_version from release.utils import update_run_sh_version from release.utils import yesno +from requests.exceptions import HTTPError from twine.commands.upload import main as twine_upload @@ -159,6 +160,24 @@ def distclean(): shutil.rmtree(folder, ignore_errors=True) +def pypi_upload(args): + print('Uploading to PyPi') + try: + twine_upload([ + 'dist/docker_compose-{}*.whl'.format(args.release), + 'dist/docker-compose-{}*.tar.gz'.format(args.release) + ]) + except HTTPError as e: + if e.response.status_code == 400 and 'File already exists' in e.message: + if not args.finalize_resume: + raise ScriptError( + 'Package already uploaded on PyPi.' + ) + print('Skipping PyPi upload - package already uploaded') + else: + raise ScriptError('Unexpected HTTP error uploading package to PyPi: {}'.format(e)) + + def resume(args): try: distclean() @@ -271,13 +290,13 @@ def finalize(args): run_setup(os.path.join(REPO_ROOT, 'setup.py'), script_args=['sdist', 'bdist_wheel']) merge_status = pr_data.merge() - if not merge_status.merged: - raise ScriptError('Unable to merge PR #{}: {}'.format(pr_data.number, merge_status.message)) - print('Uploading to PyPi') - twine_upload([ - 'dist/docker_compose-{}*.whl'.format(args.release), - 'dist/docker-compose-{}*.tar.gz'.format(args.release) - ]) + if not merge_status.merged and not args.finalize_resume: + raise ScriptError( + 'Unable to merge PR #{}: {}'.format(pr_data.number, merge_status.message) + ) + + pypi_upload(args) + img_manager.push_images() repository.publish_release(gh_release) except ScriptError as e: @@ -352,6 +371,10 @@ def main(): '--skip-ci-checks', dest='skip_ci', action='store_true', help='If set, the program will not wait for CI jobs to complete' ) + parser.add_argument( + '--finalize-resume', dest='finalize_resume', action='store_true', + help='If set, finalize will continue through steps that have already been completed.' + ) args = parser.parse_args() if args.action == 'start': diff --git a/script/release/release/images.py b/script/release/release/images.py index 24672f2ba..b8f7ed3d6 100644 --- a/script/release/release/images.py +++ b/script/release/release/images.py @@ -81,3 +81,7 @@ class ImageManager(object): for chunk in logstream: if 'status' in chunk: print(chunk['status']) + if 'error' in chunk: + raise ScriptError( + 'Error pushing {name}: {err}'.format(name=name, err=chunk['error']) + ) From f46880fe9a459c69cb20ed80825d7f466e2fcf71 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Tue, 17 Jul 2018 22:48:24 +0000 Subject: [PATCH 20/20] "Bump 1.22.0" Signed-off-by: Joffrey F --- CHANGELOG.md | 2 +- compose/__init__.py | 2 +- script/run/run.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45cba0516..b791c1e08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ Change log ========== -1.22.0 (2018-06-30) +1.22.0 (2018-07-17) ------------------- ### Features diff --git a/compose/__init__.py b/compose/__init__.py index a76ca8177..10ae3675f 100644 --- a/compose/__init__.py +++ b/compose/__init__.py @@ -1,4 +1,4 @@ from __future__ import absolute_import from __future__ import unicode_literals -__version__ = '1.22.0-rc2' +__version__ = '1.22.0' diff --git a/script/run/run.sh b/script/run/run.sh index 7f4acb765..52ff9513f 100755 --- a/script/run/run.sh +++ b/script/run/run.sh @@ -15,7 +15,7 @@ set -e -VERSION="1.22.0-rc2" +VERSION="1.22.0" IMAGE="docker/compose:$VERSION"