Skip to content

Instantly share code, notes, and snippets.

@mariotaku
Last active August 8, 2018 13:10
Show Gist options
  • Save mariotaku/7a0c51955d14def2fa0e to your computer and use it in GitHub Desktop.
Save mariotaku/7a0c51955d14def2fa0e to your computer and use it in GitHub Desktop.
Sign and upload compiled apk to Github releases automatically using Travis CI
language: android
android:
components:
# Uncomment the lines below if you want to
# use the latest revision of Android SDK Tools
- platform-tools
- tools
# The BuildTools version used by your project
- build-tools-22.0.0
# The SDK version used to compile your project
- android-22
# Additional components
- extra-google-google_play_services
- extra-google-m2repository
- extra-android-m2repository
# Specify at least one system image,
# if you need to run emulator(s) during your tests
# - sys-img-armeabi-v7a-android-19
# - sys-img-x86-android-17
script: ./gradlew build
before_install:
- sudo apt-get update -qq
- sudo apt-get install -y python2.7
after_success: ./scripts/travis_upload_release_to_github.py
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.application'
/**
* Gradle script for signing applications
* Just apply this script to your application build.gradle file.
* DON'T FORGET TO IGNORE signing.properties FROM YOUR VERSION CONTROL!!!
*
* @author Mariotaku Lee <[email protected]>
*/
android {
signingConfigs {
debug {
File signingPropFile = rootProject.file('signing.properties')
if (signingPropFile.exists()) {
Properties signingProp = new Properties()
signingProp.load(signingPropFile.newDataInputStream())
storeFile file(signingProp.get("debug.storeFile"))
storePassword signingProp.get("debug.storePassword")
keyAlias signingProp.get("debug.keyAlias")
keyPassword signingProp.get("debug.keyPassword")
} else if (System.getenv('DEBUG_KEYSTORE_BASE64') != null) {
storeFile decodeKeyStoreFileFromBase64Env('DEBUG_KEYSTORE_BASE64')
storePassword System.getenv('DEBUG_KEYSTORE_PASSWORD')
keyAlias System.getenv('DEBUG_KEYSTORE_KEY_ALIAS')
keyPassword System.getenv('DEBUG_KEYSTORE_KEY_PASSWORD')
}
}
release {
File signingPropFile = rootProject.file('signing.properties')
if (signingPropFile.exists()) {
Properties signingProp = new Properties()
signingProp.load(signingPropFile.newDataInputStream())
storeFile file(signingProp.get("release.storeFile"))
storePassword signingProp.get("release.storePassword")
keyAlias signingProp.get("release.keyAlias")
keyPassword signingProp.get("release.keyPassword")
} else if (System.getenv('RELEASE_KEYSTORE_BASE64') != null) {
storeFile decodeKeyStoreFileFromBase64Env('RELEASE_KEYSTORE_BASE64')
storePassword System.getenv('RELEASE_KEYSTORE_PASSWORD')
keyAlias System.getenv('RELEASE_KEYSTORE_KEY_ALIAS')
keyPassword System.getenv('RELEASE_KEYSTORE_KEY_PASSWORD')
}
}
}
buildTypes {
debug {
if (rootProject.file('signing.properties').exists()
|| System.getenv('DEBUG_KEYSTORE_BASE64') != null) {
signingConfig signingConfigs.debug
}
}
release {
if (rootProject.file('signing.properties').exists()
|| System.getenv('RELEASE_KEYSTORE_BASE64') != null) {
signingConfig signingConfigs.release
}
}
}
}
def decodeKeyStoreFileFromBase64Env(String name) {
String keyStoreBase64 = System.getenv(name)
if (keyStoreBase64 == null) return null
File tempKeyStoreFile = File.createTempFile("tmp_ks_", ".jks", File.createTempDir())
FileOutputStream fos = null
try {
fos = new FileOutputStream(tempKeyStoreFile)
fos.write(keyStoreBase64.decodeBase64())
fos.flush()
} finally {
if (fos != null) {
fos.close()
}
}
return tempKeyStoreFile
}
release.storeFile=/path/to/your/keystore/file.jks
release.storePassword=p455w0rd
release.keyAlias=awesome
release.keyPassword=53cr3t
debug.storeFile=/path/to/your/keystore/file.jks
debug.storePassword=p455w0rd
debug.keyAlias=awesome
debug.keyPassword=53cr3t
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
import sys
import httplib
import urllib
import urlparse
import json
import fnmatch
import re
from os import getenv
from subprocess import check_output
from subprocess import CalledProcessError
__author__ = 'mariotaku'
git_https_url_prefix = 'https://github.com/'
git_ssh_url_prefix = '[email protected]:'
git_git_url_prefix = 'git://github.com/'
git_file_suffix = '.git'
github_header_accept = 'application/vnd.github.v3+json'
github_header_user_agent = 'TravisUploader/0.1'
DEVNULL = open(os.devnull, 'w')
repo_url = None
try:
repo_url = check_output(['git', 'config', '--get', 'remote.origin.url']).splitlines()[0]
except CalledProcessError:
print('No remote url for this project, abort')
exit(0)
user_repo_name = None
if repo_url.startswith(git_ssh_url_prefix):
user_repo_name = repo_url[len(git_ssh_url_prefix):]
elif repo_url.startswith(git_https_url_prefix):
user_repo_name = repo_url[len(git_https_url_prefix):]
elif repo_url.startswith(git_git_url_prefix):
user_repo_name = repo_url[len(git_git_url_prefix):]
if not user_repo_name:
print('Not a github repo (%s), abort' % repo_url, file=sys.stderr)
exit(0)
if user_repo_name.endswith(git_file_suffix):
user_repo_name = user_repo_name[:-len(git_file_suffix)]
current_tag = None
current_tag_body = None
try:
current_tag = check_output(['git', 'describe', '--tags', '--exact-match', '--abbrev=0'],
stderr=DEVNULL).splitlines()[0]
except CalledProcessError:
print('This commit doesn\'t have tag, abort', file=sys.stderr)
exit(0)
try:
current_tag_body = '\n'.join(
check_output(['git', 'show', '-s', '--format=%b', current_tag], stderr=DEVNULL).splitlines()[2:])
except CalledProcessError:
current_tag_body = "Automatic upload for version %s" % current_tag
github_access_token = getenv('GITHUB_ACCESS_TOKEN')
if not github_access_token:
print('No access token given, abort', file=sys.stderr)
exit(0)
github_authorization_header = "token %s" % github_access_token
print('Creating release for tag %s' % current_tag)
req_headers = {'Accept': github_header_accept}
conn = httplib.HTTPSConnection('api.github.com')
conn.request('POST', '/repos/%s/releases' % user_repo_name,
body=json.dumps({
'tag_name': current_tag,
'name': "Version %s" % current_tag,
'body': current_tag_body
}),
headers={
'Accept': github_header_accept,
'Authorization': github_authorization_header,
'Content-Type': 'application/json',
'User-Agent': github_header_user_agent
})
response = conn.getresponse()
if response.status == 422:
conn = httplib.HTTPSConnection('api.github.com')
conn.request('GET', '/repos/%s/releases/tags/%s' % (user_repo_name, current_tag),
headers={
'Accept': github_header_accept,
'Authorization': github_authorization_header,
'User-Agent': github_header_user_agent
})
response = conn.getresponse()
if response.status not in range(200, 204):
print('Unable to create or get release, abort', file=sys.stderr)
exit(0)
response_values = json.loads(response.read())
upload_url = urlparse.urlparse(re.sub('\{\?([\w\d_\-]+)\}', '', response_values['upload_url']))
for root, dirnames, filenames in os.walk(os.getcwd()):
for filename in fnmatch.filter(filenames, '*-release.apk'):
conn = httplib.HTTPSConnection(upload_url.hostname)
conn.request('POST', "%s?%s" % (upload_url.path, urllib.urlencode({'name': filename})),
body=open(os.path.join(root, filename), 'r'),
headers={
'Accept': github_header_accept,
'Authorization': github_authorization_header,
'Content-Type': 'application/json',
'User-Agent': github_header_user_agent
})
print("Upload %s returned %d" % (filename, conn.getresponse().status))
@HugoGresse
Copy link

Installing python should be done using apt addons to use new Travis container based infrastructure:

addons:
  apt:
    packages:
    - python2.7

after_success: ./travis_upload_release_to_github.py

This will remove delay after job creation on open source GCE project.

@cgarnier
Copy link

cgarnier commented Mar 2, 2017

Nice gist.
But why you dont use the release feature of travis ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment