Adds ability to deploy from upstream openstack
[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, or merged
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         if change['status'] == 'MERGED':
41             logging.info('Change {} is merged, ignoring...'
42                          .format(change_id))
43             return None
44         else:
45             return change
46
47     except KeyError:
48         logging.error('Failed to get valid change data structure from url '
49                       '{}/{}, data returned: \n{}'
50                       .format(change_id, change_str, change))
51         raise
52
53
54 def clone_fork(args):
55     ref = None
56     logging.info("Cloning {}".format(args.repo))
57
58     try:
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: {}'
62                       .format(os.getcwd()))
63         cm = ''
64
65     logging.info("Current commit message: {}".format(cm))
66     m = re.search('{}:\s*(\S+)'.format(args.repo), cm)
67
68     if m:
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)
72         if change:
73             current_revision = change['current_revision']
74             ref = change['revisions'][current_revision]['ref']
75             logging.info('setting ref to {}'.format(ref))
76
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)
81         else:
82             os.remove(args.repo)
83
84     ws = git.Repo.clone_from("{}/{}".format(args.url, args.repo),
85                              args.repo, b=args.branch)
86     if ref:
87         git_cmd = ws.git
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))
91
92
93 def get_patch(change_id, repo, branch, url=con.OPENSTACK_GERRIT):
94     logging.info("Fetching patch for change id {}".format(change_id))
95     change = get_change(url, repo, branch, change_id)
96     if change:
97         current_revision = change['current_revision']
98         rest = GerritRestAPI(url=url)
99         change_path = "{}~{}~{}".format(quote_plus(repo), quote_plus(branch),
100                                         change_id)
101         patch_url = "changes/{}/revisions/{}/patch".format(change_path,
102                                                            current_revision)
103         return rest.get(patch_url)
104
105
106 def get_parser():
107     parser = argparse.ArgumentParser()
108     parser.add_argument('--debug', action='store_true', default=False,
109                         help="Turn on debug messages")
110     subparsers = parser.add_subparsers()
111     fork = subparsers.add_parser('clone-fork',
112                                  help='Clone fork of dependent repo')
113     fork.add_argument('-r', '--repo', required=True, help='Name of repository')
114     fork.add_argument('-u', '--url',
115                       default='https://gerrit.opnfv.org/gerrit',
116                       help='Gerrit URL of repository')
117     fork.add_argument('-b', '--branch',
118                       default='master',
119                       help='Branch to checkout')
120     fork.set_defaults(func=clone_fork)
121     return parser
122
123
124 def main():
125     parser = get_parser()
126     args = parser.parse_args(sys.argv[1:])
127     if args.debug:
128         logging_level = logging.DEBUG
129     else:
130         logging_level = logging.INFO
131
132     logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s',
133                         datefmt='%m/%d/%Y %I:%M:%S %p',
134                         level=logging_level)
135     if hasattr(args, 'func'):
136         args.func(args)
137     else:
138         parser.print_help()
139         exit(1)
140
141
142 if __name__ == "__main__":
143     main()