Skip to content

Commit f101599

Browse files
committed
Add version_fetch.py script
Add a script that allows for fetching the latest version of Scylla OSS, Scylla Enterprise and Cassandra 3.
1 parent 0c262f8 commit f101599

File tree

2 files changed

+209
-0
lines changed

2 files changed

+209
-0
lines changed

ci/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
requests

ci/version_fetch.py

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#!/usr/bin/python3
2+
3+
"""
4+
This Python script allows you to list the
5+
latest version numbers of Scylla and Cassandra.
6+
7+
You can specify whether you want the
8+
versions of Scylla OSS or Scylla Enterprise,
9+
either N latest stable X.Y.latest or
10+
all non-obsolete RCs. You can also fetch
11+
the latest version of Cassandra 3.
12+
13+
How are those versions fetched? We use Docker Hub
14+
tags API.
15+
"""
16+
17+
import requests
18+
import re
19+
import json
20+
from itertools import groupby, islice
21+
import sys
22+
23+
DOCKER_HUB_TAGS_ENDPOINT = 'https://registry.hub.docker.com/v1/repositories/%s/tags'
24+
DOCKER_HUB_SCYLLA_ORG = 'scylladb/'
25+
26+
SCYLLA_OSS = DOCKER_HUB_SCYLLA_ORG + 'scylla'
27+
SCYLLA_OSS_RELEASED_VERSION_REGEX = re.compile(r'(\d+)\.(\d+)\.(\d+)')
28+
SCYLLA_OSS_RC_VERSION_REGEX = re.compile(r'(\d+)\.(\d+)\.rc(\d+)')
29+
30+
SCYLLA_ENTERPRISE = DOCKER_HUB_SCYLLA_ORG + 'scylla-enterprise'
31+
SCYLLA_ENTERPRISE_RELEASED_VERSION_REGEX = re.compile(r'(\d{4})\.(\d+)\.(\d+)')
32+
SCYLLA_ENTERPRISE_RC_VERSION_REGEX = re.compile(r'(\d{4})\.(\d+)\.rc(\d+)')
33+
34+
CASSANDRA_ENDPOINT = 'https://dlcdn.apache.org/cassandra/'
35+
36+
CASSANDRA3_REGEX = re.compile(r'a href="(3)\.(\d+)\.(\d+)/"')
37+
38+
COMMAND_LINE_ARGUMENT = re.compile(
39+
r'((?:(scylla-oss-stable):(\d+))|(?:(scylla-enterprise-stable):(\d+))|(?:(cassandra3-stable):(\d+))|(?:(scylla-oss-rc))|(?:(scylla-enterprise-rc)))')
40+
41+
42+
def fetch_last_scylla_oss_minor_versions(count):
43+
# Download Docker tags for repository
44+
tags_data = requests.get(DOCKER_HUB_TAGS_ENDPOINT % (SCYLLA_OSS)).json()
45+
tags_data = map(lambda e: e['name'], tags_data)
46+
47+
# Parse only those tags which match 'NUM.NUM.NUM'
48+
# into tuple (NUM, NUM, NUM)
49+
tags_data = filter(SCYLLA_OSS_RELEASED_VERSION_REGEX.fullmatch, tags_data)
50+
tags_data = map(lambda e: SCYLLA_OSS_RELEASED_VERSION_REGEX.match(
51+
e).groups(), tags_data)
52+
tags_data = map(lambda e: tuple(map(int, e)), tags_data)
53+
54+
# Group by (major, minor) and select latest patch version
55+
tags_data = sorted(tags_data)
56+
tags_data = groupby(tags_data, key=lambda e: (e[0], e[1]))
57+
tags_data = ((e[0][0], e[0][1], max(e[1])[2])
58+
for e in tags_data)
59+
60+
# Return the latest ones
61+
tags_data = list(tags_data)[-count:]
62+
tags_data = [f'{e[0]}.{e[1]}.{e[2]}' for e in tags_data]
63+
return tags_data
64+
65+
66+
def fetch_all_scylla_oss_rc_versions():
67+
# Download Docker tags for repository
68+
tags_data = requests.get(DOCKER_HUB_TAGS_ENDPOINT % (SCYLLA_OSS)).json()
69+
tags_data = list(map(lambda e: e['name'], tags_data))
70+
71+
# Parse only those tags which match 'NUM.NUM.rcNUM'
72+
# into tuple (NUM, NUM, NUM)
73+
rc_tags_data = filter(SCYLLA_OSS_RC_VERSION_REGEX.fullmatch, tags_data)
74+
rc_tags_data = map(lambda e: SCYLLA_OSS_RC_VERSION_REGEX.match(
75+
e).groups(), rc_tags_data)
76+
rc_tags_data = map(lambda e: tuple(map(int, e)), rc_tags_data)
77+
78+
# Parse only those tags which match 'NUM.NUM.NUM'
79+
# into tuple (NUM, NUM)
80+
stable_tags_data = filter(
81+
SCYLLA_OSS_RELEASED_VERSION_REGEX.fullmatch, tags_data)
82+
stable_tags_data = map(lambda e: SCYLLA_OSS_RELEASED_VERSION_REGEX.match(
83+
e).groups(), stable_tags_data)
84+
stable_tags_data = map(lambda e: tuple(map(int, e[0:2])), stable_tags_data)
85+
stable_tags_data = set(stable_tags_data)
86+
87+
# Group by (major, minor) and select latest RC version
88+
rc_tags_data = sorted(rc_tags_data)
89+
rc_tags_data = groupby(rc_tags_data, key=lambda e: (e[0], e[1]))
90+
rc_tags_data = ((e[0][0], e[0][1], max(e[1])[2])
91+
for e in rc_tags_data)
92+
93+
# Filter out those RCs that are obsoleted by released stable version
94+
rc_tags_data = filter(lambda e: (
95+
e[0], e[1]) not in stable_tags_data, rc_tags_data)
96+
rc_tags_data = [f'{e[0]}.{e[1]}.rc{e[2]}' for e in rc_tags_data]
97+
return rc_tags_data
98+
99+
100+
def fetch_last_scylla_enterprise_minor_versions(count):
101+
# Download Docker tags for repository
102+
tags_data = requests.get(DOCKER_HUB_TAGS_ENDPOINT %
103+
(SCYLLA_ENTERPRISE)).json()
104+
tags_data = map(lambda e: e['name'], tags_data)
105+
106+
# Parse only those tags which match 'YEAR.NUM.NUM'
107+
# into tuple (YEAR, NUM, NUM)
108+
tags_data = filter(
109+
SCYLLA_ENTERPRISE_RELEASED_VERSION_REGEX.fullmatch, tags_data)
110+
tags_data = map(lambda e: SCYLLA_ENTERPRISE_RELEASED_VERSION_REGEX.match(
111+
e).groups(), tags_data)
112+
tags_data = map(lambda e: tuple(map(int, e)), tags_data)
113+
114+
# Group by (major, minor) and select latest patch version
115+
tags_data = sorted(tags_data)
116+
tags_data = groupby(tags_data, key=lambda e: (e[0], e[1]))
117+
tags_data = ((e[0][0], e[0][1], max(e[1])[2])
118+
for e in tags_data)
119+
120+
# Return the latest ones
121+
tags_data = list(tags_data)[-count:]
122+
tags_data = [f'{e[0]}.{e[1]}.{e[2]}' for e in tags_data]
123+
return tags_data
124+
125+
126+
def fetch_all_scylla_enterprise_rc_versions():
127+
# Download Docker tags for repository
128+
tags_data = requests.get(DOCKER_HUB_TAGS_ENDPOINT %
129+
(SCYLLA_ENTERPRISE)).json()
130+
tags_data = list(map(lambda e: e['name'], tags_data))
131+
132+
# Parse only those tags which match 'YEAR.NUM.rcNUM'
133+
# into tuple (YEAR, NUM, NUM)
134+
rc_tags_data = filter(
135+
SCYLLA_ENTERPRISE_RC_VERSION_REGEX.fullmatch, tags_data)
136+
rc_tags_data = map(lambda e: SCYLLA_ENTERPRISE_RC_VERSION_REGEX.match(
137+
e).groups(), rc_tags_data)
138+
rc_tags_data = map(lambda e: tuple(map(int, e)), rc_tags_data)
139+
140+
# Parse only those tags which match 'YEAR.NUM.NUM'
141+
# into tuple (YEAR, NUM)
142+
stable_tags_data = filter(
143+
SCYLLA_ENTERPRISE_RELEASED_VERSION_REGEX.fullmatch, tags_data)
144+
stable_tags_data = map(lambda e: SCYLLA_ENTERPRISE_RELEASED_VERSION_REGEX.match(
145+
e).groups(), stable_tags_data)
146+
stable_tags_data = map(lambda e: tuple(map(int, e[0:2])), stable_tags_data)
147+
148+
# Group by (major, minor) and select latest RC version
149+
rc_tags_data = sorted(rc_tags_data)
150+
rc_tags_data = groupby(rc_tags_data, key=lambda e: (e[0], e[1]))
151+
rc_tags_data = ((e[0][0], e[0][1], max(e[1])[2])
152+
for e in rc_tags_data)
153+
154+
# Filter out those RCs that are obsoleted by released stable version
155+
rc_tags_data = filter(lambda e: (
156+
e[0], e[1]) not in stable_tags_data, rc_tags_data)
157+
rc_tags_data = [f'{e[0]}.{e[1]}.rc{e[2]}' for e in rc_tags_data]
158+
return rc_tags_data
159+
160+
161+
def fetch_last_cassandra3_minor_versions(count):
162+
# Download folder listing for Cassandra download site
163+
data = requests.get(CASSANDRA_ENDPOINT).text
164+
165+
# Parse only those version numbers which match '3.NUM.NUM'
166+
# into tuple (3, NUM, NUM)
167+
data = CASSANDRA3_REGEX.finditer(data)
168+
data = map(lambda e: e.groups(), data)
169+
data = map(lambda e: tuple(map(int, e)), data)
170+
171+
# Group by (major, minor) and select latest patch version
172+
data = sorted(data)
173+
data = groupby(data, key=lambda e: (e[0], e[1]))
174+
data = ((e[0][0], e[0][1], max(e[1])[2])
175+
for e in data)
176+
177+
# Return the latest ones
178+
data = list(data)[-count:]
179+
data = [f'{e[0]}.{e[1]}.{e[2]}' for e in data]
180+
return data
181+
182+
183+
if __name__ == '__main__':
184+
names = set()
185+
186+
for arg in sys.argv[1:]:
187+
if not COMMAND_LINE_ARGUMENT.fullmatch(arg):
188+
print("Usage:", sys.argv[0], "[scylla-oss-stable:COUNT] [scylla-oss-rc] [scylla-enterprise-stable:COUNT] [scylla-enterprise-rc] [cassandra3-stable:COUNT]...", file=sys.stderr)
189+
sys.exit(1)
190+
191+
groups = COMMAND_LINE_ARGUMENT.match(arg).groups()
192+
groups = [g for g in groups if g][1:]
193+
194+
mode_name = groups[0]
195+
if mode_name == 'scylla-oss-stable':
196+
names.update(fetch_last_scylla_oss_minor_versions(int(groups[1])))
197+
elif mode_name == 'scylla-enterprise-stable':
198+
names.update(
199+
fetch_last_scylla_enterprise_minor_versions(int(groups[1])))
200+
elif mode_name == 'cassandra3-stable':
201+
names.update(
202+
fetch_last_cassandra3_minor_versions(int(groups[1])))
203+
elif mode_name == 'scylla-oss-rc':
204+
names.update(fetch_all_scylla_oss_rc_versions())
205+
elif mode_name == 'scylla-enterprise-rc':
206+
names.update(fetch_all_scylla_enterprise_rc_versions())
207+
208+
print(json.dumps(list(names)))

0 commit comments

Comments
 (0)