This is an automated email from the ASF dual-hosted git repository. knaufk pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/flink-jira-bot.git
commit 0561a81f9b9d7db4a277db1465090b97a0c21936 Author: Konstantin Knauf <[email protected]> AuthorDate: Fri Apr 9 14:15:15 2021 +0200 [FLINK-22032] introduce dry-run mode and add actual actions to rule 3 --- Makefile | 6 ++++ config.yaml | 6 ++-- flink_jira_bot.py | 102 +++++++++++++++++++++++++++++++++++++++++++++++++----- requirements.txt | 4 ++- 4 files changed, 106 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 677c9cc..adfff3d 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,12 @@ $(VENV)/bin/activate: requirements.txt # venv is a shortcut target venv: $(VENV)/bin/activate +help: venv + ./$(VENV)/bin/python3 flink_jira_bot.py --help + +dry-run: venv + ./$(VENV)/bin/python3 flink_jira_bot.py -d + run: venv ./$(VENV)/bin/python3 flink_jira_bot.py diff --git a/config.yaml b/config.yaml index d77f815..727da38 100644 --- a/config.yaml +++ b/config.yaml @@ -1,6 +1,8 @@ stale_minor: stale_days: 180 warning_days: 7 - label: "stale-minor" - comment: 'This issue (and any of its Sub-Tasks) has not been updated for {stale_days} days. So, it has been labeled "{label}". If you are still affected by this bug or are still interested in this issue, please give an update and remove the label. In {warning_days} days the issue will be closed automatically.' + warning_label: "stale-minor" + warning_comment: 'This issue and all of its Sub-Tasks have not been updated for {stale_days} days. So, it has been labeled "{warning_label}". If you are still affected by this bug or are still interested in this issue, please give an update and remove the label. In {warning_days} days the issue will be closed automatically.' + done_label: "auto-closed" + done_comment: 'This issue has been labeled "{warning_label}" for {warning_days} days. It is closed now. If you are still affected by this or would like to raise the priority of this ticket please re-open, removing the label "{done_label}" and raise the ticket priority accordingly.' diff --git a/flink_jira_bot.py b/flink_jira_bot.py index a092399..05541ca 100644 --- a/flink_jira_bot.py +++ b/flink_jira_bot.py @@ -3,14 +3,18 @@ import logging import confuse import os import abc +import sys +from argparse import ArgumentParser +from pathlib import Path class FlinkJiraRule: __metaclass__ = abc.ABCMeta - def __init__(self, jira_client, config): + def __init__(self, jira_client, config, is_dry_run): self.jira_client = jira_client self.config = config + self.is_dry_run = is_dry_run def has_recently_updated_subtask(self, parent, updated_within_days): find_subtasks_updated_within = ( @@ -19,18 +23,54 @@ class FlinkJiraRule: issues = self.jira_client.jql(find_subtasks_updated_within, limit=1) return issues["total"] > 0 + def add_label(self, issue, label): + labels = issue["fields"]["labels"] + [label] + fields = {"labels": labels} + key = issue["key"] + + if not self.is_dry_run: + self.jira.update_issue_field(key, fields) + else: + logging.info(f'DRY RUN ({key}): Adding label "{label}".') + + def replace_label(self, issue, old_label, new_label): + labels = issue["fields"]["labels"] + [new_label] + labels.remove(old_label) + fields = {"labels": labels} + key = issue["key"] + + if not self.is_dry_run: + self.jira.update_issue_field(key, fields) + else: + logging.info( + f'DRY RUN ({key}): Replace label "{old_label}" for "{new_label}".' + ) + + def add_comment(self, key, comment): + if not self.is_dry_run: + jira.issue_add_comment(key, comment) + else: + logging.info(f'DRY_RUN ({key}): Adding comment "{comment}".') + + def close_issue(self, key): + if not self.is_dry_run: + jira.issue_transition(key, "Closed") + else: + logging.info(f"DRY_RUN (({key})): Closing.") + @abc.abstractmethod def run(self): return class Rule3(FlinkJiraRule): - def __init__(self, jira_client, config): - super().__init__(jira_client, config) + def __init__(self, jira_client, config, is_dry_run): + super().__init__(jira_client, config, is_dry_run) self.stale_days = config["stale_minor"]["stale_days"].get() self.warning_days = config["stale_minor"]["warning_days"].get() - self.label = config["stale_minor"]["label"].get() - self.comment = config["stale_minor"]["comment"].get() + self.warning_label = config["stale_minor"]["warning_label"].get() + self.done_label = config["stale_minor"]["done_label"].get() + self.warning_comment = config["stale_minor"]["warning_comment"].get() def run(self): self.close_tickets_marked_stale() @@ -38,7 +78,7 @@ class Rule3(FlinkJiraRule): def close_tickets_marked_stale(self): - minor_tickets_marked_stale = f'project=FLINK AND Priority = Minor AND resolution = Unresolved AND labels in ("{self.label}") AND updated < startOfDay(-{self.warning_days}d)' + minor_tickets_marked_stale = f'project=FLINK AND Priority = Minor AND resolution = Unresolved AND labels in ("{self.warning_label}") AND updated < startOfDay(-{self.warning_days}d)' logging.info( f"Looking for minor tickets, which were previously marked as stale: {minor_tickets_marked_stale}" ) @@ -50,6 +90,16 @@ class Rule3(FlinkJiraRule): f"Found https://issues.apache.org/jira/browse/{key}. It is now closed due to inactivity." ) + formatted_comment = self.done_comment.format( + warning_days=self.warning_days, + warning_label=self.warning_label, + done_label=self.done_label, + ) + + self.add_comment(key, formatted_comment) + self.replace_label(issue, self.warning_label, self.done_label) + self.close_issue(key) + def mark_stale_tickets_stale(self): stale_minor_tickets = f"project = FLINK AND Priority = Minor AND resolution = Unresolved AND updated < startOfDay(-{self.stale_days}d)" @@ -66,19 +116,53 @@ class Rule3(FlinkJiraRule): logging.info( f"Found https://issues.apache.org/jira/browse/{key}. It is marked stale now." ) + formatted_comment = self.warning_comment.format( + stale_days=self.stale_days, + warning_days=self.warning_days, + warning_label=self.warning_label, + ) + + self.add_label(issue, self.warning_label) + self.add_comment(key, formatted_comment) else: - logging.debug( + logging.info( f"Found https://issues.apache.org/jira/browse/{key}, but is has recently updated Subtasks. Ignoring for now." ) +def is_dry_run(): + opts = [opt for opt in sys.argv[1:] if opt.startswith("-")] + return "-d" in opts + + +def get_args(): + parser = ArgumentParser(description="Apache Flink Jira Bot") + parser.add_argument( + "-d", + "--dry-run", + dest="dryrun", + action="store_true", + help="no action on Jira, only logging", + ) + parser.add_argument( + "-c", + "--config", + type=Path, + default=Path("config.yaml"), + help="path to config file (default: config.yaml)", + ) + return parser.parse_args() + + if __name__ == "__main__": logging.getLogger().setLevel(logging.INFO) + args = get_args() + config = confuse.Configuration("flink-jira-bot", __name__) - config.set_file("config.yaml") + config.set_file(args.config) jira = Jira( url="https://issues.apache.org/jira", @@ -86,5 +170,5 @@ if __name__ == "__main__": password=os.environ["JIRA_PASSWORD"], ) - rule_3 = Rule3(jira, config) + rule_3 = Rule3(jira, config, args.dryrun) rule_3.run() diff --git a/requirements.txt b/requirements.txt index c5e1dd1..336352b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ appdirs==1.4.4 atlassian-python-api==3.8.0 -black @ git+git://github.com/psf/black@e114ef5514e95cb9908b38c2397978f2070c1b0e +black==20.8b1 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 @@ -17,5 +17,7 @@ requests==2.25.1 requests-oauthlib==1.3.0 six==1.15.0 toml==0.10.2 +typed-ast==1.4.3 +typing-extensions==3.7.4.3 urllib3==1.26.4 wrapt==1.12.1
