diff options
author | Antonio Zugaldia <antonio@mapbox.com> | 2016-10-06 10:07:27 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-06 10:07:27 -0400 |
commit | 7bcb04a609415132db112b02507118835d519e36 (patch) | |
tree | c1c34eb6d6874433d91ee5d611600772e62e2207 | |
parent | 8d221cafe0614e64bce0a7364ebee3529f6b5e80 (diff) | |
download | qtlocation-mapboxgl-7bcb04a609415132db112b02507118835d519e36.tar.gz |
[android] #6522 - Automate build process for Android SDK releases
* [android] draft release supporting snapshots
* [android] release.py ready for testing
-rw-r--r-- | platform/android/scripts/release.py | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/platform/android/scripts/release.py b/platform/android/scripts/release.py new file mode 100644 index 0000000000..bc485aa706 --- /dev/null +++ b/platform/android/scripts/release.py @@ -0,0 +1,243 @@ +''' +Utility to schedule SDK builds in Bitrise. + +Examples: + +- Publish a snapshot from master (release.py uses the current branch) + + $ git branch + * master + 1234-fix-crash + $ python release.py --stage snapshot + +- Publish a snapshot from a feature branch (same as before, just switch branchs with git): + + $ git branch + master + * 1234-fix-crash + $ python release.py --stage snapshot + +- Publish a beta from a pre-release branch: + + $ git branch + master + * release-android-420-beta1 + $ python release.py --stage beta --version 4.2.0-beta.1 + +- Publish a beta from a release branch: + + $ git branch + master + * release-android-420 + $ python release.py --stage final --version 4.2.0 + +TODO: + +- Add a flag to wait until the release has been built (Bitrise) and published (Maven). + +''' + +import click +import json +import os +import requests +import subprocess + +# Three stages, from less stable to more stable +ALLOWED_STAGES = ['snapshot', 'beta', 'final'] + +# Get the version from GRADLE_PROPERTIES_PATH below +CURRENT_VERSION_TAG = 'current' + +# You can find the API token in https://www.bitrise.io/app/79cdcbdc42de4303#/code -> API token +BITRISE_API_TOKEN_ENV_VAR = 'BITRISE_API_TOKEN' + +# In the future we might want to consider alpha, or rc. +ALLOWED_PRE_RELEASE = ['beta'] + +# We get the default version from here +MAPBOX_GL_ANDROID_SDK_PATH = '../MapboxGLAndroidSDK' +GRADLE_PROPERTIES_PATH = '%s/gradle.properties' % MAPBOX_GL_ANDROID_SDK_PATH +GRADLE_TOKEN = 'VERSION_NAME=' +FABRIC_PROPERTIES_PATH = '%s/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties' % MAPBOX_GL_ANDROID_SDK_PATH +FABRIC_TOKEN = 'fabric-version=' + +# Bitrise +URL_BITRISE = 'https://www.bitrise.io/app/79cdcbdc42de4303/build/start.json' + +# We support three parameters: stage, branch, and version +@click.command() +@click.option('--stage', default=ALLOWED_STAGES[0], type=click.Choice(ALLOWED_STAGES), prompt='Set stage', help='The release stage.') +@click.option('--version', default=CURRENT_VERSION_TAG, prompt='Set version', help='The version you want to publish. E.g: 4.2.0-SNAPSHOT, 4.2.0-beta.1, or 4.2.0. If you set the version to "%s", the script will default to the current SNAPSHOT version.' % CURRENT_VERSION_TAG) +def release(stage, version): + # Validate params + final_stage = validate_stage(stage=stage) + final_branch = validate_branch(stage=final_stage) + final_version = validate_version(stage=final_stage, branch=final_branch, version=version) + + # Get user confirmation + click.echo('\n===== Build information =====') + click.echo('- Stage: %s' % final_stage) + click.echo('- Branch: %s' % final_branch) + click.echo('- Version: %s' % final_version) + click.confirm('\nDoes it look right?', abort=True) + + # Proceed + if (final_stage == 'snapshot'): + publish_snapshot(branch=final_branch, version=final_version) + elif (final_stage == 'beta'): + publish_beta(branch=final_branch, version=final_version) + elif (final_stage == 'final'): + publish_final(branch=final_branch, version=final_version) + +def validate_stage(stage): + if stage not in ALLOWED_STAGES: + abort_with_message('Invalid stage: %s' % stage) + return stage + +def validate_branch(stage): + branch = git_get_current_branch() + if not branch: + abort_with_message('The current folder is not a git repository.') + if branch == 'master' and stage != 'snapshot': + abort_with_message('You need to swtich to a release branch for a beta or a final release.') + return branch + +def validate_version(stage, branch, version): + if stage == 'snapshot' and branch == 'master' and version != CURRENT_VERSION_TAG: + abort_with_message('You cannot specify a custom version if you are building a snapshot from master.') + + if not version or version == CURRENT_VERSION_TAG: + version = get_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN) + + if stage == 'snapshot': + if not 'SNAPSHOT' in version: + abort_with_message('Version should contain the word SNAPSHOT: %s' % version) + elif stage == 'beta': + if not ALLOWED_PRE_RELEASE[0] in version: + abort_with_message('Version should contain the word %s: %s' % (ALLOWED_PRE_RELEASE[0], version)) + elif stage == 'final': + if not version or 'SNAPSHOT' in version or ALLOWED_PRE_RELEASE[0] in version: + abort_with_message('Version cannot be empty, or contain the words SNAPSHOT or %s: %s' % (ALLOWED_PRE_RELEASE[0], version)) + + return version + +def publish_snapshot(branch, version): + click.echo('Publishing snapshot for branch: %s (version: %s).' % (branch, version)) + if branch != 'master': + dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version) + if dirty_gradle: + git_add(path=GRADLE_PROPERTIES_PATH) + git_commit_and_push(branch=branch, version=version) + do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'}) + +def publish_beta(branch, version): + click.echo('Publishing beta from branch: %s (version: %s).' % (branch, version)) + dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version) + if dirty_gradle: + git_add(path=GRADLE_PROPERTIES_PATH) + git_commit_and_push(branch=branch, version=version) + do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'}) + +def publish_final(branch, version): + click.echo('Publishing final release from branch: %s (version: %s).' % (branch, version)) + dirty_gradle = update_current_version(file_path=GRADLE_PROPERTIES_PATH, file_var=GRADLE_TOKEN, version=version) + if dirty_gradle: + git_add(path=GRADLE_PROPERTIES_PATH) + dirty_fabric = update_current_version(file_path=FABRIC_PROPERTIES_PATH, file_var=FABRIC_TOKEN, version=version) + if dirty_fabric: + git_add(path=FABRIC_PROPERTIES_PATH) + if dirty_gradle or dirty_fabric: + git_commit_and_push(branch=branch, version=version) + do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'}) + +# +# Utils +# + +def abort_with_message(message): + click.echo(message) + click.get_current_context().abort() + +def execute_call(command): + click.echo('Executing: %s' % command) + result = subprocess.call(command.split(' ')) + if result != 0: + abort_with_message('Command failed: %s' % command) + +# +# Bitrise +# + +def get_bitrise_api_token(): + bitrise_api_token = os.environ.get(BITRISE_API_TOKEN_ENV_VAR) + if not bitrise_api_token: + abort_with_message('You need to set the BITRISE_API_TOKEN environment variable.') + click.echo('Found Bitrise API token.') + return bitrise_api_token + +def do_bitrise_request(build_params): + data = { + 'hook_info': {'type': 'bitrise', 'api_token': get_bitrise_api_token()}, + 'build_params' : build_params} + click.echo('Bitrise request data: %s' % json.dumps(data)) + click.confirm('\nDo you want to start a build?', abort=True) + + r = requests.post(URL_BITRISE, data=json.dumps(data)) + click.echo('- Bitrise response code: %s' % r.status_code) + click.echo('- Bitrise response content: %s' % r.text) + +# +# Git +# + +def git_get_current_branch(): + return subprocess.check_output('git symbolic-ref --short HEAD'.split(' ')).strip() + +def git_add(path): + execute_call(command='git add %s' % path) + +def git_commit_and_push(branch, version): + message = '[android] [auto] Update properties to version %s in preparation for build.' % version + commands = [ + 'git commit -m "%s"' % message, + 'git push -u origin %s' % branch] + for command in commands: + execute_call(command=command) + +# +# Read and update properties files +# + +def get_current_version(file_path, file_var): + click.echo('Getting current version from %s.' % file_path) + with open(file_path, 'r') as f: + for line in f: + if line.startswith(file_var): + version_name = line[len(file_var):].strip() + click.echo('Current version is %s.' % version_name) + return version_name + return None + +def update_current_version(file_path, file_var, version): + dirty = False + click.echo('Updating file to version %s: %s.' % (version, file_path)) + with open(file_path, 'r') as f: + file_lines = f.readlines() + for line_number in range(len(file_lines)): + if file_lines[line_number].startswith(file_var): + content_old = file_lines[line_number] + content_new = '%s%s\n' % (file_var, version) + if (content_old != content_new): + click.echo('%s -> %s' % (content_old.strip(), content_new.strip())) + file_lines[line_number] = content_new + dirty = True + if dirty: + with open(file_path, 'w') as f: + f.writelines(file_lines) + else: + click.echo('File already has the right version.') + return dirty + +if __name__ == '__main__': + release() |