Files
endoflife-date-release-data/src/cgit.py
2023-06-14 22:22:32 +02:00

83 lines
2.6 KiB
Python

import re
import sys
from bs4 import BeautifulSoup
from common import endoflife
from datetime import datetime, timezone
from liquid import Template
"""Fetch versions with their dates from a cgit repository, such as
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git.
Ideally we would want to use the git repository directly, but cgit repositories
do not support partial clone so we cannot.
"""
METHOD = 'cgit'
# Same as used in Ruby (update.rb)
DEFAULT_TAG_TEMPLATE = (
"{{major}}{% if minor %}.{{minor}}{% if patch %}.{{patch}}{%if tiny %}.{{tiny}}{%endif%}{%endif%}{%endif%}"
)
DEFAULT_VERSION_REGEX = (
r"^v?(?P<major>\d+)\.(?P<minor>\d+)\.?(?P<patch>\d+)?\.?(?P<tiny>\d+)?$"
)
# Parse date with format 2023-05-01 08:32:34 +0900 and convert to UTC
def parse_date(d):
return (
datetime.strptime(d, "%Y-%m-%d %H:%M:%S %z")
.astimezone(timezone.utc)
.strftime("%Y-%m-%d")
)
def make_bs_request(url):
response = endoflife.fetch_url(url + '/refs/tags')
return BeautifulSoup(response, features="html5lib")
def fetch_releases(url, regex, template):
releases = {}
soup = make_bs_request(url)
l_template = Template(template)
for table in soup.find_all("table", class_="list"):
for row in table.find_all("tr"):
columns = row.find_all("td")
if len(columns) == 4:
version_text = columns[0].text.strip()
datetime_td = columns[3].find_next("span")
datetime_text = datetime_td.attrs["title"] if datetime_td else None
if datetime_text:
matches = re.match(regex.strip(), version_text)
if matches:
match_data = matches.groupdict()
version_string = l_template.render(**match_data)
date = parse_date(datetime_text)
print(f"{version_string} : {date}")
releases[version_string] = date
return releases
def update_product(product_name, configs):
releases = {}
for config in configs:
t = config.get("template", DEFAULT_TAG_TEMPLATE)
regex = config.get("regex", DEFAULT_VERSION_REGEX)
releases = releases | fetch_releases(config[METHOD], regex, t)
endoflife.write_releases(product_name, dict(
# sort by version then date (asc)
sorted(releases.items(), key=lambda x: (x[0], x[1]))
))
p_filter = sys.argv[1] if len(sys.argv) > 1 else None
for product, configs in endoflife.list_products(METHOD, p_filter).items():
print(f"::group::{product}")
update_product(product, configs)
print("::endgroup::")