Automatically close issues or pull requests that have a label, after a custom delay, if no one replies back.
Install this GitHub action by creating a file in your repo at .github/workflows/issue-manager.yml
.
A minimal example could be:
name: Issue Manager
on:
schedule:
- cron: "0 0 * * *"
issue_comment:
types:
- created
issues:
types:
- labeled
pull_request_target:
types:
- labeled
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
issue-manager:
runs-on: ubuntu-latest
steps:
- uses: tiangolo/[email protected]
with:
token: ${{ secrets.GITHUB_TOKEN }}
config: '{"answered": {}}'
Then, you can answer an issue or PR and add the label from the config, in this case, answered
.
After 10 days, if no one has added a new comment (or in the case of PRs, a new review or commit), the GitHub action will write:
Assuming the original need was handled, this will be automatically closed now.
And then it will close the issue.
But if someone adds a comment after you added the label, this GitHub Action will remove the label so that you can come back and check it instead of closing it.
You can use any file name you want, issue-manager.yml
is just a suggestion. But it has to be inside of .github/workflows/
and have a .yml
extension.
If you check, the config
in that file issue-manager.yml
above has a string
, and inside the string there's a whole JSON configuration:
{"answered": {}}
...but it's all inside a string
:
'{"answered": {}}'
This JSON configuration (inside a string) is what allows us to add multiple custom labels, with different delays, and different messages.
Imagine this JSON config:
{
"answered": {
"delay": "P3DT12H30M5S",
"message": "It seems the issue was answered, closing this now."
},
"validated": {
"delay": 300,
"message": "The issue could not be validated after 5 minutes. Closing now."
},
"waiting": {
"delay": 691200,
"message": "Closing after 8 days of waiting for the additional info requested."
},
"needs-tests": {
"delay": 691200,
"message": "This PR will be closed after waiting 8 days for tests to be added. Please create a new one with tests."
}
}
In this case, if:
- the issue has a label
answered
- the label was added after the last comment
- the last comment was written more than 3 days, 12 hours, 30 minutes and 5 seconds ago
...the GitHub action would close the issue with a message of:
It seems the issue was answered, closing this now.
But if there was a new comment created after the label was added, by default, it would remove the label.
But then, if:
- the issue has a label
validated
- the label was added after the last comment
- the last comment was written more than
300
seconds ago (5 minutes)
...the GitHub action would close the issue with a message:
The issue could not be validated after 5 minutes. Closing now.
And also, if there was a new comment created after the label was added, by default, it would remove the label.
Then, if:
- the issue has a label
waiting
- the label was added after the last comment
- the last comment was addded more than
691200
seconds (8 days) ago
...the GitHub action would close the issue with:
Closing after 10 days of waiting for the additional info requested.
And again, by default, removing the label if there was a new comment written after adding the label.
And finally, if:
- a PR has a label
needs-tests
- the label was added after the last comment
- the last comment was added more than
691200
seconds (8 days) ago
...the GitHub action would close the PR with:
This PR will be closed after waiting 8 days for tests to be added. Please create a new one with tests.
Note: in this last example the process is applied to a PR instead of an issue. The same logic applies to both issues and PRs. If you want a label to only apply to issues, you should use that label only with issues, and the same with PRs.
The delay can be configured using anything supported by Pydantic's datetime
.
So, it can be an ISO 8601 period format (like P3DT12H30M5S
), or the number of seconds between the two dates (like 691200
, or 10 days) plus other options.
You can also pass a config remove_label_on_comment
per keyword. By default, it's true
.
When someone adds a comment after the label was added, then this GitHub action won't close the issue.
On top of not closing the issue, by default, it will remove the label. You can disable removing the label by setting remove_label_on_comment
to false
.
After this GitHub action closes an issue it can also automatically remove the label from the issue when you pass the config remove_label_on_close
set to true
.
By default it is false, and doesn't remove the label from the issue.
By default, any config has:
delay
: A delay of 10 days.message
: A message of:
Assuming the original issue was solved, it will be automatically closed now.
remove_label_on_comment
: True. If someone adds a comment after you added the label, it will remove the label from the issue.remove_label_on_close
: False. After this GitHub action closes the issue it would also remove the label from the issue.
To use that same JSON config from above, you would have to put it on a single string
inside the GitHub Action config (issue-manager.yml
).
But YAML supports multiline strings using >
.
Just make sure to indent everything to be part of the same string.
So, you can put all the config with:
name: Issue Manager
on:
schedule:
- cron: "0 0 * * *"
issue_comment:
types:
- created
- edited
issues:
types:
- labeled
pull_request_target:
types:
- labeled
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
issue-manager:
runs-on: ubuntu-latest
steps:
- uses: tiangolo/[email protected]
with:
token: ${{ secrets.GITHUB_TOKEN }}
config: >
{
"answered": {
"delay": "P3DT12H30M5S",
"message": "It seems the issue was answered, closing this now."
},
"validated": {
"delay": 300,
"message": "The issue could not be validated after 5 minutes. Closing now."
},
"waiting": {
"delay": 691200,
"message": "Closing after 8 days of waiting for the additional info requested."
}
}
If you have Visual Studio Code or another modern editor, you can create your JSON config by creating a JSON file, e.g. config.json
.
Then writing the contents of your config in that file, and then copying the results.
But you can do it all with autocomplete π.
You can start your JSON config file with:
{
"$schema": "https://raw.githubusercontent.com/tiangolo/issue-manager/master/schema.json"
}
And then after you write a keyword and start its config, like "answered": {}
, it will autocomplete the internal config keys, like delay
, message
. And will validate its contents.
It's fine to leave the $schema
in the config
on the .yml
file, it will be discarded and won't be used as a label.
Note: you probably don't need all the configs, the examples above should suffice for most cases. But if you want to make the GitHub action not remove the labels if someone adds a new comment, this can help as an example:
name: Issue Manager
on:
schedule:
- cron: "0 0 * * *"
issue_comment:
types:
- created
- edited
issues:
types:
- labeled
pull_request_target:
types:
- labeled
workflow_dispatch:
permissions:
issues: write
pull-requests: write
jobs:
issue-manager:
runs-on: ubuntu-latest
steps:
- uses: tiangolo/[email protected]
with:
token: ${{ secrets.GITHUB_TOKEN }}
config: >
{
"$schema": "https://raw.githubusercontent.com/tiangolo/issue-manager/master/schema.json",
"answered": {
"delay": "P3DT12H30M5S",
"message": "It seems the issue was answered, closing this now.",
"remove_label_on_comment": false,
"remove_label_on_close": false
},
"validated": {
"delay": 300,
"message": "The issue could not be validated after 5 minutes. Closing now.",
"remove_label_on_comment": true,
"remove_label_on_close": false
},
"waiting": {
"delay": 691200,
"message": "Closing after 8 days of waiting for the additional info requested.",
"remove_label_on_comment": true,
"remove_label_on_close": true
}
}
If you check the examples above, they have a section that says when to run the GitHub action:
on:
schedule:
- cron: "0 0 * * *"
issue_comment:
types:
- created
- edited
issues:
types:
- labeled
pull_request_target:
types:
- labeled
workflow_dispatch:
- The
cron
option means that the GitHub action will be run every day at 00:00 UTC. - The
issue_comment
option means that it will be run with a specific issue when a comment is added.- This way, if there's a new comment, it can immediately remove any label that was added before the new comment.
- The
issues
option with a type oflabel
will run it with each specific issue when you add a label.- This way you can add a label to an issue that was answered long ago, and if the configured delay since the last comment is enough the GitHub action will close the issue right away.
- The
pull_request_target
option with a type oflabel
will run it with each specific Pull Request made to your repo when you add a label.- This way you can add a label to a PR that was answered long ago, or that was waiting for more comments from the author, reviews, commits, etc. And if the configured delay since the last comment is enough the GitHub action will close the issue right away.
- The
workflow_dispatch
option allows you to run the action manually from the GitHub Actions tab for your repo.
From the examples above you can see a section:
permissions:
issues: write
pull-requests: write
This is to give the GitHub Action the necessary permissions to write to the issues and pull requests (including removing the label).
When you add this GitHub Action to a personal repo, you might not need this specific permission.
But when you add it to a repo that belongs to a GitHub organization, depending on the organization default configurations, you might need to explicitly set this permission.
When I answer an issue, I like to give the original user some time to respond and give them the chance to close the issue before doing it myself.
Or sometimes, I have to request additional info.
Sometimes, my answer didn't respond the real question/problem, and if I closed the issue immediately, it would end up feeling "impolite" to the user.
Moreover, if I closed the issue prematurely, there's a smaller chance that I (or someone else) will revisit it again to answer the real question/problem.
But then, if I leave the issue open after giving an answer, in many cases, the issue will keep open until I come back to close it, after many days.
Then, after that time (10 days, 30 days) and after seeing that there are no new comments, I write "I assume the problem is solved, closing this issue now".
But that requires me going through all the open issues again, one by one, check where I (or someone else) have already answered, typing that message, etc.
One option would be to use a tool that closes stale issues, like probot/stale, or the Close Stale Issues Action.
But if the user came back explaining that my answer didn't respond to his/her problem or giving the extra info requested, but I couldn't respond on time, the issue would still go "stale" and be closed.
This action allows the repo owner to add a label (e.g. answered
) to an issue after answering. Or multiple labels with multiple configurations (multiple messages, delays, etc).
Then, this action, by running every night (or however you configure it) will, for each open issue:
- Check if the issue has one of the configured labels.
- Check if the label was added after the last comment.
- If not, remove the label (configurable).
- Check if the current date-time is more than the configured delay to wait for the user to reply back (configurable).
- Then, if all that matches, it will add a comment with a message (configurable).
- And then it will close the issue.
It will also run after each comment or label added, with the specific issue that has the new comment or label (if you used the example configurations from above).
- β¬ Bump docker/build-push-action from 5 to 6. PR #35 by @dependabot[bot].
- β‘οΈ Improve speed (from 23 seconds to 3 seconds) by using Docker underneath. PR #33 by @tiangolo.
- π Update docs and include
permissions
forpull-request: write
. PR #29 by @tiangolo. - π Update docs about token permissions. PR #27 by @tiangolo.
- π· Update
issue-manager.yml
. PR #32 by @tiangolo. - π· Update
latest-changes
GitHub Action. PR #28 by @tiangolo. - π· Update issue-manager.yml GitHub Action permissions. PR #26 by @tiangolo.
- π§ Add GitHub templates for discussions and issues, and security policy. PR #22 by @alejsdev.
- π§ Add funding. PR #18 by @tiangolo.
- π· Update dependabot. PR #17 by @tiangolo.
- π· Add latest-changes GitHub Action. PR #16 by @tiangolo.
- β¨ Add support for managing PRs and remove support for HTML comments to avoid rate limits. PR #12 by @tiangolo.
- π· Add Latest Changes GitHub Action. PR #13 by @tiangolo.
- Add option to remove a label automatically after closing the issue. PR #10.
- Avoid crashing when a label has been edited after added to the issue. PR #9.
- Fix using single quote (
'
) in README examples. PR #6 by @svlandeg.
- Add support for running immediately with each specific issue after a new comment or label is added.
- Add support for issue labels, detecting if a new comment was added after the label and removing the label.
- Fix incorrect input name. PR #3 by @browniebroke.
- Initial release.
This project is licensed under the terms of the MIT license.