-
-
Save mcguffin/7fbe709a624f672f60c770c080cbc41a to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3 | |
import argparse, glob, json, re, subprocess, urllib.request, os, sys | |
class version_number: | |
major=0 | |
minor=0 | |
release=0 | |
release_suffix='' | |
def __init__(self,version='0.0.0'): | |
(self.major,self.minor,release) = version.split('.',2) | |
# extract release suffix like 0.1.2-alpha1234 | |
res = re.search(r'[^0-9]',release) | |
if res: | |
s = res.start() | |
self.release = release[:s] | |
self.release_suffix = release[s:] | |
else: | |
self.release = release | |
(self.major,self.minor,self.release) = map(int,(self.major,self.minor,self.release)) | |
def __add__(self,other): | |
self.release_suffix = '' | |
self.major += other.major | |
self.minor += other.minor | |
self.release += other.release | |
return self | |
def incr(self,what="release"): | |
self.release_suffix = '' | |
if what == 'release': | |
self.release+=1 | |
if what == 'minor': | |
self.minor+=1 | |
self.release = 0 | |
if what == 'major': | |
self.major+=1 | |
self.minor = 0 | |
self.release = 0 | |
return self | |
def __str__(self): | |
s = '.'.join( map(str,(self.major,self.minor,self.release)) ) | |
return '%s%s' % (s,self.release_suffix) | |
def shell(cmd, check=True): | |
result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, check=check ) | |
return result.stdout.decode('utf-8').strip() | |
def get_file_data( plugin_file, headers={'Plugin Name':'Plugin Name','Version':'Version'} ): | |
f = open(plugin_file,'r') | |
contents = f.read() | |
f.close() | |
contents.replace("\r","\n") | |
ret = {} | |
for field,regex in headers.items(): | |
res = re.compile( '^[ \t*#@]*%s:(?P<value>.*)$' % (regex), re.I | re.M ).search(contents) | |
ret[field] = res.group('value').strip() | |
# | |
#contents.match() | |
return ret | |
def update_plugin_version( new_version ): | |
for plugin_file in glob.glob("*.php"): | |
fdata = get_file_data( plugin_file ) | |
if 'Version' in fdata: | |
# read | |
f = open(plugin_file,'r') | |
contents = f.read() | |
f.close() | |
reg = re.compile( u'^([ \t*#@]*)Version:[\s\t]*(.*)$', re.I | re.M ) | |
repl = r'\1Version: %s' % (new_version) | |
contents = reg.sub( repl, contents ) | |
f = open(plugin_file,'w') | |
contents = f.write(contents) | |
f.close() | |
# add commit push | |
shell('git add .') | |
try: | |
shell('git commit -q -m "Release version %s"' % (new_version), check=True) | |
shell('git push', check=True) | |
return True | |
except subprocess.CalledProcessError: | |
return False | |
return False | |
# check env config | |
try: | |
access_token = shell('security find-generic-password -a ${USER} -s GithubAccessToken -w') | |
except KeyError: | |
print("Missing env var `GITHUB_ACCESS_TOKEN`") | |
sys.exit(1) | |
# check if git repo | |
repo_remote = shell('git config --get remote.origin.url') | |
if not repo_remote: | |
print("Not a git repository") | |
sys.exit(1) | |
repo_name = re.sub(r'\.git$','',os.path.basename(repo_remote) ) | |
repo_owner = shell('git config --get user.name') | |
repo_current_branch = shell('git rev-parse --abbrev-ref HEAD') | |
# Parse cli args | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-r","--release", | |
default='release', | |
const='release', | |
help="Type of Release. 'release' (default) will increment the last version number, 'minor' the middle one and 'major' the first one.", | |
type=str, | |
choices=['release','minor','major'], | |
nargs='?') | |
parser.add_argument("-v","--version", help="Version number. Must be in format `<major>.<minor>.<release>`. You may append something like `1.2.3-beta-RC3` also. For automatic versioning use -r.",type=str ) | |
parser.add_argument("-m","--message", help="Release Message") | |
parser.add_argument("-p","--pre", type=bool, help="Prerelease", default=False) | |
parser.add_argument("-d","--draft", type=bool, help="Draft", default=False) | |
parser.add_argument("-b","--branch", type=str, help="Branch", default=repo_current_branch) | |
args = parser.parse_args() | |
# get version string | |
if args.version: | |
new_version = version_number(args.version) | |
elif args.release: | |
# | |
new_version = False | |
for plugin_file in glob.glob("*.php"): | |
fdata = get_file_data( plugin_file ) | |
if 'Version' in fdata: | |
new_version = version_number(fdata['Version']) | |
break | |
else: | |
print("Nope...",plugin_file) | |
new_version.incr(args.release) | |
print('Building Release %s from branch %s now.' % (new_version,args.branch)) | |
# get message | |
if args.message: | |
body = args.message | |
else: | |
body = "Release of version %s from branch %s" % (new_version, args.branch) | |
readme_data = get_file_data('readme.txt',headers={ | |
'Requires at least': 'Requires at least', | |
'Tested up to': 'Tested up to', | |
'Requires PHP': 'Requires PHP' | |
}) | |
body = """%s | |
Requires at least: %s | |
Tested up to: %s | |
Requires PHP: %s | |
""" % (body, | |
readme_data['Requires at least'], | |
readme_data['Tested up to'], | |
readme_data['Requires PHP'] | |
) | |
# Update plugin header, commit, push | |
if not update_plugin_version(new_version): | |
print('Could not push changes') | |
sys.exit(1) | |
# create tag via api | |
request_data = { | |
'tag_name': "v%s" % (new_version), | |
'target_commitish': args.branch, | |
'name': "v%s" % (new_version), | |
'body': body, | |
'draft': bool(args.draft), | |
'prerelease': bool(args.pre) | |
} | |
request_url = 'https://api.github.com/repos/%s/%s/releases?access_token=%s' % (repo_owner,repo_name,access_token) | |
# send api request | |
print('Create tag...') | |
with urllib.request.urlopen(request_url,data=json.dumps(request_data).encode('utf-8')) as f: | |
# parse response | |
api_response = json.loads( f.read().decode('utf-8') ) | |
# create installable zip | |
# git archive --format=zip -v --output=../<reponame>.zip --worktree-attributes HEAD | |
# mk zip | |
zip_path = '../%s.zip' % (repo_name) | |
print('Create installable ZIP...') | |
shell('git archive --format=zip --prefix=%s/ --output=%s --worktree-attributes HEAD' % ( repo_name, zip_path ) ) | |
# upload zip to tag | |
print('Upload ZIP...') | |
upload_url = '%s?name=%s.zip' % ( re.sub( r'{\?.*}$', '', api_response['upload_url'] ), repo_name ) | |
hdl = open('../%s.zip' % (repo_name),'rb') | |
# post file | |
upload_req = urllib.request.Request(upload_url, | |
data = hdl.read(), | |
headers = { | |
'Authorization' : 'token %s' % (access_token), | |
'Content-Type' : 'application/zip' | |
} | |
) | |
with urllib.request.urlopen( upload_req ) as f: | |
# parse response | |
upload_response = json.loads( f.read().decode('utf-8') ) | |
print('Cleanup...') | |
shell('rm %s' % (zip_path) ) | |
print('All done.') |
Thanks for sharing!
Will the script work for ordinary privatly hosted git-repositories?
I see the script has direct references to https://api.github.com/...
, so probably it won't work as is.
In theory it should work, as long as your github ssh key and token credentials are working.
FYI I havent looked into this gist for ages, and I'm using something else now to create my WordPress Plugin releases.
Is this script only for osx?
@dcorrea777 It's calling the macOS password manager shell in line 100 – this is osx-only.
All the rest should be platform independant, as only the git
command and rm
is used.
With a hard-coded github access token you should be good to go.
Got it @mcguffin
This line itself is giving me an error, because I am not using osx but linux, is there any step that I should disregard so that it does not execute this osx command line?
@dcorrea777 replace lines 99 to 103 with access_token = '<your github access token here>'
Setup
security add-generic-password -a ${USER} -s GithubAccessToken -w <your access token>
in the commandline.Usage
Your repository's remote origin must be a github location. Setup and commit a .gitattributes file to exclude developer related files like sources or tests.