blob: c516ec868501f3b0869be849b130ac9223c22f2e [file] [log] [blame]
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +02001#!/usr/bin/env python3
2# Copyright 2022 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style
4# license that can be found in the LICENSE file or at
5# https://developers.google.com/open-source/licenses/bsd
6
7"""Script to launch the Monorail release tarball builder.
8
9It can be used to build a tarball with Monorail code based on a release branch
10(i.e. `refs/releases/monorail/...`). It triggers a go/monorail-release-tarballs
11build that uploads the release tarball and triggers its deployment to
12monorail-dev, after which it can be promoted to monorail-prod.
13
14See go/monorail-deploy for more details.
15"""
16
17import argparse
18import json
19import subprocess
20import sys
21import urllib.error
22import urllib.request
23
24
25INFRA_GIT = 'https://chromium.googlesource.com/infra/infra'
26TARBALL_BUILDER = 'infra-internal/monorail-release/monorail-release-tarballs'
27
28
29def resolve_commit(ref):
30 """Queries gitiles for a commit hash matching the given infra.git ref.
31
32 Args:
33 ref: a `refs/...` ref to resolve into a commit.
34
35 Returns:
36 None if there's no such ref, a gitiles commit URL otherwise.
37 """
38 try:
39 resp = urllib.request.urlopen('%s/+/%s?format=JSON' % (INFRA_GIT, ref))
40 except urllib.error.HTTPError as exc:
41 if exc.code == 404:
42 return None
43 raise
44
45 # Gitiles JSON responses start with XSS-protection header.
46 blob = resp.read()
47 if blob.startswith(b')]}\''):
48 blob = blob[4:]
49
50 commit = json.loads(blob)['commit']
51 return '%s/+/%s' % (INFRA_GIT, commit)
52
53
54def ensure_logged_in():
55 """Ensures `bb` tool is in PATH and the caller is logged in there.
56
57 Returns:
58 True if logged in, False if not and we should abort.
59 """
60 try:
61 proc = subprocess.run(['bb', 'auth-info'], capture_output=True)
62 except OSError:
63 print(
64 'Could not find `bb` tool in PATH. It comes with depot_tools. '
65 'Make sure depot_tools is in PATH and up-to-date, then try again.')
66 return False
67
68 if proc.returncode == 0:
69 return True # already logged in
70
71 # Launch interactive login process.
72 proc = subprocess.run(['bb', 'auth-login'])
73 if proc.returncode != 0:
74 print('Failed to login')
75 return False
76 return True
77
78
79def submit_build(ref, commit):
80 """Submits a Monorail tarball builder build via `bb` tool.
81
82 Args:
83 ref: a `refs/...` ref with the code to build.
84 commit: a gitiles commit matching this ref.
85
86 Returns:
87 None if failed, a URL to the pending build otherwise.
88 """
89 cmd = ['bb', 'add', '-json', '-ref', ref, '-commit', commit, TARBALL_BUILDER]
90 proc = subprocess.run(cmd, capture_output=True)
91 if proc.returncode != 0:
92 print(
93 'Failed to schedule the build:\n%s'
94 % proc.stderr.decode('utf-8').strip())
95 return None
96 build_id = json.loads(proc.stdout)['id']
97 return 'https://ci.chromium.org/b/%s' % build_id
98
99
100def main():
101 parser = argparse.ArgumentParser(
102 description='Submits a request to build Monorail tarball for LUCI CD.')
103 parser.add_argument(
104 'branch', type=str,
105 help='a branch to build from: refs/releases/monorail/<num> or just <num>')
106 parser.add_argument(
107 '--silent', action='store_true',
108 help='disable interactive prompts')
109 args = parser.parse_args()
110
111 ref = args.branch
112 if not ref.startswith('refs/'):
113 ref = 'refs/releases/monorail/' + ref
114
115 # `bb add` call wants a concrete git commit SHA1 as input.
116 commit = resolve_commit(ref)
117 if not commit:
118 print('No such release branch: %s' % ref)
119 return 1
120
121 # Give a chance to confirm this is the commit we want to build.
122 if not args.silent:
123 print(
124 'Will submit a request to build a Monorail code tarball from %s:\n'
125 ' %s\n\n'
126 'You may be asked to sign in with your google.com account if it is '
127 'the first time you are using this script.\n'
128 % (ref, commit)
129 )
130 if input('Proceed [Y/n]? ') not in ('', 'Y', 'y'):
131 return 0
132
133 # Submit the build via `bb` tool.
134 if not args.silent and not ensure_logged_in():
135 return 1
136 build_url = submit_build(ref, commit)
137 if not build_url:
138 return 1
139
140 print(
141 '\nScheduled the build: %s\n'
142 '\n'
143 'When it completes it will trigger deployment of this release to '
144 'monorail-dev. You can then promote it to production using the same '
145 'procedure as with regular releases built from `main` branch.\n'
146 '\n'
147 'Note that if the produced release tarball is 100%% identical to any '
148 'previously built tarball (e.g. there were no cherry-picks into the '
149 'release branch since it was cut from `main`), an existing tarball and '
150 'its version name will be reused.'
151 % build_url
152 )
153 return 0
154
155
156if __name__ == '__main__':
157 sys.exit(main())