commit e8e079144e876c99e610ca4372f1a1931a462cbc
parent 650728d0570e42834e39f272710d45c5303d4572
Author: Florian Dold <dold@taler.net>
Date: Sun, 6 Sep 2026 20:38:30 +0200
packaging/ng: add latest version filter to show-published
Diffstat:
3 files changed, 84 insertions(+), 3 deletions(-)
diff --git a/packaging/ng/README.md b/packaging/ng/README.md
@@ -185,6 +185,9 @@ is created or updated.
./taler-pkg show-published debian-trixie-stable
./taler-pkg show-published debian-trixie-testing
+# Show only the latest version of each package per architecture.
+./taler-pkg show-published --latest debian-trixie-testing
+
# Compare published testing with stable, then promote that exact snapshot.
./taler-pkg promote --dry debian-trixie
./taler-pkg promote debian-trixie
@@ -208,6 +211,9 @@ have not been successfully published cannot reach stable through promotion.
lists its enabled architectures plus architecture-independent packages, and
prints sorted, unique `name_version_architecture` lines. A base distro selects
stable; the `-stable` and `-testing` suffixes select either channel explicitly.
+Pass `--latest` to show only the newest version of each package per architecture,
+using Debian version ordering within the selected distro and channel.
+Architecture-independent packages (`all`) are grouped separately.
The same suffixes work for `ubuntu-noble`. Pending testing imports are not
included. These suffixes are specific to `show-published`; building, publishing,
and promoting continue to use the base distro.
diff --git a/packaging/ng/taler-pkg b/packaging/ng/taler-pkg
@@ -636,6 +636,16 @@ def show_published(cfg):
for package in snapshot_packages(snapshot)
if package_identity(package)[2] in architectures | {"all"}
}
+ if cfg.latest:
+ latest = {}
+ for package in sorted(packages):
+ name, version, architecture = package_identity(package)
+ key = (name, architecture)
+ if key not in latest or vercomp.compare_versions(
+ version, latest[key][0]
+ ) > 0:
+ latest[key] = (version, package)
+ packages = {package for _, package in latest.values()}
for package in sorted(packages):
print(package)
@@ -1036,6 +1046,11 @@ def main():
"show-published", help="Show packages in a published stable or testing snapshot"
)
parser_show_published.add_argument(
+ "--latest",
+ action="store_true",
+ help="Show only the newest version of each package per architecture",
+ )
+ parser_show_published.add_argument(
"distro",
choices=[
f"{distro}{suffix}"
diff --git a/packaging/ng/testing/test_publishing.py b/packaging/ng/testing/test_publishing.py
@@ -1032,6 +1032,62 @@ class ShowPublishedTests(unittest.TestCase):
self.assertEqual(2, remote.call_count)
repo.assert_not_called()
+ def test_latest_uses_debian_versions_per_package_and_architecture(self):
+ packages = [
+ "one_1.9_amd64",
+ "one_1.10~rc1_amd64",
+ "one_1.10_amd64",
+ "one_1.10-2_amd64",
+ "one_1.10-10_amd64",
+ "one_1.8_arm64",
+ "one_1.9_arm64",
+ "one_1.7_all",
+ "one_1.8_all",
+ "two_9.0_all",
+ "two_1:1.0_all",
+ "two_1:1.0_all",
+ "excluded_99_i386",
+ "source_99_source",
+ ]
+ newest = [
+ "one_1.10-10_amd64",
+ "one_1.9_arm64",
+ "one_1.8_all",
+ "two_1:1.0_all",
+ ]
+ for distro in TALER_PKG.publishing_configs:
+ for suffix in ("", "-stable", "-testing"):
+ for latest in (False, True):
+ with (
+ self.subTest(distro=distro, suffix=suffix, latest=latest),
+ patch.object(
+ TALER_PKG,
+ "published_snapshot",
+ return_value=("selected", {"amd64", "arm64"}),
+ ) as published,
+ patch.object(
+ TALER_PKG, "snapshot_packages", return_value=packages
+ ) as snapshot,
+ patch.object(
+ sys,
+ "argv",
+ ["taler-pkg", "show-published", distro + suffix]
+ + (["--latest"] if latest else []),
+ ),
+ patch("sys.stdout", new_callable=StringIO) as stdout,
+ ):
+ TALER_PKG.main()
+ expected = newest if latest else packages[:-2]
+ self.assertEqual(
+ "".join(f"{package}\n" for package in sorted(set(expected))),
+ stdout.getvalue(),
+ )
+ published.assert_called_once_with(
+ TALER_PKG.publishing_config(distro),
+ stable=suffix != "-testing",
+ )
+ snapshot.assert_called_once_with("selected")
+
def test_unsupported_targets_fail_before_contacting_server(self):
for target in (
"debian-bookworm",
@@ -1057,7 +1113,9 @@ class ShowPublishedTests(unittest.TestCase):
patch.object(TALER_PKG, "snapshot_packages", return_value=[]),
patch("sys.stdout", new_callable=StringIO) as stdout,
):
- TALER_PKG.show_published(SimpleNamespace(distro="ubuntu-noble-testing"))
+ TALER_PKG.show_published(
+ SimpleNamespace(distro="ubuntu-noble-testing", latest=True)
+ )
self.assertEqual("", stdout.getvalue())
def test_unpublished_architectures_are_excluded(self):
@@ -1072,7 +1130,9 @@ class ShowPublishedTests(unittest.TestCase):
),
patch("sys.stdout", new_callable=StringIO) as stdout,
):
- TALER_PKG.show_published(SimpleNamespace(distro="debian-trixie-testing"))
+ TALER_PKG.show_published(
+ SimpleNamespace(distro="debian-trixie-testing", latest=True)
+ )
self.assertEqual("one_1_arm64\ntwo_2_all\n", stdout.getvalue())
def test_failed_lookups_do_not_print_a_partial_listing(self):
@@ -1094,7 +1154,7 @@ class ShowPublishedTests(unittest.TestCase):
self.assertRaises(subprocess.CalledProcessError),
):
TALER_PKG.show_published(
- SimpleNamespace(distro="debian-trixie-testing")
+ SimpleNamespace(distro="debian-trixie-testing", latest=True)
)
self.assertEqual("", stdout.getvalue())