Repository: markvincze/sabledocs (language: python)

Issue:
Add support for generating deep links to sources hosted on GitLab
Sabledocs (`v0.13.784`) supports the generation of deep links to sources hosted exclusively on GitHub and Bitbucket.

This issue proposes to add support for generating deep links to sources hosted on GitLab as well.

A new `repository-type` value named `gitlab` would trigger the generation of such links.

In terms of format, GitLab's deep links are almost the same as GitHub's, the only difference being that there's a hyphen separating the repository URL and the blob part.

For example: `https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/README.md#L41`


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18bfc87..4eca54e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Changelog
 
+## [0.14]
+- Deep links to sources hosted on GitLab can be generated. Added
+  - `gitlab` value to the `repository-type` option
+
 ## [0.13]
 - Extra Jinja templates can be used. Added
   - option `extra-template-path`
diff --git a/README.md b/README.md
index 8f03291..ce8d525 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@ footer-content = "© 2023 Jane Doe. All rights reserved."
 # The following 3 fields configure the source control repository of the project.
 # They are used to generate deeplinks for the members of the Proto model pointing to the original source
 # code. By default these fields are not configured, and source code links are not included in the docs.
-# The repository-type field supports two possible values, "github" and "bitbucket".
+# The repository-type field supports three possible values, "github", "bitbucket" and "gitlab".
 # The fields repository-url and repository-branch should be configured to point to the correct repository.
 # repository-dir should be set only if the root of your Protobuf module is in a specific directory inside your repository.
 repository-type = "github"
diff --git a/pyproject.toml b/pyproject.toml
index 89cdd73..3c867d6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
 
 [project]
 name = "sabledocs"
-version = "0.13"
+version = "0.14"
 authors = [
   { name="Mark Vincze", email="mrk.vincze@gmail.com" },
 ]
diff --git a/src/sabledocs/proto_descriptor_parser.py b/src/sabledocs/proto_descriptor_parser.py
index 94217b6..9982013 100644
--- a/src/sabledocs/proto_descriptor_parser.py
+++ b/src/sabledocs/proto_descriptor_parser.py
@@ -49,6 +49,12 @@ def build_source_code_url(repository_url, repository_type, repository_branch, re
             u.fragment.add(f"lines-{line_number + 1}")
             u.path.normalize()
             return u.url
+        case RepositoryType.GITLAB:
+            # ex: https://git.example.com/-/blob/main/myrepodir/foo/bar.proto#L41
+            u = furl(repository_url) / '-' / 'blob' / repository_branch / repository_dir / file_path
+            u.fragment.add(f"L{line_number}")
+            u.path.normalize()
+            return u.url
     return ""
 
 
diff --git a/src/sabledocs/sable_config.py b/src/sabledocs/sable_config.py
index 977b5b1..9d227e9 100644
--- a/src/sabledocs/sable_config.py
+++ b/src/sabledocs/sable_config.py
@@ -8,6 +8,7 @@ class RepositoryType(Enum):
     NONE = 1
     GITHUB = 2
     BITBUCKET = 3
+    GITLAB = 4
 
 
 class MemberOrdering(Enum):
@@ -64,6 +65,8 @@ def __init__(self, config_file_path):
                             self.repository_type = RepositoryType.GITHUB
                         case 'bitbucket':
                             self.repository_type = RepositoryType.BITBUCKET
+                        case 'gitlab':
+                            self.repository_type = RepositoryType.GITLAB
 
                 self.ignore_comments_after = config_values.get('ignore-comments-after', [])
                 self.ignore_comment_lines_containing = config_values.get('ignore-comment-lines-containing', [])
diff --git a/src/sabledocs/templates/_default/base.html b/src/sabledocs/templates/_default/base.html
index c49fa55..48872bf 100644
--- a/src/sabledocs/templates/_default/base.html
+++ b/src/sabledocs/templates/_default/base.html
@@ -38,6 +38,10 @@
               <span class="icon">
                 <i class="fa-brands fa-bitbucket"></i>
               </span>
+              {% elif sable_config.repository_type | string == "RepositoryType.GITLAB" %}
+              <span class="icon">
+                <i class="fa-brands fa-gitlab"></i>
+              </span>
               {% endif %}
               <span>Source</span>
             </a>


Test patch:
diff --git a/tests/test_proto_descriptor_parser.py b/tests/test_proto_descriptor_parser.py
index 17d9c7c..10e4c4d 100644
--- a/tests/test_proto_descriptor_parser.py
+++ b/tests/test_proto_descriptor_parser.py
@@ -88,3 +88,45 @@ def test_code_url_bitbucket_style_extra_slashes(self):
         expected = 'https://git.example.com/src/main/myrepodir/foo/bar.proto#lines-42'
 
         self.assertEqual(got, expected)
+
+    def test_code_url_gitlab_style(self):
+
+        got = build_source_code_url(
+                'https://git.example.com',
+                RepositoryType.GITLAB,
+                "main",
+                "", # no repository_dir
+                "foo/bar.proto",
+                41)
+
+        expected = 'https://git.example.com/-/blob/main/foo/bar.proto#L41'
+
+        self.assertEqual(got, expected)
+
+    def test_code_url_gitlab_style_with_repo_dir(self):
+
+        got = build_source_code_url(
+                'https://git.example.com',
+                RepositoryType.GITLAB,
+                "main",
+                "myrepodir",
+                "foo/bar.proto",
+                41)
+
+        expected = 'https://git.example.com/-/blob/main/myrepodir/foo/bar.proto#L41'
+
+        self.assertEqual(got, expected)
+
+    def test_code_url_gitlab_style_extra_slashes(self):
+
+        got = build_source_code_url(
+                'https://git.example.com/',
+                RepositoryType.GITLAB,
+                "main",
+                "/myrepodir/",
+                "/foo/bar.proto",
+                41)
+
+        expected = 'https://git.example.com/-/blob/main/myrepodir/foo/bar.proto#L41'
+
+        self.assertEqual(got, expected)