Revert "Updates scenario files for hunter branch"
[apex.git] / apex / build_utils.py
1 ##############################################################################
2 # Copyright (c) 2017 Feng Pan (fpan@redhat.com) and others.
3 #
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 ##############################################################################
9
10 import argparse
11 import git
12 import logging
13 import os
14 from pygerrit2.rest import GerritRestAPI
15 import re
16 import shutil
17 import sys
18
19 from apex.common import constants as con
20 from urllib.parse import quote_plus
21
22
23 def get_change(url, repo, branch, change_id):
24     """
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
31     """
32     rest = GerritRestAPI(url=url)
33     change_path = "{}~{}~{}".format(quote_plus(repo), quote_plus(branch),
34                                     change_id)
35     change_str = "changes/{}?o=CURRENT_REVISION".format(change_path)
36     change = rest.get(change_str)
37     try:
38         assert change['status'] not in 'ABANDONED' 'CLOSED', \
39             'Change {} is in {} state'.format(change_id, change['status'])
40         logging.debug('Change found: {}'.format(change))
41         return change
42
43     except KeyError:
44         logging.error('Failed to get valid change data structure from url '
45                       '{}/{}, data returned: \n{}'
46                       .format(change_id, change_str, change))
47         raise
48
49
50 def clone_fork(args):
51     ref = None
52     logging.info("Cloning {}".format(args.repo))
53
54     try:
55         cm = git.Repo(search_parent_directories=True).commit().message
56     except git.exc.InvalidGitRepositoryError:
57         logging.debug('Current Apex directory is not a git repo: {}'
58                       .format(os.getcwd()))
59         cm = ''
60
61     logging.info("Current commit message: {}".format(cm))
62     m = re.search('{}:\s*(\S+)'.format(args.repo), cm)
63
64     if m:
65         change_id = m.group(1)
66         logging.info("Using change ID {} from {}".format(change_id, args.repo))
67         change = get_change(args.url, args.repo, args.branch, change_id)
68         if change:
69             current_revision = change['current_revision']
70             ref = change['revisions'][current_revision]['ref']
71             logging.info('setting ref to {}'.format(ref))
72
73     # remove existing file or directory named repo
74     if os.path.exists(args.repo):
75         if os.path.isdir(args.repo):
76             shutil.rmtree(args.repo)
77         else:
78             os.remove(args.repo)
79
80     ws = git.Repo.clone_from("{}/{}".format(args.url, args.repo),
81                              args.repo, b=args.branch)
82     if ref:
83         git_cmd = ws.git
84         git_cmd.fetch("{}/{}".format(args.url, args.repo), ref)
85         git_cmd.checkout('FETCH_HEAD')
86         logging.info('Checked out commit:\n{}'.format(ws.head.commit.message))
87
88
89 def strip_patch_sections(patch, sections=['releasenotes', 'tests']):
90     """
91     Removes patch sections from a diff which contain a file path
92     :param patch:  patch to strip
93     :param sections: list of keywords to use to strip out of the patch file
94     :return: stripped patch
95     """
96
97     append_line = True
98     tmp_patch = []
99     for line in patch.split("\n"):
100         if re.match('diff\s', line):
101             for section in sections:
102                 if re.search(section, line):
103                     logging.debug("Stripping {} from patch: {}".format(
104                         section, line))
105                     append_line = False
106                     break
107                 else:
108                     append_line = True
109         if append_line:
110             tmp_patch.append(line)
111     return '\n'.join(tmp_patch)
112
113
114 def is_path_in_patch(patch, path):
115     """
116     Checks if a particular path is modified in a patch diff
117     :param patch: patch diff
118     :param path: path to check for in diff
119     :return: Boolean
120     """
121     for line in patch.split("\n"):
122         if re.match('^diff.*{}'.format(path), line):
123             return True
124     return False
125
126
127 def get_patch(change_id, repo, branch, url=con.OPENSTACK_GERRIT):
128     logging.info("Fetching patch for change id {}".format(change_id))
129     change = get_change(url, repo, branch, change_id)
130     if change:
131         current_revision = change['current_revision']
132         rest = GerritRestAPI(url=url)
133         change_path = "{}~{}~{}".format(quote_plus(repo), quote_plus(branch),
134                                         change_id)
135         patch_url = "changes/{}/revisions/{}/patch".format(change_path,
136                                                            current_revision)
137         return strip_patch_sections(rest.get(patch_url))
138
139
140 def get_parser():
141     parser = argparse.ArgumentParser()
142     parser.add_argument('--debug', action='store_true', default=False,
143                         help="Turn on debug messages")
144     subparsers = parser.add_subparsers()
145     fork = subparsers.add_parser('clone-fork',
146                                  help='Clone fork of dependent repo')
147     fork.add_argument('-r', '--repo', required=True, help='Name of repository')
148     fork.add_argument('-u', '--url',
149                       default='https://gerrit.opnfv.org/gerrit',
150                       help='Gerrit URL of repository')
151     fork.add_argument('-b', '--branch',
152                       default='master',
153                       help='Branch to checkout')
154     fork.set_defaults(func=clone_fork)
155     return parser
156
157
158 def main():
159     parser = get_parser()
160     args = parser.parse_args(sys.argv[1:])
161     if args.debug:
162         logging_level = logging.DEBUG
163     else:
164         logging_level = logging.INFO
165
166     logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s',
167                         datefmt='%m/%d/%Y %I:%M:%S %p',
168                         level=logging_level)
169     if hasattr(args, 'func'):
170         args.func(args)
171     else:
172         parser.print_help()
173         exit(1)
174
175
176 if __name__ == "__main__":
177     main()