mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-01 01:27:20 +01:00
218 lines
7.2 KiB
Python
218 lines
7.2 KiB
Python
# uploads artifacts to nightly releases
|
|
# NOTE: this is just a quick fix, feel free to handle releases more cleanly
|
|
import urllib.request, json, argparse, glob, subprocess, os
|
|
|
|
# to handle nightly releases:
|
|
# - create repo (could be in main repo but needs a tag, that is associated with some commit)
|
|
# - create release w/ tag, this is were uploads go
|
|
# - upload assets manually or via API below, needs access token
|
|
# - assets have a fixed link based on tag = good
|
|
#
|
|
# To generate access tokens:
|
|
# - go to user settings > developer settings
|
|
#
|
|
# * there are github actions that automate this that could be used, this is based from manual tests
|
|
# * also "import github" to use Github(token) that comes with many helpers
|
|
# gh = Github(token)
|
|
# gh_repo = gh.get_repo(repo)
|
|
# gh_release = gh_repo.get_release(tag)
|
|
# assets = gh_release.get_assets()
|
|
# gh_release.update_release(...)
|
|
# gh_release.upload_asset(...)
|
|
#
|
|
# API: https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28
|
|
# https://docs.github.com/en/rest/releases/assets?apiVersion=2022-11-28
|
|
#
|
|
# Github's API has some limits but hopefully not reached by current token
|
|
|
|
RELEASE_TAG = 'nightly'
|
|
# gives info about release (public)
|
|
URL_RELEASE = 'https://api.github.com/repos/vgmstream/vgmstream-releases/releases/tags/nightly'
|
|
# allows deleting a single asset
|
|
URL_DELETE = 'https://api.github.com/repos/vgmstream/vgmstream-releases/releases/assets/%s'
|
|
# allows uploading a single asset
|
|
URL_UPLOAD = 'https://uploads.github.com/repos/vgmstream/vgmstream-releases/releases/%s/assets?name=%s'
|
|
# change release info
|
|
URL_UPDATE = 'https://api.github.com/repos/vgmstream/vgmstream-releases/releases/%s'
|
|
# gives info about last vgmstream tag
|
|
URL_VGMSTREAM = 'https://api.github.com/repos/vgmstream/vgmstream/releases?per_page=1'
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
def get_release():
|
|
contents = urllib.request.urlopen(URL_RELEASE).read()
|
|
data = json.loads(contents)
|
|
return data
|
|
|
|
def get_vgmstream_tag():
|
|
# TODO could use local git tag
|
|
contents = urllib.request.urlopen(URL_VGMSTREAM).read()
|
|
data = json.loads(contents)
|
|
return data[0]['tag_name']
|
|
|
|
def update_release(release, token, debug, body):
|
|
release_id = release['id']
|
|
|
|
args = [
|
|
'curl',
|
|
'-X', 'PATCH',
|
|
'-H', 'Accept: application/vnd.github+json',
|
|
'-H', 'Authorization: Bearer %s' % (token),
|
|
'-H', 'X-GitHub-Api-Version: 2022-11-28',
|
|
URL_UPDATE % (release_id),
|
|
'-d', '{"body":"%s"}' % (body),
|
|
]
|
|
#-d '{"tag_name":"v1.0.0","target_commitish":"master","name":"v1.0.0","body":"...","draft":false,"prerelease":false}'
|
|
|
|
print("* updating release text")
|
|
if debug:
|
|
print(' '.join(args))
|
|
else:
|
|
subprocess.run(args, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
|
|
def delete_asset(release, token, debug, file):
|
|
basename = os.path.basename(file)
|
|
|
|
asset_id = None
|
|
for asset in release['assets']:
|
|
if asset['name'].lower() == basename.lower():
|
|
asset_id = asset['id']
|
|
break
|
|
if not asset_id:
|
|
print("asset id not found")
|
|
return
|
|
|
|
args = [
|
|
'curl',
|
|
'-X', 'DELETE',
|
|
'-H', 'Accept: application/vnd.github+json',
|
|
'-H', 'Authorization: Bearer %s' % (token),
|
|
'-H', 'X-GitHub-Api-Version: 2022-11-28',
|
|
URL_DELETE % (asset_id),
|
|
]
|
|
|
|
print("* deleting old asset %s (%s)" % (file, asset_id))
|
|
if debug:
|
|
print(' '.join(args))
|
|
else:
|
|
subprocess.run(args, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
|
|
def upload_asset(release, token, debug, file):
|
|
basename = os.path.basename(file)
|
|
release_id = release['id']
|
|
|
|
args = [
|
|
'curl',
|
|
'-X', 'POST',
|
|
'-H', 'Accept: application/vnd.github+json',
|
|
'-H', 'Authorization: Bearer %s' % (token),
|
|
'-H', 'X-GitHub-Api-Version: 2022-11-28',
|
|
'-H', 'Content-Type: application/octet-stream',
|
|
URL_UPLOAD % (release_id, basename),
|
|
'--data-binary', '@%s' % (file)
|
|
]
|
|
|
|
print("* uploading asset %s" % (file))
|
|
if debug:
|
|
print(' '.join(args))
|
|
else:
|
|
subprocess.run(args, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
def generate_changelog(release, token, debug):
|
|
print("* generating changelog")
|
|
try:
|
|
import changelog
|
|
# writes in work dir and gets lines
|
|
lines = changelog.main()
|
|
|
|
current_tag = get_vgmstream_tag()
|
|
body = [
|
|
'Automated releases ([full diffs here](https://github.com/vgmstream/vgmstream/compare/%s...master)).' % (current_tag),
|
|
'',
|
|
'',
|
|
'<details>'
|
|
'<summary>Recent changes</summary>',
|
|
'', #important, collapsable doesn't work otherwise
|
|
]
|
|
body.extend(lines)
|
|
body.extend([
|
|
'</details>'
|
|
])
|
|
body_text = '\\n'.join(body)
|
|
body_text = body_text.replace('"', '\"')
|
|
|
|
file = "changelog.txt"
|
|
update_release(release, token, debug, body_text)
|
|
delete_asset(release, token, debug, file)
|
|
upload_asset(release, token, debug, file)
|
|
|
|
#with open("body.json",'w') as f:
|
|
# f.write('{"body":"%s"}' % (body_text))
|
|
|
|
#with open("changelog.txt",'rb') as f:
|
|
# print(f.read())
|
|
|
|
except Exception as e:
|
|
print("couldn't generate changelog", e)
|
|
|
|
|
|
def main(args):
|
|
print("starting asset uploader")
|
|
|
|
files = []
|
|
for file_glob in args.files:
|
|
files += glob.glob(file_glob)
|
|
|
|
# allow for changelog only
|
|
#if not files:
|
|
# raise ValueError("no files found")
|
|
|
|
# shouldn't happen (points to non-existing files)
|
|
if args.files and not files:
|
|
raise ValueError("no files found, expected: %s" % (args.files))
|
|
|
|
# this token usually only exists in env on merges, but allow passing for tests
|
|
token = args.token
|
|
if not token:
|
|
token = os.environ.get('UPLOADER_GITHUB_TOKEN')
|
|
if not token:
|
|
print("token not defined")
|
|
raise ValueError("token not defined")
|
|
|
|
print("handling %s files" % (len(files)))
|
|
try:
|
|
release = get_release()
|
|
for file in files:
|
|
delete_asset(release, token, args.debug, file)
|
|
upload_asset(release, token, args.debug, file)
|
|
except Exception as e:
|
|
print("error during process: %s" % (e))
|
|
raise ValueError("could't upload")
|
|
|
|
# this should be invoked separately so release doesn't change per artifact
|
|
if args.changelog:
|
|
generate_changelog(release, token, args.debug)
|
|
|
|
print("done")
|
|
|
|
def parse_args():
|
|
description = (
|
|
"uploads artifacts to releases"
|
|
)
|
|
epilog = None
|
|
|
|
ap = argparse.ArgumentParser(description=description, epilog=epilog, formatter_class=argparse.RawTextHelpFormatter)
|
|
ap.add_argument("files", help="files to upload", nargs='*')
|
|
ap.add_argument("-t","--token", help="security token")
|
|
ap.add_argument("-c","--changelog", help="update changelog as well", action="store_true")
|
|
ap.add_argument("-x","--debug", help="no actions", action="store_true")
|
|
|
|
args = ap.parse_args()
|
|
return args
|
|
|
|
if __name__ == "__main__":
|
|
args = parse_args()
|
|
main(args)
|