Skip to content

Instantly share code, notes, and snippets.

@brantje
Created January 6, 2017 20:34
Show Gist options
  • Save brantje/f097b32a80fca6643d86dee25d9d16fa to your computer and use it in GitHub Desktop.
Save brantje/f097b32a80fca6643d86dee25d9d16fa to your computer and use it in GitHub Desktop.
This is the release script i use for my passman builds
#!/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