Repository: VirtusLab/git-machete
Pull request #1412 (2025-03-08 21:46:06)

Align GitLab PR intro format with GitHub


Patch:
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index ed7fc5a..b0b9ab8 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -3,6 +3,7 @@
 ## New in git-machete 3.33.1
 
 - fixed: preserve trailing lines when updating PR/MR descriptions
+- fixed: generated sections of GitLab MRs include MR titles (as in GitHub PRs)
 
 ## New in git-machete 3.33.0
 
diff --git a/docs/man/git-machete.1 b/docs/man/git-machete.1
index f0f9192..62d60b5 100644
--- a/docs/man/git-machete.1
+++ b/docs/man/git-machete.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "GIT-MACHETE" "1" "Mar 03, 2025" "" "git-machete"
+.TH "GIT-MACHETE" "1" "Mar 08, 2025" "" "git-machete"
 .SH NAME
 git-machete \- git-machete 3.33.1
 .sp
diff --git a/git_machete/client.py b/git_machete/client.py
index 6ccec13..1aa9c1b 100644
--- a/git_machete/client.py
+++ b/git_machete/client.py
@@ -2775,6 +2775,7 @@ class MacheteClient:
             return ''
         spec = self.code_hosting_spec
         pr_short_name = spec.pr_short_name
+        br_before_branches = ' <br>' if spec.pr_intro_br_before_branches else ''
 
         pr_up_path = list(reversed(self.__get_upwards_path_including_pr(pr)))
         if style == PRDescriptionIntroStyle.FULL:
@@ -2801,10 +2802,11 @@ class MacheteClient:
         def pr_entry(_pr: PullRequest, _depth: int) -> str:
             result = '  ' * _depth
             display_text = _pr.display_text(fmt=False)
+            explicit_title = f' _{_pr.title}_' if spec.pr_intro_explicit_title else ''
             if _pr.number == pr.number:
-                result += f'* **{display_text} (THIS ONE)**:\n'
+                result += f'* **{display_text}{explicit_title} (THIS ONE)**:{br_before_branches}\n'
             else:
-                result += f'* {display_text}:\n'
+                result += f'* {display_text}{explicit_title}:{br_before_branches}\n'
             result += '  ' * _depth
             result += f'  `{_pr.base}` ← `{_pr.head}`\n\n'
             return result
diff --git a/git_machete/code_hosting.py b/git_machete/code_hosting.py
index 16815a0..13d80bf 100644
--- a/git_machete/code_hosting.py
+++ b/git_machete/code_hosting.py
@@ -9,7 +9,7 @@ from git_machete.utils import bold
 
 class PullRequest:
     def __init__(self, number: int, display_prefix: str, user: str, base: str, head: str, head_repo_id: int,
-                 state: str, description: Optional[str], html_url: str):
+                 state: str, title: str, description: Optional[str], html_url: str):
         self.__number = number
         self.__display_prefix = display_prefix
         self.__user = user
@@ -17,6 +17,7 @@ class PullRequest:
         self.__head = head
         self.__head_repo_id = head_repo_id
         self.__state = state
+        self.__title = title
         self.__description = description
         self.__html_url = html_url
 
@@ -29,6 +30,7 @@ class PullRequest:
             head=self.__head,
             head_repo_id=self.__head_repo_id,
             state=self.__state,
+            title=self.__title,
             description=self.__description,
             html_url=self.__html_url
         )
@@ -65,6 +67,10 @@ class PullRequest:
     def state(self) -> str:
         return self.__state
 
+    @property
+    def title(self) -> str:
+        return self.__title
+
     @property
     def description(self) -> Optional[str]:
         return self.__description
@@ -167,6 +173,8 @@ class CodeHostingSpec(NamedTuple):
     organization_name: str
     pr_description_path: List[str]
     pr_full_name: str
+    pr_intro_br_before_branches: bool
+    pr_intro_explicit_title: bool
     pr_ordinal_char: str
     pr_short_name_article: str
     pr_short_name: str
diff --git a/git_machete/github.py b/git_machete/github.py
index 925d701..16cc275 100644
--- a/git_machete/github.py
+++ b/git_machete/github.py
@@ -161,8 +161,10 @@ class GitHubClient(CodeHostingClient):
             organization_name='organization',
             # https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository
             pr_description_path=['.github', 'pull_request_template.md'],
-            pr_ordinal_char='#',
             pr_full_name='pull request',
+            pr_intro_br_before_branches=False,
+            pr_intro_explicit_title=False,
+            pr_ordinal_char='#',
             pr_short_name='PR',
             pr_short_name_article='a',
             repository_name='repository',
@@ -197,6 +199,7 @@ class GitHubClient(CodeHostingClient):
             head_repo_id=pr_json['head']['repo']['id'],
             html_url=pr_json['html_url'],
             state=pr_json['state'],
+            title=pr_json['title'],
             description=pr_json['body'])
 
     def __fire_github_api_request(self, method: str, path: str, request_body: Optional[Dict[str, Any]] = None) -> Any:
diff --git a/git_machete/gitlab.py b/git_machete/gitlab.py
index 93f7feb..a72ac82 100644
--- a/git_machete/gitlab.py
+++ b/git_machete/gitlab.py
@@ -118,6 +118,8 @@ class GitLabClient(CodeHostingClient):
             # To keep things simple, we'll only support the "Default.md" template for now.
             pr_description_path=['.gitlab', 'merge_request_templates', 'Default.md'],
             pr_full_name='merge request',
+            pr_intro_br_before_branches=True,
+            pr_intro_explicit_title=True,
             pr_ordinal_char='!',
             pr_short_name='MR',
             pr_short_name_article='an',
@@ -149,6 +151,7 @@ class GitLabClient(CodeHostingClient):
             head_repo_id=int(mr_json['source_project_id']),
             html_url=mr_json['web_url'],
             state=mr_json['state'],
+            title=mr_json['title'],
             description=mr_json['description'])
 
     def __fire_gitlab_api_request(self, method: str, path: str, request_body: Optional[Dict[str, Any]] = None) -> Any:


Test patch:
diff --git a/tests/mockers_github.py b/tests/mockers_github.py
index 24a3c7c..9c458a8 100644
--- a/tests/mockers_github.py
+++ b/tests/mockers_github.py
@@ -26,6 +26,7 @@ def mock_pr_json(head: str, base: str, number: int,
         'base': {'ref': base},
         'number': str(number),
         'html_url': html_url,
+        'title': 'PR title',
         'body': body,
         'state': state,
         'draft': draft
diff --git a/tests/mockers_gitlab.py b/tests/mockers_gitlab.py
index 568980d..dd957e5 100644
--- a/tests/mockers_gitlab.py
+++ b/tests/mockers_gitlab.py
@@ -28,13 +28,13 @@ def mock_mr_json(head: str, base: str, number: int,
                  draft: bool = False
                  ) -> Dict[str, Any]:
     return {
-        'title': 'Draft: MR title' if draft else 'MR title',
         'source_branch': head,
         'source_project_id': repo_id,
         'target_branch': base,
         'author': {'username': user},
         'iid': str(number),
         'web_url': html_url,
+        'title': 'Draft: MR title' if draft else 'MR title',
         'description': body,
         'state': state,
         'draft': draft
diff --git a/tests/test_gitlab_create_mr.py b/tests/test_gitlab_create_mr.py
index 7129f95..3612840 100644
--- a/tests/test_gitlab_create_mr.py
+++ b/tests/test_gitlab_create_mr.py
@@ -173,10 +173,10 @@ class TestGitLabCreateMR(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !3:
+            * MR !3 _MR title_: <br>
               `hotfix/add-trigger` ← `ignore-trailing`
 
-              * **MR !5 (THIS ONE)**:
+              * **MR !5 _Draft: remove outdated fields_ (THIS ONE)**: <br>
                 `ignore-trailing` ← `chore/fields`
 
             <!-- end git-machete generated -->
@@ -261,13 +261,13 @@ class TestGitLabCreateMR(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !6:
+            * MR !6 _HOTFIX Add the trigger (amended)_: <br>
               `master` ← `hotfix/add-trigger`
 
-              * MR !3:
+              * MR !3 _MR title_: <br>
                 `hotfix/add-trigger` ← `ignore-trailing`
 
-                * **MR !5 (THIS ONE)**:
+                * **MR !5 _Draft: remove outdated fields_ (THIS ONE)**: <br>
                   `ignore-trailing` ← `chore/fields`
 
             <!-- end git-machete generated -->
@@ -416,16 +416,16 @@ class TestGitLabCreateMR(BaseTest):
 
             ## Chain of upstream MRs & tree of downstream MRs as of 2023-12-31
 
-            * MR !1:
+            * MR !1 _MR title_: <br>
               `develop` ← `allow-ownership-link`
 
-              * MR !2:
+              * MR !2 _MR title_: <br>
                 `allow-ownership-link` ← `build-chain`
 
-                * **MR !4 (THIS ONE)**:
+                * **MR !4 _Call web service_ (THIS ONE)**: <br>
                   `build-chain` ← `call-ws`
 
-                    * MR !3:
+                    * MR !3 _Drop unneeded SQL constraints_: <br>
                       `call-ws` ← `drop-constraint`
 
             <!-- end git-machete generated -->
@@ -630,10 +630,10 @@ class TestGitLabCreateMR(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !15:
+            * MR !15 _MR title_: <br>
               `root` ← `branch-1`
 
-              * **MR !16 (THIS ONE)**:
+              * **MR !16 _introduce feature_ (THIS ONE)**: <br>
                 `branch-1` ← `feature`
 
             <!-- end git-machete generated -->
diff --git a/tests/test_gitlab_retarget_mr.py b/tests/test_gitlab_retarget_mr.py
index 6f82d8e..69b432a 100644
--- a/tests/test_gitlab_retarget_mr.py
+++ b/tests/test_gitlab_retarget_mr.py
@@ -272,10 +272,10 @@ class TestGitLabRetargetMR(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !15:
+            * MR !15 _MR title_: <br>
               `master` ← `feature`
 
-              * **MR !20 (THIS ONE)**:
+              * **MR !20 _MR title_ (THIS ONE)**: <br>
                 `feature` ← `feature_1`
 
             <!-- end git-machete generated -->
@@ -319,10 +319,10 @@ class TestGitLabRetargetMR(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !15:
+            * MR !15 _MR title_: <br>
               `master` ← `feature`
 
-              * **MR !25 (THIS ONE)**:
+              * **MR !25 _MR title_ (THIS ONE)**: <br>
                 `feature` ← `feature_2`
 
             <!-- end git-machete generated -->
@@ -361,13 +361,13 @@ class TestGitLabRetargetMR(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !15:
+            * MR !15 _MR title_: <br>
               `master` ← `feature`
 
-              * MR !25:
+              * MR !25 _MR title_: <br>
                 `feature` ← `feature_2`
 
-                * **MR !30 (THIS ONE)**:
+                * **MR !30 _MR title_ (THIS ONE)**: <br>
                   `feature_2` ← `feature_3`
 
             <!-- end git-machete generated -->
@@ -401,10 +401,10 @@ class TestGitLabRetargetMR(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !15:
+            * MR !15 _MR title_: <br>
               `master` ← `feature`
 
-              * **MR !30 (THIS ONE)**:
+              * **MR !30 _MR title_ (THIS ONE)**: <br>
                 `feature` ← `feature_3`
 
             <!-- end git-machete generated -->
@@ -469,16 +469,16 @@ class TestGitLabRetargetMR(BaseTest):
 
             ## Tree of downstream MRs as of 2023-12-31
 
-            * **MR !15 (THIS ONE)**:
+            * **MR !15 _MR title_ (THIS ONE)**: <br>
               `branch-1` ← `feature`
 
-                * MR !20:
+                * MR !20 _MR title_: <br>
                   `feature` ← `feature_1`
 
-                * MR !25:
+                * MR !25 _MR title_: <br>
                   `feature` ← `feature_2`
 
-                * MR !35:
+                * MR !35 _MR title_: <br>
                   `feature` ← `feature_4`
 
             <!-- end git-machete generated -->
diff --git a/tests/test_gitlab_update_mr_descriptions.py b/tests/test_gitlab_update_mr_descriptions.py
index c991888..6803952 100644
--- a/tests/test_gitlab_update_mr_descriptions.py
+++ b/tests/test_gitlab_update_mr_descriptions.py
@@ -153,16 +153,16 @@ class TestGitLabUpdateMRDescriptions(BaseTest):
 
             ## Tree of downstream MRs as of 2023-12-31
 
-            * **MR !6 (THIS ONE)**:
+            * **MR !6 _MR title_ (THIS ONE)**: <br>
               `enhance/feature` ← `bugfix/feature`
 
-                * MR !12:
+                * MR !12 _MR title_: <br>
                   `bugfix/feature` ← `allow-ownership-link`
 
-                  * MR !17:
+                  * MR !17 _MR title_: <br>
                     `allow-ownership-link` ← `restrict_access`
 
-                    * MR !18:
+                    * MR !18 _MR title_: <br>
                       `restrict_access` ← `chore/redundant_checks`
 
             <!-- end git-machete generated -->
@@ -179,16 +179,16 @@ class TestGitLabUpdateMRDescriptions(BaseTest):
 
             ## Chain of upstream MRs & tree of downstream MRs as of 2023-12-31
 
-            * MR !6:
+            * MR !6 _MR title_: <br>
               `enhance/feature` ← `bugfix/feature`
 
-              * **MR !12 (THIS ONE)**:
+              * **MR !12 _MR title_ (THIS ONE)**: <br>
                 `bugfix/feature` ← `allow-ownership-link`
 
-                  * MR !17:
+                  * MR !17 _MR title_: <br>
                     `allow-ownership-link` ← `restrict_access`
 
-                    * MR !18:
+                    * MR !18 _MR title_: <br>
                       `restrict_access` ← `chore/redundant_checks`
 
             <!-- end git-machete generated -->
diff --git a/tests/test_traverse_gitlab.py b/tests/test_traverse_gitlab.py
index c488bac..7d42cd0 100644
--- a/tests/test_traverse_gitlab.py
+++ b/tests/test_traverse_gitlab.py
@@ -157,10 +157,10 @@ class TestTraverseGitLab(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !1:
+            * MR !1 _MR title_: <br>
               `develop` ← `allow-ownership-link`
 
-              * **MR !2 (THIS ONE)**:
+              * **MR !2 _MR title_ (THIS ONE)**: <br>
                 `allow-ownership-link` ← `build-chain`
 
             <!-- end git-machete generated -->
@@ -176,13 +176,13 @@ class TestTraverseGitLab(BaseTest):
 
             ## Chain of upstream MRs as of 2023-12-31
 
-            * MR !1:
+            * MR !1 _MR title_: <br>
               `develop` ← `allow-ownership-link`
 
-              * MR !2:
+              * MR !2 _MR title_: <br>
                 `allow-ownership-link` ← `build-chain`
 
-                * **MR !3 (THIS ONE)**:
+                * **MR !3 _MR title_ (THIS ONE)**: <br>
                   `build-chain` ← `call-ws`
 
             <!-- end git-machete generated -->