Repository: getpatchwork/git-pw

Issue:
`patch list` is not so usable when tons of patches are available
Here is an issue with `git pw patch list`.
It can't show properly the limit of commits. `--limit=0` does not affect anything (I'm expecting no limit, or server defined limit), `--limit=1000` shows 1000 patches, however, I would rather need only few patches by given submitter (okay, this wouldn't work with API 1.0), or for given date (or period in time).
So, `git pw patch list --date=today` or alike is what being missed.

Discussion:
stephenfin: > I've been working on adding support for bounding patch and series list results with the use of --before and --since options to git-pw. This is of particular value to our use with the Yocto Project, but others may find it very helpful as well. I saw that there is an open issue (#27) where this feature has been discussed before, so hopefully this change could solve that issue.

Thanks. This is a tidy looking change. I have left some small comments inline. Could you take a look at them please? I'd be happy to merge this and cut a new release once they're addressed.

> What I'm not clear on is how to add proper tests - I've skimmed the existing test cases but I'm not understanding how the mock operates. Would testing these options fit easily into what exists? If so, could you provide suggestions?

It's very dumb, at least from the perspective of the shell. We're not actually testing any HTTP stuff: merely that the relevant function in `git_pw.api` is called (`index` in the case of list operations). I'd suggest modifying the `test_list_with_filters` tests in both `tests/test_patch.py` and `tests/test_series.py`. You want to invoke the runner with your new arguments and ensure the corresponding call to `git_pw.api.index` (mocked as `mock_index`) changes accordingly. Hopefully that makes sense.
threexc: > > I've been working on adding support for bounding patch and series list results with the use of --before and --since options to git-pw. This is of particular value to our use with the Yocto Project, but others may find it very helpful as well. I saw that there is an open issue (#27) where this feature has been discussed before, so hopefully this change could solve that issue.
> 
> Thanks. This is a tidy looking change. I have left some small comments inline. Could you take a look at them please? I'd be happy to merge this and cut a new release once they're addressed.
> 
> > What I'm not clear on is how to add proper tests - I've skimmed the existing test cases but I'm not understanding how the mock operates. Would testing these options fit easily into what exists? If so, could you provide suggestions?
> 
> It's very dumb, at least from the perspective of the shell. We're not actually testing any HTTP stuff: merely that the relevant function in `git_pw.api` is called (`index` in the case of list operations). I'd suggest modifying the `test_list_with_filters` tests in both `tests/test_patch.py` and `tests/test_series.py`. You want to invoke the runner with your new arguments and ensure the corresponding call to `git_pw.api.index` (mocked as `mock_index`) changes accordingly. Hopefully that makes sense.

Thanks for the feedback. I've pushed patches to address your review comments. Working on tests but running into issues with (duplicated) differences between expected and actual results.
threexc: I think this should be good to squash and merge now unless there are issues with linting or whatnot.
stephenfin: Looks great. Just some simple linter issues to address. Can you run `pre-commit run -a` to fix these then commit and push the changes? I'll happily merge this then.
stephenfin: Fixed the issues and squashed the commit. Looks like the tests are failing now that we're actually using `datetime` though. Taking a look...

Patch:
diff --git a/git_pw/patch.py b/git_pw/patch.py
index d436bbb..4ed80b0 100644
--- a/git_pw/patch.py
+++ b/git_pw/patch.py
@@ -329,6 +329,7 @@ def update_cmd(patch_ids, commit_ref, state, delegate, archived, fmt):
     is_flag=True,
     help='Include patches that are archived.',
 )
+@utils.date_options()
 @utils.pagination_options(sort_fields=_sort_fields, default_sort='-date')
 @utils.format_options(headers=_list_headers)
 @click.argument('name', required=False)
@@ -339,6 +340,8 @@ def list_cmd(
     delegates,
     hashes,
     archived,
+    since,
+    before,
     limit,
     page,
     sort,
@@ -403,6 +406,12 @@ def list_cmd(
         ]
     )
 
+    if since:
+        params.append(('since', since.isoformat()))
+
+    if before:
+        params.append(('before', before.isoformat()))
+
     patches = api.index('patches', params)
 
     # Format and print output
diff --git a/git_pw/series.py b/git_pw/series.py
index 59a1a25..1a46bc7 100644
--- a/git_pw/series.py
+++ b/git_pw/series.py
@@ -161,11 +161,12 @@ def show_cmd(fmt, series_id):
         'email, name or ID.'
     ),
 )
+@utils.date_options()
 @utils.pagination_options(sort_fields=_sort_fields, default_sort='-date')
 @utils.format_options(headers=_list_headers)
 @click.argument('name', required=False)
 @api.validate_multiple_filter_support
-def list_cmd(submitters, limit, page, sort, fmt, headers, name):
+def list_cmd(submitters, limit, page, sort, fmt, headers, name, since, before):
     """List series.
 
     List series on the Patchwork instance.
@@ -201,6 +202,12 @@ def list_cmd(submitters, limit, page, sort, fmt, headers, name):
         ]
     )
 
+    if since:
+        params.append(('since', since.isoformat()))
+
+    if before:
+        params.append(('before', before.isoformat()))
+
     series = api.index('series', params)
 
     # Format and print output
diff --git a/git_pw/utils.py b/git_pw/utils.py
index b714844..c94758b 100644
--- a/git_pw/utils.py
+++ b/git_pw/utils.py
@@ -207,6 +207,28 @@ def pagination_options(
     return _pagination_options
 
 
+def date_options() -> ty.Callable:
+    """Shared date bounding options."""
+
+    def _date_options(f):
+        f = click.option(
+            '--since',
+            metavar='SINCE',
+            type=click.DateTime(),
+            help='Show only items since a given date in ISO 8601 format',
+        )(f)
+        f = click.option(
+            '--before',
+            metavar='BEFORE',
+            type=click.DateTime(),
+            help='Show only items before a given date in ISO 8601 format',
+        )(f)
+
+        return f
+
+    return _date_options
+
+
 def format_options(
     original_function: ty.Optional[ty.Callable] = None,
     headers: ty.Optional[ty.Tuple[str, ...]] = None,
diff --git a/releasenotes/notes/add-before-since-options-c67799ef2ad89c0c.yaml b/releasenotes/notes/add-before-since-options-c67799ef2ad89c0c.yaml
new file mode 100644
index 0000000..dc22af5
--- /dev/null
+++ b/releasenotes/notes/add-before-since-options-c67799ef2ad89c0c.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    The ``series list`` and ``patch list`` commands now support ``--since`` and
+    ``--before`` filters to list items created since or before a given
+    date-time.


Test patch:
diff --git a/tests/test_patch.py b/tests/test_patch.py
index 74285e9..e0d98f5 100644
--- a/tests/test_patch.py
+++ b/tests/test_patch.py
@@ -391,6 +391,10 @@ class ListTestCase(unittest.TestCase):
                 '--sort',
                 '-name',
                 'test',
+                '--since',
+                '2022-01-01',
+                '--before',
+                '2022-12-31',
             ],
         )
 
@@ -412,6 +416,8 @@ class ListTestCase(unittest.TestCase):
                     ('page', 1),
                     ('per_page', 1),
                     ('order', '-name'),
+                    ('since', '2022-01-01T00:00:00'),
+                    ('before', '2022-12-31T00:00:00'),
                 ],
             ),
         ]
diff --git a/tests/test_series.py b/tests/test_series.py
index 7125519..4dd6a5e 100644
--- a/tests/test_series.py
+++ b/tests/test_series.py
@@ -226,6 +226,10 @@ class ListTestCase(unittest.TestCase):
                 '--sort',
                 '-name',
                 'test',
+                '--since',
+                '2022-01-01',
+                '--before',
+                '2022-12-31',
             ],
         )
 
@@ -241,6 +245,8 @@ class ListTestCase(unittest.TestCase):
                     ('page', 1),
                     ('per_page', 1),
                     ('order', '-name'),
+                    ('since', '2022-01-01T00:00:00'),
+                    ('before', '2022-12-31T00:00:00'),
                 ],
             ),
         ]