Repository: packit-service/packit
Pull request #141 (2019-03-11 12:38:49)

Offline LocalProject and some CLI fixes
- Be able to set branch from option in LocalProjectParameter.
- Add offline mode to LocalProject.
- Use PACKIT prefix pro env variables used instead of cli options.

-----

- [ ] ~PackageConfig decorator for CLI functions~ I've played with this, but it would be too magic for saving three lines.
- [x] Tests for offline mode of LocalProject
- [x] Tests for `path_or_url` mode of LocalProject


Patch:
diff --git a/packit/cli/types.py b/packit/cli/types.py
index be229359..6c7ae2cd 100644
--- a/packit/cli/types.py
+++ b/packit/cli/types.py
@@ -1,7 +1,4 @@
-import os
-
 import click
-import requests
 
 from packit.local_project import LocalProject
 
@@ -13,18 +10,31 @@ class LocalProjectParameter(click.ParamType):
 
     name = "repo"
 
+    def __init__(self, branch_param_name: str = None) -> None:
+        """
+        :param branch_param_name: name of the cli function parameter (not the option name)
+        """
+        super().__init__()
+        self.branch_param_name = branch_param_name
+
     def convert(self, value, param, ctx):
         try:
-            if os.path.isdir(value):
-                return LocalProject(working_dir=value)
-
-            try:
-                res = requests.get(value)
-                if res.ok:
-                    return LocalProject(git_url=value)
-                self.fail("Cannot connect to specified url.", param, ctx)
-            except requests.exceptions.BaseHTTPError as ex:
-                self.fail("Cannot connect to specified url.", param, ctx)
-
-        except ValueError as ex:
+            branch_name = None
+            if self.branch_param_name:
+                if self.branch_param_name in ctx.params:
+                    branch_name = ctx.params[self.branch_param_name]
+                else:  # use the default
+                    for param in ctx.command.params:
+                        if param.name == self.branch_param_name:
+                            branch_name = param.default
+
+            local_project = LocalProject(path_or_url=value, ref=branch_name)
+            if not local_project.working_dir and not local_project.git_url:
+                self.fail(
+                    "Parameter is not an existing directory nor correct git url.",
+                    param,
+                    ctx,
+                )
+            return local_project
+        except Exception as ex:
             self.fail(ex, param, ctx)
diff --git a/packit/cli/utils.py b/packit/cli/utils.py
index 4d5b87c2..9d44cd6a 100644
--- a/packit/cli/utils.py
+++ b/packit/cli/utils.py
@@ -29,7 +29,7 @@ def cover_packit_exception(_func=None, *, exit_code=None):
         def covered_func(config=None, *args, **kwargs):
             try:
                 if config:
-                    func(config, *args, **kwargs)
+                    func(config=config, *args, **kwargs)
                 else:
                     func(*args, **kwargs)
             except KeyboardInterrupt:
diff --git a/packit/config.py b/packit/config.py
index 5f7b8a99..e83fc072 100644
--- a/packit/config.py
+++ b/packit/config.py
@@ -71,7 +71,7 @@ def get_default_map_from_file() -> Optional[dict]:
 def get_context_settings() -> dict:
     return dict(
         help_option_names=["-h", "--help"],
-        auto_envvar_prefix="SOURCE_GIT",
+        auto_envvar_prefix="PACKIT",
         default_map=get_default_map_from_file(),
     )
 
diff --git a/packit/local_project.py b/packit/local_project.py
index 09ca4815..4afdd726 100644
--- a/packit/local_project.py
+++ b/packit/local_project.py
@@ -24,13 +24,14 @@ class LocalProject:
         namespace: str = None,
         repo_name: str = None,
         path_or_url: str = None,
+        offline: bool = False,
     ) -> None:
 
         self.working_dir_temporary = False
         if path_or_url:
             if os.path.isdir(path_or_url):
                 working_dir = working_dir or path_or_url
-            else:
+            elif not offline:
                 try:
                     res = requests.head(path_or_url)
                     if res.ok:
@@ -71,13 +72,14 @@ class LocalProject:
                 and self.namespace
                 and self.git_service
                 and not self.git_project
+                and not offline
             ):
                 self.git_project = self.git_service.get_project(
                     repo=self.repo_name, namespace=self.namespace
                 )
                 change = True
 
-            if self.git_project and not self.git_service:
+            if self.git_project and not self.git_service and not offline:
                 self.git_service = self.git_project.service
                 change = True
 
@@ -100,7 +102,7 @@ class LocalProject:
                     self.git_repo = git.Repo(path=self.working_dir)
                     logger.debug("it's a git repo!")
                     change = True
-                elif self.git_url:
+                elif self.git_url and not offline:
                     self.git_repo = get_repo(
                         url=self.git_url, directory=self.working_dir
                     )
@@ -111,12 +113,17 @@ class LocalProject:
                     )
                     change = True
 
-            if self.git_url and not self.working_dir and not self.git_repo:
+            if (
+                self.git_url
+                and not self.working_dir
+                and not self.git_repo
+                and not offline
+            ):
                 self.git_repo = get_repo(url=self.git_url)
                 self.working_dir_temporary = True
                 change = True
 
-            if self.git_project and not self.git_url:
+            if self.git_project and not self.git_url and not offline:
                 self.git_url = self.git_project.get_git_urls()["git"]
                 change = True
 


Test patch:
diff --git a/tests/unit/test_local_project.py b/tests/unit/test_local_project.py
index ea896b53..03df1bf5 100644
--- a/tests/unit/test_local_project.py
+++ b/tests/unit/test_local_project.py
@@ -1,7 +1,11 @@
+import tempfile
+from os import path
+
 import git
+import requests
 from flexmock import flexmock
 
-from packit import local_project
+from packit import local_project, utils
 from packit.local_project import LocalProject
 
 
@@ -185,7 +189,6 @@ def test_local_project_repo_from_working_dir():
 
 
 def test_local_project_dir_url():
-
     flexmock(local_project).should_receive("get_repo").with_args(
         "http://some.example/url", "some/example/path"
     ).and_return(
@@ -206,3 +209,139 @@ def test_local_project_dir_url():
     assert project.git_repo.active_branch == "branch"
     assert project.git_repo.working_dir == "some/example/path"
     assert not project.working_dir_temporary
+
+
+def test_local_project_offline_git_project():
+    """No get_project on offline"""
+
+    project = LocalProject(
+        repo_name="repo_name",
+        namespace="namespace",
+        git_service=flexmock().should_receive("get_project").times(0).mock(),
+        offline=True,
+    )
+    assert project.repo_name == "repo_name"
+    assert project.namespace == "namespace"
+    assert project.git_service
+    assert not project.git_project
+
+
+def test_local_project_offline_git_service():
+    """No git service on on offline"""
+
+    project = LocalProject(
+        repo_name="repo_name",
+        namespace="namespace",
+        git_project=flexmock(service="something")
+        .should_receive("get_git_urls")
+        .times(0)
+        .mock(),
+        offline=True,
+    )
+    assert project.repo_name == "repo_name"
+    assert project.namespace == "namespace"
+    assert project.git_project
+    assert not project.git_service
+    assert not project.git_url
+
+
+def test_local_project_offline_no_clone():
+    """No clone on offline"""
+    flexmock(utils).should_receive("get_repo").times(0)
+    flexmock(tempfile).should_receive("mkdtemp").times(0)
+    flexmock(git.Repo).should_receive("clone_from").times(0)
+
+    project = LocalProject(
+        working_dir="some/example/path", git_url="http://some.example/url", offline=True
+    )
+    assert project.working_dir == "some/example/path"
+    assert project.git_url == "http://some.example/url"
+    assert not project.git_repo
+
+
+def test_local_project_offline_no_clone_no_temp_dir():
+    """No clone on offline, no temp dir"""
+    flexmock(utils).should_receive("get_repo").times(0)
+    flexmock(tempfile).should_receive("mkdtemp").times(0)
+    flexmock(git.Repo).should_receive("clone_from").times(0)
+    project = LocalProject(git_url="http://some.example/url", offline=True)
+
+    assert project.git_url == "http://some.example/url"
+    assert not project.git_repo
+    assert not project.working_dir
+
+
+def test_local_project_path_or_url_path():
+    """isdir=True"""
+    flexmock(path).should_receive("isdir").and_return(True).once()
+    project = LocalProject(
+        path_or_url="some/example/path",
+        git_repo=flexmock(branches={"other": flexmock(checkout=lambda: None)}),
+        git_url="nothing",
+        ref="other",
+    )
+
+    assert project.working_dir == "some/example/path"
+    assert project.git_repo
+    assert project.git_url == "nothing"
+
+
+def test_local_project_path_or_url_overwrite():
+    """overwrite the path_or_url with working_dir"""
+    flexmock(path).should_receive("isdir").and_return(True).once()
+    project = LocalProject(
+        path_or_url="some/example/path",
+        working_dir="new/dir",
+        git_repo=flexmock(branches={"other": flexmock(checkout=lambda: None)}),
+        git_url="nothing",
+        ref="other",
+    )
+
+    assert project.working_dir == "new/dir"
+    assert project.git_repo
+    assert project.git_url == "nothing"
+
+
+def test_local_project_path_or_url_url():
+    """isdir=False requests.head => ok=True"""
+    flexmock(path).should_receive("isdir").and_return(False).once()
+    flexmock(requests).should_receive("head").and_return(flexmock(ok=True)).once()
+
+    project = LocalProject(
+        path_or_url="http://some.example/url",
+        git_repo=flexmock(branches={"other": flexmock(checkout=lambda: None)}),
+        working_dir="nothing",
+        ref="other",
+    )
+
+    assert project.git_url == "http://some.example/url"
+    assert project.git_repo
+    assert project.working_dir == "nothing"
+
+
+def test_local_project_path_or_url_url_overwrite():
+    """overwrite the path_or_url with git_url"""
+    flexmock(path).should_receive("isdir").and_return(False).once()
+    flexmock(requests).should_receive("head").and_return(flexmock(ok=True)).once()
+
+    project = LocalProject(
+        path_or_url="http://some.example/url",
+        git_repo=flexmock(branches={"other": flexmock(checkout=lambda: None)}),
+        working_dir="nothing",
+        git_url="http://some.new/url",
+        ref="other",
+    )
+
+    assert project.git_url == "http://some.new/url"
+    assert project.git_repo
+    assert project.working_dir == "nothing"
+
+
+def test_local_project_path_or_url_nok():
+    """isdir=False requests.head => ok=False"""
+    flexmock(path).should_receive("isdir").and_return(False).once()
+    flexmock(requests).should_receive("head").and_return(flexmock(ok=False)).once()
+
+    project = LocalProject(path_or_url="http://some.example/url")
+
+    assert not project.git_url