mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-25 11:00:35 +00:00
Adding an auto-backport.py script to handle backport automation instead of Mergify.
The rules of backport are as follows:
* Merged or Closed PRs with any backport/x.y label (one or more) and promoted-to-master label
* Backport PR will be automatically assigned to the original PR author
* In case of conflicts the backport PR will be open in the original autoor fork in draft mode. This will give the PR owner the option to resolve conflicts and push those changes to the PR branch (Today in Scylla when we have conflicts, the developers are forced to open another PR and manually close the backport PR opened by Mergify)
* Fixing cherry-pick the wrong commit SHA. With the new script, we always take the SHA from the stable branch
* Support backport for enterprise releases (from Enterprise branch)
Fixes: https://github.com/scylladb/scylladb/issues/18973
(cherry picked from commit f9e171c7af)
Closes scylladb/scylladb#21469
88 lines
3.8 KiB
Python
Executable File
88 lines
3.8 KiB
Python
Executable File
import argparse
|
|
import re
|
|
import sys
|
|
import os
|
|
from github import Github
|
|
from github.GithubException import UnknownObjectException
|
|
|
|
try:
|
|
github_token = os.environ["GITHUB_TOKEN"]
|
|
except KeyError:
|
|
print("Please set the 'GITHUB_TOKEN' environment variable")
|
|
sys.exit(1)
|
|
|
|
|
|
def parser():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--repository', type=str, required=True,
|
|
help='Github repository name (e.g., scylladb/scylladb)')
|
|
parser.add_argument('--commits', type=str, required=True, help='Range of promoted commits.')
|
|
parser.add_argument('--label', type=str, default='promoted-to-master', help='Label to use')
|
|
parser.add_argument('--ref', type=str, required=True, help='PR target branch')
|
|
return parser.parse_args()
|
|
|
|
|
|
def add_comment_and_close_pr(pr, comment):
|
|
if pr.state == 'open':
|
|
pr.create_issue_comment(comment)
|
|
pr.edit(state="closed")
|
|
|
|
|
|
def mark_backport_done(repo, ref_pr_number, branch):
|
|
pr = repo.get_pull(int(ref_pr_number))
|
|
label_to_remove = f'backport/{branch}'
|
|
label_to_add = f'{label_to_remove}-done'
|
|
current_labels = [label.name for label in pr.get_labels()]
|
|
if label_to_remove in current_labels:
|
|
pr.remove_from_labels(label_to_remove)
|
|
if label_to_add not in current_labels:
|
|
pr.add_to_labels(label_to_add)
|
|
|
|
|
|
def main():
|
|
# This script is triggered by a push event to either the master branch or a branch named branch-x.y (where x and y represent version numbers). Based on the pushed branch, the script performs the following actions:
|
|
# - When ref branch is `master`, it will add the `promoted-to-master` label, which we need later for the auto backport process
|
|
# - When ref branch is `branch-x.y` (which means we backported a patch), it will replace in the original PR the `backport/x.y` label with `backport/x.y-done` and will close the backport PR (Since GitHub close only the one referring to default branch)
|
|
args = parser()
|
|
pr_pattern = re.compile(r'Closes .*#([0-9]+)')
|
|
target_branch = re.search(r'branch-(\d+\.\d+)', args.ref)
|
|
g = Github(github_token)
|
|
repo = g.get_repo(args.repository, lazy=False)
|
|
start_commit, end_commit = args.commits.split('..')
|
|
commits = repo.compare(start_commit, end_commit).commits
|
|
processed_prs = set()
|
|
# Print commit information
|
|
for commit in commits:
|
|
print(f'Commit sha is: {commit.sha}')
|
|
match = pr_pattern.search(commit.commit.message)
|
|
if match:
|
|
pr_number = int(match.group(1))
|
|
if pr_number in processed_prs:
|
|
continue
|
|
if target_branch:
|
|
pr = repo.get_pull(pr_number)
|
|
branch_name = target_branch[1]
|
|
refs_pr = re.findall(r'Parent PR: (?:#|https.*?)(\d+)', pr.body)
|
|
if refs_pr:
|
|
print(f'branch-{target_branch.group(1)}, pr number is: {pr_number}')
|
|
# 1. change the backport label of the parent PR to note that
|
|
# we've merged the corresponding backport PR
|
|
# 2. close the backport PR and leave a comment on it to note
|
|
# that it has been merged with a certain git commit.
|
|
ref_pr_number = refs_pr[0]
|
|
mark_backport_done(repo, ref_pr_number, branch_name)
|
|
comment = f'Closed via {commit.sha}'
|
|
add_comment_and_close_pr(pr, comment)
|
|
else:
|
|
try:
|
|
pr = repo.get_pull(pr_number)
|
|
pr.add_to_labels('promoted-to-master')
|
|
print(f'master branch, pr number is: {pr_number}')
|
|
except UnknownObjectException:
|
|
print(f'{pr_number} is not a PR but an issue, no need to add label')
|
|
processed_prs.add(pr_number)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|