build/upload_release.py (82 lines of code) (raw):

# Copyright (c) 2020 The Neuropod Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import glob import os import platform import subprocess import sys import requests # The `or` pattern below handles empty strings and unset env variables # Using a default value only handles unset env variables # TODO(vip): Don't duplicate this between install_frameworks.py and upload_release.py REQUESTED_TF_VERSION = os.getenv("NEUROPOD_TENSORFLOW_VERSION") or "1.12.0" REQUESTED_TORCH_VERSION = os.getenv("NEUROPOD_TORCH_VERSION") or "1.1.0" IS_GPU = (os.getenv("NEUROPOD_IS_GPU") or None) is not None CUDA_VERSION = os.getenv("NEUROPOD_CUDA_VERSION") or "10.0" IS_MAC = platform.system() == "Darwin" GIT_TAG = os.getenv("BUILDKITE_TAG") if GIT_TAG is None: # Check GH actions github_ref = os.getenv("GITHUB_REF", default="") if github_ref.startswith("refs/tags/"): GIT_TAG = github_ref.replace("refs/tags/","", 1) PYTHON_VERSION = "{}{}".format(sys.version_info.major, sys.version_info.minor) GH_UPLOAD_TOKEN = os.getenv("GH_UPLOAD_TOKEN") # Get the frameworks we should upload NEUROPOD_TEST_FRAMEWORKS = os.getenv("NEUROPOD_TEST_FRAMEWORKS") if NEUROPOD_TEST_FRAMEWORKS is not None: NEUROPOD_TEST_FRAMEWORKS = set(NEUROPOD_TEST_FRAMEWORKS.split(",")) def should_upload(framework): """ Whether we should upload an artifact for `framework` """ if NEUROPOD_TEST_FRAMEWORKS is None: return True return framework in NEUROPOD_TEST_FRAMEWORKS def upload(): release_id = get_release_id(GIT_TAG) platform = "libneuropod-{gpustring}-{os}-{tag}".format( gpustring="gpu-cuda-{}".format(CUDA_VERSION) if IS_GPU else "cpu", os="macos" if IS_MAC else "linux", tag=GIT_TAG, ) # Only upload the main library on one build (because we don't need to upload once per backend version) # This is also not CPU/GPU dependent # For each OS: if REQUESTED_TF_VERSION == "1.14.0" and not IS_GPU: upload_package( "source/bazel-bin/neuropod/libneuropod.tar.gz", release_id, "libneuropod-{os}-{tag}.tar.gz".format( os="macos" if IS_MAC else "linux", tag=GIT_TAG, ) ) if should_upload("torchscript"): # For each OS: For each backend version: For each CPU/GPU: upload_package("source/bazel-bin/neuropod/backends/torchscript/neuropod_torchscript_backend.tar.gz", release_id, "{}-torchscript-{}-backend.tar.gz".format(platform, REQUESTED_TORCH_VERSION)) if should_upload("tensorflow"): # For each OS: For each backend version: For each CPU/GPU: upload_package("source/bazel-bin/neuropod/backends/tensorflow/neuropod_tensorflow_backend.tar.gz", release_id, "{}-tensorflow-{}-backend.tar.gz".format(platform, REQUESTED_TF_VERSION)) # The python package is the same across CPU/GPU and different versions of backends so we'll only upload once for mac and once for linux # TODO(vip): Do this better if REQUESTED_TORCH_VERSION not in ["1.6.0", "1.7.0", "1.8.1", "1.9.0"] and not IS_GPU: # For each OS: For each python version # Upload the pythonbridge backend upload_package("source/bazel-bin/neuropod/backends/python_bridge/neuropod_pythonbridge_backend.tar.gz", release_id, "{}-python-{}-backend.tar.gz".format(platform, PYTHON_VERSION)) # Upload the wheels for gpath in ["source/python/dist/neuropod-*.whl"]: whl_path = glob.glob(gpath)[0] fname = os.path.basename(whl_path) upload_package(whl_path, release_id, fname, content_type="application/zip") def get_release_id(tag_name): # https://api.github.com/repos/uber/neuropod/releases/tags/{tag_name} release_id = requests.get( 'https://api.github.com/repos/uber/neuropod/releases/tags/{}'.format(tag_name), headers={"Authorization": "token {}".format(GH_UPLOAD_TOKEN)}, ).json()["id"] print("Release ID: {}".format(release_id)) return release_id def get_repo_info(): # https://api.github.com/repos/uber/neuropod return requests.get('https://api.github.com/repos/uber/neuropod').json() def upload_package(local_path, release_id, asset_filename, content_type="application/gzip"): # POST https://uploads.github.com/repos/uber/neuropod/releases/{release_id}/assets?name={asset_filename} print("Uploading {}...".format(asset_filename)) with open(local_path, 'rb') as f: r = requests.post( "https://uploads.github.com/repos/uber/neuropod/releases/{}/assets?name={}".format(release_id, asset_filename), headers={ "Authorization": "token {}".format(GH_UPLOAD_TOKEN), "Content-Type": content_type, }, data=f ) if r.status_code != 201: print("Error uploading", r.json()) raise ValueError("Error uploading {}. Got message: {}".format(asset_filename, r.json()["message"])) if __name__ == '__main__': if os.getenv("CI") is not None: # Make a request to the github API to ensure we can (this helps catch failures like old SSL libs) get_repo_info() if not GIT_TAG or not GH_UPLOAD_TOKEN: # Don't upload if we don't have a tag or token pass else: print("Uploading packages for tag {}...".format(GIT_TAG)) upload()