diff --git a/scripts/generate_channel.py b/scripts/generate_channel.py index 70f102f6f..99a47352b 100644 --- a/scripts/generate_channel.py +++ b/scripts/generate_channel.py @@ -6,9 +6,9 @@ import json import sys import os -from typing import TypedDict, Literal, NotRequired +from typing import Generator, Literal, NotRequired, TypedDict -from ._utils import pick, pl, write_json +from ._utils import flatten, pick, pl, write_json, parse_version type RepositoryUrl = str type Platform = Literal["*", "windows", "osx", "linux"] @@ -249,6 +249,9 @@ def normalize_package(pkg) -> Package | None: "url": rel["url"], "date": format_utc_datetime(rel["date"]), }) + + releases = remove_older_releases(releases) + if not releases: err(f"Drop package {name} with no valid releases") return None @@ -292,6 +295,37 @@ def normalize_package(pkg) -> Package | None: return out +def remove_older_releases(releases: list[Release]) -> list[Release]: + grouped: dict[tuple[str, tuple[Platform, ...]], list[Release]] = defaultdict(list) + for rel in releases: + grouped[(rel["sublime_text"], tuple(rel["platforms"]))].append(rel) + + compressed: list[Release] = list(flatten( + compress_release_group(rels) + for rels in grouped.values() + )) + compressed.sort( + key=lambda rel: ( + rel.get("sublime_text"), + rel.get("platforms"), + rel.get("date") + ) + ) + return compressed + + +def compress_release_group(releases: list[Release]) -> Generator[Release]: + prerelease_found = False + for rel in sorted(releases, key=lambda rel: rel["date"], reverse=True): + version = parse_version(rel["version"]) + if not version or version.is_final: + yield rel + break + if version.is_prerelease and not prerelease_found: + prerelease_found = True + yield rel + + def normalize_library(lib) -> Library | None: name = lib.get("name") if not name: diff --git a/tests/generate_channel/test_generate_channel.py b/tests/generate_channel/test_generate_channel.py index 669c6961c..b54fe56e7 100644 --- a/tests/generate_channel/test_generate_channel.py +++ b/tests/generate_channel/test_generate_channel.py @@ -171,6 +171,111 @@ def test_normalize_package_formats_fields_and_defaults(): } +def test_normalize_package_compresses_versions_by_build_and_platform(): + pkg = { + "name": "Monokai Pro", + "author": ["Monokai"], + "last_modified": "2026-01-11T10:00:00Z", + "source": "https://repo.example", + "releases": [ + { + "sublime_text": ">=3000", + "platforms": ["*"], + "version": "2.0.3", + "url": "https://repo.example/2.0.3.zip", + "date": "2024-12-04T14:00:00Z", + }, + { + "sublime_text": ">=3000", + "platforms": ["*"], + "version": "2.0.6", + "url": "https://repo.example/2.0.6.zip", + "date": "2025-01-15T13:30:00Z", + }, + { + "sublime_text": ">=4050", + "platforms": ["*"], + "version": "2.1.5", + "url": "https://repo.example/2.1.5.zip", + "date": "2025-12-17T10:00:00Z", + }, + { + "sublime_text": ">=4050", + "platforms": ["*"], + "version": "2.1.6", + "url": "https://repo.example/2.1.6.zip", + "date": "2026-01-07T10:00:00Z", + }, + { + "sublime_text": ">=4050", + "platforms": ["*"], + "version": "2.2.0-rc1", + "url": "https://repo.example/2.2.0-rc1.zip", + "date": "2026-01-10T10:00:00Z", + }, + ], + } + + normalized = normalize_package(pkg) + + versions = sorted(rel["version"] for rel in normalized["releases"]) + assert versions == ["2.0.6", "2.1.6", "2.2.0-rc1"] + + +def test_normalize_package_drops_prerelease_older_than_final(): + pkg = { + "name": "Example", + "author": ["Ada"], + "last_modified": "2024-03-22T12:13:14Z", + "source": "https://repo.example", + "releases": [ + { + "sublime_text": ">=4100", + "platforms": ["*"], + "version": "1.0.0-rc1", + "url": "https://repo.example/1.0.0-rc1.zip", + "date": "2024-03-20T12:13:14Z", + }, + { + "sublime_text": ">=4100", + "platforms": ["*"], + "version": "1.0.0", + "url": "https://repo.example/1.0.0.zip", + "date": "2024-03-21T12:13:14Z", + }, + ], + } + + normalized = normalize_package(pkg) + + versions = [rel["version"] for rel in normalized["releases"]] + assert versions == ["1.0.0"] + + +def test_normalize_package_handles_non_semver_release(): + pkg = { + "name": "Repeat Macro", + "author": ["Siva"], + "last_modified": "2018-05-27T17:41:14Z", + "source": "https://repo.example", + "releases": [ + { + "sublime_text": "*", + "platforms": ["*"], + "version": "2018.05.27.17.41.14", + "url": "https://repo.example/repeat-macro.zip", + "date": "2018-05-27 17:41:14", + } + ], + } + + normalized = normalize_package(pkg) + + assert [rel["version"] for rel in normalized["releases"]] == [ + "2018.05.27.17.41.14" + ] + + def test_normalize_library_formats_release_dates_and_pick_fields(): lib = { "name": "Lib",