diff --git a/build.rs b/build.rs index 0a3d19be1..6c69b391a 100644 --- a/build.rs +++ b/build.rs @@ -6,10 +6,13 @@ use std::path::Path; fn main() { let version = std::env::var("CARGO_PKG_VERSION").expect("Cargo package version"); let parts: Vec<&str> = version.split('.').collect(); - let app_version = if parts.len() == 3 && parts[0].len() == 4 - && parts[0].starts_with("20") && parts[2] == "0" - { - format!("{}.{:02}", parts[0], parts[1].parse::().expect("week number")) + let app_version = if parts.len() == 3 && parts[0].len() == 4 && parts[0].starts_with("20") { + let week = parts[1].parse::().expect("week number"); + if parts[2] == "0" { + format!("{}.{week:02}", parts[0]) + } else { + format!("{}.{week:02}.{}", parts[0], parts[2]) + } } else { version.clone() }; diff --git a/scripts/release.py b/scripts/release.py index 96b7ae1c9..28bafe5c4 100644 --- a/scripts/release.py +++ b/scripts/release.py @@ -21,12 +21,14 @@ def gh(*args): def versions(tag): version = tag.removeprefix("v") - weekly = re.fullmatch(r"(20\d{2})\.(\d{2})", version) + # `2026.40` is the weekly release; `2026.40.1` a fix release on top of it. + weekly = re.fullmatch(r"(20\d{2})\.(\d{2})(?:\.([1-9]\d*))?", version) if weekly: - year, week = map(int, weekly.groups()) + year, week = int(weekly[1]), int(weekly[2]) + patch = int(weekly[3] or 0) date.fromisocalendar(year, week, 1) - cargo = f"{year}.{week}.0" - msi = f"{year - 2000}.{week}.0" + cargo = f"{year}.{week}.{patch}" + msi = f"{year - 2000}.{week}.{patch}" elif re.fullmatch(r"(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)", version): cargo = msi = version major, minor, patch = map(int, version.split(".")) @@ -43,8 +45,9 @@ def cargo_version(): def display_version(cargo): year, week, patch = cargo.split(".") - if len(year) == 4 and year.startswith("20") and patch == "0": - return versions(f"{year}.{int(week):02}")["version"] + if len(year) == 4 and year.startswith("20"): + weekly = f"{year}.{int(week):02}" + return versions(weekly if patch == "0" else f"{weekly}.{patch}")["version"] return cargo diff --git a/scripts/test_release.py b/scripts/test_release.py index 753c09595..d5c6b9257 100644 --- a/scripts/test_release.py +++ b/scripts/test_release.py @@ -50,7 +50,7 @@ class ReleaseTests(unittest.TestCase): with tempfile.TemporaryDirectory() as temp: binary = str(Path(temp) / "build-script") subprocess.run(["rustc", str(Path(__file__).resolve().parents[1] / "build.rs"), "-o", binary], check=True) - for cargo in ("0.9.8", "2026.9.0", "2026.35.0", "2026.53.0", "2027.1.0"): + for cargo in ("0.9.8", "2026.9.0", "2026.35.0", "2026.53.0", "2027.1.0", "2026.40.1", "2026.5.2"): result = subprocess.check_output([binary], text=True, env={**os.environ, "CARGO_PKG_VERSION": cargo}) self.assertIn(f"cargo:rustc-env=OCS_APP_VERSION={release.display_version(cargo)}\n", result) @@ -61,6 +61,10 @@ class ReleaseTests(unittest.TestCase): self.assertEqual(release.versions("2026.09")["cargo"], "2026.9.0") self.assertEqual(release.display_version("2026.9.0"), "2026.09") self.assertEqual(release.display_version("0.9.8"), "0.9.8") + self.assertEqual(release.versions("v2026.40.1"), { + "version": "2026.40.1", "cargo": "2026.40.1", "msi": "26.40.1", "tag": "v2026.40.1", + }) + self.assertEqual(release.display_version("2026.5.2"), "2026.05.2") self.assertEqual(datetime(2027, 1, 3, tzinfo=timezone.utc).strftime("v%G.%V"), "v2026.53") for value in ("2026.00", "2026.54", "2027.53", "2026.9", "2026.35.0", "bad", "0.09.8"): with self.assertRaises(ValueError, msg=value): diff --git a/src/io/update_check.rs b/src/io/update_check.rs index cc24c402a..6c126bc08 100644 --- a/src/io/update_check.rs +++ b/src/io/update_check.rs @@ -137,10 +137,11 @@ fn parse_iso8601_utc(s: &str) -> Option { fn is_newer(latest: &str, installed: &str) -> bool { let parse = |version: &str| { let version = version.trim_start_matches('v'); - if let Some((year, week)) = version.split_once('.') { - if year.len() == 4 && year.starts_with("20") && !week.contains('.') { - return Some(semver::Version::new(year.parse().ok()?, week.parse().ok()?, 0)); - } + // `2026.40` and its fix release `2026.40.1`; the week may be zero-padded. + let parts: Vec<&str> = version.split('.').collect(); + if (2..=3).contains(&parts.len()) && parts[0].len() == 4 && parts[0].starts_with("20") { + let patch = parts.get(2).map_or(Some(0), |patch| patch.parse().ok())?; + return Some(semver::Version::new(parts[0].parse().ok()?, parts[1].parse().ok()?, patch)); } semver::Version::parse(version).ok() }; @@ -157,6 +158,9 @@ mod tests { assert!(is_newer("2026.10", "2026.09")); assert!(is_newer("2027.01", "2026.53")); assert!(!is_newer("2026.35", "2026.35")); + assert!(is_newer("2026.40.1", "2026.40")); + assert!(is_newer("2026.05.2", "2026.05.1")); + assert!(is_newer("2026.41", "2026.40.1")); assert!(!is_newer("0.9.8", "2026.35")); assert!(!is_newer("invalid", "2026.35")); }