diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a78d98185b..e27aa1bf36 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,6 +39,7 @@ repos: hooks: - id: djlint-jinja types_or: ["html"] + exclude: ^tests/test_build/.*\.html$ - repo: "https://github.com/PyCQA/doc8" rev: v1.1.2 diff --git a/docs/user_guide/source-buttons.rst b/docs/user_guide/source-buttons.rst index a4db469adf..249ca8454b 100644 --- a/docs/user_guide/source-buttons.rst +++ b/docs/user_guide/source-buttons.rst @@ -4,6 +4,8 @@ Source Buttons Source buttons are links to the source of your page's content (either on your site, or on hosting sites like GitHub). +.. _add-edit-button: + Add an edit button ================== diff --git a/docs/user_guide/theme-elements.md b/docs/user_guide/theme-elements.md index 3a40bec5be..633efbf640 100644 --- a/docs/user_guide/theme-elements.md +++ b/docs/user_guide/theme-elements.md @@ -212,7 +212,7 @@ All will end up as numbers in the rendered HTML, but in the source they look lik ## Link shortening for git repository services -Many projects have links back to their issues / PRs hosted on platforms like **GitHub** or **GitLab**. +Many projects have links back to their issues / PRs hosted on platforms like **GitHub**, **GitLab**, or **Bitbucket**. Instead of displaying these as raw links, this theme does some lightweight formatting for these platforms specifically. In **reStructuredText**, URLs are automatically converted to links, so this works automatically. @@ -252,5 +252,25 @@ There are a variety of link targets supported, here's a table for reference: - `https://gitlab.com/gitlab-org`: https://gitlab.com/gitlab-org - `https://gitlab.com/gitlab-org/gitlab`: https://gitlab.com/gitlab-org/gitlab - `https://gitlab.com/gitlab-org/gitlab/-/issues/375583`: https://gitlab.com/gitlab-org/gitlab/-/issues/375583 +- `https://gitlab.com/gitlab-org/gitlab/-/merge_requests/174667`: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/174667 + +**Bitbucket** + +- `https://bitbucket.org`: https://bitbucket.org +- `https://bitbucket.org/atlassian/workspace/overview`: https://bitbucket.org/atlassian/workspace/overview +- `https://bitbucket.org/atlassian/aui`: https://bitbucket.org/atlassian/aui +- `https://bitbucket.org/atlassian/aui/pull-requests/4758`: https://bitbucket.org/atlassian/aui/pull-requests/4758 Links provided with a text body won't be changed. + +If you have links to GitHub, GitLab, or Bitbucket repository URLs that are on non-standard domains +(i.e., not on `github.com`, `gitlab.com`, or `bitbucket.org`, respectively), then these will be +shortened if the base URL is given in the `html_context` section of your `conf.py` file (see +{ref}`Add an edit button `), e.g., + +```python +html_context = { + "gitlab_url": "https://gitlab.mydomain.com", # your self-hosted GitLab + ... +} +``` diff --git a/src/pydata_sphinx_theme/__init__.py b/src/pydata_sphinx_theme/__init__.py index 0b1ed7d4fe..5b4b25ec92 100644 --- a/src/pydata_sphinx_theme/__init__.py +++ b/src/pydata_sphinx_theme/__init__.py @@ -275,6 +275,33 @@ def _fix_canonical_url( context["pageurl"] = app.config.html_baseurl + target +def _add_self_hosted_platforms_to_link_transform_class(app: Sphinx) -> None: + if not hasattr(app.config, "html_context"): + return + + # Use list() to force the iterator to completion because the for-loop below + # can modify the dictionary. + platforms = list(short_link.ShortenLinkTransform.supported_platform.values()) + + for platform in platforms: + # {platform}_url -- e.g.: github_url, gitlab_url, bitbucket_url + self_hosted_url = app.config.html_context.get(f"{platform}_url", None) + if self_hosted_url is None: + continue + parsed = urlparse(self_hosted_url) + if parsed.scheme not in ("http", "https"): + raise Exception( + f"If you provide a value for html_context option {platform}_url," + " it must begin with http or https." + ) + if not parsed.netloc: + raise Exception( + f"Unsupported URL provided for html_context option {platform}_url." + " Could not get domain (netloc) from ${self_hosted_url}." + ) + short_link.ShortenLinkTransform.add_platform_mapping(platform, parsed.netloc) + + def setup(app: Sphinx) -> Dict[str, str]: """Setup the Sphinx application.""" here = Path(__file__).parent.resolve() @@ -286,6 +313,7 @@ def setup(app: Sphinx) -> Dict[str, str]: app.connect("builder-inited", translator.setup_translators) app.connect("builder-inited", update_config) + app.connect("builder-inited", _add_self_hosted_platforms_to_link_transform_class) app.connect("html-page-context", _fix_canonical_url) app.connect("html-page-context", edit_this_page.setup_edit_url) app.connect("html-page-context", toctree.add_toctree_functions) diff --git a/src/pydata_sphinx_theme/assets/styles/base/_base.scss b/src/pydata_sphinx_theme/assets/styles/base/_base.scss index 82235df440..6a7d64563f 100644 --- a/src/pydata_sphinx_theme/assets/styles/base/_base.scss +++ b/src/pydata_sphinx_theme/assets/styles/base/_base.scss @@ -48,7 +48,8 @@ a { // set up a icon next to the shorten links from github and gitlab &.github, - &.gitlab { + &.gitlab, + &.bitbucket { &::before { color: var(--pst-color-text-muted); font: var(--fa-font-brands); @@ -63,6 +64,10 @@ a { &.gitlab::before { content: var(--pst-icon-gitlab); } + + &.bitbucket::before { + content: var(--pst-icon-bitbucket); + } } %heading-style { diff --git a/src/pydata_sphinx_theme/assets/styles/variables/_icons.scss b/src/pydata_sphinx_theme/assets/styles/variables/_icons.scss index f7618ec4ed..9db8fff4ed 100644 --- a/src/pydata_sphinx_theme/assets/styles/variables/_icons.scss +++ b/src/pydata_sphinx_theme/assets/styles/variables/_icons.scss @@ -20,6 +20,7 @@ html { --pst-icon-search-minus: "\f010"; // fa-solid fa-magnifying-glass-minus --pst-icon-github: "\f09b"; // fa-brands fa-github --pst-icon-gitlab: "\f296"; // fa-brands fa-gitlab + --pst-icon-bitbucket: "\f171"; // fa-brands fa-bitbucket --pst-icon-share: "\f064"; // fa-solid fa-share --pst-icon-bell: "\f0f3"; // fa-solid fa-bell --pst-icon-pencil: "\f303"; // fa-solid fa-pencil diff --git a/src/pydata_sphinx_theme/short_link.py b/src/pydata_sphinx_theme/short_link.py index 34db161e49..f9f147f4c0 100644 --- a/src/pydata_sphinx_theme/short_link.py +++ b/src/pydata_sphinx_theme/short_link.py @@ -1,7 +1,9 @@ """A custom Transform object to shorten github and gitlab links.""" +import re + from typing import ClassVar -from urllib.parse import ParseResult, urlparse, urlunparse +from urllib.parse import urlparse from docutils import nodes from sphinx.transforms.post_transforms import SphinxPostTransform @@ -12,8 +14,8 @@ class ShortenLinkTransform(SphinxPostTransform): """ - Shorten link when they are coming from github or gitlab and add an extra class to - the tag for further styling. + Shorten link when they are coming from github, gitlab, or bitbucket and add + an extra class to the tag for further styling. Before: .. code-block:: html @@ -37,8 +39,13 @@ class ShortenLinkTransform(SphinxPostTransform): supported_platform: ClassVar[dict[str, str]] = { "github.com": "github", "gitlab.com": "gitlab", + "bitbucket.org": "bitbucket", } - platform = None + + @classmethod + def add_platform_mapping(cls, platform, netloc): + """Add domain->platform mapping to class at run-time.""" + cls.supported_platform.update({netloc: platform}) def run(self, **kwargs): """Run the Transform object.""" @@ -50,74 +57,146 @@ def run(self, **kwargs): # only act if the uri and text are the same # if not the user has already customized the display of the link if uri is not None and text is not None and text == uri: - uri = urlparse(uri) + parsed_uri = urlparse(uri) # only do something if the platform is identified - self.platform = self.supported_platform.get(uri.netloc) - if self.platform is not None: - node.attributes["classes"].append(self.platform) - node.children[0] = nodes.Text(self.parse_url(uri)) - - def parse_url(self, uri: ParseResult) -> str: - """Parse the content of the url with respect to the selected platform. - - Args: - uri: the link to the platform content - - Returns: - the reformated url title - """ - path = uri.path - if path == "": - # plain url passed, return platform only - return self.platform - - # if the path is not empty it contains a leading "/", which we don't want to - # include in the parsed content - path = path.lstrip("/") - - # check the platform name and read the information accordingly - # as "/#" - # or "//…//#" - if self.platform == "github": - # split the url content - parts = path.split("/") - - if parts[0] == "orgs" and "/projects" in path: - # We have a projects board link - # ref: `orgs/{org}/projects/{project-id}` - text = f"{parts[1]}/projects#{parts[3]}" - else: - # We have an issues, PRs, or repository link - if len(parts) > 0: - text = parts[0] # organisation - if len(parts) > 1: - text += f"/{parts[1]}" # repository - if len(parts) > 2: - if parts[2] in ["issues", "pull", "discussions"]: - text += f"#{parts[-1]}" # element number - - elif self.platform == "gitlab": - # cp. https://docs.gitlab.com/ee/user/markdown.html#gitlab-specific-references - if "/-/" in path and any( - map(uri.path.__contains__, ["issues", "merge_requests"]) - ): - group_and_subgroups, parts, *_ = path.split("/-/") - parts = parts.rstrip("/") - if "/" not in parts: - text = f"{group_and_subgroups}/{parts}" - else: - parts = parts.split("/") - url_type, element_number, *_ = parts - if not element_number: - text = group_and_subgroups - elif url_type == "issues": - text = f"{group_and_subgroups}#{element_number}" - elif url_type == "merge_requests": - text = f"{group_and_subgroups}!{element_number}" - else: - # display the whole uri (after "gitlab.com/") including parameters - # for example "///" - text = uri._replace(netloc="", scheme="") # remove platform - text = urlunparse(text)[1:] # combine to string and strip leading "/" - - return text + platform = self.supported_platform.get(parsed_uri.netloc) + if platform is not None: + short = shorten_url(platform, uri) + if short != uri: + node.attributes["classes"].append(platform) + node.children[0] = nodes.Text(short) + + +def shorten_url(platform: str, url: str) -> str: + """Parse the content of the path with respect to the selected platform. + + Args: + platform: "github", "gitlab", "bitbucket", etc. + url: the full url to the platform content, beginning with https:// + + Returns: + short form version of the url, + or the full url if it could not shorten it + """ + if platform == "github": + return shorten_github(url) + elif platform == "bitbucket": + return shorten_bitbucket(url) + elif platform == "gitlab": + return shorten_gitlab(url) + + return url + + +def shorten_github(url: str) -> str: + """ + Convert a GitHub URL to a short form like owner/repo#123 or + owner/repo@abc123. + """ + path = urlparse(url).path + + # Pull request URL + # - Example: + # - https://github.com/pydata/pydata-sphinx-theme/pull/2068 + # - pydata/pydata-sphinx-theme#2068 + if match := re.match(r"/([^/]+)/([^/]+)/pull/(\d+)", path): + owner, repo, pr_id = match.groups() + return f"{owner}/{repo}#{pr_id}" + + # Issue URL + # - Example: + # - https://github.com/pydata/pydata-sphinx-theme/issues/2176 + # - pydata/pydata-sphinx-theme#2176 + elif match := re.match(r"/([^/]+)/([^/]+)/issues/(\d+)", path): + owner, repo, issue_id = match.groups() + return f"{owner}/{repo}#{issue_id}" + + # Commit URL + # - Example: + # - https://github.com/pydata/pydata-sphinx-theme/commit/51af2a27e8a008d0b44ed9ea9b45311e686d12f7 + # - pydata/pydata-sphinx-theme@51af2a2 + elif match := re.match(r"/([^/]+)/([^/]+)/commit/([a-f0-9]+)", path): + owner, repo, commit_hash = match.groups() + return f"{owner}/{repo}@{commit_hash[:7]}" + + # No match — return the original URL + return url + + +def shorten_gitlab(url: str) -> str: + """ + Convert a GitLab URL to a short form like group/project!123 or + group/project@abcdef7. + + Only supports canonical ('/-/') GitLab URLs. + """ + path = urlparse(url).path + + # Merge requests + # - Example: + # - https://gitlab.com/gitlab-org/gitlab/-/merge_requests/195598 + # - gitlab-org/gitlab!195598 + if match := re.match(r"^/(.+)/([^/]+)/-/merge_requests/(\d+)$", path): + namespace, project, mr_id = match.groups() + return f"{namespace}/{project}!{mr_id}" + + # Issues + # - Example: + # - https://gitlab.com/gitlab-org/gitlab/-/issues/551885 + # - gitlab-org/gitlab#195598 + # + # TODO: support hash URLs, for example: + # https://gitlab.com/gitlab-org/gitlab/-/issues/545699#note_2543533261 + if match := re.match(r"^/(.+)/([^/]+)/-/issues/(\d+)$", path): + namespace, project, issue_id = match.groups() + return f"{namespace}/{project}#{issue_id}" + + # Commits + # - Example: + # - https://gitlab.com/gitlab-org/gitlab/-/commit/81872624c4c58425a040e158fd228d8f0c2bda07 + # - gitlab-org/gitlab@8187262 + if match := re.match(r"^/(.+)/([^/]+)/-/commit/([a-f0-9]+)$", path): + namespace, project, commit_hash = match.groups() + return f"{namespace}/{project}@{commit_hash[:7]}" + + # No match — return the original URL + return url + + +def shorten_bitbucket(url: str) -> str: + """ + Convert a Bitbucket URL to a short form like team/repo#123 or + team/repo@main. + """ + path = urlparse(url).path + + # Pull request URL + # - Example: + # - https://bitbucket.org/atlassian/atlassian-jwt-js/pull-requests/23 + # - atlassian/atlassian-jwt-js#23 + if match := re.match(r"^/([^/]+)/([^/]+)/pull-requests/(\d+)$", path): + workspace, repo, pr_id = match.groups() + return f"{workspace}/{repo}#{pr_id}" + + # Issue URL. + # - Example: + # - https://bitbucket.org/atlassian/atlassian-jwt-js/issues/11/ + # - atlassian/atlassian-jwt-js!11 + # + # Deliberately not matching the end of the string because sometimes + # Bitbucket issue URLs include a slug at the end, for example: + # https://bitbucket.org/atlassian/atlassian-jwt-js/issues/11/nested-object-properties-are-represented + elif match := re.match(r"^/([^/]+)/([^/]+)/issues/(\d+)", path): + workspace, repo, issue_id = match.groups() + return f"{workspace}/{repo}!{issue_id}" + + # Commit URL + # - Example: + # - https://bitbucket.org/atlassian/atlassian-jwt-js/commits/d9b5197f0aeedeabf9d0f8d0953a80be65743d8a + # - atlassian/atlassian-jwt-js@d9b5197 + elif match := re.match(r"^/([^/]+)/([^/]+)/commits/([a-f0-9]+)$", path): + workspace, repo, commit_hash = match.groups() + return f"{workspace}/{repo}@{commit_hash[:7]}" + + # No match — return the original URL + return url diff --git a/tests/sites/base/page1.rst b/tests/sites/base/page1.rst index ce3393abbd..a96baf73d1 100644 --- a/tests/sites/base/page1.rst +++ b/tests/sites/base/page1.rst @@ -15,6 +15,18 @@ Page 1 https://github.com/pydata/pydata-sphinx-theme/pull/1012 https://github.com/orgs/pydata/projects/2 + http will get shortened: + + http://github.com/pydata/pydata-sphinx-theme/pull/1012 + + www will not get shortened: + + https://www.github.com/pydata/pydata-sphinx-theme/pull/1012 + + will not be linkified: + + github.com/pydata/pydata-sphinx-theme/pull/1012 + **GitLab** .. container:: gitlab-container @@ -31,3 +43,12 @@ Page 1 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84669 https://gitlab.com/gitlab-org/gitlab/-/pipelines/511894707 https://gitlab.com/gitlab-com/gl-infra/production/-/issues/6788 + +**Bitbucket** + +.. container:: bitbucket-container + + https://bitbucket.org + https://bitbucket.org/atlassian/workspace/overview + https://bitbucket.org/atlassian/aui + https://bitbucket.org/atlassian/aui/pull-requests/4758 diff --git a/tests/sites/self_hosted_version_control/conf.py b/tests/sites/self_hosted_version_control/conf.py new file mode 100644 index 0000000000..e3186b47cf --- /dev/null +++ b/tests/sites/self_hosted_version_control/conf.py @@ -0,0 +1,22 @@ +"""Test conf file.""" + +# -- Project information ----------------------------------------------------- + +project = "Test Self Hosted Version Control URLs" +copyright = "2020, Pydata community" +author = "Pydata community" + +root_doc = "index" + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] +html_theme = "pydata_sphinx_theme" +html_context = { + "github_url": "https://github.pydata.org", + "gitlab_url": "https://gitlab.pydata.org", + "bitbucket_url": "https://bitbucket.pydata.org", +} diff --git a/tests/sites/self_hosted_version_control/index.rst b/tests/sites/self_hosted_version_control/index.rst new file mode 100644 index 0000000000..268664d9d0 --- /dev/null +++ b/tests/sites/self_hosted_version_control/index.rst @@ -0,0 +1,13 @@ +Test conversion of a self-hosted GitHub URL +=========================================== + +This test ensures that a site using PyData Sphinx Theme can set a self-hosted +version control URL via the theme options and then when the site is built, that +the URLs that go to that self-hosted version control domain will be properly +shortened (just like for github.com, gitlab.com, and bitbucket.org). + +.. toctree:: + :caption: My caption + :numbered: + + links diff --git a/tests/sites/self_hosted_version_control/links.rst b/tests/sites/self_hosted_version_control/links.rst new file mode 100644 index 0000000000..da7b95bb2e --- /dev/null +++ b/tests/sites/self_hosted_version_control/links.rst @@ -0,0 +1,42 @@ +Test Self Hosted Version Control URLs +===================================== + +**normal link** + +- https://pydata-sphinx-theme.readthedocs.io/en/latest/ + +**GitHub** + +.. container:: github-container + + https://github.pydata.org + https://github.pydata.org/pydata + https://github.pydata.org/pydata/pydata-sphinx-theme + https://github.pydata.org/pydata/pydata-sphinx-theme/pull/1012 + https://github.pydata.org/orgs/pydata/projects/2 + +**GitLab** + +.. container:: gitlab-container + + https://gitlab.pydata.org + https://gitlab.pydata.org/gitlab-org + https://gitlab.pydata.org/gitlab-org/gitlab + https://gitlab.pydata.org/gitlab-org/gitlab/-/issues/375583 + https://gitlab.pydata.org/gitlab-org/gitlab/issues/375583 + https://gitlab.pydata.org/gitlab-org/gitlab/-/issues/ + https://gitlab.pydata.org/gitlab-org/gitlab/issues/ + https://gitlab.pydata.org/gitlab-org/gitlab/-/issues + https://gitlab.pydata.org/gitlab-org/gitlab/issues + https://gitlab.pydata.org/gitlab-org/gitlab/-/merge_requests/84669 + https://gitlab.pydata.org/gitlab-org/gitlab/-/pipelines/511894707 + https://gitlab.pydata.org/gitlab-com/gl-infra/production/-/issues/6788 + +**Bitbucket** + +.. container:: bitbucket-container + + https://bitbucket.pydata.org + https://bitbucket.pydata.org/atlassian/workspace/overview + https://bitbucket.pydata.org/atlassian/aui + https://bitbucket.pydata.org/atlassian/aui/pull-requests/4758 diff --git a/tests/test_build.py b/tests/test_build.py index f40a38acd2..99b81cab9f 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -852,6 +852,42 @@ def test_shorten_link(sphinx_build_factory, file_regression) -> None: gitlab = sphinx_build.html_tree("page1.html").select(".gitlab-container")[0] file_regression.check(gitlab.prettify(), basename="gitlab_links", extension=".html") + bitbucket = sphinx_build.html_tree("page1.html").select(".bitbucket-container")[0] + file_regression.check( + bitbucket.prettify(), basename="bitbucket_links", extension=".html" + ) + + +def test_self_hosted_shorten_link(sphinx_build_factory, file_regression) -> None: + """Check that self-hosted version control URLs get shortened. + + Before build: + + conf.py + + html_context = {"github_url": "https://github.example.com"} + + example_page.rst + + In https://github.example.com/pydata/pydata-sphinx-theme/pull/101, + we refactored stylesheets and updated typography. + + After build: + + example_page.html + + In + pydata/pydata-sphinx-theme#101, we refactored stylesheets and + updated typography. + """ + sphinx_build = sphinx_build_factory("self_hosted_version_control").build() + urls_page = sphinx_build.html_tree("links.html").select("article")[0] + file_regression.check( + urls_page.prettify(), + basename="self_hosted_version_control_links", + extension=".html", + ) + def test_math_header_item(sphinx_build_factory, file_regression) -> None: """Regression test for math items in a header title.""" diff --git a/tests/test_build/bitbucket_links.html b/tests/test_build/bitbucket_links.html new file mode 100644 index 0000000000..229faef6fb --- /dev/null +++ b/tests/test_build/bitbucket_links.html @@ -0,0 +1,16 @@ + diff --git a/tests/test_build/github_links.html b/tests/test_build/github_links.html index 104637fc70..2a6a8b507a 100644 --- a/tests/test_build/github_links.html +++ b/tests/test_build/github_links.html @@ -1,19 +1,41 @@ diff --git a/tests/test_build/gitlab_links.html b/tests/test_build/gitlab_links.html index f12fcba43b..4a36fe4132 100644 --- a/tests/test_build/gitlab_links.html +++ b/tests/test_build/gitlab_links.html @@ -1,37 +1,37 @@

- - gitlab + + https://gitlab.com - - gitlab-org + + https://gitlab.com/gitlab-org - - gitlab-org/gitlab + + https://gitlab.com/gitlab-org/gitlab gitlab-org/gitlab#375583 - - gitlab-org/gitlab/issues/375583 + + https://gitlab.com/gitlab-org/gitlab/issues/375583 - - gitlab-org/gitlab/issues + + https://gitlab.com/gitlab-org/gitlab/-/issues/ - - gitlab-org/gitlab/issues/ + + https://gitlab.com/gitlab-org/gitlab/issues/ - - gitlab-org/gitlab/issues + + https://gitlab.com/gitlab-org/gitlab/-/issues - - gitlab-org/gitlab/issues + + https://gitlab.com/gitlab-org/gitlab/issues gitlab-org/gitlab!84669 - - gitlab-org/gitlab/-/pipelines/511894707 + + https://gitlab.com/gitlab-org/gitlab/-/pipelines/511894707 gitlab-com/gl-infra/production#6788 diff --git a/tests/test_build/self_hosted_version_control_links.html b/tests/test_build/self_hosted_version_control_links.html new file mode 100644 index 0000000000..b51ab7bc50 --- /dev/null +++ b/tests/test_build/self_hosted_version_control_links.html @@ -0,0 +1,117 @@ +

+
+

+ + 1. + + Test Self Hosted Version Control URLs + + # + +

+

+ + normal link + +

+ +

+ + GitHub + +

+ +

+ + GitLab + +

+ +

+ + Bitbucket + +

+ +
+
diff --git a/tests/test_short_url.py b/tests/test_short_url.py index e5f92bdc83..b3786dd4b0 100644 --- a/tests/test_short_url.py +++ b/tests/test_short_url.py @@ -1,78 +1,86 @@ """Shortening url tests.""" -from urllib.parse import urlparse - import pytest -from pydata_sphinx_theme.short_link import ShortenLinkTransform - - -class Mock: - """mock object.""" - - pass +from pydata_sphinx_theme.short_link import shorten_url @pytest.mark.parametrize( "platform,url,expected", [ - # TODO, I belive this is wrong as both github.com and github.com/github - # shorten to just github. - ("github", "https://github.com", "github"), - ("github", "https://github.com/github", "github"), - ("github", "https://github.com/pydata", "pydata"), + ("github", "https://github.com", "https://github.com"), + ("github", "https://github.com/github", "https://github.com/github"), + ("github", "https://github.com/pydata", "https://github.com/pydata"), ( "github", "https://github.com/pydata/pydata-sphinx-theme", - "pydata/pydata-sphinx-theme", + "https://github.com/pydata/pydata-sphinx-theme", ), ( "github", "https://github.com/pydata/pydata-sphinx-theme/pull/1012", "pydata/pydata-sphinx-theme#1012", ), - # TODO, I belive this is wrong as both orgs/pydata/projects/2 and - # pydata/projects/issue/2 shorten to the same - ("github", "https://github.com/orgs/pydata/projects/2", "pydata/projects#2"), + ( + "github", + "https://github.com/pydata/pydata-sphinx-theme/issues", + "https://github.com/pydata/pydata-sphinx-theme/issues", + ), + ( + "github", + "https://github.com/pydata/pydata-sphinx-theme/commit/3caf346cacd2dad2a192a83c6cc9f8852e5a722e", + "pydata/pydata-sphinx-theme@3caf346", + ), + ( + "github", + "https://github.com/orgs/pydata/projects/2", + "https://github.com/orgs/pydata/projects/2", + ), ("github", "https://github.com/pydata/projects/pull/2", "pydata/projects#2"), - # issues and pulls are athe same, so it's ok to normalise to the same here + # issues and pulls are the same, so it's ok to normalise to the same here ("github", "https://github.com/pydata/projects/issues/2", "pydata/projects#2"), # Gitlab - ("gitlab", "https://gitlab.com/tezos/tezos/-/issues", "tezos/tezos/issues"), - ("gitlab", "https://gitlab.com/tezos/tezos/issues", "tezos/tezos/issues"), + ( + "gitlab", + "https://gitlab.com/tezos/tezos/-/issues", + "https://gitlab.com/tezos/tezos/-/issues", + ), + ( + "gitlab", + "https://gitlab.com/tezos/tezos/issues", + "https://gitlab.com/tezos/tezos/issues", + ), ( "gitlab", "https://gitlab.com/gitlab-org/gitlab/-/issues/375583", "gitlab-org/gitlab#375583", ), ( - # TODO, non canonical url, discuss if should maybe be shortened to - # gitlab-org/gitlab#375583 + # non canonical url - not supported "gitlab", "https://gitlab.com/gitlab-org/gitlab/issues/375583", - "gitlab-org/gitlab/issues/375583", + "https://gitlab.com/gitlab-org/gitlab/issues/375583", ), ( "gitlab", "https://gitlab.com/gitlab-org/gitlab/-/issues/", - "gitlab-org/gitlab/issues", + "https://gitlab.com/gitlab-org/gitlab/-/issues/", ), ( - # TODO, non canonical url, discuss if should maybe be shortened to - # gitlab-org/gitlab/issues (no trailing slash) + # non canonical url "gitlab", "https://gitlab.com/gitlab-org/gitlab/issues/", - "gitlab-org/gitlab/issues/", + "https://gitlab.com/gitlab-org/gitlab/issues/", ), ( "gitlab", "https://gitlab.com/gitlab-org/gitlab/-/issues", - "gitlab-org/gitlab/issues", + "https://gitlab.com/gitlab-org/gitlab/-/issues", ), ( "gitlab", "https://gitlab.com/gitlab-org/gitlab/issues", - "gitlab-org/gitlab/issues", + "https://gitlab.com/gitlab-org/gitlab/issues", ), ( "gitlab", @@ -82,13 +90,75 @@ class Mock: ( "gitlab", "https://gitlab.com/gitlab-org/gitlab/-/pipelines/511894707", - "gitlab-org/gitlab/-/pipelines/511894707", + "https://gitlab.com/gitlab-org/gitlab/-/pipelines/511894707", ), ( "gitlab", "https://gitlab.com/gitlab-com/gl-infra/production/-/issues/6788", "gitlab-com/gl-infra/production#6788", ), + # Bitbucket + ("bitbucket", "https://bitbucket.org", "https://bitbucket.org"), + ( + "bitbucket", + "https://bitbucket.org/atlassian", + "https://bitbucket.org/atlassian", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/workspace/overview", + "https://bitbucket.org/atlassian/workspace/overview", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui", + "https://bitbucket.org/atlassian/aui", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/", + "https://bitbucket.org/atlassian/aui/", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/pull-requests/4758", + "atlassian/aui#4758", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/issues/375583", + "atlassian/aui!375583", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/issues", + "https://bitbucket.org/atlassian/aui/issues", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/issues/", + "https://bitbucket.org/atlassian/aui/issues/", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/commits/de41ded719e579d0ed4ffb8a81c29bb9ada10011", + "atlassian/aui@de41ded", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/branch/future/10.0.x", + "https://bitbucket.org/atlassian/aui/branch/future/10.0.x", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/pipelines", + "https://bitbucket.org/atlassian/aui/pipelines", + ), + ( + "bitbucket", + "https://bitbucket.org/atlassian/aui/pipelines/results/14542", + "https://bitbucket.org/atlassian/aui/pipelines/results/14542", + ), ], ) def test_shorten(platform, url, expected): @@ -96,14 +166,4 @@ def test_shorten(platform, url, expected): Usually you also want a build test in `test_build.py` """ - document = Mock() - document.settings = Mock() - document.settings.language_code = "en" - document.reporter = None - - sl = ShortenLinkTransform(document) - sl.platform = platform - - URI = urlparse(url) - - assert sl.parse_url(URI) == expected + assert shorten_url(platform, url) == expected