Skip to content

Commit

Permalink
feat: accept a regular GitHub URL as a style
Browse files Browse the repository at this point in the history
  • Loading branch information
andreoliwa committed Jul 11, 2021
1 parent 1bf8b62 commit f29438f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 33 deletions.
51 changes: 29 additions & 22 deletions src/nitpick/style/fetchers/__init__.py
Expand Up @@ -32,38 +32,43 @@ def __post_init__(self):
self.fetchers = _get_fetchers(self.cache_repository, self.cache_option)

def fetch(self, url) -> StyleInfo:
"""Determine which fetcher to be used and fetch from it."""
scheme = self._get_scheme(url)
try:
fetcher = self.fetchers[scheme]
except KeyError as exc:
raise RuntimeError(f"protocol {scheme} not supported") from exc
"""Determine which fetcher to be used and fetch from it.
Try a fetcher by domain first, then by protocol scheme.
"""
domain, scheme = self._get_domain_scheme(url)
fetcher = None
if domain:
fetcher = self.fetchers.get(domain)
if not fetcher:
fetcher = self.fetchers.get(scheme)
if not fetcher:
raise RuntimeError(f"Protocol {scheme} and/or domain {domain} not supported")

if self.offline and fetcher.requires_connection:
return None, ""

return fetcher.fetch(url)

@staticmethod
def _get_scheme(url: str) -> str:
r"""Get a scheme from an URL or a file.
>>> StyleFetcherManager._get_scheme("/abc")
'file'
>>> StyleFetcherManager._get_scheme("file:///abc")
'file'
>>> StyleFetcherManager._get_scheme(r"c:\abc")
'file'
>>> StyleFetcherManager._get_scheme("c:/abc")
'file'
>>> StyleFetcherManager._get_scheme("http://server.com/abc")
'http'
def _get_domain_scheme(url: str) -> Tuple[str, str]:
r"""Get domain and scheme from an URL or a file.
>>> StyleFetcherManager._get_domain_scheme("/abc")
('', 'file')
>>> StyleFetcherManager._get_domain_scheme("file:///abc")
('', 'file')
>>> StyleFetcherManager._get_domain_scheme(r"c:\abc")
('', 'file')
>>> StyleFetcherManager._get_domain_scheme("c:/abc")
('', 'file')
>>> StyleFetcherManager._get_domain_scheme("http://server.com/abc")
('server.com', 'http')
"""
if is_url(url):
parsed_url = urlparse(url)
return parsed_url.scheme

return "file"
return parsed_url.netloc, parsed_url.scheme
return "", "file"


def _get_fetchers(cache_repository, cache_option) -> "FetchersType":
Expand All @@ -85,6 +90,8 @@ def _fetchers_to_pairs(fetchers):
for protocol in fetcher.protocols:
_register_on_urllib(protocol)
yield protocol, fetcher
for domain in fetcher.domains:
yield domain, fetcher


@lru_cache()
Expand Down
1 change: 1 addition & 0 deletions src/nitpick/style/fetchers/base.py
Expand Up @@ -23,6 +23,7 @@ class StyleFetcher:

requires_connection = False
protocols: Tuple[str, ...] = ()
domains: Tuple[str, ...] = ()

def fetch(self, url) -> StyleInfo:
"""Fetch a style form cache or from a specific fetcher."""
Expand Down
7 changes: 2 additions & 5 deletions src/nitpick/style/fetchers/github.py
Expand Up @@ -134,11 +134,8 @@ class GitHubFetcher(HttpFetcher): # pylint: disable=too-few-public-methods
"""Fetch styles from GitHub repositories."""

protocols: Tuple[str, ...] = (GitHubProtocol.SHORT.value, GitHubProtocol.LONG.value)
domains: Tuple[str, ...] = ("github.com",)

def _download(self, url) -> str:
parsed_url = urlparse(url)
owner = parsed_url.netloc
repository = str(parsed_url.path.split("/")[1])

github_url = GitHubURL(owner, repository, "", parsed_url.path.replace(f"/{repository}", ""))
github_url = GitHubURL.parse_url(url)
return super()._download(github_url.raw_content_url)
23 changes: 17 additions & 6 deletions tests/test_style.py
Expand Up @@ -711,8 +711,21 @@ def test_invalid_nitpick_files(offline, tmp_path):


@responses.activate
def test_github_fetch(tmp_path):
"""Test that gh:// and github:// URLs can be fetched."""
@pytest.mark.parametrize(
"style_url",
[
# Without commit reference (uses default branch)
"github://andreoliwa/nitpick/initial.toml",
"gh://andreoliwa/nitpick/initial.toml",
# Explicit commit reference
"github://andreoliwa/nitpick@develop/initial.toml",
"gh://andreoliwa/nitpick@develop/initial.toml",
# Regular GitHub URL
"https://github.com/andreoliwa/nitpick/blob/develop/initial.toml",
],
)
def test_always_fetch_github_raw_url(style_url, tmp_path):
"""Test that gh://, github:// and normal github URLs can be fetched always by their corresponding raw URL."""
raw_url = "https://raw.githubusercontent.com/andreoliwa/nitpick/develop"
data = [
(
Expand All @@ -736,11 +749,9 @@ def test_github_fetch(tmp_path):
responses.add(responses.GET, "https://api.github.com/repos/andreoliwa/nitpick", '{"default_branch": "develop"}')

ProjectMock(tmp_path).pyproject_toml(
"""
f"""
[tool.nitpick]
style = [
"github://andreoliwa/nitpick/initial.toml",
]
style = ["{style_url}"]
"""
).api_check().assert_violations(
Fuss(
Expand Down

0 comments on commit f29438f

Please sign in to comment.