1 ##############################################################################
2 # Copyright (c) 2017 Feng Pan (fpan@redhat.com) and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
14 from pygerrit2.rest import GerritRestAPI
19 from apex.common import constants as con
20 from urllib.parse import quote_plus
23 def get_change(url, repo, branch, change_id):
25 Fetches a change from upstream repo
26 :param url: URL of upstream gerrit
27 :param repo: name of repo
28 :param branch: branch of repo
29 :param change_id: SHA change id
30 :return: change if found and not abandoned, closed, or merged
32 rest = GerritRestAPI(url=url)
33 change_path = "{}~{}~{}".format(quote_plus(repo), quote_plus(branch),
35 change_str = "changes/{}?o=CURRENT_REVISION".format(change_path)
36 change = rest.get(change_str)
38 assert change['status'] not in 'ABANDONED' 'CLOSED', \
39 'Change {} is in {} state'.format(change_id, change['status'])
40 if change['status'] == 'MERGED':
41 logging.info('Change {} is merged, ignoring...'
48 logging.error('Failed to get valid change data structure from url '
49 '{}/{}, data returned: \n{}'
50 .format(change_id, change_str, change))
56 logging.info("Cloning {}".format(args.repo))
59 cm = git.Repo(search_parent_directories=True).commit().message
60 except git.exc.InvalidGitRepositoryError:
61 logging.debug('Current Apex directory is not a git repo: {}'
65 logging.info("Current commit message: {}".format(cm))
66 m = re.search('{}:\s*(\S+)'.format(args.repo), cm)
69 change_id = m.group(1)
70 logging.info("Using change ID {} from {}".format(change_id, args.repo))
71 change = get_change(args.url, args.repo, args.branch, change_id)
73 current_revision = change['current_revision']
74 ref = change['revisions'][current_revision]['ref']
75 logging.info('setting ref to {}'.format(ref))
77 # remove existing file or directory named repo
78 if os.path.exists(args.repo):
79 if os.path.isdir(args.repo):
80 shutil.rmtree(args.repo)
84 ws = git.Repo.clone_from("{}/{}".format(args.url, args.repo),
85 args.repo, b=args.branch)
88 git_cmd.fetch("{}/{}".format(args.url, args.repo), ref)
89 git_cmd.checkout('FETCH_HEAD')
90 logging.info('Checked out commit:\n{}'.format(ws.head.commit.message))
93 def strip_patch_sections(patch, sections=['releasenotes']):
95 Removes patch sections from a diff which contain a file path
96 :param patch: patch to strip
97 :param sections: list of keywords to use to strip out of the patch file
98 :return: stripped patch
103 for line in patch.split("\n"):
104 if re.match('diff\s', line):
105 for section in sections:
106 if re.search(section, line):
107 logging.debug("Stripping {} from patch: {}".format(
114 tmp_patch.append(line)
115 return '\n'.join(tmp_patch)
118 def get_patch(change_id, repo, branch, url=con.OPENSTACK_GERRIT):
119 logging.info("Fetching patch for change id {}".format(change_id))
120 change = get_change(url, repo, branch, change_id)
122 current_revision = change['current_revision']
123 rest = GerritRestAPI(url=url)
124 change_path = "{}~{}~{}".format(quote_plus(repo), quote_plus(branch),
126 patch_url = "changes/{}/revisions/{}/patch".format(change_path,
128 return strip_patch_sections(rest.get(patch_url))
132 parser = argparse.ArgumentParser()
133 parser.add_argument('--debug', action='store_true', default=False,
134 help="Turn on debug messages")
135 subparsers = parser.add_subparsers()
136 fork = subparsers.add_parser('clone-fork',
137 help='Clone fork of dependent repo')
138 fork.add_argument('-r', '--repo', required=True, help='Name of repository')
139 fork.add_argument('-u', '--url',
140 default='https://gerrit.opnfv.org/gerrit',
141 help='Gerrit URL of repository')
142 fork.add_argument('-b', '--branch',
144 help='Branch to checkout')
145 fork.set_defaults(func=clone_fork)
150 parser = get_parser()
151 args = parser.parse_args(sys.argv[1:])
153 logging_level = logging.DEBUG
155 logging_level = logging.INFO
157 logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s',
158 datefmt='%m/%d/%Y %I:%M:%S %p',
160 if hasattr(args, 'func'):
167 if __name__ == "__main__":