1
|
|
|
#!/usr/bin/env python |
2
|
|
|
""" |
3
|
|
|
Use the AppVeyor API to download Windows artifacts. |
4
|
|
|
|
5
|
|
|
Taken from: https://bitbucket.org/ned/coveragepy/src/tip/ci/download_appveyor.py |
6
|
|
|
# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
7
|
|
|
# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt |
8
|
|
|
""" |
9
|
|
|
from __future__ import unicode_literals |
10
|
|
|
|
11
|
|
|
import argparse |
12
|
|
|
import os |
13
|
|
|
import zipfile |
14
|
|
|
|
15
|
|
|
import requests |
16
|
|
|
|
17
|
|
|
|
18
|
|
|
def make_auth_headers(): |
19
|
|
|
"""Make the authentication headers needed to use the Appveyor API.""" |
20
|
|
|
path = os.path.expanduser("~/.appveyor.token") |
21
|
|
|
if not os.path.exists(path): |
22
|
|
|
raise RuntimeError( |
23
|
|
|
"Please create a file named `.appveyor.token` in your home directory. " |
24
|
|
|
"You can get the token from https://ci.appveyor.com/api-token" |
25
|
|
|
) |
26
|
|
|
with open(path) as f: |
27
|
|
|
token = f.read().strip() |
28
|
|
|
|
29
|
|
|
headers = { |
30
|
|
|
'Authorization': 'Bearer {}'.format(token), |
31
|
|
|
} |
32
|
|
|
return headers |
33
|
|
|
|
34
|
|
|
|
35
|
|
|
def download_latest_artifacts(account_project, build_id): |
36
|
|
|
"""Download all the artifacts from the latest build.""" |
37
|
|
|
if build_id is None: |
38
|
|
|
url = "https://ci.appveyor.com/api/projects/{}".format(account_project) |
39
|
|
|
else: |
40
|
|
|
url = "https://ci.appveyor.com/api/projects/{}/build/{}".format(account_project, build_id) |
41
|
|
|
build = requests.get(url, headers=make_auth_headers()).json() |
42
|
|
|
jobs = build['build']['jobs'] |
43
|
|
|
print(u"Build {0[build][version]}, {1} jobs: {0[build][message]}".format(build, len(jobs))) |
44
|
|
|
|
45
|
|
|
for job in jobs: |
46
|
|
|
name = job['name'] |
47
|
|
|
print(u" {0}: {1[status]}, {1[artifactsCount]} artifacts".format(name, job)) |
48
|
|
|
|
49
|
|
|
url = "https://ci.appveyor.com/api/buildjobs/{}/artifacts".format(job['jobId']) |
50
|
|
|
response = requests.get(url, headers=make_auth_headers()) |
51
|
|
|
artifacts = response.json() |
52
|
|
|
|
53
|
|
|
for artifact in artifacts: |
54
|
|
|
is_zip = artifact['type'] == "Zip" |
55
|
|
|
filename = artifact['fileName'] |
56
|
|
|
print(u" {0}, {1} bytes".format(filename, artifact['size'])) |
57
|
|
|
|
58
|
|
|
url = "https://ci.appveyor.com/api/buildjobs/{}/artifacts/{}".format(job['jobId'], filename) |
59
|
|
|
download_url(url, filename, make_auth_headers()) |
60
|
|
|
|
61
|
|
|
if is_zip: |
62
|
|
|
unpack_zipfile(filename) |
63
|
|
|
os.remove(filename) |
64
|
|
|
|
65
|
|
|
|
66
|
|
|
def ensure_dirs(filename): |
67
|
|
|
"""Make sure the directories exist for `filename`.""" |
68
|
|
|
dirname = os.path.dirname(filename) |
69
|
|
|
if dirname and not os.path.exists(dirname): |
70
|
|
|
os.makedirs(dirname) |
71
|
|
|
|
72
|
|
|
|
73
|
|
|
def download_url(url, filename, headers): |
74
|
|
|
"""Download a file from `url` to `filename`.""" |
75
|
|
|
ensure_dirs(filename) |
76
|
|
|
response = requests.get(url, headers=headers, stream=True) |
77
|
|
|
if response.status_code == 200: |
78
|
|
|
with open(filename, 'wb') as f: |
79
|
|
|
for chunk in response.iter_content(16 * 1024): |
80
|
|
|
f.write(chunk) |
81
|
|
|
else: |
82
|
|
|
print(u" Error downloading {}: {}".format(url, response)) |
83
|
|
|
|
84
|
|
|
|
85
|
|
|
def unpack_zipfile(filename): |
86
|
|
|
"""Unpack a zipfile, using the names in the zip.""" |
87
|
|
|
with open(filename, 'rb') as fzip: |
88
|
|
|
z = zipfile.ZipFile(fzip) |
89
|
|
|
for name in z.namelist(): |
90
|
|
|
print(u" extracting {}".format(name)) |
91
|
|
|
ensure_dirs(name) |
92
|
|
|
z.extract(name) |
93
|
|
|
|
94
|
|
|
|
95
|
|
|
parser = argparse.ArgumentParser(description='Download artifacts from AppVeyor.') |
96
|
|
|
parser.add_argument('--id', |
97
|
|
|
metavar='PROJECT_ID', |
98
|
|
|
default='ionelmc/python-tblib', |
99
|
|
|
help='Project ID in AppVeyor.') |
100
|
|
|
parser.add_argument('build', |
101
|
|
|
nargs='?', |
102
|
|
|
metavar='BUILD_ID', |
103
|
|
|
help='Build ID in AppVeyor. Eg: master-123') |
104
|
|
|
|
105
|
|
|
if __name__ == "__main__": |
106
|
|
|
# import logging |
107
|
|
|
# logging.basicConfig(level="DEBUG") |
108
|
|
|
args = parser.parse_args() |
109
|
|
|
download_latest_artifacts(args.id, args.build) |
110
|
|
|
|