CI: Add stale PR action
State: closed

Adding a GitHub Action for ~closing stale PRs~ labeling PRs as stale which I think could help in managing the backlog

https://github.com/actions/stale

Labels:
name: CI
description: Continuous Integration

Comments:
neat idea
Might want to make exemptions for works in progress or PRs awaiting review, seems both are possible with this action
yeah let's just label to start
> can we just close PRs and not issues?

Yes, I believe if we don't specify a `stale-issue-message` then it won't do anything for issues (this is according to the sample YAML under basic usage)
Updated to never close PRs for now and use debug only (I'm assuming this means we would see what actions would have occurred within the logs). Rate limiting I think is handled by default with occurences-per-run set to 30.
@datapythonista if you'd have a quick look.
I also think it could be interesting to automatically label new PRs with "Needs review" (similar to new issues being flagged with "Needs triage"), and in addition exempt these from becoming stale
> I guess `days-before-close: -1` means that we'll just label PRs, and not actually close them, right? That sounds good to me.

Yes, I think that essentially disables closing according to their documentation:

```
  days-before-close:
    description: 'The number of days to wait to close an issue or pull request after it being marked stale. Set to -1 to never close stale issues.'
    default: 7
```
I don't directly find where we discussed this before (or at least where I raised this concern, some other short discussions at https://github.com/pandas-dev/pandas/issues/23489, https://github.com/pandas-dev/pandas/issues/23489), but my main concern with something like this is that this somewhat assumes that PRs are inactive because of the contributors being inactive.

Looking at the 10 first PRs when sorting by "least recently updated", roughly 6 of them are actually waiting on review of a core developer, 2 first need discussion / a decision, and 2 are really waiting on changes of the contributor. 

Which doesn't mean that a bot cannot help improve our workflow, to be clear (it can also help us to be reminded to review, or at some point if no core dev has interest to review a PR, then the best solution is to actually close it). But at least that should somehow be reflected in the messaging of the bot.


---

Comment from @TomAugspurger on gitter: "Are you aware of any bots that could check with the last comment was by a pandas maintainer / requested changes? Ideally we would only auto-close when we were the last one to comment." 
As another example: the cpython has a more advanced labeling / bot workflow (labels "awaiting review", "awaiting changes", "awaiting merge") where the bot will eg add a "awaiting review" label on a PR whenever a new push to the PR was done, and add a "awaiting changes" label whenever a core dev left a review comment.


@jorisvandenbossche I think not automatically closing PRs partly addresses your concerns. but I agree the message seems targeted to the author. maybe just a terse `This pull request has been labelled as stale because it has been open for 30 days with no activity.` instead.
According to https://github.com/actions/stale, there are ways to configure depending on labels already present on the PR. 
So eg we could not message or use a different message on PRs that are labeled with "Needs review" (if the then more consistently add this to PRs that are updated by the contributor, though). 
maybe we need another action in place first that labels PRs with "Needs review" when changes are pushed.
Agree exempting some labels would make sense, I also opened https://github.com/pandas-dev/pandas/pull/36349 to start trying to move towards that (this and exempting "Needs Review" would at least deal with the situation of someone opening a PR that doesn't get reviewed for a while).

Regarding wording could add something asking the person to ping a team member if they're waiting for a review (or can contributors be given the ability to label as "Needs Review" themselves, and ask them to do this if they're still waiting?). That way the onus doesn't sound like it's being placed only on the contributor.
I'm happy with this as-is, so just spitballing:

1) Would it make sense to have a a blocked-by-### label/status?  e.g.
  - #35845 is apparently waiting on something upstream in ipython
  - #36298 is blocked by (i think) cy3 compat
  - #34997 is really only relevant once cy3 is available

2) On the review side, visualization is a weak point.  I don't have a good solution for this.
> I'm happy with this as-is, so just spitballing:
> 
> 1. Would it make sense to have a a blocked-by-### label/status?  e.g.
> 
> * #35845 is apparently waiting on something upstream in ipython
> * #36298 is blocked by (i think) cy3 compat
> * #34997 is really only relevant once cy3 is available
> 
> 1. On the review side, visualization is a weak point.  I don't have a good solution for this.

@jbrockmendel Maybe a generic "Blocked" label and add that to the exempt list here?

I'm also assuming these labels should already exist (the action won't create them) so should I add "Stale" and "Blocked" to the current set?

Edit: went ahead and added them
ok let's give this a try, can always disable if its out of control.
thanks @dsaxton 
for info.. from https://github.com/pandas-dev/pandas/runs/1116110678?check_suite_focus=true

Marking issue #35514 - BUG: fix combine_first converting timestamp to int as stale
Marking issue #35428 - WIP BUG: Inconsistent date parsing of to_datetime as stale
Marking issue #35373 - ENH: Add validation checks for non-unique merge keys as stale
Marking issue #35348 - fix generate_range function in datetimes.py file as stale
Marking issue #35300 - ENH: add percentage threshold to dropna as stale
Marking issue #35292 - ENH: Add orient=tight format for dictionaries as stale
Marking issue #35270 - TST: Add test to ensure DF describe does not throw an error (#32409) as stale
Marking issue #35223 - PERF: Allow str.split callers to skip expensive post-processing as stale
Marking issue #35207 - ENH: raise limit for completion number of columns and warn beyond as stale
Marking issue #35127 - ENH: make is_list_like handle non iterable numpy-like arrays correctly as stale
Marking issue #35011 - Fix Issue #34923: Inferred dtype at the end of df explode method as stale
Marking issue #34987 - BUG: Cannot create third-party ExtensionArrays for datetime types (xfail) as stale
Marking issue #34878 - BUG: Fix replace for different dtype equal value as stale
Marking issue #34827 - BUG fix _Unstacker int32 limit in dataframe sizes (pandas-dev#26314) as stale
Marking issue #34814 - ENH: add masked algorithm for mean() function [WIP] #34754 as stale

#35292 has label:"Needs Discussion". maybe add to skip list.
Marking issue #35292 - ENH: Add orient=tight format for dictionaries as stale
Marking issue #34755 - TST: Period with Timestamp overflow as stale
Marking issue #34720 - BUG #34621 added nanosecond support to class Period as stale
Marking issue #34584 - DOC: DataFrame.reindex improve summary and return type as stale
Marking issue #34488 - BUG: Raise ValueError for non numerical join columns in merge_asof as stale
Marking issue #34426 - Categorical.(to|from)_dummies as stale
Marking issue #34385 - use ensure_clean rather than explicit os.remove #34384 as stale

Marking issue #35292 - ENH: Add orient=tight format for dictionaries as stale
Marking issue #34330 - BUG: Fix using dtype with parse_dates in read_csv as stale
Marking issue #34293 - ENH: categorical scatter plot as stale
Marking issue #34011 - Add fix to raise error when category value 'x' is not predefined but is assigned through df.loc[..]=x as stale

Top one should be ignored if / when https://github.com/pandas-dev/pandas/pull/36382 gets merged
Marking issue #35292 - ENH: Add orient=tight format for dictionaries as stale
Marking issue #35063 - ENH: support index=True/False keyword for io.sql.get_schema as stale
Marking issue #35018 - BUG-Fix: AssertionError when slicing MultiIndex and setting value of … as stale
Marking issue #33739 - PERF: fix #32976 slow group by for categorical columns as stale
Marking issue #33543 - Preserving boolean dtype in Series.any/all function with level keyword #33449 as stale
Marking issue #33531 - BUG: Do not use string Index like Datetimelike Index as stale