127 lines
3.9 KiB
Python
127 lines
3.9 KiB
Python
import json
|
|
import os
|
|
import sys
|
|
import glob
|
|
import time
|
|
import urllib.request
|
|
|
|
api_url = 'https://api.github.com/repos/duckdb/duckdb/'
|
|
|
|
if len(sys.argv) < 2:
|
|
print("Usage: [filename1] [filename2] ... ")
|
|
exit(1)
|
|
|
|
# this essentially should run on release tag builds to fill up release assets and master
|
|
|
|
repo = os.getenv("GITHUB_REPOSITORY", "")
|
|
if repo != "duckdb/duckdb":
|
|
print("Not running on forks. Exiting.")
|
|
exit(0)
|
|
|
|
ref = os.getenv("GITHUB_REF", '') # this env var is always present just not always used
|
|
if ref == 'refs/heads/main':
|
|
print("Not running on main branch. Exiting.")
|
|
exit(0)
|
|
elif ref.startswith('refs/tags/'):
|
|
tag = ref.replace('refs/tags/', '')
|
|
else:
|
|
print("Not running on branches. Exiting.")
|
|
exit(0)
|
|
|
|
|
|
print("Running on tag %s" % tag)
|
|
|
|
|
|
token = os.getenv("GH_TOKEN", "")
|
|
if token == "":
|
|
raise ValueError('need a GitHub token in GH_TOKEN')
|
|
|
|
|
|
def internal_gh_api(suburl, filename='', method='GET'):
|
|
url = api_url + suburl
|
|
headers = {"Content-Type": "application/json", 'Authorization': 'token ' + token}
|
|
|
|
body_data = b''
|
|
raw_resp = None
|
|
if len(filename) > 0:
|
|
method = 'POST'
|
|
body_data = open(filename, 'rb')
|
|
headers["Content-Type"] = "binary/octet-stream"
|
|
headers["Content-Length"] = os.path.getsize(local_filename)
|
|
url = suburl # cough
|
|
|
|
req = urllib.request.Request(url, body_data, headers)
|
|
req.get_method = lambda: method
|
|
print(f'GH API URL: "{url}" Filename: "{filename}" Method: "{method}"')
|
|
raw_resp = urllib.request.urlopen(req).read().decode()
|
|
|
|
if method != 'DELETE':
|
|
return json.loads(raw_resp)
|
|
else:
|
|
return {}
|
|
|
|
|
|
def gh_api(suburl, filename='', method='GET'):
|
|
timeout = 1
|
|
nretries = 10
|
|
success = False
|
|
for i in range(nretries + 1):
|
|
try:
|
|
response = internal_gh_api(suburl, filename, method)
|
|
success = True
|
|
except urllib.error.HTTPError as e:
|
|
print(e.read().decode()) # gah
|
|
except Exception as e:
|
|
print(e)
|
|
if success:
|
|
break
|
|
print(f"Failed upload, retrying in {timeout} seconds... ({i}/{nretries})")
|
|
time.sleep(timeout)
|
|
timeout = timeout * 2
|
|
if not success:
|
|
raise Exception("Failed to open URL " + suburl)
|
|
return response
|
|
|
|
|
|
# check if tag exists
|
|
resp = gh_api('git/ref/tags/%s' % tag)
|
|
if 'object' not in resp or 'sha' not in resp['object']: # or resp['object']['sha'] != sha
|
|
raise ValueError('tag %s not found' % tag)
|
|
|
|
resp = gh_api('releases/tags/%s' % tag)
|
|
if 'id' not in resp or 'upload_url' not in resp:
|
|
raise ValueError('release does not exist for tag ' % tag)
|
|
|
|
|
|
# double-check that release exists and has correct sha
|
|
# disabled to not spam people watching releases
|
|
# if 'id' not in resp or 'upload_url' not in resp or 'target_commitish' not in resp or resp['target_commitish'] != sha:
|
|
# raise ValueError('release does not point to requested commit %s' % sha)
|
|
|
|
# TODO this could be a paged response!
|
|
assets = gh_api('releases/%s/assets' % resp['id'])
|
|
|
|
upload_url = resp['upload_url'].split('{')[0] # gah
|
|
files = sys.argv[1:]
|
|
for filename in files:
|
|
if '=' in filename:
|
|
parts = filename.split("=")
|
|
asset_filename = parts[0]
|
|
paths = glob.glob(parts[1])
|
|
if len(paths) != 1:
|
|
raise ValueError("Could not find file for pattern %s" % parts[1])
|
|
local_filename = paths[0]
|
|
else:
|
|
asset_filename = os.path.basename(filename)
|
|
local_filename = filename
|
|
|
|
# delete if present
|
|
for asset in assets:
|
|
if asset['name'] == asset_filename:
|
|
gh_api('releases/assets/%s' % asset['id'], method='DELETE')
|
|
|
|
resp = gh_api(f'{upload_url}?name={asset_filename}', filename=local_filename)
|
|
if 'id' not in resp:
|
|
raise ValueError('upload failed :/ ' + str(resp))
|
|
print("%s -> %s" % (local_filename, resp['browser_download_url']))
|