Preserve all version fields (#286)

Up to now extra version fields were ignored: only name and date fields were accepted. This changes that by retaining the full JSON data when reading the file, making it possible in the future to support custom fields.

This also fixes a bug with versions having released on the same date: they was not ordered as expected (reverse order).
This commit is contained in:
Marc Wrobel
2024-01-28 23:46:41 +01:00
committed by GitHub
parent abaa97ddfc
commit 42165ea287
29 changed files with 5472 additions and 5481 deletions

View File

@@ -11,25 +11,28 @@ VERSIONS_PATH = Path(os.environ.get("VERSIONS_PATH", "releases"))
class ProductVersion:
def __init__(self, product: "Product", name: str, date: datetime) -> None:
def __init__(self, product: "Product", data: dict) -> None:
self.product = str(product)
self.name = name
self.date = date
self.data = data
@staticmethod
def from_json(product: "Product", data: dict) -> "ProductVersion":
name = data["name"]
date = datetime.strptime(data["date"], "%Y-%m-%d").replace(tzinfo=timezone.utc)
return ProductVersion(product, name, date)
def of(product: "Product", name: str, date: datetime) -> "ProductVersion":
return ProductVersion(product, {
"name": name,
"date": date.strftime("%Y-%m-%d"),
})
def __dict__(self) -> dict:
return {
"name": self.name,
"date": self.date.strftime("%Y-%m-%d"),
}
def name(self) -> str:
return self.data["name"]
def date(self) -> datetime:
return datetime.strptime(self.data["date"], "%Y-%m-%d").replace(tzinfo=timezone.utc)
def replace_date(self, date: datetime) -> None:
self.data["date"] = date.strftime("%Y-%m-%d")
def __repr__(self) -> str:
return f"{self.product}#{self.name} ({self.date})"
return f"{self.product}#{self.name()} ({self.date()})"
class Product:
@@ -46,8 +49,8 @@ class Product:
if product.versions_path.is_file():
with product.versions_path.open() as f:
for json_version in json.load(f)["versions"].values():
version = ProductVersion.from_json(product, json_version)
product.versions[version.name] = version
version = ProductVersion(product, json_version)
product.versions[version.name()] = version
logging.info(f"loaded versions data for {product} from {product.versions_path}")
else:
logging.warning(f"no versions data found for {product} at {product.versions_path}")
@@ -57,31 +60,21 @@ class Product:
def has_version(self, version: str) -> bool:
return version in self.versions
def get_version_date(self, version: str) -> datetime:
return self.versions[version].date if version in self.versions else None
def get_version(self, version: str) -> ProductVersion:
return self.versions[version] if version in self.versions else None
def declare_version(self, version: str, date: datetime) -> None:
if version in self.versions:
if self.versions[version].date != date:
logging.warning(f"overwriting {version} ({self.get_version_date(version)} -> {date}) for {self}")
else:
return # already declared
logging.info(f"adding version {version} ({date}) to {self}")
self.versions[version] = ProductVersion(self, version, date)
if version in self.versions and self.versions[version].date() != date:
logging.info(f"overwriting {version} ({self.get_version(version).date()} -> {date}) for {self}")
self.versions[version].replace_date(date)
else:
logging.info(f"adding version {version} ({date}) to {self}")
self.versions[version] = ProductVersion.of(self, version, date)
def declare_versions(self, dates_by_version: dict[str, datetime]) -> None:
for (version, date) in dates_by_version.items():
self.declare_version(version, date)
def replace_version(self, version: str, date: datetime) -> None:
if version not in self.versions:
msg = f"version {version} cannot be replaced as it does not exist for {self}"
raise ValueError(msg)
logging.info(f"replacing version {version} ({self.get_version_date(version)} -> {date}) in {self}")
self.versions[version].date = date
def remove_version(self, version: str) -> None:
if not self.has_version(version):
logging.warning(f"version {version} cannot be removed as it does not exist for {self}")
@@ -91,10 +84,10 @@ class Product:
def write(self) -> None:
# sort by date then version (desc)
ordered_versions = sorted(self.versions.values(), key=lambda v: (v.date, v.name), reverse=True)
ordered_versions = sorted(self.versions.values(), key=lambda v: (v.date(), v.name()), reverse=True)
with self.versions_path.open("w") as f:
f.write(json.dumps({
"versions": {version.name: version.__dict__() for version in ordered_versions},
"versions": {version.name(): version.data for version in ordered_versions},
}, indent=2))
logging.info("::endgroup::")