#!/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())