Skip to content

Commit e42ab6a

Browse files
authored
currency: added new columns to currency report table (#447)
Signed-off-by: Cagri Yonca <cagri@ibm.com>
1 parent 370982f commit e42ab6a

File tree

1 file changed

+194
-22
lines changed

1 file changed

+194
-22
lines changed

.tekton/.currency/scripts/generate_report.py

Lines changed: 194 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import glob
33
import re
44
from json import load
5+
from datetime import datetime
56

67
# Third Party
78
from requests import get
@@ -11,9 +12,10 @@
1112
JSON_FILE = "resources/table.json"
1213
REPORT_FILE = "docs/report.md"
1314
API_V1_ENDPOINT = "https://rubygems.org/api/v1/versions/"
15+
GEM_INFO_ENDPOINT = "https://rubygems.org/api/v1/gems/"
1416

15-
def get_bundle_install_output():
1617

18+
def get_bundle_install_output():
1719
libraries_from_logs = {
1820
"cuba": "cuba_40_ruby_3.3.",
1921
"excon": "excon_100_ruby_3.3.",
@@ -28,22 +30,23 @@ def get_bundle_install_output():
2830
"dalli": "dalli_32_ruby_3.3.",
2931
"resque": "resque_20_ruby_3.3.",
3032
"sidekiq": "sidekiq_70_ruby_3.3.",
31-
"sequel": "sequel_58_ruby_3.3."
33+
"sequel": "sequel_58_ruby_3.3.",
3234
}
3335

3436
bundle_install_output = ""
3537

3638
for library, pattern in libraries_from_logs.items():
3739
glob_result = glob.glob(f"../../dep_{pattern}*")
40+
3841
if not glob_result:
3942
print(f"Could not find bundle install log for gem '{library}'.")
4043
continue
4144

42-
with open(glob_result[0], 'r') as file:
43-
logs = file.read().replace('\n', ' ')
45+
with open(glob_result[0], "r") as file:
46+
logs = file.read().replace("\n", " ")
4447

4548
if "Installing" not in logs:
46-
print( f"Unable to retrieve logs from for gem '{library}'.")
49+
print(f"Unable to retrieve logs from for gem '{library}'.")
4750
continue
4851

4952
print(f"Retrieving currency for gem '{library}'.")
@@ -53,27 +56,176 @@ def get_bundle_install_output():
5356
return bundle_install_output
5457

5558

59+
def estimate_days_behind(release_date, last_supported_release_date):
60+
"""Calculate days between release dates"""
61+
latest_date = datetime.strptime(release_date, "%Y-%m-%d")
62+
supported_date = datetime.strptime(last_supported_release_date, "%Y-%m-%d")
63+
days_diff = (latest_date - supported_date).days
64+
return max(0, days_diff)
65+
66+
5667
def get_upstream_version(dependency):
57-
"""get the latest version available upstream"""
68+
"""get the latest version available upstream and release date"""
5869
if dependency != "rails lts":
59-
response = get(f"{API_V1_ENDPOINT}/{dependency}/latest.json")
60-
response_json = response.json()
61-
latest_version = response_json["version"]
70+
try:
71+
response = get(f"{API_V1_ENDPOINT}{dependency}/latest.json")
72+
if not response:
73+
return "Unknown", "Unknown"
74+
75+
response_json = response.json()
76+
latest_version = response_json["version"]
77+
78+
gem_info_response = get(f"{GEM_INFO_ENDPOINT}{dependency}.json")
79+
if not gem_info_response:
80+
return latest_version, "Unknown"
81+
gem_info = gem_info_response.json()
82+
83+
version_info_response = get(f"{API_V1_ENDPOINT}{dependency}.json")
84+
if not version_info_response:
85+
return latest_version, "Unknown"
86+
version_info = version_info_response.json()
87+
88+
latest_version_release_date = None
89+
for version_data in version_info:
90+
if version_data["number"] == latest_version:
91+
if "created_at" in version_data:
92+
created_at = version_data["created_at"]
93+
latest_version_release_date = datetime.strptime(
94+
created_at, "%Y-%m-%dT%H:%M:%S.%fZ"
95+
).strftime("%Y-%m-%d")
96+
break
97+
98+
if not latest_version_release_date and "created_at" in gem_info:
99+
created_at = gem_info["created_at"]
100+
latest_version_release_date = datetime.strptime(
101+
created_at, "%Y-%m-%dT%H:%M:%S.%fZ"
102+
).strftime("%Y-%m-%d")
103+
104+
if not latest_version_release_date:
105+
latest_version_release_date = "Unknown"
106+
print(f"Could not find release date for {dependency}")
107+
108+
return latest_version, latest_version_release_date
109+
except Exception as e:
110+
return "Unknown", "Unknown"
62111
else:
63-
url = "https://makandracards.com/railslts/16137-installing-rails-lts/read"
64-
page = get(url)
65-
soup = BeautifulSoup(page.text, "html.parser")
66-
text = soup.findAll("li")[-1].text
67-
pattern = "(\d+\.\d+\.?\d*)"
68-
latest_version = re.search(pattern, text)[1]
69-
return latest_version
112+
try:
113+
initial_response = get(
114+
"https://makandracards.com/railslts/16137-installing-rails-lts/read"
115+
)
116+
if not initial_response:
117+
return "Unknown", "Unknown"
118+
119+
initial_soup = BeautifulSoup(initial_response.text, "html.parser")
120+
121+
text = initial_soup.find_all("li")[-1].text
122+
pattern = "(\d+\.\d+\.?\d*)"
123+
latest_version_match = re.search(pattern, text)
124+
125+
latest_version = "Unknown"
126+
if latest_version_match:
127+
latest_version = latest_version_match[1]
128+
rails_lts_links = initial_soup.find_all("a", href=re.compile(r"railslts"))
129+
latest_rails_lts_link = None
130+
latest_version_num = 0.0
131+
132+
for link in rails_lts_links:
133+
href = link.get("href", "")
134+
link_text = link.text.strip()
135+
136+
if "Installing Rails" in link_text:
137+
version_match = re.search(r"Installing Rails (\d+\.\d+)", link_text)
138+
if version_match:
139+
version_str = version_match.group(1)
140+
try:
141+
version_num = float(version_str)
142+
if version_num > latest_version_num:
143+
latest_version_num = version_num
144+
latest_rails_lts_link = href
145+
latest_version = version_str
146+
except ValueError:
147+
pass
148+
149+
latest_version_release_date = None
150+
151+
if latest_rails_lts_link:
152+
if latest_rails_lts_link.startswith("/"):
153+
full_url = f"https://makandracards.com{latest_rails_lts_link}"
154+
else:
155+
full_url = latest_rails_lts_link
156+
157+
detail_response = get(full_url)
158+
if detail_response:
159+
detail_soup = BeautifulSoup(detail_response.text, "html.parser")
160+
161+
time_tags = detail_soup.find_all(
162+
"time", attrs={"data-relative": "true"}
163+
)
164+
for time_tag in time_tags:
165+
if "Updated" in time_tag.parent.text:
166+
if "datetime" in time_tag.attrs:
167+
datetime_str = time_tag["datetime"]
168+
try:
169+
date_obj = datetime.strptime(
170+
datetime_str, "%Y-%m-%dT%H:%M:%SZ"
171+
)
172+
latest_version_release_date = date_obj.strftime(
173+
"%Y-%m-%d"
174+
)
175+
break
176+
except ValueError:
177+
try:
178+
date_obj = datetime.strptime(
179+
datetime_str, "%Y-%m-%dT%H:%M:%S.%fZ"
180+
)
181+
latest_version_release_date = date_obj.strftime(
182+
"%Y-%m-%d"
183+
)
184+
break
185+
except ValueError as e:
186+
print(f"Error parsing datetime: {e}")
187+
188+
if not latest_version_release_date:
189+
latest_version_release_date = datetime.now().strftime("%Y-%m-%d")
190+
return latest_version, latest_version_release_date
191+
192+
except Exception as e:
193+
print(f"Error getting Rails LTS information: {str(e)}")
194+
return "Unknown", datetime.now().strftime("%Y-%m-%d")
195+
196+
197+
def get_version_release_date(dependency, version):
198+
if dependency == "rails lts":
199+
_, release_date = get_upstream_version(dependency)
200+
return release_date
201+
202+
try:
203+
response = get(f"{API_V1_ENDPOINT}/{dependency}.json")
204+
if not response:
205+
print(f"Failed to get version info for {dependency}")
206+
return "Unknown"
207+
208+
version_info = response.json()
209+
for version_data in version_info:
210+
if version_data["number"] == version and "created_at" in version_data:
211+
created_at = version_data["created_at"]
212+
release_date = datetime.strptime(
213+
created_at, "%Y-%m-%dT%H:%M:%S.%fZ"
214+
).strftime("%Y-%m-%d")
215+
return release_date
216+
except Exception as e:
217+
print(f"Error getting release date for {dependency} {version}: {str(e)}")
218+
219+
return "Unknown"
70220

71221

72222
def get_last_supported_version(bundle_install_output, dependency):
73223
"""get up-to-date supported version"""
74224
pattern = r" ([^\s]+)"
75225

76-
last_supported_version = re.search(dependency + pattern, bundle_install_output, flags=re.I | re.M)
226+
last_supported_version = re.search(
227+
dependency + pattern, bundle_install_output, flags=re.I | re.M
228+
)
77229

78230
return last_supported_version[1]
79231

@@ -86,6 +238,7 @@ def isUptodate(last_supported_version, latest_version):
86238

87239
return up_to_date
88240

241+
89242
def main():
90243
# Read the JSON file
91244
with open(JSON_FILE) as file:
@@ -99,23 +252,41 @@ def main():
99252
package = item["Package name"]
100253
package = package.lower().replace("::", "-")
101254

102-
latest_version = get_upstream_version(package)
103-
104-
if not package in ["rails lts", "rails-api"]:
105-
last_supported_version = get_last_supported_version(bundle_install_output, package)
255+
latest_version, release_date = get_upstream_version(package)
256+
if package not in ["rails lts", "rails-api"]:
257+
last_supported_version = get_last_supported_version(
258+
bundle_install_output, package
259+
)
106260
else:
107261
last_supported_version = latest_version
108262

263+
last_supported_version_release_date = get_version_release_date(
264+
package, last_supported_version
265+
)
266+
109267
up_to_date = isUptodate(last_supported_version, latest_version)
110268

269+
days_behind = "0 day/s"
270+
if (
271+
up_to_date == "No"
272+
and release_date != "Unknown"
273+
and last_supported_version_release_date != "Unknown"
274+
):
275+
days = estimate_days_behind(
276+
release_date, last_supported_version_release_date
277+
)
278+
days_behind = f"{days} day/s"
279+
111280
item.update(
112281
{
113282
"Last Supported Version": last_supported_version,
114283
"Latest version": latest_version,
115284
"Up-to-date": up_to_date,
285+
"Release date": release_date,
286+
"Latest Version Published At": last_supported_version_release_date,
287+
"Days behind": days_behind,
116288
},
117289
)
118-
119290
# Create a DataFrame from the list of dictionaries
120291
df = DataFrame(items)
121292
df.insert(len(df.columns) - 1, "Cloud Native", df.pop("Cloud Native"))
@@ -132,5 +303,6 @@ def main():
132303
with open(REPORT_FILE, "w") as file:
133304
file.write(final_markdown)
134305

306+
135307
if __name__ == "__main__":
136308
main()

0 commit comments

Comments
 (0)