Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 41 additions & 32 deletions compose/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ def run(self, options):
to the host.
-T Disable pseudo-tty allocation. By default `docker-compose run`
allocates a TTY.
-w, --workdir="" Working directory inside the container
"""
service = self.project.get_service(options['SERVICE'])
detach = options['-d']
Expand All @@ -537,45 +538,18 @@ def run(self, options):
"Please pass the -d flag when using `docker-compose run`."
)

if options['COMMAND']:
command = [options['COMMAND']] + options['ARGS']
else:
command = service.options.get('command')

container_options = {
'command': command,
'tty': not (detach or options['-T'] or not sys.stdin.isatty()),
'stdin_open': not detach,
'detach': detach,
}

if options['-e']:
container_options['environment'] = parse_environment(options['-e'])

if options['--entrypoint']:
container_options['entrypoint'] = options.get('--entrypoint')

if options['--rm']:
container_options['restart'] = None

if options['--user']:
container_options['user'] = options.get('--user')

if not options['--service-ports']:
container_options['ports'] = []

if options['--publish']:
container_options['ports'] = options.get('--publish')

if options['--publish'] and options['--service-ports']:
raise UserError(
'Service port mapping and manual port mapping '
'can not be used togather'
)

if options['--name']:
container_options['name'] = options['--name']
if options['COMMAND']:
command = [options['COMMAND']] + options['ARGS']
else:
command = service.options.get('command')

container_options = build_container_options(options, detach, command)
run_one_off_container(container_options, self.project, service, options)

def scale(self, options):
Expand Down Expand Up @@ -776,6 +750,41 @@ def build_action_from_opts(options):
return BuildAction.none


def build_container_options(options, detach, command):
container_options = {
'command': command,
'tty': not (detach or options['-T'] or not sys.stdin.isatty()),
'stdin_open': not detach,
'detach': detach,
}

if options['-e']:
container_options['environment'] = parse_environment(options['-e'])

if options['--entrypoint']:
container_options['entrypoint'] = options.get('--entrypoint')

if options['--rm']:
container_options['restart'] = None

if options['--user']:
container_options['user'] = options.get('--user')

if not options['--service-ports']:
container_options['ports'] = []

if options['--publish']:
container_options['ports'] = options.get('--publish')

if options['--name']:
container_options['name'] = options['--name']

if options['--workdir']:
container_options['working_dir'] = options['--workdir']

return container_options


def run_one_off_container(container_options, project, service, options):
if not options['--no-deps']:
deps = service.get_dependency_names()
Expand Down
1 change: 1 addition & 0 deletions docs/reference/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Options:
-p, --publish=[] Publish a container's port(s) to the host
--service-ports Run command with the service's ports enabled and mapped to the host.
-T Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY.
-w, --workdir="" Working directory inside the container
```

Runs a one-time command against a service. For example, the following command starts the `web` service and runs `bash` as its command.
Expand Down
18 changes: 18 additions & 0 deletions tests/acceptance/cli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,24 @@ def test_run_with_custom_name(self):
container, = service.containers(stopped=True, one_off=True)
self.assertEqual(container.name, name)

def test_run_service_with_workdir_overridden(self):
self.base_dir = 'tests/fixtures/run-workdir'
name = 'service'
workdir = '/var'
self.dispatch(['run', '--workdir={workdir}'.format(workdir=workdir), name])
service = self.project.get_service(name)
container = service.containers(stopped=True, one_off=True)[0]
self.assertEqual(workdir, container.get('Config.WorkingDir'))

def test_run_service_with_workdir_overridden_short_form(self):
self.base_dir = 'tests/fixtures/run-workdir'
name = 'service'
workdir = '/var'
self.dispatch(['run', '-w', workdir, name])
service = self.project.get_service(name)
container = service.containers(stopped=True, one_off=True)[0]
self.assertEqual(workdir, container.get('Config.WorkingDir'))

@v2_only()
def test_run_interactive_connects_to_network(self):
self.base_dir = 'tests/fixtures/networks'
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/run-workdir/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
service:
image: busybox:latest
working_dir: /etc
command: /bin/true
3 changes: 3 additions & 0 deletions tests/unit/cli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def test_run_interactive_passes_logs_false(self, mock_pseudo_terminal, mock_run_
'--publish': [],
'--rm': None,
'--name': None,
'--workdir': None,
})

_, _, call_kwargs = mock_run_operation.mock_calls[0]
Expand Down Expand Up @@ -135,6 +136,7 @@ def test_run_service_with_restart_always(self):
'--publish': [],
'--rm': None,
'--name': None,
'--workdir': None,
})

self.assertEquals(
Expand All @@ -156,6 +158,7 @@ def test_run_service_with_restart_always(self):
'--publish': [],
'--rm': True,
'--name': None,
'--workdir': None,
})

self.assertFalse(
Expand Down