You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by kn...@apache.org on 2021/05/19 08:09:28 UTC

[flink-jira-bot] 06/47: [FLINK-22032] introduce dry-run mode and add actual actions to rule 3

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 <kn...@gmail.com>
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