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

[bugfix] Preserve the explicit value None for SCM attributes with a different default #8622

Merged
merged 1 commit into from Mar 10, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions conans/model/scm.py
Expand Up @@ -38,7 +38,7 @@ def __init__(self, conanfile):
data = getattr(conanfile, "scm")
self.type = _get_dict_value(data, "type", string_types)
self.url = _get_dict_value(data, "url", string_types)
self.revision = _get_dict_value(data, "revision", string_types + (int, ),
self.revision = _get_dict_value(data, "revision", string_types + (int,),
disallowed_type=bool) # bool is subclass of integer
self.verify_ssl = _get_dict_value(data, "verify_ssl", bool, SCMData.VERIFY_SSL_DEFAULT)
self.username = _get_dict_value(data, "username", string_types)
Expand All @@ -65,11 +65,12 @@ def as_dict(self):
d = {"url": self.url, "revision": self.revision, "username": self.username,
"password": self.password, "type": self.type,
"subfolder": self.subfolder, "submodule": self.submodule}
d = {k: v for k, v in d.items() if v is not None}
# Preserve the value 'None' for those entries with not falsy default.
if self.shallow != self.SHALLOW_DEFAULT:
d.update({"shallow": self.shallow})
if self.verify_ssl != self.VERIFY_SSL_DEFAULT:
d.update({"verify_ssl": self.verify_ssl})
d = {k: v for k, v in d.items() if v is not None}
return d

def __repr__(self):
Expand All @@ -78,6 +79,8 @@ def __repr__(self):
def _kv_to_string(key, value):
if isinstance(value, bool):
return '"{}": {}'.format(key, value)
elif value is None:
return '"{}": None'.format(key)
else:
value_str = str(value).replace('"', r'\"')
return '"{}": "{}"'.format(key, value_str)
Expand Down
68 changes: 61 additions & 7 deletions conans/test/functional/scm/test_git_shallow.py
@@ -1,5 +1,5 @@
# coding=utf-8

import os
import textwrap
import unittest

Expand All @@ -8,13 +8,32 @@
from parameterized.parameterized import parameterized_class

from conans.model.ref import ConanFileReference
from conans.test.utils.tools import TestClient
from conans.paths import DATA_YML
from conans.test.utils.scm import create_local_git_repo
from conans.test.utils.tools import TestClient
from conans.util.files import load


@pytest.mark.parametrize("scm_to_conandata", [True, False])
def test_shallow_none_string(scm_to_conandata):
client = TestClient()
client.run("config set general.scm_to_conandata={}".format('1' if scm_to_conandata else '0'))
client.save({'conanfile.py': textwrap.dedent("""
from conans import ConanFile

class Recipe(ConanFile):
scm = {"type": "git", "url": "https://github.com/repo/library.git",
"revision": "123456", "shallow": 'None' }
""")})

client.run('export . name/version@', assert_error=True)
assert "ERROR: SCM value for 'shallow' must be of type 'bool' (found 'str')" in str(client.out)


@pytest.mark.tool_git
@parameterized_class([{"shallow": True}, {"shallow": False}, {"shallow": None}, {"shallow": "None"}])
@parameterized_class([{"shallow": True}, {"shallow": False},
{"shallow": None}, # No value written in the recipe
{"shallow": 'None'}]) # Explicit 'None' written in the recipe
class GitShallowTestCase(unittest.TestCase):
conanfile = textwrap.dedent("""
from conans import ConanFile
Expand All @@ -41,7 +60,20 @@ def _shallow_attrib_str(self):
shallow_attrib_str = '"shallow": {}'.format(self.shallow)
return shallow_attrib_str

def test_export(self):
def _check_info_values(self, client):
client.run("inspect {} -a scm".format(self.ref)) # Check we get a loadable conanfile.py
if self.shallow in [None]:
self.assertNotIn('shallow', str(client.out))
elif self.shallow in [True]: # This is the default value
not_appears = 'shallow' not in str(client.out)
value_explicit = 'shallow: True' in str(client.out)
self.assertTrue(not_appears or value_explicit)
elif self.shallow in ['None']:
self.assertIn('shallow: None', str(client.out))
else:
self.assertIn('shallow: False', str(client.out))

def test_export_scm_substituted(self):
# Check the shallow value is substituted with the proper value
client = TestClient()
files = {'conanfile.py': self.conanfile.format(shallow_attrib=self._shallow_attrib_str(),
Expand All @@ -52,12 +84,34 @@ def test_export(self):

client.run("export . {}".format(self.ref))
content = load(client.cache.package_layout(self.ref).conanfile())
if self.shallow in [None, True, "None"]:
if self.shallow in [None, True]:
self.assertNotIn("shallow", content)
elif self.shallow in ['None']:
self.assertIn('"shallow": None', content)
else:
self.assertIn('"shallow": False', content)

client.run("inspect {} -a scm".format(self.ref)) # Check we get a loadable conanfile.py
self._check_info_values(client)

def test_export_scm_to_conandata(self):
# Check the shallow value is stored and propagated with the proper value
client = TestClient()
client.run("config set general.scm_to_conandata=1")
files = {'conanfile.py': self.conanfile.format(shallow_attrib=self._shallow_attrib_str(),
url='auto', rev='auto')}
url, _ = create_local_git_repo(files=files)
client.run_command('git clone "{}" .'.format(url))

client.run("export . {}".format(self.ref))
content = load(os.path.join(client.cache.package_layout(self.ref).export(), DATA_YML))
if self.shallow in [None, True]:
self.assertNotIn('shallow', content)
elif self.shallow in ['None']:
self.assertIn('shallow: null', content)
else:
self.assertIn('shallow: false', content)

self._check_info_values(client)

@parameterized.expand([("c6cc15fa2f4b576bd", False), ("0.22.1", True)])
def test_remote_build(self, revision, shallow_works):
Expand All @@ -70,7 +124,7 @@ def test_remote_build(self, revision, shallow_works):

client.run("create . {}".format(self.ref))

if self.shallow in [None, True, "None"] and shallow_works:
if self.shallow in [None, True] and shallow_works:
self.assertIn(">>> describe-fails", client.out)
else:
self.assertIn(">>> tags: 0.22.1", client.out)
63 changes: 56 additions & 7 deletions conans/test/functional/scm/test_verify_ssl.py
@@ -1,20 +1,39 @@
# coding=utf-8

import os
import textwrap
import unittest

import pytest
from parameterized.parameterized import parameterized_class

from conans.model.ref import ConanFileReference
from conans.test.utils.tools import TestClient
from conans.paths import DATA_YML
from conans.test.utils.scm import create_local_git_repo
from conans.test.utils.tools import TestClient
from conans.util.files import load


@pytest.mark.parametrize("scm_to_conandata", [True, False])
def test_verify_ssl_none_string(scm_to_conandata):
client = TestClient()
client.run("config set general.scm_to_conandata={}".format('1' if scm_to_conandata else '0'))
client.save({'conanfile.py': textwrap.dedent("""
from conans import ConanFile

class Recipe(ConanFile):
scm = {"type": "git", "url": "https://github.com/repo/library.git",
"revision": "123456", "verify_ssl": 'None' }
""")})

client.run('export . name/version@', assert_error=True)
assert "ERROR: SCM value for 'verify_ssl' must be of type " \
"'bool' (found 'str')" in str(client.out)


@pytest.mark.tool_git
@parameterized_class([{"verify_ssl": True}, {"verify_ssl": False},
{"verify_ssl": None},{"verify_ssl": "None"}, ])
{"verify_ssl": None}, # No value written in the recipe
{"verify_ssl": 'None'}]) # Explicit 'None' written in the recipe
class GitVerifySSLTestCase(unittest.TestCase):
conanfile = textwrap.dedent("""
from conans import ConanFile
Expand All @@ -37,13 +56,43 @@ def setUp(self):
url, _ = create_local_git_repo(files=files, commits=4, tags=['v0', ])
self.client.run_command('git clone "{}" .'.format(url))

def test_export(self):
# Check the shallow value is substituted with the proper value
def _check_info_values(self, client):
client.run("inspect {} -a scm".format(self.ref)) # Check we get a loadable conanfile.py
if self.verify_ssl in [None]:
self.assertNotIn('verify_ssl', str(client.out))
elif self.verify_ssl in [True]: # This is the default value
not_appears = 'verify_ssl' not in str(client.out)
value_explicit = 'verify_ssl: True' in str(client.out)
self.assertTrue(not_appears or value_explicit)
elif self.verify_ssl in ['None']:
self.assertIn('verify_ssl: None', str(client.out))
else:
self.assertIn('verify_ssl: False', str(client.out))

def test_export_scm_substituted(self):
# Check the verify_ssl value is substituted with the proper value
self.client.run("config set general.scm_to_conandata=0")
self.client.run("export . {}".format(self.ref))
content = load(self.client.cache.package_layout(self.ref).conanfile())
if self.verify_ssl in [None, True, "None"]:
if self.verify_ssl in [None, True]:
self.assertNotIn("verify_ssl", content)
elif self.verify_ssl in ['None']:
self.assertIn('"verify_ssl": None', content)
else:
self.assertIn('"verify_ssl": False', content)

self.client.run("inspect {} -a scm".format(self.ref)) # Check we get a loadable conanfile.py
self._check_info_values(self.client)

def test_export_scm_to_conandata(self):
# Check the verify_ssl value is stored and propagated with the proper value
self.client.run("config set general.scm_to_conandata=1")
self.client.run("export . {}".format(self.ref))
content = load(os.path.join(self.client.cache.package_layout(self.ref).export(), DATA_YML))
if self.verify_ssl in [None, True]:
self.assertNotIn('verify_ssl', content)
elif self.verify_ssl in ['None']:
self.assertIn('verify_ssl: null', content)
else:
self.assertIn('verify_ssl: false', content)

self._check_info_values(self.client)