Merge pull request #18195 from abyss7/backport-lts

Add support for LTS branches in backport automation
This commit is contained in:
alexey-milovidov 2020-12-22 09:49:02 +03:00 committed by GitHub
commit 839e873aa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 131 deletions

View File

@ -1,8 +1,13 @@
# -*- coding: utf-8 -*-
from clickhouse.utils.github.cherrypick import CherryPick
from clickhouse.utils.github.query import Query as RemoteRepo
from clickhouse.utils.github.local import Repository as LocalRepo
try:
from clickhouse.utils.github.cherrypick import CherryPick
from clickhouse.utils.github.query import Query as RemoteRepo
from clickhouse.utils.github.local import Repository as LocalRepo
except:
from .cherrypick import CherryPick
from .query import Query as RemoteRepo
from .local import Repository as LocalRepo
import argparse
import logging
@ -20,9 +25,25 @@ class Backport:
def getPullRequests(self, from_commit):
return self._gh.get_pull_requests(from_commit)
def execute(self, repo, until_commit, number, run_cherrypick):
def getBranchesWithLTS(self):
branches = []
for pull_request in self._gh.find_pull_requests("release-lts"):
if not pull_request['merged'] and not pull_request['closed']:
branches.append(pull_request['headRefName'])
return branches
def execute(self, repo, until_commit, number, run_cherrypick, find_lts=False):
repo = LocalRepo(repo, 'origin', self.default_branch_name)
branches = repo.get_release_branches()[-number:] # [(branch_name, base_commit)]
all_branches = repo.get_release_branches() # [(branch_name, base_commit)]
last_branches = set([branch[0] for branch in all_branches[-number:]])
lts_branches = set(self.getBranchesWithLTS() if find_lts else [])
branches = []
# iterate over all branches to preserve their precedence.
for branch in all_branches:
if branch in last_branches or branch in lts_branches:
branches.append(branch)
if not branches:
logging.info('No release branches found!')
@ -95,6 +116,7 @@ if __name__ == "__main__":
parser.add_argument('--repo', type=str, required=True, help='path to full repository', metavar='PATH')
parser.add_argument('--til', type=str, help='check PRs from HEAD til this commit', metavar='COMMIT')
parser.add_argument('-n', type=int, dest='number', help='number of last release branches to consider')
parser.add_argument('--lts', action='store_true', help='consider branches with LTS')
parser.add_argument('--dry-run', action='store_true', help='do not create or merge any PRs', default=False)
parser.add_argument('--verbose', '-v', action='store_true', help='more verbose output', default=False)
args = parser.parse_args()
@ -106,4 +128,4 @@ if __name__ == "__main__":
cherrypick_run = lambda token, pr, branch: CherryPick(token, 'ClickHouse', 'ClickHouse', 'core', pr, branch).execute(args.repo, args.dry_run)
bp = Backport(args.token, 'ClickHouse', 'ClickHouse', 'core')
bp.execute(args.repo, args.til, args.number, cherrypick_run)
bp.execute(args.repo, args.til, args.number, cherrypick_run, args.lts)

View File

@ -14,7 +14,10 @@ Second run checks PR from previous run to be merged or at least being mergeable.
Third run creates PR from backport branch (with merged previous PR) to release branch.
'''
from clickhouse.utils.github.query import Query as RemoteRepo
try:
from clickhouse.utils.github.query import Query as RemoteRepo
except:
from .query import Query as RemoteRepo
import argparse
from enum import Enum

View File

@ -39,6 +39,7 @@ class Query:
baseRefName
closed
headRefName
id
mergeable
merged
@ -158,6 +159,24 @@ class Query:
else:
return {}
def find_pull_requests(self, label_name):
'''
Get all pull-requests filtered by label name
'''
_QUERY = '''
repository(owner: "{owner}" name: "{name}") {{
pullRequests(first: {min_page_size} labels: "{label_name}") {{
nodes {{
{pull_request_data}
}}
}}
}}
'''
query = _QUERY.format(owner=self._owner, name=self._name, label_name=label_name,
pull_request_data=self._PULL_REQUEST, min_page_size=self._min_page_size)
return self._run(query)['repository']['pullRequests']['nodes']
def get_pull_requests(self, before_commit):
'''
Get all merged pull-requests from the HEAD of default branch to the last commit (excluding)
@ -342,130 +361,6 @@ class Query:
query = _SET_LABEL.format(pr_id=pull_request['id'], label_id=labels[0]['id'])
self._run(query, is_mutation=True)
# OLD METHODS
# _LABELS = '''
# repository(owner: "ClickHouse" name: "ClickHouse") {{
# pullRequest(number: {number}) {{
# labels(first: {max_page_size} {next}) {{
# pageInfo {{
# hasNextPage
# endCursor
# }}
# nodes {{
# name
# color
# }}
# }}
# }}
# }}
# '''
# def get_labels(self, pull_request):
# '''Fetchs all labels for given pull-request
# Args:
# pull_request: JSON object returned by `get_pull_requests()`
# Returns:
# labels: a list of JSON nodes with the name and color fields
# '''
# labels = [label for label in pull_request['labels']['nodes']]
# not_end = pull_request['labels']['pageInfo']['hasNextPage']
# query = Query._LABELS.format(number = pull_request['number'],
# max_page_size = self._max_page_size,
# next=f'after: "{pull_request["labels"]["pageInfo"]["endCursor"]}"')
# while not_end:
# result = self._run(query)['repository']['pullRequest']['labels']
# not_end = result['pageInfo']['hasNextPage']
# query = Query._LABELS.format(number=pull_request['number'],
# max_page_size=self._max_page_size,
# next=f'after: "{result["pageInfo"]["endCursor"]}"')
# labels += [label for label in result['nodes']]
# return labels
# _TIMELINE = '''
# repository(owner: "ClickHouse" name: "ClickHouse") {{
# pullRequest(number: {number}) {{
# timeline(first: {max_page_size} {next}) {{
# pageInfo {{
# hasNextPage
# endCursor
# }}
# nodes {{
# ... on CrossReferencedEvent {{
# isCrossRepository
# source {{
# ... on PullRequest {{
# number
# baseRefName
# merged
# labels(first: {max_page_size}) {{
# pageInfo {{
# hasNextPage
# endCursor
# }}
# nodes {{
# name
# color
# }}
# }}
# }}
# }}
# target {{
# ... on PullRequest {{
# number
# }}
# }}
# }}
# }}
# }}
# }}
# }}
# '''
# def get_timeline(self, pull_request):
# '''Fetchs all cross-reference events from pull-request's timeline
# Args:
# pull_request: JSON object returned by `get_pull_requests()`
# Returns:
# events: a list of JSON nodes for CrossReferenceEvent
# '''
# events = [event for event in pull_request['timeline']['nodes'] if event and event['source']]
# not_end = pull_request['timeline']['pageInfo']['hasNextPage']
# query = Query._TIMELINE.format(number = pull_request['number'],
# max_page_size = self._max_page_size,
# next=f'after: "{pull_request["timeline"]["pageInfo"]["endCursor"]}"')
# while not_end:
# result = self._run(query)['repository']['pullRequest']['timeline']
# not_end = result['pageInfo']['hasNextPage']
# query = Query._TIMELINE.format(number=pull_request['number'],
# max_page_size=self._max_page_size,
# next=f'after: "{result["pageInfo"]["endCursor"]}"')
# events += [event for event in result['nodes'] if event and event['source']]
# return events
# _DEFAULT = '''
# repository(owner: "ClickHouse", name: "ClickHouse") {
# defaultBranchRef {
# name
# }
# }
# '''
# def get_default_branch(self):
# '''Get short name of the default branch
# Returns:
# name (string): branch name
# '''
# return self._run(Query._DEFAULT)['repository']['defaultBranchRef']['name']
def _run(self, query, is_mutation=False):
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry