Repository: VirtusLab/git-machete
Pull request #649 (2022-09-09 12:30:20)

Issue #648: Handle forkpoint that is overriden with invalid commit hash

codecov-commenter: # [Codecov](https://codecov.io/gh/VirtusLab/git-machete/pull/649?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab) Report
> Merging [#649](https://codecov.io/gh/VirtusLab/git-machete/pull/649?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab) (fef2e4c) into [develop](https://codecov.io/gh/VirtusLab/git-machete/commit/bf0d7c317de6d3a767d23800a53e22c32aabed63?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab) (bf0d7c3) will **decrease** coverage by `0.14%`.
> The diff coverage is `50.00%`.

```diff
@@             Coverage Diff             @@
##           develop     #649      +/-   ##
===========================================
- Coverage    69.54%   69.40%   -0.15%     
===========================================
  Files           10       10              
  Lines         2932     2938       +6     
  Branches       709      711       +2     
===========================================
  Hits          2039     2039              
- Misses         623      626       +3     
- Partials       270      273       +3     
```


| [Impacted Files](https://codecov.io/gh/VirtusLab/git-machete/pull/649?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab) | Coverage Δ | |
|---|---|---|
| [git\_machete/client.py](https://codecov.io/gh/VirtusLab/git-machete/pull/649/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab#diff-Z2l0X21hY2hldGUvY2xpZW50LnB5) | `64.74% <20.00%> (-0.22%)` | :arrow_down: |
| [git\_machete/git\_operations.py](https://codecov.io/gh/VirtusLab/git-machete/pull/649/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab#diff-Z2l0X21hY2hldGUvZ2l0X29wZXJhdGlvbnMucHk=) | `73.61% <100.00%> (-0.19%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=VirtusLab)


Patch:
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index cbd4fd4..5ef6a47 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -3,6 +3,7 @@
 ## New in git-machete 3.12.1
 
 - fixed: removed redundant files from Ubuntu package
+- fixed: fork-point overridden with invalid commit hash is ignored (doesn't crash git-machete anymore)
 
 ## New in git-machete 3.12.0
 
diff --git a/git_machete/client.py b/git_machete/client.py
index 64845aa..66c43d3 100644
--- a/git_machete/client.py
+++ b/git_machete/client.py
@@ -1583,17 +1583,20 @@ class MacheteClient:
                 self.__git.get_config_attr_or_none(self.config_key_for_override_fork_point_while_descendant_of(branch))) is not None
 
     def __get_fork_point_override_data(self, branch: LocalBranchShortName) -> Optional[ForkPointOverrideData]:
+        to, while_descendant_of = None, None
         to_key = self.config_key_for_override_fork_point_to(branch)
-        to = FullCommitHash.of(self.__git.get_config_attr_or_none(to_key) or "")
+        if FullCommitHash.is_valid(self.__git.get_config_attr_or_none(to_key)):
+            to = FullCommitHash.of(self.__git.get_config_attr_or_none(to_key))
         while_descendant_of_key = self.config_key_for_override_fork_point_while_descendant_of(branch)
-        while_descendant_of = FullCommitHash.of(self.__git.get_config_attr_or_none(while_descendant_of_key) or "")
+        if FullCommitHash.is_valid(self.__git.get_config_attr_or_none(to_key)):
+            while_descendant_of = FullCommitHash.of(self.__git.get_config_attr_or_none(while_descendant_of_key))
         if not to and not while_descendant_of:
             return None
         if to and not while_descendant_of:
-            warn(f"{to_key} config is set but {while_descendant_of_key} config is missing")
+            warn(f"{to_key} config is set but {while_descendant_of_key} config is missing or invalid")
             return None
         if not to and while_descendant_of:
-            warn(f"{while_descendant_of_key} config is set but {to_key} config is missing")
+            warn(f"{while_descendant_of_key} config is set but {to_key} config is missing or invalid")
             return None
 
         to_hash: Optional[FullCommitHash] = self.__git.get_commit_hash_by_revision(to)
diff --git a/git_machete/git_operations.py b/git_machete/git_operations.py
index 0b55972..d9fd2b5 100644
--- a/git_machete/git_operations.py
+++ b/git_machete/git_operations.py
@@ -1,3 +1,4 @@
+import string
 from pathlib import Path
 from typing import Any, Callable, Dict, Generator, Iterator, List, Match, NamedTuple, Optional, Set, Tuple
 
@@ -123,6 +124,10 @@ class FullCommitHash(AnyRevision):
                                 'Consider posting an issue on https://github.com/VirtusLab/git-machete/issues/new')
         return None
 
+    @staticmethod
+    def is_valid(value: str) -> bool:
+        return value is not None and len(value) == 40 and all(c in string.hexdigits for c in value)
+
     def full_name(self) -> "FullCommitHash":
         return self
 


Test patch:
diff --git a/tests/test_fork_point.py b/tests/test_fork_point.py
index 404bb40..facee4e 100644
--- a/tests/test_fork_point.py
+++ b/tests/test_fork_point.py
@@ -50,3 +50,30 @@ class TestForkPoint:
         assert_command(["fork-point", 'develop'], "515319fa0ab47f372f6159bcc8ac27b43ee8a0ed\n", strip_indentation=False)
 
         assert_command(["fork-point", 'refs/heads/develop'], "515319fa0ab47f372f6159bcc8ac27b43ee8a0ed\n", strip_indentation=False)
+
+    def test_fork_point_override(self) -> None:
+        """
+        Verify behaviour of a 'git machete fork-point' command with fork-point being overridden by config key.
+        """
+        (
+            self.repo_sandbox.new_branch("master")
+                .commit("master commit")
+                .new_branch("develop")
+                .commit("develop commit")
+        )
+        launch_command('discover', '-y')
+
+        # invalid fork point with length not equal to 40
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.to', 39 * 'a')
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.whileDescendantOf', 39 * 'b')
+        launch_command('fork-point')
+
+        # invalid, non-hexadecimal alphanumeric characters present in the fork point
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.to', 20 * 'g1')
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.whileDescendantOf', 20 * 'g1')
+        launch_command('fork-point')
+
+        # invalid, non-hexadecimal special characters present in the fork point
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.to', 40 * '#')
+        self.repo_sandbox.add_git_config_key('machete.overrideForkPoint.develop.whileDescendantOf', 40 * '!')
+        launch_command('fork-point')