Skip to content

Commit 088148a

Browse files
committed
currency: added release date and days behind support
Signed-off-by: Cagri Yonca <[email protected]>
1 parent ba7efff commit 088148a

File tree

2 files changed

+126
-49
lines changed

2 files changed

+126
-49
lines changed

.tekton/.currency/docs/report.md

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
##### This page is auto-generated. Any change will be overwritten after the next sync. Please apply changes directly to the files in the [python tracer](https://github.com/instana/python-sensor) repo.
22
## Python supported packages and versions
3-
| Package name | Support Policy | Beta version | Last Supported Version | Latest version | Up-to-date | Cloud Native |
4-
|:---------------------|:-----------------|:---------------|:-------------------------|:-----------------|:-------------|:---------------|
5-
| ASGI | 45-days | No | 3.0 | 3.0 | Yes | No |
6-
| Celery | 45-days | No | 5.4.0 | 5.4.0 | Yes | No |
7-
| Django | 45-days | No | 5.1.1 | 5.1.1 | Yes | No |
8-
| FastAPI | 45-days | No | 0.115.0 | 0.115.0 | Yes | No |
9-
| Flask | 45-days | No | 3.0.3 | 3.0.3 | Yes | No |
10-
| Pyramid | 45-days | No | 2.0.2 | 2.0.2 | Yes | No |
11-
| Sanic | On demand | No | 24.6.0 | 24.6.0 | Yes | No |
12-
| Starlette | 45-days | No | 0.38.6 | 0.39.2 | No | No |
13-
| Tornado | 45-days | No | 6.4.1 | 6.4.1 | Yes | No |
14-
| Webapp2 | On demand | No | 2.5.2 | 2.5.2 | Yes | No |
15-
| WSGI | 0-day | Yes | 1.0.1 | 1.0.1 | Yes | No |
16-
| Aiohttp | 45-days | No | 3.10.8 | 3.10.8 | Yes | No |
17-
| Asynqp | Deprecated | No | 0.6 | 0.6 | Yes | No |
18-
| Boto3 | 45-days | No | 1.35.33 | 1.35.33 | Yes | Yes |
19-
| Google-cloud-pubsub | 45-days | No | 2.25.2 | 2.25.2 | Yes | Yes |
20-
| Google-cloud-storage | 45-days | No | 2.18.2 | 2.18.2 | Yes | Yes |
21-
| Grpcio | 45-days | No | 1.66.2 | 1.66.2 | Yes | Yes |
22-
| Mysqlclient | 45-days | No | 2.2.4 | 2.2.4 | Yes | Yes |
23-
| Pika | 45-days | No | 1.3.2 | 1.3.2 | Yes | No |
24-
| PyMySQL | 45-days | No | 1.1.1 | 1.1.1 | Yes | Yes |
25-
| Pymongo | 45-days | No | 4.10.1 | 4.10.1 | Yes | Yes |
26-
| Psycopg2 | 45-days | No | 2.9.9 | 2.9.9 | Yes | No |
27-
| Redis | 45-days | No | 5.1.1 | 5.1.1 | Yes | Yes |
28-
| Requests | 45-days | No | 2.32.3 | 2.32.3 | Yes | Yes |
29-
| SQLAlchemy | 45-days | No | 2.0.35 | 2.0.35 | Yes | Yes |
30-
| Urllib3 | 45-days | No | 2.2.3 | 2.2.3 | Yes | No |
3+
| Package name | Support Policy | Beta version | Last Supported Version | Latest version | Up-to-date | Release date | Latest Version Published At | Days behind | Cloud Native |
4+
|:---------------------|:-----------------|:---------------|:-------------------------|:-----------------|:-------------|:---------------|:------------------------------|:--------------|:---------------|
5+
| ASGI | 45-days | No | 3.0 | 3.0 | Yes | 2019-03-04 | 2019-03-04 | 0 day/s | No |
6+
| Celery | 45-days | No | 5.4.0 | 5.4.0 | Yes | 2024-04-17 | 2024-04-17 | 0 day/s | No |
7+
| Django | 45-days | No | 5.1.6 | 5.1.6 | Yes | 2025-02-05 | 2025-02-05 | 0 day/s | No |
8+
| FastAPI | 45-days | No | 0.115.11 | 0.115.11 | Yes | 2025-03-01 | 2025-03-01 | 0 day/s | No |
9+
| Flask | 45-days | No | 3.1.0 | 3.1.0 | Yes | 2024-11-13 | 2024-11-13 | 0 day/s | No |
10+
| Pyramid | 45-days | No | 2.0.2 | 2.0.2 | Yes | 2023-08-25 | 2023-08-25 | 0 day/s | No |
11+
| Sanic | On demand | No | 24.12.0 | 24.12.0 | Yes | 2024-12-31 | 2024-12-31 | 0 day/s | No |
12+
| Starlette | 45-days | No | 0.46.0 | 0.46.0 | Yes | 2025-02-22 | 2025-02-22 | 0 day/s | No |
13+
| Tornado | 45-days | No | 6.4.2 | 6.4.2 | Yes | 2024-11-22 | 2024-11-22 | 0 day/s | No |
14+
| Webapp2 | On demand | No | 2.5.2 | 2.5.2 | Yes | 2012-09-28 | 2012-09-28 | 0 day/s | No |
15+
| WSGI | 0-day | Yes | 1.0.1 | 1.0.1 | Yes | 2010-09-26 | 2010-09-26 | 0 day/s | No |
16+
| Aiohttp | 45-days | No | 3.11.13 | 3.11.13 | Yes | 2025-02-24 | 2025-02-24 | 0 day/s | No |
17+
| Asynqp | Deprecated | No | 0.6 | 0.6 | Yes | 2019-01-20 | 2019-01-20 | 0 day/s | No |
18+
| Boto3 | 45-days | No | 1.37.5 | 1.37.5 | Yes | 2025-03-03 | 2025-03-03 | 0 day/s | Yes |
19+
| Google-cloud-pubsub | 45-days | No | 2.28.0 | 2.28.0 | Yes | 2025-01-30 | 2025-01-30 | 0 day/s | Yes |
20+
| Google-cloud-storage | 45-days | No | 3.1.0 | 3.1.0 | Yes | 2025-02-28 | 2025-02-28 | 0 day/s | Yes |
21+
| Grpcio | 45-days | No | 1.71.0rc2 | 1.70.0 | Yes | 2025-01-23 | 2025-02-24 | 0 day/s | Yes |
22+
| Mysqlclient | 45-days | No | 2.2.7 | 2.2.7 | Yes | 2025-01-10 | 2025-01-10 | 0 day/s | Yes |
23+
| Pika | 45-days | No | 1.3.2 | 1.3.2 | Yes | 2023-05-05 | 2023-05-05 | 0 day/s | No |
24+
| PyMySQL | 45-days | No | 1.1.1 | 1.1.1 | Yes | 2024-05-21 | 2024-05-21 | 0 day/s | Yes |
25+
| Pymongo | 45-days | No | 4.11.2 | 4.11.2 | Yes | 2025-03-03 | 2025-03-03 | 0 day/s | Yes |
26+
| Psycopg2 | 45-days | No | 2.9.10 | 2.9.10 | Yes | 2024-10-16 | 2024-10-16 | 0 day/s | No |
27+
| Redis | 45-days | No | 5.2.1 | 5.2.1 | Yes | 2024-12-06 | 2024-12-06 | 0 day/s | Yes |
28+
| Requests | 45-days | No | 2.32.3 | 2.32.3 | Yes | 2024-05-29 | 2024-05-29 | 0 day/s | Yes |
29+
| SQLAlchemy | 45-days | No | 2.0.38 | 2.0.38 | Yes | 2025-02-06 | 2025-02-06 | 0 day/s | Yes |
30+
| Urllib3 | 45-days | No | 2.3.0 | 2.3.0 | Yes | 2024-12-22 | 2024-12-22 | 0 day/s | No |

.tekton/.currency/scripts/generate_report.py

Lines changed: 98 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Standard Libraries
22
import json
33
import re
4+
from datetime import datetime
45

56
import pandas as pd
67

@@ -13,44 +14,104 @@
1314
JSON_FILE = "resources/table.json"
1415
REPORT_FILE = "docs/report.md"
1516
PIP_INDEX_URL = "https://pypi.org/pypi"
17+
PEP_BASE_URL = "https://peps.python.org/"
1618

1719
SPEC_MAP = {
1820
"ASGI": "https://asgi.readthedocs.io/en/latest/specs/main.html",
1921
"WSGI": "https://peps.python.org/numerical",
2022
}
2123

2224

23-
def get_upstream_version(dependency):
25+
def estimate_days_behind(release_date):
26+
return datetime.today() - datetime.strptime(release_date, "%Y-%m-%d")
27+
28+
29+
def get_upstream_version(dependency, last_supported_version):
2430
"""Get the latest version available upstream"""
31+
last_supported_version_release_date = "Not found"
2532
if dependency in SPEC_MAP:
2633
# webscrape info from official website
27-
pattern = "(\d+\.\d+\.?\d*)"
34+
version_pattern = "(\d+\.\d+\.?\d*)"
35+
latest_version_release_date = ""
2836

2937
url = SPEC_MAP[dependency]
3038
page = requests.get(url)
3139
soup = BeautifulSoup(page.text, "html.parser")
3240
# ASGI
3341
if "asgi" in url:
34-
text = (
35-
soup.find(id="version-history")
36-
.findChild("li", string=re.compile(pattern))
37-
.text
38-
)
42+
all_versions = soup.find(id="version-history").find_all("li")
43+
pattern = re.compile(r"([\d.]+) \((\d{4}-\d{2}-\d{2})\)")
44+
latest_version, latest_version_release_date = pattern.search(
45+
all_versions[0].text
46+
).groups()
47+
for li in all_versions:
48+
match = pattern.search(li.text)
49+
if match:
50+
version, date = match.groups()
51+
if version == last_supported_version:
52+
last_supported_version_release_date = date
53+
break
3954
# WSGI
4055
else:
41-
tag = soup.find(id="numerical-index").find_all(
56+
all_versions = soup.find(id="numerical-index").find_all(
4257
"a", string=re.compile("Web Server Gateway Interface")
43-
)[-1]
44-
text = tag.text
45-
res = re.search(pattern, text)
46-
return res[1]
58+
)
59+
latest_version = re.search(version_pattern, all_versions[-1].text).group()
60+
61+
for a in all_versions:
62+
pep_link = PEP_BASE_URL + a.get("href").split("..")[1]
63+
response = requests.get(pep_link)
64+
soup = BeautifulSoup(response.text, "html.parser")
65+
version = re.search(version_pattern, a.text).group()
66+
pep_page_metadata = soup.find("dl")
67+
68+
if pep_page_metadata and version in [
69+
latest_version,
70+
last_supported_version,
71+
]:
72+
metadata_fields = pep_page_metadata.find_all("dt")
73+
metadata_values = pep_page_metadata.find_all("dd")
74+
75+
for dt, dd in zip(metadata_fields, metadata_values):
76+
if "Created" in dt.text:
77+
release_date = dd.text.strip()
78+
release_date_as_datetime = datetime.strptime(
79+
release_date, "%d-%b-%Y"
80+
)
81+
if version == latest_version:
82+
latest_version_release_date = (
83+
release_date_as_datetime.strftime("%Y-%m-%d")
84+
)
85+
if version == last_supported_version:
86+
last_supported_version_release_date = (
87+
release_date_as_datetime.strftime("%Y-%m-%d")
88+
)
89+
return (
90+
latest_version,
91+
latest_version_release_date,
92+
last_supported_version_release_date,
93+
)
4794

4895
else:
4996
# get info using PYPI API
5097
response = requests.get(f"{PIP_INDEX_URL}/{dependency}/json")
5198
response_json = response.json()
5299
latest_version = response_json["info"]["version"]
53-
return latest_version
100+
release_time = response_json["releases"][latest_version][-1][
101+
"upload_time_iso_8601"
102+
]
103+
latest_version_release_date = datetime.fromisoformat(release_time)
104+
formatted_release_date = latest_version_release_date.strftime("%Y-%m-%d")
105+
for version, release_info in response_json["releases"].items():
106+
if version == last_supported_version:
107+
release_time = release_info[-1]["upload_time_iso_8601"]
108+
release_date = datetime.fromisoformat(release_time)
109+
last_supported_version_release_date = release_date.strftime("%Y-%m-%d")
110+
return (
111+
latest_version,
112+
formatted_release_date,
113+
last_supported_version_release_date,
114+
)
54115

55116

56117
def get_last_supported_version(tekton_ci_output, dependency):
@@ -67,14 +128,18 @@ def get_last_supported_version(tekton_ci_output, dependency):
67128
return last_supported_version[1]
68129

69130

70-
def isUptodate(last_supported_version, latest_version):
131+
def is_up_to_date(
132+
last_supported_version, latest_version, last_supported_version_release_date
133+
):
71134
"""Check if the supported package is up-to-date"""
72135
if Version(last_supported_version) >= Version(latest_version):
73136
up_to_date = "Yes"
137+
days_behind = 0
74138
else:
75139
up_to_date = "No"
140+
days_behind = estimate_days_behind(last_supported_version_release_date)
76141

77-
return up_to_date
142+
return up_to_date, days_behind
78143

79144

80145
def get_taskruns(namespace, task_name, taskrun_filter):
@@ -144,15 +209,15 @@ def get_tekton_ci_output():
144209
core_v1_client = client.CoreV1Api()
145210

146211
task_name = "python-tracer-unittest-gevent-starlette-task"
147-
taskrun_filter = lambda tr: tr["status"]["conditions"][0]["type"] == "Succeeded"
212+
taskrun_filter = lambda tr: tr["status"]["conditions"][0]["type"] == "Succeeded" # noqa: E731
148213
starlette_taskruns = get_taskruns(namespace, task_name, taskrun_filter)
149214

150215
tekton_ci_output = process_taskrun_logs(
151216
starlette_taskruns, core_v1_client, namespace, task_name, ""
152217
)
153218

154219
task_name = "python-tracer-unittest-googlecloud-task"
155-
taskrun_filter = (
220+
taskrun_filter = ( # noqa: E731
156221
lambda tr: tr["metadata"]["name"].endswith("unittest-googlecloud-0")
157222
and tr["status"]["conditions"][0]["type"] == "Succeeded"
158223
)
@@ -163,7 +228,7 @@ def get_tekton_ci_output():
163228
)
164229

165230
task_name = "python-tracer-unittest-default-task"
166-
taskrun_filter = (
231+
taskrun_filter = ( # noqa: E731
167232
lambda tr: tr["metadata"]["name"].endswith("unittest-default-3")
168233
and tr["status"]["conditions"][0]["type"] == "Succeeded"
169234
)
@@ -195,11 +260,23 @@ def main():
195260
else:
196261
last_supported_version = item["Last Supported Version"]
197262

198-
latest_version = get_upstream_version(package)
263+
latest_version, release_date, last_supported_version_release_date = (
264+
get_upstream_version(package, last_supported_version)
265+
)
199266

200-
up_to_date = isUptodate(last_supported_version, latest_version)
267+
up_to_date, days_behind = is_up_to_date(
268+
last_supported_version, latest_version, last_supported_version_release_date
269+
)
201270

202-
item.update({"Latest version": latest_version, "Up-to-date": up_to_date})
271+
item.update(
272+
{
273+
"Latest version": latest_version,
274+
"Up-to-date": up_to_date,
275+
"Release date": release_date,
276+
"Latest Version Published At": last_supported_version_release_date,
277+
"Days behind": f"{days_behind} day/s",
278+
}
279+
)
203280

204281
# Create a DataFrame from the list of dictionaries
205282
df = pd.DataFrame(items)

0 commit comments

Comments
 (0)