Edward, send the script to you. Here is a log fragment of my tests, please
ignore the git repo url in it, the real url of eagle has been placed in the
attached script, you don't need to modify anything but download the script
to any git working directory and open a console and run
./merge_pull_request.py -n 39. If there is anything that doesn't follow our
criteria, it will notify in output:
-------------------- START PROCESSING --------------------
INF: query pr information from github...
INF: will use "am_eagle_remote" as a remote name to operate
INF: looking up comments from github...
INF: verified: this pr is reviewed by ['anyway1021'] and finally approved
by ['anyway1021'], it's good to merge
INF: querying email address for reviewers' account from github...
INF: downloading 17.patch from github...
IPT: please input the description of the merge, which will be regarded as a
part of the final commit message
( to start new lines, to finish inputting):
recover
INF: committed to local repository on branch
operating_branch_1451350746196985, the commit history now looks like:
new -> * commit 643dc13d5560eae734ea1e9ac166d68adf363113 (HEAD,
operating_branch_1451350746196985)
| Author: ziwu ziyang...@ebay.com
| Date: Tue Dec 29 08:59:39 2015 +0800
|
| EAGLE-31 recover toString() of Address.java
| recover
|
| https://issues.apache.org/jira/browse/EAGLE-31
|
| Author: @anyway1021 <https://github.com/anyway1021> mchl....@gmail.com
| Reviewer(s): @anyway1021 <https://github.com/anyway1021>
mchl....@gmail.com
|
| Closes #17 <https://github.com/apache/incubator-eagle/pull/17>.
|
old -> * commit 2a935badad668b97de7c8e8a9150786c88fabb8d
(am_eagle_remote/master)
| Author: ziwu ziyang...@ebay.com
| Date: Mon Dec 28 22:58:14 2015 +0800
|
| EAGLE-31 add street1 info to toString() of Address.java
| ddaabb
|
| https://issues.apache.org/jira/browse/EAGLE-31
|
| Author: @anyway1021 <https://github.com/anyway1021> mchl....@gmail.com
| Reviewer(s): @anyway1021 <https://github.com/anyway1021>
mchl....@gmail.com
|
| Closes #16 <https://github.com/apache/incubator-eagle/pull/16>.
* commit ......
IPT: shall we push commit <643dc13d5560eae734ea1e9ac166d68adf363113> to
remote ?
():y
INF: pushing to remote repository...
INF: pull request <17> has been applied and pushed to remote of repository
https://github.com/anyway-checker/pr-merge-test.git
INF: if you're going to continue with any forked repository, please update
it accordingly
INF: Bye.
-------------------- ENDED PROCESSING --------------------

If you find any issue of using this script, please log a comment on
https://github.com/apache/incubator-eagle/pull/42

Thanks,
Michael


On Thu, Dec 31, 2015 at 2:57 PM, Zhang, Edward (GDI Hadoop) <
yonzh...@ebay.com> wrote:

> I am going to merge pull request 39, which is EAGLE-47.
>
> I did not follow your merge_pull_request.py, where do I get this python
> script and what is output of this script.
>
> Thanks
> Edward
>
> On 12/30/15, 22:48, "Michael Wu" <mchl....@gmail.com> wrote:
>
> >Edward,
> >
> >I think there may be 2 ways to reopen it:
> >1. you can ask the author to reopen it.
> >2. you can create a new one on page
> >
> https://github.com/apache/incubator-eagle/compare/master...qinzhaokun:EAGL
> >E-78?expand=1
> >.
> >
> >BTW, were you using the script I sent to you to merge and close the PR?
> >With it, you only need to execute it as "merge_pull_request.py -n 47".
> >Tips: the number "47" is the number of the PR. The script will check the
> >pr
> >title and all other necessary info to compose the final commit message.
> >
> >And, the title of PR 47 doesn't follow our criteria: EAGLE-${jira_number}
> >${pr_title_content}, please ask the author to revise it or you change it
> >when you recreate the PR.
> >
> >Thanks.
> >Michael
> >
> >On Thu, Dec 31, 2015 at 2:35 PM, Zhang, Edward (GDI Hadoop) <
> >yonzh...@ebay.com> wrote:
> >
> >> I made a mistake to close this pull request because I mistaken pull
> >> request id for jira id.
> >>
> >> Please advise how to reopen this pull request #47
> >>
> >> Thanks
> >> Edward
> >>
> >> On 12/30/15, 22:12, "asfgit" <g...@git.apache.org> wrote:
> >>
> >> >Github user asfgit closed the pull request at:
> >> >
> >> >    https://github.com/apache/incubator-eagle/pull/47
> >> >
> >> >
> >> >---
> >> >If your project is set up for it, you can reply to this email and have
> >> >your
> >> >reply appear on GitHub as well. If your project does not have this
> >>feature
> >> >enabled and wishes so, or if the feature is enabled but not working,
> >> >please
> >> >contact infrastructure at infrastruct...@apache.org or file a JIRA
> >>ticket
> >> >with INFRA.
> >> >---
> >>
> >>
>
>
#! /usr/bin/python2.7
import os
import urllib2 as url_lib
import getopt
import json
import sys
import subprocess
import re
import time

##### Constants Definitions - start #####
# textuals:
HELP_MESSAGE = "auto_merge.py -n <pr_number>"
GITHUB_ORGANIZATION = "apache"
REPO_NAME = "incubator-eagle"
APACHE_GIT_REPO_URL = "https://git-wip-us.apache.org/repos/asf/incubator-eagle.git";
PROJECT_PREFIX = "EAGLE-"
GITHUB_PR_STATE_OPEN = "open"
DEFAULT_REMOTE_NAME = "eagle_temp_upstream"
OPERATING_BRANCH_PREFIX = "operating_branch_"
TEMP_FILE_DIR = "patch_temp_folder"
APPROVED_SIGNS = [":+1:", "LGTM"]
REJECTED_SIGNS = [":-1:"]
ENCODING = "utf-8"

# string templates:
GITHUB_PATH_TUPLE = (GITHUB_ORGANIZATION, REPO_NAME)
GITHUB_PATCH_URL_TEMPLATE = "/".join(["https://patch-diff.githubusercontent.com/raw";, GITHUB_ORGANIZATION, REPO_NAME, "pull", "%s.patch"])
GITHUB_USER_INFO_TEMPLATE = "https://api.github.com/users/%s";
PR_INFO_API_TEMPLATE = "/".join(["https://api.github.com/repos";, GITHUB_ORGANIZATION, REPO_NAME, "pulls", "%s"])
PR_COMMENTS_API_TEMPLATE = "/".join(["https://api.github.com/repos";, GITHUB_ORGANIZATION, REPO_NAME, "issues", "%s/comments"])
JIRA_TICKET_LINK_TEMPLATE = "".join(["https://issues.apache.org/jira/browse/";, PROJECT_PREFIX, "%s"])
##### Constants Definitions - end #####

##### Define Valid Committers - start #####
committers = dict()
# here is where to add committer, with syntax: committers[author_github_id] = author_email_address
##### Define Valid Committers - end #####

# TODO - Px - need to filter low level log type and define invoking argument for specifying it

def to_console(msg):
	print msg

def __log_msg_list__(key, msg):
	if isinstance(msg, list):
		for sm in msg:
			to_console("%s: %s" % (key, sm))
	elif isinstance(msg, str):
		to_console("%s: %s" % (key, msg))
	elif isinstance(msg, unicode):
		to_console("%s: %s" % (key, msg.encode(ENCODING)))
	else:
		raise AttributeError("argument 'msg' must be a string, unicode or list, but %s is given" % type(msg))

def error(msg):
	__log_msg_list__("ERR", msg)

def warn(msg):
	__log_msg_list__("WRN", msg)

def info(msg):
	__log_msg_list__("INF", msg)

def debug(msg):
	__log_msg_list__("DBG", msg)

def display_help(*err_msg):
	if err_msg:
		if len(err_msg) == 1 and isinstance(err_msg[0], list):
			error(err_msg[0])
		else:
			error(list(err_msg))
	to_console("Usage: %s" % HELP_MESSAGE)

def exit_with_errmsg(err, err_code):
	if isinstance(err, subprocess.CalledProcessError):
		error(err.output.decode().strip() + ", exit with code %s ..." % str(err_code))
	else:
		error(str(err) + ", exit with code %s ..." % str(err_code))
	exit(err_code)

def extract_run_command_err_msg(e):
	return e.output.decode().strip()

def run_command(command):
	c = None
	if isinstance(command, list):
		c = command
	else:
		c = command.split(" ")
	return subprocess.check_output(c, stderr=subprocess.STDOUT).decode()

def get_info_from_github(url):
	try:
		gh_req = url_lib.Request(url)
		response = url_lib.urlopen(gh_req)
		pr_info = response.read().decode()
		return json.loads(pr_info)
	except url_lib.HTTPError as e:
		exit_with_errmsg("failed to get data from URL: %s" % url, -1)
	except url_lib.URLError as e:
		exit_with_errmsg("server not reachable: %s" % url, -1)

def get_repo_root_dir():
	try:
		return run_command("git rev-parse --show-toplevel").strip()
	except subprocess.CalledProcessError as e:
		exit_with_errmsg(e, -1)

def get_temp_file_dir():
	repo_root_dir = get_repo_root_dir()
	return os.sep.join([repo_root_dir, "..", TEMP_FILE_DIR])

def compose_patch_file_path(temp_dir, pr_number):
	return os.sep.join([temp_dir, "%s.patch" % pr_number])

def compose_commit_msg_template(temp_dir, pr_number):
	return os.sep.join([temp_dir, "pr_%s_commit_msg.template" % pr_number])

def is_working_directory_clean():
	return_code = subprocess.call(["git", "diff-index", "--quiet", "HEAD"])
	if return_code == 0:
		return True
	else:
		return False

def ensure_env(pr_number):
	try:
		temp_dir = get_temp_file_dir()

		# choose a remote name to operate
		rows = run_command("git remote -v").strip().split("\n")
		pushable_remote_name = ""
		for row in rows:
			if APACHE_GIT_REPO_URL in row:
				parts = re.split("\s+", row)
				if "push" in parts[2]:
					pushable_remote_name = parts[0]
					break
		if pushable_remote_name != "":   # find a pushable remote name
			info("will use \"%s\" as a remote name to operate" % pushable_remote_name)
		else:   # no pushable remote name, add one
			info("there is no pushable remote name defined, add \"%s\" for you" % DEFAULT_REMOTE_NAME)
			run_command("git remote add %s %s" % (DEFAULT_REMOTE_NAME, APACHE_GIT_REPO_URL))
			info("remote name \"%s\" added" % DEFAULT_REMOTE_NAME)
			pushable_remote_name = DEFAULT_REMOTE_NAME

		# check if the git working directory is clean
		if not is_working_directory_clean():
			exit_with_errmsg("working directory is not clean, please commit un-staged changes or stash them and try again", -1)

		# create temporary folder
		patch_file_path = compose_patch_file_path(temp_dir, pr_number)
		if os.path.exists(temp_dir):
			if os.path.exists(patch_file_path):
				os.remove(patch_file_path)
				info("old %s deleted successfully" % patch_file_path)
		else:
			run_command("mkdir %s" % temp_dir)
			info("%s created successfully" % temp_dir)
		
		return (pushable_remote_name, temp_dir)	
	except subprocess.CalledProcessError as e:
		exit_with_errmsg(e, -1)

def parse_pr_title(pr_title):
	regex = re.compile("^%s(\d+)\s+(.+)$" % PROJECT_PREFIX)
	match = re.search(regex, pr_title)
	if match:
		return (match.group(1), match.group(2))
	else:
		err_msg = "the title of the pull request should start with \"%s${jira_id}\", followed by a white-space and textual content, please revise accordingly" % PROJECT_PREFIX
		exit_with_errmsg(err_msg, -1)

def is_self_reviewed(author, reviewer):
	# currently, allow self-reviewing, but may disallow in the future
	#return author == reviewer
	return False

def is_valid_reviewer(reviewer):
	# currently, don't validate the authorization of the reviewer, may validate it in the future
	#return reviewer in committers.keys()
	return True

def ensure_quality_metrics(pr_number, author, last_push_timestamp):
	# TODO - Px - need to add checking steps for CI auto testing
	pr_comments_url = PR_COMMENTS_API_TEMPLATE % pr_number
	info("looking up comments from github...")
	pr_comments = get_info_from_github(pr_comments_url)
	count = len(pr_comments)
	reviewers = set()
	approvers = set()
	rejecters = set()
	never_found_review_comment = True   # True to mean haven't found any review comment
	for i in range(count-1, -1, -1):   # loop from count-1 to 0, step is -1
		comment_json = pr_comments[i]
		reviewer = comment_json['user']['login'].encode(ENCODING)
		comment_timestamp = comment_json['created_at'].encode(ENCODING)
		is_current_comment_valid = comment_timestamp > last_push_timestamp
		# currently, allow self-reviewing, but may disallow in the future, to disallow, modify in function is_self_reviewed()
		if is_self_reviewed(author, reviewer):   # the author of the pr shall not be considered as a reviewer
			continue
		if (is_valid_reviewer(reviewer) and
			not (reviewer in approvers or 
				reviewer in rejecters or 
				reviewer in reviewers)):   # valid review comments of this reviewer have been proceeded, continue to next comment
			comment = comment_json['body'].encode(ENCODING)
			parts = re.split("\n", comment)
			for part in parts:
				part = part.strip()
				#if part in APPROVED_SIGNS or part in REJECTED_SIGNS:
				if part in APPROVED_SIGNS:   # means current comment is a review comment
					if never_found_review_comment and not is_current_comment_valid:   # means the latest review comment is earlier than the latest commit
						exit_with_errmsg("the latest commit(s) of this pull request has not been approved, cannot merge it", -1)
					if never_found_review_comment:   # means find the latest review comment that is later than the latest commit, shall switch never_found_review_comment off
						never_found_review_comment = False
					if is_current_comment_valid:   # this review comment should be considered as part of approval or rejection of the pr
						if part in APPROVED_SIGNS:
							if reviewer not in rejecters:   # means, this approval is the latest valid review of this reviewer, considered as pr approved by this reviewer
								approvers.add(reviewer)
						else:   # means part in REJECTED_SIGNS, currently this condition is unreachable, but may be reachable in the future when we allow rejections, just keep it
							if reviewer not in approvers:   # means, this rejection is the latest valid review of this reviewer, considered as pr rejected by this reviewer
								rejecters.add(reviewer)
					reviewers.add(reviewer)
					break   # have found the review part in this comment, break to check next comment
		# currently, don't take rejections into account, may take it in the future by un-comment below 2 lines
		'''
		if (not is_current_comment_valid or i == 0) and len(rejecters) != 0:   # find the pr is rejected by some reviewers, and found all rejecters, should ask for their approval
			exit_with_errmsg("this pr is rejected by reviewers: %s, cannot merge it, please get approved and try again" % list(rejecters), -1)
		'''
	if never_found_review_comment:
		exit_with_errmsg("this pull request has not been approved, cannot merge it", -1)
	info("verified: this pr is reviewed by %s and finally approved by %s, it's good to merge" % (list(reviewers), list(approvers)))
	return list(reviewers)

def get_reviewer_email_mapping(reviewers_accounts):
	info("querying email address for reviewers' account from github...")
	reviewer_email_mapping = dict()
	for account in reviewers_accounts:
		reviewer_info = get_info_from_github(GITHUB_USER_INFO_TEMPLATE % account)
		email = reviewer_info['email'].encode(ENCODING)
		if email:
			reviewer_email_mapping[account] = email
		else:
			reviewer_email_mapping[account] = ""
			# because currently don't keep information of committers, if an email is None, just save it as ""
			#reviewer_email_mapping[account] = committers[account]
	return reviewer_email_mapping

def ask_for_input(prompt_msg):
	return raw_input("%s%s" % ("IPT: ", prompt_msg))

def ask_for_multiline_input(prompt_msg):
	to_console("IPT: %s" % prompt_msg)
	lines = sys.stdin.readlines()
	return lines

def is_valid_email(email):
	if not email:
		return False
	return re.search("^[\w\-\.]+@(\w[\w\-]+\.)+[a-zA-Z0-9]+$", email)

def has_branch(branch):
	try:
		result = run_command("git branch --list %s" % branch).strip()
		return result != ""
	except subprocess.CalledProcessError as e:
		exit_with_errmsg(e, -1)

def get_commit_history(branch, required_count):
	try:
		result = run_command("git log --decorate --graph -n %s" % required_count).strip()
		rows = re.split("\n", result)
		git_logs = []
		i = 0
		for row in rows:
			if row.startswith("*"):
				if i == 0:
					git_logs.append("new -> \t%s\n" % row)
					i += 1
				elif i == 1:
					git_logs.append("old -> \t%s\n" % row)
					i += 1
				else:
					git_logs.append("\t%s\n" % row)
			else:
				git_logs.append("\t%s\n" % row)
		git_logs.append("\t* commit ......")
		return "".join(git_logs)
	except subprocess.CalledProcessError as e:
		exit_with_errmsg(e, -1)

def compose_commit_template(commit_msg_template_file_path, pr_number, jira_id, pr_title_content, commit_description_lines, jira_url, author, author_email, reviewer_email_mapping):
	if os.path.exists(commit_msg_template_file_path):
		os.remove(commit_msg_template_file_path)
	comp = ["@%s <%s>" % (key, reviewer_email_mapping.get(key)) for key in reviewer_email_mapping.keys()]
	reviewer_row = "Reviewer(s): %s\r\n" % ", ".join(comp)
	with open(commit_msg_template_file_path, "w") as f:
		f.write("%s%s %s\r\n" % (PROJECT_PREFIX, jira_id, pr_title_content))
		for line in commit_description_lines:
			if line.strip() != "":
				f.write("%s" % line)
		f.write("\r\n")
		f.write("%s\r\n" % jira_url)
		f.write("\r\n")
		f.write("Author: @%s <%s>\r\n" % (author, author_email))
		f.write(reviewer_row)
		f.write("\r\n")
		f.write("Closes #%s.\r\n" % pr_number)

def download_file(download_url, file_path):
	source = url_lib.urlopen(download_url)
	with open(file_path, "wb") as f:
		f.write(source.read())

def merge_and_push(pushable_remote_name, base_sha, pr_number, temp_dir, jira_id, pr_title_content, jira_url, author, reviewer_email_mapping):
	original_branch = None
	operating_branch = "%s%s" % (OPERATING_BRANCH_PREFIX, str(time.time()).replace(".", ""))
	commit_msg_template_file_path = compose_commit_msg_template(temp_dir, pr_number)
	download_url = GITHUB_PATCH_URL_TEMPLATE % pr_number
	patch_file_path = compose_patch_file_path(temp_dir, pr_number)

	current_dir = run_command("pwd").strip()

	success = False

	try:
		repo_root_dir = get_repo_root_dir()
		os.chdir(repo_root_dir)   # this step is very important to 'git applly', without it, the command executed from some location may do nothing without notifications

		# download patch
		info("downloading %s.patch from github..." % pr_number)
		download_file(download_url, patch_file_path)

		# choose the right branch and check the sha
		original_branch = run_command("git rev-parse --abbrev-ref HEAD").strip()
		run_command("git fetch %s master" % pushable_remote_name)
		remote_master_sha = run_command("git rev-parse %s/master" % pushable_remote_name).strip()
		if base_sha != remote_master_sha:
			warn("the master branch of remote <%s> has commit(s) ahead of the ones in this %s.patch" % (pushable_remote_name, pr_number))
		run_command("git checkout -b %s %s/master" % (operating_branch, pushable_remote_name))
		run_command("git apply %s" % patch_file_path)

		# query email address of the author
		author_email = ""
		if author in reviewer_email_mapping.keys():   # the email of the author in reviewer list has been queried, no need to query again
			author_email = reviewer_email_mapping[author]
		else:
			info("querying email address of author <%s> from github" % author)
			author_info = get_info_from_github(GITHUB_USER_INFO_TEMPLATE % author)
			author_email = author_info['email'].encode(ENCODING)
		if not author_email or author_email.strip() == "":   # means couldn't find public email of author
			log_error = False
			skip_author_email_regexp = re.compile("^no$", re.I)
			# ask operater to input email for the author, skip by "no" or validate the input string
			while not is_valid_email(author_email):
				if not log_error:   # the first loop, shall not log error
					log_error = True
				else:
					error("the input is not a valid email address")
				author_email = ask_for_input("couldn't find public email of author <%s>, please input one (<input \"no\" and press Enter key> to skip):" % author).strip()
				if re.search(skip_author_email_regexp, author_email):
					author_email = ""
					break

		# prompt user to input description of this merge, better to open a vi
		commit_description_lines = ask_for_multiline_input("please input the description of the merge, which will be regarded as a part of the final commit message\n(<press Enter key> to start new lines, <press Ctrl+D> to finish inputting):")
		# in the input multi-line message, discard redundant blank lines after the meanful lines
		while len(commit_description_lines) != 0 and commit_description_lines[-1].strip() == "":
			commit_description_lines.pop()

		# compose the template file
		compose_commit_template(commit_msg_template_file_path, pr_number, jira_id, pr_title_content, commit_description_lines, jira_url, author, author_email, reviewer_email_mapping)

		# commit
		run_command("git commit -aF %s" % commit_msg_template_file_path)
		info("committed to local repository on branch %s, the commit history now looks like: " % operating_branch)
		history = get_commit_history(operating_branch, 2)
		to_console("%s" % history)
		newest_commit = run_command("git rev-parse HEAD").strip()
		choice = ask_for_input("shall we push commit <%s> to remote <%s/master>?\n(<input \"y\" or \"n\" and press Enter key>):" % (newest_commit, pushable_remote_name)).strip()
		if choice == "Y" or choice == "y":
			# push to remote
			info("pushing to remote repository...")
			run_command("git push %s %s:master" % (pushable_remote_name, operating_branch))
			success = True
		else:
			# log the info and depend finally-block to recover environment
			info("recovering working directory to original state...")
		return success
	except subprocess.CalledProcessError as e:
		exit_with_errmsg(e, -1)
	finally:
		if success:
			try:
				run_command("git checkout %s" % original_branch)
				run_command("git branch -D %s" % operating_branch)
			except subprocess.CalledProcessError as e:
				exit_with_errmsg(e, -1)
			finally:
				os.remove(commit_msg_template_file_path)
				os.remove(patch_file_path)
		else:
			try:
				if original_branch:
					if not is_working_directory_clean():
						run_command("git reset --hard %s" % original_branch)
					run_command("git checkout %s" % original_branch)
					if has_branch(operating_branch):
						run_command("git branch -D %s" % operating_branch)
			except subprocess.CalledProcessError as e:
				exit_with_errmsg(e, -1)
			finally:
				if os.path.exists(commit_msg_template_file_path):
					os.remove(commit_msg_template_file_path)
				if os.path.exists(patch_file_path):
					os.remove(patch_file_path)
		os.chdir(current_dir)

def main(argv):
	# cope with invoking arguments
	if len(argv) == 0:
		display_help("pull request number must be provided")
		exit(-1)
	pr_number = ""
	try:
		opts, args = getopt.getopt(argv, "hn:")
	except getopt.GetoptError as e:
		display_help(e.msg)
		sys.exit(-1)
	for opt, arg in opts:
		if opt == "-h":
			display_help()
			exit(1)
		elif opt == "-n":
			pr_number = arg

	# validate pr info
	to_console("-------------------- START PROCESSING --------------------")
	info("query pr information from github...")
	pr_info_url = PR_INFO_API_TEMPLATE % pr_number
	pr_info = get_info_from_github(pr_info_url)

	# validate pr state
	pr_state = pr_info['state'].encode(ENCODING)
	if pr_state != GITHUB_PR_STATE_OPEN:
		exit_with_errmsg("the state of pr %s is not %s, please try another pull request number" % (pr_number, GITHUB_PR_STATE_OPEN), -1)

	# validate if pr has conflict(s)
	pr_mergeable = pr_info['mergeable']
	if not pr_mergeable:
		exit_with_errmsg("this pull request contains conflict(s) that must be revolved", -1)

	# guarantee the environment for operations
	(pushable_remote_name, temp_dir) = ensure_env(pr_number)

	# validate and extract info from pr title, then generate jira url
	# currently will not check if the jira ticket is valid for reason of authentication complication
	(jira_id, pr_title_content) = parse_pr_title(pr_info['title'].encode(ENCODING))
	jira_url = JIRA_TICKET_LINK_TEMPLATE % jira_id

	# check if the pr is well approved and get reviewers' account together with their email
	last_push_timestamp = pr_info['head']['repo']['pushed_at'].encode(ENCODING)
	pr_author = pr_info['user']['login'].encode(ENCODING)
	reviewer_accounts = ensure_quality_metrics(pr_number, pr_author, last_push_timestamp)
	reviewer_email_mapping = get_reviewer_email_mapping(reviewer_accounts)

	# merge and push to github, to finish the whole process
	base_sha = pr_info['base']['sha'].encode(ENCODING)
	success = merge_and_push(pushable_remote_name, base_sha, pr_number, temp_dir, jira_id, pr_title_content, jira_url, pr_author, reviewer_email_mapping)

	# notify user to update the forked repo for original has been updated
	if success:
		info("pull request <%s> has been applied and pushed to remote <%s/master> of repository <%s>" % (pr_number, pushable_remote_name, APACHE_GIT_REPO_URL))
		info("if you're going to continue with any forked repository, please update it accordingly")
	else:
		info("the process is cancelled, and the environment has been recovered")
	info("Bye.")
	to_console("-------------------- ENDED PROCESSING --------------------")

if __name__ == "__main__":
	main(sys.argv[1:])

Reply via email to