-
-
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.') |
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>'
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.