Created
January 6, 2017 20:34
-
-
Save brantje/f097b32a80fca6643d86dee25d9d16fa to your computer and use it in GitHub Desktop.
This is the release script i use for my passman builds
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os | |
import subprocess | |
from xml.dom import minidom | |
from pprint import pprint | |
import git | |
import urllib, json | |
import re | |
import wget | |
import zipfile | |
import tarfile | |
import requests | |
from shutil import copyfile, rmtree | |
from optparse import OptionParser | |
from time import sleep | |
import tweepy | |
import hashlib | |
app_sign_key = '/home/passman/.nextcloud/certificates/passman.key' | |
work_dir = '/home/passman/build/passman' | |
build_dir = '/home/passman/build' | |
release_dir = '/var/www/html/releases' | |
os.chdir(work_dir) | |
src_repo = git.Git('.') | |
dist_repo = git.Repo('dist') | |
twitter_cfg = { | |
"consumer_key": "x", | |
"consumer_secret": "xxx", | |
"access_token": "xxxx-xxxxx", | |
"access_token_secret": "xxxxxx" | |
} | |
appstore_token = 'xxxxxx' | |
parser = OptionParser() | |
parser.add_option("-f", "--force", dest="force", action="store_true") | |
parser.add_option("-v", "--version", type="str", | |
help="version to build", | |
dest="version") | |
(options, args) = parser.parse_args() | |
force_build = options.force | |
def mycmp(version1, version2): | |
def normalize(v): | |
return [int(x) for x in re.sub(r'(\.0+)*$', '', v).split(".")] | |
return cmp(normalize(version1), normalize(version2)) | |
def get_last_commit_message(): | |
return src_repo.log('-1', '--pretty=%B') | |
def get_twitter_api(cfg): | |
auth = tweepy.OAuthHandler(cfg['consumer_key'], cfg['consumer_secret']) | |
auth.set_access_token(cfg['access_token'], cfg['access_token_secret']) | |
return tweepy.API(auth) | |
def get_app_version(): | |
info_file = os.getcwd() + '/appinfo/info.xml' | |
xml = minidom.parse(info_file) | |
app_version = xml.getElementsByTagName('version')[0].childNodes[0].nodeValue | |
return app_version | |
def make_new_build(): | |
subprocess.call(["grunt", "build"]) | |
def get_last_tag(): | |
return src_repo.tag(l=True) | |
def get_zip_from_tag(version): | |
lastTag = False | |
url = "https://api.github.com/repos/nextcloud/passman/tags" | |
response = urllib.urlopen(url) | |
data = json.loads(response.read()) | |
for tag in data: | |
if tag['name'] == version: | |
lastTag = tag | |
return lastTag['zipball_url'] | |
def download_file(url, filename): | |
file = wget.download(url, filename) | |
print "\n" | |
return file | |
def unzip(source_filename, dest_dir): | |
zip_ref = zipfile.ZipFile(source_filename, 'r') | |
zip_ref.extractall(dest_dir) | |
zip_ref.close() | |
def make_tarfile(source_dir, output_filename): | |
with tarfile.open(output_filename, "w:gz") as tar: | |
print "Adding " + source_dir | |
tar.add(source_dir, arcname=os.path.basename(source_dir)) | |
def create_file(path, content): | |
text_file = open(path, "w") | |
text_file.write(content) | |
text_file.close() | |
def md5(fname): | |
hash_md5 = hashlib.md5() | |
with open(fname, "rb") as f: | |
for chunk in iter(lambda: f.read(4096), b""): | |
hash_md5.update(chunk) | |
return hash_md5.hexdigest() | |
def generate_file_hashes(_version): | |
gz_path = '/var/www/html/releases/passman_' + _version + '.tar.gz' | |
md5_hash = md5(gz_path) | |
sha512 = hashlib.sha512(open(gz_path, 'rb').read()).hexdigest() #str(os.popen('openssl dgst -sha512 ' + gz_path).read()).strip() | |
sha256 = hashlib.sha256(open(gz_path,'rb').read()).hexdigest() #str(os.popen('openssl dgst -sha256 ' + gz_path).read()).strip() | |
append = ' '+ _version + '.tar.gz' | |
os.popen('gpg -ab '+ gz_path).read() | |
hashes = {'md5': md5_hash, 'sha512': sha512 +append, 'sha256': sha256+append} | |
for key, value in hashes.iteritems(): | |
create_file(gz_path + '.'+ key, value) | |
def zip(src, dst): | |
zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED) | |
abs_src = os.path.abspath(src) | |
for dirname, subdirs, files in os.walk(src): | |
for filename in files: | |
absname = os.path.abspath(os.path.join(dirname, filename)) | |
arcname = absname[len(abs_src) + 1:] | |
print 'zipping %s as %s' % (os.path.join(dirname, filename), | |
arcname) | |
zf.write(absname, arcname) | |
zf.close() | |
def prepare_app_store_release(version): | |
zip_link = get_zip_from_tag(version) | |
print "Prepairing appstore release..." | |
if os.path.exists(build_dir + '/tmp'): | |
rmtree(build_dir + '/tmp') | |
os.makedirs(build_dir + '/tmp') | |
download_file(zip_link, '/home/passman/build/tmp/' + version + '.zip') | |
unzip(build_dir + '/tmp/' + version + '.zip', build_dir + '/tmp') | |
os.remove(build_dir + '/tmp/' + version + '.zip') | |
dir_name = os.listdir(build_dir + '/tmp/')[0] | |
os.rename(build_dir + '/tmp/' + dir_name, build_dir + '/tmp/passman') | |
make_tarfile(build_dir + '/tmp/passman', build_dir + '/passman_' + _version + '.tar.gz') | |
gz_file = build_dir + '/passman_' + _version + '.tar.gz' | |
if os.path.exists(release_dir + '/passman_' + _version + '.tar.gz'): | |
os.remove(release_dir + '/passman_' + _version + '.tar.gz') | |
copyfile(gz_file, release_dir + '/passman_' + _version + '.tar.gz') | |
generate_file_hashes(_version) | |
print "Published to releases.passman.cc" | |
signature = os.popen( | |
'openssl dgst -sha512 -sign ' + app_sign_key + ' ' + gz_file + ' | openssl base64').read() | |
nightly = False | |
if _version.lower().find('rc') or _version.lower().find('alpha') or _version.lower().find( | |
'nightly') or _version.lower().find('beta') >= 0: | |
nightly = True | |
postData = { | |
'download': 'https://releases.passman.cc/passman_' + _version + '.tar.gz', | |
'signature': signature, | |
'nightly': nightly | |
} | |
pprint(postData) | |
headers = {'Authorization': 'Token '+ appstore_token, | |
'Content-Type': 'application/json; charset=utf8'} | |
print "Uploading to NextCloud Appstore" | |
r = requests.post('https://apps.nextcloud.com/api/v1/apps/releases', data=json.dumps(postData), headers=headers) | |
os.remove(gz_file) | |
if r.status_code == 201 or r.status_code == 200: | |
print "App published to Nextcloud appstore (" + str(r.status_code) + ")" | |
return True | |
else: | |
print(r.status_code, r.reason) | |
return False | |
print git.cmd.Git(work_dir).pull() | |
_version = False | |
if options.version and force_build: | |
_version = options.version | |
else: | |
_version = get_app_version() | |
if _version != get_last_tag() or force_build == True: | |
if force_build == True: | |
# print os.popen('git push origin :refs/tags/' + _version + ' && git tag --delete ' + _version).read() | |
print '' | |
print "Staring to make a build for Passman " + _version + "\n" | |
make_new_build() | |
commit_message = 'Passman ' + _version + "\n" + get_last_commit_message() | |
print "Committing changes" | |
dist_repo.index.add(dist_repo.untracked_files) | |
try: | |
commit = dist_repo.git.commit(a=True, m=commit_message.strip(), s=True) | |
except: | |
print '' | |
try: | |
print "Pushing to dist branch..." | |
dist_repo.remotes.origin.push() | |
except: | |
print '' | |
_app_published = False | |
if not force_build == True: | |
try: | |
print "Creating tag " + _version | |
new_tag = dist_repo.create_tag(_version, message=commit_message.strip(), s=True) | |
print "Creating new release" | |
dist_repo.remotes.origin.push(['--tags']) | |
_app_published = prepare_app_store_release(_version) | |
except: | |
print '' | |
if force_build: | |
os.system('git tag --delete ' + _version) | |
os.system('git push origin :refs/tags/' + _version) | |
git.cmd.Git(work_dir).pull() | |
dist_repo.delete_tag(_version) | |
print "Creating tag " + _version | |
new_tag = dist_repo.create_tag(_version, message=commit_message.strip(), s=True, f=True) | |
print "Creating new release" | |
dist_repo.remotes.origin.push(['--tags']) | |
sleep(3) | |
_app_published = prepare_app_store_release(_version) | |
if _app_published and not force_build: | |
api = get_twitter_api(twitter_cfg) | |
tweet = 'We just released ' + _version + '! Download available on: https://releases.passman.cc/passman_' + _version + '.tar.gz' | |
status = api.update_status(status=tweet) | |
else: | |
print 'Same version, no need to build' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment