From 287a11dc600b6e77d7064e65373a81809c26716a Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Sat, 13 Aug 2022 10:33:36 +0200 Subject: [PATCH 1/4] Refactor relationship between repo_url, repo_name, edit_uri And deprecate RepoURL --- mkdocs/config/config_options.py | 58 ++++++++++++++++++--- mkdocs/config/defaults.py | 6 +-- mkdocs/tests/config/config_options_tests.py | 8 +-- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py index 0c42186652..745c844cfc 100644 --- a/mkdocs/config/config_options.py +++ b/mkdocs/config/config_options.py @@ -5,6 +5,7 @@ import sys import traceback import typing as t +import warnings from typing import NamedTuple from urllib.parse import urlsplit, urlunsplit @@ -347,12 +348,11 @@ def run_validation(self, value): class RepoURL(URL): - """ - Repo URL Config Option - - A small extension to the URL config that sets the repo_name and edit_uri, - based on the url if they haven't already been provided. - """ + def __init__(self, *args, **kwargs): + warnings.warn( + "RepoURL is no longer used in MkDocs and will be removed.", DeprecationWarning + ) + super().__init__(*args, **kwargs) def post_validation(self, config, key_name): repo_host = urlsplit(config['repo_url']).netloc.lower() @@ -385,6 +385,52 @@ def post_validation(self, config, key_name): config['edit_uri'] = edit_uri +class EditURI(Type): + def __init__(self, repo_url_key): + super().__init__(str) + self.repo_url_key = repo_url_key + + def post_validation(self, config, key_name): + edit_uri = config.get(key_name) + repo_url = config.get(self.repo_url_key) + + if edit_uri is None and repo_url is not None: + repo_host = urlsplit(repo_url).netloc.lower() + if repo_host == 'github.com' or repo_host == 'gitlab.com': + edit_uri = 'edit/master/docs/' + elif repo_host == 'bitbucket.org': + edit_uri = 'src/default/docs/' + + # ensure a well-formed edit_uri + if edit_uri and not edit_uri.endswith('/'): + edit_uri += '/' + + config[key_name] = edit_uri + + +class RepoName(Type): + def __init__(self, repo_url_key): + super().__init__(str) + self.repo_url_key = repo_url_key + + def post_validation(self, config, key_name): + repo_name = config.get(key_name) + repo_url = config.get(self.repo_url_key) + + # derive repo_name from repo_url if unset + if repo_url is not None and repo_name is None: + repo_host = urlsplit(config['repo_url']).netloc.lower() + if repo_host == 'github.com': + repo_name = 'GitHub' + elif repo_host == 'bitbucket.org': + repo_name = 'Bitbucket' + elif repo_host == 'gitlab.com': + repo_name = 'GitLab' + else: + repo_name = repo_host.split('.')[0].title() + config[key_name] = repo_name + + class FilesystemObject(Type): """ Base class for options that point to filesystem objects. diff --git a/mkdocs/config/defaults.py b/mkdocs/config/defaults.py index d2f99845fa..45e1186cf1 100644 --- a/mkdocs/config/defaults.py +++ b/mkdocs/config/defaults.py @@ -63,17 +63,17 @@ class _MkDocsConfig: True generates nicer URLs, but False is useful if browsing the output on a filesystem.""" - repo_url = config_options.RepoURL() + repo_url = config_options.URL() """Specify a link to the project source repo to be included in the documentation pages.""" - repo_name = config_options.Type(str) + repo_name = config_options.RepoName('repo_url') """A name to use for the link to the project source repo. Default, If repo_url is unset then None, otherwise "GitHub", "Bitbucket" or "GitLab" for known url or Hostname for unknown urls.""" - edit_uri = config_options.Type(str) + edit_uri = config_options.EditURI('repo_url') """Specify a URI to the docs dir in the project source repo, relative to the repo_url. When set, a link directly to the page in the source repo will be added to the generated HTML. If repo_url is not set also, this option diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py index 3ad71f2fc0..093a0d71eb 100644 --- a/mkdocs/tests/config/config_options_tests.py +++ b/mkdocs/tests/config/config_options_tests.py @@ -419,9 +419,9 @@ class Schema: class RepoURLTest(TestCase): class Schema: - repo_url = config_options.RepoURL() - repo_name = config_options.Type(str) - edit_uri = config_options.Type(str) + repo_url = config_options.URL() + repo_name = config_options.RepoName('repo_url') + edit_uri = config_options.EditURI('repo_url') def test_repo_name_github(self): config = self.get_config( @@ -479,7 +479,7 @@ def test_edit_uri_custom(self): self.Schema, {'repo_url': "https://launchpad.net/python-tuskarclient"}, ) - self.assertEqual(config.get('edit_uri'), '') + self.assertEqual(config.get('edit_uri'), None) self.assertEqual(config['repo_url'], "https://launchpad.net/python-tuskarclient") def test_repo_name_custom_and_empty_edit_uri(self): From ad43f1b8b7c5280dd8679af1d9624eed3b1bce1b Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Tue, 16 Aug 2022 00:39:21 +0200 Subject: [PATCH 2/4] Add `edit_uri_template` config --- mkdocs/config/config_options.py | 39 +++++++++++++++++++++ mkdocs/config/defaults.py | 1 + mkdocs/structure/pages.py | 19 +++++++--- mkdocs/tests/config/config_options_tests.py | 1 + 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py index 745c844cfc..9839114e84 100644 --- a/mkdocs/config/config_options.py +++ b/mkdocs/config/config_options.py @@ -2,11 +2,14 @@ import ipaddress import os +import string import sys import traceback import typing as t import warnings +from collections import UserString from typing import NamedTuple +from urllib.parse import quote as urlquote from urllib.parse import urlsplit, urlunsplit import markdown @@ -408,6 +411,42 @@ def post_validation(self, config, key_name): config[key_name] = edit_uri +class EditURITemplate(OptionallyRequired): + class Formatter(string.Formatter): + def convert_field(self, value, conversion): + if conversion == 'q': + return urlquote(value, safe='') + return super().convert_field(value, conversion) + + class Template(UserString): + def __init__(self, formatter, data): + super().__init__(data) + self.formatter = formatter + try: + self.format('', '') + except KeyError as e: + raise ValueError(f"Unknown template substitute: {e}") + + def format(self, path, path_noext): + return self.formatter.format(self.data, path=path, path_noext=path_noext) + + def __init__(self, edit_uri_key=None): + super().__init__() + self.edit_uri_key = edit_uri_key + + def run_validation(self, value): + try: + return self.Template(self.Formatter(), value) + except Exception as e: + raise ValidationError(e) + + def post_validation(self, config, key_name): + if self.edit_uri_key and config.get(key_name) and config.get(self.edit_uri_key): + self.warnings.append( + f"The option '{self.edit_uri_key}' has no effect when '{key_name}' is set." + ) + + class RepoName(Type): def __init__(self, repo_url_key): super().__init__(str) diff --git a/mkdocs/config/defaults.py b/mkdocs/config/defaults.py index 45e1186cf1..cf4b407327 100644 --- a/mkdocs/config/defaults.py +++ b/mkdocs/config/defaults.py @@ -73,6 +73,7 @@ class _MkDocsConfig: "GitHub", "Bitbucket" or "GitLab" for known url or Hostname for unknown urls.""" + edit_uri_template = config_options.EditURITemplate('edit_uri') edit_uri = config_options.EditURI('repo_url') """Specify a URI to the docs dir in the project source repo, relative to the repo_url. When set, a link directly to the page in the source repo will diff --git a/mkdocs/structure/pages.py b/mkdocs/structure/pages.py index 651f8bcafb..9fee878ba5 100644 --- a/mkdocs/structure/pages.py +++ b/mkdocs/structure/pages.py @@ -41,7 +41,9 @@ def __init__(self, title: Optional[str], file: File, config: Config) -> None: self.update_date = get_build_date() self._set_canonical_url(config.get('site_url', None)) - self._set_edit_url(config.get('repo_url', None), config.get('edit_uri', None)) + self._set_edit_url( + config.get('repo_url', None), config.get('edit_uri'), config.get('edit_uri_template') + ) # Placeholders to be filled in later in the build process. self.markdown = None @@ -172,10 +174,19 @@ def _set_canonical_url(self, base: Optional[str]) -> None: self.canonical_url = None self.abs_url = None - def _set_edit_url(self, repo_url: Optional[str], edit_uri: Optional[str]) -> None: - if edit_uri: + def _set_edit_url( + self, + repo_url: Optional[str], + edit_uri: Optional[str] = None, + edit_uri_template: Optional[str] = None, + ) -> None: + if edit_uri or edit_uri_template: src_uri = self.file.src_uri - edit_uri += src_uri + if edit_uri_template: + noext = posixpath.splitext(src_uri)[0] + edit_uri = edit_uri_template.format(path=src_uri, path_noext=noext) + else: + edit_uri += src_uri if repo_url: # Ensure urljoin behavior is correct if not edit_uri.startswith(('?', '#')) and not repo_url.endswith('/'): diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py index 093a0d71eb..8b7edc8e43 100644 --- a/mkdocs/tests/config/config_options_tests.py +++ b/mkdocs/tests/config/config_options_tests.py @@ -421,6 +421,7 @@ class RepoURLTest(TestCase): class Schema: repo_url = config_options.URL() repo_name = config_options.RepoName('repo_url') + edit_uri_template = config_options.EditURITemplate('edit_uri') edit_uri = config_options.EditURI('repo_url') def test_repo_name_github(self): From 4fcbdd3d3c2967bd6a24e25fd50be1168fd13115 Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Fri, 9 Sep 2022 23:16:48 +0200 Subject: [PATCH 3/4] Refactor `test_page_edit_url` --- mkdocs/tests/structure/page_tests.py | 120 ++++++++------------------- 1 file changed, 33 insertions(+), 87 deletions(-) diff --git a/mkdocs/tests/structure/page_tests.py b/mkdocs/tests/structure/page_tests.py index a0d1e3162c..5af1c0dc1f 100644 --- a/mkdocs/tests/structure/page_tests.py +++ b/mkdocs/tests/structure/page_tests.py @@ -429,156 +429,106 @@ def test_BOM(self, docs_dir): self.assertEqual(pg.markdown, md_src) self.assertEqual(pg.meta, {}) - def test_page_edit_url(self): + def test_page_edit_url( + self, paths={'testing.md': 'testing/', 'sub1/non-index.md': 'sub1/non-index/'} + ): for case in [ dict( config={'repo_url': 'http://github.com/mkdocs/mkdocs'}, edit_url='http://github.com/mkdocs/mkdocs/edit/master/docs/testing.md', + edit_url2='http://github.com/mkdocs/mkdocs/edit/master/docs/sub1/non-index.md', ), dict( config={'repo_url': 'https://github.com/mkdocs/mkdocs/'}, edit_url='https://github.com/mkdocs/mkdocs/edit/master/docs/testing.md', + edit_url2='https://github.com/mkdocs/mkdocs/edit/master/docs/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com'}, edit_url=None, + edit_url2=None, ), dict( config={'repo_url': 'http://example.com', 'edit_uri': 'edit/master'}, edit_url='http://example.com/edit/master/testing.md', + edit_url2='http://example.com/edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com', 'edit_uri': '/edit/master'}, edit_url='http://example.com/edit/master/testing.md', + edit_url2='http://example.com/edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com/foo/', 'edit_uri': '/edit/master/'}, edit_url='http://example.com/edit/master/testing.md', + edit_url2='http://example.com/edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com/foo', 'edit_uri': '/edit/master/'}, edit_url='http://example.com/edit/master/testing.md', + edit_url2='http://example.com/edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com/foo/', 'edit_uri': '/edit/master'}, edit_url='http://example.com/edit/master/testing.md', + edit_url2='http://example.com/edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com/foo/', 'edit_uri': 'edit/master/'}, edit_url='http://example.com/foo/edit/master/testing.md', + edit_url2='http://example.com/foo/edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com/foo', 'edit_uri': 'edit/master/'}, edit_url='http://example.com/foo/edit/master/testing.md', + edit_url2='http://example.com/foo/edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com', 'edit_uri': '?query=edit/master'}, edit_url='http://example.com?query=edit/master/testing.md', + edit_url2='http://example.com?query=edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com/', 'edit_uri': '?query=edit/master/'}, edit_url='http://example.com/?query=edit/master/testing.md', + edit_url2='http://example.com/?query=edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com', 'edit_uri': '#edit/master'}, edit_url='http://example.com#edit/master/testing.md', + edit_url2='http://example.com#edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com/', 'edit_uri': '#edit/master/'}, edit_url='http://example.com/#edit/master/testing.md', + edit_url2='http://example.com/#edit/master/sub1/non-index.md', ), dict( config={'edit_uri': 'http://example.com/edit/master'}, edit_url='http://example.com/edit/master/testing.md', + edit_url2='http://example.com/edit/master/sub1/non-index.md', ), dict( config={'repo_url': 'http://example.com', 'edit_uri': ''}, # Set to blank value edit_url=None, + edit_url2=None, ), - dict(config={}, edit_url=None), # Nothing defined + dict(config={}, edit_url=None, edit_url2=None), # Nothing defined ]: - with self.subTest(case['config']): - cfg = load_config(**case['config']) - fl = File('testing.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) - pg = Page('Foo', fl, cfg) - self.assertEqual(pg.url, 'testing/') - self.assertEqual(pg.edit_url, case['edit_url']) + for i, path in enumerate(paths, 1): + edit_url_key = f'edit_url{i}' if i > 1 else 'edit_url' + with self.subTest(case['config'], path=path): + cfg = load_config(**case['config']) + fl = File(path, cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) + pg = Page('Foo', fl, cfg) + self.assertEqual(pg.url, paths[path]) + self.assertEqual(pg.edit_url, case[edit_url_key]) - def test_nested_page_edit_url(self, file_src_path='sub1/non-index.md'): - for case in [ - dict( - config={'repo_url': 'http://github.com/mkdocs/mkdocs'}, - edit_url='http://github.com/mkdocs/mkdocs/edit/master/docs/sub1/non-index.md', - ), - dict( - config={'repo_url': 'https://github.com/mkdocs/mkdocs/'}, - edit_url='https://github.com/mkdocs/mkdocs/edit/master/docs/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com'}, - edit_url=None, - ), - dict( - config={'repo_url': 'http://example.com', 'edit_uri': 'edit/master'}, - edit_url='http://example.com/edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com', 'edit_uri': '/edit/master'}, - edit_url='http://example.com/edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com/foo/', 'edit_uri': '/edit/master/'}, - edit_url='http://example.com/edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com/foo', 'edit_uri': '/edit/master/'}, - edit_url='http://example.com/edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com/foo/', 'edit_uri': '/edit/master'}, - edit_url='http://example.com/edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com/foo/', 'edit_uri': 'edit/master/'}, - edit_url='http://example.com/foo/edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com/foo', 'edit_uri': 'edit/master/'}, - edit_url='http://example.com/foo/edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com', 'edit_uri': '?query=edit/master'}, - edit_url='http://example.com?query=edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com/', 'edit_uri': '?query=edit/master/'}, - edit_url='http://example.com/?query=edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com', 'edit_uri': '#edit/master'}, - edit_url='http://example.com#edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com/', 'edit_uri': '#edit/master/'}, - edit_url='http://example.com/#edit/master/sub1/non-index.md', - ), - dict( - config={'edit_uri': 'http://example.com/edit/master'}, - edit_url='http://example.com/edit/master/sub1/non-index.md', - ), - dict( - config={'repo_url': 'http://example.com', 'edit_uri': ''}, # Set to blank value - edit_url=None, - ), - ]: - with self.subTest(case['config']): - cfg = load_config(**case['config'], docs_dir=self.DOCS_DIR) - fl = File( - file_src_path, cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls'] - ) - pg = Page('Foo', fl, cfg) - self.assertEqual(pg.url, 'sub1/non-index/') - self.assertEqual(pg.edit_url, case['edit_url']) + @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") + def test_page_edit_url_windows(self): + self.test_page_edit_url( + paths={'testing.md': 'testing/', 'sub1\\non-index.md': 'sub1/non-index/'} + ) def test_page_edit_url_warning(self): for case in [ @@ -600,10 +550,6 @@ def test_page_edit_url_warning(self): self.assertEqual(pg.edit_url, case['edit_url']) self.assertEqual(cm.output, [case['warning']]) - @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") - def test_nested_page_edit_url_windows(self): - self.test_nested_page_edit_url(file_src_path='sub1\\non-index.md') - def test_page_render(self): cfg = load_config() fl = File('testing.md', cfg['docs_dir'], cfg['site_dir'], cfg['use_directory_urls']) From 4d4ef4c8f75699d466b5587ff6fd163e5c7d3e9a Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Fri, 9 Sep 2022 23:53:06 +0200 Subject: [PATCH 4/4] Add docs and tests for `edit_uri_template` option --- docs/user-guide/configuration.md | 75 +++++++++++++++++++++ mkdocs/structure/pages.py | 1 + mkdocs/tests/config/config_options_tests.py | 56 ++++++++++++++- mkdocs/tests/structure/page_tests.py | 35 +++++++++- 4 files changed, 165 insertions(+), 2 deletions(-) diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md index 953ce14ffb..8d4c266068 100644 --- a/docs/user-guide/configuration.md +++ b/docs/user-guide/configuration.md @@ -93,6 +93,24 @@ directory. edit_uri: root/path/docs/ ``` +For example, having this config: + +```yaml +repo_url: https://example.com/project/repo +edit_uri: blob/main/docs/ +``` + +means that a page named 'foo/bar.md' will have its edit link lead to: + + +`edit_uri` can actually be just an absolute URL, not necessarily relative to `repo_url`, so this can achieve the same result: + +```yaml +repo_url: https://example.com/project/repo/blob/main/docs/ +``` + +For more flexibility, see [edit_uri_template](#edit_uri_template) below. + > NOTE: > On a few known hosts (specifically GitHub, Bitbucket and GitLab), the > `edit_uri` is derived from the 'repo_url' and does not need to be set @@ -124,6 +142,63 @@ access. `src/default/docs/` for a Bitbucket repo, if `repo_url` matches those domains, otherwise `null` +### edit_uri_template + +The more flexible variant of [edit_uri](#edit_uri). These two are equivalent: + +```yaml +edit_uri: 'blob/main/docs/' +edit_uri_template: 'blob/main/docs/{path}' +``` + +(they are also mutually exclusive -- don't specify both). + +Starting from here, you can change the positioning or formatting of the path, in case the default behavior of appending the path isn't enough. + +The contents of `edit_uri_template` are normal [Python format strings](https://docs.python.org/3/library/string.html#formatstrings), with only these fields available: + +* `{path}`, e.g. `foo/bar.md` +* `{path_noext}`, e.g. `foo/bar` + +And the conversion flag `!q` is available, to percent-encode the field: + +* `{path!q}`, e.g. `foo%2Fbar.md` + +Here are some suggested configurations that can be useful: + +GitHub Wiki: +(e.g. `https://github.com/project/repo/wiki/foo/bar/_edit`) + +```yaml +repo_url: 'https://github.com/project/repo/wiki' +edit_uri_template: '{path_noext}/_edit' +``` + +BitBucket editor: +(e.g. `https://bitbucket.org/project/repo/src/master/docs/foo/bar.md?mode=edit`) + +```yaml +repo_url: 'https://bitbucket.org/project/repo/' +edit_uri_template: 'src/master/docs/{path}?mode=edit' +``` + +GitLab Static Site Editor: +(e.g. `https://gitlab.com/project/repo/-/sse/master/docs%2Ffoo%2bar.md`) + +```yaml +repo_url: 'https://gitlab.com/project/repo' +edit_uri_template: '-/sse/master/docs%2F{path!q}' +``` + +GitLab Web IDE: +(e.g. `https://gitlab.com/-/ide/project/repo/edit/master/-/docs/foo/bar.md`) + +```yaml +edit_uri_template: 'https://gitlab.com/-/ide/project/repo/edit/master/-/docs/{path}' +``` + +**default**: `null` + ### site_description Set the site description. This will add a meta tag to the generated HTML header. diff --git a/mkdocs/structure/pages.py b/mkdocs/structure/pages.py index 9fee878ba5..7f9d2ef511 100644 --- a/mkdocs/structure/pages.py +++ b/mkdocs/structure/pages.py @@ -186,6 +186,7 @@ def _set_edit_url( noext = posixpath.splitext(src_uri)[0] edit_uri = edit_uri_template.format(path=src_uri, path_noext=noext) else: + assert edit_uri is not None and edit_uri.endswith('/') edit_uri += src_uri if repo_url: # Ensure urljoin behavior is correct diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py index 8b7edc8e43..a1b0b3c1eb 100644 --- a/mkdocs/tests/config/config_options_tests.py +++ b/mkdocs/tests/config/config_options_tests.py @@ -417,7 +417,7 @@ class Schema: self.get_config(Schema, {'option': 1}) -class RepoURLTest(TestCase): +class EditURITest(TestCase): class Schema: repo_url = config_options.URL() repo_name = config_options.RepoName('repo_url') @@ -490,6 +490,60 @@ def test_repo_name_custom_and_empty_edit_uri(self): ) self.assertEqual(config.get('edit_uri'), 'edit/master/docs/') + def test_edit_uri_template_ok(self): + config = self.get_config( + self.Schema, + { + 'repo_url': "https://github.com/mkdocs/mkdocs", + 'edit_uri_template': 'edit/foo/docs/{path}', + }, + ) + self.assertEqual(config['edit_uri_template'], 'edit/foo/docs/{path}') + + def test_edit_uri_template_errors(self): + with self.expect_error( + edit_uri_template=re.compile(r'.*[{}].*') # Complains about unclosed '{' or missing '}' + ): + self.get_config( + self.Schema, + { + 'repo_url': "https://github.com/mkdocs/mkdocs", + 'edit_uri_template': 'edit/master/{path', + }, + ) + + with self.expect_error(edit_uri_template=re.compile(r'.*\bz\b.*')): + self.get_config( + self.Schema, + { + 'repo_url': "https://github.com/mkdocs/mkdocs", + 'edit_uri_template': 'edit/master/{path!z}', + }, + ) + + with self.expect_error(edit_uri_template="Unknown template substitute: 'foo'"): + self.get_config( + self.Schema, + { + 'repo_url': "https://github.com/mkdocs/mkdocs", + 'edit_uri_template': 'edit/master/{foo}', + }, + ) + + def test_edit_uri_template_warning(self): + config = self.get_config( + self.Schema, + { + 'repo_url': "https://github.com/mkdocs/mkdocs", + 'edit_uri': 'edit', + 'edit_uri_template': 'edit/master/{path}', + }, + warnings=dict( + edit_uri_template="The option 'edit_uri' has no effect when 'edit_uri_template' is set." + ), + ) + self.assertEqual(config['edit_uri_template'], 'edit/master/{path}') + class ListOfItemsTest(TestCase): def test_int_type(self): diff --git a/mkdocs/tests/structure/page_tests.py b/mkdocs/tests/structure/page_tests.py index 5af1c0dc1f..24b17a01a8 100644 --- a/mkdocs/tests/structure/page_tests.py +++ b/mkdocs/tests/structure/page_tests.py @@ -509,7 +509,40 @@ def test_page_edit_url( edit_url2='http://example.com/edit/master/sub1/non-index.md', ), dict( - config={'repo_url': 'http://example.com', 'edit_uri': ''}, # Set to blank value + config={'edit_uri_template': 'https://github.com/project/repo/wiki/{path_noext}'}, + edit_url='https://github.com/project/repo/wiki/testing', + edit_url2='https://github.com/project/repo/wiki/sub1/non-index', + ), + dict( + config={ + 'repo_url': 'https://github.com/project/repo/wiki', + 'edit_uri_template': '{path_noext}/_edit', + }, + edit_url='https://github.com/project/repo/wiki/testing/_edit', + edit_url2='https://github.com/project/repo/wiki/sub1/non-index/_edit', + ), + dict( + config={ + 'repo_url': 'https://gitlab.com/project/repo', + 'edit_uri_template': '-/sse/master/docs%2F{path!q}', + }, + edit_url='https://gitlab.com/project/repo/-/sse/master/docs%2Ftesting.md', + edit_url2='https://gitlab.com/project/repo/-/sse/master/docs%2Fsub1%2Fnon-index.md', + ), + dict( + config={ + 'repo_url': 'https://bitbucket.org/project/repo/', + 'edit_uri_template': 'src/master/docs/{path}?mode=edit', + }, + edit_url='https://bitbucket.org/project/repo/src/master/docs/testing.md?mode=edit', + edit_url2='https://bitbucket.org/project/repo/src/master/docs/sub1/non-index.md?mode=edit', + ), + dict( + config={ + 'repo_url': 'http://example.com', + 'edit_uri': '', + 'edit_uri_template': '', + }, # Set to blank value edit_url=None, edit_url2=None, ),