Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly support interactive Subversion client #6515

Merged
merged 19 commits into from
May 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b47bc7a
Properly support interactive Subversion features based on Subversion …
johnthagen May 20, 2019
60019ae
Add news entry
johnthagen May 20, 2019
9c85436
Fix tests
johnthagen May 20, 2019
3cab748
Set use_interactive=False to avoid having to mock
johnthagen May 20, 2019
1361456
Explain why use_interactive is set to False in unit tests
johnthagen May 21, 2019
00efe18
Remove unnecessary get_remote_call_options() invocation for local `sv…
johnthagen May 21, 2019
a708240
Document why get_remote_call_options is not needed for svn info invoc…
johnthagen May 22, 2019
fcbefc0
Merge branch 'master' into svn-interactive-final
johnthagen May 22, 2019
5100f81
Improve news file
johnthagen May 23, 2019
034e483
Merge remote-tracking branch 'origin/svn-interactive-final' into svn-…
johnthagen May 23, 2019
6c5da6b
Remove unnecessary pytest.mark.network from tests that use mocked svn…
johnthagen May 23, 2019
b9c8394
Fix PEP8 error
johnthagen May 23, 2019
eb3db3b
Add type hints to methods to improve documentation and type safety
johnthagen May 23, 2019
128730f
Add tests for fetch_new, switch, and update
johnthagen May 23, 2019
a4aff3b
Use a TestCase to remove some duplication across similar tests
johnthagen May 24, 2019
8de73a1
Use bare strings in test assertion
johnthagen May 25, 2019
c90e632
Simplify test method names
johnthagen May 25, 2019
ae03f49
Fold obtain and export tests into TestSubversionArgs TestCase
johnthagen May 25, 2019
920b95f
Add test with non-trivial RevOptions input
johnthagen May 25, 2019
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
2 changes: 2 additions & 0 deletions news/6386.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Extend to Subversion 1.8+ the behavior of calling Subversion in
interactive mode when pip is run interactively.
22 changes: 18 additions & 4 deletions src/pip/_internal/vcs/subversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

if MYPY_CHECK_RUNNING:
from typing import List, Optional, Tuple
from pip._internal.vcs import RevOptions

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -48,26 +49,34 @@ def export(self, location, url):
# Subversion doesn't like to check out over an existing
# directory --force fixes this, but was only added in svn 1.5
rmtree(location)
cmd_args = ['export'] + rev_options.to_args() + [url, location]
cmd_args = (['export'] + self.get_remote_call_options() +
rev_options.to_args() + [url, location])
self.run_command(cmd_args, show_stdout=False)

def fetch_new(self, dest, url, rev_options):
# type: (str, str, RevOptions) -> None
rev_display = rev_options.to_display()
logger.info(
'Checking out %s%s to %s',
url,
rev_display,
display_path(dest),
)
cmd_args = ['checkout', '-q'] + rev_options.to_args() + [url, dest]
cmd_args = (['checkout', '-q'] +
self.get_remote_call_options() +
rev_options.to_args() + [url, dest])
self.run_command(cmd_args)

def switch(self, dest, url, rev_options):
cmd_args = ['switch'] + rev_options.to_args() + [url, dest]
# type: (str, str, RevOptions) -> None
cmd_args = (['switch'] + self.get_remote_call_options() +
rev_options.to_args() + [url, dest])
self.run_command(cmd_args)

def update(self, dest, url, rev_options):
cmd_args = ['update'] + rev_options.to_args() + [dest]
# type: (str, str, RevOptions) -> None
cmd_args = (['update'] + self.get_remote_call_options() +
rev_options.to_args() + [dest])
self.run_command(cmd_args)

@classmethod
Expand Down Expand Up @@ -177,6 +186,11 @@ def _get_svn_url_rev(cls, location):
else:
try:
# subversion >= 1.7
# Note that using get_remote_call_options is not necessary here
# because `svn info` is being run against a local directory.
# We don't need to worry about making sure interactive mode
# is being used to prompt for passwords, because passwords
# are only potentially needed for remote server requests.
xml = cls.run_command(
['info', '--xml', location],
show_stdout=False,
Expand Down
86 changes: 61 additions & 25 deletions tests/functional/test_install_vcs_svn.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,66 @@
import pytest
from unittest import TestCase

from mock import patch

from pip._internal.vcs import RevOptions
from pip._internal.vcs.subversion import Subversion


@patch('pip._internal.vcs.call_subprocess')
@pytest.mark.network
def test_obtain_should_recognize_auth_info_url(call_subprocess_mock, script):
url = 'svn+http://username:[email protected]/'
svn = Subversion()
svn.obtain(script.scratch_path / 'test', url=url)
assert call_subprocess_mock.call_args[0][0] == [
svn.name, 'checkout', '-q', '--username', 'username', '--password',
'password', 'http://svn.example.com/',
script.scratch_path / 'test',
]


@patch('pip._internal.vcs.call_subprocess')
@pytest.mark.network
def test_export_should_recognize_auth_info_url(call_subprocess_mock, script):
url = 'svn+http://username:[email protected]/'
svn = Subversion()
svn.export(script.scratch_path / 'test', url=url)
assert call_subprocess_mock.call_args[0][0] == [
svn.name, 'export', '--username', 'username', '--password',
'password', 'http://svn.example.com/',
script.scratch_path / 'test',
]
class TestSubversionArgs(TestCase):
def setUp(self):
patcher = patch('pip._internal.vcs.call_subprocess')
self.addCleanup(patcher.stop)
self.call_subprocess_mock = patcher.start()

# Test Data.
self.url = 'svn+http://username:[email protected]/'
# use_interactive is set to False to test that remote call options are
# properly added.
self.svn = Subversion(use_interactive=False)
self.rev_options = RevOptions(Subversion)
johnthagen marked this conversation as resolved.
Show resolved Hide resolved
self.dest = '/tmp/test'

def assert_call_args(self, args):
assert self.call_subprocess_mock.call_args[0][0] == args

def test_obtain(self):
self.svn.obtain(self.dest, self.url)
self.assert_call_args(
['svn', 'checkout', '-q', '--non-interactive', '--username',
'username', '--password', 'password',
'http://svn.example.com/', '/tmp/test'])

def test_export(self):
self.svn.export(self.dest, self.url)
self.assert_call_args(
['svn', 'export', '--non-interactive', '--username', 'username',
'--password', 'password', 'http://svn.example.com/',
'/tmp/test'])

def test_fetch_new(self):
self.svn.fetch_new(self.dest, self.url, self.rev_options)
self.assert_call_args(
['svn', 'checkout', '-q', '--non-interactive',
'svn+http://username:[email protected]/',
'/tmp/test'])

def test_fetch_new_revision(self):
rev_options = RevOptions(Subversion, '123')
self.svn.fetch_new(self.dest, self.url, rev_options)
self.assert_call_args(
['svn', 'checkout', '-q', '--non-interactive',
'-r', '123',
'svn+http://username:[email protected]/',
'/tmp/test'])

def test_switch(self):
self.svn.switch(self.dest, self.url, self.rev_options)
self.assert_call_args(
['svn', 'switch', '--non-interactive',
'svn+http://username:[email protected]/',
'/tmp/test'])

def test_update(self):
self.svn.update(self.dest, self.url, self.rev_options)
self.assert_call_args(
['svn', 'update', '--non-interactive', '/tmp/test'])