diff --git a/CHANGES.md b/CHANGES.md index 78e629b89..1f43d88d4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,15 @@ Change log ========== +1.3.1 (2015-06-21) +------------------ + +The following bugs have been fixed: + +- `docker-compose build` would always attempt to pull the base image before building. +- `docker-compose help migrate-to-labels` failed with an error. +- If no network mode was specified, Compose would set it to "bridge", rather than allowing the Docker daemon to use its configured default network mode. + 1.3.0 (2015-06-18) ------------------ diff --git a/compose/__init__.py b/compose/__init__.py index 9e4c3fdb2..f3ec6acb0 100644 --- a/compose/__init__.py +++ b/compose/__init__.py @@ -1,3 +1,3 @@ from __future__ import unicode_literals -__version__ = '1.3.0' +__version__ = '1.3.1' diff --git a/compose/cli/docopt_command.py b/compose/cli/docopt_command.py index ee6947012..6eeb33a31 100644 --- a/compose/cli/docopt_command.py +++ b/compose/cli/docopt_command.py @@ -33,12 +33,7 @@ class DocoptCommand(object): if command is None: raise SystemExit(getdoc(self)) - command = command.replace('-', '_') - - if not hasattr(self, command): - raise NoSuchCommand(command, self) - - handler = getattr(self, command) + handler = self.get_handler(command) docstring = getdoc(handler) if docstring is None: @@ -47,6 +42,14 @@ class DocoptCommand(object): command_options = docopt_full_help(docstring, options['ARGS'], options_first=True) return options, handler, command_options + def get_handler(self, command): + command = command.replace('-', '_') + + if not hasattr(self, command): + raise NoSuchCommand(command, self) + + return getattr(self, command) + class NoSuchCommand(Exception): def __init__(self, command, supercommand): diff --git a/compose/cli/main.py b/compose/cli/main.py index 4f3f11e4e..8aeb0459d 100644 --- a/compose/cli/main.py +++ b/compose/cli/main.py @@ -128,10 +128,8 @@ class TopLevelCommand(Command): Usage: help COMMAND """ - command = options['COMMAND'] - if not hasattr(self, command): - raise NoSuchCommand(command, self) - raise SystemExit(getdoc(getattr(self, command))) + handler = self.get_handler(options['COMMAND']) + raise SystemExit(getdoc(handler)) def kill(self, project, options): """ @@ -485,6 +483,24 @@ class TopLevelCommand(Command): """ Recreate containers to add labels + If you're coming from Compose 1.2 or earlier, you'll need to remove or + migrate your existing containers after upgrading Compose. This is + because, as of version 1.3, Compose uses Docker labels to keep track + of containers, and so they need to be recreated with labels added. + + If Compose detects containers that were created without labels, it + will refuse to run so that you don't end up with two sets of them. If + you want to keep using your existing containers (for example, because + they have data volumes you want to preserve) you can migrate them with + the following command: + + docker-compose migrate-to-labels + + Alternatively, if you're not worried about keeping them, you can + remove them - Compose will just create new ones. + + docker rm -f myapp_web_1 myapp_db_1 ... + Usage: migrate-to-labels """ legacy.migrate_project_to_labels(project) diff --git a/compose/project.py b/compose/project.py index bc093628c..6446a6d33 100644 --- a/compose/project.py +++ b/compose/project.py @@ -178,7 +178,7 @@ class Project(object): del service_dict['net'] else: - net = 'bridge' + net = None return net diff --git a/compose/service.py b/compose/service.py index 1e91a9f23..6c2cc4da5 100644 --- a/compose/service.py +++ b/compose/service.py @@ -473,7 +473,7 @@ class Service(object): def _get_net(self): if not self.net: - return "bridge" + return None if isinstance(self.net, Service): containers = self.net.containers() @@ -628,6 +628,7 @@ class Service(object): tag=self.image_name, stream=True, rm=True, + pull=False, nocache=no_cache, dockerfile=self.options.get('dockerfile', None), ) diff --git a/docs/install.md b/docs/install.md index a608d8fe7..96a4a2376 100644 --- a/docs/install.md +++ b/docs/install.md @@ -27,7 +27,7 @@ First, install Docker version 1.6 or greater: To install Compose, run the following commands: - curl -L https://github.com/docker/compose/releases/download/1.3.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose + curl -L https://github.com/docker/compose/releases/download/1.3.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose > Note: If you get a "Permission denied" error, your `/usr/local/bin` directory probably isn't writable and you'll need to install Compose as the superuser. Run `sudo -i`, then the two commands above, then `exit`. diff --git a/tests/unit/cli_test.py b/tests/unit/cli_test.py index 3173a274d..d10cb9b30 100644 --- a/tests/unit/cli_test.py +++ b/tests/unit/cli_test.py @@ -11,6 +11,7 @@ import mock from compose.cli import main from compose.cli.main import TopLevelCommand +from compose.cli.docopt_command import NoSuchCommand from compose.cli.errors import ComposeFileNotFound from compose.service import Service @@ -101,6 +102,22 @@ class CLITestCase(unittest.TestCase): with self.assertRaises(SystemExit): command.dispatch(['-h'], None) + def test_command_help(self): + with self.assertRaises(SystemExit) as ctx: + TopLevelCommand().dispatch(['help', 'up'], None) + + self.assertIn('Usage: up', str(ctx.exception)) + + def test_command_help_dashes(self): + with self.assertRaises(SystemExit) as ctx: + TopLevelCommand().dispatch(['help', 'migrate-to-labels'], None) + + self.assertIn('Usage: migrate-to-labels', str(ctx.exception)) + + def test_command_help_nonexistent(self): + with self.assertRaises(NoSuchCommand): + TopLevelCommand().dispatch(['help', 'nonexistent'], None) + def test_setup_logging(self): main.setup_logging() self.assertEqual(logging.getLogger().level, logging.DEBUG) diff --git a/tests/unit/project_test.py b/tests/unit/project_test.py index fc49e9b88..9ee6f28c3 100644 --- a/tests/unit/project_test.py +++ b/tests/unit/project_test.py @@ -209,6 +209,18 @@ class ProjectTest(unittest.TestCase): ], None) self.assertEqual(project.get_service('test')._get_volumes_from(), container_ids) + def test_net_unset(self): + mock_client = mock.create_autospec(docker.Client) + project = Project.from_dicts('test', [ + { + 'name': 'test', + 'image': 'busybox:latest', + } + ], mock_client) + service = project.get_service('test') + self.assertEqual(service._get_net(), None) + self.assertNotIn('NetworkMode', service._get_container_host_config({})) + def test_use_net_from_container(self): container_id = 'aabbccddee' container_dict = dict(Name='aaa', Id=container_id) diff --git a/tests/unit/service_test.py b/tests/unit/service_test.py index fb3a7fcbb..88d301470 100644 --- a/tests/unit/service_test.py +++ b/tests/unit/service_test.py @@ -303,6 +303,17 @@ class ServiceTest(unittest.TestCase): with self.assertRaises(NeedsBuildError): service.create_container(do_build=False) + def test_build_does_not_pull(self): + self.mock_client.build.return_value = [ + '{"stream": "Successfully built 12345"}', + ] + + service = Service('foo', client=self.mock_client, build='.') + service.build() + + self.assertEqual(self.mock_client.build.call_count, 1) + self.assertFalse(self.mock_client.build.call_args[1]['pull']) + class ServiceVolumesTest(unittest.TestCase):