diff --git a/Makefile b/Makefile index ccd9a5fb..71a58144 100644 --- a/Makefile +++ b/Makefile @@ -137,6 +137,10 @@ release: bin/equinox github-release: cloudflared python3 github_release.py --path $(EXECUTABLE_PATH) --release-version $(VERSION) +.PHONY: github-message +github-message: + python3 github_message.py --release-version $(VERSION) + bin/equinox: mkdir -p bin curl -s https://bin.equinox.io/c/75JtLRTsJ3n/release-tool-beta-$(EQUINOX_PLATFORM).tgz | tar xz -C bin/ diff --git a/cfsetup.yaml b/cfsetup.yaml index ebde55de..9a1004ed 100644 --- a/cfsetup.yaml +++ b/cfsetup.yaml @@ -190,6 +190,15 @@ stretch: &stretch - s3cmd post-cache: - .teamcity/update-homebrew.sh + github-message-release: + build_dir: *build_dir + builddeps: + - *pinned_go + - python3-setuptools + - python3-pip + post-cache: + - pip3 install pygithub + - make github-message jessie: *stretch diff --git a/github_message.py b/github_message.py new file mode 100644 index 00000000..0e8dc960 --- /dev/null +++ b/github_message.py @@ -0,0 +1,117 @@ +#!/usr/bin/python3 +""" +Creates Github Releases Notes with content hashes +""" + +import argparse +import logging +import os +import hashlib +import glob + +from github import Github, GithubException, UnknownObjectException + +FORMAT = "%(levelname)s - %(asctime)s: %(message)s" +logging.basicConfig(format=FORMAT) + +CLOUDFLARED_REPO = os.environ.get("GITHUB_REPO", "cloudflare/cloudflared") +GITHUB_CONFLICT_CODE = "already_exists" + +def get_sha256(filename): + """ get the sha256 of a file """ + sha256_hash = hashlib.sha256() + with open(filename,"rb") as f: + for byte_block in iter(lambda: f.read(4096),b""): + sha256_hash.update(byte_block) + return sha256_hash.hexdigest() + + +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="Creates Github Releases and uploads assets." + ) + parser.add_argument( + "--api-key", default=os.environ.get("API_KEY"), help="Github API key" + ) + 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 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 = release.body + + for filename in glob.glob(".artifacts/*.*"): + pkg_hash = get_sha256(filename) + # add the sha256 of the new artifact to the release message body + msg = update_or_add_message(msg, filename, pkg_hash) + + if args.dry_run: + logging.info("Skipping asset upload because of dry-run") + return + + # update the release body text + release.update_release(version, version, msg) + + except Exception as e: + logging.exception(e) + exit(1) + + +main() \ No newline at end of file diff --git a/github_release.py b/github_release.py index 88505e07..ddcd8134 100755 --- a/github_release.py +++ b/github_release.py @@ -6,7 +6,7 @@ Creates Github Releases and uploads assets import argparse import logging import os -import hashlib +import shutil from github import Github, GithubException, UnknownObjectException @@ -16,31 +16,6 @@ logging.basicConfig(format=FORMAT) CLOUDFLARED_REPO = os.environ.get("GITHUB_REPO", "cloudflare/cloudflared") GITHUB_CONFLICT_CODE = "already_exists" -def get_sha256(filename): - """ get the sha256 of a file """ - sha256_hash = hashlib.sha256() - with open(filename,"rb") as f: - for byte_block in iter(lambda: f.read(4096),b""): - sha256_hash.update(byte_block) - return sha256_hash.hexdigest() - - -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 assert_tag_exists(repo, version): """ Raise exception if repo does not contain a tag matching version """ tags = repo.get_tags() @@ -146,12 +121,16 @@ def main(): release.upload_asset(args.path, name=args.name) - # add the sha256 of the new artifact to the release message body - pkg_hash = get_sha256(args.path) + # create the artifacts directory if it doesn't exist + artifact_path = os.path.join(os.getcwd(), 'artifacts') + if not os.path.isdir(artifact_path): + os.mkdir(artifact_path) + + # copy the binary to the path + copy_path = os.path.join(artifact_path, args.name) + shutil.copy(args.path, copy_path) + - # update the release body text - msg = update_or_add_message(release.body, args.name, pkg_hash) - release.update_release(version, version, msg) except Exception as e: logging.exception(e)