blob: f9d14f975c5d2b0f46cc5dd7e5a3d9dd29ca879f [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
import argparse
import datetime
import os.path
import re
import subprocess
import sys
import urllib.request
import xml.etree.ElementTree
import zipfile
import utils
R8_DEV_BRANCH = '3.2'
R8_VERSION_FILE = os.path.join(
'src', 'main', 'java', 'com', 'android', 'tools', 'r8', 'Version.java')
THIS_FILE_RELATIVE = os.path.join('tools', 'r8_release.py')
GMAVEN_PUBLISHER = '/google/bin/releases/android-devtools/gmaven/publisher/gmaven-publisher'
DESUGAR_JDK_LIBS = 'desugar_jdk_libs'
DESUGAR_JDK_LIBS_CONFIGURATION = DESUGAR_JDK_LIBS + '_configuration'
ANDROID_TOOLS_PACKAGE = 'com.android.tools'
GITHUB_DESUGAR_JDK_LIBS = 'https://github.com/google/desugar_jdk_libs'
def checkout_r8(temp, branch):
subprocess.check_call(['git', 'clone', utils.REPO_SOURCE, temp])
with utils.ChangedWorkingDirectory(temp):
subprocess.check_call([
'git',
'new-branch',
'--upstream',
'origin/%s' % branch,
'dev-release'])
return temp
def prepare_release(args):
if args.version:
print("Cannot manually specify version when making a dev release.")
sys.exit(1)
def make_release(args):
commithash = args.dev_release
with utils.TempDir() as temp:
with utils.ChangedWorkingDirectory(checkout_r8(temp, R8_DEV_BRANCH)):
# Compute the current and new version on the branch.
result = None
for line in open(R8_VERSION_FILE, 'r'):
result = re.match(
r'.*LABEL = "%s\.(\d+)\-dev";' % R8_DEV_BRANCH, line)
if result:
break
if not result or not result.group(1):
print('Failed to find version label matching %s(\d+)-dev'\
% R8_DEV_BRANCH)
sys.exit(1)
try:
patch_version = int(result.group(1))
except ValueError:
print('Failed to convert version to integer: %s' % result.group(1))
old_version = '%s.%s-dev' % (R8_DEV_BRANCH, patch_version)
version = '%s.%s-dev' % (R8_DEV_BRANCH, patch_version + 1)
# Verify that the merge point from main is not empty.
merge_diff_output = subprocess.check_output([
'git', 'diff', 'HEAD..%s' % commithash]).decode('utf-8')
other_diff = version_change_diff(
merge_diff_output, old_version, "main")
if not other_diff:
print('Merge point from main (%s)' % commithash, \
'is the same as exiting release (%s).' % old_version)
sys.exit(1)
if args.dev_pre_cherry_pick:
for pre_commit in args.dev_pre_cherry_pick:
subprocess.check_call([
'git', 'cherry-pick', '--no-edit', pre_commit])
# Merge the desired commit from main on to the branch.
subprocess.check_call([
'git', 'merge', '--no-ff', '--no-edit', commithash])
# Rewrite the version, commit and validate.
sed(old_version, version, R8_VERSION_FILE)
subprocess.check_call([
'git', 'commit', '-a', '-m', 'Version %s' % version])
version_diff_output = subprocess.check_output([
'git', 'diff', '%s..HEAD' % commithash]).decode('utf-8')
validate_version_change_diff(version_diff_output, "main", version)
# Double check that we want to push the release.
if not args.dry_run:
answer = input('Publish dev release version %s [y/N]:' % version)
if answer != 'y':
print('Aborting dev release for %s' % version)
sys.exit(1)
maybe_check_call(args, [
'git', 'push', 'origin', 'HEAD:%s' % R8_DEV_BRANCH])
maybe_tag(args, version)
return "%s dev version %s from hash %s" % (
'DryRun: omitted publish of' if args.dry_run else 'Published',
version,
commithash)
return make_release
def maybe_tag(args, version):
maybe_check_call(args, [
'git', 'tag', '-a', version, '-m', '"%s"' % version])
maybe_check_call(args, [
'git', 'push', 'origin', 'refs/tags/%s' % version])
def version_change_diff(diff, old_version, new_version):
invalid_line = None
for line in str(diff).splitlines():
if line.startswith('- ') and \
line != '- public static final String LABEL = "%s";' % old_version:
invalid_line = line
elif line.startswith('+ ') and \
line != '+ public static final String LABEL = "%s";' % new_version:
invalid_line = line
return invalid_line
def validate_version_change_diff(version_diff_output, old_version, new_version):
invalid = version_change_diff(version_diff_output, old_version, new_version)
if invalid:
print("Unexpected diff:")
print("=" * 80)
print(version_diff_output)
print("=" * 80)
accept_string = 'THE DIFF IS OK!'
answer = input(
"Accept the additonal diff as part of the release? "
"Type '%s' to accept: " % accept_string)
if answer != accept_string:
print("You did not type '%s'" % accept_string)
print('Aborting dev release for %s' % version)
sys.exit(1)
def maybe_check_call(args, cmd):
if args.dry_run:
print('DryRun:', ' '.join(cmd))
else:
print(' '.join(cmd))
return subprocess.check_call(cmd)
def update_prebuilds(r8_checkout, version, checkout):
path = os.path.join(r8_checkout, 'tools', 'update_prebuilds_in_android.py')
commit_arg = '--commit_hash=' if len(version) == 40 else '--version='
subprocess.check_call([path, '--targets=lib', '--maps', commit_arg + version, checkout])
def release_studio_or_aosp(r8_checkout, path, options, git_message):
with utils.ChangedWorkingDirectory(path):
if not options.use_existing_work_branch:
subprocess.call(['repo', 'abandon', 'update-r8'])
if not options.no_sync:
subprocess.check_call(['repo', 'sync', '-cq', '-j', '16'])
prebuilts_r8 = os.path.join(path, 'prebuilts', 'r8')
if not options.use_existing_work_branch:
with utils.ChangedWorkingDirectory(prebuilts_r8):
subprocess.check_call(['repo', 'start', 'update-r8'])
update_prebuilds(r8_checkout, options.version, path)
with utils.ChangedWorkingDirectory(prebuilts_r8):
if not options.use_existing_work_branch:
subprocess.check_call(['git', 'commit', '-a', '-m', git_message])
else:
print('Not committing when --use-existing-work-branch. '
+ 'Commit message should be:\n\n'
+ git_message
+ '\n')
# Don't upload if requested not to, or if changes are not committed due
# to --use-existing-work-branch
if not options.no_upload and not options.use_existing_work_branch:
process = subprocess.Popen(['repo', 'upload', '.', '--verify'],
stdin=subprocess.PIPE)
return process.communicate(input=b'y\n')[0]
def prepare_aosp(args):
assert args.version
assert os.path.exists(args.aosp), "Could not find AOSP path %s" % args.aosp
def release_aosp(options):
print("Releasing for AOSP")
if options.dry_run:
return 'DryRun: omitting AOSP release for %s' % options.version
git_message = ("""Update D8 and R8 to %s
Version: %s
This build IS NOT suitable for preview or public release.
Built here: go/r8-releases/raw/%s
Test: TARGET_PRODUCT=aosp_arm64 m -j core-oj"""
% (args.version, args.version, args.version))
return release_studio_or_aosp(
utils.REPO_ROOT, args.aosp, options, git_message)
return release_aosp
def prepare_maven(args):
assert args.version
def release_maven(options):
gfile = '/bigstore/r8-releases/raw/%s/r8lib.zip' % args.version
release_id = gmaven_publisher_stage(options, [gfile])
print("Staged Release ID " + release_id + ".\n")
gmaven_publisher_stage_redir_test_info(
release_id, "com.android.tools:r8:%s" % args.version, "r8lib.jar")
print
answer = input("Continue with publishing [y/N]:")
if answer != 'y':
print('Aborting release to Google maven')
sys.exit(1)
gmaven_publisher_publish(args, release_id)
print("")
print("Published. Use the email workflow for approval.")
return release_maven
# ------------------------------------------------------ column 70 --v
def git_message_dev(version, bugs):
return """Update D8 R8 to %s
This is a development snapshot, it's fine to use for studio canary
build, but not for BETA or release, for those we would need a release
version of R8 binaries. This build IS suitable for preview release
but IS NOT suitable for public release.
Built here: go/r8-releases/raw/%s
Test: ./gradlew check
Bug: %s""" % (version, version, '\nBug: '.join(bugs))
def git_message_release(version, bugs):
return """D8 R8 version %s
Built here: go/r8-releases/raw/%s/
Test: ./gradlew check
Bug: %s""" % (version, version, '\nBug: '.join(bugs))
def prepare_studio(args):
assert args.version
assert os.path.exists(args.studio), ("Could not find STUDIO path %s"
% args.studio)
def release_studio(options):
print("Releasing for STUDIO")
if options.dry_run:
return 'DryRun: omitting studio release for %s' % options.version
if 'dev' in options.version:
git_message = git_message_dev(options.version, options.bug)
r8_checkout = utils.REPO_ROOT
return release_studio_or_aosp(
r8_checkout, args.studio, options, git_message)
else:
with utils.TempDir() as temp:
checkout_r8(temp, options.version[0:options.version.rindex('.')])
git_message = git_message_release(options.version, options.bug)
return release_studio_or_aosp(temp, args.studio, options, git_message)
return release_studio
def g4_cp(old, new, file):
subprocess.check_call('g4 cp {%s,%s}/%s' % (old, new, file), shell=True)
def g4_open(file):
if not os.access(file, os.W_OK):
subprocess.check_call('g4 open %s' % file, shell=True)
def g4_change(version):
return subprocess.check_output(
'g4 change --desc "Update R8 to version %s\n"' % (version),
shell=True).decode('utf-8')
def get_cl_id(c4_change_output):
startIndex = c4_change_output.find('Change ') + len('Change ')
endIndex = c4_change_output.find(' ', startIndex)
cl = c4_change_output[startIndex:endIndex]
assert cl.isdigit()
return cl
def sed(pattern, replace, path):
with open(path, "r") as sources:
lines = sources.readlines()
with open(path, "w") as sources:
for line in lines:
sources.write(re.sub(pattern, replace, line))
def download_file(version, file, dst):
urllib.request.urlretrieve(
('https://storage.googleapis.com/r8-releases/raw/%s/%s' % (version, file)),
dst)
def download_gfile(gfile, dst):
if not gfile.startswith('/bigstore/r8-releases'):
print('Unexpected gfile prefix for %s' % gfile)
sys.exit(1)
urllib.request.urlretrieve(
'https://storage.googleapis.com/%s' % gfile[len('/bigstore/'):],
dst)
def blaze_run(target):
return subprocess.check_output(
'blaze run %s' % target, shell=True, stderr=subprocess.STDOUT).decode('utf-8')
def prepare_google3(args):
assert args.version
# Check if an existing client exists.
if not args.use_existing_work_branch:
check_no_google3_client(args, args.p4_client)
def release_google3(options):
print("Releasing for Google 3")
if options.dry_run:
return 'DryRun: omitting g3 release for %s' % options.version
google3_base = subprocess.check_output(
['p4', 'g4d', '-f', args.p4_client]).decode('utf-8').rstrip()
third_party_r8 = os.path.join(google3_base, 'third_party', 'java', 'r8')
today = datetime.date.today()
with utils.ChangedWorkingDirectory(third_party_r8):
# download files
g4_open('full.jar')
g4_open('src.jar')
g4_open('lib.jar')
g4_open('lib.jar.map')
g4_open('retrace_lib.jar')
g4_open('desugar_jdk_libs_configuration.jar')
download_file(options.version, 'r8-full-exclude-deps.jar', 'full.jar')
download_file(options.version, 'r8-src.jar', 'src.jar')
download_file(options.version, 'r8lib-exclude-deps.jar', 'lib.jar')
download_file(
options.version, 'r8lib-exclude-deps.jar.map', 'lib.jar.map')
download_file(options.version, 'desugar_jdk_libs_configuration.jar',
'desugar_jdk_libs_configuration.jar')
download_file(options.version, 'r8retrace-exclude-deps.jar', 'retrace_lib.jar')
g4_open('METADATA')
sed(r'[1-9]\.[0-9]{1,2}\.[0-9]{1,3}-dev',
options.version,
os.path.join(third_party_r8, 'METADATA'))
sed(r'\{ year.*\}',
('{ year: %i month: %i day: %i }'
% (today.year, today.month, today.day)),
os.path.join(third_party_r8, 'METADATA'))
subprocess.check_output('chmod u+w *', shell=True)
with utils.ChangedWorkingDirectory(google3_base):
blaze_result = blaze_run('//third_party/java/r8:d8 -- --version')
assert options.version in blaze_result
if not options.no_upload:
change_result = g4_change(options.version)
change_result += 'Run \'(g4d ' + args.p4_client \
+ ' && tap_presubmit -p all --train -c ' \
+ get_cl_id(change_result) + ')\' for running TAP global' \
+ ' presubmit using the train.\n' \
+ 'Run \'(g4d ' + args.p4_client \
+ ' && tap_presubmit -p all --notrain --detach --email' \
+ ' --skip_flaky_targets --skip_already_failing -c ' \
+ get_cl_id(change_result) + ')\' for running an isolated' \
+ ' TAP global presubmit.'
return change_result
return release_google3
def update_desugar_library_in_studio(args):
assert os.path.exists(args.studio), ("Could not find STUDIO path %s"
% args.studio)
def make_release(args):
library_version = args.update_desugar_library_in_studio[0]
configuration_version = args.update_desugar_library_in_studio[1]
change_name = 'update-desugar-library-dependencies'
with utils.ChangedWorkingDirectory(args.studio):
if not args.use_existing_work_branch:
subprocess.call(['repo', 'abandon', change_name])
if not args.no_sync:
subprocess.check_call(['repo', 'sync', '-cq', '-j', '16'])
cmd = ['tools/base/bazel/bazel',
'run',
'//tools/base/bazel:add_dependency',
'--',
'--repo=https://maven.google.com com.android.tools:desugar_jdk_libs:%s' % library_version]
utils.PrintCmd(cmd)
subprocess.check_call(" ".join(cmd), shell=True)
cmd = ['tools/base/bazel/bazel', 'shutdown']
utils.PrintCmd(cmd)
subprocess.check_call(cmd)
prebuilts_tools = os.path.join(args.studio, 'prebuilts', 'tools')
with utils.ChangedWorkingDirectory(prebuilts_tools):
if not args.use_existing_work_branch:
with utils.ChangedWorkingDirectory(prebuilts_tools):
subprocess.check_call(['repo', 'start', change_name])
m2_dir = os.path.join(
'common', 'm2', 'repository', 'com', 'android', 'tools')
subprocess.check_call(
['git',
'add',
os.path.join(m2_dir, DESUGAR_JDK_LIBS, library_version)])
subprocess.check_call(
['git',
'add',
os.path.join(
m2_dir, DESUGAR_JDK_LIBS_CONFIGURATION, configuration_version)])
git_message = ("""Update library desugaring dependencies
com.android.tools:desugar_jdk_libs:%s
com.android.tools:desugar_jdk_libs_configuration:%s
Bug: %s
Test: L8ToolTest, L8DexDesugarTest"""
% (library_version,
configuration_version,
'\nBug: '.join(args.bug)))
if not args.use_existing_work_branch:
subprocess.check_call(['git', 'commit', '-a', '-m', git_message])
else:
print('Not committing when --use-existing-work-branch. '
+ 'Commit message should be:\n\n'
+ git_message
+ '\n')
# Don't upload if requested not to, or if changes are not committed due
# to --use-existing-work-branch
if not args.no_upload and not args.use_existing_work_branch:
process = subprocess.Popen(['repo', 'upload', '.', '--verify'],
stdin=subprocess.PIPE)
return process.communicate(input='y\n')[0]
return make_release
def prepare_desugar_library(args):
def make_release(args):
library_version = args.desugar_library[0]
configuration_version = args.desugar_library[1]
library_archive = DESUGAR_JDK_LIBS + '.zip'
library_jar = DESUGAR_JDK_LIBS + '.jar'
library_artifact_id = \
'%s:%s:%s' % (ANDROID_TOOLS_PACKAGE, DESUGAR_JDK_LIBS, library_version)
configuration_archive = DESUGAR_JDK_LIBS_CONFIGURATION + '.zip'
with utils.TempDir() as temp:
with utils.ChangedWorkingDirectory(temp):
library_gfile = ('/bigstore/r8-releases/raw/%s/%s/%s'
% (DESUGAR_JDK_LIBS, library_version, library_archive))
configuration_gfile = ('/bigstore/r8-releases/raw/main/%s/%s'
% (configuration_version, configuration_archive))
download_gfile(library_gfile, library_archive)
download_gfile(configuration_gfile, configuration_archive)
check_configuration(configuration_archive)
release_id = gmaven_publisher_stage(
args, [library_gfile, configuration_gfile])
print("Staged Release ID " + release_id + ".\n")
gmaven_publisher_stage_redir_test_info(
release_id,
"com.android.tools:%s:%s" % (DESUGAR_JDK_LIBS, library_version),
library_jar)
print("")
answer = input("Continue with publishing [y/N]:")
if answer != 'y':
print('Aborting release to Google maven')
sys.exit(1)
gmaven_publisher_publish(args, release_id)
print("")
print("Published. Use the email workflow for approval.")
return make_release
def check_configuration(configuration_archive):
zip = zipfile.ZipFile(configuration_archive)
zip.extractall()
dirs = os.listdir(
os.path.join('com', 'android', 'tools', DESUGAR_JDK_LIBS_CONFIGURATION))
if len(dirs) != 1:
print('Unexpected archive content, %s' + dirs)
sys.exit(1)
version = dirs[0]
pom_file = os.path.join(
'com',
'android',
'tools',
DESUGAR_JDK_LIBS_CONFIGURATION,
version,
'%s-%s.pom' % (DESUGAR_JDK_LIBS_CONFIGURATION, version))
version_from_pom = extract_version_from_pom(pom_file)
if version != version_from_pom:
print('Version mismatch, %s != %s' % (version, version_from_pom))
sys.exit(1)
def check_no_google3_client(args, client_name):
if not args.use_existing_work_branch:
clients = subprocess.check_output('g4 myclients', shell=True).decode('utf-8')
if ':%s:' % client_name in clients:
print(("Remove the existing '%s' client before continuing " +
"(force delete: 'g4 citc -d -f %s'), " +
"or use option --use-existing-work-branch.") % (client_name, client_name))
sys.exit(1)
def extract_version_from_pom(pom_file):
ns = "http://maven.apache.org/POM/4.0.0"
xml.etree.ElementTree.register_namespace('', ns)
tree = xml.etree.ElementTree.ElementTree()
tree.parse(pom_file)
return tree.getroot().find("{%s}version" % ns).text
GMAVEN_PUBLISH_STAGE_RELEASE_ID_PATTERN = re.compile('Release ID = ([0-9a-f\-]+)')
def gmaven_publisher_stage(args, gfiles):
if args.dry_run:
print('Dry-run, would have staged %s' % gfiles)
return 'dry-run-release-id'
print("Staging: %s" % ', '.join(gfiles))
print("")
cmd = [GMAVEN_PUBLISHER, 'stage', '--gfile', ','.join(gfiles)]
output = subprocess.check_output(cmd)
# Expect output to contain:
# [INFO] 06/19/2020 09:35:12 CEST: >>>>>>>>>> Staged
# [INFO] 06/19/2020 09:35:12 CEST: Release ID = 9171d015-18f6-4a90-9984-1c362589dc1b
# [INFO] 06/19/2020 09:35:12 CEST: Stage Path = /bigstore/studio_staging/maven2/sgjesse/9171d015-18f6-4a90-9984-1c362589dc1b
matches = GMAVEN_PUBLISH_STAGE_RELEASE_ID_PATTERN.findall(output.decode("utf-8"))
if matches == None or len(matches) > 1:
print("Could not determine the release ID from the gmaven_publisher " +
"output. Expected a line with 'Release ID = <release id>'.")
print("Output was:")
print(output)
sys.exit(1)
print(output)
release_id = matches[0]
return release_id
def gmaven_publisher_stage_redir_test_info(release_id, artifact, dst):
redir_command = ("/google/data/ro/teams/android-devtools-infra/tools/redir "
+ "--alsologtostderr "
+ "--gcs_bucket_path=/bigstore/gmaven-staging/${USER}/%s "
+ "--port=1480") % release_id
get_command = ("mvn org.apache.maven.plugins:maven-dependency-plugin:2.4:get "
+ "-Dmaven.repo.local=/tmp/maven_repo_local "
+ "-DremoteRepositories=http://localhost:1480 "
+ "-Dartifact=%s "
+ "-Ddest=%s") % (artifact, dst)
print("""To test the staged content with 'redir' run:
%s
Add the following repository to gradle.build for using 'redir':
repositories {
maven {
url 'http://localhost:1480'
allowInsecureProtocol true
}
dependencies {
classpath '%s' // Must be before the Gradle Plugin for Android.
}
}
Use this commands to get artifact from 'redir':
rm -rf /tmp/maven_repo_local
%s
""" % (redir_command, artifact, get_command))
def gmaven_publisher_publish(args, release_id):
if args.dry_run:
print('Dry-run, would have published %s' % release_id)
return
cmd = [GMAVEN_PUBLISHER, 'publish', release_id]
output = subprocess.check_output(cmd)
def branch_change_diff(diff, old_version, new_version):
invalid_line = None
for line in str(diff).splitlines():
if line.startswith('-R8') and \
line != "-R8_DEV_BRANCH = '%s'" % old_version:
print(line)
invalid_line = line
elif line.startswith('+R8') and \
line != "+R8_DEV_BRANCH = '%s'" % new_version:
print(line)
invalid_line = line
return invalid_line
def validate_branch_change_diff(version_diff_output, old_version, new_version):
invalid = branch_change_diff(version_diff_output, old_version, new_version)
if invalid:
print("")
print("The diff for the branch change in tools/release.py is not as expected:")
print("")
print("=" * 80)
print(version_diff_output)
print("=" * 80)
print("")
print("Validate the uploaded CL before landing.")
print("")
def prepare_branch(args):
branch_version = args.new_dev_branch[0]
commithash = args.new_dev_branch[1]
current_semver = utils.check_basic_semver_version(
R8_DEV_BRANCH, ", current release branch version should be x.y", 2)
semver = utils.check_basic_semver_version(
branch_version, ", release branch version should be x.y", 2)
if not semver.larger_than(current_semver):
print('New branch version "'
+ branch_version
+ '" must be strictly larger than the current "'
+ R8_DEV_BRANCH
+ '"')
sys.exit(1)
def make_branch(options):
with utils.TempDir() as temp:
subprocess.check_call(['git', 'clone', utils.REPO_SOURCE, temp])
with utils.ChangedWorkingDirectory(temp):
subprocess.check_call(['git', 'branch', branch_version, commithash])
subprocess.check_call(['git', 'checkout', branch_version])
# Rewrite the version, commit and validate.
old_version = 'main'
full_version = branch_version + '.0-dev'
version_prefix = 'LABEL = "'
sed(version_prefix + old_version,
version_prefix + full_version,
R8_VERSION_FILE)
subprocess.check_call([
'git', 'commit', '-a', '-m', 'Version %s' % full_version])
version_diff_output = subprocess.check_output([
'git', 'diff', '%s..HEAD' % commithash])
validate_version_change_diff(version_diff_output, old_version, full_version)
# Double check that we want to create a new release branch.
if not options.dry_run:
answer = input('Create new branch for %s [y/N]:' % branch_version)
if answer != 'y':
print('Aborting new branch for %s' % branch_version)
sys.exit(1)
maybe_check_call(options, [
'git', 'push', 'origin', 'HEAD:%s' % branch_version])
maybe_tag(options, full_version)
print('Updating tools/r8_release.py to make new dev releases on %s'
% branch_version)
subprocess.check_call(['git', 'new-branch', 'update-release-script'])
# Check this file for the setting of the current dev branch.
result = None
for line in open(THIS_FILE_RELATIVE, 'r'):
result = re.match(
r"^R8_DEV_BRANCH = '(\d+).(\d+)'", line)
if result:
break
if not result or not result.group(1):
print('Failed to find version label in %s' % THIS_FILE_RELATIVE)
sys.exit(1)
# Update this file with the new dev branch.
sed("R8_DEV_BRANCH = '%s.%s" % (result.group(1), result.group(2)),
"R8_DEV_BRANCH = '%s.%s" % (str(semver.major), str(semver.minor)),
THIS_FILE_RELATIVE)
message = \
'Prepare %s for branch %s' % (THIS_FILE_RELATIVE, branch_version)
subprocess.check_call(['git', 'commit', '-a', '-m', message])
branch_diff_output = subprocess.check_output(['git', 'diff', 'HEAD~'])
validate_branch_change_diff(
branch_diff_output, R8_DEV_BRANCH, branch_version)
maybe_check_call(options, ['git', 'cl', 'upload', '-f', '-m', message])
print('')
print('Make sure to send out the branch change CL for review.')
print('')
return make_branch
def parse_options():
result = argparse.ArgumentParser(description='Release r8')
group = result.add_mutually_exclusive_group()
group.add_argument('--dev-release',
metavar=('<main hash>'),
help='The hash to use for the new dev version of R8')
group.add_argument('--version',
metavar=('<version>'),
help='The new version of R8 (e.g., 1.4.51) to release to selected channels')
group.add_argument('--desugar-library',
nargs=2,
metavar=('<version>', '<configuration hash>'),
help='The new version of com.android.tools:desugar_jdk_libs')
group.add_argument('--update-desugar-library-in-studio',
nargs=2,
metavar=('<version>', '<configuration version>'),
help='Update studio mirror of com.android.tools:desugar_jdk_libs')
group.add_argument('--new-dev-branch',
nargs=2,
metavar=('<version>', '<main hash>'),
help='Create a new branch starting a version line (e.g. 2.0)')
result.add_argument('--dev-pre-cherry-pick',
metavar=('<main hash(s)>'),
default=[],
action='append',
help='List of commits to cherry pick before doing full '
'merge, mostly used for reverting cherry picks')
result.add_argument('--no-sync', '--no_sync',
default=False,
action='store_true',
help='Do not sync repos before uploading')
result.add_argument('--bug',
metavar=('<bug(s)>'),
default=[],
action='append',
help='List of bugs for release version')
result.add_argument('--studio',
metavar=('<path>'),
help='Release for studio by setting the path to a studio '
'checkout')
result.add_argument('--aosp',
metavar=('<path>'),
help='Release for aosp by setting the path to the '
'checkout')
result.add_argument('--maven',
default=False,
action='store_true',
help='Release to Google Maven')
result.add_argument('--google3',
default=False,
action='store_true',
help='Release for google 3')
result.add_argument('--p4-client',
default='update-r8',
metavar=('<client name>'),
help='P4 client name for google 3')
result.add_argument('--use-existing-work-branch', '--use_existing_work_branch',
default=False,
action='store_true',
help='Use existing work branch/CL in aosp/studio/google3')
result.add_argument('--no-upload', '--no_upload',
default=False,
action='store_true',
help="Don't upload for code review")
result.add_argument('--dry-run',
default=False,
action='store_true',
help='Only perform non-commiting tasks and print others.')
result.add_argument('--dry-run-output', '--dry_run_output',
default=os.getcwd(),
metavar=('<path>'),
help='Location for dry run output.')
args = result.parse_args()
if (args.studio
and args.version
and not 'dev' in args.version
and args.bug == []):
print("When releasing a release version to Android Studio add the "
+ "list of bugs by using '--bug'")
sys.exit(1)
if args.version and not 'dev' in args.version and args.google3:
print("You should not roll a release version into google 3")
sys.exit(1)
return args
def main():
args = parse_options()
targets_to_run = []
if args.new_dev_branch:
if args.google3 or args.studio or args.aosp:
print('Cannot create a branch and roll at the same time.')
sys.exit(1)
targets_to_run.append(prepare_branch(args))
if args.dev_release:
if args.google3 or args.studio or args.aosp:
print('Cannot create a dev release and roll at the same time.')
sys.exit(1)
targets_to_run.append(prepare_release(args))
if (args.google3
or args.maven
or (args.studio and not args.no_sync)
or (args.desugar_library and not args.dry_run)):
utils.check_gcert()
if args.google3:
targets_to_run.append(prepare_google3(args))
if args.studio and not args.update_desugar_library_in_studio:
targets_to_run.append(prepare_studio(args))
if args.aosp:
targets_to_run.append(prepare_aosp(args))
if args.maven:
targets_to_run.append(prepare_maven(args))
if args.desugar_library:
targets_to_run.append(prepare_desugar_library(args))
if args.update_desugar_library_in_studio:
if not args.studio:
print("--studio required")
sys.exit(1)
if args.bug == []:
print("Update studio mirror of com.android.tools:desugar_jdk_libs "
+ "requires at least one bug by using '--bug'")
sys.exit(1)
targets_to_run.append(update_desugar_library_in_studio(args))
final_results = []
for target_closure in targets_to_run:
final_results.append(target_closure(args))
print('\n\n**************************************************************')
print('PRINTING SUMMARY')
print('**************************************************************\n\n')
for result in final_results:
if result is not None:
print(result)
if __name__ == '__main__':
sys.exit(main())