1# This file is dual licensed under the terms of the Apache License, Version 2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 3# for complete details. 4 5from __future__ import absolute_import, division, print_function 6 7import getpass 8import glob 9import io 10import os 11import subprocess 12import time 13 14import click 15 16from clint.textui.progress import Bar as ProgressBar 17 18import requests 19 20 21JENKINS_URL = ( 22 "https://ci.cryptography.io/job/cryptography-support-jobs/" 23 "job/wheel-builder" 24) 25 26 27def run(*args, **kwargs): 28 print("[running] {0}".format(list(args))) 29 subprocess.check_call(list(args), **kwargs) 30 31 32def wait_for_build_completed(session): 33 # Wait 20 seconds before actually checking if the build is complete, to 34 # ensure that it had time to really start. 35 time.sleep(20) 36 while True: 37 response = session.get( 38 "{0}/lastBuild/api/json/".format(JENKINS_URL), 39 headers={ 40 "Accept": "application/json", 41 } 42 ) 43 response.raise_for_status() 44 if not response.json()["building"]: 45 assert response.json()["result"] == "SUCCESS" 46 break 47 time.sleep(0.1) 48 49 50def download_artifacts(session): 51 response = session.get( 52 "{0}/lastBuild/api/json/".format(JENKINS_URL), 53 headers={ 54 "Accept": "application/json" 55 } 56 ) 57 response.raise_for_status() 58 json_response = response.json() 59 assert not json_response["building"] 60 assert json_response["result"] == "SUCCESS" 61 62 paths = [] 63 64 for artifact in json_response["artifacts"]: 65 response = session.get( 66 "{0}artifact/{1}".format( 67 json_response["url"], artifact["relativePath"] 68 ), stream=True 69 ) 70 assert response.headers["content-length"] 71 print("Downloading {0}".format(artifact["fileName"])) 72 bar = ProgressBar( 73 expected_size=int(response.headers["content-length"]), 74 filled_char="=" 75 ) 76 content = io.BytesIO() 77 for data in response.iter_content(chunk_size=8192): 78 content.write(data) 79 bar.show(content.tell()) 80 assert bar.expected_size == content.tell() 81 bar.done() 82 out_path = os.path.join( 83 os.path.dirname(__file__), 84 "dist", 85 artifact["fileName"], 86 ) 87 with open(out_path, "wb") as f: 88 f.write(content.getvalue()) 89 paths.append(out_path) 90 return paths 91 92 93@click.command() 94@click.argument("version") 95def release(version): 96 """ 97 ``version`` should be a string like '0.4' or '1.0'. 98 """ 99 run("git", "tag", "-s", version, "-m", "{0} release".format(version)) 100 run("git", "push", "--tags") 101 102 run("python", "setup.py", "sdist") 103 run("python", "setup.py", "sdist", "bdist_wheel", cwd="vectors/") 104 105 packages = ( 106 glob.glob("dist/cryptography-{0}*".format(version)) + 107 glob.glob("vectors/dist/cryptography_vectors-{0}*".format(version)) 108 ) 109 run("twine", "upload", "-s", *packages) 110 111 session = requests.Session() 112 113 token = getpass.getpass("Input the Jenkins token: ") 114 response = session.get( 115 "{0}/buildWithParameters".format(JENKINS_URL), 116 params={ 117 "token": token, 118 "BUILD_VERSION": version, 119 "cause": "Building wheels for {0}".format(version) 120 } 121 ) 122 response.raise_for_status() 123 wait_for_build_completed(session) 124 paths = download_artifacts(session) 125 run("twine", "upload", *paths) 126 127 128if __name__ == "__main__": 129 release() 130