#!/usr/bin/env python """ push_apk.py Upload the apk of a Firefox app on Google play Example for a beta upload: $ python push_apk.py --package-name org.mozilla.firefox_beta --service-account foo@developer.gserviceaccount.com --credentials key.p12 --apk-x86=/path/to/fennec-XX.0bY.multi.android-i386.apk --apk-armv7-v9=/path/to/fennec-XX.0bY.multi.android-arm-v9.apk --apk-armv7-v11=/path/to/fennec-XX.0bY.multi.android-arm-v11.apk --track production --push_apk """ import sys import os from oauth2client import client # load modules from parent dir sys.path.insert(1, os.path.dirname(sys.path[0])) # import the guts from mozharness.base.script import BaseScript from mozharness.mozilla.googleplay import GooglePlayMixin from mozharness.base.python import VirtualenvMixin class PushAPK(BaseScript, GooglePlayMixin, VirtualenvMixin): all_actions = [ 'create-virtualenv', 'push_apk', 'test', ] default_actions = [ 'create-virtualenv', 'test', ] config_options = [ [["--track"], { "dest": "track", "help": "Track on which to upload " "(production, beta, alpha, rollout)", # We are not using alpha but we default to it to avoid mistake "default": "alpha" }], [["--service-account"], { "dest": "service_account", "help": "The service account email", }], [["--credentials"], { "dest": "google_play_credentials_file", "help": "The p12 authentication file", "default": "key.p12" }], [["--package-name"], { "dest": "package_name", "help": "The Google play name of the app", }], [["--apk-x86"], { "dest": "apk_file_x86", "help": "The path to the x86 APK file", }], [["--apk-armv7-v9"], { "dest": "apk_file_armv7_v9", "help": "The path to the ARM v7 API v9 APK file", }], [["--apk-armv7-v11"], { "dest": "apk_file_armv7_v11", "help": "The path to the ARM v7 API v11 APK file", }], [["--apk-armv6"], { "dest": "apk_file_armv6", "help": "The path to the ARM v6 APK file", }], ] # Google play has currently 3 tracks. Rollout deploys # to a limited percentage of users track_values = ("production", "beta", "alpha", "rollout") # We have 3 apps. Make sure that their names are correct package_name_values = ("org.mozilla.fennec_aurora", "org.mozilla.firefox_beta", "org.mozilla.firefox") def __init__(self, require_config_file=False, config={}, all_actions=all_actions, default_actions=default_actions): # Default configuration default_config = { 'debug_build': False, 'pip_index': True, # this will pip install it automajically when we call the create-virtualenv action 'virtualenv_modules': ['google-api-python-client'], "find_links": [ # so mozharness knows where to look for the package "http://pypi.pvt.build.mozilla.org/pub", "http://pypi.pub.build.mozilla.org/pub", ], # the path inside the work_dir ('build') of where we will install the env. # pretty sure it's the default and not needed. 'virtualenv_path': 'venv', } default_config.update(config) BaseScript.__init__( self, config_options=self.config_options, require_config_file=require_config_file, config=default_config, all_actions=all_actions, default_actions=default_actions, ) def check_argument(self): """ Check that the given values are correct, files exists, etc """ if self.config['track'] not in self.track_values: self.fatal("Unknown track value " + self.config['track']) if self.config['package_name'] not in self.package_name_values: self.fatal("Unknown package name value " + self.config['package_name']) if not os.path.isfile(self.config['apk_file_x86']): self.fatal("Could not find " + self.config['apk_file_x86']) if not os.path.isfile(self.config['apk_file_armv7_v9']): self.fatal("Could not find " + self.config['apk_file_armv7_v9']) if not os.path.isfile(self.config['apk_file_armv7_v11']): self.fatal("Could not find " + self.config['apk_file_armv7_v11']) if self.config.get('apk_file_armv6') and not os.path.isfile(self.config['apk_file_armv6']): self.fatal("Could not find " + self.config['apk_file_armv6']) if not os.path.isfile(self.config['google_play_credentials_file']): self.fatal("Could not find " + self.config['google_play_credentials_file']) def upload_apks(self, service, apk_files): """ Upload the APK to google play service -- The session to Google play apk_files -- The files """ edit_request = service.edits().insert(body={}, packageName=self.config['package_name']) result = edit_request.execute() edit_id = result['id'] # Store all the versions to set the tracks (needs to happen # at the same time versions = [] # For each files, upload it for apk_file in apk_files: try: # Upload the file apk_response = service.edits().apks().upload( editId=edit_id, packageName=self.config['package_name'], media_body=apk_file).execute() self.log('Version code %d has been uploaded. ' 'Filename "%s" edit_id %s' % (apk_response['versionCode'], apk_file, edit_id)) versions.append(apk_response['versionCode']) except client.AccessTokenRefreshError: self.log('The credentials have been revoked or expired,' 'please re-run the application to re-authorize') # Set the track for all apk service.edits().tracks().update( editId=edit_id, track=self.config['track'], packageName=self.config['package_name'], body={u'versionCodes': versions}).execute() self.log('Application "%s" set to track "%s" for versions %s' % (self.config['package_name'], self.config['track'], versions)) # Commit our changes commit_request = service.edits().commit( editId=edit_id, packageName=self.config['package_name']).execute() self.log('Edit "%s" has been committed' % (commit_request['id'])) def push_apk(self): """ Upload the APK files """ self.check_argument() service = self.connect_to_play() apks = [self.config['apk_file_armv7_v9'], self.config['apk_file_armv7_v11'], self.config['apk_file_x86']] if self.config.get('apk_file_armv6'): apks.append(self.config['apk_file_armv6']) self.upload_apks(service, apks) def test(self): """ Test if the connexion can be done """ self.check_argument() self.connect_to_play() # main {{{1 if __name__ == '__main__': myScript = PushAPK() myScript.run_and_exit()