Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: fix path mounting when running in Docker
Currently pre-commit mounts the current directory to /src and uses current directory name as mount base. However this does not work when pre-commit is run inside the container on some mounted path already, because mount points are relative to the host, not to the container. Fixes #1387
- Loading branch information
Oleg Kainov
committed
Apr 27, 2021
1 parent
60bf370
commit 237334c
Showing
2 changed files
with
166 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,144 @@ | ||
import builtins | ||
import json | ||
from typing import List | ||
from unittest import mock | ||
|
||
import pytest | ||
|
||
from pre_commit.languages import docker | ||
|
||
|
||
def test_docker_fallback_user(): | ||
def invalid_attribute(): | ||
raise AttributeError | ||
|
||
with mock.patch.multiple( | ||
'os', create=True, | ||
getuid=invalid_attribute, | ||
getgid=invalid_attribute, | ||
'os', create=True, | ||
getuid=invalid_attribute, | ||
getgid=invalid_attribute, | ||
): | ||
assert docker.get_docker_user() == () | ||
|
||
|
||
class TestInDocker: | ||
|
||
@pytest.fixture | ||
def mock_file_fixture(self): | ||
return lambda read_data: mock.patch.object( | ||
builtins, 'open', | ||
new_callable=mock.mock_open, | ||
read_data=read_data, | ||
) | ||
|
||
def test_in_docker_no_file(self, mock_file_fixture): | ||
with mock_file_fixture(None) as m: | ||
m.side_effect = FileNotFoundError | ||
|
||
assert docker._is_in_docker() is False | ||
m.assert_called() | ||
|
||
def test_in_docker_docker_in_file(self, mock_file_fixture): | ||
with mock_file_fixture(b'tdockert'): | ||
assert docker._is_in_docker() is True | ||
|
||
def test_in_docker_docker_not_in_file(self, mock_file_fixture): | ||
with mock_file_fixture(b'testtest'): | ||
assert docker._is_in_docker() is False | ||
|
||
|
||
class TestDockerPath: | ||
@pytest.fixture | ||
def in_docker(self): | ||
with mock.patch.object(docker, '_is_in_docker', return_value=True): | ||
yield | ||
|
||
@pytest.fixture | ||
def not_in_docker(self): | ||
with mock.patch.object(docker, '_is_in_docker', return_value=False): | ||
yield | ||
|
||
def test_not_in_docker_returns_same(self, not_in_docker): | ||
assert docker._get_docker_path('abc') == 'abc' | ||
|
||
def test_in_docker_no_binds_same_path(self, in_docker): | ||
binds_list: List[str] = [] | ||
output_string = json.dumps( | ||
[{'HostConfig': {'Binds': binds_list}}], | ||
).encode('utf-8') | ||
with mock.patch.object( | ||
docker, 'cmd_output_b', | ||
return_value=(0, output_string, b''), | ||
): | ||
assert docker._get_docker_path('abc') == 'abc' | ||
|
||
def test_in_docker_binds_path_equal(self, in_docker): | ||
binds_list = [ | ||
'/opt/my_code:/project', | ||
] | ||
output_string = json.dumps( | ||
[{'HostConfig': {'Binds': binds_list}}], | ||
).encode('utf-8') | ||
with mock.patch.object( | ||
docker, 'cmd_output_b', | ||
return_value=(0, output_string, b''), | ||
): | ||
assert docker._get_docker_path('/project') == '/opt/my_code' | ||
|
||
def test_in_docker_binds_path_complex(self, in_docker): | ||
binds_list = [ | ||
'/opt/my_code:/project', | ||
] | ||
output_string = json.dumps( | ||
[{'HostConfig': {'Binds': binds_list}}], | ||
).encode('utf-8') | ||
with mock.patch.object( | ||
docker, 'cmd_output_b', | ||
return_value=(0, output_string, b''), | ||
): | ||
path = '/project/test/something' | ||
expected = '/opt/my_code/test/something' | ||
assert docker._get_docker_path(path) == expected | ||
|
||
def test_in_docker_no_substring(self, in_docker): | ||
binds_list = [ | ||
'/opt/my_code:/project', | ||
] | ||
output_string = json.dumps( | ||
[{'HostConfig': {'Binds': binds_list}}], | ||
).encode('utf-8') | ||
with mock.patch.object( | ||
docker, 'cmd_output_b', | ||
return_value=(0, output_string, b''), | ||
): | ||
path = '/projectSUffix/test/something' | ||
assert docker._get_docker_path(path) == path | ||
|
||
def test_in_docker_binds_path_many_binds(self, in_docker): | ||
binds_list = [ | ||
'/something_random:/not_related', | ||
'/opt/my_code:/project', | ||
'/something_random2:/not_related2', | ||
] | ||
output_string = json.dumps( | ||
[{'HostConfig': {'Binds': binds_list}}], | ||
).encode('utf-8') | ||
with mock.patch.object( | ||
docker, 'cmd_output_b', | ||
return_value=(0, output_string, b''), | ||
): | ||
assert docker._get_docker_path('/project') == '/opt/my_code' | ||
|
||
def test_in_docker_two_colons(self, in_docker): | ||
binds_list = [ | ||
'/opt/my_code:/project:qqqrandom', | ||
] | ||
output_string = json.dumps( | ||
[{'HostConfig': {'Binds': binds_list}}], | ||
).encode('utf-8') | ||
with mock.patch.object( | ||
docker, 'cmd_output_b', | ||
return_value=(0, output_string, b''), | ||
): | ||
path = '/project/test/something' | ||
expected = '/opt/my_code/test/something' | ||
assert docker._get_docker_path(path) == expected |