DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (b6057e17f856)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
#!/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
from mozharness.base.script import PreScriptAction


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, package_name, apk_files):
        """ Upload the APK to google play

        service -- The session to Google play
        package_name -- The name of the package
        apk_files -- The files
        """
        edit_request = service.edits().insert(body={},
                                              packageName=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=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=package_name,
            body={u'versionCodes': versions}).execute()
        self.log('Application "%s" set to track "%s" for versions %s' %
                 (package_name, self.config['track'], versions))

        # Commit our changes
        commit_request = service.edits().commit(
            editId=edit_id, packageName=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, self.config['package_name'], 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()