Skip to content

Commit 9a099d8

Browse files
committed
ENH - edit button support for codeberg, forgejo, gitea
Signed-off-by: Martin Matous <[email protected]>
1 parent 0f946cd commit 9a099d8

File tree

4 files changed

+207
-11
lines changed

4 files changed

+207
-11
lines changed

docs/user_guide/source-buttons.rst

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ your ``conf.py`` file in 'html_theme_options':
1919
}
2020
2121
A number of providers are available for building *Edit this Page* links, including
22-
GitHub, GitLab, and Bitbucket. For each, the default public instance URL can be
22+
GitHub, GitLab, Bitbucket, Forgejo and Gitea. For each, the default public instance URL (should it exist) can be
2323
replaced with a self-hosted instance.
2424

2525

@@ -65,6 +65,33 @@ Bitbucket
6565
}
6666
6767
68+
Forgejo
69+
---------
70+
71+
.. code:: python
72+
73+
html_context = {
74+
# "forgejo_url": "https://codeberg.org", # or your self-hosted Forgejo
75+
"forgejo_user": "<your-forgejo-org>",
76+
"forgejo_repo": "<your-forgejo-repo>",
77+
"forgejo_version": "<your-branch>",
78+
"doc_path": "<path-from-root-to-your-docs>",
79+
}
80+
81+
82+
Gitea
83+
---------
84+
85+
.. code:: python
86+
87+
html_context = {
88+
# "gitea_url": "https://gitea.com", # or your self-hosted Gitea
89+
"gitea_user": "<your-gitea-org>",
90+
"gitea_repo": "<your-gitea-repo>",
91+
"gitea_version": "<your-branch>",
92+
"doc_path": "<path-from-root-to-your-docs>",
93+
}
94+
6895
Custom Edit URL
6996
---------------
7097

@@ -80,7 +107,7 @@ any other context values.
80107
"some_other_arg": "?some-other-arg"
81108
}
82109
83-
With the predefined providers, the link text reads "Edit on GitHub/GitLab/Bitbucket".
110+
With the predefined providers, the link text reads "Edit on GitHub/GitLab/Bitbucket/Codeberg/Forgejo/Gitea".
84111
By default, a simple "Edit" is used if you use a custom URL. However, you can set
85112
a provider name like this:
86113

src/pydata_sphinx_theme/edit_this_page.py

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
"""Create an "edit this page" url compatible with bitbucket, gitlab and github."""
22

3+
import urllib
4+
35
import jinja2
46

57
from sphinx.application import Sphinx
68
from sphinx.errors import ExtensionError
79

10+
from .utils import get_theme_options_dict
11+
812

913
def setup_edit_url(
1014
app: Sphinx, pagename: str, templatename: str, context, doctree
@@ -20,11 +24,24 @@ def get_edit_provider_and_url() -> None:
2024
if doc_path and not doc_path.endswith("/"):
2125
doc_path = f"{doc_path}/"
2226

23-
default_provider_urls = {
27+
provider_urls = {
2428
"bitbucket_url": "https://bitbucket.org",
29+
"forgejo_url": "https://codeberg.org",
30+
"gitea_url": "https://gitea.com",
2531
"github_url": "https://github.com",
2632
"gitlab_url": "https://gitlab.com",
2733
}
34+
provider_labels = {
35+
"bitbucket": "Bitbucket",
36+
"forgejo": "Forgejo",
37+
"gitea": "Gitea",
38+
"github": "GitHub",
39+
"gitlab": "GitLab",
40+
}
41+
theme_options = get_theme_options_dict(app)
42+
provider_urls, provider_labels = adjust_forge_params(
43+
provider_urls, provider_labels, theme_options
44+
)
2845

2946
edit_attrs = {}
3047

@@ -44,25 +61,35 @@ def get_edit_provider_and_url() -> None:
4461
edit_attrs.update(
4562
{
4663
("bitbucket_user", "bitbucket_repo", "bitbucket_version"): (
47-
"Bitbucket",
64+
provider_labels["bitbucket"],
4865
"{{ bitbucket_url }}/{{ bitbucket_user }}/{{ bitbucket_repo }}"
4966
"/src/{{ bitbucket_version }}"
5067
"/{{ doc_path }}{{ file_name }}?mode=edit",
5168
),
69+
("forgejo_user", "forgejo_repo", "forgejo_version"): (
70+
provider_labels["forgejo"],
71+
"{{ forgejo_url }}/{{ forgejo_user }}/{{ forgejo_repo }}"
72+
"/_edit/{{ forgejo_version }}/{{ doc_path }}{{ file_name }}",
73+
),
74+
("gitea_user", "gitea_repo", "gitea_version"): (
75+
provider_labels["gitea"],
76+
"{{ gitea_url }}/{{ gitea_user }}/{{ gitea_repo }}"
77+
"/_edit/{{ gitea_version }}/{{ doc_path }}{{ file_name }}",
78+
),
5279
("github_user", "github_repo", "github_version"): (
53-
"GitHub",
80+
provider_labels["github"],
5481
"{{ github_url }}/{{ github_user }}/{{ github_repo }}"
5582
"/edit/{{ github_version }}/{{ doc_path }}{{ file_name }}",
5683
),
5784
("gitlab_user", "gitlab_repo", "gitlab_version"): (
58-
"GitLab",
85+
provider_labels["gitlab"],
5986
"{{ gitlab_url }}/{{ gitlab_user }}/{{ gitlab_repo }}"
6087
"/-/edit/{{ gitlab_version }}/{{ doc_path }}{{ file_name }}",
6188
),
6289
}
6390
)
6491

65-
doc_context = dict(default_provider_urls)
92+
doc_context = dict(provider_urls)
6693
doc_context.update(context)
6794
doc_context.update(doc_path=doc_path, file_name=file_name)
6895

@@ -80,3 +107,27 @@ def get_edit_provider_and_url() -> None:
80107

81108
# Ensure that the max TOC level is an integer
82109
context["theme_show_toc_level"] = int(context.get("theme_show_toc_level", 1))
110+
111+
112+
def adjust_forge_params(
113+
forge_urls: dict[str, str],
114+
forge_labels: dict[str, str],
115+
theme_options: dict[str, str],
116+
) -> (dict[str, str], dict[str, str]):
117+
"""Adjust labels and URLs for some of the more decentralized forges."""
118+
# use *_urls given in html_theme_options as authority (netloc)
119+
# instead of default if available
120+
for url_key in forge_urls:
121+
forge_url = theme_options.get(url_key)
122+
if forge_url:
123+
forge_url = urllib.parse.urlsplit(forge_url, allow_fragments=False)
124+
forge_url = f"{forge_url.scheme}://{forge_url.netloc}"
125+
forge_urls[url_key] = forge_url
126+
127+
# use rebranded forge label instead of generic SW name where known
128+
if "forgejo_url" in theme_options:
129+
url = theme_options["forgejo_url"]
130+
if url.startswith("https://codeberg.org"):
131+
forge_labels["forgejo"] = "Codeberg"
132+
133+
return forge_urls, forge_labels

tests/test_build.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,44 @@ def test_footer(sphinx_build_factory) -> None:
585585
"https://bitbucket.org/foo/bar/src/HEAD/docs/index.rst?mode=edit",
586586
),
587587
],
588+
[
589+
{
590+
"forgejo_user": "foo",
591+
"forgejo_repo": "bar",
592+
"forgejo_version": "HEAD",
593+
"doc_path": "docs",
594+
"forgejo_url": "https://my-forgejo.com",
595+
},
596+
(
597+
"Edit on Forgejo",
598+
"https://my-forgejo.com/foo/bar/_edit/HEAD/docs/index.rst",
599+
),
600+
],
601+
[
602+
{
603+
"forgejo_user": "foo",
604+
"forgejo_repo": "bar",
605+
"forgejo_version": "HEAD",
606+
"doc_path": "docs",
607+
"forgejo_url": "https://codeberg.org",
608+
},
609+
(
610+
"Edit on Codeberg",
611+
"https://codeberg.org/foo/bar/_edit/HEAD/docs/index.rst",
612+
),
613+
],
614+
[
615+
{
616+
"gitea_user": "foo",
617+
"gitea_repo": "bar",
618+
"gitea_version": "HEAD",
619+
"doc_path": "docs",
620+
},
621+
(
622+
"Edit on Gitea",
623+
"https://gitea.com/foo/bar/_edit/HEAD/docs/index.rst",
624+
),
625+
],
588626
]
589627

590628

@@ -608,16 +646,22 @@ def test_footer(sphinx_build_factory) -> None:
608646
dict(
609647
# copy all the values
610648
**html_context,
611-
# add a provider url
612-
**{f"{provider}_url": f"https://{provider}.example.com"},
649+
# add a provider url if not specified in html_context
650+
**(
651+
{f"{provider}_url": f"https://{provider}.example.com"}
652+
if f"{provider}_url" not in html_context
653+
else {}
654+
),
613655
),
614656
(
615657
text,
616-
f"""https://{provider}.example.com/foo/{url.split("/foo/")[1]}""",
658+
f"""https://{provider}.example.com/foo/{url.split("/foo/")[1]}"""
659+
if f"{provider}_url" not in html_context
660+
else f"{html_context[f'{provider}_url']}/foo/{url.split('/foo/')[1]}",
617661
),
618662
]
619663
for html_context, (text, url) in good_edits
620-
for provider in ["github", "gitlab", "bitbucket"]
664+
for provider in ["github", "gitlab", "bitbucket", "forgejo", "gitea"]
621665
if provider in text.lower()
622666
]
623667

@@ -687,6 +731,10 @@ def test_edit_page_url(sphinx_build_factory, html_context, edit_text_and_url) ->
687731
"html_theme_options.use_edit_page_button": True,
688732
"html_context": html_context,
689733
}
734+
if html_context.get("forgejo_url"):
735+
confoverrides.update(
736+
{"html_theme_options.forgejo_url": html_context["forgejo_url"]}
737+
)
690738
sphinx_build = sphinx_build_factory("base", confoverrides=confoverrides)
691739

692740
if edit_text_and_url is None:

tests/test_edit.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Edit button unit tests."""
2+
3+
import pytest
4+
5+
from pydata_sphinx_theme.edit_this_page import adjust_forge_params
6+
7+
8+
@pytest.fixture
9+
def default_forge_urls():
10+
"""Setup default edit URLs."""
11+
return {
12+
"forgejo_url": "https://codeberg.org",
13+
"gitea_url": "https://gitea.com",
14+
"gitlab_url": "https://gitlab.com",
15+
}
16+
17+
18+
@pytest.mark.parametrize(
19+
"html_theme_options,modified_urls",
20+
[
21+
(
22+
{"forgejo_url": "https://my-forgejo.com/f-proj/f-repo"},
23+
{"forgejo_url": "https://my-forgejo.com"},
24+
),
25+
(
26+
{"gitea_url": "https://my-gitea.com/g-proj/g-repo"},
27+
{"gitea_url": "https://my-gitea.com"},
28+
),
29+
(
30+
{
31+
"gitlab_url": "https://my-gitlab.org/gl-proj/gl-repo",
32+
"forgejo_url": "https://my-forgejo.com/f-proj/f-repo",
33+
},
34+
{
35+
"forgejo_url": "https://my-forgejo.com",
36+
"gitlab_url": "https://my-gitlab.org",
37+
},
38+
),
39+
],
40+
)
41+
def test_adjust_forge_params_replace_urls(
42+
default_forge_urls, html_theme_options, modified_urls
43+
):
44+
"""Unit test for adjust_forge_params() url replacing."""
45+
forge_urls, forge_labels = adjust_forge_params(
46+
default_forge_urls, {}, html_theme_options
47+
)
48+
expected_urls = default_forge_urls | modified_urls
49+
50+
assert forge_urls == expected_urls
51+
assert forge_labels == {}
52+
53+
54+
@pytest.mark.parametrize(
55+
"html_theme_options,expected_labels",
56+
[
57+
({"forgejo_url": "https://noreplace.com"}, {}),
58+
({"forgejo_url": "https://codeberg.org"}, {"forgejo": "Codeberg"}),
59+
],
60+
)
61+
def test_adjust_forge_params_relabel(
62+
default_forge_urls, html_theme_options, expected_labels
63+
):
64+
"""Unit test for adjust_forge_params() relabeling."""
65+
forge_urls, forge_labels = adjust_forge_params(
66+
default_forge_urls, {}, html_theme_options
67+
)
68+
69+
assert forge_urls == default_forge_urls
70+
assert forge_labels == expected_labels

0 commit comments

Comments
 (0)