| #!/usr/bin/env python3 | |
| # Copyright 2013 The Flutter Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| # A script for re-running prod builds on LUCI | |
| # | |
| # Usage: | |
| # $ build.py --commit [Engine commit hash] --builder [builder name] | |
| # | |
| # NOTE: This script requires python3.7 or later. | |
| # | |
| import argparse | |
| import os | |
| import re | |
| import subprocess | |
| import sys | |
| def GetAllBuilders(): | |
| curl_command = [ | |
| 'curl', | |
| 'https://ci.chromium.org/p/flutter/g/engine/builders', | |
| ] | |
| curl_result = subprocess.run( | |
| curl_command, | |
| universal_newlines=True, | |
| capture_output=True, | |
| ) | |
| if curl_result.returncode != 0: | |
| print('Failed to fetch builder list: stderr:\n%s' % curl_result.stderr) | |
| return [] | |
| sed_command = [ | |
| 'sed', | |
| '-En', | |
| 's:.*aria-label="builder buildbucket/luci\\.flutter\\.prod/([^/]+)".*:\\1:p', | |
| ] | |
| sed_result = subprocess.run( | |
| sed_command, | |
| input=curl_result.stdout, | |
| capture_output=True, | |
| universal_newlines=True, | |
| ) | |
| if sed_result.returncode != 0: | |
| print('Failed to fetch builder list: stderr:\n%s' % sed_result.stderr) | |
| return list(set(sed_result.stdout.splitlines())) | |
| def Main(): | |
| parser = argparse.ArgumentParser(description='Reruns Engine LUCI prod builds') | |
| parser.add_argument( | |
| '--force-upload', | |
| action='store_true', | |
| default=False, | |
| help='Force artifact upload, overwriting existing artifacts.' | |
| ) | |
| parser.add_argument( | |
| '--all', action='store_true', default=False, help='Re-run all builds.' | |
| ) | |
| parser.add_argument('--builder', type=str, help='The builer to rerun.') | |
| parser.add_argument( | |
| '--commit', type=str, required=True, help='The commit to rerun.' | |
| ) | |
| parser.add_argument( | |
| '--dry-run', | |
| action='store_true', | |
| help='Print what would be done, but do nothing.' | |
| ) | |
| args = parser.parse_args() | |
| if 'help' in vars(args) and args.help: | |
| parser.print_help() | |
| return 0 | |
| if args.all: | |
| builders = GetAllBuilders() | |
| elif args.builder == None: | |
| print('Either --builder or --all is required.') | |
| return 1 | |
| else: | |
| builders = [args.builder] | |
| auth_command = [ | |
| 'gcloud', | |
| 'auth', | |
| 'print-identity-token', | |
| ] | |
| auth_result = subprocess.run( | |
| auth_command, | |
| universal_newlines=True, | |
| capture_output=True, | |
| ) | |
| if auth_result.returncode != 0: | |
| print( | |
| 'Auth failed:\nstdout:\n%s\nstderr:\n%s' % | |
| (auth_result.stdout, auth_result.stderr) | |
| ) | |
| return 1 | |
| auth_token = auth_result.stdout.rstrip() | |
| for builder in builders: | |
| if args.force_upload: | |
| params = ( | |
| '{"Commit": "%s", "Builder": "%s", "Repo": "engine", "Properties": {"force_upload":true}}' | |
| % (args.commit, builder) | |
| ) | |
| else: | |
| params = '{"Commit": "%s", "Builder": "%s", "Repo": "engine"}' % ( | |
| args.commit, builder | |
| ) | |
| curl_command = [ | |
| 'curl', | |
| 'http://flutter-dashboard.appspot.com/api/reset-prod-task', | |
| "-d %s" % params, | |
| '-H', | |
| 'X-Flutter-IdToken: %s' % auth_token, | |
| ] | |
| if args.dry_run: | |
| print('Running: %s' % ' '.join(curl_command)) | |
| else: | |
| result = subprocess.run(curl_command) | |
| if result.returncode != 0: | |
| print('Trigger for %s failed. Aborting.' % builder) | |
| return 1 | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(Main()) |