Skip to content

feat(list-versions): show cooldown status and upload timestamps#1127

Open
shifa-khan wants to merge 1 commit intopython-wheel-build:mainfrom
shifa-khan:list-versions-1078
Open

feat(list-versions): show cooldown status and upload timestamps#1127
shifa-khan wants to merge 1 commit intopython-wheel-build:mainfrom
shifa-khan:list-versions-1078

Conversation

@shifa-khan
Copy link
Copy Markdown
Contributor

@shifa-khan shifa-khan commented May 7, 2026

package list-versions now shows upload_time, age in days, and cooldown status for each version.

--format controls the output: versions (default) and requirements print a filtered list excluding blocked entries; table, csv, and json include the full detail columns. This replaces the previous --details and --format-as-requirements flags.

--ignore-per-package-overrides shows what the global --min-release-age would block without per-package exemptions. The deprecated list-versions shim maps --format-as-requirements to --format requirements for backward compat.

Closes: #1078

@shifa-khan shifa-khan requested a review from a team as a code owner May 7, 2026 17:52
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR implements the cooldown details phase of the release-age cooldown feature (#1078). The package list-versions command gains a --details flag that outputs per-version metadata: upload timestamp, computed age in days, and cooldown status (blocked/allowed/skipped/blank). When --details is enabled, output formats as table, CSV, or JSON via --format/--output; plain mode preserves backward compatibility, listing only versions as before. A new --ignore-per-package-overrides flag lets operators check what global cooldown rules would enforce without per-package exemptions. Internally, versions are deduplicated and sorted, then routed through helpers that resolve effective cooldown policy, compute per-version metadata by grouping candidates, and classify each version based on cooldown settings and upload availability. Exporters render JSON, CSV, or Rich tables with an optional Cooldown column. Tests cover plain mode, formats, file output, override bypass behavior, CLI warnings, and unit tests for the cooldown classifier.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely describes the primary change: adding cooldown status and upload timestamp display to list-versions command.
Linked Issues check ✅ Passed The PR implementation fully satisfies issue #1078 requirements: displays upload_time and age_days, marks cooldown status (blocked/allowed/skipped), and implements --ignore-per-package-overrides flag with per-package override configuration.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #1078 objectives: cooldown display enhancements, filtering, and export options. The deprecated list-versions shim is intentionally left unmodified as documented.
Description check ✅ Passed The PR description directly addresses the changeset: it explains the new --details flag showing upload_time, age, and cooldown status, describes the --format options and filtering behavior, and mentions the --ignore-per-package-overrides flag.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mergify mergify Bot added the ci label May 7, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/fromager/commands/package.py (1)

196-245: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add per-requirement logging context in list_versions

list_versions logs requirement-specific messages but does not use log.req_ctxvar_context(req), so contextual logging is inconsistent with other command paths.

Suggested fix
-    logger.info(f"Looking up versions for {req.name}")
-    if req.specifier:
-        logger.info(f"Filtering versions with specifier: {req.specifier}")
+    with log.req_ctxvar_context(req):
+        logger.info(f"Looking up versions for {req.name}")
+        if req.specifier:
+            logger.info(f"Filtering versions with specifier: {req.specifier}")
 
-    pbi = wkctx.package_build_info(req)
-    override_sdist_server_url = pbi.resolver_sdist_server_url(sdist_server_url)
+        pbi = wkctx.package_build_info(req)
+        override_sdist_server_url = pbi.resolver_sdist_server_url(sdist_server_url)
 
-    include_sdists, include_wheels = parse_distribution_option(
-        distribution_type,
-        pbi,
-    )
+        include_sdists, include_wheels = parse_distribution_option(
+            distribution_type,
+            pbi,
+        )
 
-    provider = overrides.find_and_invoke(
+        provider = overrides.find_and_invoke(
         ...
-    )
+        )
+        ...

As per coding guidelines: src/fromager/**/*.py: “Use req_ctxvar_context() for per-requirement logging”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/fromager/commands/package.py` around lines 196 - 245, The
requirement-specific logs in this block should be executed inside the
per-requirement logging context; wrap the code that starts after
Requirement(requirement_spec) (the logger.info calls, pbi =
wkctx.package_build_info(req), parse_distribution_option,
overrides.find_and_invoke(...), provider.find_matches(...) and the
candidates/versions handling) in the context manager returned by
log.req_ctxvar_context(req) so that all requirement-scoped log messages use the
req context; locate the code around Requirement(...) and wrap the subsequent
logic (up through computing versions) with with log.req_ctxvar_context(req): to
ensure consistent contextual logging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/fromager/commands/package.py`:
- Around line 263-270: The table branch ignores the requested output
destination: in the match on output_format you call
_export_versions_table(version_rows, req.name, cooldown) which always prints to
stdout, so update the call and the function to accept an output file/stream
(e.g. add an output parameter) and forward the provided output handle used by
the json/csv branches; modify _export_versions_table signature and all call
sites (including the other occurrence around lines 402-422) to accept and write
to the passed output instead of writing directly to stdout.

---

Outside diff comments:
In `@src/fromager/commands/package.py`:
- Around line 196-245: The requirement-specific logs in this block should be
executed inside the per-requirement logging context; wrap the code that starts
after Requirement(requirement_spec) (the logger.info calls, pbi =
wkctx.package_build_info(req), parse_distribution_option,
overrides.find_and_invoke(...), provider.find_matches(...) and the
candidates/versions handling) in the context manager returned by
log.req_ctxvar_context(req) so that all requirement-scoped log messages use the
req context; locate the code around Requirement(...) and wrap the subsequent
logic (up through computing versions) with with log.req_ctxvar_context(req): to
ensure consistent contextual logging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 028ca9d6-ba8a-480e-8b7a-b9666d871f34

📥 Commits

Reviewing files that changed from the base of the PR and between 5fd5d20 and 88f414f.

📒 Files selected for processing (2)
  • src/fromager/commands/package.py
  • tests/test_list_versions.py

Comment thread src/fromager/commands/package.py
@shifa-khan
Copy link
Copy Markdown
Contributor Author

Tested the changes locally:

$ fromager --min-release-age 20 package list-versions --details --format json click
13:52:27 INFO Looking up versions for click
13:52:27 INFO Found 57 version(s)
    },
    {
        "package": "click",
        "version": "8.3.0",
        "upload_time": "2025-09-18T17:32:23.696258+00:00",
        "age_days": "231",
        "cooldown": "allowed"
    },
    {
        "package": "click",
        "version": "8.3.1",
        "upload_time": "2025-11-15T20:45:42.706404+00:00",
        "age_days": "172",
        "cooldown": "allowed"
    },
    {
        "package": "click",
        "version": "8.3.2",
        "upload_time": "2026-04-03T19:14:45.118083+00:00",
        "age_days": "33",
        "cooldown": "allowed"
    },
    {
        "package": "click",
        "version": "8.3.3",
        "upload_time": "2026-04-22T15:11:27.506141+00:00",
        "age_days": "15",
        "cooldown": "blocked"
    }
]

With a 20-day cooldown, click 8.3.3 (15 days old) is correctly marked as blocked while 8.3.2 (33 days old) is allowed.

Comment thread src/fromager/commands/package.py Outdated
@shifa-khan shifa-khan force-pushed the list-versions-1078 branch 5 times, most recently from ba62e44 to 22685c7 Compare May 8, 2026 16:53
Comment thread src/fromager/commands/package.py Outdated
"--format",
"output_format",
type=click.Choice(["table", "csv", "json"], case_sensitive=False),
default="table",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about adding "requirements" to this list of options, and eliminating the --format-as-requirements flag? Then we could also add a format of "versions" and that would be the default, to maintain consistency. Then I think we can skip the --details flag entirely, because each format would tell us whether we should be including those details or not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes sense. I was thinking about it too but since --format-as-requirements preexisted, I didn't want to make that change as part of this PR. I'll go ahead and fold it in.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first instinct would have been to preserve backwards compatibility, too, but I think in this case it's OK to fix things without doing that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, the deprecated list-versions shim still accepts --format-as-requirements and maps it to --format requirements

@shifa-khan shifa-khan force-pushed the list-versions-1078 branch from 22685c7 to 39e1053 Compare May 8, 2026 18:22
package list-versions now shows upload_time, age in days, and cooldown status for each version.

--format controls the output: versions (default) and requirements print a filtered list excluding blocked entries; table, csv, and json include the full detail columns. This replaces the previous --details and --format-as-requirements flags.

--ignore-per-package-overrides shows what the global --min-release-age would block without per-package exemptions. The deprecated list-versions shim maps --format-as-requirements to --format requirements for backward compat.

Co-authored-by: Cursor <cursoragent@cursor.com>
@shifa-khan shifa-khan force-pushed the list-versions-1078 branch from 39e1053 to 650cd2b Compare May 8, 2026 18:24
@dhellmann
Copy link
Copy Markdown
Member

We need to add some e2e tests, it looks like. The version-only listing works properly, but the table formatter does not filter by age.

$ .tox/cli/bin/fromager --min-release-age 800 package list-versions torch
18:12:55 INFO loading settings from /home/dhellmann/devel/aipcc/builder/overrides/settings.yaml
18:12:55 INFO Looking up versions for torch
18:12:55 INFO Found 17 version(s)
2.2.0
2.2.1

$ .tox/cli/bin/fromager --min-release-age 800 package list-versions --format table torch
18:13:07 INFO loading settings from /home/dhellmann/devel/aipcc/builder/overrides/settings.yaml
18:13:07 INFO Looking up versions for torch
18:13:07 INFO Found 17 version(s)
                          Versions for torch
┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Version ┃ Upload Time                      ┃ Age (days) ┃ Cooldown ┃
┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━┩
│ 2.2.0   │ 2024-01-30T17:31:54.836329+00:00 │        829 │ allowed  │
│ 2.2.1   │ 2024-02-22T19:17:39.398581+00:00 │        806 │ allowed  │
│ 2.2.2   │ 2024-03-27T21:09:07.247742+00:00 │        772 │ blocked  │
│ 2.3.0   │ 2024-04-24T15:47:07.772402+00:00 │        744 │ blocked  │
│ 2.3.1   │ 2024-06-05T16:42:05.146656+00:00 │        702 │ blocked  │
│ 2.4.0   │ 2024-07-24T15:29:48.218784+00:00 │        653 │ blocked  │
│ 2.4.1   │ 2024-09-04T19:13:19.273720+00:00 │        611 │ blocked  │
│ 2.5.0   │ 2024-10-17T14:47:22.380657+00:00 │        568 │ blocked  │
│ 2.5.1   │ 2024-10-29T17:32:42.789246+00:00 │        556 │ blocked  │
│ 2.6.0   │ 2025-01-29T16:25:55.649425+00:00 │        464 │ blocked  │
│ 2.7.0   │ 2025-04-23T14:35:15.589323+00:00 │        380 │ blocked  │
│ 2.7.1   │ 2025-06-04T17:39:12.852763+00:00 │        338 │ blocked  │
│ 2.8.0   │ 2025-08-06T14:53:52.631799+00:00 │        275 │ blocked  │
│ 2.9.0   │ 2025-10-15T15:46:20.883880+00:00 │        205 │ blocked  │
│ 2.9.1   │ 2025-11-12T15:20:41.620358+00:00 │        177 │ blocked  │
│ 2.10.0  │ 2026-01-21T16:24:44.171477+00:00 │        107 │ blocked  │
│ 2.11.0  │ 2026-03-23T18:11:06.944421+00:00 │         46 │ blocked  │
└─────────┴──────────────────────────────────┴────────────┴──────────┘

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

list-versions: show cooldown status and upload timestamps

2 participants