From b46acd7f6381dbfff81b265c3d8a06988424af62 Mon Sep 17 00:00:00 2001 From: Michael Borkenstein Date: Tue, 23 Jun 2020 16:23:40 -0500 Subject: [PATCH] AUTH-2685: Adds script to create release --- Makefile | 10 ++++ cfsetup.yaml | 64 +++++++++++++++++++++++ github_release.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100755 github_release.py diff --git a/Makefile b/Makefile index 56158453..41fc274c 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,12 @@ else $(error This system's OS $(LOCAL_OS) isn't supported) endif +ifeq ($(TARGET_OS), windows) + EXECUTABLE_PATH=./cloudflared.exe +else + EXECUTABLE_PATH=./cloudflared +endif + .PHONY: all all: cloudflared test @@ -88,6 +94,10 @@ homebrew-release: homebrew-upload release: bin/equinox bin/equinox release $(EQUINOX_FLAGS) -- $(VERSION_FLAGS) $(IMPORT_PATH)/cmd/cloudflared +.PHONY: github-release +github-release: cloudflared + python3 github_release.py --path $(EXECUTABLE_PATH) --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 f7ddcb2c..55420ee9 100644 --- a/cfsetup.yaml +++ b/cfsetup.yaml @@ -31,6 +31,18 @@ stretch: &stretch - export GOOS=linux - export GOARCH=amd64 - make release + github-release-linux-amd64: + build_dir: *build_dir + builddeps: + - *pinned_go + - build-essential + - python3-setuptools + - python3-pip + post-cache: + - pip3 install pygithub + - export GOOS=linux + - export GOARCH=amd64 + - make github-release release-linux-armv6: build_dir: *build_dir builddeps: @@ -42,6 +54,20 @@ stretch: &stretch - export GOARCH=arm - export CC=arm-linux-gnueabihf-gcc - make release + github-release-linux-armv6: + build_dir: *build_dir + builddeps: + - *pinned_go + - crossbuild-essential-armhf + - gcc-arm-linux-gnueabihf + - python3-setuptools + - python3-pip + post-cache: + - pip3 install pygithub + - export GOOS=linux + - export GOARCH=arm + - export CC=arm-linux-gnueabihf-gcc + - make github-release release-linux-386: build_dir: *build_dir builddeps: @@ -51,6 +77,18 @@ stretch: &stretch - export GOOS=linux - export GOARCH=386 - make release + github-release-linux-386: + build_dir: *build_dir + builddeps: + - *pinned_go + - gcc-multilib + - python3-setuptools + - python3-pip + post-cache: + - pip3 install pygithub + - export GOOS=linux + - export GOARCH=386 + - make github-release release-windows-amd64: build_dir: *build_dir builddeps: @@ -61,6 +99,19 @@ stretch: &stretch - export GOARCH=amd64 - export CC=x86_64-w64-mingw32-gcc - make release + github-release-windows-amd64: + build_dir: *build_dir + builddeps: + - *pinned_go + - gcc-mingw-w64 + - python3-setuptools + - python3-pip + post-cache: + - pip3 install pygithub + - export GOOS=windows + - export GOARCH=amd64 + - export CC=x86_64-w64-mingw32-gcc + - make github-release release-windows-386: build_dir: *build_dir builddeps: @@ -71,6 +122,19 @@ stretch: &stretch - export GOARCH=386 - export CC=i686-w64-mingw32-gcc-win32 - make release + github-release-windows-386: + build_dir: *build_dir + builddeps: + - *pinned_go + - gcc-mingw-w64 + - python3-setuptools + - python3-pip + post-cache: + - pip3 install pygithub + - export GOOS=windows + - export GOARCH=386 + - export CC=i686-w64-mingw32-gcc-win32 + - make github-release test: build_dir: *build_dir builddeps: diff --git a/github_release.py b/github_release.py new file mode 100755 index 00000000..6ced8032 --- /dev/null +++ b/github_release.py @@ -0,0 +1,128 @@ +#!/usr/bin/python3 +""" +Creates Github Releases and uploads assets +""" + +import argparse +import logging +import os + +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 assert_tag_exists(repo, version): + """ Raise exception if repo does not contain a tag matching version """ + tags = repo.get_tags() + if not tags or tags[0].name != version: + raise Exception("Tag {} not found".format(version)) + + +def get_or_create_release(repo, version, dry_run=False): + """ + Get a Github Release matching the version tag or create a new one. + If a conflict occurs on creation, attempt to fetch the Release on last time + """ + try: + release = repo.get_release(version) + logging.info("Release %s found", version) + return release + except UnknownObjectException: + logging.info("Release %s not found", version) + + # We dont want to create a new release tag if one doesnt already exist + assert_tag_exists(repo, version) + + if dry_run: + logging.info("Skipping Release creation because of dry-run") + return + + try: + logging.info("Creating release %s", version) + return repo.create_git_release(version, version, "") + except GithubException as e: + errors = e.data.get("errors", []) + if e.status == 422 and any( + [err.get("code") == GITHUB_CONFLICT_CODE for err in errors] + ): + logging.warning( + "Conflict: Release was likely just made by a different build: %s", + e.data, + ) + return repo.get_release(version) + raise e + + +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( + "--path", default=os.environ.get("ASSET_PATH"), help="Asset path" + ) + parser.add_argument( + "--name", default=os.environ.get("ASSET_NAME"), help="Asset Name" + ) + parser.add_argument( + "--dry-run", action="store_true", help="Do not create release or upload asset" + ) + + args = parser.parse_args() + is_valid = True + if not args.release_version: + logging.error("Missing release version") + is_valid = False + + if not args.path: + logging.error("Missing asset path") + is_valid = False + + if not args.name: + logging.error("Missing asset name") + 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 upload Asset to Github Release. Creates Release if it doesnt exist """ + try: + args = parse_args() + client = Github(args.api_key) + repo = client.get_repo(CLOUDFLARED_REPO) + release = get_or_create_release(repo, args.release_version, args.dry_run) + + if args.dry_run: + logging.info("Skipping asset upload because of dry-run") + return + + release.upload_asset(args.path, name=args.name) + except Exception as e: + logging.exception(e) + exit(1) + + +main()