diff --git a/tools/big_red_button.py b/tools/big_red_button.py old mode 100644 new mode 100755 index 75b246b62b9..1ec80340627 --- a/tools/big_red_button.py +++ b/tools/big_red_button.py @@ -1,3 +1,8 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + # Prepare release script. # # 1) Bump versions: @@ -18,24 +23,32 @@ # 4) Run this script. # -# Useful links: -# http://stackoverflow.com/questions/14665518/api-to-automatically-upload-apk-to-google-play -# https://developers.google.com/resources/api-libraries/documentation/androidpublisher/v2/python/latest/androidpublisher_v2.edits.apks.html - import argparse import os import subprocess import sys +import distutils.util DEFAULT_MOJO_ROOT = '/src/mojo/src' DEFAULT_SKY_SDK_ROOT = '/src/sky_sdk' DEFAULT_DEMO_SITE_ROOT = '/src/domokit.github.io' +CONFIRM_MESSAGE = """This tool is destructive and will revert your current branch to +origin/master among other things. Are you sure you wish to continue?""" + def run(cwd, args): print 'RUNNING:', ' '.join(args), 'IN:', cwd subprocess.check_call(args, cwd=cwd) +def confirm(prompt): + user_input = raw_input("%s (y/N) " % prompt) + try: + return distutils.util.strtobool(user_input) == 1 + except ValueError: + return False + + def main(): parser = argparse.ArgumentParser(description='Deploy!') parser.add_argument('--mojo-root', @@ -58,6 +71,10 @@ def main(): default=DEFAULT_DEMO_SITE_ROOT) args = parser.parse_args() + if not confirm(CONFIRM_MESSAGE): + print "Aborted." + return 1 + mojo_root = os.path.abspath(os.path.expanduser(args.mojo_root)) sky_sdk_root = os.path.abspath(os.path.expanduser(args.sky_sdk_root)) demo_site_root = os.path.abspath(os.path.expanduser(args.demo_site_root)) diff --git a/tools/publish_apk.py b/tools/publish_apk.py new file mode 100755 index 00000000000..786c9d0bb22 --- /dev/null +++ b/tools/publish_apk.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modeled on examples from: +# https://github.com/googlesamples/android-play-publisher-api/tree/master/v2/python + +import argparse +import httplib2 +import logging +import os +import sys + +from apiclient.discovery import build +from oauth2client import client + + +SERVICE_ACCOUNT_EMAIL = ( + '69268379666-mu02g6delkg25t856t773fkdt9p90lpd@developer.gserviceaccount.com') +KEY_FILE_PATH = os.path.expanduser('~/sky_publish_key.p12') +API_AUTH_SCOPE = 'https://www.googleapis.com/auth/androidpublisher' +DEFAULT_TRACK = 'production' + + +def read_binary_file(path): + with file(path, 'rb') as f: + return f.read() + + +def read_text_file(path): + with file(path, 'r') as f: + return f.read() + + +def publish_apk(service, package_name, apk_path, changes_text, track): + edit_request = service.edits().insert(body={}, packageName=package_name) + result = edit_request.execute() + edit_id = result['id'] + + apk_response = service.edits().apks().upload( + editId=edit_id, + packageName=package_name, + media_body=apk_path).execute() + + print 'Version code %d has been uploaded' % apk_response['versionCode'] + + track_response = service.edits().tracks().update( + editId=edit_id, + track=track, + packageName=package_name, + body={u'versionCodes': [apk_response['versionCode']]}).execute() + + print 'Track %s is set for version code(s) %s' % ( + track_response['track'], str(track_response['versionCodes'])) + + listing_response = service.edits().apklistings().update( + editId=edit_id, packageName=package_name, language='en-US', + apkVersionCode=apk_response['versionCode'], + body={'recentChanges': changes}).execute() + + print ('Listing for language %s was updated.' + % listing_response['language']) + + commit_request = service.edits().commit( + editId=edit_id, packageName=package_name).execute() + + print 'Edit "%s" has been committed' % (commit_request['id']) + + +def connect_to_service(email, key_file, auth_scope): + credentials = client.SignedJwtAssertionCredentials( + email, + read_binary_file(key_file), + scope=auth_scope) + http = httplib2.Http() + http = credentials.authorize(http) + + return build('androidpublisher', 'v2', http=http) + + +def main(argv): + logging.basicConfig() + + parser = argparse.ArgumentParser() + parser.add_argument('package_name', help='Package (e.g. com.android.sample)') + parser.add_argument('apk_path', help='Path to the APK file to upload.') + parser.add_argument('changes_file', + help='Path to file containing "What\'s new in this version?" text.') + parser.add_argument('--track', default=DEFAULT_TRACK, + choices=['alpha', 'beta', 'production', 'rollout']) + args = parser.parse_args() + + changes_text = read_text_file(args.changes_file) + + service = connect_to_service(SERVICE_ACCOUNT_EMAIL, KEY_FILE_PATH, + API_AUTH_SCOPE) + + try: + publish_apk(service, args.package_name, args.apk_path, changes_text, + args.track) + except client.AccessTokenRefreshError: + print ('The credentials have been revoked or expired, please re-run the ' + 'application to re-authorize') + + +if __name__ == '__main__': + main(sys.argv)