{"action":"created","comment":{"url":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/comments/33830437","id":33830437,"diff_hunk":"@@ -64,11 +64,24 @@ def slugify(self, content):\n         if not content:\n             return ''\n         slugified = ''\n+        content = content.lower()\n         for char in content:\n             if char not in self.allowed_chars:\n                 slugified += self.placeholder\n             else:\n                 slugified += char\n+\n+        # Do not start and end in punctuation.\n+        slug_length = len(slugified)\n+        diff = 1\n+        while diff > 0:\n+            for char in self.allowed_punctuation:\n+                slugified = slugified.strip(char)\n+            diff = slug_length - len(slugified)\n+            slug_length = len(slugified)\n+\n+        if not slugified:\n+            return self.fallback_slug","path":"readthedocs/builds/version_slug.py","position":42,"original_position":42,"commit_id":"13f989b5c59b8af8dd44d926ff8ec55c4afb9d5c","original_commit_id":"13f989b5c59b8af8dd44d926ff8ec55c4afb9d5c","user":{"login":"agjohnson","id":1140183,"avatar_url":"https://avatars.githubusercontent.com/u/1140183?v=3","gravatar_id":"","url":"https://api.github.com/users/agjohnson","html_url":"https://github.com/agjohnson","followers_url":"https://api.github.com/users/agjohnson/followers","following_url":"https://api.github.com/users/agjohnson/following{/other_user}","gists_url":"https://api.github.com/users/agjohnson/gists{/gist_id}","starred_url":"https://api.github.com/users/agjohnson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/agjohnson/subscriptions","organizations_url":"https://api.github.com/users/agjohnson/orgs","repos_url":"https://api.github.com/users/agjohnson/repos","events_url":"https://api.github.com/users/agjohnson/events{/privacy}","received_events_url":"https://api.github.com/users/agjohnson/received_events","type":"User","site_admin":false},"body":"I'd also be +1 on replacing these blocks with regex comparisons/substitutions. These two blocks could be a single regex substitution, with a check against the final matches for empty/invalid slug.","created_at":"2015-07-02T22:53:54Z","updated_at":"2015-07-02T22:53:54Z","html_url":"https://github.com/rtfd/readthedocs.org/pull/1396#discussion_r33830437","pull_request_url":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/1396","_links":{"self":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/comments/33830437"},"html":{"href":"https://github.com/rtfd/readthedocs.org/pull/1396#discussion_r33830437"},"pull_request":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/1396"}}},"pull_request":{"url":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/1396","id":39128155,"html_url":"https://github.com/rtfd/readthedocs.org/pull/1396","diff_url":"https://github.com/rtfd/readthedocs.org/pull/1396.diff","patch_url":"https://github.com/rtfd/readthedocs.org/pull/1396.patch","issue_url":"https://api.github.com/repos/rtfd/readthedocs.org/issues/1396","number":1396,"state":"open","locked":false,"title":"Fix slug generation for uppercase branch names","user":{"login":"gregmuellegger","id":88278,"avatar_url":"https://avatars.githubusercontent.com/u/88278?v=3","gravatar_id":"","url":"https://api.github.com/users/gregmuellegger","html_url":"https://github.com/gregmuellegger","followers_url":"https://api.github.com/users/gregmuellegger/followers","following_url":"https://api.github.com/users/gregmuellegger/following{/other_user}","gists_url":"https://api.github.com/users/gregmuellegger/gists{/gist_id}","starred_url":"https://api.github.com/users/gregmuellegger/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gregmuellegger/subscriptions","organizations_url":"https://api.github.com/users/gregmuellegger/orgs","repos_url":"https://api.github.com/users/gregmuellegger/repos","events_url":"https://api.github.com/users/gregmuellegger/events{/privacy}","received_events_url":"https://api.github.com/users/gregmuellegger/received_events","type":"User","site_admin":false},"body":"There is another issue with slugs that was raised in #1176. The current implementation turns uppercase letters into dashes so that `SomeChar-charclass` as branch name results in `-ome-har-charclass` as slug. However our regex in the URLs don't allow leading dashes.\r\n\r\nThis PR changes the algorithm to strip punctuation from the generated slug. It includes a migration to fix the currently broken slugs. I tested locally that pypy's version page works after applying it.","created_at":"2015-07-02T21:34:00Z","updated_at":"2015-07-02T22:53:54Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1050df8b8a8fde2bb26153f7da51710146133005","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/1396/commits","review_comments_url":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/1396/comments","review_comment_url":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rtfd/readthedocs.org/issues/1396/comments","statuses_url":"https://api.github.com/repos/rtfd/readthedocs.org/statuses/13f989b5c59b8af8dd44d926ff8ec55c4afb9d5c","head":{"label":"rtfd:fix-slug-generation-for-uppercase","ref":"fix-slug-generation-for-uppercase","sha":"13f989b5c59b8af8dd44d926ff8ec55c4afb9d5c","user":{"login":"rtfd","id":366329,"avatar_url":"https://avatars.githubusercontent.com/u/366329?v=3","gravatar_id":"","url":"https://api.github.com/users/rtfd","html_url":"https://github.com/rtfd","followers_url":"https://api.github.com/users/rtfd/followers","following_url":"https://api.github.com/users/rtfd/following{/other_user}","gists_url":"https://api.github.com/users/rtfd/gists{/gist_id}","starred_url":"https://api.github.com/users/rtfd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rtfd/subscriptions","organizations_url":"https://api.github.com/users/rtfd/orgs","repos_url":"https://api.github.com/users/rtfd/repos","events_url":"https://api.github.com/users/rtfd/events{/privacy}","received_events_url":"https://api.github.com/users/rtfd/received_events","type":"Organization","site_admin":false},"repo":{"id":841835,"name":"readthedocs.org","full_name":"rtfd/readthedocs.org","owner":{"login":"rtfd","id":366329,"avatar_url":"https://avatars.githubusercontent.com/u/366329?v=3","gravatar_id":"","url":"https://api.github.com/users/rtfd","html_url":"https://github.com/rtfd","followers_url":"https://api.github.com/users/rtfd/followers","following_url":"https://api.github.com/users/rtfd/following{/other_user}","gists_url":"https://api.github.com/users/rtfd/gists{/gist_id}","starred_url":"https://api.github.com/users/rtfd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rtfd/subscriptions","organizations_url":"https://api.github.com/users/rtfd/orgs","repos_url":"https://api.github.com/users/rtfd/repos","events_url":"https://api.github.com/users/rtfd/events{/privacy}","received_events_url":"https://api.github.com/users/rtfd/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rtfd/readthedocs.org","description":"source code to readthedocs.org","fork":false,"url":"https://api.github.com/repos/rtfd/readthedocs.org","forks_url":"https://api.github.com/repos/rtfd/readthedocs.org/forks","keys_url":"https://api.github.com/repos/rtfd/readthedocs.org/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rtfd/readthedocs.org/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rtfd/readthedocs.org/teams","hooks_url":"https://api.github.com/repos/rtfd/readthedocs.org/hooks","issue_events_url":"https://api.github.com/repos/rtfd/readthedocs.org/issues/events{/number}","events_url":"https://api.github.com/repos/rtfd/readthedocs.org/events","assignees_url":"https://api.github.com/repos/rtfd/readthedocs.org/assignees{/user}","branches_url":"https://api.github.com/repos/rtfd/readthedocs.org/branches{/branch}","tags_url":"https://api.github.com/repos/rtfd/readthedocs.org/tags","blobs_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/refs{/sha}","trees_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rtfd/readthedocs.org/statuses/{sha}","languages_url":"https://api.github.com/repos/rtfd/readthedocs.org/languages","stargazers_url":"https://api.github.com/repos/rtfd/readthedocs.org/stargazers","contributors_url":"https://api.github.com/repos/rtfd/readthedocs.org/contributors","subscribers_url":"https://api.github.com/repos/rtfd/readthedocs.org/subscribers","subscription_url":"https://api.github.com/repos/rtfd/readthedocs.org/subscription","commits_url":"https://api.github.com/repos/rtfd/readthedocs.org/commits{/sha}","git_commits_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/commits{/sha}","comments_url":"https://api.github.com/repos/rtfd/readthedocs.org/comments{/number}","issue_comment_url":"https://api.github.com/repos/rtfd/readthedocs.org/issues/comments{/number}","contents_url":"https://api.github.com/repos/rtfd/readthedocs.org/contents/{+path}","compare_url":"https://api.github.com/repos/rtfd/readthedocs.org/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rtfd/readthedocs.org/merges","archive_url":"https://api.github.com/repos/rtfd/readthedocs.org/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rtfd/readthedocs.org/downloads","issues_url":"https://api.github.com/repos/rtfd/readthedocs.org/issues{/number}","pulls_url":"https://api.github.com/repos/rtfd/readthedocs.org/pulls{/number}","milestones_url":"https://api.github.com/repos/rtfd/readthedocs.org/milestones{/number}","notifications_url":"https://api.github.com/repos/rtfd/readthedocs.org/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rtfd/readthedocs.org/labels{/name}","releases_url":"https://api.github.com/repos/rtfd/readthedocs.org/releases{/id}","created_at":"2010-08-16T19:18:06Z","updated_at":"2015-07-02T15:28:13Z","pushed_at":"2015-07-02T21:42:46Z","git_url":"git://github.com/rtfd/readthedocs.org.git","ssh_url":"git@github.com:rtfd/readthedocs.org.git","clone_url":"https://github.com/rtfd/readthedocs.org.git","svn_url":"https://github.com/rtfd/readthedocs.org","homepage":"http://rtfd.org/","size":42315,"stargazers_count":1925,"watchers_count":1925,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":857,"mirror_url":null,"open_issues_count":154,"forks":857,"open_issues":154,"watchers":1925,"default_branch":"master"}},"base":{"label":"rtfd:master","ref":"master","sha":"5b59828ba14d3409613c7b5302e1cdcd2920eb11","user":{"login":"rtfd","id":366329,"avatar_url":"https://avatars.githubusercontent.com/u/366329?v=3","gravatar_id":"","url":"https://api.github.com/users/rtfd","html_url":"https://github.com/rtfd","followers_url":"https://api.github.com/users/rtfd/followers","following_url":"https://api.github.com/users/rtfd/following{/other_user}","gists_url":"https://api.github.com/users/rtfd/gists{/gist_id}","starred_url":"https://api.github.com/users/rtfd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rtfd/subscriptions","organizations_url":"https://api.github.com/users/rtfd/orgs","repos_url":"https://api.github.com/users/rtfd/repos","events_url":"https://api.github.com/users/rtfd/events{/privacy}","received_events_url":"https://api.github.com/users/rtfd/received_events","type":"Organization","site_admin":false},"repo":{"id":841835,"name":"readthedocs.org","full_name":"rtfd/readthedocs.org","owner":{"login":"rtfd","id":366329,"avatar_url":"https://avatars.githubusercontent.com/u/366329?v=3","gravatar_id":"","url":"https://api.github.com/users/rtfd","html_url":"https://github.com/rtfd","followers_url":"https://api.github.com/users/rtfd/followers","following_url":"https://api.github.com/users/rtfd/following{/other_user}","gists_url":"https://api.github.com/users/rtfd/gists{/gist_id}","starred_url":"https://api.github.com/users/rtfd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rtfd/subscriptions","organizations_url":"https://api.github.com/users/rtfd/orgs","repos_url":"https://api.github.com/users/rtfd/repos","events_url":"https://api.github.com/users/rtfd/events{/privacy}","received_events_url":"https://api.github.com/users/rtfd/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rtfd/readthedocs.org","description":"source code to readthedocs.org","fork":false,"url":"https://api.github.com/repos/rtfd/readthedocs.org","forks_url":"https://api.github.com/repos/rtfd/readthedocs.org/forks","keys_url":"https://api.github.com/repos/rtfd/readthedocs.org/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rtfd/readthedocs.org/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rtfd/readthedocs.org/teams","hooks_url":"https://api.github.com/repos/rtfd/readthedocs.org/hooks","issue_events_url":"https://api.github.com/repos/rtfd/readthedocs.org/issues/events{/number}","events_url":"https://api.github.com/repos/rtfd/readthedocs.org/events","assignees_url":"https://api.github.com/repos/rtfd/readthedocs.org/assignees{/user}","branches_url":"https://api.github.com/repos/rtfd/readthedocs.org/branches{/branch}","tags_url":"https://api.github.com/repos/rtfd/readthedocs.org/tags","blobs_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/refs{/sha}","trees_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rtfd/readthedocs.org/statuses/{sha}","languages_url":"https://api.github.com/repos/rtfd/readthedocs.org/languages","stargazers_url":"https://api.github.com/repos/rtfd/readthedocs.org/stargazers","contributors_url":"https://api.github.com/repos/rtfd/readthedocs.org/contributors","subscribers_url":"https://api.github.com/repos/rtfd/readthedocs.org/subscribers","subscription_url":"https://api.github.com/repos/rtfd/readthedocs.org/subscription","commits_url":"https://api.github.com/repos/rtfd/readthedocs.org/commits{/sha}","git_commits_url":"https://api.github.com/repos/rtfd/readthedocs.org/git/commits{/sha}","comments_url":"https://api.github.com/repos/rtfd/readthedocs.org/comments{/number}","issue_comment_url":"https://api.github.com/repos/rtfd/readthedocs.org/issues/comments{/number}","contents_url":"https://api.github.com/repos/rtfd/readthedocs.org/contents/{+path}","compare_url":"https://api.github.com/repos/rtfd/readthedocs.org/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rtfd/readthedocs.org/merges","archive_url":"https://api.github.com/repos/rtfd/readthedocs.org/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rtfd/readthedocs.org/downloads","issues_url":"https://api.github.com/repos/rtfd/readthedocs.org/issues{/number}","pulls_url":"https://api.github.com/repos/rtfd/readthedocs.org/pulls{/number}","milestones_url":"https://api.github.com/repos/rtfd/readthedocs.org/milestones{/number}","notifications_url":"https://api.github.com/repos/rtfd/readthedocs.org/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rtfd/readthedocs.org/labels{/name}","releases_url":"https://api.github.com/repos/rtfd/readthedocs.org/releases{/id}","created_at":"2010-08-16T19:18:06Z","updated_at":"2015-07-02T15:28:13Z","pushed_at":"2015-07-02T21:42:46Z","git_url":"git://github.com/rtfd/readthedocs.org.git","ssh_url":"git@github.com:rtfd/readthedocs.org.git","clone_url":"https://github.com/rtfd/readthedocs.org.git","svn_url":"https://github.com/rtfd/readthedocs.org","homepage":"http://rtfd.org/","size":42315,"stargazers_count":1925,"watchers_count":1925,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":857,"mirror_url":null,"open_issues_count":154,"forks":857,"open_issues":154,"watchers":1925,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/1396"},"html":{"href":"https://github.com/rtfd/readthedocs.org/pull/1396"},"issue":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/issues/1396"},"comments":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/issues/1396/comments"},"review_comments":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/1396/comments"},"review_comment":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/pulls/1396/commits"},"statuses":{"href":"https://api.github.com/repos/rtfd/readthedocs.org/statuses/13f989b5c59b8af8dd44d926ff8ec55c4afb9d5c"}}}}