|
2 | 2 | # 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
3 | 3 | # for complete details.
|
4 | 4 |
|
5 |
| -import getpass |
6 |
| -import io |
7 |
| -import os |
8 | 5 | import subprocess
|
9 |
| -import time |
10 |
| -import typing |
11 |
| -import zipfile |
12 | 6 |
|
13 | 7 | import click
|
14 |
| -import requests |
15 | 8 |
|
16 | 9 |
|
17 | 10 | def run(*args: str) -> None:
|
18 | 11 | print(f"[running] {list(args)}")
|
19 | 12 | subprocess.check_call(list(args))
|
20 | 13 |
|
21 | 14 |
|
22 |
| -def wait_for_build_complete_github_actions( |
23 |
| - session: requests.Session, token: str, run_url: str |
24 |
| -) -> None: |
25 |
| - while True: |
26 |
| - response = session.get( |
27 |
| - run_url, |
28 |
| - headers={ |
29 |
| - "Content-Type": "application/json", |
30 |
| - "Authorization": f"token {token}", |
31 |
| - }, |
32 |
| - ) |
33 |
| - response.raise_for_status() |
34 |
| - if response.json()["conclusion"] is not None: |
35 |
| - break |
36 |
| - time.sleep(3) |
37 |
| - |
38 |
| - |
39 |
| -def download_artifacts_github_actions( |
40 |
| - session: requests.Session, token: str, run_url: str |
41 |
| -) -> typing.List[str]: |
42 |
| - response = session.get( |
43 |
| - run_url, |
44 |
| - headers={ |
45 |
| - "Content-Type": "application/json", |
46 |
| - "Authorization": f"token {token}", |
47 |
| - }, |
48 |
| - ) |
49 |
| - response.raise_for_status() |
50 |
| - |
51 |
| - response = session.get( |
52 |
| - response.json()["artifacts_url"], |
53 |
| - headers={ |
54 |
| - "Content-Type": "application/json", |
55 |
| - "Authorization": f"token {token}", |
56 |
| - }, |
57 |
| - ) |
58 |
| - response.raise_for_status() |
59 |
| - paths = [] |
60 |
| - for artifact in response.json()["artifacts"]: |
61 |
| - response = session.get( |
62 |
| - artifact["archive_download_url"], |
63 |
| - headers={ |
64 |
| - "Content-Type": "application/json", |
65 |
| - "Authorization": f"token {token}", |
66 |
| - }, |
67 |
| - ) |
68 |
| - with zipfile.ZipFile(io.BytesIO(response.content)) as z: |
69 |
| - for name in z.namelist(): |
70 |
| - if not name.endswith(".whl") and not name.endswith(".tar.gz"): |
71 |
| - continue |
72 |
| - p = z.open(name) |
73 |
| - out_path = os.path.join( |
74 |
| - os.path.dirname(__file__), |
75 |
| - "dist", |
76 |
| - os.path.basename(name), |
77 |
| - ) |
78 |
| - with open(out_path, "wb") as f: |
79 |
| - f.write(p.read()) |
80 |
| - paths.append(out_path) |
81 |
| - return paths |
82 |
| - |
83 |
| - |
84 |
| -def fetch_github_actions_artifacts( |
85 |
| - token: str, version: str |
86 |
| -) -> typing.List[str]: |
87 |
| - session = requests.Session() |
88 |
| - |
89 |
| - workflow_runs = [] |
90 |
| - |
91 |
| - # There is a race condition where no workflow run has triggered after |
92 |
| - # pushing the tag, so loop until we get the run. |
93 |
| - while True: |
94 |
| - response = session.get( |
95 |
| - ( |
96 |
| - f"https://api.github.com/repos/pyca/cryptography/actions" |
97 |
| - f"/workflows/wheel-builder.yml/runs?event=push&" |
98 |
| - f"branch={version}" |
99 |
| - ), |
100 |
| - headers={ |
101 |
| - "Content-Type": "application/json", |
102 |
| - "Authorization": f"token {token}", |
103 |
| - }, |
104 |
| - ) |
105 |
| - response.raise_for_status() |
106 |
| - workflow_runs = response.json()["workflow_runs"] |
107 |
| - if len(workflow_runs) > 0: |
108 |
| - break |
109 |
| - time.sleep(3) |
110 |
| - |
111 |
| - run_url: str = workflow_runs[0]["url"] |
112 |
| - wait_for_build_complete_github_actions(session, token, run_url) |
113 |
| - return download_artifacts_github_actions(session, token, run_url) |
114 |
| - |
115 |
| - |
116 | 15 | @click.command()
|
117 | 16 | @click.argument("version")
|
118 | 17 | def release(version: str) -> None:
|
119 | 18 | """
|
120 | 19 | ``version`` should be a string like '0.4' or '1.0'.
|
121 | 20 | """
|
122 |
| - print( |
123 |
| - f"Create a new GH PAT with only actions permissions at: " |
124 |
| - f"https://github.com/settings/tokens/new?" |
125 |
| - f"description={version}&scopes=repo" |
126 |
| - ) |
127 |
| - github_token = getpass.getpass("Github person access token: ") |
128 |
| - |
129 | 21 | # Tag and push the tag (this will trigger the wheel builder in Actions)
|
130 | 22 | run("git", "tag", "-s", version, "-m", f"{version} release")
|
131 | 23 | run("git", "push", "--tags")
|
132 | 24 |
|
133 |
| - os.makedirs(os.path.join(os.path.dirname(__file__), "dist"), exist_ok=True) |
134 |
| - |
135 |
| - # Wait for Actions to complete and download the wheels |
136 |
| - github_actions_artifact_paths = fetch_github_actions_artifacts( |
137 |
| - github_token, version |
138 |
| - ) |
139 |
| - |
140 |
| - # Upload wheels and sdist |
141 |
| - run("twine", "upload", *github_actions_artifact_paths) |
142 |
| - |
143 | 25 |
|
144 | 26 | if __name__ == "__main__":
|
145 | 27 | release()
|
0 commit comments