Repository: mkdocs/mkdocs

Issue:
Broken 'Edit on GitHub' link
We recently updated to 0.17.0 and it seems to have broken our 'Edit on GitHub' link, you can see this in action [here](https://opensciencegrid.github.io/docs/). The link given is https://github.com/edit/master/docs/index.md when it should be https://github.com/opensciencegrid/docs/edit/master/docs/index.md. [repo_url](https://github.com/opensciencegrid/docs/blob/master/mkdocs.yml#L3) appears to be set properly.

Discussion:

Patch:
diff --git a/docs/about/release-notes.md b/docs/about/release-notes.md
index 22e2d900..64dc8a9b 100644
--- a/docs/about/release-notes.md
+++ b/docs/about/release-notes.md
@@ -23,6 +23,7 @@ The current and past members of the MkDocs team.
 
 ## Development Version
 
+* Bugfix: Support `repo_url` with missing ending slash. (#1321).
 * Bugfix: Add length support to `mkdocs.toc.TableOfContext` (#1325).
 * Bugfix: Add some theme specific settings to the search plugin for third party
   themes (#1316).
diff --git a/mkdocs/config/config_options.py b/mkdocs/config/config_options.py
index 230a49e8..01fbd5ab 100644
--- a/mkdocs/config/config_options.py
+++ b/mkdocs/config/config_options.py
@@ -276,7 +276,7 @@ class RepoURL(URL):
         if edit_uri:
             if not edit_uri.startswith(('?', '#')) \
                     and not config['repo_url'].endswith('/'):
-                edit_uri = '/' + edit_uri
+                config['repo_url'] += '/'
             if not edit_uri.endswith('/'):
                 edit_uri += '/'
 


Test patch:
diff --git a/mkdocs/tests/config/config_options_tests.py b/mkdocs/tests/config/config_options_tests.py
index 7bdb49a0..87394fe5 100644
--- a/mkdocs/tests/config/config_options_tests.py
+++ b/mkdocs/tests/config/config_options_tests.py
@@ -196,7 +196,7 @@ class RepoURLTest(unittest.TestCase):
         option = config_options.RepoURL()
         config = {'repo_url': "https://github.com/mkdocs/mkdocs"}
         option.post_validation(config, 'repo_url')
-        self.assertEqual(config['edit_uri'], '/edit/master/docs/')
+        self.assertEqual(config['edit_uri'], 'edit/master/docs/')
 
     def test_edit_uri_bitbucket(self):
 
@@ -218,7 +218,7 @@ class RepoURLTest(unittest.TestCase):
         config = {'repo_url': "https://github.com/mkdocs/mkdocs",
                   'repo_name': 'mkdocs'}
         option.post_validation(config, 'repo_url')
-        self.assertEqual(config.get('edit_uri'), '/edit/master/docs/')
+        self.assertEqual(config.get('edit_uri'), 'edit/master/docs/')
 
 
 class DirTest(unittest.TestCase):
diff --git a/mkdocs/tests/nav_tests.py b/mkdocs/tests/nav_tests.py
index 98fa515e..d8648b1c 100644
--- a/mkdocs/tests/nav_tests.py
+++ b/mkdocs/tests/nav_tests.py
@@ -466,9 +466,6 @@ class SiteNavigationTests(unittest.TestCase):
         self.assertEqual(str(site_navigation).strip(), expected)
 
     def test_edit_uri(self):
-        """
-        Ensure that set_edit_url creates well formed URLs for edit_uri
-        """
 
         pages = [
             'index.md',
@@ -500,6 +497,47 @@ class SiteNavigationTests(unittest.TestCase):
         for idx, page in enumerate(site_navigation.walk_pages()):
             self.assertEqual(page.edit_url, expected_results[idx])
 
+    def test_edit_uri_sub_dir(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub/internal.md',
+            'sub1/sub2/internal.md',
+        ]
+
+        # Basic test
+        repo_url = 'http://example.com/foo/'
+        edit_uri = 'edit/master/docs/'
+
+        site_navigation = nav.SiteNavigation(load_config(
+            pages=pages,
+            repo_url=repo_url,
+            edit_uri=edit_uri,
+            site_dir='site',
+            site_url='',
+            use_directory_urls=True
+        ))
+
+        expected_results = (
+            repo_url + edit_uri + pages[0],
+            repo_url + edit_uri + pages[1],
+            repo_url + edit_uri + pages[2],
+            repo_url + edit_uri + pages[3],
+        )
+
+        for idx, page in enumerate(site_navigation.walk_pages()):
+            self.assertEqual(page.edit_url, expected_results[idx])
+
+    def test_edit_uri_missing_slash(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub/internal.md',
+            'sub1/sub2/internal.md',
+        ]
+
         # Ensure the '/' is added to the repo_url and edit_uri
         repo_url = 'http://example.com'
         edit_uri = 'edit/master/docs'
@@ -513,9 +551,57 @@ class SiteNavigationTests(unittest.TestCase):
             use_directory_urls=True
         ))
 
+        expected_results = (
+            repo_url + '/' + edit_uri + '/' + pages[0],
+            repo_url + '/' + edit_uri + '/' + pages[1],
+            repo_url + '/' + edit_uri + '/' + pages[2],
+            repo_url + '/' + edit_uri + '/' + pages[3],
+        )
+
         for idx, page in enumerate(site_navigation.walk_pages()):
             self.assertEqual(page.edit_url, expected_results[idx])
 
+    def test_edit_uri_sub_dir_missing_slash(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub/internal.md',
+            'sub1/sub2/internal.md',
+        ]
+
+        # Basic test
+        repo_url = 'http://example.com/foo'
+        edit_uri = 'edit/master/docs'
+
+        site_navigation = nav.SiteNavigation(load_config(
+            pages=pages,
+            repo_url=repo_url,
+            edit_uri=edit_uri,
+            site_dir='site',
+            site_url='',
+            use_directory_urls=True
+        ))
+
+        expected_results = (
+            repo_url + '/' + edit_uri + '/' + pages[0],
+            repo_url + '/' + edit_uri + '/' + pages[1],
+            repo_url + '/' + edit_uri + '/' + pages[2],
+            repo_url + '/' + edit_uri + '/' + pages[3],
+        )
+
+        for idx, page in enumerate(site_navigation.walk_pages()):
+            self.assertEqual(page.edit_url, expected_results[idx])
+
+    def test_edit_uri_query_string(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub/internal.md',
+            'sub1/sub2/internal.md',
+        ]
+
         # Ensure query strings are supported
         repo_url = 'http://example.com'
         edit_uri = '?query=edit/master/docs/'
@@ -539,6 +625,15 @@ class SiteNavigationTests(unittest.TestCase):
         for idx, page in enumerate(site_navigation.walk_pages()):
             self.assertEqual(page.edit_url, expected_results[idx])
 
+    def test_edit_uri_fragment(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub/internal.md',
+            'sub1/sub2/internal.md',
+        ]
+
         # Ensure fragment strings are supported
         repo_url = 'http://example.com'
         edit_uri = '#fragment/edit/master/docs/'
@@ -563,9 +658,6 @@ class SiteNavigationTests(unittest.TestCase):
             self.assertEqual(page.edit_url, expected_results[idx])
 
     def test_edit_uri_windows(self):
-        """
-        Ensure that set_edit_url creates well formed URLs for edit_uri with a windows path
-        """
 
         pages = [
             'index.md',
@@ -597,6 +689,47 @@ class SiteNavigationTests(unittest.TestCase):
         for idx, page in enumerate(site_navigation.walk_pages()):
             self.assertEqual(page.edit_url, expected_results[idx])
 
+    def test_edit_uri_sub_dir_windows(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub\\internal.md',
+            'sub1\\sub2\\internal.md',
+        ]
+
+        # Basic test
+        repo_url = 'http://example.com/foo/'
+        edit_uri = 'edit/master/docs/'
+
+        site_navigation = nav.SiteNavigation(load_config(
+            pages=pages,
+            repo_url=repo_url,
+            edit_uri=edit_uri,
+            site_dir='site',
+            site_url='',
+            use_directory_urls=True
+        ))
+
+        expected_results = (
+            repo_url + edit_uri + pages[0],
+            repo_url + edit_uri + pages[1],
+            repo_url + edit_uri + pages[2].replace('\\', '/'),
+            repo_url + edit_uri + pages[3].replace('\\', '/'),
+        )
+
+        for idx, page in enumerate(site_navigation.walk_pages()):
+            self.assertEqual(page.edit_url, expected_results[idx])
+
+    def test_edit_uri_missing_slash_windows(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub\\internal.md',
+            'sub1\\sub2\\internal.md',
+        ]
+
         # Ensure the '/' is added to the repo_url and edit_uri
         repo_url = 'http://example.com'
         edit_uri = 'edit/master/docs'
@@ -610,9 +743,57 @@ class SiteNavigationTests(unittest.TestCase):
             use_directory_urls=True
         ))
 
+        expected_results = (
+            repo_url + '/' + edit_uri + '/' + pages[0],
+            repo_url + '/' + edit_uri + '/' + pages[1],
+            repo_url + '/' + edit_uri + '/' + pages[2].replace('\\', '/'),
+            repo_url + '/' + edit_uri + '/' + pages[3].replace('\\', '/'),
+        )
+
         for idx, page in enumerate(site_navigation.walk_pages()):
             self.assertEqual(page.edit_url, expected_results[idx])
 
+    def test_edit_uri_sub_dir_missing_slash_windows(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub\\internal.md',
+            'sub1\\sub2\\internal.md',
+        ]
+
+        # Ensure the '/' is added to the repo_url and edit_uri
+        repo_url = 'http://example.com/foo'
+        edit_uri = 'edit/master/docs'
+
+        site_navigation = nav.SiteNavigation(load_config(
+            pages=pages,
+            repo_url=repo_url,
+            edit_uri=edit_uri,
+            site_dir='site',
+            site_url='',
+            use_directory_urls=True
+        ))
+
+        expected_results = (
+            repo_url + '/' + edit_uri + '/' + pages[0],
+            repo_url + '/' + edit_uri + '/' + pages[1],
+            repo_url + '/' + edit_uri + '/' + pages[2].replace('\\', '/'),
+            repo_url + '/' + edit_uri + '/' + pages[3].replace('\\', '/'),
+        )
+
+        for idx, page in enumerate(site_navigation.walk_pages()):
+            self.assertEqual(page.edit_url, expected_results[idx])
+
+    def test_edit_uri_query_string_windows(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub\\internal.md',
+            'sub1\\sub2\\internal.md',
+        ]
+
         # Ensure query strings are supported
         repo_url = 'http://example.com'
         edit_uri = '?query=edit/master/docs/'
@@ -636,6 +817,15 @@ class SiteNavigationTests(unittest.TestCase):
         for idx, page in enumerate(site_navigation.walk_pages()):
             self.assertEqual(page.edit_url, expected_results[idx])
 
+    def test_edit_uri_fragment_windows(self):
+
+        pages = [
+            'index.md',
+            'internal.md',
+            'sub\\internal.md',
+            'sub1\\sub2\\internal.md',
+        ]
+
         # Ensure fragment strings are supported
         repo_url = 'http://example.com'
         edit_uri = '#fragment/edit/master/docs/'