172 lines
5.2 KiB
Python
Executable File
172 lines
5.2 KiB
Python
Executable File
#!/usr/bin/python3
|
|
"""
|
|
Create Github Releases Notes with binary checksums from Workers KV
|
|
"""
|
|
|
|
import argparse
|
|
import logging
|
|
import os
|
|
import requests
|
|
|
|
from github import Github, UnknownObjectException
|
|
|
|
FORMAT = "%(levelname)s - %(asctime)s: %(message)s"
|
|
logging.basicConfig(format=FORMAT, level=logging.INFO)
|
|
|
|
CLOUDFLARED_REPO = os.environ.get("GITHUB_REPO", "cloudflare/cloudflared")
|
|
GITHUB_CONFLICT_CODE = "already_exists"
|
|
BASE_KV_URL = 'https://api.cloudflare.com/client/v4/accounts/'
|
|
|
|
|
|
def kv_get_keys(prefix, account, namespace, api_token):
|
|
""" get the KV keys for a given prefix """
|
|
response = requests.get(
|
|
BASE_KV_URL + account + "/storage/kv/namespaces/" +
|
|
namespace + "/keys" + "?prefix=" + prefix,
|
|
headers={
|
|
"Content-Type": "application/json",
|
|
"Authorization": "Bearer " + api_token,
|
|
},
|
|
)
|
|
if response.status_code != 200:
|
|
jsonResponse = response.json()
|
|
errors = jsonResponse["errors"]
|
|
if len(errors) > 0:
|
|
raise Exception("failed to get checksums: {0}", errors[0])
|
|
return response.json()["result"]
|
|
|
|
|
|
def kv_get_value(key, account, namespace, api_token):
|
|
""" get the KV value for a provided key """
|
|
response = requests.get(
|
|
BASE_KV_URL + account + "/storage/kv/namespaces/" + namespace + "/values/" + key,
|
|
headers={
|
|
"Content-Type": "application/json",
|
|
"Authorization": "Bearer " + api_token,
|
|
},
|
|
)
|
|
if response.status_code != 200:
|
|
jsonResponse = response.json()
|
|
errors = jsonResponse["errors"]
|
|
if len(errors) > 0:
|
|
raise Exception("failed to get checksums: {0}", errors[0])
|
|
return response.text
|
|
|
|
|
|
def update_or_add_message(msg, name, sha):
|
|
"""
|
|
updates or builds the github version message for each new asset's sha256.
|
|
Searches the existing message string to update or create.
|
|
"""
|
|
new_text = '{0}: {1}\n'.format(name, sha)
|
|
start = msg.find(name)
|
|
if (start != -1):
|
|
end = msg.find("\n", start)
|
|
if (end != -1):
|
|
return msg.replace(msg[start:end+1], new_text)
|
|
back = msg.rfind("```")
|
|
if (back != -1):
|
|
return '{0}{1}```'.format(msg[:back], new_text)
|
|
return '{0} \n### SHA256 Checksums:\n```\n{1}```'.format(msg, new_text)
|
|
|
|
|
|
def get_release(repo, version):
|
|
""" Get a Github Release matching the version tag. """
|
|
try:
|
|
release = repo.get_release(version)
|
|
logging.info("Release %s found", version)
|
|
return release
|
|
except UnknownObjectException:
|
|
logging.info("Release %s not found", version)
|
|
|
|
|
|
def parse_args():
|
|
""" Parse and validate args """
|
|
parser = argparse.ArgumentParser(
|
|
description="Updates a Github Release with checksums from KV"
|
|
)
|
|
parser.add_argument(
|
|
"--api-key", default=os.environ.get("API_KEY"), help="Github API key"
|
|
)
|
|
parser.add_argument(
|
|
"--kv-namespace-id", default=os.environ.get("KV_NAMESPACE"), help="workers KV namespace id"
|
|
)
|
|
parser.add_argument(
|
|
"--kv-account-id", default=os.environ.get("KV_ACCOUNT"), help="workers KV account id"
|
|
)
|
|
parser.add_argument(
|
|
"--kv-api-token", default=os.environ.get("KV_API_TOKEN"), help="workers KV API Token"
|
|
)
|
|
parser.add_argument(
|
|
"--release-version",
|
|
metavar="version",
|
|
default=os.environ.get("VERSION"),
|
|
help="Release version",
|
|
)
|
|
parser.add_argument(
|
|
"--dry-run", action="store_true", help="Do not modify the release message"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
is_valid = True
|
|
if not args.release_version:
|
|
logging.error("Missing release version")
|
|
is_valid = False
|
|
|
|
if not args.api_key:
|
|
logging.error("Missing API key")
|
|
is_valid = False
|
|
|
|
if not args.kv_namespace_id:
|
|
logging.error("Missing KV namespace id")
|
|
is_valid = False
|
|
|
|
if not args.kv_account_id:
|
|
logging.error("Missing KV account id")
|
|
is_valid = False
|
|
|
|
if not args.kv_api_token:
|
|
logging.error("Missing KV API token")
|
|
is_valid = False
|
|
|
|
if is_valid:
|
|
return args
|
|
|
|
parser.print_usage()
|
|
exit(1)
|
|
|
|
|
|
def main():
|
|
""" Attempts to update the Github Release message with the github asset's checksums """
|
|
try:
|
|
args = parse_args()
|
|
client = Github(args.api_key)
|
|
repo = client.get_repo(CLOUDFLARED_REPO)
|
|
release = get_release(repo, args.release_version)
|
|
|
|
msg = ""
|
|
|
|
prefix = f"update_{args.release_version}_"
|
|
keys = kv_get_keys(prefix, args.kv_account_id,
|
|
args.kv_namespace_id, args.kv_api_token)
|
|
for key in [k["name"] for k in keys]:
|
|
checksum = kv_get_value(
|
|
key, args.kv_account_id, args.kv_namespace_id, args.kv_api_token)
|
|
binary_name = key[len(prefix):]
|
|
msg = update_or_add_message(msg, binary_name, checksum)
|
|
|
|
if args.dry_run:
|
|
logging.info("Skipping release message update because of dry-run")
|
|
logging.info(f"Github message:\n{msg}")
|
|
return
|
|
|
|
# update the release body text
|
|
release.update_release(args.release_version, msg)
|
|
|
|
except Exception as e:
|
|
logging.exception(e)
|
|
exit(1)
|
|
|
|
|
|
main()
|