Skip to content

Commit 79bb141

Browse files
Add script to download an artifact from a GitHub Action workflow run.
1 parent a7edc79 commit 79bb141

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/bin/env python3
2+
"""
3+
This script downloads an artifact from a GitHub Action workflow run,
4+
unzips and and stores the files in a directory of your choice.
5+
6+
Use cases:
7+
* You want to locally test or inspect the generated artifact.
8+
* You want to upload the artifact to a remote repository (test.pypi.org for example)
9+
before a release.
10+
"""
11+
import io
12+
import os
13+
import sys
14+
import json
15+
import time
16+
import zipfile
17+
import argparse
18+
19+
import urllib.request
20+
21+
parser = argparse.ArgumentParser(
22+
description="Download an artifact from a GitHub Action workflow run."
23+
)
24+
parser.add_argument("sha", help="Commit hash")
25+
parser.add_argument("token", help="GitHub Personal Access Token.")
26+
parser.add_argument(
27+
"-w",
28+
"--workflow",
29+
default="OpenTimelineIO",
30+
help="Name of the workflow to download artifact from.",
31+
)
32+
parser.add_argument(
33+
"-a", "--artifact", default="wheels", help="Artifact name to download."
34+
)
35+
parser.add_argument(
36+
"-d", "--directory", default="dist", help="Directory where to write the artifact."
37+
)
38+
39+
args = parser.parse_args()
40+
41+
headers = {
42+
"Accept": "application/vnd.github.v3+json",
43+
"Authorization": "token {args.token}".format(args=args),
44+
}
45+
46+
if os.path.exists(args.directory) and os.listdir(args.directory):
47+
sys.stderr.write(
48+
"{0!r} directory contains files. It should be empty.".format(args.directory)
49+
)
50+
sys.exit(1)
51+
52+
if not os.path.exists(args.directory):
53+
os.makedirs(args.directory)
54+
55+
request = urllib.request.Request(
56+
"https://api.github.com/repos/JeanChristopheMorinPerso/OpenTimelineIO/actions/runs?status=success", # noqa: E501
57+
headers=headers,
58+
)
59+
response = urllib.request.urlopen(request).read()
60+
workflow_runs = json.loads(response)["workflow_runs"]
61+
for run in workflow_runs:
62+
if run["head_sha"] == args.sha and run["name"] == args.workflow:
63+
workflow_run = run
64+
break
65+
else:
66+
sys.stderr.write(
67+
"No run for a workflow named {0!r} found for commit {1!r}.".format(
68+
args.workflow, args.sha
69+
)
70+
)
71+
sys.exit(1)
72+
73+
74+
print("Found workflow:")
75+
print(" Name: {0}".format(workflow_run["name"]))
76+
print(" Branch: {0}".format(workflow_run["head_branch"]))
77+
print(" Commit: {0}".format(workflow_run["head_sha"]))
78+
print(" Committer: {0}".format(workflow_run["head_commit"]["committer"]))
79+
print(" Run Number: {0}".format(workflow_run["run_number"]))
80+
print(" Status: {0}".format(workflow_run["status"]))
81+
print(" Conclusion: {0}".format(workflow_run["conclusion"]))
82+
print(" URL: {0}".format(workflow_run["html_url"]))
83+
84+
85+
print("Getting list of artifacts")
86+
request = urllib.request.Request(workflow_run["artifacts_url"], headers=headers)
87+
response = urllib.request.urlopen(request).read()
88+
artifacts = json.loads(response)["artifacts"]
89+
for artifact in artifacts:
90+
if artifact["name"] == args.artifact:
91+
artifact_download_url = artifact["archive_download_url"]
92+
break
93+
else:
94+
sys.stderr.write("No artifact named {0!r} found.".format(args.artifact))
95+
sys.exit(1)
96+
97+
print(
98+
"Downloading {0!r} artifact and unzipping to {1!r}".format(
99+
args.artifact, args.directory
100+
)
101+
)
102+
103+
request = urllib.request.Request(artifact_download_url, headers=headers)
104+
file_content = urllib.request.urlopen(request).read()
105+
106+
zip_file = zipfile.ZipFile(io.BytesIO(file_content))
107+
for zip_info in zip_file.infolist():
108+
output_path = os.path.join(args.directory, zip_info.filename)
109+
110+
print("Writing {0!r} to {1!r}".format(zip_info.filename, output_path))
111+
with open(output_path, "wb") as fd:
112+
fd.write(zip_file.open(zip_info).read())
113+
114+
# Keep the timestamp!
115+
date_time = time.mktime(zip_info.date_time + (0, 0, -1))
116+
os.utime(output_path, (date_time, date_time))

0 commit comments

Comments
 (0)