diff --git a/cherry_picker/cherry_picker/cherry_picker.py b/cherry_picker/cherry_picker/cherry_picker.py index 01efce3..c3d29a7 100755 --- a/cherry_picker/cherry_picker/cherry_picker.py +++ b/cherry_picker/cherry_picker/cherry_picker.py @@ -6,9 +6,13 @@ import subprocess import webbrowser import sys +import requests + +from gidgethub import sansio from . import __version__ +CPYTHON_CREATE_PR_URL = "https://api.github.com/repos/python/cpython/pulls" class CherryPicker: @@ -139,9 +143,10 @@ def amend_commit_message(self, cherry_pick_branch): except subprocess.CalledProcessError as cpe: click.echo("Failed to amend the commit message \u2639") click.echo(cpe.output) + return updated_commit_message - def push_to_remote(self, base_branch, head_branch): + def push_to_remote(self, base_branch, head_branch, commit_message=""): """ git push """ cmd = f"git push {self.pr_remote} {head_branch}" @@ -150,7 +155,36 @@ def push_to_remote(self, base_branch, head_branch): except subprocess.CalledProcessError: click.echo(f"Failed to push to {self.pr_remote} \u2639") else: - self.open_pr(self.get_pr_url(base_branch, head_branch)) + gh_auth = os.getenv("GH_AUTH") + if gh_auth: + self.create_gh_pr(base_branch, head_branch, + commit_message=commit_message, + gh_auth=gh_auth) + else: + self.open_pr(self.get_pr_url(base_branch, head_branch)) + + def create_gh_pr(self, base_branch, head_branch, *, + commit_message, + gh_auth): + """ + Create PR in GitHub + """ + request_headers = sansio.create_headers( + self.username, oauth_token=gh_auth) + title, body = normalize_commit_message(commit_message) + data = { + "title": title, + "body": body, + "head": f"{self.username}:{head_branch}", + "base": base_branch, + "maintainer_can_modify": True + } + response = requests.post(CPYTHON_CREATE_PR_URL, headers=request_headers, json=data) + if response.status_code == requests.codes.created: + click.echo(f"Backport PR created at {response.json()['_links']['html']}") + else: + click.echo(response.status_code) + click.echo(response.text) def open_pr(self, url): """ @@ -184,16 +218,19 @@ def backport(self): cherry_pick_branch = self.get_cherry_pick_branch(maint_branch) self.checkout_branch(maint_branch) + commit_message = "" try: self.cherry_pick() - self.amend_commit_message(cherry_pick_branch) + commit_message = self.amend_commit_message(cherry_pick_branch) except subprocess.CalledProcessError as cpe: click.echo(cpe.output) click.echo(self.get_exit_message(maint_branch)) sys.exit(-1) else: if self.push: - self.push_to_remote(maint_branch, cherry_pick_branch) + self.push_to_remote(maint_branch, + cherry_pick_branch, + commit_message) self.cleanup_branch(cherry_pick_branch) else: click.echo(\ @@ -331,6 +368,15 @@ def is_cpython_repo(): return False return True +def normalize_commit_message(commit_message): + """ + Return a tuple of title and body from the commit message + """ + split_commit_message = commit_message.split("\n") + title = split_commit_message[0] + body = "\n".join(split_commit_message[1:]) + return title, body.lstrip("\n") + if __name__ == '__main__': cherry_pick_cli() diff --git a/cherry_picker/cherry_picker/test.py b/cherry_picker/cherry_picker/test.py index cae072e..6c50b4f 100644 --- a/cherry_picker/cherry_picker/test.py +++ b/cherry_picker/cherry_picker/test.py @@ -3,7 +3,8 @@ import pytest from .cherry_picker import get_base_branch, get_current_branch, \ - get_full_sha_from_short, is_cpython_repo, CherryPicker + get_full_sha_from_short, is_cpython_repo, CherryPicker, \ + normalize_commit_message def test_get_base_branch(): @@ -112,3 +113,24 @@ def test_is_cpython_repo(subprocess_check_output): def test_is_not_cpython_repo(): assert is_cpython_repo() == False +def test_normalize_long_commit_message(): + commit_message = """[3.6] Fix broken `Show Source` links on documentation pages (GH-3113) + +The `Show Source` was broken because of a change made in sphinx 1.5.1 +In Sphinx 1.4.9, the sourcename was "index.txt". +In Sphinx 1.5.1+, it is now "index.rst.txt". +(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)""" + title, body = normalize_commit_message(commit_message) + assert title == "[3.6] Fix broken `Show Source` links on documentation pages (GH-3113)" + assert body == """The `Show Source` was broken because of a change made in sphinx 1.5.1 +In Sphinx 1.4.9, the sourcename was "index.txt". +In Sphinx 1.5.1+, it is now "index.rst.txt". +(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)""" + +def test_normalize_short_commit_message(): + commit_message = """[3.6] Fix broken `Show Source` links on documentation pages (GH-3113) + +(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)""" + title, body = normalize_commit_message(commit_message) + assert title == "[3.6] Fix broken `Show Source` links on documentation pages (GH-3113)" + assert body == """(cherry picked from commit b9ff498793611d1c6a9b99df464812931a1e2d69)""" \ No newline at end of file diff --git a/cherry_picker/flit.ini b/cherry_picker/flit.ini index 9e1abd1..5539194 100644 --- a/cherry_picker/flit.ini +++ b/cherry_picker/flit.ini @@ -6,6 +6,8 @@ maintainer = Python Core Developers maintainer-email = core-workflow@python.org home-page = https://github.com/python/core-workflow/tree/master/cherry_picker requires = click~=6.7 + gidgethub + requests dev-requires = pytest~=3.0.7 description-file = readme.rst classifiers = Programming Language :: Python :: 3.6 diff --git a/cherry_picker/readme.rst b/cherry_picker/readme.rst index 888bbaf..9663460 100644 --- a/cherry_picker/readme.rst +++ b/cherry_picker/readme.rst @@ -18,7 +18,7 @@ maintenance branches (``3.6``, ``3.5``, ``2.7``). It will prefix the commit message with the branch, e.g. ``[3.6]``, and then opens up the pull request page. -Tests are to be written using pytest. +Tests are to be written using `pytest `_. Setup Info