From 69210066baa1a2ea47f385641d80e651c15dd30c Mon Sep 17 00:00:00 2001 From: colinmoynes Date: Wed, 14 Jan 2026 16:55:20 +0000 Subject: [PATCH 1/2] uploaded date now returned --- Docker/Sonar/sonar.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/Docker/Sonar/sonar.py b/Docker/Sonar/sonar.py index ffa74ef..f76a195 100755 --- a/Docker/Sonar/sonar.py +++ b/Docker/Sonar/sonar.py @@ -250,6 +250,7 @@ def get_digest_data(workspace, repo, img, digest, ntag_display, platform="unknow status_raw = "Unknown" dl = 0 + uploaded_at = "" if pkg_details: statuses = set(find_key_recursive(pkg_details, 'status_str')) @@ -262,12 +263,17 @@ def get_digest_data(workspace, repo, img, digest, ntag_display, platform="unknow elif len(downloads) > 0: dl = downloads[0] + uploaded_at = find_key_recursive(pkg_details, 'uploaded_at') + if uploaded_at: + uploaded = uploaded_at + return { "tag": ntag_display, "type": "image", "platform": platform, "status": status_raw, "downloads": dl, + "uploaded": uploaded, "digest": digest, "is_child": True } @@ -323,6 +329,7 @@ def fetch_tag_data(workspace, repo, img, ntag, detailed=False, include_all=False if pkg_details and len(pkg_details) > 0: pkg = pkg_details[0] parent_status = pkg.get('status_str', 'Unknown') + uploaded_at = pkg.get('uploaded_at') slug = pkg.get('slug', '') ver = pkg.get('version', '') if ver and not ver.startswith('sha256:'): @@ -413,6 +420,7 @@ def fetch_tag_data(workspace, repo, img, ntag, detailed=False, include_all=False "type": "manifest/list" if is_list else "image", "platform": parent_platform, "status": parent_status, + "uploaded": uploaded_at, "downloads": total_downloads, "digest": index_digest, "is_child": False, @@ -441,6 +449,7 @@ def fetch_untagged_data(pkg, workspace, repo, img, detailed=False): pkg_type = pkg.get('type_display', 'image') platform_str = "unknown" + uploaded_at = pkg.get('uploaded_at') # 1. Try to get architecture from Cloudsmith Package API (List Object) api_arch = pkg.get('architecture') @@ -516,10 +525,14 @@ def fetch_untagged_data(pkg, workspace, repo, img, detailed=False): details_url = f"https://api.cloudsmith.io/v1/packages/{workspace}/{repo}/{slug}/" details = make_request(details_url) if details: - d_arch = details.get('architecture') - if d_arch and d_arch != 'unknown': + d_uploaded = details.get('uploaded_at') + if d_uploaded: + uploaded_at = d_uploaded + + d_arch = details.get('architecture') + if d_arch and d_arch != 'unknown': platform_str = d_arch - else: + else: d_archs = details.get('architectures') if d_archs: names = [] @@ -531,7 +544,8 @@ def fetch_untagged_data(pkg, workspace, repo, img, detailed=False): valid_names = [n for n in names if n and n != 'unknown'] if valid_names: platform_str = " ".join(sorted(list(set(valid_names)))) - + + tag_display = "(untagged)" if pkg_type == "manifest/list" else "(orphan)" results = [] @@ -540,6 +554,7 @@ def fetch_untagged_data(pkg, workspace, repo, img, detailed=False): "type": pkg_type, "platform": platform_str, "status": status, + "uploaded": uploaded_at, "downloads": downloads, "digest": digest, "is_child": False, @@ -846,6 +861,7 @@ def render_table(image_name, groups, is_untagged=False, has_action=False): table.add_column("Type", style="magenta") table.add_column("Platform") table.add_column("Status") + table.add_column("Uploaded") table.add_column("Downloads", justify="right") table.add_column("Digest", style="dim") if has_action: @@ -866,6 +882,7 @@ def render_table(image_name, groups, is_untagged=False, has_action=False): parent.get("type", ""), parent.get("platform", ""), format_status(parent.get("status", "")), + parent.get("uploaded", ""), f"[bold cyan]{parent.get('downloads', 0)}[/bold cyan]", f"[dim]{parent.get('digest', '')}[/dim]", action_str if has_action else None @@ -876,6 +893,7 @@ def render_table(image_name, groups, is_untagged=False, has_action=False): f"[magenta]{parent.get('type', 'manifest/list')}[/magenta]", parent.get('platform', 'multi'), format_status(parent.get("status", "")), + f"[cyan]{parent.get('uploaded', '')}[/cyan]", f"[bold cyan]{parent.get('downloads', 0)}[/bold cyan]", f"[bold cyan]{parent.get('digest', '')}[/bold cyan]" ] @@ -895,6 +913,7 @@ def render_table(image_name, groups, is_untagged=False, has_action=False): f"[white]{row.get('type', '')}[/white]", row.get("platform", ""), format_status(row.get("status", "")), + f"[dim cyan]{parent.get('uploaded', '')}[/dim cyan]", f"[dim]{row.get('downloads', 0)}[/dim]", f"[dim]{row.get('digest', '')}[/dim]" ] @@ -1090,7 +1109,7 @@ def console(self): return console # fallback elif args.output == 'csv': # CSV Output (simple flat structure) csv_lines = [] - csv_lines.append(["Image", "Tag", "Type", "Platform", "Status", "Downloads", "Digest", "Action"]) # Header + csv_lines.append(["Image", "Tag", "Type", "Platform", "Status", "Uploaded", "Downloads", "Digest", "Action"]) # Header for img_name, groups in collected_results: for group in groups: @@ -1103,6 +1122,7 @@ def console(self): return console # fallback group.get("type", ""), group.get("platform", ""), group.get("status", ""), + group.get("uploaded", ""), str(group.get("downloads", 0)), group.get("digest", ""), group.get("action", "") From db589a826f52cff15d9317db9b431ad960ea18aa Mon Sep 17 00:00:00 2001 From: colinmoynes Date: Wed, 14 Jan 2026 17:16:17 +0000 Subject: [PATCH 2/2] readme update for v1.2 --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a55900..7f5aa80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,13 @@ ## [Unreleased] -### Sonar +## [Sonar] [v1.2] [2026-01-14] + +### Added - Added `--filter` flag which accepts the (Package Search Syntax)[https://docs.cloudsmith.com/artifact-management/search-filter-sort-packages] string. e.g. `--filter "downloads:>0"`. +- `Uploaded` date of the package now added to the results. + +### Fixed - Deletion now correctly works against non multi-arch images. Previously they where ignored and only multi-arch images were being deleted. Additionally improved log output for deletions.