mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
Show mod downloads and release dates in the launcher MODS panel
The MODS tab now shows each installed mod's total GitHub downloads (summed asset download_count across all releases), its first and latest release dates, and a Sort row (Name / Popularity / Release date / Last updated) persisted in options.modSort. The launcher already fetched per-repo release lists for update checks, so the data rides the same cached fetch: parseRelease keeps download_count and published_at, writeCache persists them, and a cache entry written before the fields existed is treated as stale and refetched once instead of hiding the line behind an old cache.
This commit is contained in:
@@ -108,4 +108,133 @@ do
|
||||
check(preview:find("Changes", 1, true), "previewLine keeps heading text")
|
||||
end
|
||||
|
||||
-- downloads: per-release sum over every asset's download_count
|
||||
do
|
||||
local body = Json.encode({
|
||||
{
|
||||
tag_name = "v1.2.0",
|
||||
assets = {
|
||||
{ name = "demo-1.2.0.zip", browser_download_url = "https://x/d.zip",
|
||||
size = 99, download_count = 41 },
|
||||
{ name = "demo-1.2.0.sha256", browser_download_url = "https://x/d.sha",
|
||||
download_count = 9 },
|
||||
},
|
||||
},
|
||||
})
|
||||
local list = ModUpdate.parseReleases(body, "demo")
|
||||
eq(list[1].downloads, 50, "downloads sums every asset, not just the zip")
|
||||
end
|
||||
|
||||
-- published: the release date is kept as an ISO day
|
||||
do
|
||||
local body = Json.encode({
|
||||
{ tag_name = "v1.2.0", published_at = "2025-04-13T09:24:00Z",
|
||||
assets = { { name = "demo-1.2.0.zip",
|
||||
browser_download_url = "https://x/d.zip" } } },
|
||||
})
|
||||
local list = ModUpdate.parseReleases(body, "demo")
|
||||
eq(list[1].published, "2025-04-13", "published_at is reduced to the day")
|
||||
local noDate = ModUpdate.parseReleases(Json.encode({
|
||||
{ tag_name = "v1.0.0",
|
||||
assets = { { name = "demo-1.0.0.zip",
|
||||
browser_download_url = "https://x/d.zip" } } },
|
||||
}), "demo")
|
||||
check(noDate[1].published == nil, "missing dates stay nil, never throw")
|
||||
end
|
||||
|
||||
-- releaseDates: first and latest across releases
|
||||
do
|
||||
local d = ModUpdate.releaseDates({
|
||||
{ version = "1.0.0", published = "2024-05-31" },
|
||||
{ version = "1.2.0", published = "2025-11-02" },
|
||||
{ version = "1.1.0", published = "2025-01-15" },
|
||||
})
|
||||
eq(d.first, "2024-05-31", "first is the oldest release date")
|
||||
eq(d.latest, "2025-11-02", "latest is the newest release date")
|
||||
check(ModUpdate.releaseDates({ { version = "1.0.0" } }) == nil,
|
||||
"releases without dates report no data")
|
||||
check(ModUpdate.releaseDates({}) == nil, "empty list reports no data")
|
||||
check(ModUpdate.releaseDates(nil) == nil, "nil list reports no data")
|
||||
end
|
||||
|
||||
-- totalDownloads: totals across releases; nil until data actually exists
|
||||
do
|
||||
local new = {
|
||||
{ version = "1.0.0", downloads = 41 },
|
||||
{ version = "1.1.0", downloads = 9 },
|
||||
}
|
||||
local dl = ModUpdate.totalDownloads(new)
|
||||
eq(dl.total, 50, "totals across releases")
|
||||
eq(dl.releases, 2, "counts the releases")
|
||||
dl = ModUpdate.totalDownloads({ { version = "1.0.0", downloads = 0 } })
|
||||
eq(dl.total, 0, "a real zero stays zero")
|
||||
dl = ModUpdate.totalDownloads({ { version = "1.0.0" } })
|
||||
check(dl == nil, "pre-downloads cache rows report no data")
|
||||
check(ModUpdate.totalDownloads({}) == nil, "empty list reports no data")
|
||||
check(ModUpdate.totalDownloads(nil) == nil, "nil list reports no data")
|
||||
end
|
||||
|
||||
-- formatCount: thousands separators, never throws
|
||||
eq(ModUpdate.formatCount(0), "0", "zero formats plain")
|
||||
eq(ModUpdate.formatCount(999), "999", "below 1000 formats plain")
|
||||
eq(ModUpdate.formatCount(1000), "1,000", "1000 gets a separator")
|
||||
eq(ModUpdate.formatCount(1234567), "1,234,567", "large counts group by 3")
|
||||
eq(ModUpdate.formatCount("12345"), "12,345", "numeric strings are accepted")
|
||||
eq(ModUpdate.formatCount(nil), "0", "nil formats as zero")
|
||||
eq(ModUpdate.formatCount("garbage"), "0", "garbage formats as zero")
|
||||
|
||||
-- cacheUsable: a cache entry from before downloads existed must not be
|
||||
-- trusted, everything current is
|
||||
do
|
||||
local old = { checkedAt = os.time(),
|
||||
releases = { { version = "1.0.0", tag = "v1.0.0" } } }
|
||||
check(not ModUpdate.cacheUsable(old), "pre-downloads cache is unusable")
|
||||
local zero = { checkedAt = os.time(),
|
||||
releases = { { version = "1.0.0", downloads = 0 } } }
|
||||
check(ModUpdate.cacheUsable(zero), "current cache is usable even at zero")
|
||||
check(ModUpdate.cacheUsable({ checkedAt = os.time(), releases = {} }),
|
||||
"empty release list stays usable")
|
||||
check(not ModUpdate.cacheUsable(nil), "nil cache is unusable")
|
||||
check(not ModUpdate.cacheUsable({}), "cache without releases is unusable")
|
||||
end
|
||||
|
||||
-- fetchReleases: an old-format cache entry is refetched once and rewritten
|
||||
-- in the current format; a current one is served untouched
|
||||
do
|
||||
local HostShell = require("src.core.HostShell")
|
||||
local realRead, realWrite = ModUpdate.readCache, ModUpdate.writeCache
|
||||
local realCanFetch, realHttpGet = HostShell.canFetch, HostShell.httpGet
|
||||
local cached, fetched
|
||||
ModUpdate.readCache = function() return cached end
|
||||
ModUpdate.writeCache = function(repo, releases)
|
||||
fetched = releases
|
||||
return true
|
||||
end
|
||||
HostShell.canFetch = function() return true end
|
||||
HostShell.httpGet = function()
|
||||
return Json.encode({ {
|
||||
tag_name = "v1.0.0",
|
||||
assets = { { name = "demo-1.0.0.zip",
|
||||
browser_download_url = "https://x/d.zip", download_count = 7 } },
|
||||
} })
|
||||
end
|
||||
|
||||
cached = { checkedAt = os.time(),
|
||||
releases = { { version = "1.0.0", tag = "v1.0.0" } } }
|
||||
fetched = nil
|
||||
local list = ModUpdate.fetchReleases("acme/mod", "demo")
|
||||
check(fetched ~= nil, "old-format cache triggers a refetch")
|
||||
check(list[1].downloads == 7, "refetched release carries downloads")
|
||||
|
||||
cached = { checkedAt = os.time(),
|
||||
releases = { { version = "1.0.0", tag = "v1.0.0", downloads = 0 } } }
|
||||
fetched = nil
|
||||
list = ModUpdate.fetchReleases("acme/mod", "demo")
|
||||
check(fetched == nil, "current cache is served without refetch")
|
||||
check(list[1].downloads == 0, "cached zero stays zero")
|
||||
|
||||
ModUpdate.readCache, ModUpdate.writeCache = realRead, realWrite
|
||||
HostShell.canFetch, HostShell.httpGet = realCanFetch, realHttpGet
|
||||
end
|
||||
|
||||
print("ok mod_update_tests")
|
||||
|
||||
Reference in New Issue
Block a user