Merge "Release Automation"
[releng.git] / releases / scripts / create_branch.py
1 #!/usr/bin/env python2
2 # SPDX-License-Identifier: Apache-2.0
3 ##############################################################################
4 # Copyright (c) 2018 The Linux Foundation and others.
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 ##############################################################################
10 """
11 Create Gerrit Branchs
12 """
13
14 import argparse
15 import ConfigParser
16 import logging
17 import os
18 import yaml
19
20 from requests.compat import quote
21 from requests.exceptions import RequestException
22
23 from pygerrit2.rest import GerritRestAPI
24 from pygerrit2.rest.auth import HTTPDigestAuthFromNetrc, HTTPBasicAuthFromNetrc
25
26
27 logging.basicConfig(level=logging.INFO)
28
29
30 def quote_branch(arguments):
31     """
32     Quote is used here to escape the '/' in branch name. By
33     default '/' is listed in 'safe' characters which aren't escaped.
34     quote is not used in the data of the PUT request, as quoting for
35     arguments is handled by the request library
36     """
37     new_args = arguments.copy()
38     new_args['branch'] = quote(new_args['branch'], '')
39     return new_args
40
41
42 def create_branch(api, arguments):
43     """
44     Create a branch using the Gerrit REST API
45     """
46     logger = logging.getLogger(__file__)
47
48     branch_data = """
49     {
50       "ref": "%(branch)s"
51       "revision": "%(commit)s"
52     }""" % arguments
53
54     # First verify the commit exists, otherwise the branch will be
55     # created at HEAD
56     try:
57         request = api.get("/projects/%(project)s/commits/%(commit)s" %
58                           arguments)
59         logger.debug(request)
60         logger.debug("Commit exists: %(commit)s", arguments)
61     except RequestException as err:
62         if hasattr(err, 'response') and err.response.status_code in [404]:
63             logger.warn("Commit %(commit)s for %(project)s:%(branch)s does"
64                         " not exist. Not creating branch.", arguments)
65         else:
66             logger.error("Error: %s", str(err))
67         # Skip trying to create the branch
68         return
69
70     # Try to create the branch and let us know if it already exist.
71     try:
72         request = api.put("/projects/%(project)s/branches/%(branch)s" %
73                           quote_branch(arguments), branch_data)
74         logger.info("Branch %(branch)s for %(project)s successfully created",
75                     arguments)
76     except RequestException as err:
77         if hasattr(err, 'response') and err.response.status_code in [412, 409]:
78             logger.info("Branch %(branch)s already created for %(project)s",
79                         arguments)
80         else:
81             logger.error("Error: %s", str(err))
82
83
84 def main():
85     """Given a yamlfile that follows the release syntax, create branches
86     in Gerrit listed under branches"""
87
88     config = ConfigParser.ConfigParser()
89     config.read(os.path.join(os.path.abspath(os.path.dirname(__file__)),
90                 'defaults.cfg'))
91     config.read([os.path.expanduser('~/releases.cfg'), 'releases.cfg'])
92
93     gerrit_url = config.get('gerrit', 'url')
94
95     parser = argparse.ArgumentParser()
96     parser.add_argument('--file', '-f',
97                         type=argparse.FileType('r'),
98                         required=True)
99     parser.add_argument('--basicauth', '-b', action='store_true')
100     args = parser.parse_args()
101
102     GerritAuth = HTTPDigestAuthFromNetrc
103     if args.basicauth:
104         GerritAuth = HTTPBasicAuthFromNetrc
105
106     try:
107         auth = GerritAuth(url=gerrit_url)
108     except ValueError, err:
109         logging.error("%s for %s", err, gerrit_url)
110         quit(1)
111     restapi = GerritRestAPI(url=gerrit_url, auth=auth)
112
113     project = yaml.safe_load(args.file)
114
115     create_branches(restapi, project)
116
117
118 def create_branches(restapi, project):
119     """Create branches for a specific project defined in the release
120     file"""
121
122     branches = []
123     for branch in project['branches']:
124         repo, ref = next(iter(branch['location'].items()))
125         branches.append({
126             'project': repo,
127             'branch': branch['name'],
128             'commit': ref
129         })
130
131     for branch in branches:
132         create_branch(restapi, branch)
133
134
135 if __name__ == "__main__":
136     main()